Bug Summary

File:home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx
Warning:line 2406, column 17
Called C++ object pointer is null

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name ucbstorage.cxx -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D BOOST_ERROR_CODE_HEADER_ONLY -D BOOST_SYSTEM_NO_DEPRECATED -D CPPU_ENV=gcc3 -D LINUX -D OSL_DEBUG_LEVEL=1 -D SAL_LOG_INFO -D SAL_LOG_WARN -D UNIX -D UNX -D X86_64 -D _PTHREADS -D _REENTRANT -D SOT_DLLIMPLEMENTATION -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/sot/inc -I /home/maarten/src/libreoffice/core/external/boost/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/boost -I /home/maarten/src/libreoffice/core/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include/linux -I /home/maarten/src/libreoffice/core/config_host -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/udkapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wno-missing-braces -std=c++17 -fdeprecated-macro -fdebug-compilation-dir /home/maarten/src/libreoffice/core -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -debug-info-kind=constructor -analyzer-output=html -faddrsig -o /home/maarten/tmp/wis/scan-build-libreoffice/output/report/2020-10-07-141433-9725-1 -x c++ /home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx

/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx

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 <com/sun/star/io/NotConnectedException.hpp>
21#include <com/sun/star/io/BufferSizeExceededException.hpp>
22#include <com/sun/star/uno/RuntimeException.hpp>
23#include <ucbhelper/content.hxx>
24#include <com/sun/star/uno/Reference.h>
25#include <com/sun/star/ucb/NameClash.hpp>
26#include <unotools/tempfile.hxx>
27#include <unotools/ucbstreamhelper.hxx>
28#include <com/sun/star/io/XInputStream.hpp>
29#include <com/sun/star/ucb/InsertCommandArgument.hpp>
30#include <com/sun/star/ucb/ResultSetException.hpp>
31#include <com/sun/star/uno/Sequence.h>
32#include <com/sun/star/sdbc/XResultSet.hpp>
33#include <com/sun/star/sdbc/XRow.hpp>
34#include <com/sun/star/ucb/CommandAbortedException.hpp>
35#include <com/sun/star/datatransfer/DataFlavor.hpp>
36#include <com/sun/star/ucb/ContentInfo.hpp>
37#include <com/sun/star/ucb/ContentInfoAttribute.hpp>
38#include <com/sun/star/beans/Property.hpp>
39#include <com/sun/star/packages/manifest/ManifestWriter.hpp>
40#include <com/sun/star/packages/manifest/ManifestReader.hpp>
41#include <com/sun/star/ucb/InteractiveIOException.hpp>
42#include <com/sun/star/ucb/ContentCreationException.hpp>
43
44#include <memory>
45#include <osl/diagnose.h>
46#include <osl/file.hxx>
47#include <sal/log.hxx>
48#include <tools/diagnose_ex.h>
49#include <tools/ref.hxx>
50#include <tools/debug.hxx>
51#include <unotools/streamwrap.hxx>
52#include <unotools/ucbhelper.hxx>
53#include <tools/urlobj.hxx>
54#include <comphelper/processfactory.hxx>
55#include <cppuhelper/implbase.hxx>
56#include <ucbhelper/commandenvironment.hxx>
57
58#include <sot/stg.hxx>
59#include <sot/storinfo.hxx>
60#include <sot/exchange.hxx>
61#include <sot/formats.hxx>
62#include <comphelper/classids.hxx>
63
64#include <vector>
65
66namespace com::sun::star::ucb { class XCommandEnvironment; }
67
68using namespace ::com::sun::star::lang;
69using namespace ::com::sun::star::beans;
70using namespace ::com::sun::star::uno;
71using namespace ::com::sun::star::ucb;
72using namespace ::com::sun::star::io;
73using namespace ::com::sun::star::sdbc;
74using namespace ::ucbhelper;
75
76#if OSL_DEBUG_LEVEL1 > 0
77static int nOpenFiles=0;
78static int nOpenStreams=0;
79#endif
80
81typedef ::cppu::WeakImplHelper < XInputStream, XSeekable > FileInputStreamWrapper_Base;
82
83namespace {
84
85class FileStreamWrapper_Impl : public FileInputStreamWrapper_Base
86{
87protected:
88 ::osl::Mutex m_aMutex;
89 OUString m_aURL;
90 std::unique_ptr<SvStream> m_pSvStream;
91
92public:
93 explicit FileStreamWrapper_Impl(const OUString& rName);
94 virtual ~FileStreamWrapper_Impl() override;
95
96 virtual void SAL_CALL seek( sal_Int64 _nLocation ) override;
97 virtual sal_Int64 SAL_CALL getPosition( ) override;
98 virtual sal_Int64 SAL_CALL getLength( ) override;
99 virtual sal_Int32 SAL_CALL readBytes( Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead) override;
100 virtual sal_Int32 SAL_CALL readSomeBytes( Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead) override;
101 virtual void SAL_CALL skipBytes(sal_Int32 nBytesToSkip) override;
102 virtual sal_Int32 SAL_CALL available() override;
103 virtual void SAL_CALL closeInput() override;
104
105protected:
106 void checkConnected();
107 void checkError();
108};
109
110}
111
112FileStreamWrapper_Impl::FileStreamWrapper_Impl( const OUString& rName )
113 : m_aURL( rName )
114{
115 // if no URL is provided the stream is empty
116}
117
118
119FileStreamWrapper_Impl::~FileStreamWrapper_Impl()
120{
121 if ( m_pSvStream )
122 {
123 m_pSvStream.reset();
124#if OSL_DEBUG_LEVEL1 > 0
125 --nOpenFiles;
126#endif
127 }
128
129 if (!m_aURL.isEmpty())
130 osl::File::remove(m_aURL);
131}
132
133
134sal_Int32 SAL_CALL FileStreamWrapper_Impl::readBytes(Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead)
135{
136 if ( m_aURL.isEmpty() )
137 {
138 aData.realloc( 0 );
139 return 0;
140 }
141
142 checkConnected();
143
144 if (nBytesToRead < 0)
145 throw BufferSizeExceededException(OUString(),static_cast<XWeak*>(this));
146
147 ::osl::MutexGuard aGuard( m_aMutex );
148
149 if (aData.getLength() < nBytesToRead)
150 aData.realloc(nBytesToRead);
151
152 sal_uInt32 nRead = m_pSvStream->ReadBytes(static_cast<void*>(aData.getArray()), nBytesToRead);
153 checkError();
154
155 // if read characters < MaxLength, adjust sequence
156 if (static_cast<sal_Int32>(nRead) < aData.getLength())
157 aData.realloc( nRead );
158
159 return nRead;
160}
161
162
163sal_Int32 SAL_CALL FileStreamWrapper_Impl::readSomeBytes(Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead)
164{
165 if ( m_aURL.isEmpty() )
166 {
167 aData.realloc( 0 );
168 return 0;
169 }
170
171 checkError();
172
173 if (nMaxBytesToRead < 0)
174 throw BufferSizeExceededException(OUString(),static_cast<XWeak*>(this));
175
176 if (m_pSvStream->eof())
177 {
178 aData.realloc(0);
179 return 0;
180 }
181 else
182 return readBytes(aData, nMaxBytesToRead);
183}
184
185
186void SAL_CALL FileStreamWrapper_Impl::skipBytes(sal_Int32 nBytesToSkip)
187{
188 if ( m_aURL.isEmpty() )
189 return;
190
191 ::osl::MutexGuard aGuard( m_aMutex );
192 checkError();
193
194 m_pSvStream->SeekRel(nBytesToSkip);
195 checkError();
196}
197
198
199sal_Int32 SAL_CALL FileStreamWrapper_Impl::available()
200{
201 if ( m_aURL.isEmpty() )
202 return 0;
203
204 ::osl::MutexGuard aGuard( m_aMutex );
205 checkConnected();
206
207 sal_Int64 nAvailable = m_pSvStream->remainingSize();
208 checkError();
209
210 return std::min<sal_Int64>(SAL_MAX_INT32((sal_Int32) 0x7FFFFFFF), nAvailable);
211}
212
213
214void SAL_CALL FileStreamWrapper_Impl::closeInput()
215{
216 if ( m_aURL.isEmpty() )
217 return;
218
219 ::osl::MutexGuard aGuard( m_aMutex );
220 checkConnected();
221 m_pSvStream.reset();
222#if OSL_DEBUG_LEVEL1 > 0
223 --nOpenFiles;
224#endif
225 osl::File::remove(m_aURL);
226 m_aURL.clear();
227}
228
229
230void SAL_CALL FileStreamWrapper_Impl::seek( sal_Int64 _nLocation )
231{
232 if ( m_aURL.isEmpty() )
233 return;
234
235 ::osl::MutexGuard aGuard( m_aMutex );
236 checkConnected();
237
238 m_pSvStream->Seek(static_cast<sal_uInt32>(_nLocation));
239 checkError();
240}
241
242
243sal_Int64 SAL_CALL FileStreamWrapper_Impl::getPosition( )
244{
245 if ( m_aURL.isEmpty() )
246 return 0;
247
248 ::osl::MutexGuard aGuard( m_aMutex );
249 checkConnected();
250
251 sal_uInt32 nPos = m_pSvStream->Tell();
252 checkError();
253 return static_cast<sal_Int64>(nPos);
254}
255
256
257sal_Int64 SAL_CALL FileStreamWrapper_Impl::getLength( )
258{
259 if ( m_aURL.isEmpty() )
260 return 0;
261
262 ::osl::MutexGuard aGuard( m_aMutex );
263 checkConnected();
264
265 checkError();
266
267 sal_Int64 nEndPos = m_pSvStream->TellEnd();
268
269 return nEndPos;
270}
271
272
273void FileStreamWrapper_Impl::checkConnected()
274{
275 if ( m_aURL.isEmpty() )
276 throw NotConnectedException(OUString(), static_cast<XWeak*>(this));
277 if ( !m_pSvStream )
278 {
279 m_pSvStream = ::utl::UcbStreamHelper::CreateStream( m_aURL, StreamMode::STD_READ );
280#if OSL_DEBUG_LEVEL1 > 0
281 ++nOpenFiles;
282#endif
283 }
284}
285
286
287void FileStreamWrapper_Impl::checkError()
288{
289 checkConnected();
290
291 if (m_pSvStream->SvStream::GetError() != ERRCODE_NONEErrCode(0))
292 // TODO: really evaluate the error
293 throw NotConnectedException(OUString(), static_cast<XWeak*>(this));
294}
295
296
297#define COMMIT_RESULT_FAILURE0 0
298#define COMMIT_RESULT_NOTHING_TO_DO1 1
299#define COMMIT_RESULT_SUCCESS2 2
300
301static SotClipboardFormatId GetFormatId_Impl( const SvGlobalName& aName )
302{
303 if ( aName == SvGlobalName( SO3_SW_CLASSID_600x8BC6B165, 0xB1B2, 0x4EDD, 0xAA, 0x47, 0xDA, 0xE2, 0xEE, 0x68
, 0x9D, 0xD6
) )
304 return SotClipboardFormatId::STARWRITER_60;
305 if ( aName == SvGlobalName( SO3_SWWEB_CLASSID_600xA8BBA60C, 0x7C60, 0x4550, 0x91, 0xCE, 0x39, 0xC3, 0x90, 0x3F
, 0xAC, 0x5E
) )
306 return SotClipboardFormatId::STARWRITERWEB_60;
307 if ( aName == SvGlobalName( SO3_SWGLOB_CLASSID_600xB21A0A7C, 0xE403, 0x41FE, 0x95, 0x62, 0xBD, 0x13, 0xEA, 0x6F
, 0x15, 0xA0
) )
308 return SotClipboardFormatId::STARWRITERGLOB_60;
309 if ( aName == SvGlobalName( SO3_SDRAW_CLASSID_600x4BAB8970, 0x8A3B, 0x45B3, 0x99, 0x1C, 0xCB, 0xEE, 0xAC, 0x6B
, 0xD5, 0xE3
) )
310 return SotClipboardFormatId::STARDRAW_60;
311 if ( aName == SvGlobalName( SO3_SIMPRESS_CLASSID_600x9176E48A, 0x637A, 0x4D1F, 0x80, 0x3B, 0x99, 0xD9, 0xBF, 0xAC
, 0x10, 0x47
) )
312 return SotClipboardFormatId::STARIMPRESS_60;
313 if ( aName == SvGlobalName( SO3_SC_CLASSID_600x47BBB4CB, 0xCE4C, 0x4E80, 0xA5, 0x91, 0x42, 0xD9, 0xAE, 0x74
, 0x95, 0x0F
) )
314 return SotClipboardFormatId::STARCALC_60;
315 if ( aName == SvGlobalName( SO3_SCH_CLASSID_600x12DCAE26, 0x281F, 0x416F, 0xA2, 0x34, 0xC3, 0x08, 0x61, 0x27
, 0x38, 0x2E
) )
316 return SotClipboardFormatId::STARCHART_60;
317 if ( aName == SvGlobalName( SO3_SM_CLASSID_600x078B7ABA, 0x54FC, 0x457F, 0x85, 0x51, 0x61, 0x47, 0xE7, 0x76
, 0xA9, 0x97
) )
318 return SotClipboardFormatId::STARMATH_60;
319 if ( aName == SvGlobalName( SO3_OUT_CLASSID0x970b1e82, 0xcf2d, 0x11cf, 0x89, 0xca, 0x00, 0x80, 0x29, 0xe4
, 0xb0, 0xb1
) ||
320 aName == SvGlobalName( SO3_APPLET_CLASSID0x970b1e81, 0xcf2d, 0x11cf, 0x89,0xca,0x00,0x80,0x29,0xe4,0xb0
,0xb1
) ||
321 aName == SvGlobalName( SO3_PLUGIN_CLASSID0x4caa7761, 0x6b8b, 0x11cf, 0x89,0xca,0x0,0x80,0x29,0xe4,0xb0
,0xb1
) ||
322 aName == SvGlobalName( SO3_IFRAME_CLASSID0x1a8a6701, 0xde58, 0x11cf, 0x89, 0xca, 0x0, 0x80, 0x29, 0xe4
, 0xb0, 0xb1
) )
323 // allowed, but not supported
324 return SotClipboardFormatId::NONE;
325 else
326 {
327 OSL_FAIL( "Unknown UCB storage format!" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "327" ": "), "%s", "Unknown UCB storage format!"); } } while
(false)
;
328 return SotClipboardFormatId::NONE;
329 }
330}
331
332
333static SvGlobalName GetClassId_Impl( SotClipboardFormatId nFormat )
334{
335 switch ( nFormat )
336 {
337 case SotClipboardFormatId::STARWRITER_8 :
338 case SotClipboardFormatId::STARWRITER_8_TEMPLATE :
339 return SvGlobalName( SO3_SW_CLASSID_600x8BC6B165, 0xB1B2, 0x4EDD, 0xAA, 0x47, 0xDA, 0xE2, 0xEE, 0x68
, 0x9D, 0xD6
);
340 case SotClipboardFormatId::STARWRITERWEB_8 :
341 return SvGlobalName( SO3_SWWEB_CLASSID_600xA8BBA60C, 0x7C60, 0x4550, 0x91, 0xCE, 0x39, 0xC3, 0x90, 0x3F
, 0xAC, 0x5E
);
342 case SotClipboardFormatId::STARWRITERGLOB_8 :
343 case SotClipboardFormatId::STARWRITERGLOB_8_TEMPLATE :
344 return SvGlobalName( SO3_SWGLOB_CLASSID_600xB21A0A7C, 0xE403, 0x41FE, 0x95, 0x62, 0xBD, 0x13, 0xEA, 0x6F
, 0x15, 0xA0
);
345 case SotClipboardFormatId::STARDRAW_8 :
346 case SotClipboardFormatId::STARDRAW_8_TEMPLATE :
347 return SvGlobalName( SO3_SDRAW_CLASSID_600x4BAB8970, 0x8A3B, 0x45B3, 0x99, 0x1C, 0xCB, 0xEE, 0xAC, 0x6B
, 0xD5, 0xE3
);
348 case SotClipboardFormatId::STARIMPRESS_8 :
349 case SotClipboardFormatId::STARIMPRESS_8_TEMPLATE :
350 return SvGlobalName( SO3_SIMPRESS_CLASSID_600x9176E48A, 0x637A, 0x4D1F, 0x80, 0x3B, 0x99, 0xD9, 0xBF, 0xAC
, 0x10, 0x47
);
351 case SotClipboardFormatId::STARCALC_8 :
352 case SotClipboardFormatId::STARCALC_8_TEMPLATE :
353 return SvGlobalName( SO3_SC_CLASSID_600x47BBB4CB, 0xCE4C, 0x4E80, 0xA5, 0x91, 0x42, 0xD9, 0xAE, 0x74
, 0x95, 0x0F
);
354 case SotClipboardFormatId::STARCHART_8 :
355 case SotClipboardFormatId::STARCHART_8_TEMPLATE :
356 return SvGlobalName( SO3_SCH_CLASSID_600x12DCAE26, 0x281F, 0x416F, 0xA2, 0x34, 0xC3, 0x08, 0x61, 0x27
, 0x38, 0x2E
);
357 case SotClipboardFormatId::STARMATH_8 :
358 case SotClipboardFormatId::STARMATH_8_TEMPLATE :
359 return SvGlobalName( SO3_SM_CLASSID_600x078B7ABA, 0x54FC, 0x457F, 0x85, 0x51, 0x61, 0x47, 0xE7, 0x76
, 0xA9, 0x97
);
360 case SotClipboardFormatId::STARWRITER_60 :
361 return SvGlobalName( SO3_SW_CLASSID_600x8BC6B165, 0xB1B2, 0x4EDD, 0xAA, 0x47, 0xDA, 0xE2, 0xEE, 0x68
, 0x9D, 0xD6
);
362 case SotClipboardFormatId::STARWRITERWEB_60 :
363 return SvGlobalName( SO3_SWWEB_CLASSID_600xA8BBA60C, 0x7C60, 0x4550, 0x91, 0xCE, 0x39, 0xC3, 0x90, 0x3F
, 0xAC, 0x5E
);
364 case SotClipboardFormatId::STARWRITERGLOB_60 :
365 return SvGlobalName( SO3_SWGLOB_CLASSID_600xB21A0A7C, 0xE403, 0x41FE, 0x95, 0x62, 0xBD, 0x13, 0xEA, 0x6F
, 0x15, 0xA0
);
366 case SotClipboardFormatId::STARDRAW_60 :
367 return SvGlobalName( SO3_SDRAW_CLASSID_600x4BAB8970, 0x8A3B, 0x45B3, 0x99, 0x1C, 0xCB, 0xEE, 0xAC, 0x6B
, 0xD5, 0xE3
);
368 case SotClipboardFormatId::STARIMPRESS_60 :
369 return SvGlobalName( SO3_SIMPRESS_CLASSID_600x9176E48A, 0x637A, 0x4D1F, 0x80, 0x3B, 0x99, 0xD9, 0xBF, 0xAC
, 0x10, 0x47
);
370 case SotClipboardFormatId::STARCALC_60 :
371 return SvGlobalName( SO3_SC_CLASSID_600x47BBB4CB, 0xCE4C, 0x4E80, 0xA5, 0x91, 0x42, 0xD9, 0xAE, 0x74
, 0x95, 0x0F
);
372 case SotClipboardFormatId::STARCHART_60 :
373 return SvGlobalName( SO3_SCH_CLASSID_600x12DCAE26, 0x281F, 0x416F, 0xA2, 0x34, 0xC3, 0x08, 0x61, 0x27
, 0x38, 0x2E
);
374 case SotClipboardFormatId::STARMATH_60 :
375 return SvGlobalName( SO3_SM_CLASSID_600x078B7ABA, 0x54FC, 0x457F, 0x85, 0x51, 0x61, 0x47, 0xE7, 0x76
, 0xA9, 0x97
);
376 default :
377 return SvGlobalName();
378 }
379}
380
381// All storage and streams are refcounted internally; outside of this classes they are only accessible through a handle
382// class, that uses the refcounted object as impl-class.
383
384class UCBStorageStream_Impl : public SvRefBase, public SvStream
385{
386 virtual ~UCBStorageStream_Impl() override;
387public:
388
389 virtual std::size_t GetData(void* pData, std::size_t nSize) override;
390 virtual std::size_t PutData(const void* pData, std::size_t nSize) override;
391 virtual sal_uInt64 SeekPos( sal_uInt64 nPos ) override;
392 virtual void SetSize( sal_uInt64 nSize ) override;
393 virtual void FlushData() override;
394 virtual void ResetError() override;
395
396 UCBStorageStream* m_pAntiImpl; // only valid if an external reference exists
397
398 OUString m_aOriginalName;// the original name before accessing the stream
399 OUString m_aName; // the actual name ( changed with a Rename command at the parent )
400 OUString m_aURL; // the full path name to create the content
401 OUString m_aContentType;
402 OUString m_aOriginalContentType;
403 OString m_aKey;
404 ::ucbhelper::Content* m_pContent; // the content that provides the data
405 Reference<XInputStream> m_rSource; // the stream covering the original data of the content
406 std::unique_ptr<SvStream> m_pStream; // the stream worked on; for readonly streams it is the original stream of the content
407 // for read/write streams it's a copy into a temporary file
408 OUString m_aTempURL; // URL of this temporary stream
409 ErrCode m_nError;
410 StreamMode m_nMode; // open mode ( read/write/trunc/nocreate/sharing )
411 bool m_bSourceRead; // Source still contains useful information
412 bool m_bModified; // only modified streams will be sent to the original content
413 bool m_bCommited; // sending the streams is coordinated by the root storage of the package
414 bool m_bDirect; // the storage and its streams are opened in direct mode; for UCBStorages
415 // this means that the root storage does an autocommit when its external
416 // reference is destroyed
417 bool m_bIsOLEStorage;// an OLEStorage on a UCBStorageStream makes this an Autocommit-stream
418
419 UCBStorageStream_Impl( const OUString&, StreamMode, UCBStorageStream*, bool,
420 bool bRepair, Reference< XProgressHandler > const & xProgress );
421
422 void Free();
423 bool Init();
424 bool Clear();
425 sal_Int16 Commit(); // if modified and committed: transfer an XInputStream to the content
426 void Revert(); // discard all changes
427 BaseStorage* CreateStorage();// create an OLE Storage on the UCBStorageStream
428 sal_uLong GetSize();
429
430 sal_uInt64 ReadSourceWriteTemporary( sal_uInt64 aLength ); // read aLength from source and copy to temporary,
431 // no seeking is produced
432 void ReadSourceWriteTemporary(); // read source till the end and copy to temporary,
433
434 void CopySourceToTemporary(); // same as ReadSourceWriteToTemporary()
435 // but the writing is done at the end of temporary
436 // pointer position is not changed
437 using SvStream::SetError;
438 void SetError( ErrCode nError );
439 void PrepareCachedForReopen( StreamMode nMode );
440};
441
442typedef tools::SvRef<UCBStorageStream_Impl> UCBStorageStream_ImplRef;
443
444struct UCBStorageElement_Impl;
445typedef std::vector<std::unique_ptr<UCBStorageElement_Impl>> UCBStorageElementList_Impl;
446
447class UCBStorage_Impl : public SvRefBase
448{
449 virtual ~UCBStorage_Impl() override;
450public:
451 UCBStorage* m_pAntiImpl; // only valid if external references exists
452
453 OUString m_aName; // the actual name ( changed with a Rename command at the parent )
454 OUString m_aURL; // the full path name to create the content
455 OUString m_aContentType;
456 OUString m_aOriginalContentType;
457 std::unique_ptr<::ucbhelper::Content> m_pContent; // the content that provides the storage elements
458 std::unique_ptr<::utl::TempFile> m_pTempFile; // temporary file, only for storages on stream
459 SvStream* m_pSource; // original stream, only for storages on a stream
460 ErrCode m_nError;
461 StreamMode m_nMode; // open mode ( read/write/trunc/nocreate/sharing )
462 bool m_bCommited; // sending the streams is coordinated by the root storage of the package
463 bool m_bDirect; // the storage and its streams are opened in direct mode; for UCBStorages
464 // this means that the root storage does an autocommit when its external
465 // reference is destroyed
466 bool m_bIsRoot; // marks this storage as root storages that manages all commits and reverts
467 bool m_bIsLinked;
468 bool m_bListCreated;
469 SotClipboardFormatId m_nFormat;
470 OUString m_aUserTypeName;
471 SvGlobalName m_aClassId;
472
473 UCBStorageElementList_Impl m_aChildrenList;
474
475 bool m_bRepairPackage;
476 Reference< XProgressHandler > m_xProgressHandler;
477
478 UCBStorage_Impl( const ::ucbhelper::Content&, const OUString&, StreamMode, UCBStorage*, bool,
479 bool, bool = false, Reference< XProgressHandler > const & = Reference< XProgressHandler >() );
480 UCBStorage_Impl( const OUString&, StreamMode, UCBStorage*, bool, bool,
481 bool, Reference< XProgressHandler > const & );
482 UCBStorage_Impl( SvStream&, UCBStorage*, bool );
483 void Init();
484 sal_Int16 Commit();
485 void Revert();
486 bool Insert( ::ucbhelper::Content *pContent );
487 UCBStorage_Impl* OpenStorage( UCBStorageElement_Impl* pElement, StreamMode nMode, bool bDirect );
488 void OpenStream( UCBStorageElement_Impl*, StreamMode, bool );
489 void SetProps( const Sequence < Sequence < PropertyValue > >& rSequence, const OUString& );
490 void GetProps( sal_Int32&, Sequence < Sequence < PropertyValue > >& rSequence, const OUString& );
491 sal_Int32 GetObjectCount();
492 void ReadContent();
493 void CreateContent();
494 ::ucbhelper::Content* GetContent()
495 {
496 if ( !m_pContent )
497 CreateContent();
498 return m_pContent.get();
499 }
500 UCBStorageElementList_Impl& GetChildrenList()
501 {
502 const ErrCode nError = m_nError;
503 ReadContent();
504 if ( m_nMode & StreamMode::WRITE )
505 {
506 m_nError = nError;
507 if ( m_pAntiImpl )
508 {
509 m_pAntiImpl->ResetError();
510 m_pAntiImpl->SetError( nError );
511 }
512 }
513 return m_aChildrenList;
514 }
515
516 void SetError( ErrCode nError );
517};
518
519typedef tools::SvRef<UCBStorage_Impl> UCBStorage_ImplRef;
520
521// this struct contains all necessary information on an element inside a UCBStorage
522struct UCBStorageElement_Impl
523{
524 OUString m_aName; // the actual URL relative to the root "folder"
525 OUString m_aOriginalName;// the original name in the content
526 sal_uLong m_nSize;
527 bool m_bIsFolder; // Only true when it is a UCBStorage !
528 bool m_bIsStorage; // Also true when it is an OLEStorage !
529 bool m_bIsRemoved; // element will be removed on commit
530 bool m_bIsInserted; // element will be removed on revert
531 UCBStorage_ImplRef m_xStorage; // reference to the "real" storage
532 UCBStorageStream_ImplRef m_xStream; // reference to the "real" stream
533
534 UCBStorageElement_Impl( const OUString& rName,
535 bool bIsFolder = false, sal_uLong nSize = 0 )
536 : m_aName( rName )
537 , m_aOriginalName( rName )
538 , m_nSize( nSize )
539 , m_bIsFolder( bIsFolder )
540 , m_bIsStorage( bIsFolder )
541 , m_bIsRemoved( false )
542 , m_bIsInserted( false )
543 {
544 }
545
546 ::ucbhelper::Content* GetContent();
547 bool IsModified() const;
548 OUString GetContentType() const;
549 void SetContentType( const OUString& );
550 OUString GetOriginalContentType() const;
551 bool IsLoaded() const
552 { return m_xStream.is() || m_xStorage.is(); }
553};
554
555::ucbhelper::Content* UCBStorageElement_Impl::GetContent()
556{
557 if ( m_xStream.is() )
558 return m_xStream->m_pContent;
559 else if ( m_xStorage.is() )
560 return m_xStorage->GetContent();
561 else
562 return nullptr;
563}
564
565OUString UCBStorageElement_Impl::GetContentType() const
566{
567 if ( m_xStream.is() )
568 return m_xStream->m_aContentType;
569 else if ( m_xStorage.is() )
570 return m_xStorage->m_aContentType;
571 else
572 {
573 OSL_FAIL("Element not loaded!")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "573" ": "), "%s", "Element not loaded!"); } } while (false
)
;
574 return OUString();
575 }
576}
577
578void UCBStorageElement_Impl::SetContentType( const OUString& rType )
579{
580 if ( m_xStream.is() ) {
581 m_xStream->m_aContentType = m_xStream->m_aOriginalContentType = rType;
582 }
583 else if ( m_xStorage.is() ) {
584 m_xStorage->m_aContentType = m_xStorage->m_aOriginalContentType = rType;
585 }
586 else {
587 OSL_FAIL("Element not loaded!")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "587" ": "), "%s", "Element not loaded!"); } } while (false
)
;
588 }
589}
590
591OUString UCBStorageElement_Impl::GetOriginalContentType() const
592{
593 if ( m_xStream.is() )
594 return m_xStream->m_aOriginalContentType;
595 else if ( m_xStorage.is() )
596 return m_xStorage->m_aOriginalContentType;
597 else
598 return OUString();
599}
600
601bool UCBStorageElement_Impl::IsModified() const
602{
603 bool bModified = m_bIsRemoved || m_bIsInserted || m_aName != m_aOriginalName;
604 if ( bModified )
605 {
606 if ( m_xStream.is() )
607 bModified = m_xStream->m_aContentType != m_xStream->m_aOriginalContentType;
608 else if ( m_xStorage.is() )
609 bModified = m_xStorage->m_aContentType != m_xStorage->m_aOriginalContentType;
610 }
611
612 return bModified;
613}
614
615UCBStorageStream_Impl::UCBStorageStream_Impl( const OUString& rName, StreamMode nMode, UCBStorageStream* pStream, bool bDirect, bool bRepair, Reference< XProgressHandler > const & xProgress )
616 : m_pAntiImpl( pStream )
617 , m_aURL( rName )
618 , m_pContent( nullptr )
619 , m_nError( ERRCODE_NONEErrCode(0) )
620 , m_nMode( nMode )
621 , m_bSourceRead( !( nMode & StreamMode::TRUNC ) )
622 , m_bModified( false )
623 , m_bCommited( false )
624 , m_bDirect( bDirect )
625 , m_bIsOLEStorage( false )
626{
627 // name is last segment in URL
628 INetURLObject aObj( rName );
629 m_aName = m_aOriginalName = aObj.GetLastName();
630 try
631 {
632 // create the content
633 Reference< css::ucb::XCommandEnvironment > xComEnv;
634
635 OUString aTemp( rName );
636
637 if ( bRepair )
638 {
639 xComEnv = new ::ucbhelper::CommandEnvironment( Reference< css::task::XInteractionHandler >(), xProgress );
640 aTemp += "?repairpackage";
641 }
642
643 m_pContent = new ::ucbhelper::Content( aTemp, xComEnv, comphelper::getProcessComponentContext() );
644 }
645 catch (const ContentCreationException&)
646 {
647 // content could not be created
648 SetError( SVSTREAM_CANNOT_MAKEErrCode( ErrCodeArea::Io, ErrCodeClass::Create, 25 ) );
649 }
650 catch (const RuntimeException&)
651 {
652 // any other error - not specified
653 SetError( ERRCODE_IO_GENERALErrCode( ErrCodeArea::Io, ErrCodeClass::General, 13 ) );
654 }
655}
656
657UCBStorageStream_Impl::~UCBStorageStream_Impl()
658{
659 if( m_rSource.is() )
660 m_rSource.clear();
661
662 m_pStream.reset();
663
664 if (!m_aTempURL.isEmpty())
665 osl::File::remove(m_aTempURL);
666
667 delete m_pContent;
668}
669
670
671bool UCBStorageStream_Impl::Init()
672{
673 if( !m_pStream )
674 {
675 // no temporary stream was created
676 // create one
677
678 if ( m_aTempURL.isEmpty() )
679 m_aTempURL = ::utl::TempFile().GetURL();
680
681 m_pStream = ::utl::UcbStreamHelper::CreateStream( m_aTempURL, StreamMode::STD_READWRITE, true /* bFileExists */ );
682#if OSL_DEBUG_LEVEL1 > 0
683 ++nOpenFiles;
684#endif
685
686 if( !m_pStream )
687 {
688 OSL_FAIL( "Suspicious temporary stream creation!" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "688" ": "), "%s", "Suspicious temporary stream creation!"
); } } while (false)
;
689 SetError( SVSTREAM_CANNOT_MAKEErrCode( ErrCodeArea::Io, ErrCodeClass::Create, 25 ) );
690 return false;
691 }
692
693 SetError( m_pStream->GetError() );
694 }
695
696 if( m_bSourceRead && !m_rSource.is() )
697 {
698 // source file contain useful information and is not opened
699 // open it from the point of noncopied data
700
701 try
702 {
703 m_rSource = m_pContent->openStream();
704 }
705 catch (const Exception&)
706 {
707 // usually means that stream could not be opened
708 }
709
710 if( m_rSource.is() )
711 {
712 m_pStream->Seek( STREAM_SEEK_TO_END((sal_uInt64) 0xFFFFFFFFFFFFFFFFul) );
713
714 try
715 {
716 m_rSource->skipBytes( m_pStream->Tell() );
717 }
718 catch (const BufferSizeExceededException&)
719 {
720 // the temporary stream already contain all the data
721 m_bSourceRead = false;
722 }
723 catch (const Exception&)
724 {
725 // something is really wrong
726 m_bSourceRead = false;
727 OSL_FAIL( "Can not operate original stream!" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "727" ": "), "%s", "Can not operate original stream!"); }
} while (false)
;
728 SetError( SVSTREAM_CANNOT_MAKEErrCode( ErrCodeArea::Io, ErrCodeClass::Create, 25 ) );
729 }
730
731 m_pStream->Seek( 0 );
732 }
733 else
734 {
735 // if the new file is edited then no source exist
736 m_bSourceRead = false;
737 //SetError( SVSTREAM_CANNOT_MAKE );
738 }
739 }
740
741 DBG_ASSERT( m_rSource.is() || !m_bSourceRead, "Unreadable source stream!" )do { if (true && (!(m_rSource.is() || !m_bSourceRead)
)) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"
), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "741" ": "), "%s", "Unreadable source stream!"); } } while
(false)
;
742
743 return true;
744}
745
746void UCBStorageStream_Impl::ReadSourceWriteTemporary()
747{
748 // read source stream till the end and copy all the data to
749 // the current position of the temporary stream
750
751 if( m_bSourceRead )
752 {
753 Sequence<sal_Int8> aData(32000);
754
755 try
756 {
757 sal_uLong aReaded;
758 do
759 {
760 aReaded = m_rSource->readBytes( aData, 32000 );
761 m_pStream->WriteBytes(aData.getArray(), aReaded);
762 } while( aReaded == 32000 );
763 }
764 catch (const Exception &)
765 {
766 TOOLS_WARN_EXCEPTION("sot", "")do { css::uno::Any tools_warn_exception( DbgGetCaughtException
() ); do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sot")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "" << " " << exceptionToString(tools_warn_exception
)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"sot"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "766" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "" << " " << exceptionToString
(tools_warn_exception)), 0); } else { ::std::ostringstream sal_detail_stream
; sal_detail_stream << "" << " " << exceptionToString
(tools_warn_exception); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("sot"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "766" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "" << " " << exceptionToString(tools_warn_exception
)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"sot"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "766" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "" << " " << exceptionToString
(tools_warn_exception)), 0); } else { ::std::ostringstream sal_detail_stream
; sal_detail_stream << "" << " " << exceptionToString
(tools_warn_exception); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("sot"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "766" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false); } while (false)
;
767 }
768 }
769
770 m_bSourceRead = false;
771}
772
773sal_uInt64 UCBStorageStream_Impl::ReadSourceWriteTemporary(sal_uInt64 aLength)
774{
775 // read aLength bite from the source stream and copy them to the current
776 // position of the temporary stream
777
778 sal_uInt64 aResult = 0;
779
780 if( m_bSourceRead )
781 {
782 Sequence<sal_Int8> aData(32000);
783
784 try
785 {
786
787 sal_uLong aReaded = 32000;
788
789 for (sal_uInt64 nInd = 0; nInd < aLength && aReaded == 32000 ; nInd += 32000)
790 {
791 sal_uLong aToCopy = std::min<sal_uInt64>( aLength - nInd, 32000 );
792 aReaded = m_rSource->readBytes( aData, aToCopy );
793 aResult += m_pStream->WriteBytes(aData.getArray(), aReaded);
794 }
795
796 if( aResult < aLength )
797 m_bSourceRead = false;
798 }
799 catch( const Exception & )
800 {
801 TOOLS_WARN_EXCEPTION("sot", "")do { css::uno::Any tools_warn_exception( DbgGetCaughtException
() ); do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sot")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "" << " " << exceptionToString(tools_warn_exception
)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"sot"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "801" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "" << " " << exceptionToString
(tools_warn_exception)), 0); } else { ::std::ostringstream sal_detail_stream
; sal_detail_stream << "" << " " << exceptionToString
(tools_warn_exception); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("sot"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "801" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "" << " " << exceptionToString(tools_warn_exception
)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"sot"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "801" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "" << " " << exceptionToString
(tools_warn_exception)), 0); } else { ::std::ostringstream sal_detail_stream
; sal_detail_stream << "" << " " << exceptionToString
(tools_warn_exception); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("sot"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "801" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false); } while (false)
;
802 }
803 }
804
805 return aResult;
806}
807
808void UCBStorageStream_Impl::CopySourceToTemporary()
809{
810 // current position of the temporary stream is not changed
811 if( m_bSourceRead )
812 {
813 sal_uInt64 aPos = m_pStream->Tell();
814 m_pStream->Seek( STREAM_SEEK_TO_END((sal_uInt64) 0xFFFFFFFFFFFFFFFFul) );
815 ReadSourceWriteTemporary();
816 m_pStream->Seek( aPos );
817 }
818}
819
820// UCBStorageStream_Impl must have a SvStream interface, because it then can be used as underlying stream
821// of an OLEStorage; so every write access caused by storage operations marks the UCBStorageStream as modified
822std::size_t UCBStorageStream_Impl::GetData(void* pData, std::size_t const nSize)
823{
824 std::size_t aResult = 0;
825
826 if( !Init() )
827 return 0;
828
829
830 // read data that is in temporary stream
831 aResult = m_pStream->ReadBytes( pData, nSize );
832 if( m_bSourceRead && aResult < nSize )
833 {
834 // read the tail of the data from original stream
835 // copy this tail to the temporary stream
836
837 std::size_t aToRead = nSize - aResult;
838 pData = static_cast<void*>( static_cast<char*>(pData) + aResult );
839
840 try
841 {
842 Sequence<sal_Int8> aData( aToRead );
843 std::size_t aReaded = m_rSource->readBytes( aData, aToRead );
844 aResult += m_pStream->WriteBytes(static_cast<void*>(aData.getArray()), aReaded);
845 memcpy( pData, aData.getArray(), aReaded );
846 }
847 catch (const Exception &)
848 {
849 TOOLS_WARN_EXCEPTION("sot", "")do { css::uno::Any tools_warn_exception( DbgGetCaughtException
() ); do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sot")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "" << " " << exceptionToString(tools_warn_exception
)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"sot"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "849" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "" << " " << exceptionToString
(tools_warn_exception)), 0); } else { ::std::ostringstream sal_detail_stream
; sal_detail_stream << "" << " " << exceptionToString
(tools_warn_exception); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("sot"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "849" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "" << " " << exceptionToString(tools_warn_exception
)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"sot"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "849" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "" << " " << exceptionToString
(tools_warn_exception)), 0); } else { ::std::ostringstream sal_detail_stream
; sal_detail_stream << "" << " " << exceptionToString
(tools_warn_exception); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("sot"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "849" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false); } while (false)
;
850 }
851
852 if( aResult < nSize )
853 m_bSourceRead = false;
854 }
855
856 return aResult;
857}
858
859std::size_t UCBStorageStream_Impl::PutData(const void* pData, std::size_t const nSize)
860{
861 if ( !(m_nMode & StreamMode::WRITE) )
862 {
863 SetError( ERRCODE_IO_ACCESSDENIEDErrCode( ErrCodeArea::Io, ErrCodeClass::Access, 7 ) );
864 return 0; // ?mav?
865 }
866
867 if( !nSize || !Init() )
868 return 0;
869
870 std::size_t aResult = m_pStream->WriteBytes( pData, nSize );
871
872 m_bModified = aResult > 0;
873
874 return aResult;
875
876}
877
878sal_uInt64 UCBStorageStream_Impl::SeekPos(sal_uInt64 const nPos)
879{
880 // check if a truncated STREAM_SEEK_TO_END was passed
881 assert(nPos != SAL_MAX_UINT32)(static_cast <bool> (nPos != ((sal_uInt32) 0xFFFFFFFF))
? void (0) : __assert_fail ("nPos != SAL_MAX_UINT32", "/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
, 881, __extension__ __PRETTY_FUNCTION__))
;
882
883 if( !Init() )
884 return 0;
885
886 sal_uInt64 aResult;
887
888 if( nPos == STREAM_SEEK_TO_END((sal_uInt64) 0xFFFFFFFFFFFFFFFFul) )
889 {
890 m_pStream->Seek( STREAM_SEEK_TO_END((sal_uInt64) 0xFFFFFFFFFFFFFFFFul) );
891 ReadSourceWriteTemporary();
892 aResult = m_pStream->Tell();
893 }
894 else
895 {
896 // the problem is that even if nPos is larger the length
897 // of the stream, the stream pointer will be moved to this position
898 // so we have to check if temporary stream does not contain required position
899
900 if( m_pStream->Tell() > nPos
901 || m_pStream->Seek( STREAM_SEEK_TO_END((sal_uInt64) 0xFFFFFFFFFFFFFFFFul) ) > nPos )
902 {
903 // no copying is required
904 aResult = m_pStream->Seek( nPos );
905 }
906 else
907 {
908 // the temp stream pointer points to the end now
909 aResult = m_pStream->Tell();
910
911 if( aResult < nPos )
912 {
913 if( m_bSourceRead )
914 {
915 aResult += ReadSourceWriteTemporary( nPos - aResult );
916 if( aResult < nPos )
917 m_bSourceRead = false;
918
919 DBG_ASSERT( aResult == m_pStream->Tell(), "Error in stream arithmetic!\n" )do { if (true && (!(aResult == m_pStream->Tell()))
) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"
), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "919" ": "), "%s", "Error in stream arithmetic!\n"); } }
while (false)
;
920 }
921
922 if( (m_nMode & StreamMode::WRITE) && !m_bSourceRead && aResult < nPos )
923 {
924 // it means that all the Source stream was copied already
925 // but the required position still was not reached
926 // for writable streams it should be done
927 m_pStream->SetStreamSize( nPos );
928 aResult = m_pStream->Seek( STREAM_SEEK_TO_END((sal_uInt64) 0xFFFFFFFFFFFFFFFFul) );
929 DBG_ASSERT( aResult == nPos, "Error in stream arithmetic!\n" )do { if (true && (!(aResult == nPos))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "929" ": "), "%s", "Error in stream arithmetic!\n"); } }
while (false)
;
930 }
931 }
932 }
933 }
934
935 return aResult;
936}
937
938void UCBStorageStream_Impl::SetSize(sal_uInt64 const nSize)
939{
940 if ( !(m_nMode & StreamMode::WRITE) )
941 {
942 SetError( ERRCODE_IO_ACCESSDENIEDErrCode( ErrCodeArea::Io, ErrCodeClass::Access, 7 ) );
943 return;
944 }
945
946 if( !Init() )
947 return;
948
949 m_bModified = true;
950
951 if( m_bSourceRead )
952 {
953 sal_uInt64 const aPos = m_pStream->Tell();
954 m_pStream->Seek( STREAM_SEEK_TO_END((sal_uInt64) 0xFFFFFFFFFFFFFFFFul) );
955 if( m_pStream->Tell() < nSize )
956 ReadSourceWriteTemporary( nSize - m_pStream->Tell() );
957 m_pStream->Seek( aPos );
958 }
959
960 m_pStream->SetStreamSize( nSize );
961 m_bSourceRead = false;
962}
963
964void UCBStorageStream_Impl::FlushData()
965{
966 if( m_pStream )
967 {
968 CopySourceToTemporary();
969 m_pStream->Flush();
970 }
971
972 m_bCommited = true;
973}
974
975void UCBStorageStream_Impl::SetError( ErrCode nErr )
976{
977 if ( !m_nError )
978 {
979 m_nError = nErr;
980 SvStream::SetError( nErr );
981 if ( m_pAntiImpl ) m_pAntiImpl->SetError( nErr );
982 }
983}
984
985void UCBStorageStream_Impl::ResetError()
986{
987 m_nError = ERRCODE_NONEErrCode(0);
988 SvStream::ResetError();
989 if ( m_pAntiImpl )
990 m_pAntiImpl->ResetError();
991}
992
993sal_uLong UCBStorageStream_Impl::GetSize()
994{
995 if( !Init() )
996 return 0;
997
998 sal_uInt64 nPos = m_pStream->Tell();
999 m_pStream->Seek( STREAM_SEEK_TO_END((sal_uInt64) 0xFFFFFFFFFFFFFFFFul) );
1000 ReadSourceWriteTemporary();
1001 sal_uInt64 nRet = m_pStream->Tell();
1002 m_pStream->Seek( nPos );
1003
1004 return nRet;
1005}
1006
1007BaseStorage* UCBStorageStream_Impl::CreateStorage()
1008{
1009 // create an OLEStorage on a SvStream ( = this )
1010 // it gets the root attribute because otherwise it would probably not write before my root is committed
1011 UCBStorageStream* pNewStorageStream = new UCBStorageStream( this );
1012 Storage *pStorage = new Storage( *pNewStorageStream, m_bDirect );
1013
1014 // GetError() call clears error code for OLE storages, must be changed in future
1015 const ErrCode nTmpErr = pStorage->GetError();
1016 pStorage->SetError( nTmpErr );
1017
1018 m_bIsOLEStorage = !nTmpErr;
1019 return static_cast< BaseStorage* > ( pStorage );
1020}
1021
1022sal_Int16 UCBStorageStream_Impl::Commit()
1023{
1024 // send stream to the original content
1025 // the parent storage is responsible for the correct handling of deleted contents
1026 if ( m_bCommited || m_bIsOLEStorage || m_bDirect )
1027 {
1028 // modified streams with OLEStorages on it have autocommit; it is assumed that the OLEStorage
1029 // was committed as well ( if not opened in direct mode )
1030
1031 if ( m_bModified )
1032 {
1033 try
1034 {
1035 CopySourceToTemporary();
1036
1037 // release all stream handles
1038 Free();
1039
1040 // the temporary file does not exist only for truncated streams
1041 DBG_ASSERT( !m_aTempURL.isEmpty() || ( m_nMode & StreamMode::TRUNC ), "No temporary file to read from!")do { if (true && (!(!m_aTempURL.isEmpty() || ( m_nMode
& StreamMode::TRUNC )))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "1041" ": "), "%s", "No temporary file to read from!"); }
} while (false)
;
1042 if ( m_aTempURL.isEmpty() && !( m_nMode & StreamMode::TRUNC ) )
1043 throw RuntimeException();
1044
1045 // create wrapper to stream that is only used while reading inside package component
1046 Reference < XInputStream > xStream = new FileStreamWrapper_Impl( m_aTempURL );
1047
1048 InsertCommandArgument aArg;
1049 aArg.Data = xStream;
1050 aArg.ReplaceExisting = true;
1051 m_pContent->executeCommand( "insert", Any(aArg) );
1052
1053 // wrapper now controls lifetime of temporary file
1054 m_aTempURL.clear();
1055
1056 INetURLObject aObj( m_aURL );
1057 aObj.setName( m_aName );
1058 m_aURL = aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
1059 m_bModified = false;
1060 m_bSourceRead = true;
1061 }
1062 catch (const CommandAbortedException&)
1063 {
1064 // any command wasn't executed successfully - not specified
1065 SetError( ERRCODE_IO_GENERALErrCode( ErrCodeArea::Io, ErrCodeClass::General, 13 ) );
1066 return COMMIT_RESULT_FAILURE0;
1067 }
1068 catch (const RuntimeException&)
1069 {
1070 // any other error - not specified
1071 SetError( ERRCODE_IO_GENERALErrCode( ErrCodeArea::Io, ErrCodeClass::General, 13 ) );
1072 return COMMIT_RESULT_FAILURE0;
1073 }
1074 catch (const Exception&)
1075 {
1076 // any other error - not specified
1077 SetError( ERRCODE_IO_GENERALErrCode( ErrCodeArea::Io, ErrCodeClass::General, 13 ) );
1078 return COMMIT_RESULT_FAILURE0;
1079 }
1080
1081 m_bCommited = false;
1082 return COMMIT_RESULT_SUCCESS2;
1083 }
1084 }
1085
1086 return COMMIT_RESULT_NOTHING_TO_DO1;
1087}
1088
1089void UCBStorageStream_Impl::Revert()
1090{
1091 // if an OLEStorage is created on this stream, no "revert" is necessary because OLEStorages do nothing on "Revert" !
1092 if ( m_bCommited )
1093 {
1094 OSL_FAIL("Revert while commit is in progress!" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "1094" ": "), "%s", "Revert while commit is in progress!"
); } } while (false)
;
1095 return; // ???
1096 }
1097
1098 Free();
1099 if ( !m_aTempURL.isEmpty() )
1100 {
1101 osl::File::remove(m_aTempURL);
1102 m_aTempURL.clear();
1103 }
1104
1105 m_bSourceRead = false;
1106 try
1107 {
1108 m_rSource = m_pContent->openStream();
1109 if( m_rSource.is() )
1110 {
1111 if ( m_pAntiImpl && ( m_nMode & StreamMode::TRUNC ) )
1112 // stream is in use and should be truncated
1113 m_bSourceRead = false;
1114 else
1115 {
1116 m_nMode &= ~StreamMode::TRUNC;
1117 m_bSourceRead = true;
1118 }
1119 }
1120 else
1121 SetError( SVSTREAM_CANNOT_MAKEErrCode( ErrCodeArea::Io, ErrCodeClass::Create, 25 ) );
1122 }
1123 catch (const ContentCreationException&)
1124 {
1125 SetError( ERRCODE_IO_GENERALErrCode( ErrCodeArea::Io, ErrCodeClass::General, 13 ) );
1126 }
1127 catch (const RuntimeException&)
1128 {
1129 SetError( ERRCODE_IO_GENERALErrCode( ErrCodeArea::Io, ErrCodeClass::General, 13 ) );
1130 }
1131 catch (const Exception&)
1132 {
1133 }
1134
1135 m_bModified = false;
1136 m_aName = m_aOriginalName;
1137 m_aContentType = m_aOriginalContentType;
1138}
1139
1140bool UCBStorageStream_Impl::Clear()
1141{
1142 bool bRet = ( m_pAntiImpl == nullptr );
1143 DBG_ASSERT( bRet, "Removing used stream!" )do { if (true && (!(bRet))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "1143" ": "), "%s", "Removing used stream!"); } } while (
false)
;
1144 if( bRet )
1145 {
1146 Free();
1147 }
1148
1149 return bRet;
1150}
1151
1152void UCBStorageStream_Impl::Free()
1153{
1154#if OSL_DEBUG_LEVEL1 > 0
1155 if ( m_pStream )
1156 {
1157 if ( !m_aTempURL.isEmpty() )
1158 --nOpenFiles;
1159 else
1160 --nOpenStreams;
1161 }
1162#endif
1163
1164 m_rSource.clear();
1165 m_pStream.reset();
1166}
1167
1168void UCBStorageStream_Impl::PrepareCachedForReopen( StreamMode nMode )
1169{
1170 bool isWritable = bool( m_nMode & StreamMode::WRITE );
1171 if ( isWritable )
1172 {
1173 // once stream was writable, never reset to readonly
1174 nMode |= StreamMode::WRITE;
1175 }
1176
1177 m_nMode = nMode;
1178 Free();
1179
1180 if ( nMode & StreamMode::TRUNC )
1181 {
1182 m_bSourceRead = false; // usually it should be 0 already but just in case...
1183
1184 if ( !m_aTempURL.isEmpty() )
1185 {
1186 osl::File::remove(m_aTempURL);
1187 m_aTempURL.clear();
1188 }
1189 }
1190}
1191
1192UCBStorageStream::UCBStorageStream( const OUString& rName, StreamMode nMode, bool bDirect, bool bRepair, Reference< XProgressHandler > const & xProgress )
1193{
1194 // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized
1195 // to class UCBStorageStream !
1196 pImp = new UCBStorageStream_Impl( rName, nMode, this, bDirect, bRepair, xProgress );
1197 pImp->AddFirstRef(); // use direct refcounting because in header file only a pointer should be used
1198 StorageBase::m_nMode = pImp->m_nMode;
1199}
1200
1201UCBStorageStream::UCBStorageStream( UCBStorageStream_Impl *pImpl )
1202 : pImp( pImpl )
1203{
1204 pImp->AddFirstRef(); // use direct refcounting because in header file only a pointer should be used
1205 pImp->m_pAntiImpl = this;
1206 SetError( pImp->m_nError );
1207 StorageBase::m_nMode = pImp->m_nMode;
1208}
1209
1210UCBStorageStream::~UCBStorageStream()
1211{
1212 if ( pImp->m_nMode & StreamMode::WRITE )
1213 pImp->Flush();
1214 pImp->m_pAntiImpl = nullptr;
1215 pImp->Free();
1216 pImp->ReleaseRef();
1217}
1218
1219sal_uLong UCBStorageStream::Read( void * pData, sal_uLong nSize )
1220{
1221 //return pImp->m_pStream->Read( pData, nSize );
1222 return pImp->GetData( pData, nSize );
1223}
1224
1225sal_uLong UCBStorageStream::Write( const void* pData, sal_uLong nSize )
1226{
1227 return pImp->PutData( pData, nSize );
1228}
1229
1230sal_uInt64 UCBStorageStream::Seek( sal_uInt64 nPos )
1231{
1232 //return pImp->m_pStream->Seek( nPos );
1233 return pImp->Seek( nPos );
1234}
1235
1236sal_uLong UCBStorageStream::Tell()
1237{
1238 if( !pImp->Init() )
1239 return 0;
1240 return pImp->m_pStream->Tell();
1241}
1242
1243void UCBStorageStream::Flush()
1244{
1245 // streams are never really transacted, so flush also means commit !
1246 Commit();
1247}
1248
1249bool UCBStorageStream::SetSize( sal_uLong nNewSize )
1250{
1251 pImp->SetSize( nNewSize );
1252 return !pImp->GetError();
1253}
1254
1255bool UCBStorageStream::Validate( bool bWrite ) const
1256{
1257 return ( !bWrite || ( pImp->m_nMode & StreamMode::WRITE ) );
1258}
1259
1260bool UCBStorageStream::ValidateMode( StreamMode m ) const
1261{
1262 // ???
1263 if( m == ( StreamMode::READ | StreamMode::TRUNC ) ) // from stg.cxx
1264 return true;
1265 if( ( m & StreamMode::READWRITE) == StreamMode::READ )
1266 {
1267 // only SHARE_DENYWRITE or SHARE_DENYALL allowed
1268 if( ( m & StreamMode::SHARE_DENYWRITE )
1269 || ( m & StreamMode::SHARE_DENYALL ) )
1270 return true;
1271 }
1272 else
1273 {
1274 // only SHARE_DENYALL allowed
1275 // storages open in r/o mode are OK, since only
1276 // the commit may fail
1277 if( m & StreamMode::SHARE_DENYALL )
1278 return true;
1279 }
1280
1281 return true;
1282}
1283
1284SvStream* UCBStorageStream::GetModifySvStream()
1285{
1286 return static_cast<SvStream*>(pImp);
1287}
1288
1289bool UCBStorageStream::Equals( const BaseStorageStream& rStream ) const
1290{
1291 // ???
1292 return static_cast<BaseStorageStream const *>(this) == &rStream;
1293}
1294
1295bool UCBStorageStream::Commit()
1296{
1297 // mark this stream for sending it on root commit
1298 pImp->FlushData();
1299 return true;
1300}
1301
1302void UCBStorageStream::CopyTo( BaseStorageStream* pDestStm )
1303{
1304 if( !pImp->Init() )
1305 return;
1306
1307 UCBStorageStream* pStg = dynamic_cast<UCBStorageStream*>( pDestStm );
1308 if ( pStg )
1309 pStg->pImp->m_aContentType = pImp->m_aContentType;
1310
1311 pDestStm->SetSize( 0 );
1312 Seek( STREAM_SEEK_TO_END((sal_uInt64) 0xFFFFFFFFFFFFFFFFul) );
1313 sal_Int32 n = Tell();
1314 if( n < 0 )
1315 return;
1316
1317 if( !pDestStm->SetSize( n ) || !n )
1318 return;
1319
1320 std::unique_ptr<sal_uInt8[]> p(new sal_uInt8[ 4096 ]);
1321 Seek( 0 );
1322 pDestStm->Seek( 0 );
1323 while( n )
1324 {
1325 sal_uInt32 nn = n;
1326 if( nn > 4096 )
1327 nn = 4096;
1328 if( Read( p.get(), nn ) != nn )
1329 break;
1330 if( pDestStm->Write( p.get(), nn ) != nn )
1331 break;
1332 n -= nn;
1333 }
1334}
1335
1336bool UCBStorageStream::SetProperty( const OUString& rName, const css::uno::Any& rValue )
1337{
1338 if ( rName == "Title")
1339 return false;
1340
1341 if ( rName == "MediaType")
1342 {
1343 OUString aTmp;
1344 rValue >>= aTmp;
1345 pImp->m_aContentType = aTmp;
1346 }
1347
1348 try
1349 {
1350 if ( pImp->m_pContent )
1351 {
1352 pImp->m_pContent->setPropertyValue( rName, rValue );
1353 return true;
1354 }
1355 }
1356 catch (const Exception&)
1357 {
1358 }
1359
1360 return false;
1361}
1362
1363sal_uLong UCBStorageStream::GetSize() const
1364{
1365 return pImp->GetSize();
1366}
1367
1368UCBStorage::UCBStorage( SvStream& rStrm, bool bDirect )
1369{
1370 // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized
1371 // to class UCBStorage !
1372 pImp = new UCBStorage_Impl( rStrm, this, bDirect );
1373
1374 pImp->AddFirstRef();
1375 pImp->Init();
1376 StorageBase::m_nMode = pImp->m_nMode;
1377}
1378
1379UCBStorage::UCBStorage( const ::ucbhelper::Content& rContent, const OUString& rName, StreamMode nMode, bool bDirect, bool bIsRoot )
1380{
1381 // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized
1382 // to class UCBStorage !
1383 pImp = new UCBStorage_Impl( rContent, rName, nMode, this, bDirect, bIsRoot );
1384 pImp->AddFirstRef();
1385 pImp->Init();
1386 StorageBase::m_nMode = pImp->m_nMode;
1387}
1388
1389UCBStorage::UCBStorage( const OUString& rName, StreamMode nMode, bool bDirect, bool bIsRoot, bool bIsRepair, Reference< XProgressHandler > const & xProgressHandler )
1390{
1391 // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized
1392 // to class UCBStorage !
1393 pImp = new UCBStorage_Impl( rName, nMode, this, bDirect, bIsRoot, bIsRepair, xProgressHandler );
1394 pImp->AddFirstRef();
1395 pImp->Init();
1396 StorageBase::m_nMode = pImp->m_nMode;
1397}
1398
1399UCBStorage::UCBStorage( const OUString& rName, StreamMode nMode, bool bDirect, bool bIsRoot )
1400{
1401 // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized
1402 // to class UCBStorage !
1403 pImp = new UCBStorage_Impl( rName, nMode, this, bDirect, bIsRoot, false, Reference< XProgressHandler >() );
1404 pImp->AddFirstRef();
1405 pImp->Init();
1406 StorageBase::m_nMode = pImp->m_nMode;
1407}
1408
1409UCBStorage::UCBStorage( UCBStorage_Impl *pImpl )
1410 : pImp( pImpl )
1411{
1412 pImp->m_pAntiImpl = this;
1413 SetError( pImp->m_nError );
1414 pImp->AddFirstRef(); // use direct refcounting because in header file only a pointer should be used
1415 StorageBase::m_nMode = pImp->m_nMode;
1416}
1417
1418UCBStorage::~UCBStorage()
1419{
1420 if ( pImp->m_bIsRoot && pImp->m_bDirect && ( !pImp->m_pTempFile || pImp->m_pSource ) )
1421 // DirectMode is simulated with an AutoCommit
1422 Commit();
1423
1424 pImp->m_pAntiImpl = nullptr;
1425 pImp->ReleaseRef();
1426}
1427
1428UCBStorage_Impl::UCBStorage_Impl( const ::ucbhelper::Content& rContent, const OUString& rName, StreamMode nMode, UCBStorage* pStorage, bool bDirect, bool bIsRoot, bool bIsRepair, Reference< XProgressHandler > const & xProgressHandler )
1429 : m_pAntiImpl( pStorage )
1430 , m_pContent( new ::ucbhelper::Content( rContent ) )
1431 , m_pSource( nullptr )
1432 //, m_pStream( NULL )
1433 , m_nError( ERRCODE_NONEErrCode(0) )
1434 , m_nMode( nMode )
1435 , m_bCommited( false )
1436 , m_bDirect( bDirect )
1437 , m_bIsRoot( bIsRoot )
1438 , m_bIsLinked( true )
1439 , m_bListCreated( false )
1440 , m_nFormat( SotClipboardFormatId::NONE )
1441 , m_aClassId( SvGlobalName() )
1442 , m_bRepairPackage( bIsRepair )
1443 , m_xProgressHandler( xProgressHandler )
1444{
1445 OUString aName( rName );
1446 if( aName.isEmpty() )
1447 {
1448 // no name given = use temporary name!
1449 DBG_ASSERT( m_bIsRoot, "SubStorage must have a name!" )do { if (true && (!(m_bIsRoot))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "1449" ": "), "%s", "SubStorage must have a name!"); } }
while (false)
;
1450 m_pTempFile.reset(new ::utl::TempFile);
1451 m_pTempFile->EnableKillingFile();
1452 m_aName = aName = m_pTempFile->GetURL();
1453 }
1454
1455 m_aURL = rName;
1456}
1457
1458UCBStorage_Impl::UCBStorage_Impl( const OUString& rName, StreamMode nMode, UCBStorage* pStorage, bool bDirect, bool bIsRoot, bool bIsRepair, Reference< XProgressHandler > const & xProgressHandler )
1459 : m_pAntiImpl( pStorage )
1460 , m_pSource( nullptr )
1461 //, m_pStream( NULL )
1462 , m_nError( ERRCODE_NONEErrCode(0) )
1463 , m_nMode( nMode )
1464 , m_bCommited( false )
1465 , m_bDirect( bDirect )
1466 , m_bIsRoot( bIsRoot )
1467 , m_bIsLinked( false )
1468 , m_bListCreated( false )
1469 , m_nFormat( SotClipboardFormatId::NONE )
1470 , m_aClassId( SvGlobalName() )
1471 , m_bRepairPackage( bIsRepair )
1472 , m_xProgressHandler( xProgressHandler )
1473{
1474 OUString aName( rName );
1475 if( aName.isEmpty() )
1476 {
1477 // no name given = use temporary name!
1478 DBG_ASSERT( m_bIsRoot, "SubStorage must have a name!" )do { if (true && (!(m_bIsRoot))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "1478" ": "), "%s", "SubStorage must have a name!"); } }
while (false)
;
1479 m_pTempFile.reset(new ::utl::TempFile);
1480 m_pTempFile->EnableKillingFile();
1481 m_aName = aName = m_pTempFile->GetURL();
1482 }
1483
1484 if ( m_bIsRoot )
1485 {
1486 // create the special package URL for the package content
1487 m_aURL = "vnd.sun.star.pkg://" +
1488 INetURLObject::encode( aName, INetURLObject::PART_AUTHORITY, INetURLObject::EncodeMechanism::All );
1489
1490 if ( m_nMode & StreamMode::WRITE )
1491 {
1492 // the root storage opens the package, so make sure that there is any
1493 ::utl::UcbStreamHelper::CreateStream( aName, StreamMode::STD_READWRITE, m_pTempFile != nullptr /* bFileExists */ );
1494 }
1495 }
1496 else
1497 {
1498 // substorages are opened like streams: the URL is a "child URL" of the root package URL
1499 m_aURL = rName;
1500 if ( !m_aURL.startsWith( "vnd.sun.star.pkg://") )
1501 m_bIsLinked = true;
1502 }
1503}
1504
1505UCBStorage_Impl::UCBStorage_Impl( SvStream& rStream, UCBStorage* pStorage, bool bDirect )
1506 : m_pAntiImpl( pStorage )
1507 , m_pTempFile( new ::utl::TempFile )
1508 , m_pSource( &rStream )
1509 , m_nError( ERRCODE_NONEErrCode(0) )
1510 , m_bCommited( false )
1511 , m_bDirect( bDirect )
1512 , m_bIsRoot( true )
1513 , m_bIsLinked( false )
1514 , m_bListCreated( false )
1515 , m_nFormat( SotClipboardFormatId::NONE )
1516 , m_aClassId( SvGlobalName() )
1517 , m_bRepairPackage( false )
1518{
1519 // opening in direct mode is too fuzzy because the data is transferred to the stream in the Commit() call,
1520 // which will be called in the storages' dtor
1521 m_pTempFile->EnableKillingFile();
1522 DBG_ASSERT( !bDirect, "Storage on a stream must not be opened in direct mode!" )do { if (true && (!(!bDirect))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "1522" ": "), "%s", "Storage on a stream must not be opened in direct mode!"
); } } while (false)
;
1523
1524 // UCBStorages work on a content, so a temporary file for a content must be created, even if the stream is only
1525 // accessed readonly
1526 // the root storage opens the package; create the special package URL for the package content
1527 m_aURL = "vnd.sun.star.pkg://" +
1528 INetURLObject::encode( m_pTempFile->GetURL(), INetURLObject::PART_AUTHORITY, INetURLObject::EncodeMechanism::All );
1529
1530 // copy data into the temporary file
1531 std::unique_ptr<SvStream> pStream(::utl::UcbStreamHelper::CreateStream( m_pTempFile->GetURL(), StreamMode::STD_READWRITE, true /* bFileExists */ ));
1532 if ( pStream )
1533 {
1534 rStream.Seek(0);
1535 rStream.ReadStream( *pStream );
1536 pStream->Flush();
1537 pStream.reset();
1538 }
1539
1540 // close stream and let content access the file
1541 m_pSource->Seek(0);
1542
1543 // check opening mode
1544 m_nMode = StreamMode::READ;
1545 if( rStream.IsWritable() )
1546 m_nMode = StreamMode::READ | StreamMode::WRITE;
1547}
1548
1549void UCBStorage_Impl::Init()
1550{
1551 // name is last segment in URL
1552 INetURLObject aObj( m_aURL );
1553 if ( m_aName.isEmpty() )
1554 // if the name was not already set to a temp name
1555 m_aName = aObj.GetLastName();
1556
1557 if ( !m_pContent )
1558 CreateContent();
1559
1560 if ( m_pContent )
1561 {
1562 if ( m_bIsLinked )
1563 {
1564 if( m_bIsRoot )
1565 {
1566 ReadContent();
1567 if ( m_nError == ERRCODE_NONEErrCode(0) )
1568 {
1569 // read the manifest.xml file
1570 aObj.Append( "META-INF" );
1571 aObj.Append( "manifest.xml" );
1572
1573 // create input stream
1574 std::unique_ptr<SvStream> pStream(::utl::UcbStreamHelper::CreateStream( aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ), StreamMode::STD_READ ));
1575 // no stream means no manifest.xml
1576 if ( pStream )
1577 {
1578 if ( !pStream->GetError() )
1579 {
1580 ::utl::OInputStreamWrapper* pHelper = new ::utl::OInputStreamWrapper( *pStream );
1581 css::uno::Reference < css::io::XInputStream > xInputStream( pHelper );
1582
1583 // create a manifest reader object that will read in the manifest from the stream
1584 Reference < css::packages::manifest::XManifestReader > xReader =
1585 css::packages::manifest::ManifestReader::create(
1586 ::comphelper::getProcessComponentContext() ) ;
1587 Sequence < Sequence < PropertyValue > > aProps = xReader->readManifestSequence( xInputStream );
1588
1589 // cleanup
1590 xReader = nullptr;
1591 xInputStream = nullptr;
1592 SetProps( aProps, OUString() );
1593 }
1594 }
1595 }
1596 }
1597 else
1598 ReadContent();
1599 }
1600 else
1601 {
1602 // get the manifest information from the package
1603 try {
1604 Any aAny = m_pContent->getPropertyValue("MediaType");
1605 OUString aTmp;
1606 if ( ( aAny >>= aTmp ) && !aTmp.isEmpty() )
1607 m_aContentType = m_aOriginalContentType = aTmp;
1608 }
1609 catch (const Exception&)
1610 {
1611 SAL_WARN( "sot",do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sot")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "getPropertyValue has thrown an exception! Please let developers know the scenario!"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sot"
), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "1612" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "getPropertyValue has thrown an exception! Please let developers know the scenario!"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "getPropertyValue has thrown an exception! Please let developers know the scenario!"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sot"),
("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "1612" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "getPropertyValue has thrown an exception! Please let developers know the scenario!"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sot"
), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "1612" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "getPropertyValue has thrown an exception! Please let developers know the scenario!"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "getPropertyValue has thrown an exception! Please let developers know the scenario!"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sot"),
("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "1612" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
1612 "getPropertyValue has thrown an exception! Please let developers know the scenario!" )do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sot")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "getPropertyValue has thrown an exception! Please let developers know the scenario!"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sot"
), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "1612" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "getPropertyValue has thrown an exception! Please let developers know the scenario!"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "getPropertyValue has thrown an exception! Please let developers know the scenario!"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sot"),
("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "1612" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "getPropertyValue has thrown an exception! Please let developers know the scenario!"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sot"
), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "1612" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "getPropertyValue has thrown an exception! Please let developers know the scenario!"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "getPropertyValue has thrown an exception! Please let developers know the scenario!"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sot"),
("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "1612" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1613 }
1614 }
1615 }
1616
1617 if ( m_aContentType.isEmpty() )
1618 return;
1619
1620 // get the clipboard format using the content type
1621 css::datatransfer::DataFlavor aDataFlavor;
1622 aDataFlavor.MimeType = m_aContentType;
1623 m_nFormat = SotExchange::GetFormat( aDataFlavor );
1624
1625 // get the ClassId using the clipboard format ( internal table )
1626 m_aClassId = GetClassId_Impl( m_nFormat );
1627
1628 // get human presentable name using the clipboard format
1629 SotExchange::GetFormatDataFlavor( m_nFormat, aDataFlavor );
1630 m_aUserTypeName = aDataFlavor.HumanPresentableName;
1631
1632 if( m_pContent && !m_bIsLinked && m_aClassId != SvGlobalName() )
1633 ReadContent();
1634}
1635
1636void UCBStorage_Impl::CreateContent()
1637{
1638 try
1639 {
1640 // create content; where to put StreamMode ?! ( already done when opening the file of the package ? )
1641 Reference< css::ucb::XCommandEnvironment > xComEnv;
1642
1643 OUString aTemp( m_aURL );
1644
1645 if ( m_bRepairPackage )
1646 {
1647 xComEnv = new ::ucbhelper::CommandEnvironment( Reference< css::task::XInteractionHandler >(),
1648 m_xProgressHandler );
1649 aTemp += "?repairpackage";
1650 }
1651
1652 m_pContent.reset(new ::ucbhelper::Content( aTemp, xComEnv, comphelper::getProcessComponentContext() ));
1653 }
1654 catch (const ContentCreationException&)
1655 {
1656 // content could not be created
1657 SetError( SVSTREAM_CANNOT_MAKEErrCode( ErrCodeArea::Io, ErrCodeClass::Create, 25 ) );
1658 }
1659 catch (const RuntimeException&)
1660 {
1661 // any other error - not specified
1662 SetError( SVSTREAM_CANNOT_MAKEErrCode( ErrCodeArea::Io, ErrCodeClass::Create, 25 ) );
1663 }
1664}
1665
1666void UCBStorage_Impl::ReadContent()
1667{
1668 if ( m_bListCreated )
1669 return;
1670
1671 m_bListCreated = true;
1672
1673 // create cursor for access to children
1674 Sequence< OUString > aProps(4);
1675 aProps[0] = "Title";
1676 aProps[1] = "IsFolder";
1677 aProps[2] = "MediaType";
1678 aProps[3] = "Size";
1679
1680 try
1681 {
1682 GetContent();
1683 if ( !m_pContent )
1684 return;
1685
1686 Reference< XResultSet > xResultSet = m_pContent->createCursor( aProps, ::ucbhelper::INCLUDE_FOLDERS_AND_DOCUMENTS );
1687 Reference< XRow > xRow( xResultSet, UNO_QUERY );
1688 if ( xResultSet.is() )
1689 {
1690 while ( xResultSet->next() )
1691 {
1692 // insert all into the children list
1693 OUString aTitle( xRow->getString(1) );
1694 if ( m_bIsLinked )
1695 {
1696 // unpacked storages have to deal with the meta-inf folder by themselves
1697 if ( aTitle == "META-INF" )
1698 continue;
1699 }
1700
1701 bool bIsFolder( xRow->getBoolean(2) );
1702 sal_Int64 nSize = xRow->getLong(4);
1703 UCBStorageElement_Impl* pElement = new UCBStorageElement_Impl( aTitle, bIsFolder, static_cast<sal_uLong>(nSize) );
1704 m_aChildrenList.emplace_back( pElement );
1705
1706 bool bIsOfficeDocument = m_bIsLinked || ( m_aClassId != SvGlobalName() );
1707 if ( bIsFolder )
1708 {
1709 if ( m_bIsLinked )
1710 OpenStorage( pElement, m_nMode, m_bDirect );
1711 if ( pElement->m_xStorage.is() )
1712 pElement->m_xStorage->Init();
1713 }
1714 else if ( bIsOfficeDocument )
1715 {
1716 // streams can be external OLE objects, so they are now folders, but storages!
1717 OUString aName( m_aURL + "/" + xRow->getString(1));
1718
1719 Reference< css::ucb::XCommandEnvironment > xComEnv;
1720 if ( m_bRepairPackage )
1721 {
1722 xComEnv = new ::ucbhelper::CommandEnvironment( Reference< css::task::XInteractionHandler >(),
1723 m_xProgressHandler );
1724 aName += "?repairpackage";
1725 }
1726
1727 ::ucbhelper::Content aContent( aName, xComEnv, comphelper::getProcessComponentContext() );
1728
1729 OUString aMediaType;
1730 Any aAny = aContent.getPropertyValue("MediaType");
1731 if ( ( aAny >>= aMediaType ) && ( aMediaType == "application/vnd.sun.star.oleobject" ) )
1732 pElement->m_bIsStorage = true;
1733 else if ( aMediaType.isEmpty() )
1734 {
1735 // older files didn't have that special content type, so they must be detected
1736 OpenStream( pElement, StreamMode::STD_READ, m_bDirect );
1737 if ( Storage::IsStorageFile( pElement->m_xStream.get() ) )
1738 pElement->m_bIsStorage = true;
1739 else
1740 pElement->m_xStream->Free();
1741 }
1742 }
1743 }
1744 }
1745 }
1746 catch (const InteractiveIOException& r)
1747 {
1748 if ( r.Code != IOErrorCode_NOT_EXISTING )
1749 SetError( ERRCODE_IO_GENERALErrCode( ErrCodeArea::Io, ErrCodeClass::General, 13 ) );
1750 }
1751 catch (const CommandAbortedException&)
1752 {
1753 // any command wasn't executed successfully - not specified
1754 if ( !( m_nMode & StreamMode::WRITE ) )
1755 // if the folder was just inserted and not already committed, this is not an error!
1756 SetError( ERRCODE_IO_GENERALErrCode( ErrCodeArea::Io, ErrCodeClass::General, 13 ) );
1757 }
1758 catch (const RuntimeException&)
1759 {
1760 // any other error - not specified
1761 SetError( ERRCODE_IO_GENERALErrCode( ErrCodeArea::Io, ErrCodeClass::General, 13 ) );
1762 }
1763 catch (const ResultSetException&)
1764 {
1765 // means that the package file is broken
1766 SetError( ERRCODE_IO_BROKENPACKAGEErrCode( ErrCodeArea::Io, ErrCodeClass::Format, 38 ) );
1767 }
1768 catch (const SQLException&)
1769 {
1770 // means that the file can be broken
1771 SetError( ERRCODE_IO_WRONGFORMATErrCode( ErrCodeArea::Io, ErrCodeClass::Format, 21 ) );
1772 }
1773 catch (const Exception&)
1774 {
1775 // any other error - not specified
1776 SetError( ERRCODE_IO_GENERALErrCode( ErrCodeArea::Io, ErrCodeClass::General, 13 ) );
1777 }
1778}
1779
1780void UCBStorage_Impl::SetError( ErrCode nError )
1781{
1782 if ( !m_nError )
1783 {
1784 m_nError = nError;
1785 if ( m_pAntiImpl ) m_pAntiImpl->SetError( nError );
1786 }
1787}
1788
1789sal_Int32 UCBStorage_Impl::GetObjectCount()
1790{
1791 sal_Int32 nCount = m_aChildrenList.size();
1792 for (auto& pElement : m_aChildrenList)
1793 {
1794 DBG_ASSERT( !pElement->m_bIsFolder || pElement->m_xStorage.is(), "Storage should be open!" )do { if (true && (!(!pElement->m_bIsFolder || pElement
->m_xStorage.is()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "1794" ": "), "%s", "Storage should be open!"); } } while
(false)
;
1795 if ( pElement->m_bIsFolder && pElement->m_xStorage.is() )
1796 nCount += pElement->m_xStorage->GetObjectCount();
1797 }
1798
1799 return nCount;
1800}
1801
1802static OUString Find_Impl( const Sequence < Sequence < PropertyValue > >& rSequence, const OUString& rPath )
1803{
1804 bool bFound = false;
1805 for ( const Sequence < PropertyValue >& rMyProps : rSequence )
1806 {
1807 OUString aType;
1808
1809 for ( const PropertyValue& rAny : rMyProps )
1810 {
1811 if ( rAny.Name == "FullPath" )
1812 {
1813 OUString aTmp;
1814 if ( ( rAny.Value >>= aTmp ) && aTmp == rPath )
1815 bFound = true;
1816 if ( !aType.isEmpty() )
1817 break;
1818 }
1819 else if ( rAny.Name == "MediaType" )
1820 {
1821 if ( ( rAny.Value >>= aType ) && !aType.isEmpty() && bFound )
1822 break;
1823 }
1824 }
1825
1826 if ( bFound )
1827 return aType;
1828 }
1829
1830 return OUString();
1831}
1832
1833void UCBStorage_Impl::SetProps( const Sequence < Sequence < PropertyValue > >& rSequence, const OUString& rPath )
1834{
1835 OUString aPath( rPath );
1836 if ( !m_bIsRoot )
1837 aPath += m_aName;
1838 aPath += "/";
1839
1840 m_aContentType = m_aOriginalContentType = Find_Impl( rSequence, aPath );
1841
1842 if ( m_bIsRoot )
1843 // the "FullPath" of a child always starts without '/'
1844 aPath.clear();
1845
1846 for (auto& pElement : m_aChildrenList)
1847 {
1848 DBG_ASSERT( !pElement->m_bIsFolder || pElement->m_xStorage.is(), "Storage should be open!" )do { if (true && (!(!pElement->m_bIsFolder || pElement
->m_xStorage.is()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "1848" ": "), "%s", "Storage should be open!"); } } while
(false)
;
1849 if ( pElement->m_bIsFolder && pElement->m_xStorage.is() )
1850 pElement->m_xStorage->SetProps( rSequence, aPath );
1851 else
1852 {
1853 OUString aElementPath = aPath + pElement->m_aName;
1854 pElement->SetContentType( Find_Impl( rSequence, aElementPath ) );
1855 }
1856 }
1857
1858 if ( m_aContentType.isEmpty() )
1859 return;
1860
1861 // get the clipboard format using the content type
1862 css::datatransfer::DataFlavor aDataFlavor;
1863 aDataFlavor.MimeType = m_aContentType;
1864 m_nFormat = SotExchange::GetFormat( aDataFlavor );
1865
1866 // get the ClassId using the clipboard format ( internal table )
1867 m_aClassId = GetClassId_Impl( m_nFormat );
1868
1869 // get human presentable name using the clipboard format
1870 SotExchange::GetFormatDataFlavor( m_nFormat, aDataFlavor );
1871 m_aUserTypeName = aDataFlavor.HumanPresentableName;
1872}
1873
1874void UCBStorage_Impl::GetProps( sal_Int32& nProps, Sequence < Sequence < PropertyValue > >& rSequence, const OUString& rPath )
1875{
1876 // first my own properties
1877 Sequence < PropertyValue > aProps(2);
1878
1879 // first property is the "FullPath" name
1880 // it's '/' for the root storage and m_aName for each element, followed by a '/' if it's a folder
1881 OUString aPath( rPath );
1882 if ( !m_bIsRoot )
1883 aPath += m_aName;
1884 aPath += "/";
1885 aProps[0].Name = "MediaType";
1886 aProps[0].Value <<= m_aContentType;
1887 aProps[1].Name = "FullPath";
1888 aProps[1].Value <<= aPath;
1889 rSequence[ nProps++ ] = aProps;
1890
1891 if ( m_bIsRoot )
1892 // the "FullPath" of a child always starts without '/'
1893 aPath.clear();
1894
1895 // now the properties of my elements
1896 for (auto& pElement : m_aChildrenList)
1897 {
1898 DBG_ASSERT( !pElement->m_bIsFolder || pElement->m_xStorage.is(), "Storage should be open!" )do { if (true && (!(!pElement->m_bIsFolder || pElement
->m_xStorage.is()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "1898" ": "), "%s", "Storage should be open!"); } } while
(false)
;
1899 if ( pElement->m_bIsFolder && pElement->m_xStorage.is() )
1900 // storages add there properties by themselves ( see above )
1901 pElement->m_xStorage->GetProps( nProps, rSequence, aPath );
1902 else
1903 {
1904 // properties of streams
1905 OUString aElementPath = aPath + pElement->m_aName;
1906 aProps[0].Name = "MediaType";
1907 aProps[0].Value <<= pElement->GetContentType();
1908 aProps[1].Name = "FullPath";
1909 aProps[1].Value <<= aElementPath;
1910 rSequence[ nProps++ ] = aProps;
1911 }
1912 }
1913}
1914
1915UCBStorage_Impl::~UCBStorage_Impl()
1916{
1917 m_aChildrenList.clear();
1918
1919 m_pContent.reset();
1920 m_pTempFile.reset();
1921}
1922
1923bool UCBStorage_Impl::Insert( ::ucbhelper::Content *pContent )
1924{
1925 // a new substorage is inserted into a UCBStorage ( given by the parameter pContent )
1926 // it must be inserted with a title and a type
1927 bool bRet = false;
1928
1929 try
1930 {
1931 const Sequence< ContentInfo > aInfo = pContent->queryCreatableContentsInfo();
1932 if ( !aInfo.hasElements() )
1933 return false;
1934
1935 for ( const ContentInfo & rCurr : aInfo )
1936 {
1937 // Simply look for the first KIND_FOLDER...
1938 if ( rCurr.Attributes & ContentInfoAttribute::KIND_FOLDER )
1939 {
1940 // Make sure the only required bootstrap property is "Title",
1941 const Sequence< Property > & rProps = rCurr.Properties;
1942 if ( rProps.getLength() != 1 )
1943 continue;
1944
1945 if ( rProps[ 0 ].Name != "Title" )
1946 continue;
1947
1948 Sequence < OUString > aNames { "Title" };
1949 Sequence < Any > aValues(1);
1950 aValues[0] <<= m_aName;
1951
1952 Content aNewFolder;
1953 if ( !pContent->insertNewContent( rCurr.Type, aNames, aValues, aNewFolder ) )
1954 continue;
1955
1956 // remove old content, create an "empty" new one and initialize it with the new inserted
1957 m_pContent.reset(new ::ucbhelper::Content( aNewFolder ));
1958 bRet = true;
1959 }
1960 }
1961 }
1962 catch (const CommandAbortedException&)
1963 {
1964 // any command wasn't executed successfully - not specified
1965 SetError( ERRCODE_IO_GENERALErrCode( ErrCodeArea::Io, ErrCodeClass::General, 13 ) );
1966 }
1967 catch (const RuntimeException&)
1968 {
1969 // any other error - not specified
1970 SetError( ERRCODE_IO_GENERALErrCode( ErrCodeArea::Io, ErrCodeClass::General, 13 ) );
1971 }
1972 catch (const Exception&)
1973 {
1974 // any other error - not specified
1975 SetError( ERRCODE_IO_GENERALErrCode( ErrCodeArea::Io, ErrCodeClass::General, 13 ) );
1976 }
1977
1978 return bRet;
1979}
1980
1981sal_Int16 UCBStorage_Impl::Commit()
1982{
1983 // send all changes to the package
1984 sal_Int16 nRet = COMMIT_RESULT_NOTHING_TO_DO1;
1985
1986 // there is nothing to do if the storage has been opened readonly or if it was opened in transacted mode and no
1987 // commit command has been sent
1988 if ( ( m_nMode & StreamMode::WRITE ) && ( m_bCommited || m_bDirect ) )
1989 {
1990 try
1991 {
1992 // all errors will be caught in the "catch" statement outside the loop
1993 for ( size_t i = 0; i < m_aChildrenList.size() && nRet; ++i )
1994 {
1995 auto& pElement = m_aChildrenList[ i ];
1996 ::ucbhelper::Content* pContent = pElement->GetContent();
1997 std::unique_ptr< ::ucbhelper::Content > xDeleteContent;
1998 if ( !pContent && pElement->IsModified() )
1999 {
2000 // if the element has never been opened, no content has been created until now
2001 OUString aName = m_aURL + "/" + pElement->m_aOriginalName;
2002 pContent = new ::ucbhelper::Content( aName, Reference< css::ucb::XCommandEnvironment >(), comphelper::getProcessComponentContext() );
2003 xDeleteContent.reset(pContent); // delete it later on exit scope
2004 }
2005
2006 if ( pElement->m_bIsRemoved )
2007 {
2008 // was it inserted, then removed (so there would be nothing to do!)
2009 if ( !pElement->m_bIsInserted )
2010 {
2011 // first remove all open stream handles
2012 if (pContent && (!pElement->m_xStream.is() || pElement->m_xStream->Clear()))
2013 {
2014 pContent->executeCommand( "delete", makeAny( true ) );
2015 nRet = COMMIT_RESULT_SUCCESS2;
2016 }
2017 else
2018 // couldn't release stream because there are external references to it
2019 nRet = COMMIT_RESULT_FAILURE0;
2020 }
2021 }
2022 else
2023 {
2024 sal_Int16 nLocalRet = COMMIT_RESULT_NOTHING_TO_DO1;
2025 if ( pElement->m_xStorage.is() )
2026 {
2027 // element is a storage
2028 // do a commit in the following cases:
2029 // - if storage is already inserted, and changed
2030 // - storage is not in a package
2031 // - it's a new storage, try to insert and commit if successful inserted
2032 if ( !pElement->m_bIsInserted || m_bIsLinked || pElement->m_xStorage->Insert( m_pContent.get() ) )
2033 {
2034 nLocalRet = pElement->m_xStorage->Commit();
2035 pContent = pElement->GetContent();
2036 }
2037 }
2038 else if ( pElement->m_xStream.is() )
2039 {
2040 // element is a stream
2041 nLocalRet = pElement->m_xStream->Commit();
2042 if ( pElement->m_xStream->m_bIsOLEStorage )
2043 {
2044 // OLE storage should be stored encrypted, if the storage uses encryption
2045 pElement->m_xStream->m_aContentType = "application/vnd.sun.star.oleobject";
2046 Any aValue;
2047 aValue <<= true;
2048 pElement->m_xStream->m_pContent->setPropertyValue("Encrypted", aValue );
2049 }
2050
2051 pContent = pElement->GetContent();
2052 }
2053
2054 if (pContent && pElement->m_aName != pElement->m_aOriginalName)
2055 {
2056 // name ( title ) of the element was changed
2057 nLocalRet = COMMIT_RESULT_SUCCESS2;
2058 pContent->setPropertyValue("Title", Any(pElement->m_aName) );
2059 }
2060
2061 if (pContent && pElement->IsLoaded() && pElement->GetContentType() != pElement->GetOriginalContentType())
2062 {
2063 // mediatype of the element was changed
2064 nLocalRet = COMMIT_RESULT_SUCCESS2;
2065 pContent->setPropertyValue("MediaType", Any(pElement->GetContentType()) );
2066 }
2067
2068 if ( nLocalRet != COMMIT_RESULT_NOTHING_TO_DO1 )
2069 nRet = nLocalRet;
2070 }
2071
2072 if ( nRet == COMMIT_RESULT_FAILURE0 )
2073 break;
2074 }
2075 }
2076 catch (const ContentCreationException&)
2077 {
2078 // content could not be created
2079 SetError( ERRCODE_IO_NOTEXISTSErrCode( ErrCodeArea::Io, ErrCodeClass::NotExists, 2 ) );
2080 return COMMIT_RESULT_FAILURE0;
2081 }
2082 catch (const CommandAbortedException&)
2083 {
2084 // any command wasn't executed successfully - not specified
2085 SetError( ERRCODE_IO_GENERALErrCode( ErrCodeArea::Io, ErrCodeClass::General, 13 ) );
2086 return COMMIT_RESULT_FAILURE0;
2087 }
2088 catch (const RuntimeException&)
2089 {
2090 // any other error - not specified
2091 SetError( ERRCODE_IO_GENERALErrCode( ErrCodeArea::Io, ErrCodeClass::General, 13 ) );
2092 return COMMIT_RESULT_FAILURE0;
2093 }
2094 catch (const Exception&)
2095 {
2096 // any other error - not specified
2097 SetError( ERRCODE_IO_GENERALErrCode( ErrCodeArea::Io, ErrCodeClass::General, 13 ) );
2098 return COMMIT_RESULT_FAILURE0;
2099 }
2100
2101 if ( m_bIsRoot && m_pContent )
2102 {
2103 // the root storage must flush the root package content
2104 if ( nRet == COMMIT_RESULT_SUCCESS2 )
2105 {
2106 try
2107 {
2108 // commit the media type to the JAR file
2109 // clipboard format and ClassId will be retrieved from the media type when the file is loaded again
2110 Any aType;
2111 aType <<= m_aContentType;
2112 m_pContent->setPropertyValue("MediaType", aType );
2113
2114 if ( m_bIsLinked )
2115 {
2116 // write a manifest file
2117 // first create a subfolder "META-inf"
2118 Content aNewSubFolder;
2119 bool bRet = ::utl::UCBContentHelper::MakeFolder( *m_pContent, "META-INF", aNewSubFolder );
2120 if ( bRet )
2121 {
2122 // create a stream to write the manifest file - use a temp file
2123 OUString aURL( aNewSubFolder.getURL() );
2124 std::unique_ptr< ::utl::TempFile> pTempFile(new ::utl::TempFile( &aURL ));
2125
2126 // get the stream from the temp file and create an output stream wrapper
2127 SvStream* pStream = pTempFile->GetStream( StreamMode::STD_READWRITE );
2128 ::utl::OOutputStreamWrapper* pHelper = new ::utl::OOutputStreamWrapper( *pStream );
2129 css::uno::Reference < css::io::XOutputStream > xOutputStream( pHelper );
2130
2131 // create a manifest writer object that will fill the stream
2132 Reference < css::packages::manifest::XManifestWriter > xWriter =
2133 css::packages::manifest::ManifestWriter::create(
2134 ::comphelper::getProcessComponentContext() );
2135 sal_Int32 nCount = GetObjectCount() + 1;
2136 Sequence < Sequence < PropertyValue > > aProps( nCount );
2137 sal_Int32 nProps = 0;
2138 GetProps( nProps, aProps, OUString() );
2139 xWriter->writeManifestSequence( xOutputStream, aProps );
2140
2141 // move the stream to its desired location
2142 Content aSource( pTempFile->GetURL(), Reference < XCommandEnvironment >(), comphelper::getProcessComponentContext() );
2143 xWriter = nullptr;
2144 xOutputStream = nullptr;
2145 pTempFile.reset();
2146 aNewSubFolder.transferContent( aSource, InsertOperation::Move, "manifest.xml", NameClash::OVERWRITE );
2147 }
2148 }
2149 else
2150 {
2151#if OSL_DEBUG_LEVEL1 > 0
2152 SAL_INFO("sot", "Files: " << nOpenFiles)do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "sot")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Files: " << nOpenFiles) == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sot"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "2152" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "Files: " << nOpenFiles), 0); }
else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Files: " << nOpenFiles; ::sal::detail::log( (
::SAL_DETAIL_LOG_LEVEL_INFO), ("sot"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "2152" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Files: " << nOpenFiles) == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sot"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "2152" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "Files: " << nOpenFiles), 0); }
else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Files: " << nOpenFiles; ::sal::detail::log( (
::SAL_DETAIL_LOG_LEVEL_INFO), ("sot"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "2152" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
2153 SAL_INFO("sot", "Streams: " << nOpenStreams)do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "sot")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Streams: " << nOpenStreams) == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sot"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "2153" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "Streams: " << nOpenStreams), 0
); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Streams: " << nOpenStreams; ::sal::detail::log
( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sot"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "2153" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Streams: " << nOpenStreams) == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sot"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "2153" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "Streams: " << nOpenStreams), 0
); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Streams: " << nOpenStreams; ::sal::detail::log
( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sot"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "2153" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
2154#endif
2155 // force writing
2156 Any aAny;
2157 m_pContent->executeCommand( "flush", aAny );
2158 if ( m_pSource != nullptr )
2159 {
2160 std::unique_ptr<SvStream> pStream(::utl::UcbStreamHelper::CreateStream( m_pTempFile->GetURL(), StreamMode::STD_READ ));
2161 m_pSource->SetStreamSize(0);
2162 // m_pSource->Seek(0);
2163 pStream->ReadStream( *m_pSource );
2164 pStream.reset();
2165 m_pSource->Seek(0);
2166 }
2167 }
2168 }
2169 catch (const CommandAbortedException&)
2170 {
2171 // how to tell the content : forget all changes ?!
2172 // or should we assume that the content does it by itself because he threw an exception ?!
2173 // any command wasn't executed successfully - not specified
2174 SetError( ERRCODE_IO_GENERALErrCode( ErrCodeArea::Io, ErrCodeClass::General, 13 ) );
2175 return COMMIT_RESULT_FAILURE0;
2176 }
2177 catch (const RuntimeException&)
2178 {
2179 // how to tell the content : forget all changes ?!
2180 // or should we assume that the content does it by itself because he threw an exception ?!
2181 // any other error - not specified
2182 SetError( ERRCODE_IO_GENERALErrCode( ErrCodeArea::Io, ErrCodeClass::General, 13 ) );
2183 return COMMIT_RESULT_FAILURE0;
2184 }
2185 catch (const InteractiveIOException& r)
2186 {
2187 if ( r.Code == IOErrorCode_ACCESS_DENIED || r.Code == IOErrorCode_LOCKING_VIOLATION )
2188 SetError( ERRCODE_IO_ACCESSDENIEDErrCode( ErrCodeArea::Io, ErrCodeClass::Access, 7 ) );
2189 else if ( r.Code == IOErrorCode_NOT_EXISTING )
2190 SetError( ERRCODE_IO_NOTEXISTSErrCode( ErrCodeArea::Io, ErrCodeClass::NotExists, 2 ) );
2191 else if ( r.Code == IOErrorCode_CANT_READ )
2192 SetError( ERRCODE_IO_CANTREADErrCode( ErrCodeArea::Io, ErrCodeClass::Read, 15 ) );
2193 else if ( r.Code == IOErrorCode_CANT_WRITE )
2194 SetError( ERRCODE_IO_CANTWRITEErrCode( ErrCodeArea::Io, ErrCodeClass::Write, 16 ) );
2195 else
2196 SetError( ERRCODE_IO_GENERALErrCode( ErrCodeArea::Io, ErrCodeClass::General, 13 ) );
2197
2198 return COMMIT_RESULT_FAILURE0;
2199 }
2200 catch (const Exception&)
2201 {
2202 // how to tell the content : forget all changes ?!
2203 // or should we assume that the content does it by itself because he threw an exception ?!
2204 // any other error - not specified
2205 SetError( ERRCODE_IO_GENERALErrCode( ErrCodeArea::Io, ErrCodeClass::General, 13 ) );
2206 return COMMIT_RESULT_FAILURE0;
2207 }
2208 }
2209 else if ( nRet != COMMIT_RESULT_NOTHING_TO_DO1 )
2210 {
2211 // how to tell the content : forget all changes ?! Should we ?!
2212 SetError( ERRCODE_IO_GENERALErrCode( ErrCodeArea::Io, ErrCodeClass::General, 13 ) );
2213 return nRet;
2214 }
2215
2216 // after successful root commit all elements names and types are adjusted and all removed elements
2217 // are also removed from the lists
2218 for ( size_t i = 0; i < m_aChildrenList.size(); )
2219 {
2220 auto& pInnerElement = m_aChildrenList[ i ];
2221 if ( pInnerElement->m_bIsRemoved )
2222 m_aChildrenList.erase( m_aChildrenList.begin() + i );
2223 else
2224 {
2225 pInnerElement->m_aOriginalName = pInnerElement->m_aName;
2226 pInnerElement->m_bIsInserted = false;
2227 ++i;
2228 }
2229 }
2230 }
2231
2232 m_bCommited = false;
2233 }
2234
2235 return nRet;
2236}
2237
2238void UCBStorage_Impl::Revert()
2239{
2240 for ( size_t i = 0; i < m_aChildrenList.size(); )
2241 {
2242 auto& pElement = m_aChildrenList[ i ];
2243 pElement->m_bIsRemoved = false;
2244 if ( pElement->m_bIsInserted )
2245 m_aChildrenList.erase( m_aChildrenList.begin() + i );
2246 else
2247 {
2248 if ( pElement->m_xStream.is() )
2249 {
2250 pElement->m_xStream->m_bCommited = false;
2251 pElement->m_xStream->Revert();
2252 }
2253 else if ( pElement->m_xStorage.is() )
2254 {
2255 pElement->m_xStorage->m_bCommited = false;
2256 pElement->m_xStorage->Revert();
2257 }
2258
2259 pElement->m_aName = pElement->m_aOriginalName;
2260 pElement->m_bIsRemoved = false;
2261 ++i;
2262 }
2263 }
2264}
2265
2266const OUString& UCBStorage::GetName() const
2267{
2268 return pImp->m_aName; // pImp->m_aURL ?!
2269}
2270
2271bool UCBStorage::IsRoot() const
2272{
2273 return pImp->m_bIsRoot;
2274}
2275
2276void UCBStorage::SetDirty()
2277{
2278}
2279
2280void UCBStorage::SetClass( const SvGlobalName & rClass, SotClipboardFormatId nOriginalClipFormat, const OUString & rUserTypeName )
2281{
2282 pImp->m_aClassId = rClass;
2283 pImp->m_nFormat = nOriginalClipFormat;
2284 pImp->m_aUserTypeName = rUserTypeName;
2285
2286 // in UCB storages only the content type will be stored, all other information can be reconstructed
2287 // ( see the UCBStorage_Impl::Init() method )
2288 css::datatransfer::DataFlavor aDataFlavor;
2289 SotExchange::GetFormatDataFlavor( pImp->m_nFormat, aDataFlavor );
2290 pImp->m_aContentType = aDataFlavor.MimeType;
2291}
2292
2293void UCBStorage::SetClassId( const ClsId& rClsId )
2294{
2295 pImp->m_aClassId = SvGlobalName( rClsId );
2296 if ( pImp->m_aClassId == SvGlobalName() )
2297 return;
2298
2299 // in OLE storages the clipboard format and the user name will be transferred when a storage is copied because both are
2300 // stored in one the substreams
2301 // UCB storages store the content type information as content type in the manifest file and so this information must be
2302 // kept up to date, and also the other type information that is hold only at runtime because it can be reconstructed from
2303 // the content type
2304 pImp->m_nFormat = GetFormatId_Impl( pImp->m_aClassId );
2305 if ( pImp->m_nFormat != SotClipboardFormatId::NONE )
2306 {
2307 css::datatransfer::DataFlavor aDataFlavor;
2308 SotExchange::GetFormatDataFlavor( pImp->m_nFormat, aDataFlavor );
2309 pImp->m_aUserTypeName = aDataFlavor.HumanPresentableName;
2310 pImp->m_aContentType = aDataFlavor.MimeType;
2311 }
2312}
2313
2314const ClsId& UCBStorage::GetClassId() const
2315{
2316 return pImp->m_aClassId.GetCLSID();
2317}
2318
2319SvGlobalName UCBStorage::GetClassName()
2320{
2321 return pImp->m_aClassId;
2322}
2323
2324SotClipboardFormatId UCBStorage::GetFormat()
2325{
2326 return pImp->m_nFormat;
2327}
2328
2329OUString UCBStorage::GetUserName()
2330{
2331 OSL_FAIL("UserName is not implemented in UCB storages!" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "2331" ": "), "%s", "UserName is not implemented in UCB storages!"
); } } while (false)
;
2332 return pImp->m_aUserTypeName;
2333}
2334
2335void UCBStorage::FillInfoList( SvStorageInfoList* pList ) const
2336{
2337 // put information in childrenlist into StorageInfoList
2338 for (auto& pElement : pImp->GetChildrenList())
2339 {
2340 if ( !pElement->m_bIsRemoved )
2341 {
2342 // problem: what about the size of a substorage ?!
2343 sal_uLong nSize = pElement->m_nSize;
2344 if ( pElement->m_xStream.is() )
2345 nSize = pElement->m_xStream->GetSize();
2346 SvStorageInfo aInfo( pElement->m_aName, nSize, pElement->m_bIsStorage );
2347 pList->push_back( aInfo );
2348 }
2349 }
2350}
2351
2352bool UCBStorage::CopyStorageElement_Impl( UCBStorageElement_Impl const & rElement, BaseStorage* pDest, const OUString& rNew ) const
2353{
2354 // insert stream or storage into the list or stream of the destination storage
2355 // not into the content, this will be done on commit !
2356 // be aware of name changes !
2357 if ( !rElement.m_bIsStorage )
12
Assuming field 'm_bIsStorage' is true
13
Taking false branch
2358 {
2359 // copy the streams data
2360 // the destination stream must not be open
2361 tools::SvRef<BaseStorageStream> pOtherStream(pDest->OpenStream( rNew, StreamMode::WRITE | StreamMode::SHARE_DENYALL, pImp->m_bDirect ));
2362 BaseStorageStream* pStream = nullptr;
2363 bool bDeleteStream = false;
2364
2365 // if stream is already open, it is allowed to copy it, so be aware of this
2366 if ( rElement.m_xStream.is() )
2367 pStream = rElement.m_xStream->m_pAntiImpl;
2368 if ( !pStream )
2369 {
2370 pStream = const_cast< UCBStorage* >(this)->OpenStream( rElement.m_aName, StreamMode::STD_READ, pImp->m_bDirect );
2371 bDeleteStream = true;
2372 }
2373
2374 pStream->CopyTo( pOtherStream.get() );
2375 SetError( pStream->GetError() );
2376 if( pOtherStream->GetError() )
2377 pDest->SetError( pOtherStream->GetError() );
2378 else
2379 pOtherStream->Commit();
2380
2381 if ( bDeleteStream )
2382 delete pStream;
2383 }
2384 else
2385 {
2386 // copy the storage content
2387 // the destination storage must not be open
2388 BaseStorage* pStorage = nullptr;
2389
2390 // if stream is already open, it is allowed to copy it, so be aware of this
2391 bool bDeleteStorage = false;
2392 if ( rElement.m_xStorage.is() )
14
Taking false branch
2393 pStorage = rElement.m_xStorage->m_pAntiImpl;
2394 if ( !pStorage
14.1
'pStorage' is null
14.1
'pStorage' is null
)
15
Taking true branch
2395 {
2396 pStorage = const_cast<UCBStorage*>(this)->OpenStorage( rElement.m_aName, pImp->m_nMode, pImp->m_bDirect );
2397 bDeleteStorage = true;
2398 }
2399
2400 UCBStorage* pUCBDest = dynamic_cast<UCBStorage*>( pDest );
2401 UCBStorage* pUCBCopy = dynamic_cast<UCBStorage*>( pStorage );
2402
2403 bool bOpenUCBStorage = pUCBDest && pUCBCopy;
16
Assuming 'pUCBDest' is null
2404 tools::SvRef<BaseStorage> pOtherStorage(bOpenUCBStorage
16.1
'bOpenUCBStorage' is false
16.1
'bOpenUCBStorage' is false
?
17
'?' condition is false
2405 pDest->OpenUCBStorage( rNew, StreamMode::WRITE | StreamMode::SHARE_DENYALL, pImp->m_bDirect ) :
2406 pDest->OpenOLEStorage( rNew, StreamMode::WRITE | StreamMode::SHARE_DENYALL, pImp->m_bDirect ));
18
Called C++ object pointer is null
2407
2408 // For UCB storages, the class id and the format id may differ,
2409 // do passing the class id is not sufficient.
2410 if( bOpenUCBStorage )
2411 pOtherStorage->SetClass( pStorage->GetClassName(),
2412 pStorage->GetFormat(),
2413 pUCBCopy->pImp->m_aUserTypeName );
2414 else
2415 pOtherStorage->SetClassId( pStorage->GetClassId() );
2416 pStorage->CopyTo( pOtherStorage.get() );
2417 SetError( pStorage->GetError() );
2418 if( pOtherStorage->GetError() )
2419 pDest->SetError( pOtherStorage->GetError() );
2420 else
2421 pOtherStorage->Commit();
2422
2423 if ( bDeleteStorage )
2424 delete pStorage;
2425 }
2426
2427 return Good() && pDest->Good();
2428}
2429
2430UCBStorageElement_Impl* UCBStorage::FindElement_Impl( const OUString& rName ) const
2431{
2432 DBG_ASSERT( !rName.isEmpty(), "Name is empty!" )do { if (true && (!(!rName.isEmpty()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "2432" ": "), "%s", "Name is empty!"); } } while (false)
;
2433 for (const auto& pElement : pImp->GetChildrenList())
2434 {
2435 if ( pElement->m_aName == rName && !pElement->m_bIsRemoved )
2436 return pElement.get();
2437 }
2438 return nullptr;
2439}
2440
2441bool UCBStorage::CopyTo( BaseStorage* pDestStg ) const
2442{
2443 DBG_ASSERT( pDestStg != static_cast<BaseStorage const *>(this), "Self-Copying is not possible!" )do { if (true && (!(pDestStg != static_cast<BaseStorage
const *>(this)))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "2443" ": "), "%s", "Self-Copying is not possible!"); } }
while (false)
;
2444 if ( pDestStg == static_cast<BaseStorage const *>(this) )
2445 return false;
2446
2447 // perhaps it's also a problem if one storage is a parent of the other ?!
2448 // or if not: could be optimized ?!
2449
2450 // For UCB storages, the class id and the format id may differ,
2451 // do passing the class id is not sufficient.
2452 if( dynamic_cast<const UCBStorage *>(pDestStg) != nullptr )
2453 pDestStg->SetClass( pImp->m_aClassId, pImp->m_nFormat,
2454 pImp->m_aUserTypeName );
2455 else
2456 pDestStg->SetClassId( GetClassId() );
2457 pDestStg->SetDirty();
2458
2459 bool bRet = true;
2460 for ( size_t i = 0; i < pImp->GetChildrenList().size() && bRet; ++i )
2461 {
2462 auto& pElement = pImp->GetChildrenList()[ i ];
2463 if ( !pElement->m_bIsRemoved )
2464 bRet = CopyStorageElement_Impl( *pElement, pDestStg, pElement->m_aName );
2465 }
2466
2467 if( !bRet )
2468 SetError( pDestStg->GetError() );
2469 return Good() && pDestStg->Good();
2470}
2471
2472bool UCBStorage::CopyTo( const OUString& rElemName, BaseStorage* pDest, const OUString& rNew )
2473{
2474 if( rElemName.isEmpty() )
1
Calling 'OUString::isEmpty'
4
Returning from 'OUString::isEmpty'
5
Taking false branch
2475 return false;
2476
2477 if ( pDest == static_cast<BaseStorage*>(this) )
6
Assuming the condition is false
7
Taking false branch
2478 {
2479 // can't double an element
2480 return false;
2481 }
2482 else
2483 {
2484 // for copying no optimization is useful, because in every case the stream data must be copied
2485 UCBStorageElement_Impl* pElement = FindElement_Impl( rElemName );
2486 if ( pElement )
8
Assuming 'pElement' is non-null
9
Taking true branch
2487 return CopyStorageElement_Impl( *pElement, pDest, rNew );
10
Passing value via 2nd parameter 'pDest'
11
Calling 'UCBStorage::CopyStorageElement_Impl'
2488 else
2489 {
2490 SetError( SVSTREAM_FILE_NOT_FOUNDErrCode( ErrCodeArea::Io, ErrCodeClass::NotExists, 2 ) );
2491 return false;
2492 }
2493 }
2494}
2495
2496bool UCBStorage::Commit()
2497{
2498 // mark this storage for sending it on root commit
2499 pImp->m_bCommited = true;
2500 if ( pImp->m_bIsRoot )
2501 // the root storage coordinates committing by sending a Commit command to its content
2502 return ( pImp->Commit() != COMMIT_RESULT_FAILURE0 );
2503 else
2504 return true;
2505}
2506
2507bool UCBStorage::Revert()
2508{
2509 pImp->Revert();
2510 return true;
2511}
2512
2513BaseStorageStream* UCBStorage::OpenStream( const OUString& rEleName, StreamMode nMode, bool bDirect )
2514{
2515 if( rEleName.isEmpty() )
2516 return nullptr;
2517
2518 // try to find the storage element
2519 UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
2520 if ( !pElement )
2521 {
2522 // element does not exist, check if creation is allowed
2523 if( nMode & StreamMode::NOCREATE )
2524 {
2525 SetError( ( nMode & StreamMode::WRITE ) ? SVSTREAM_CANNOT_MAKEErrCode( ErrCodeArea::Io, ErrCodeClass::Create, 25 ) : SVSTREAM_FILE_NOT_FOUNDErrCode( ErrCodeArea::Io, ErrCodeClass::NotExists, 2 ) );
2526 OUString aName = pImp->m_aURL + "/" + rEleName;
2527 UCBStorageStream* pStream = new UCBStorageStream( aName, nMode, bDirect, pImp->m_bRepairPackage, pImp->m_xProgressHandler );
2528 pStream->SetError( GetError() );
2529 pStream->pImp->m_aName = rEleName;
2530 return pStream;
2531 }
2532 else
2533 {
2534 // create a new UCBStorageElement and insert it into the list
2535 pElement = new UCBStorageElement_Impl( rEleName );
2536 pElement->m_bIsInserted = true;
2537 pImp->m_aChildrenList.emplace_back( pElement );
2538 }
2539 }
2540
2541 if ( !pElement->m_bIsFolder )
2542 {
2543 // check if stream is already created
2544 if ( pElement->m_xStream.is() )
2545 {
2546 // stream has already been created; if it has no external reference, it may be opened another time
2547 if ( pElement->m_xStream->m_pAntiImpl )
2548 {
2549 OSL_FAIL("Stream is already open!" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "2549" ": "), "%s", "Stream is already open!"); } } while
(false)
;
2550 SetError( SVSTREAM_ACCESS_DENIEDErrCode( ErrCodeArea::Io, ErrCodeClass::Access, 7 ) ); // ???
2551 return nullptr;
2552 }
2553 else
2554 {
2555 // check if stream is opened with the same keyword as before
2556 // if not, generate a new stream because it could be encrypted vs. decrypted!
2557 if ( pElement->m_xStream->m_aKey.isEmpty() )
2558 {
2559 pElement->m_xStream->PrepareCachedForReopen( nMode );
2560
2561 return new UCBStorageStream( pElement->m_xStream.get() );
2562 }
2563 }
2564 }
2565
2566 // stream is opened the first time
2567 pImp->OpenStream( pElement, nMode, bDirect );
2568
2569 // if name has been changed before creating the stream: set name!
2570 pElement->m_xStream->m_aName = rEleName;
2571 return new UCBStorageStream( pElement->m_xStream.get() );
2572 }
2573
2574 return nullptr;
2575}
2576
2577void UCBStorage_Impl::OpenStream( UCBStorageElement_Impl* pElement, StreamMode nMode, bool bDirect )
2578{
2579 OUString aName = m_aURL + "/" +pElement->m_aOriginalName;
2580 pElement->m_xStream = new UCBStorageStream_Impl( aName, nMode, nullptr, bDirect, m_bRepairPackage, m_xProgressHandler );
2581}
2582
2583BaseStorage* UCBStorage::OpenUCBStorage( const OUString& rEleName, StreamMode nMode, bool bDirect )
2584{
2585 if( rEleName.isEmpty() )
2586 return nullptr;
2587
2588 return OpenStorage_Impl( rEleName, nMode, bDirect, true );
2589}
2590
2591BaseStorage* UCBStorage::OpenOLEStorage( const OUString& rEleName, StreamMode nMode, bool bDirect )
2592{
2593 if( rEleName.isEmpty() )
2594 return nullptr;
2595
2596 return OpenStorage_Impl( rEleName, nMode, bDirect, false );
2597}
2598
2599BaseStorage* UCBStorage::OpenStorage( const OUString& rEleName, StreamMode nMode, bool bDirect )
2600{
2601 if( rEleName.isEmpty() )
2602 return nullptr;
2603
2604 return OpenStorage_Impl( rEleName, nMode, bDirect, true );
2605}
2606
2607BaseStorage* UCBStorage::OpenStorage_Impl( const OUString& rEleName, StreamMode nMode, bool bDirect, bool bForceUCBStorage )
2608{
2609 // try to find the storage element
2610 UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
2611 if ( !pElement )
2612 {
2613 // element does not exist, check if creation is allowed
2614 if( nMode & StreamMode::NOCREATE )
2615 {
2616 SetError( ( nMode & StreamMode::WRITE ) ? SVSTREAM_CANNOT_MAKEErrCode( ErrCodeArea::Io, ErrCodeClass::Create, 25 ) : SVSTREAM_FILE_NOT_FOUNDErrCode( ErrCodeArea::Io, ErrCodeClass::NotExists, 2 ) );
2617 OUString aName = pImp->m_aURL + "/" + rEleName; // ???
2618 UCBStorage *pStorage = new UCBStorage( aName, nMode, bDirect, false, pImp->m_bRepairPackage, pImp->m_xProgressHandler );
2619 pStorage->pImp->m_bIsRoot = false;
2620 pStorage->pImp->m_bListCreated = true; // the storage is pretty new, nothing to read
2621 pStorage->SetError( GetError() );
2622 return pStorage;
2623 }
2624
2625 // create a new UCBStorageElement and insert it into the list
2626 // problem: perhaps an OLEStorage should be created ?!
2627 // Because nothing is known about the element that should be created, an external parameter is needed !
2628 pElement = new UCBStorageElement_Impl( rEleName );
2629 pElement->m_bIsInserted = true;
2630 pImp->m_aChildrenList.emplace_back( pElement );
2631 }
2632
2633 if ( !pElement->m_bIsFolder && ( pElement->m_bIsStorage || !bForceUCBStorage ) )
2634 {
2635 // create OLE storages on a stream ( see ctor of SotStorage )
2636 // Such a storage will be created on a UCBStorageStream; it will write into the stream
2637 // if it is opened in direct mode or when it is committed. In this case the stream will be
2638 // modified and then it MUST be treated as committed.
2639 if ( !pElement->m_xStream.is() )
2640 {
2641 BaseStorageStream* pStr = OpenStream( rEleName, nMode, bDirect );
2642 UCBStorageStream* pStream = dynamic_cast<UCBStorageStream*>( pStr );
2643 if ( !pStream )
2644 {
2645 SetError( ( nMode & StreamMode::WRITE ) ? SVSTREAM_CANNOT_MAKEErrCode( ErrCodeArea::Io, ErrCodeClass::Create, 25 ) : SVSTREAM_FILE_NOT_FOUNDErrCode( ErrCodeArea::Io, ErrCodeClass::NotExists, 2 ) );
2646 return nullptr;
2647 }
2648
2649 pElement->m_xStream = pStream->pImp;
2650 delete pStream;
2651 }
2652
2653 pElement->m_xStream->PrepareCachedForReopen( nMode );
2654 bool bInited = pElement->m_xStream->Init();
2655 if (!bInited)
2656 {
2657 SetError( ( nMode & StreamMode::WRITE ) ? SVSTREAM_CANNOT_MAKEErrCode( ErrCodeArea::Io, ErrCodeClass::Create, 25 ) : SVSTREAM_FILE_NOT_FOUNDErrCode( ErrCodeArea::Io, ErrCodeClass::NotExists, 2 ) );
2658 return nullptr;
2659 }
2660
2661 pElement->m_bIsStorage = true;
2662 return pElement->m_xStream->CreateStorage(); // can only be created in transacted mode
2663 }
2664 else if ( pElement->m_xStorage.is() )
2665 {
2666 // storage has already been opened; if it has no external reference, it may be opened another time
2667 if ( pElement->m_xStorage->m_pAntiImpl )
2668 {
2669 OSL_FAIL("Storage is already open!" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "2669" ": "), "%s", "Storage is already open!"); } } while
(false)
;
2670 SetError( SVSTREAM_ACCESS_DENIEDErrCode( ErrCodeArea::Io, ErrCodeClass::Access, 7 ) ); // ???
2671 }
2672 else
2673 {
2674 bool bIsWritable = bool( pElement->m_xStorage->m_nMode & StreamMode::WRITE );
2675 if ( !bIsWritable && ( nMode & StreamMode::WRITE ) )
2676 {
2677 OUString aName = pImp->m_aURL + "/" + pElement->m_aOriginalName;
2678 UCBStorage* pStorage = new UCBStorage( aName, nMode, bDirect, false, pImp->m_bRepairPackage, pImp->m_xProgressHandler );
2679 pElement->m_xStorage = pStorage->pImp;
2680 return pStorage;
2681 }
2682 else
2683 {
2684 return new UCBStorage( pElement->m_xStorage.get() );
2685 }
2686 }
2687 }
2688 else if ( !pElement->m_xStream.is() )
2689 {
2690 // storage is opened the first time
2691 bool bIsWritable = bool(pImp->m_nMode & StreamMode::WRITE);
2692 if ( pImp->m_bIsLinked && pImp->m_bIsRoot && bIsWritable )
2693 {
2694 // make sure that the root storage object has been created before substorages will be created
2695 INetURLObject aFolderObj( pImp->m_aURL );
2696 aFolderObj.removeSegment();
2697
2698 Content aFolder( aFolderObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ), Reference < XCommandEnvironment >(), comphelper::getProcessComponentContext() );
2699 pImp->m_pContent.reset(new Content);
2700 bool bRet = ::utl::UCBContentHelper::MakeFolder( aFolder, pImp->m_aName, *pImp->m_pContent );
2701 if ( !bRet )
2702 {
2703 SetError( SVSTREAM_CANNOT_MAKEErrCode( ErrCodeArea::Io, ErrCodeClass::Create, 25 ) );
2704 return nullptr;
2705 }
2706 }
2707
2708 UCBStorage_Impl* pStor = pImp->OpenStorage( pElement, nMode, bDirect );
2709 if ( pStor )
2710 {
2711 if ( pElement->m_bIsInserted )
2712 pStor->m_bListCreated = true; // the storage is pretty new, nothing to read
2713
2714 return new UCBStorage( pStor );
2715 }
2716 }
2717
2718 return nullptr;
2719}
2720
2721UCBStorage_Impl* UCBStorage_Impl::OpenStorage( UCBStorageElement_Impl* pElement, StreamMode nMode, bool bDirect )
2722{
2723 UCBStorage_Impl* pRet = nullptr;
2724 OUString aName = m_aURL + "/" + pElement->m_aOriginalName; // ???
2725
2726 pElement->m_bIsStorage = pElement->m_bIsFolder = true;
2727
2728 if ( m_bIsLinked && !::utl::UCBContentHelper::Exists( aName ) )
2729 {
2730 Content aNewFolder;
2731 bool bRet = ::utl::UCBContentHelper::MakeFolder( *m_pContent, pElement->m_aOriginalName, aNewFolder );
2732 if ( bRet )
2733 pRet = new UCBStorage_Impl( aNewFolder, aName, nMode, nullptr, bDirect, false, m_bRepairPackage, m_xProgressHandler );
2734 }
2735 else
2736 {
2737 pRet = new UCBStorage_Impl( aName, nMode, nullptr, bDirect, false, m_bRepairPackage, m_xProgressHandler );
2738 }
2739
2740 if ( pRet )
2741 {
2742 pRet->m_bIsLinked = m_bIsLinked;
2743 pRet->m_bIsRoot = false;
2744
2745 // if name has been changed before creating the stream: set name!
2746 pRet->m_aName = pElement->m_aOriginalName;
2747 pElement->m_xStorage = pRet;
2748 }
2749
2750 if ( pRet )
2751 pRet->Init();
2752
2753 return pRet;
2754}
2755
2756bool UCBStorage::IsStorage( const OUString& rEleName ) const
2757{
2758 if( rEleName.isEmpty() )
2759 return false;
2760
2761 const UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
2762 return ( pElement && pElement->m_bIsStorage );
2763}
2764
2765bool UCBStorage::IsStream( const OUString& rEleName ) const
2766{
2767 if( rEleName.isEmpty() )
2768 return false;
2769
2770 const UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
2771 return ( pElement && !pElement->m_bIsStorage );
2772}
2773
2774bool UCBStorage::IsContained( const OUString & rEleName ) const
2775{
2776 if( rEleName.isEmpty() )
2777 return false;
2778 const UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
2779 return ( pElement != nullptr );
2780}
2781
2782void UCBStorage::Remove( const OUString& rEleName )
2783{
2784 if( rEleName.isEmpty() )
2785 return;
2786
2787 UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
2788 if ( pElement )
2789 {
2790 pElement->m_bIsRemoved = true;
2791 }
2792 else
2793 SetError( SVSTREAM_FILE_NOT_FOUNDErrCode( ErrCodeArea::Io, ErrCodeClass::NotExists, 2 ) );
2794}
2795
2796bool UCBStorage::ValidateFAT()
2797{
2798 // ???
2799 return true;
2800}
2801
2802bool UCBStorage::Validate( bool bWrite ) const
2803{
2804 // ???
2805 return ( !bWrite || ( pImp->m_nMode & StreamMode::WRITE ) );
2806}
2807
2808bool UCBStorage::ValidateMode( StreamMode m ) const
2809{
2810 // ???
2811 if( m == ( StreamMode::READ | StreamMode::TRUNC ) ) // from stg.cxx
2812 return true;
2813 // only SHARE_DENYALL allowed
2814 // storages open in r/o mode are OK, since only
2815 // the commit may fail
2816 if( m & StreamMode::SHARE_DENYALL )
2817 return true;
2818
2819 return true;
2820}
2821
2822bool UCBStorage::Equals( const BaseStorage& rStorage ) const
2823{
2824 // ???
2825 return static_cast<BaseStorage const *>(this) == &rStorage;
2826}
2827
2828bool UCBStorage::IsStorageFile( SvStream* pFile )
2829{
2830 if ( !pFile )
2831 return false;
2832
2833 sal_uInt64 nPos = pFile->Tell();
2834 if ( pFile->TellEnd() < 4 )
2835 return false;
2836
2837 pFile->Seek(0);
2838 sal_uInt32 nBytes(0);
2839 pFile->ReadUInt32( nBytes );
2840
2841 // search for the magic bytes
2842 bool bRet = ( nBytes == 0x04034b50 );
2843 if ( !bRet )
2844 {
2845 // disk spanned file have an additional header in front of the usual one
2846 bRet = ( nBytes == 0x08074b50 );
2847 if ( bRet )
2848 {
2849 nBytes = 0;
2850 pFile->ReadUInt32( nBytes );
2851 bRet = ( nBytes == 0x04034b50 );
2852 }
2853 }
2854
2855 pFile->Seek( nPos );
2856 return bRet;
2857}
2858
2859/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx

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#ifndef INCLUDED_RTL_USTRING_HXX
21#define INCLUDED_RTL_USTRING_HXX
22
23#include "sal/config.h"
24
25#include <cassert>
26#include <cstddef>
27#include <cstdlib>
28#include <limits>
29#include <new>
30#include <ostream>
31#include <utility>
32
33#if defined LIBO_INTERNAL_ONLY1
34#include <string_view>
35#include <type_traits>
36#endif
37
38#include "rtl/ustring.h"
39#include "rtl/string.hxx"
40#include "rtl/stringutils.hxx"
41#include "rtl/textenc.h"
42
43#ifdef LIBO_INTERNAL_ONLY1 // "RTL_FAST_STRING"
44#include "config_global.h"
45#include "rtl/stringconcat.hxx"
46#endif
47
48#ifdef RTL_STRING_UNITTEST
49extern bool rtl_string_unittest_invalid_conversion;
50#endif
51
52// The unittest uses slightly different code to help check that the proper
53// calls are made. The class is put into a different namespace to make
54// sure the compiler generates a different (if generating also non-inline)
55// copy of the function and does not merge them together. The class
56// is "brought" into the proper rtl namespace by a typedef below.
57#ifdef RTL_STRING_UNITTEST
58#define rtl rtlunittest
59#endif
60
61namespace rtl
62{
63
64class OUStringBuffer;
65
66#ifdef RTL_STRING_UNITTEST
67#undef rtl
68#endif
69
70#if defined LIBO_INTERNAL_ONLY1 // "RTL_FAST_STRING"
71/// @cond INTERNAL
72
73/**
74A wrapper dressing a string literal as a static-refcount rtl_uString.
75
76This class is not part of public API and is meant to be used only in LibreOffice code.
77@since LibreOffice 4.0
78*/
79template<std::size_t N> class SAL_WARN_UNUSED__attribute__((warn_unused)) OUStringLiteral {
80 static_assert(N != 0);
81 static_assert(N - 1 <= std::numeric_limits<sal_Int32>::max(), "literal too long");
82
83public:
84#if HAVE_CPP_CONSTEVAL0
85 consteval
86#else
87 constexpr
88#endif
89 OUStringLiteral(char16_t const (&literal)[N]) {
90 assertLayout();
91 assert(literal[N - 1] == '\0')(static_cast <bool> (literal[N - 1] == '\0') ? void (0)
: __assert_fail ("literal[N - 1] == '\\0'", "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 91, __extension__ __PRETTY_FUNCTION__))
;
92 //TODO: Use C++20 constexpr std::copy_n (P0202R3):
93 for (std::size_t i = 0; i != N; ++i) {
94 buffer[i] = literal[i];
95 }
96 }
97
98 constexpr sal_Int32 getLength() const { return length; }
99
100 constexpr sal_Unicode const * getStr() const SAL_RETURNS_NONNULL__attribute__((returns_nonnull)) { return buffer; }
101
102 constexpr operator std::u16string_view() const { return {buffer, sal_uInt32(length)}; }
103
104private:
105 static constexpr void assertLayout() {
106 // These static_asserts verifying the layout compatibility with rtl_uString cannot be class
107 // member declarations, as offsetof requires a complete type, so defer them to here:
108 static_assert(offsetof(OUStringLiteral, refCount)__builtin_offsetof(OUStringLiteral, refCount) == offsetof(rtl_uString, refCount)__builtin_offsetof(rtl_uString, refCount));
109 static_assert(std::is_same_v<decltype(refCount), decltype(rtl_uString::refCount)>);
110 static_assert(offsetof(OUStringLiteral, length)__builtin_offsetof(OUStringLiteral, length) == offsetof(rtl_uString, length)__builtin_offsetof(rtl_uString, length));
111 static_assert(std::is_same_v<decltype(length), decltype(rtl_uString::length)>);
112 static_assert(offsetof(OUStringLiteral, buffer)__builtin_offsetof(OUStringLiteral, buffer) == offsetof(rtl_uString, buffer)__builtin_offsetof(rtl_uString, buffer));
113 static_assert(
114 std::is_same_v<
115 std::remove_extent_t<decltype(buffer)>,
116 std::remove_extent_t<decltype(rtl_uString::buffer)>>);
117 }
118
119 // Same layout as rtl_uString (include/rtl/ustring.h):
120 oslInterlockedCount refCount = 0x40000000; // SAL_STRING_STATIC_FLAG (sal/rtl/strimp.hxx)
121 sal_Int32 length = N - 1;
122 sal_Unicode buffer[N] = {}; //TODO: drop initialization for C++20 (P1331R2)
123};
124
125#if defined RTL_STRING_UNITTEST
126namespace libreoffice_internal {
127template<std::size_t N> struct ExceptConstCharArrayDetector<OUStringLiteral<N>> {};
128template<std::size_t N> struct ExceptCharArrayDetector<OUStringLiteral<N>> {};
129}
130#endif
131
132/// @endcond
133#endif
134
135/* ======================================================================= */
136
137/**
138 This String class provides base functionality for C++ like Unicode
139 character array handling. The advantage of this class is that it
140 handles all the memory management for you - and it does it
141 more efficiently. If you assign a string to another string, the
142 data of both strings are shared (without any copy operation or
143 memory allocation) as long as you do not change the string. This class
144 also stores the length of the string, so that many operations are
145 faster than the C-str-functions.
146
147 This class provides only readonly string handling. So you could create
148 a string and you could only query the content from this string.
149 It provides also functionality to change the string, but this results
150 in every case in a new string instance (in the most cases with a
151 memory allocation). You don't have functionality to change the
152 content of the string. If you want to change the string content, then
153 you should use the OStringBuffer class, which provides these
154 functionalities and avoids too much memory allocation.
155
156 The design of this class is similar to the string classes in Java so
157 less people should have understanding problems when they use this class.
158*/
159
160class SAL_WARN_UNUSED__attribute__((warn_unused)) SAL_DLLPUBLIC_RTTI__attribute__ ((type_visibility("default"))) OUString
161{
162public:
163 /// @cond INTERNAL
164 rtl_uString * pData;
165 /// @endcond
166
167 /**
168 New string containing no characters.
169 */
170 OUString()
171 {
172 pData = NULL__null;
173 rtl_uString_new( &pData );
174 }
175
176 /**
177 New string from OUString.
178
179 @param str an OUString.
180 */
181 OUString( const OUString & str )
182 {
183 pData = str.pData;
184 rtl_uString_acquire( pData );
185 }
186
187#if defined LIBO_INTERNAL_ONLY1
188 /**
189 Move constructor.
190
191 @param str an OUString.
192 @since LibreOffice 5.2
193 */
194 OUString( OUString && str ) noexcept
195 {
196 pData = str.pData;
197 str.pData = nullptr;
198 rtl_uString_new( &str.pData );
199 }
200#endif
201
202 /**
203 New string from OUString data.
204
205 @param str an OUString data.
206 */
207 OUString( rtl_uString * str )
208 {
209 pData = str;
210 rtl_uString_acquire( pData );
211 }
212
213 /** New OUString from OUString data without acquiring it. Takeover of ownership.
214
215 The SAL_NO_ACQUIRE dummy parameter is only there to distinguish this
216 from other constructors.
217
218 @param str
219 OUString data
220 */
221 OUString( rtl_uString * str, __sal_NoAcquire )
222 { pData = str; }
223
224 /**
225 New string from a single Unicode character.
226
227 @param value a Unicode character.
228 */
229 explicit OUString( sal_Unicode value )
230 : pData (NULL__null)
231 {
232 rtl_uString_newFromStr_WithLength( &pData, &value, 1 );
233 }
234
235#if defined LIBO_INTERNAL_ONLY1 && !defined RTL_STRING_UNITTEST_CONCAT
236 /// @cond INTERNAL
237 // Catch inadvertent conversions to the above ctor (but still allow
238 // construction from char literals):
239 OUString(int) = delete;
240 explicit OUString(char c):
241 OUString(sal_Unicode(static_cast<unsigned char>(c)))
242 {}
243 /// @endcond
244#endif
245
246#if defined LIBO_INTERNAL_ONLY1
247
248 template<typename T> explicit OUString(
249 T const & value,
250 typename libreoffice_internal::CharPtrDetector<T, libreoffice_internal::Dummy>::TypeUtf16
251 = libreoffice_internal::Dummy()):
252 pData(nullptr)
253 { rtl_uString_newFromStr(&pData, value); }
254
255 template<typename T> explicit OUString(
256 T & value,
257 typename
258 libreoffice_internal::NonConstCharArrayDetector<T, libreoffice_internal::Dummy>::TypeUtf16
259 = libreoffice_internal::Dummy()):
260 pData(nullptr)
261 { rtl_uString_newFromStr(&pData, value); }
262
263#else
264
265 /**
266 New string from a Unicode character buffer array.
267
268 @param value a NULL-terminated Unicode character array.
269 */
270 OUString( const sal_Unicode * value )
271 {
272 pData = NULL__null;
273 rtl_uString_newFromStr( &pData, value );
274 }
275
276#endif
277
278 /**
279 New string from a Unicode character buffer array.
280
281 @param value a Unicode character array.
282 @param length the number of character which should be copied.
283 The character array length must be greater than
284 or equal to this value.
285 */
286 OUString( const sal_Unicode * value, sal_Int32 length )
287 {
288 pData = NULL__null;
289 rtl_uString_newFromStr_WithLength( &pData, value, length );
290 }
291
292 /**
293 New string from an 8-Bit string literal that is expected to contain only
294 characters in the ASCII set (i.e. first 128 characters). This constructor
295 allows an efficient and convenient way to create OUString
296 instances from ASCII literals. When creating strings from data that
297 is not pure ASCII, it needs to be converted to OUString by explicitly
298 providing the encoding to use for the conversion.
299
300 If there are any embedded \0's in the string literal, the result is undefined.
301 Use the overload that explicitly accepts length.
302
303 @param literal the 8-bit ASCII string literal
304
305 @since LibreOffice 3.6
306 */
307 template< typename T >
308 OUString( T& literal, typename libreoffice_internal::ConstCharArrayDetector< T, libreoffice_internal::Dummy >::Type = libreoffice_internal::Dummy() )
309 {
310 assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 311, __extension__ __PRETTY_FUNCTION__))
311 libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 311, __extension__ __PRETTY_FUNCTION__))
;
312 pData = NULL__null;
313 if (libreoffice_internal::ConstCharArrayDetector<T>::length == 0) {
314 rtl_uString_new(&pData);
315 } else {
316 rtl_uString_newFromLiteral(
317 &pData,
318 libreoffice_internal::ConstCharArrayDetector<T>::toPointer(
319 literal),
320 libreoffice_internal::ConstCharArrayDetector<T>::length, 0);
321 }
322#ifdef RTL_STRING_UNITTEST
323 rtl_string_unittest_const_literal = true;
324#endif
325 }
326
327#if defined LIBO_INTERNAL_ONLY1
328 /** @overload @since LibreOffice 5.3 */
329 template<typename T> OUString(
330 T & literal,
331 typename libreoffice_internal::ConstCharArrayDetector<
332 T, libreoffice_internal::Dummy>::TypeUtf16
333 = libreoffice_internal::Dummy()):
334 pData(nullptr)
335 {
336 assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 337, __extension__ __PRETTY_FUNCTION__))
337 libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 337, __extension__ __PRETTY_FUNCTION__))
;
338 if (libreoffice_internal::ConstCharArrayDetector<T>::length == 0) {
339 rtl_uString_new(&pData);
340 } else {
341 rtl_uString_newFromStr_WithLength(
342 &pData,
343 libreoffice_internal::ConstCharArrayDetector<T>::toPointer(
344 literal),
345 libreoffice_internal::ConstCharArrayDetector<T>::length);
346 }
347 }
348#endif
349
350#if defined LIBO_INTERNAL_ONLY1 && defined RTL_STRING_UNITTEST
351 /// @cond INTERNAL
352 /**
353 * Only used by unittests to detect incorrect conversions.
354 * @internal
355 */
356 template< typename T >
357 OUString( T&, typename libreoffice_internal::ExceptConstCharArrayDetector< T >::Type = libreoffice_internal::Dummy() )
358 {
359 pData = NULL__null;
360 rtl_uString_newFromLiteral( &pData, "!!br0ken!!", 10, 0 ); // set to garbage
361 rtl_string_unittest_invalid_conversion = true;
362 }
363 /**
364 * Only used by unittests to detect incorrect conversions.
365 * @internal
366 */
367 template< typename T >
368 OUString( const T&, typename libreoffice_internal::ExceptCharArrayDetector< T >::Type = libreoffice_internal::Dummy() )
369 {
370 pData = NULL__null;
371 rtl_uString_newFromLiteral( &pData, "!!br0ken!!", 10, 0 ); // set to garbage
372 rtl_string_unittest_invalid_conversion = true;
373 }
374 /// @endcond
375#endif
376
377#ifdef LIBO_INTERNAL_ONLY1 // "RTL_FAST_STRING"
378 /// @cond INTERNAL
379 /**
380 New string from a string literal.
381
382 @since LibreOffice 5.0
383 */
384 template<std::size_t N> OUString(OUStringLiteral<N> const & literal):
385 pData(const_cast<rtl_uString *>(reinterpret_cast<rtl_uString const *>(&literal))) {}
386 template<std::size_t N> OUString(OUStringLiteral<N> &&) = delete;
387 /// @endcond
388#endif
389
390 /**
391 New string from an 8-Bit character buffer array.
392
393 @param value An 8-Bit character array.
394 @param length The number of character which should be converted.
395 The 8-Bit character array length must be
396 greater than or equal to this value.
397 @param encoding The text encoding from which the 8-Bit character
398 sequence should be converted.
399 @param convertFlags Flags which control the conversion.
400 see RTL_TEXTTOUNICODE_FLAGS_...
401
402 @exception std::bad_alloc is thrown if an out-of-memory condition occurs
403 */
404 OUString( const char * value, sal_Int32 length,
405 rtl_TextEncoding encoding,
406 sal_uInt32 convertFlags = OSTRING_TO_OUSTRING_CVTFLAGS(((sal_uInt32)0x0003) | ((sal_uInt32)0x0030) | ((sal_uInt32)0x0300
))
)
407 {
408 pData = NULL__null;
409 rtl_string2UString( &pData, value, length, encoding, convertFlags );
410 if (pData == NULL__null) {
411 throw std::bad_alloc();
412 }
413 }
414
415 /** Create a new string from an array of Unicode code points.
416
417 @param codePoints
418 an array of at least codePointCount code points, which each must be in
419 the range from 0 to 0x10FFFF, inclusive. May be null if codePointCount
420 is zero.
421
422 @param codePointCount
423 the non-negative number of code points.
424
425 @exception std::bad_alloc
426 is thrown if either an out-of-memory condition occurs or the resulting
427 number of UTF-16 code units would have been larger than SAL_MAX_INT32.
428
429 @since UDK 3.2.7
430 */
431 explicit OUString(
432 sal_uInt32 const * codePoints, sal_Int32 codePointCount):
433 pData(NULL__null)
434 {
435 rtl_uString_newFromCodePoints(&pData, codePoints, codePointCount);
436 if (pData == NULL__null) {
437 throw std::bad_alloc();
438 }
439 }
440
441#ifdef LIBO_INTERNAL_ONLY1 // "RTL_FAST_STRING"
442 /**
443 @overload
444 @internal
445 */
446 template< typename T1, typename T2 >
447 OUString( OUStringConcat< T1, T2 >&& c )
448 {
449 const sal_Int32 l = c.length();
450 pData = rtl_uString_alloc( l );
451 if (l != 0)
452 {
453 sal_Unicode* end = c.addData( pData->buffer );
454 pData->length = l;
455 *end = '\0';
456 // TODO realloc in case pData->length is noticeably smaller than l?
457 }
458 }
459
460 /**
461 @overload
462 @internal
463 */
464 template< typename T >
465 OUString( OUStringNumber< T >&& n )
466 : OUString( n.buf, n.length )
467 {}
468#endif
469
470#if defined LIBO_INTERNAL_ONLY1
471 OUString(std::u16string_view sv) {
472 if (sv.size() > sal_uInt32(std::numeric_limits<sal_Int32>::max())) {
473 throw std::bad_alloc();
474 }
475 pData = nullptr;
476 rtl_uString_newFromStr_WithLength(&pData, sv.data(), sv.size());
477 }
478#endif
479
480 /**
481 Release the string data.
482 */
483 ~OUString()
484 {
485 rtl_uString_release( pData );
486 }
487
488 /** Provides an OUString const & passing a storage pointer of an
489 rtl_uString * handle.
490 It is more convenient to use C++ OUString member functions when dealing
491 with rtl_uString * handles. Using this function avoids unnecessary
492 acquire()/release() calls for a temporary OUString object.
493
494 @param ppHandle
495 pointer to storage
496 @return
497 OUString const & based on given storage
498 */
499 static OUString const & unacquired( rtl_uString * const * ppHandle )
500 { return * reinterpret_cast< OUString const * >( ppHandle ); }
501
502 /**
503 Assign a new string.
504
505 @param str an OUString.
506 */
507 OUString & operator=( const OUString & str )
508 {
509 rtl_uString_assign( &pData, str.pData );
510 return *this;
511 }
512
513#if defined LIBO_INTERNAL_ONLY1
514 /**
515 Move assign a new string.
516
517 @param str an OUString.
518 @since LibreOffice 5.2
519 */
520 OUString & operator=( OUString && str ) noexcept
521 {
522 rtl_uString_release( pData );
523 pData = str.pData;
524 str.pData = nullptr;
525 rtl_uString_new( &str.pData );
526 return *this;
527 }
528#endif
529
530 /**
531 Assign a new string from an 8-Bit string literal that is expected to contain only
532 characters in the ASCII set (i.e. first 128 characters). This operator
533 allows an efficient and convenient way to assign OUString
534 instances from ASCII literals. When assigning strings from data that
535 is not pure ASCII, it needs to be converted to OUString by explicitly
536 providing the encoding to use for the conversion.
537
538 @param literal the 8-bit ASCII string literal
539
540 @since LibreOffice 3.6
541 */
542 template< typename T >
543 typename libreoffice_internal::ConstCharArrayDetector< T, OUString& >::Type operator=( T& literal )
544 {
545 assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 546, __extension__ __PRETTY_FUNCTION__))
546 libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 546, __extension__ __PRETTY_FUNCTION__))
;
547 if (libreoffice_internal::ConstCharArrayDetector<T>::length == 0) {
548 rtl_uString_new(&pData);
549 } else {
550 rtl_uString_newFromLiteral(
551 &pData,
552 libreoffice_internal::ConstCharArrayDetector<T>::toPointer(
553 literal),
554 libreoffice_internal::ConstCharArrayDetector<T>::length, 0);
555 }
556 return *this;
557 }
558
559#if defined LIBO_INTERNAL_ONLY1
560 /** @overload @since LibreOffice 5.3 */
561 template<typename T>
562 typename
563 libreoffice_internal::ConstCharArrayDetector<T, OUString &>::TypeUtf16
564 operator =(T & literal) {
565 if (libreoffice_internal::ConstCharArrayDetector<T>::length == 0) {
566 rtl_uString_new(&pData);
567 } else {
568 rtl_uString_newFromStr_WithLength(
569 &pData,
570 libreoffice_internal::ConstCharArrayDetector<T>::toPointer(
571 literal),
572 libreoffice_internal::ConstCharArrayDetector<T>::length);
573 }
574 return *this;
575 }
576
577 /** @overload @since LibreOffice 5.4 */
578 template<std::size_t N> OUString & operator =(OUStringLiteral<N> const & literal) {
579 if (literal.getLength() == 0) {
580 rtl_uString_new(&pData);
581 } else {
582 rtl_uString_newFromStr_WithLength(&pData, literal.getStr(), literal.getLength());
583 }
584 return *this;
585 }
586
587 template<typename T>
588 OUString & operator =(OUStringNumber<T> && n) {
589 // n.length should never be zero, so no need to add an optimization for that case
590 rtl_uString_newFromStr_WithLength(&pData, n.buf, n.length);
591 return *this;
592 }
593
594 OUString & operator =(std::u16string_view sv) {
595 if (sv.empty()) {
596 rtl_uString_new(&pData);
597 } else {
598 rtl_uString_newFromStr_WithLength(&pData, sv.data(), sv.size());
599 }
600 return *this;
601 }
602#endif
603
604#if defined LIBO_INTERNAL_ONLY1
605 /**
606 Append the contents of an OUStringBuffer to this string.
607
608 @param str an OUStringBuffer.
609
610 @exception std::bad_alloc is thrown if an out-of-memory condition occurs
611 @since LibreOffice 6.2
612 */
613 inline OUString & operator+=( const OUStringBuffer & str ) &;
614#endif
615
616 /**
617 Append a string to this string.
618
619 @param str an OUString.
620
621 @exception std::bad_alloc is thrown if an out-of-memory condition occurs
622 */
623 OUString & operator+=( const OUString & str )
624#if defined LIBO_INTERNAL_ONLY1
625 &
626#endif
627 {
628 return internalAppend(str.pData);
629 }
630#if defined LIBO_INTERNAL_ONLY1
631 void operator+=(OUString const &) && = delete;
632#endif
633
634 /** Append an ASCII string literal to this string.
635
636 @param literal an 8-bit ASCII-only string literal
637
638 @since LibreOffice 5.1
639 */
640 template<typename T>
641 typename libreoffice_internal::ConstCharArrayDetector<T, OUString &>::Type
642 operator +=(T & literal)
643#if defined LIBO_INTERNAL_ONLY1
644 &
645#endif
646 {
647 assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 648, __extension__ __PRETTY_FUNCTION__))
648 libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 648, __extension__ __PRETTY_FUNCTION__))
;
649 rtl_uString_newConcatAsciiL(
650 &pData, pData,
651 libreoffice_internal::ConstCharArrayDetector<T>::toPointer(literal),
652 libreoffice_internal::ConstCharArrayDetector<T>::length);
653 return *this;
654 }
655#if defined LIBO_INTERNAL_ONLY1
656 template<typename T>
657 typename libreoffice_internal::ConstCharArrayDetector<T, OUString &>::Type
658 operator +=(T &) && = delete;
659#endif
660
661#if defined LIBO_INTERNAL_ONLY1
662 /** @overload @since LibreOffice 5.3 */
663 template<typename T>
664 typename
665 libreoffice_internal::ConstCharArrayDetector<T, OUString &>::TypeUtf16
666 operator +=(T & literal) & {
667 rtl_uString_newConcatUtf16L(
668 &pData, pData,
669 libreoffice_internal::ConstCharArrayDetector<T>::toPointer(literal),
670 libreoffice_internal::ConstCharArrayDetector<T>::length);
671 return *this;
672 }
673 template<typename T>
674 typename
675 libreoffice_internal::ConstCharArrayDetector<T, OUString &>::TypeUtf16
676 operator +=(T &) && = delete;
677
678 /** @overload @since LibreOffice 5.4 */
679 template<std::size_t N> OUString & operator +=(OUStringLiteral<N> const & literal) & {
680 rtl_uString_newConcatUtf16L(&pData, pData, literal.getStr(), literal.getLength());
681 return *this;
682 }
683 template<std::size_t N> void operator +=(OUStringLiteral<N> const &) && = delete;
684
685 OUString & operator +=(std::u16string_view sv) & {
686 if (sv.size() > sal_uInt32(std::numeric_limits<sal_Int32>::max())) {
687 throw std::bad_alloc();
688 }
689 rtl_uString_newConcatUtf16L(&pData, pData, sv.data(), sv.size());
690 return *this;
691 }
692 void operator +=(std::u16string_view) && = delete;
693#endif
694
695#ifdef LIBO_INTERNAL_ONLY1 // "RTL_FAST_STRING"
696 /**
697 @overload
698 @internal
699 */
700 template< typename T1, typename T2 >
701 OUString& operator+=( OUStringConcat< T1, T2 >&& c ) & {
702 sal_Int32 l = c.length();
703 if( l == 0 )
704 return *this;
705 l += pData->length;
706 rtl_uString_ensureCapacity( &pData, l );
707 sal_Unicode* end = c.addData( pData->buffer + pData->length );
708 *end = '\0';
709 pData->length = l;
710 return *this;
711 }
712 template<typename T1, typename T2> void operator +=(
713 OUStringConcat<T1, T2> &&) && = delete;
714
715 /**
716 @overload
717 @internal
718 */
719 template< typename T >
720 OUString& operator+=( OUStringNumber< T >&& n ) & {
721 sal_Int32 l = n.length;
722 if( l == 0 )
723 return *this;
724 l += pData->length;
725 rtl_uString_ensureCapacity( &pData, l );
726 sal_Unicode* end = addDataHelper( pData->buffer + pData->length, n.buf, n.length );
727 *end = '\0';
728 pData->length = l;
729 return *this;
730 }
731 template<typename T> void operator +=(
732 OUStringNumber<T> &&) && = delete;
733#endif
734
735 /**
736 Clears the string, i.e, makes a zero-character string
737 @since LibreOffice 4.4
738 */
739 void clear()
740 {
741 rtl_uString_new( &pData );
742 }
743
744 /**
745 Returns the length of this string.
746
747 The length is equal to the number of Unicode characters in this string.
748
749 @return the length of the sequence of characters represented by this
750 object.
751 */
752 sal_Int32 getLength() const { return pData->length; }
753
754 /**
755 Checks if a string is empty.
756
757 @return true if the string is empty;
758 false, otherwise.
759
760 @since LibreOffice 3.4
761 */
762 bool isEmpty() const
763 {
764 return pData->length == 0;
2
Assuming field 'length' is not equal to 0
3
Returning zero, which participates in a condition later
765 }
766
767 /**
768 Returns a pointer to the Unicode character buffer for this string.
769
770 It isn't necessarily NULL terminated.
771
772 @return a pointer to the Unicode characters buffer for this object.
773 */
774 const sal_Unicode * getStr() const SAL_RETURNS_NONNULL__attribute__((returns_nonnull)) { return pData->buffer; }
775
776 /**
777 Access to individual characters.
778
779 @param index must be non-negative and less than length.
780
781 @return the character at the given index.
782
783 @since LibreOffice 3.5
784 */
785 sal_Unicode operator [](sal_Int32 index) const {
786 // silence spurious -Werror=strict-overflow warnings from GCC 4.8.2
787 assert(index >= 0 && static_cast<sal_uInt32>(index) < static_cast<sal_uInt32>(getLength()))(static_cast <bool> (index >= 0 && static_cast
<sal_uInt32>(index) < static_cast<sal_uInt32>(
getLength())) ? void (0) : __assert_fail ("index >= 0 && static_cast<sal_uInt32>(index) < static_cast<sal_uInt32>(getLength())"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 787, __extension__ __PRETTY_FUNCTION__))
;
788 return getStr()[index];
789 }
790
791 /**
792 Compares two strings.
793
794 The comparison is based on the numeric value of each character in
795 the strings and return a value indicating their relationship.
796 This function can't be used for language specific sorting.
797
798 @param str the object to be compared.
799 @return 0 - if both strings are equal
800 < 0 - if this string is less than the string argument
801 > 0 - if this string is greater than the string argument
802 */
803 sal_Int32 compareTo( const OUString & str ) const
804 {
805 return rtl_ustr_compare_WithLength( pData->buffer, pData->length,
806 str.pData->buffer, str.pData->length );
807 }
808
809 /**
810 Compares two strings with a maximum count of characters.
811
812 The comparison is based on the numeric value of each character in
813 the strings and return a value indicating their relationship.
814 This function can't be used for language specific sorting.
815
816 @param str the object to be compared.
817 @param maxLength the maximum count of characters to be compared.
818 @return 0 - if both strings are equal
819 < 0 - if this string is less than the string argument
820 > 0 - if this string is greater than the string argument
821
822 @since UDK 3.2.7
823 */
824 sal_Int32 compareTo( const OUString & str, sal_Int32 maxLength ) const
825 {
826 return rtl_ustr_shortenedCompare_WithLength( pData->buffer, pData->length,
827 str.pData->buffer, str.pData->length, maxLength );
828 }
829
830 /**
831 Compares two strings in reverse order.
832
833 The comparison is based on the numeric value of each character in
834 the strings and return a value indicating their relationship.
835 This function can't be used for language specific sorting.
836
837 @param str the object to be compared.
838 @return 0 - if both strings are equal
839 < 0 - if this string is less than the string argument
840 > 0 - if this string is greater than the string argument
841 */
842#if defined LIBO_INTERNAL_ONLY1
843 sal_Int32 reverseCompareTo(std::u16string_view sv) const {
844 return rtl_ustr_reverseCompare_WithLength(
845 pData->buffer, pData->length, sv.data(), sv.size());
846 }
847#else
848 sal_Int32 reverseCompareTo( const OUString & str ) const
849 {
850 return rtl_ustr_reverseCompare_WithLength( pData->buffer, pData->length,
851 str.pData->buffer, str.pData->length );
852 }
853#endif
854
855 /**
856 @overload
857 This function accepts an ASCII string literal as its argument.
858 @since LibreOffice 4.1
859 */
860 template< typename T >
861 typename libreoffice_internal::ConstCharArrayDetector< T, sal_Int32 >::Type reverseCompareTo( T& literal ) const
862 {
863 assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 864, __extension__ __PRETTY_FUNCTION__))
864 libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 864, __extension__ __PRETTY_FUNCTION__))
;
865 return rtl_ustr_asciil_reverseCompare_WithLength(
866 pData->buffer, pData->length,
867 libreoffice_internal::ConstCharArrayDetector<T>::toPointer(literal),
868 libreoffice_internal::ConstCharArrayDetector<T>::length);
869 }
870
871 /**
872 Perform a comparison of two strings.
873
874 The result is true if and only if second string
875 represents the same sequence of characters as the first string.
876 This function can't be used for language specific comparison.
877
878 @param str the object to be compared.
879 @return true if the strings are equal;
880 false, otherwise.
881 */
882 bool equals( const OUString & str ) const
883 {
884 if ( pData->length != str.pData->length )
885 return false;
886 if ( pData == str.pData )
887 return true;
888 return rtl_ustr_reverseCompare_WithLength( pData->buffer, pData->length,
889 str.pData->buffer, str.pData->length ) == 0;
890 }
891
892 /**
893 Perform an ASCII lowercase comparison of two strings.
894
895 The result is true if and only if second string
896 represents the same sequence of characters as the first string,
897 ignoring the case.
898 Character values between 65 and 90 (ASCII A-Z) are interpreted as
899 values between 97 and 122 (ASCII a-z).
900 This function can't be used for language specific comparison.
901
902 @param str the object to be compared.
903 @return true if the strings are equal;
904 false, otherwise.
905 */
906#if defined LIBO_INTERNAL_ONLY1
907 bool equalsIgnoreAsciiCase(std::u16string_view sv) const {
908 return
909 rtl_ustr_compareIgnoreAsciiCase_WithLength(
910 pData->buffer, pData->length, sv.data(), sv.size())
911 == 0;
912 }
913#else
914 bool equalsIgnoreAsciiCase( const OUString & str ) const
915 {
916 if ( pData->length != str.pData->length )
917 return false;
918 if ( pData == str.pData )
919 return true;
920 return rtl_ustr_compareIgnoreAsciiCase_WithLength( pData->buffer, pData->length,
921 str.pData->buffer, str.pData->length ) == 0;
922 }
923#endif
924
925 /**
926 Perform an ASCII lowercase comparison of two strings.
927
928 Compare the two strings with uppercase ASCII
929 character values between 65 and 90 (ASCII A-Z) interpreted as
930 values between 97 and 122 (ASCII a-z).
931 This function can't be used for language specific comparison.
932
933 @param str the object to be compared.
934 @return 0 - if both strings are equal
935 < 0 - if this string is less than the string argument
936 > 0 - if this string is greater than the string argument
937
938 @since LibreOffice 4.0
939 */
940#if defined LIBO_INTERNAL_ONLY1
941 sal_Int32 compareToIgnoreAsciiCase(std::u16string_view sv) const {
942 return rtl_ustr_compareIgnoreAsciiCase_WithLength(
943 pData->buffer, pData->length, sv.data(), sv.size());
944 }
945#else
946 sal_Int32 compareToIgnoreAsciiCase( const OUString & str ) const
947 {
948 return rtl_ustr_compareIgnoreAsciiCase_WithLength( pData->buffer, pData->length,
949 str.pData->buffer, str.pData->length );
950 }
951#endif
952
953 /**
954 @overload
955 This function accepts an ASCII string literal as its argument.
956 @since LibreOffice 3.6
957 */
958 template< typename T >
959 typename libreoffice_internal::ConstCharArrayDetector< T, bool >::Type equalsIgnoreAsciiCase( T& literal ) const
960 {
961 assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 962, __extension__ __PRETTY_FUNCTION__))
962 libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 962, __extension__ __PRETTY_FUNCTION__))
;
963 return
964 (pData->length
965 == libreoffice_internal::ConstCharArrayDetector<T>::length)
966 && (rtl_ustr_ascii_compareIgnoreAsciiCase_WithLength(
967 pData->buffer, pData->length,
968 libreoffice_internal::ConstCharArrayDetector<T>::toPointer(
969 literal))
970 == 0);
971 }
972
973 /**
974 Match against a substring appearing in this string.
975
976 The result is true if and only if the second string appears as a substring
977 of this string, at the given position.
978 This function can't be used for language specific comparison.
979
980 @param str the object (substring) to be compared.
981 @param fromIndex the index to start the comparison from.
982 The index must be greater than or equal to 0
983 and less or equal as the string length.
984 @return true if str match with the characters in the string
985 at the given position;
986 false, otherwise.
987 */
988#if defined LIBO_INTERNAL_ONLY1
989 bool match(std::u16string_view sv, sal_Int32 fromIndex = 0) const {
990 return
991 rtl_ustr_shortenedCompare_WithLength(
992 pData->buffer + fromIndex, pData->length - fromIndex, sv.data(), sv.size(),
993 sv.size())
994 == 0;
995 }
996#else
997 bool match( const OUString & str, sal_Int32 fromIndex = 0 ) const
998 {
999 return rtl_ustr_shortenedCompare_WithLength( pData->buffer+fromIndex, pData->length-fromIndex,
1000 str.pData->buffer, str.pData->length, str.pData->length ) == 0;
1001 }
1002#endif
1003
1004 /**
1005 @overload
1006 This function accepts an ASCII string literal as its argument.
1007 @since LibreOffice 3.6
1008 */
1009 template< typename T >
1010 typename libreoffice_internal::ConstCharArrayDetector< T, bool >::Type match( T& literal, sal_Int32 fromIndex = 0 ) const
1011 {
1012 assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 1013, __extension__ __PRETTY_FUNCTION__))
1013 libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 1013, __extension__ __PRETTY_FUNCTION__))
;
1014 return
1015 rtl_ustr_ascii_shortenedCompare_WithLength(
1016 pData->buffer+fromIndex, pData->length-fromIndex,
1017 libreoffice_internal::ConstCharArrayDetector<T>::toPointer(
1018 literal),
1019 libreoffice_internal::ConstCharArrayDetector<T>::length)
1020 == 0;
1021 }
1022
1023 /**
1024 Match against a substring appearing in this string, ignoring the case of
1025 ASCII letters.
1026
1027 The result is true if and only if the second string appears as a substring
1028 of this string, at the given position.
1029 Character values between 65 and 90 (ASCII A-Z) are interpreted as
1030 values between 97 and 122 (ASCII a-z).
1031 This function can't be used for language specific comparison.
1032
1033 @param str the object (substring) to be compared.
1034 @param fromIndex the index to start the comparison from.
1035 The index must be greater than or equal to 0
1036 and less than or equal to the string length.
1037 @return true if str match with the characters in the string
1038 at the given position;
1039 false, otherwise.
1040 */
1041#if defined LIBO_INTERNAL_ONLY1
1042 bool matchIgnoreAsciiCase(std::u16string_view sv, sal_Int32 fromIndex = 0) const {
1043 return
1044 rtl_ustr_shortenedCompareIgnoreAsciiCase_WithLength(
1045 pData->buffer + fromIndex, pData->length - fromIndex, sv.data(), sv.size(),
1046 sv.size())
1047 == 0;
1048 }
1049#else
1050 bool matchIgnoreAsciiCase( const OUString & str, sal_Int32 fromIndex = 0 ) const
1051 {
1052 return rtl_ustr_shortenedCompareIgnoreAsciiCase_WithLength( pData->buffer+fromIndex, pData->length-fromIndex,
1053 str.pData->buffer, str.pData->length,
1054 str.pData->length ) == 0;
1055 }
1056#endif
1057
1058 /**
1059 @overload
1060 This function accepts an ASCII string literal as its argument.
1061 @since LibreOffice 3.6
1062 */
1063 template< typename T >
1064 typename libreoffice_internal::ConstCharArrayDetector< T, bool >::Type matchIgnoreAsciiCase( T& literal, sal_Int32 fromIndex = 0 ) const
1065 {
1066 assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 1067, __extension__ __PRETTY_FUNCTION__))
1067 libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 1067, __extension__ __PRETTY_FUNCTION__))
;
1068 return
1069 rtl_ustr_ascii_shortenedCompareIgnoreAsciiCase_WithLength(
1070 pData->buffer+fromIndex, pData->length-fromIndex,
1071 libreoffice_internal::ConstCharArrayDetector<T>::toPointer(
1072 literal),
1073 libreoffice_internal::ConstCharArrayDetector<T>::length)
1074 == 0;
1075 }
1076
1077 /**
1078 Compares two strings.
1079
1080 The comparison is based on the numeric value of each character in
1081 the strings and return a value indicating their relationship.
1082 Since this method is optimized for performance, the ASCII character
1083 values are not converted in any way. The caller has to make sure that
1084 all ASCII characters are in the allowed range between 0 and 127.
1085 The ASCII string must be NULL-terminated.
1086 This function can't be used for language specific sorting.
1087
1088 @param asciiStr the 8-Bit ASCII character string to be compared.
1089 @return 0 - if both strings are equal
1090 < 0 - if this string is less than the string argument
1091 > 0 - if this string is greater than the string argument
1092 */
1093 sal_Int32 compareToAscii( const char* asciiStr ) const
1094 {
1095 return rtl_ustr_ascii_compare_WithLength( pData->buffer, pData->length, asciiStr );
1096 }
1097
1098 /**
1099 Compares two strings with a maximum count of characters.
1100
1101 The comparison is based on the numeric value of each character in
1102 the strings and return a value indicating their relationship.
1103 Since this method is optimized for performance, the ASCII character
1104 values are not converted in any way. The caller has to make sure that
1105 all ASCII characters are in the allowed range between 0 and 127.
1106 The ASCII string must be NULL-terminated.
1107 This function can't be used for language specific sorting.
1108
1109 @deprecated This is a confusing overload with unexpectedly different
1110 semantics from the one-parameter form, so it is marked as deprecated.
1111 Practically all uses compare the return value against zero and can thus
1112 be replaced with uses of startsWith.
1113
1114 @param asciiStr the 8-Bit ASCII character string to be compared.
1115 @param maxLength the maximum count of characters to be compared.
1116 @return 0 - if both strings are equal
1117 < 0 - if this string is less than the string argument
1118 > 0 - if this string is greater than the string argument
1119 */
1120 SAL_DEPRECATED(__attribute__((deprecated("replace s1.compareToAscii(s2, strlen(s2)) == 0 with s1.startsWith(s2)"
)))
1121 "replace s1.compareToAscii(s2, strlen(s2)) == 0 with s1.startsWith(s2)")__attribute__((deprecated("replace s1.compareToAscii(s2, strlen(s2)) == 0 with s1.startsWith(s2)"
)))
1122 sal_Int32 compareToAscii( const char * asciiStr, sal_Int32 maxLength ) const
1123 {
1124 return rtl_ustr_ascii_shortenedCompare_WithLength( pData->buffer, pData->length,
1125 asciiStr, maxLength );
1126 }
1127
1128 /**
1129 Compares two strings in reverse order.
1130
1131 This could be useful, if normally both strings start with the same
1132 content. The comparison is based on the numeric value of each character
1133 in the strings and return a value indicating their relationship.
1134 Since this method is optimized for performance, the ASCII character
1135 values are not converted in any way. The caller has to make sure that
1136 all ASCII characters are in the allowed range between 0 and 127.
1137 The ASCII string must be NULL-terminated and must be greater than
1138 or equal to asciiStrLength.
1139 This function can't be used for language specific sorting.
1140
1141 @param asciiStr the 8-Bit ASCII character string to be compared.
1142 @param asciiStrLength the length of the ascii string
1143 @return 0 - if both strings are equal
1144 < 0 - if this string is less than the string argument
1145 > 0 - if this string is greater than the string argument
1146 */
1147 sal_Int32 reverseCompareToAsciiL( const char * asciiStr, sal_Int32 asciiStrLength ) const
1148 {
1149 return rtl_ustr_asciil_reverseCompare_WithLength( pData->buffer, pData->length,
1150 asciiStr, asciiStrLength );
1151 }
1152
1153 /**
1154 Perform a comparison of two strings.
1155
1156 The result is true if and only if second string
1157 represents the same sequence of characters as the first string.
1158 Since this method is optimized for performance, the ASCII character
1159 values are not converted in any way. The caller has to make sure that
1160 all ASCII characters are in the allowed range between 0 and 127.
1161 The ASCII string must be NULL-terminated.
1162 This function can't be used for language specific comparison.
1163
1164 @param asciiStr the 8-Bit ASCII character string to be compared.
1165 @return true if the strings are equal;
1166 false, otherwise.
1167 */
1168 bool equalsAscii( const char* asciiStr ) const
1169 {
1170 return rtl_ustr_ascii_compare_WithLength( pData->buffer, pData->length,
1171 asciiStr ) == 0;
1172 }
1173
1174 /**
1175 Perform a comparison of two strings.
1176
1177 The result is true if and only if second string
1178 represents the same sequence of characters as the first string.
1179 Since this method is optimized for performance, the ASCII character
1180 values are not converted in any way. The caller has to make sure that
1181 all ASCII characters are in the allowed range between 0 and 127.
1182 The ASCII string must be NULL-terminated and must be greater than
1183 or equal to asciiStrLength.
1184 This function can't be used for language specific comparison.
1185
1186 @param asciiStr the 8-Bit ASCII character string to be compared.
1187 @param asciiStrLength the length of the ascii string
1188 @return true if the strings are equal;
1189 false, otherwise.
1190 */
1191 bool equalsAsciiL( const char* asciiStr, sal_Int32 asciiStrLength ) const
1192 {
1193 if ( pData->length != asciiStrLength )
1194 return false;
1195
1196 return rtl_ustr_asciil_reverseEquals_WithLength(
1197 pData->buffer, asciiStr, asciiStrLength );
1198 }
1199
1200 /**
1201 Perform an ASCII lowercase comparison of two strings.
1202
1203 The result is true if and only if second string
1204 represents the same sequence of characters as the first string,
1205 ignoring the case.
1206 Character values between 65 and 90 (ASCII A-Z) are interpreted as
1207 values between 97 and 122 (ASCII a-z).
1208 Since this method is optimized for performance, the ASCII character
1209 values are not converted in any way. The caller has to make sure that
1210 all ASCII characters are in the allowed range between 0 and 127.
1211 The ASCII string must be NULL-terminated.
1212 This function can't be used for language specific comparison.
1213
1214 @param asciiStr the 8-Bit ASCII character string to be compared.
1215 @return true if the strings are equal;
1216 false, otherwise.
1217 */
1218 bool equalsIgnoreAsciiCaseAscii( const char * asciiStr ) const
1219 {
1220 return rtl_ustr_ascii_compareIgnoreAsciiCase_WithLength( pData->buffer, pData->length, asciiStr ) == 0;
1221 }
1222
1223 /**
1224 Compares two ASCII strings ignoring case
1225
1226 The comparison is based on the numeric value of each character in
1227 the strings and return a value indicating their relationship.
1228 Since this method is optimized for performance, the ASCII character
1229 values are not converted in any way. The caller has to make sure that
1230 all ASCII characters are in the allowed range between 0 and 127.
1231 The ASCII string must be NULL-terminated.
1232 This function can't be used for language specific sorting.
1233
1234 @param asciiStr the 8-Bit ASCII character string to be compared.
1235 @return 0 - if both strings are equal
1236 < 0 - if this string is less than the string argument
1237 > 0 - if this string is greater than the string argument
1238
1239 @since LibreOffice 3.5
1240 */
1241 sal_Int32 compareToIgnoreAsciiCaseAscii( const char * asciiStr ) const
1242 {
1243 return rtl_ustr_ascii_compareIgnoreAsciiCase_WithLength( pData->buffer, pData->length, asciiStr );
1244 }
1245
1246 /**
1247 Perform an ASCII lowercase comparison of two strings.
1248
1249 The result is true if and only if second string
1250 represents the same sequence of characters as the first string,
1251 ignoring the case.
1252 Character values between 65 and 90 (ASCII A-Z) are interpreted as
1253 values between 97 and 122 (ASCII a-z).
1254 Since this method is optimized for performance, the ASCII character
1255 values are not converted in any way. The caller has to make sure that
1256 all ASCII characters are in the allowed range between 0 and 127.
1257 The ASCII string must be NULL-terminated and must be greater than
1258 or equal to asciiStrLength.
1259 This function can't be used for language specific comparison.
1260
1261 @param asciiStr the 8-Bit ASCII character string to be compared.
1262 @param asciiStrLength the length of the ascii string
1263 @return true if the strings are equal;
1264 false, otherwise.
1265 */
1266 bool equalsIgnoreAsciiCaseAsciiL( const char * asciiStr, sal_Int32 asciiStrLength ) const
1267 {
1268 if ( pData->length != asciiStrLength )
1269 return false;
1270
1271 return rtl_ustr_ascii_compareIgnoreAsciiCase_WithLength( pData->buffer, pData->length, asciiStr ) == 0;
1272 }
1273
1274 /**
1275 Match against a substring appearing in this string.
1276
1277 The result is true if and only if the second string appears as a substring
1278 of this string, at the given position.
1279 Since this method is optimized for performance, the ASCII character
1280 values are not converted in any way. The caller has to make sure that
1281 all ASCII characters are in the allowed range between 0 and 127.
1282 The ASCII string must be NULL-terminated and must be greater than or
1283 equal to asciiStrLength.
1284 This function can't be used for language specific comparison.
1285
1286 @param asciiStr the object (substring) to be compared.
1287 @param asciiStrLength the length of asciiStr.
1288 @param fromIndex the index to start the comparison from.
1289 The index must be greater than or equal to 0
1290 and less than or equal to the string length.
1291 @return true if str match with the characters in the string
1292 at the given position;
1293 false, otherwise.
1294 */
1295 bool matchAsciiL( const char* asciiStr, sal_Int32 asciiStrLength, sal_Int32 fromIndex = 0 ) const
1296 {
1297 return rtl_ustr_ascii_shortenedCompare_WithLength( pData->buffer+fromIndex, pData->length-fromIndex,
1298 asciiStr, asciiStrLength ) == 0;
1299 }
1300
1301 // This overload is left undefined, to detect calls of matchAsciiL that
1302 // erroneously use RTL_CONSTASCII_USTRINGPARAM instead of
1303 // RTL_CONSTASCII_STRINGPARAM (but would lead to ambiguities on 32 bit
1304 // platforms):
1305#if SAL_TYPES_SIZEOFLONG8 == 8
1306 void matchAsciiL(char const *, sal_Int32, rtl_TextEncoding) const;
1307#endif
1308
1309 /**
1310 Match against a substring appearing in this string, ignoring the case of
1311 ASCII letters.
1312
1313 The result is true if and only if the second string appears as a substring
1314 of this string, at the given position.
1315 Character values between 65 and 90 (ASCII A-Z) are interpreted as
1316 values between 97 and 122 (ASCII a-z).
1317 Since this method is optimized for performance, the ASCII character
1318 values are not converted in any way. The caller has to make sure that
1319 all ASCII characters are in the allowed range between 0 and 127.
1320 The ASCII string must be NULL-terminated and must be greater than or
1321 equal to asciiStrLength.
1322 This function can't be used for language specific comparison.
1323
1324 @param asciiStr the 8-Bit ASCII character string to be compared.
1325 @param asciiStrLength the length of the ascii string
1326 @param fromIndex the index to start the comparison from.
1327 The index must be greater than or equal to 0
1328 and less than or equal to the string length.
1329 @return true if str match with the characters in the string
1330 at the given position;
1331 false, otherwise.
1332 */
1333 bool matchIgnoreAsciiCaseAsciiL( const char* asciiStr, sal_Int32 asciiStrLength, sal_Int32 fromIndex = 0 ) const
1334 {
1335 return rtl_ustr_ascii_shortenedCompareIgnoreAsciiCase_WithLength( pData->buffer+fromIndex, pData->length-fromIndex,
1336 asciiStr, asciiStrLength ) == 0;
1337 }
1338
1339 // This overload is left undefined, to detect calls of
1340 // matchIgnoreAsciiCaseAsciiL that erroneously use
1341 // RTL_CONSTASCII_USTRINGPARAM instead of RTL_CONSTASCII_STRINGPARAM (but
1342 // would lead to ambiguities on 32 bit platforms):
1343#if SAL_TYPES_SIZEOFLONG8 == 8
1344 void matchIgnoreAsciiCaseAsciiL(char const *, sal_Int32, rtl_TextEncoding)
1345 const;
1346#endif
1347
1348 /**
1349 Check whether this string starts with a given substring.
1350
1351 @param str the substring to be compared
1352
1353 @param rest if non-null, and this function returns true, then assign a
1354 copy of the remainder of this string to *rest. Available since
1355 LibreOffice 4.2
1356
1357 @return true if and only if the given str appears as a substring at the
1358 start of this string
1359
1360 @since LibreOffice 4.0
1361 */
1362#if defined LIBO_INTERNAL_ONLY1
1363 bool startsWith(std::u16string_view sv, OUString * rest = nullptr) const {
1364 auto const b = match(sv);
1365 if (b && rest != nullptr) {
1366 *rest = copy(sv.size());
1367 }
1368 return b;
1369 }
1370#else
1371 bool startsWith(OUString const & str, OUString * rest = NULL__null) const {
1372 bool b = match(str);
1373 if (b && rest != NULL__null) {
1374 *rest = copy(str.getLength());
1375 }
1376 return b;
1377 }
1378#endif
1379
1380 /**
1381 @overload
1382 This function accepts an ASCII string literal as its argument.
1383 @since LibreOffice 4.0
1384 */
1385 template< typename T >
1386 typename libreoffice_internal::ConstCharArrayDetector< T, bool >::Type startsWith(
1387 T & literal, OUString * rest = NULL__null) const
1388 {
1389 assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 1390, __extension__ __PRETTY_FUNCTION__))
1390 libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 1390, __extension__ __PRETTY_FUNCTION__))
;
1391 bool b
1392 = (libreoffice_internal::ConstCharArrayDetector<T>::length
1393 <= sal_uInt32(pData->length))
1394 && rtl_ustr_asciil_reverseEquals_WithLength(
1395 pData->buffer,
1396 libreoffice_internal::ConstCharArrayDetector<T>::toPointer(
1397 literal),
1398 libreoffice_internal::ConstCharArrayDetector<T>::length);
1399 if (b && rest != NULL__null) {
1400 *rest = copy(
1401 libreoffice_internal::ConstCharArrayDetector<T>::length);
1402 }
1403 return b;
1404 }
1405
1406 /**
1407 Check whether this string starts with a given string, ignoring the case of
1408 ASCII letters.
1409
1410 Character values between 65 and 90 (ASCII A-Z) are interpreted as
1411 values between 97 and 122 (ASCII a-z).
1412 This function can't be used for language specific comparison.
1413
1414 @param str the substring to be compared
1415
1416 @param rest if non-null, and this function returns true, then assign a
1417 copy of the remainder of this string to *rest. Available since
1418 LibreOffice 4.2
1419
1420 @return true if and only if the given str appears as a substring at the
1421 start of this string, ignoring the case of ASCII letters ("A"--"Z" and
1422 "a"--"z")
1423
1424 @since LibreOffice 4.0
1425 */
1426#if defined LIBO_INTERNAL_ONLY1
1427 bool startsWithIgnoreAsciiCase(std::u16string_view sv, OUString * rest = nullptr) const {
1428 auto const b = matchIgnoreAsciiCase(sv);
1429 if (b && rest != nullptr) {
1430 *rest = copy(sv.size());
1431 }
1432 return b;
1433 }
1434#else
1435 bool startsWithIgnoreAsciiCase(OUString const & str, OUString * rest = NULL__null)
1436 const
1437 {
1438 bool b = matchIgnoreAsciiCase(str);
1439 if (b && rest != NULL__null) {
1440 *rest = copy(str.getLength());
1441 }
1442 return b;
1443 }
1444#endif
1445
1446 /**
1447 @overload
1448 This function accepts an ASCII string literal as its argument.
1449 @since LibreOffice 4.0
1450 */
1451 template< typename T >
1452 typename libreoffice_internal::ConstCharArrayDetector< T, bool >::Type
1453 startsWithIgnoreAsciiCase(T & literal, OUString * rest = NULL__null) const
1454 {
1455 assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 1456, __extension__ __PRETTY_FUNCTION__))
1456 libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 1456, __extension__ __PRETTY_FUNCTION__))
;
1457 bool b
1458 = (rtl_ustr_ascii_compareIgnoreAsciiCase_WithLengths(
1459 pData->buffer,
1460 libreoffice_internal::ConstCharArrayDetector<T>::length,
1461 libreoffice_internal::ConstCharArrayDetector<T>::toPointer(
1462 literal),
1463 libreoffice_internal::ConstCharArrayDetector<T>::length)
1464 == 0);
1465 if (b && rest != NULL__null) {
1466 *rest = copy(
1467 libreoffice_internal::ConstCharArrayDetector<T>::length);
1468 }
1469 return b;
1470 }
1471
1472 /**
1473 Check whether this string ends with a given substring.
1474
1475 @param str the substring to be compared
1476
1477 @param rest if non-null, and this function returns true, then assign a
1478 copy of the remainder of this string to *rest. Available since
1479 LibreOffice 4.2
1480
1481 @return true if and only if the given str appears as a substring at the
1482 end of this string
1483
1484 @since LibreOffice 3.6
1485 */
1486#if defined LIBO_INTERNAL_ONLY1
1487 bool endsWith(std::u16string_view sv, OUString * rest = nullptr) const {
1488 auto const b = sv.size() <= sal_uInt32(pData->length)
1489 && match(sv, pData->length - sv.size());
1490 if (b && rest != nullptr) {
1491 *rest = copy(0, (pData->length - sv.size()));
1492 }
1493 return b;
1494 }
1495#else
1496 bool endsWith(OUString const & str, OUString * rest = NULL__null) const {
1497 bool b = str.getLength() <= getLength()
1498 && match(str, getLength() - str.getLength());
1499 if (b && rest != NULL__null) {
1500 *rest = copy(0, getLength() - str.getLength());
1501 }
1502 return b;
1503 }
1504#endif
1505
1506 /**
1507 @overload
1508 This function accepts an ASCII string literal as its argument.
1509 @since LibreOffice 3.6
1510 */
1511 template< typename T >
1512 typename libreoffice_internal::ConstCharArrayDetector< T, bool >::Type
1513 endsWith(T & literal, OUString * rest = NULL__null) const
1514 {
1515 assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 1516, __extension__ __PRETTY_FUNCTION__))
1516 libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 1516, __extension__ __PRETTY_FUNCTION__))
;
1517 bool b
1518 = (libreoffice_internal::ConstCharArrayDetector<T>::length
1519 <= sal_uInt32(pData->length))
1520 && rtl_ustr_asciil_reverseEquals_WithLength(
1521 (pData->buffer + pData->length
1522 - libreoffice_internal::ConstCharArrayDetector<T>::length),
1523 libreoffice_internal::ConstCharArrayDetector<T>::toPointer(
1524 literal),
1525 libreoffice_internal::ConstCharArrayDetector<T>::length);
1526 if (b && rest != NULL__null) {
1527 *rest = copy(
1528 0,
1529 (getLength()
1530 - libreoffice_internal::ConstCharArrayDetector<T>::length));
1531 }
1532 return b;
1533 }
1534
1535 /**
1536 Check whether this string ends with a given ASCII string.
1537
1538 @param asciiStr a sequence of at least asciiStrLength ASCII characters
1539 (bytes in the range 0x00--0x7F)
1540 @param asciiStrLength the length of asciiStr; must be non-negative
1541 @return true if this string ends with asciiStr; otherwise, false is
1542 returned
1543
1544 @since UDK 3.2.7
1545 */
1546 bool endsWithAsciiL(char const * asciiStr, sal_Int32 asciiStrLength)
1547 const
1548 {
1549 return asciiStrLength <= pData->length
1550 && rtl_ustr_asciil_reverseEquals_WithLength(
1551 pData->buffer + pData->length - asciiStrLength, asciiStr,
1552 asciiStrLength);
1553 }
1554
1555 /**
1556 Check whether this string ends with a given string, ignoring the case of
1557 ASCII letters.
1558
1559 Character values between 65 and 90 (ASCII A-Z) are interpreted as
1560 values between 97 and 122 (ASCII a-z).
1561 This function can't be used for language specific comparison.
1562
1563 @param str the substring to be compared
1564
1565 @param rest if non-null, and this function returns true, then assign a
1566 copy of the remainder of this string to *rest. Available since
1567 LibreOffice 4.2
1568
1569 @return true if and only if the given str appears as a substring at the
1570 end of this string, ignoring the case of ASCII letters ("A"--"Z" and
1571 "a"--"z")
1572
1573 @since LibreOffice 3.6
1574 */
1575#if defined LIBO_INTERNAL_ONLY1
1576 bool endsWithIgnoreAsciiCase(std::u16string_view sv, OUString * rest = nullptr) const {
1577 auto const b = sv.size() <= sal_uInt32(pData->length)
1578 && matchIgnoreAsciiCase(sv, pData->length - sv.size());
1579 if (b && rest != nullptr) {
1580 *rest = copy(0, pData->length - sv.size());
1581 }
1582 return b;
1583 }
1584#else
1585 bool endsWithIgnoreAsciiCase(OUString const & str, OUString * rest = NULL__null) const
1586 {
1587 bool b = str.getLength() <= getLength()
1588 && matchIgnoreAsciiCase(str, getLength() - str.getLength());
1589 if (b && rest != NULL__null) {
1590 *rest = copy(0, getLength() - str.getLength());
1591 }
1592 return b;
1593 }
1594#endif
1595
1596 /**
1597 @overload
1598 This function accepts an ASCII string literal as its argument.
1599 @since LibreOffice 3.6
1600 */
1601 template< typename T >
1602 typename libreoffice_internal::ConstCharArrayDetector< T, bool >::Type
1603 endsWithIgnoreAsciiCase(T & literal, OUString * rest = NULL__null) const
1604 {
1605 assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 1606, __extension__ __PRETTY_FUNCTION__))
1606 libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 1606, __extension__ __PRETTY_FUNCTION__))
;
1607 bool b
1608 = (libreoffice_internal::ConstCharArrayDetector<T>::length
1609 <= sal_uInt32(pData->length))
1610 && (rtl_ustr_ascii_compareIgnoreAsciiCase_WithLengths(
1611 (pData->buffer + pData->length
1612 - libreoffice_internal::ConstCharArrayDetector<T>::length),
1613 libreoffice_internal::ConstCharArrayDetector<T>::length,
1614 libreoffice_internal::ConstCharArrayDetector<T>::toPointer(
1615 literal),
1616 libreoffice_internal::ConstCharArrayDetector<T>::length)
1617 == 0);
1618 if (b && rest != NULL__null) {
1619 *rest = copy(
1620 0,
1621 (getLength()
1622 - libreoffice_internal::ConstCharArrayDetector<T>::length));
1623 }
1624 return b;
1625 }
1626
1627 /**
1628 Check whether this string ends with a given ASCII string, ignoring the
1629 case of ASCII letters.
1630
1631 @param asciiStr a sequence of at least asciiStrLength ASCII characters
1632 (bytes in the range 0x00--0x7F)
1633 @param asciiStrLength the length of asciiStr; must be non-negative
1634 @return true if this string ends with asciiStr, ignoring the case of ASCII
1635 letters ("A"--"Z" and "a"--"z"); otherwise, false is returned
1636 */
1637 bool endsWithIgnoreAsciiCaseAsciiL(
1638 char const * asciiStr, sal_Int32 asciiStrLength) const
1639 {
1640 return asciiStrLength <= pData->length
1641 && (rtl_ustr_ascii_compareIgnoreAsciiCase_WithLengths(
1642 pData->buffer + pData->length - asciiStrLength,
1643 asciiStrLength, asciiStr, asciiStrLength)
1644 == 0);
1645 }
1646
1647 friend bool operator == ( const OUString& rStr1, const OUString& rStr2 )
1648 { return rStr1.equals(rStr2); }
1649
1650 friend bool operator != ( const OUString& rStr1, const OUString& rStr2 )
1651 { return !(operator == ( rStr1, rStr2 )); }
1652
1653 friend bool operator < ( const OUString& rStr1, const OUString& rStr2 )
1654 { return rStr1.compareTo( rStr2 ) < 0; }
1655 friend bool operator > ( const OUString& rStr1, const OUString& rStr2 )
1656 { return rStr1.compareTo( rStr2 ) > 0; }
1657 friend bool operator <= ( const OUString& rStr1, const OUString& rStr2 )
1658 { return rStr1.compareTo( rStr2 ) <= 0; }
1659 friend bool operator >= ( const OUString& rStr1, const OUString& rStr2 )
1660 { return rStr1.compareTo( rStr2 ) >= 0; }
1661
1662#if defined LIBO_INTERNAL_ONLY1
1663
1664 template<typename T> friend typename libreoffice_internal::CharPtrDetector<T, bool>::TypeUtf16
1665 operator ==(OUString const & s1, T const & s2) {
1666 return rtl_ustr_compare_WithLength(s1.getStr(), s1.getLength(), s2, rtl_ustr_getLength(s2))
1667 == 0;
1668 }
1669
1670 template<typename T>
1671 friend typename libreoffice_internal::NonConstCharArrayDetector<T, bool>::TypeUtf16
1672 operator ==(OUString const & s1, T & s2) {
1673 return rtl_ustr_compare_WithLength(s1.getStr(), s1.getLength(), s2, rtl_ustr_getLength(s2))
1674 == 0;
1675 }
1676
1677 template<typename T> friend typename libreoffice_internal::CharPtrDetector<T, bool>::TypeUtf16
1678 operator ==(T const & s1, OUString const & s2) {
1679 return rtl_ustr_compare_WithLength(s1, rtl_ustr_getLength(s1), s2.getStr(), s2.getLength())
1680 == 0;
1681 }
1682
1683 template<typename T>
1684 friend typename libreoffice_internal::NonConstCharArrayDetector<T, bool>::TypeUtf16
1685 operator ==(T & s1, OUString const & s2) {
1686 return rtl_ustr_compare_WithLength(s1, rtl_ustr_getLength(s1), s2.getStr(), s2.getLength())
1687 == 0;
1688 }
1689
1690 template<typename T> friend typename libreoffice_internal::CharPtrDetector<T, bool>::TypeUtf16
1691 operator !=(OUString const & s1, T const & s2) { return !(s1 == s2); }
1692
1693 template<typename T>
1694 friend typename libreoffice_internal::NonConstCharArrayDetector<T, bool>::TypeUtf16
1695 operator !=(OUString const & s1, T & s2) { return !(s1 == s2); }
1696
1697 template<typename T> friend typename libreoffice_internal::CharPtrDetector<T, bool>::TypeUtf16
1698 operator !=(T const & s1, OUString const & s2) { return !(s1 == s2); }
1699
1700 template<typename T>
1701 friend typename libreoffice_internal::NonConstCharArrayDetector<T, bool>::TypeUtf16
1702 operator !=(T & s1, OUString const & s2) { return !(s1 == s2); }
1703
1704#else
1705
1706 friend bool operator == ( const OUString& rStr1, const sal_Unicode * pStr2 )
1707 { return rStr1.compareTo( pStr2 ) == 0; }
1708 friend bool operator == ( const sal_Unicode * pStr1, const OUString& rStr2 )
1709 { return OUString( pStr1 ).compareTo( rStr2 ) == 0; }
1710
1711 friend bool operator != ( const OUString& rStr1, const sal_Unicode * pStr2 )
1712 { return !(operator == ( rStr1, pStr2 )); }
1713 friend bool operator != ( const sal_Unicode * pStr1, const OUString& rStr2 )
1714 { return !(operator == ( pStr1, rStr2 )); }
1715
1716#endif
1717
1718 /**
1719 * Compare string to an ASCII string literal.
1720 *
1721 * This operator is equal to calling equalsAsciiL().
1722 *
1723 * @since LibreOffice 3.6
1724 */
1725 template< typename T >
1726 friend typename libreoffice_internal::ConstCharArrayDetector< T, bool >::Type operator==( const OUString& rString, T& literal )
1727 {
1728 assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 1729, __extension__ __PRETTY_FUNCTION__))
1729 libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 1729, __extension__ __PRETTY_FUNCTION__))
;
1730 return rString.equalsAsciiL(
1731 libreoffice_internal::ConstCharArrayDetector<T>::toPointer(literal),
1732 libreoffice_internal::ConstCharArrayDetector<T>::length);
1733 }
1734 /**
1735 * Compare string to an ASCII string literal.
1736 *
1737 * This operator is equal to calling equalsAsciiL().
1738 *
1739 * @since LibreOffice 3.6
1740 */
1741 template< typename T >
1742 friend typename libreoffice_internal::ConstCharArrayDetector< T, bool >::Type operator==( T& literal, const OUString& rString )
1743 {
1744 assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 1745, __extension__ __PRETTY_FUNCTION__))
1745 libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 1745, __extension__ __PRETTY_FUNCTION__))
;
1746 return rString.equalsAsciiL(
1747 libreoffice_internal::ConstCharArrayDetector<T>::toPointer(literal),
1748 libreoffice_internal::ConstCharArrayDetector<T>::length);
1749 }
1750 /**
1751 * Compare string to an ASCII string literal.
1752 *
1753 * This operator is equal to calling !equalsAsciiL().
1754 *
1755 * @since LibreOffice 3.6
1756 */
1757 template< typename T >
1758 friend typename libreoffice_internal::ConstCharArrayDetector< T, bool >::Type operator!=( const OUString& rString, T& literal )
1759 {
1760 assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 1761, __extension__ __PRETTY_FUNCTION__))
1761 libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 1761, __extension__ __PRETTY_FUNCTION__))
;
1762 return !rString.equalsAsciiL(
1763 libreoffice_internal::ConstCharArrayDetector<T>::toPointer(literal),
1764 libreoffice_internal::ConstCharArrayDetector<T>::length);
1765 }
1766 /**
1767 * Compare string to an ASCII string literal.
1768 *
1769 * This operator is equal to calling !equalsAsciiL().
1770 *
1771 * @since LibreOffice 3.6
1772 */
1773 template< typename T >
1774 friend typename libreoffice_internal::ConstCharArrayDetector< T, bool >::Type operator!=( T& literal, const OUString& rString )
1775 {
1776 assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 1777, __extension__ __PRETTY_FUNCTION__))
1777 libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 1777, __extension__ __PRETTY_FUNCTION__))
;
1778 return !rString.equalsAsciiL(
1779 libreoffice_internal::ConstCharArrayDetector<T>::toPointer(literal),
1780 libreoffice_internal::ConstCharArrayDetector<T>::length);
1781 }
1782
1783#if defined LIBO_INTERNAL_ONLY1
1784 /** @overload @since LibreOffice 5.3 */
1785 template<typename T> friend typename libreoffice_internal::ConstCharArrayDetector<T, bool>::TypeUtf16
1786 operator ==(OUString const & string, T & literal) {
1787 return
1788 rtl_ustr_reverseCompare_WithLength(
1789 string.pData->buffer, string.pData->length,
1790 libreoffice_internal::ConstCharArrayDetector<T>::toPointer(
1791 literal),
1792 libreoffice_internal::ConstCharArrayDetector<T>::length)
1793 == 0;
1794 }
1795 /** @overload @since LibreOffice 5.3 */
1796 template<typename T> friend typename libreoffice_internal::ConstCharArrayDetector<T, bool>::TypeUtf16
1797 operator ==(T & literal, OUString const & string) {
1798 return
1799 rtl_ustr_reverseCompare_WithLength(
1800 libreoffice_internal::ConstCharArrayDetector<T>::toPointer(
1801 literal),
1802 libreoffice_internal::ConstCharArrayDetector<T>::length,
1803 string.pData->buffer, string.pData->length)
1804 == 0;
1805 }
1806 /** @overload @since LibreOffice 5.3 */
1807 template<typename T> friend typename libreoffice_internal::ConstCharArrayDetector<T, bool>::TypeUtf16
1808 operator !=(OUString const & string, T & literal) {
1809 return
1810 rtl_ustr_reverseCompare_WithLength(
1811 string.pData->buffer, string.pData->length,
1812 libreoffice_internal::ConstCharArrayDetector<T>::toPointer(
1813 literal),
1814 libreoffice_internal::ConstCharArrayDetector<T>::length)
1815 != 0;
1816 }
1817 /** @overload @since LibreOffice 5.3 */
1818 template<typename T> friend typename libreoffice_internal::ConstCharArrayDetector<T, bool>::TypeUtf16
1819 operator !=(T & literal, OUString const & string) {
1820 return
1821 rtl_ustr_reverseCompare_WithLength(
1822 libreoffice_internal::ConstCharArrayDetector<T>::toPointer(
1823 literal),
1824 libreoffice_internal::ConstCharArrayDetector<T>::length,
1825 string.pData->buffer, string.pData->length)
1826 != 0;
1827 }
1828#endif
1829
1830#if defined LIBO_INTERNAL_ONLY1
1831 /// @cond INTERNAL
1832
1833 /* Comparison between OUString and OUStringLiteral.
1834
1835 @since LibreOffice 5.0
1836 */
1837
1838 template<std::size_t N>
1839 friend bool operator ==(OUString const & lhs, OUStringLiteral<N> const & rhs) {
1840 return
1841 rtl_ustr_reverseCompare_WithLength(
1842 lhs.pData->buffer, lhs.pData->length, rhs.getStr(), rhs.getLength())
1843 == 0;
1844 }
1845
1846 template<std::size_t N>
1847 friend bool operator !=(OUString const & lhs, OUStringLiteral<N> const & rhs) {
1848 return
1849 rtl_ustr_reverseCompare_WithLength(
1850 lhs.pData->buffer, lhs.pData->length, rhs.getStr(), rhs.getLength())
1851 != 0;
1852 }
1853
1854 template<std::size_t N>
1855 friend bool operator <(OUString const & lhs, OUStringLiteral<N> const & rhs) {
1856 return
1857 (rtl_ustr_compare_WithLength(
1858 lhs.pData->buffer, lhs.pData->length, rhs.getStr(), rhs.getLength()))
1859 < 0;
1860 }
1861
1862 template<std::size_t N>
1863 friend bool operator <=(OUString const & lhs, OUStringLiteral<N> const & rhs) {
1864 return
1865 (rtl_ustr_compare_WithLength(
1866 lhs.pData->buffer, lhs.pData->length, rhs.getStr(), rhs.getLength()))
1867 <= 0;
1868 }
1869
1870 template<std::size_t N>
1871 friend bool operator >(OUString const & lhs, OUStringLiteral<N> const & rhs) {
1872 return
1873 (rtl_ustr_compare_WithLength(
1874 lhs.pData->buffer, lhs.pData->length, rhs.getStr(), rhs.getLength()))
1875 > 0;
1876 }
1877
1878 template<std::size_t N>
1879 friend bool operator >=(OUString const & lhs, OUStringLiteral<N> const & rhs) {
1880 return
1881 (rtl_ustr_compare_WithLength(
1882 lhs.pData->buffer, lhs.pData->length, rhs.getStr(), rhs.getLength()))
1883 >= 0;
1884 }
1885
1886 template<std::size_t N>
1887 friend bool operator ==(OUStringLiteral<N> const & lhs, OUString const & rhs) {
1888 return
1889 rtl_ustr_reverseCompare_WithLength(
1890 lhs.getStr(), lhs.getLength(), rhs.pData->buffer, rhs.pData->length)
1891 == 0;
1892 }
1893
1894 template<std::size_t N>
1895 friend bool operator !=(OUStringLiteral<N> const & lhs, OUString const & rhs) {
1896 return
1897 rtl_ustr_reverseCompare_WithLength(
1898 lhs.getStr(), lhs.getLength(), rhs.pData->buffer, rhs.pData->length)
1899 != 0;
1900 }
1901
1902 template<std::size_t N>
1903 friend bool operator <(OUStringLiteral<N> const & lhs, OUString const & rhs) {
1904 return
1905 (rtl_ustr_compare_WithLength(
1906 lhs.getStr(), lhs.getLength(), rhs.pData->buffer, rhs.pData->length))
1907 < 0;
1908 }
1909
1910 template<std::size_t N>
1911 friend bool operator <=(OUStringLiteral<N> const & lhs, OUString const & rhs) {
1912 return
1913 (rtl_ustr_compare_WithLength(
1914 lhs.getStr(), lhs.getLength(), rhs.pData->buffer, rhs.pData->length))
1915 <= 0;
1916 }
1917
1918 template<std::size_t N>
1919 friend bool operator >(OUStringLiteral<N> const & lhs, OUString const & rhs) {
1920 return
1921 (rtl_ustr_compare_WithLength(
1922 lhs.getStr(), lhs.getLength(), rhs.pData->buffer, rhs.pData->length))
1923 > 0;
1924 }
1925
1926 template<std::size_t N>
1927 friend bool operator >=(OUStringLiteral<N> const & lhs, OUString const & rhs) {
1928 return
1929 (rtl_ustr_compare_WithLength(
1930 lhs.getStr(), lhs.getLength(), rhs.pData->buffer, rhs.pData->length))
1931 >= 0;
1932 }
1933
1934 /// @endcond
1935#endif
1936
1937#if defined LIBO_INTERNAL_ONLY1
1938 friend bool operator ==(OUString const & lhs, std::u16string_view rhs) {
1939 return
1940 rtl_ustr_reverseCompare_WithLength(
1941 lhs.pData->buffer, lhs.pData->length, rhs.data(), rhs.size())
1942 == 0;
1943 }
1944
1945 friend bool operator !=(OUString const & lhs, std::u16string_view rhs) {
1946 return
1947 rtl_ustr_reverseCompare_WithLength(
1948 lhs.pData->buffer, lhs.pData->length, rhs.data(), rhs.size())
1949 != 0;
1950 }
1951
1952 friend bool operator <(OUString const & lhs, std::u16string_view rhs) {
1953 return
1954 (rtl_ustr_compare_WithLength(
1955 lhs.pData->buffer, lhs.pData->length, rhs.data(), rhs.size()))
1956 < 0;
1957 }
1958
1959 friend bool operator <=(OUString const & lhs, std::u16string_view rhs) {
1960 return
1961 (rtl_ustr_compare_WithLength(
1962 lhs.pData->buffer, lhs.pData->length, rhs.data(), rhs.size()))
1963 <= 0;
1964 }
1965
1966 friend bool operator >(OUString const & lhs, std::u16string_view rhs) {
1967 return
1968 (rtl_ustr_compare_WithLength(
1969 lhs.pData->buffer, lhs.pData->length, rhs.data(), rhs.size()))
1970 > 0;
1971 }
1972
1973 friend bool operator >=(OUString const & lhs, std::u16string_view rhs) {
1974 return
1975 (rtl_ustr_compare_WithLength(
1976 lhs.pData->buffer, lhs.pData->length, rhs.data(), rhs.size()))
1977 >= 0;
1978 }
1979
1980 friend bool operator ==(std::u16string_view lhs, OUString const & rhs) {
1981 return
1982 rtl_ustr_reverseCompare_WithLength(
1983 lhs.data(), lhs.size(), rhs.pData->buffer, rhs.pData->length)
1984 == 0;
1985 }
1986
1987 friend bool operator !=(std::u16string_view lhs, OUString const & rhs) {
1988 return
1989 rtl_ustr_reverseCompare_WithLength(
1990 lhs.data(), lhs.size(), rhs.pData->buffer, rhs.pData->length)
1991 != 0;
1992 }
1993
1994 friend bool operator <(std::u16string_view lhs, OUString const & rhs) {
1995 return
1996 (rtl_ustr_compare_WithLength(
1997 lhs.data(), lhs.size(), rhs.pData->buffer, rhs.pData->length))
1998 < 0;
1999 }
2000
2001 friend bool operator <=(std::u16string_view lhs, OUString const & rhs) {
2002 return
2003 (rtl_ustr_compare_WithLength(
2004 lhs.data(), lhs.size(), rhs.pData->buffer, rhs.pData->length))
2005 <= 0;
2006 }
2007
2008 friend bool operator >(std::u16string_view lhs, OUString const & rhs) {
2009 return
2010 (rtl_ustr_compare_WithLength(
2011 lhs.data(), lhs.size(), rhs.pData->buffer, rhs.pData->length))
2012 > 0;
2013 }
2014
2015 friend bool operator >=(std::u16string_view lhs, OUString const & rhs) {
2016 return
2017 (rtl_ustr_compare_WithLength(
2018 lhs.data(), lhs.size(), rhs.pData->buffer, rhs.pData->length))
2019 >= 0;
2020 }
2021#endif
2022
2023 /**
2024 Returns a hashcode for this string.
2025
2026 @return a hash code value for this object.
2027
2028 @see rtl::OUStringHash for convenient use of std::unordered_map
2029 */
2030 sal_Int32 hashCode() const
2031 {
2032 return rtl_ustr_hashCode_WithLength( pData->buffer, pData->length );
2033 }
2034
2035 /**
2036 Returns the index within this string of the first occurrence of the
2037 specified character, starting the search at the specified index.
2038
2039 @param ch character to be located.
2040 @param fromIndex the index to start the search from.
2041 The index must be greater than or equal to 0
2042 and less than or equal to the string length.
2043 @return the index of the first occurrence of the character in the
2044 character sequence represented by this string that is
2045 greater than or equal to fromIndex, or
2046 -1 if the character does not occur.
2047 */
2048 sal_Int32 indexOf( sal_Unicode ch, sal_Int32 fromIndex = 0 ) const
2049 {
2050 sal_Int32 ret = rtl_ustr_indexOfChar_WithLength( pData->buffer+fromIndex, pData->length-fromIndex, ch );
2051 return (ret < 0 ? ret : ret+fromIndex);
2052 }
2053
2054 /**
2055 Returns the index within this string of the last occurrence of the
2056 specified character, searching backward starting at the end.
2057
2058 @param ch character to be located.
2059 @return the index of the last occurrence of the character in the
2060 character sequence represented by this string, or
2061 -1 if the character does not occur.
2062 */
2063 sal_Int32 lastIndexOf( sal_Unicode ch ) const
2064 {
2065 return rtl_ustr_lastIndexOfChar_WithLength( pData->buffer, pData->length, ch );
2066 }
2067
2068 /**
2069 Returns the index within this string of the last occurrence of the
2070 specified character, searching backward starting before the specified
2071 index.
2072
2073 @param ch character to be located.
2074 @param fromIndex the index before which to start the search.
2075 @return the index of the last occurrence of the character in the
2076 character sequence represented by this string that
2077 is less than fromIndex, or -1
2078 if the character does not occur before that point.
2079 */
2080 sal_Int32 lastIndexOf( sal_Unicode ch, sal_Int32 fromIndex ) const
2081 {
2082 return rtl_ustr_lastIndexOfChar_WithLength( pData->buffer, fromIndex, ch );
2083 }
2084
2085 /**
2086 Returns the index within this string of the first occurrence of the
2087 specified substring, starting at the specified index.
2088
2089 If str doesn't include any character, always -1 is
2090 returned. This is also the case, if both strings are empty.
2091
2092 @param str the substring to search for.
2093 @param fromIndex the index to start the search from.
2094 @return If the string argument occurs one or more times as a substring
2095 within this string at the starting index, then the index
2096 of the first character of the first such substring is
2097 returned. If it does not occur as a substring starting
2098 at fromIndex or beyond, -1 is returned.
2099 */
2100#if defined LIBO_INTERNAL_ONLY1
2101 sal_Int32 indexOf(std::u16string_view sv, sal_Int32 fromIndex = 0) const {
2102 auto const n = rtl_ustr_indexOfStr_WithLength(
2103 pData->buffer + fromIndex, pData->length - fromIndex, sv.data(), sv.size());
2104 return n < 0 ? n : n + fromIndex;
2105 }
2106#else
2107 sal_Int32 indexOf( const OUString & str, sal_Int32 fromIndex = 0 ) const
2108 {
2109 sal_Int32 ret = rtl_ustr_indexOfStr_WithLength( pData->buffer+fromIndex, pData->length-fromIndex,
2110 str.pData->buffer, str.pData->length );
2111 return (ret < 0 ? ret : ret+fromIndex);
2112 }
2113#endif
2114
2115 /**
2116 @overload
2117 This function accepts an ASCII string literal as its argument.
2118 @since LibreOffice 3.6
2119 */
2120 template< typename T >
2121 typename libreoffice_internal::ConstCharArrayDetector< T, sal_Int32 >::Type indexOf( T& literal, sal_Int32 fromIndex = 0 ) const
2122 {
2123 assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 2124, __extension__ __PRETTY_FUNCTION__))
2124 libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 2124, __extension__ __PRETTY_FUNCTION__))
;
2125 sal_Int32 n = rtl_ustr_indexOfAscii_WithLength(
2126 pData->buffer + fromIndex, pData->length - fromIndex,
2127 libreoffice_internal::ConstCharArrayDetector<T>::toPointer(literal),
2128 libreoffice_internal::ConstCharArrayDetector<T>::length);
2129 return n < 0 ? n : n + fromIndex;
2130 }
2131
2132 /**
2133 Returns the index within this string of the first occurrence of the
2134 specified ASCII substring, starting at the specified index.
2135
2136 @param str
2137 the substring to be searched for. Need not be null-terminated, but must
2138 be at least as long as the specified len. Must only contain characters
2139 in the ASCII range 0x00--7F.
2140
2141 @param len
2142 the length of the substring; must be non-negative.
2143
2144 @param fromIndex
2145 the index to start the search from. Must be in the range from zero to
2146 the length of this string, inclusive.
2147
2148 @return
2149 the index (starting at 0) of the first character of the first occurrence
2150 of the substring within this string starting at the given fromIndex, or
2151 -1 if the substring does not occur. If len is zero, -1 is returned.
2152
2153 @since UDK 3.2.7
2154 */
2155 sal_Int32 indexOfAsciiL(
2156 char const * str, sal_Int32 len, sal_Int32 fromIndex = 0) const
2157 {
2158 sal_Int32 ret = rtl_ustr_indexOfAscii_WithLength(
2159 pData->buffer + fromIndex, pData->length - fromIndex, str, len);
2160 return ret < 0 ? ret : ret + fromIndex;
2161 }
2162
2163 // This overload is left undefined, to detect calls of indexOfAsciiL that
2164 // erroneously use RTL_CONSTASCII_USTRINGPARAM instead of
2165 // RTL_CONSTASCII_STRINGPARAM (but would lead to ambiguities on 32 bit
2166 // platforms):
2167#if SAL_TYPES_SIZEOFLONG8 == 8
2168 void indexOfAsciiL(char const *, sal_Int32 len, rtl_TextEncoding) const;
2169#endif
2170
2171 /**
2172 Returns the index within this string of the last occurrence of
2173 the specified substring, searching backward starting at the end.
2174
2175 The returned index indicates the starting index of the substring
2176 in this string.
2177 If str doesn't include any character, always -1 is
2178 returned. This is also the case, if both strings are empty.
2179
2180 @param str the substring to search for.
2181 @return If the string argument occurs one or more times as a substring
2182 within this string, then the index of the first character of
2183 the last such substring is returned. If it does not occur as
2184 a substring, -1 is returned.
2185 */
2186#if defined LIBO_INTERNAL_ONLY1
2187 sal_Int32 lastIndexOf(std::u16string_view sv) const {
2188 return rtl_ustr_lastIndexOfStr_WithLength(
2189 pData->buffer, pData->length, sv.data(), sv.size());
2190 }
2191#else
2192 sal_Int32 lastIndexOf( const OUString & str ) const
2193 {
2194 return rtl_ustr_lastIndexOfStr_WithLength( pData->buffer, pData->length,
2195 str.pData->buffer, str.pData->length );
2196 }
2197#endif
2198
2199 /**
2200 Returns the index within this string of the last occurrence of
2201 the specified substring, searching backward starting before the specified
2202 index.
2203
2204 The returned index indicates the starting index of the substring
2205 in this string.
2206 If str doesn't include any character, always -1 is
2207 returned. This is also the case, if both strings are empty.
2208
2209 @param str the substring to search for.
2210 @param fromIndex the index before which to start the search.
2211 @return If the string argument occurs one or more times as a substring
2212 within this string before the starting index, then the index
2213 of the first character of the last such substring is
2214 returned. Otherwise, -1 is returned.
2215 */
2216#if defined LIBO_INTERNAL_ONLY1
2217 sal_Int32 lastIndexOf(std::u16string_view sv, sal_Int32 fromIndex) const {
2218 return rtl_ustr_lastIndexOfStr_WithLength(pData->buffer, fromIndex, sv.data(), sv.size());
2219 }
2220#else
2221 sal_Int32 lastIndexOf( const OUString & str, sal_Int32 fromIndex ) const
2222 {
2223 return rtl_ustr_lastIndexOfStr_WithLength( pData->buffer, fromIndex,
2224 str.pData->buffer, str.pData->length );
2225 }
2226#endif
2227
2228 /**
2229 @overload
2230 This function accepts an ASCII string literal as its argument.
2231 @since LibreOffice 3.6
2232 */
2233 template< typename T >
2234 typename libreoffice_internal::ConstCharArrayDetector< T, sal_Int32 >::Type lastIndexOf( T& literal ) const
2235 {
2236 assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 2237, __extension__ __PRETTY_FUNCTION__))
2237 libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 2237, __extension__ __PRETTY_FUNCTION__))
;
2238 return rtl_ustr_lastIndexOfAscii_WithLength(
2239 pData->buffer, pData->length,
2240 libreoffice_internal::ConstCharArrayDetector<T>::toPointer(literal),
2241 libreoffice_internal::ConstCharArrayDetector<T>::length);
2242 }
2243
2244 /**
2245 Returns the index within this string of the last occurrence of the
2246 specified ASCII substring.
2247
2248 @param str
2249 the substring to be searched for. Need not be null-terminated, but must
2250 be at least as long as the specified len. Must only contain characters
2251 in the ASCII range 0x00--7F.
2252
2253 @param len
2254 the length of the substring; must be non-negative.
2255
2256 @return
2257 the index (starting at 0) of the first character of the last occurrence
2258 of the substring within this string, or -1 if the substring does not
2259 occur. If len is zero, -1 is returned.
2260
2261 @since UDK 3.2.7
2262 */
2263 sal_Int32 lastIndexOfAsciiL(char const * str, sal_Int32 len) const
2264 {
2265 return rtl_ustr_lastIndexOfAscii_WithLength(
2266 pData->buffer, pData->length, str, len);
2267 }
2268
2269 /**
2270 Returns a new string that is a substring of this string.
2271
2272 The substring begins at the specified beginIndex. If
2273 beginIndex is negative or be greater than the length of
2274 this string, behaviour is undefined.
2275
2276 @param beginIndex the beginning index, inclusive.
2277 @return the specified substring.
2278 */
2279 SAL_WARN_UNUSED_RESULT[[nodiscard]] OUString copy( sal_Int32 beginIndex ) const
2280 {
2281 return copy(beginIndex, getLength() - beginIndex);
2282 }
2283
2284 /**
2285 Returns a new string that is a substring of this string.
2286
2287 The substring begins at the specified beginIndex and contains count
2288 characters. If either beginIndex or count are negative,
2289 or beginIndex + count are greater than the length of this string
2290 then behaviour is undefined.
2291
2292 @param beginIndex the beginning index, inclusive.
2293 @param count the number of characters.
2294 @return the specified substring.
2295 */
2296 SAL_WARN_UNUSED_RESULT[[nodiscard]] OUString copy( sal_Int32 beginIndex, sal_Int32 count ) const
2297 {
2298 rtl_uString *pNew = NULL__null;
2299 rtl_uString_newFromSubString( &pNew, pData, beginIndex, count );
2300 return OUString( pNew, SAL_NO_ACQUIRE );
2301 }
2302
2303 /**
2304 Concatenates the specified string to the end of this string.
2305
2306 @param str the string that is concatenated to the end
2307 of this string.
2308 @return a string that represents the concatenation of this string
2309 followed by the string argument.
2310 */
2311 SAL_WARN_UNUSED_RESULT[[nodiscard]] OUString concat( const OUString & str ) const
2312 {
2313 rtl_uString* pNew = NULL__null;
2314 rtl_uString_newConcat( &pNew, pData, str.pData );
2315 return OUString( pNew, SAL_NO_ACQUIRE );
2316 }
2317
2318#ifndef LIBO_INTERNAL_ONLY1 // "RTL_FAST_STRING"
2319 friend OUString operator+( const OUString& rStr1, const OUString& rStr2 )
2320 {
2321 return rStr1.concat( rStr2 );
2322 }
2323#endif
2324
2325 /**
2326 Returns a new string resulting from replacing n = count characters
2327 from position index in this string with newStr.
2328
2329 @param index the replacing index in str.
2330 The index must be greater than or equal to 0 and
2331 less than or equal to the length of the string.
2332 @param count the count of characters that will be replaced
2333 The count must be greater than or equal to 0 and
2334 less than or equal to the length of the string minus index.
2335 @param newStr the new substring.
2336 @return the new string.
2337 */
2338 SAL_WARN_UNUSED_RESULT[[nodiscard]] OUString replaceAt( sal_Int32 index, sal_Int32 count, const OUString& newStr ) const
2339 {
2340 rtl_uString* pNew = NULL__null;
2341 rtl_uString_newReplaceStrAt( &pNew, pData, index, count, newStr.pData );
2342 return OUString( pNew, SAL_NO_ACQUIRE );
2343 }
2344
2345 /**
2346 Returns a new string resulting from replacing all occurrences of
2347 oldChar in this string with newChar.
2348
2349 If the character oldChar does not occur in the character sequence
2350 represented by this object, then the string is assigned with
2351 str.
2352
2353 @param oldChar the old character.
2354 @param newChar the new character.
2355 @return a string derived from this string by replacing every
2356 occurrence of oldChar with newChar.
2357 */
2358 SAL_WARN_UNUSED_RESULT[[nodiscard]] OUString replace( sal_Unicode oldChar, sal_Unicode newChar ) const
2359 {
2360 rtl_uString* pNew = NULL__null;
2361 rtl_uString_newReplace( &pNew, pData, oldChar, newChar );
2362 return OUString( pNew, SAL_NO_ACQUIRE );
2363 }
2364
2365 /**
2366 Returns a new string resulting from replacing the first occurrence of a
2367 given substring with another substring.
2368
2369 @param from the substring to be replaced
2370
2371 @param to the replacing substring
2372
2373 @param[in,out] index pointer to a start index; if the pointer is
2374 non-null: upon entry to the function, its value is the index into this
2375 string at which to start searching for the \p from substring, the value
2376 must be non-negative and not greater than this string's length; upon exiting
2377 the function its value is the index into this string at which the
2378 replacement took place or -1 if no replacement took place; if the pointer
2379 is null, searching always starts at index 0
2380
2381 @since LibreOffice 3.6
2382 */
2383#if defined LIBO_INTERNAL_ONLY1
2384 [[nodiscard]] OUString replaceFirst(
2385 std::u16string_view from, std::u16string_view to, sal_Int32 * index = nullptr) const
2386 {
2387 rtl_uString * s = nullptr;
2388 sal_Int32 i = 0;
2389 rtl_uString_newReplaceFirstUtf16LUtf16L(
2390 &s, pData, from.data(), from.size(), to.data(), to.size(),
2391 index == nullptr ? &i : index);
2392 return OUString(s, SAL_NO_ACQUIRE);
2393 }
2394#else
2395 SAL_WARN_UNUSED_RESULT[[nodiscard]] OUString replaceFirst(
2396 OUString const & from, OUString const & to, sal_Int32 * index = NULL__null) const
2397 {
2398 rtl_uString * s = NULL__null;
2399 sal_Int32 i = 0;
2400 rtl_uString_newReplaceFirst(
2401 &s, pData, from.pData, to.pData, index == NULL__null ? &i : index);
2402 return OUString(s, SAL_NO_ACQUIRE);
2403 }
2404#endif
2405
2406 /**
2407 Returns a new string resulting from replacing the first occurrence of a
2408 given substring with another substring.
2409
2410 @param from ASCII string literal, the substring to be replaced
2411
2412 @param to the replacing substring
2413
2414 @param[in,out] index pointer to a start index; if the pointer is
2415 non-null: upon entry to the function, its value is the index into the this
2416 string at which to start searching for the \p from substring, the value
2417 must be non-negative and not greater than this string's length; upon exiting
2418 the function its value is the index into this string at which the
2419 replacement took place or -1 if no replacement took place; if the pointer
2420 is null, searching always starts at index 0
2421
2422 @since LibreOffice 3.6
2423 */
2424#if defined LIBO_INTERNAL_ONLY1
2425 template<typename T> [[nodiscard]]
2426 typename libreoffice_internal::ConstCharArrayDetector<T, OUString >::Type replaceFirst(
2427 T & from, std::u16string_view to, sal_Int32 * index = nullptr) const
2428 {
2429 assert(libreoffice_internal::ConstCharArrayDetector<T>::isValid(from))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(from)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(from)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 2429, __extension__ __PRETTY_FUNCTION__))
;
2430 rtl_uString * s = nullptr;
2431 sal_Int32 i = 0;
2432 rtl_uString_newReplaceFirstAsciiLUtf16L(
2433 &s, pData, libreoffice_internal::ConstCharArrayDetector<T>::toPointer(from),
2434 libreoffice_internal::ConstCharArrayDetector<T>::length, to.data(), to.size(),
2435 index == nullptr ? &i : index);
2436 return OUString(s, SAL_NO_ACQUIRE);
2437 }
2438#else
2439 template< typename T >
2440 SAL_WARN_UNUSED_RESULT[[nodiscard]] typename libreoffice_internal::ConstCharArrayDetector< T, OUString >::Type replaceFirst( T& from, OUString const & to,
2441 sal_Int32 * index = NULL__null) const
2442 {
2443 assert(libreoffice_internal::ConstCharArrayDetector<T>::isValid(from))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(from)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(from)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 2443, __extension__ __PRETTY_FUNCTION__))
;
2444 rtl_uString * s = NULL__null;
2445 sal_Int32 i = 0;
2446 rtl_uString_newReplaceFirstAsciiL(
2447 &s, pData,
2448 libreoffice_internal::ConstCharArrayDetector<T>::toPointer(from),
2449 libreoffice_internal::ConstCharArrayDetector<T>::length, to.pData,
2450 index == NULL__null ? &i : index);
2451 return OUString(s, SAL_NO_ACQUIRE);
2452 }
2453#endif
2454
2455 /**
2456 Returns a new string resulting from replacing the first occurrence of a
2457 given substring with another substring.
2458
2459 @param from the substring to be replaced
2460
2461 @param to ASCII string literal, the replacing substring
2462
2463 @param[in,out] index pointer to a start index; if the pointer is
2464 non-null: upon entry to the function, its value is the index into the this
2465 string at which to start searching for the \p from substring, the value
2466 must be non-negative and not greater than this string's length; upon exiting
2467 the function its value is the index into this string at which the
2468 replacement took place or -1 if no replacement took place; if the pointer
2469 is null, searching always starts at index 0
2470
2471 @since LibreOffice 5.1
2472 */
2473#if defined LIBO_INTERNAL_ONLY1
2474 template<typename T> [[nodiscard]]
2475 typename libreoffice_internal::ConstCharArrayDetector<T, OUString >::Type replaceFirst(
2476 std::u16string_view from, T & to, sal_Int32 * index = nullptr) const
2477 {
2478 assert(libreoffice_internal::ConstCharArrayDetector<T>::isValid(to))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(to)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(to)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 2478, __extension__ __PRETTY_FUNCTION__))
;
2479 rtl_uString * s = nullptr;
2480 sal_Int32 i = 0;
2481 rtl_uString_newReplaceFirstUtf16LAsciiL(
2482 &s, pData, from.data(), from.size(),
2483 libreoffice_internal::ConstCharArrayDetector<T>::toPointer(to),
2484 libreoffice_internal::ConstCharArrayDetector<T>::length, index == nullptr ? &i : index);
2485 return OUString(s, SAL_NO_ACQUIRE);
2486 }
2487#else
2488 template< typename T >
2489 SAL_WARN_UNUSED_RESULT[[nodiscard]] typename libreoffice_internal::ConstCharArrayDetector< T, OUString >::Type replaceFirst( OUString const & from, T& to,
2490 sal_Int32 * index = NULL__null) const
2491 {
2492 assert(libreoffice_internal::ConstCharArrayDetector<T>::isValid(to))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(to)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(to)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 2492, __extension__ __PRETTY_FUNCTION__))
;
2493 rtl_uString * s = NULL__null;
2494 sal_Int32 i = 0;
2495 rtl_uString_newReplaceFirstToAsciiL(
2496 &s, pData, from.pData,
2497 libreoffice_internal::ConstCharArrayDetector<T>::toPointer(to),
2498 libreoffice_internal::ConstCharArrayDetector<T>::length,
2499 index == NULL__null ? &i : index);
2500 return OUString(s, SAL_NO_ACQUIRE);
2501 }
2502#endif
2503
2504 /**
2505 Returns a new string resulting from replacing the first occurrence of a
2506 given substring with another substring.
2507
2508 @param from ASCII string literal, the substring to be replaced
2509
2510 @param to ASCII string literal, the substring to be replaced
2511
2512 @param[in,out] index pointer to a start index; if the pointer is
2513 non-null: upon entry to the function, its value is the index into the this
2514 string at which to start searching for the \p from substring, the value
2515 must be non-negative and not greater than this string's length; upon exiting
2516 the function its value is the index into this string at which the
2517 replacement took place or -1 if no replacement took place; if the pointer
2518 is null, searching always starts at index 0
2519
2520 @since LibreOffice 3.6
2521 */
2522 template< typename T1, typename T2 >
2523 SAL_WARN_UNUSED_RESULT[[nodiscard]] typename libreoffice_internal::ConstCharArrayDetector< T1, typename libreoffice_internal::ConstCharArrayDetector< T2, OUString >::Type >::Type
2524 replaceFirst( T1& from, T2& to, sal_Int32 * index = NULL__null) const
2525 {
2526 assert(libreoffice_internal::ConstCharArrayDetector<T1>::isValid(from))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T1>::isValid(from)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T1>::isValid(from)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 2526, __extension__ __PRETTY_FUNCTION__))
;
2527 assert(libreoffice_internal::ConstCharArrayDetector<T2>::isValid(to))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T2>::isValid(to)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T2>::isValid(to)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 2527, __extension__ __PRETTY_FUNCTION__))
;
2528 rtl_uString * s = NULL__null;
2529 sal_Int32 i = 0;
2530 rtl_uString_newReplaceFirstAsciiLAsciiL(
2531 &s, pData,
2532 libreoffice_internal::ConstCharArrayDetector<T1>::toPointer(from),
2533 libreoffice_internal::ConstCharArrayDetector<T1>::length,
2534 libreoffice_internal::ConstCharArrayDetector<T2>::toPointer(to),
2535 libreoffice_internal::ConstCharArrayDetector<T2>::length,
2536 index == NULL__null ? &i : index);
2537 return OUString(s, SAL_NO_ACQUIRE);
2538 }
2539
2540 /**
2541 Returns a new string resulting from replacing all occurrences of a given
2542 substring with another substring.
2543
2544 Replacing subsequent occurrences picks up only after a given replacement.
2545 That is, replacing from "xa" to "xx" in "xaa" results in "xxa", not "xxx".
2546
2547 @param from the substring to be replaced
2548
2549 @param to the replacing substring
2550
2551 @param fromIndex the position in the string where we will begin searching
2552
2553 @since LibreOffice 4.0
2554 */
2555#if defined LIBO_INTERNAL_ONLY1
2556 [[nodiscard]] OUString replaceAll(
2557 std::u16string_view from, std::u16string_view to, sal_Int32 fromIndex = 0) const
2558 {
2559 rtl_uString * s = nullptr;
2560 rtl_uString_newReplaceAllFromIndexUtf16LUtf16L(
2561 &s, pData, from.data(), from.size(), to.data(), to.size(), fromIndex);
2562 return OUString(s, SAL_NO_ACQUIRE);
2563 }
2564#else
2565 SAL_WARN_UNUSED_RESULT[[nodiscard]] OUString replaceAll(
2566 OUString const & from, OUString const & to, sal_Int32 fromIndex = 0) const
2567 {
2568 rtl_uString * s = NULL__null;
2569 rtl_uString_newReplaceAllFromIndex(&s, pData, from.pData, to.pData, fromIndex);
2570 return OUString(s, SAL_NO_ACQUIRE);
2571 }
2572#endif
2573
2574 /**
2575 Returns a new string resulting from replacing all occurrences of a given
2576 substring with another substring.
2577
2578 Replacing subsequent occurrences picks up only after a given replacement.
2579 That is, replacing from "xa" to "xx" in "xaa" results in "xxa", not "xxx".
2580
2581 @param from ASCII string literal, the substring to be replaced
2582
2583 @param to the replacing substring
2584
2585 @since LibreOffice 3.6
2586 */
2587#if defined LIBO_INTERNAL_ONLY1
2588 template<typename T> [[nodiscard]]
2589 typename libreoffice_internal::ConstCharArrayDetector<T, OUString >::Type replaceAll(
2590 T & from, std::u16string_view to) const
2591 {
2592 assert(libreoffice_internal::ConstCharArrayDetector<T>::isValid(from))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(from)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(from)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 2592, __extension__ __PRETTY_FUNCTION__))
;
2593 rtl_uString * s = nullptr;
2594 rtl_uString_newReplaceAllAsciiLUtf16L(
2595 &s, pData, libreoffice_internal::ConstCharArrayDetector<T>::toPointer(from),
2596 libreoffice_internal::ConstCharArrayDetector<T>::length, to.data(), to.size());
2597 return OUString(s, SAL_NO_ACQUIRE);
2598 }
2599#else
2600 template< typename T >
2601 SAL_WARN_UNUSED_RESULT[[nodiscard]] typename libreoffice_internal::ConstCharArrayDetector< T, OUString >::Type replaceAll( T& from, OUString const & to) const
2602 {
2603 assert(libreoffice_internal::ConstCharArrayDetector<T>::isValid(from))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(from)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(from)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 2603, __extension__ __PRETTY_FUNCTION__))
;
2604 rtl_uString * s = NULL__null;
2605 rtl_uString_newReplaceAllAsciiL(
2606 &s, pData,
2607 libreoffice_internal::ConstCharArrayDetector<T>::toPointer(from),
2608 libreoffice_internal::ConstCharArrayDetector<T>::length, to.pData);
2609 return OUString(s, SAL_NO_ACQUIRE);
2610 }
2611#endif
2612
2613 /**
2614 Returns a new string resulting from replacing all occurrences of a given
2615 substring with another substring.
2616
2617 Replacing subsequent occurrences picks up only after a given replacement.
2618 That is, replacing from "xa" to "xx" in "xaa" results in "xxa", not "xxx".
2619
2620 @param from the substring to be replaced
2621
2622 @param to ASCII string literal, the replacing substring
2623
2624 @since LibreOffice 5.1
2625 */
2626#if defined LIBO_INTERNAL_ONLY1
2627 template<typename T> [[nodiscard]]
2628 typename libreoffice_internal::ConstCharArrayDetector<T, OUString >::Type replaceAll(
2629 std::u16string_view from, T & to) const
2630 {
2631 assert(libreoffice_internal::ConstCharArrayDetector<T>::isValid(to))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(to)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(to)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 2631, __extension__ __PRETTY_FUNCTION__))
;
2632 rtl_uString * s = nullptr;
2633 rtl_uString_newReplaceAllUtf16LAsciiL(
2634 &s, pData, from.data(), from.size(),
2635 libreoffice_internal::ConstCharArrayDetector<T>::toPointer(to),
2636 libreoffice_internal::ConstCharArrayDetector<T>::length);
2637 return OUString(s, SAL_NO_ACQUIRE);
2638 }
2639#else
2640 template< typename T >
2641 SAL_WARN_UNUSED_RESULT[[nodiscard]] typename libreoffice_internal::ConstCharArrayDetector< T, OUString >::Type replaceAll( OUString const & from, T& to) const
2642 {
2643 assert(libreoffice_internal::ConstCharArrayDetector<T>::isValid(to))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(to)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(to)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 2643, __extension__ __PRETTY_FUNCTION__))
;
2644 rtl_uString * s = NULL__null;
2645 rtl_uString_newReplaceAllToAsciiL(
2646 &s, pData, from.pData,
2647 libreoffice_internal::ConstCharArrayDetector<T>::toPointer(to),
2648 libreoffice_internal::ConstCharArrayDetector<T>::length);
2649 return OUString(s, SAL_NO_ACQUIRE);
2650 }
2651#endif
2652
2653 /**
2654 Returns a new string resulting from replacing all occurrences of a given
2655 substring with another substring.
2656
2657 Replacing subsequent occurrences picks up only after a given replacement.
2658 That is, replacing from "xa" to "xx" in "xaa" results in "xxa", not "xxx".
2659
2660 @param from ASCII string literal, the substring to be replaced
2661
2662 @param to ASCII string literal, the substring to be replaced
2663
2664 @since LibreOffice 3.6
2665 */
2666 template< typename T1, typename T2 >
2667 SAL_WARN_UNUSED_RESULT[[nodiscard]] typename libreoffice_internal::ConstCharArrayDetector< T1, typename libreoffice_internal::ConstCharArrayDetector< T2, OUString >::Type >::Type
2668 replaceAll( T1& from, T2& to ) const
2669 {
2670 assert(libreoffice_internal::ConstCharArrayDetector<T1>::isValid(from))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T1>::isValid(from)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T1>::isValid(from)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 2670, __extension__ __PRETTY_FUNCTION__))
;
2671 assert(libreoffice_internal::ConstCharArrayDetector<T2>::isValid(to))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T2>::isValid(to)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T2>::isValid(to)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 2671, __extension__ __PRETTY_FUNCTION__))
;
2672 rtl_uString * s = NULL__null;
2673 rtl_uString_newReplaceAllAsciiLAsciiL(
2674 &s, pData,
2675 libreoffice_internal::ConstCharArrayDetector<T1>::toPointer(from),
2676 libreoffice_internal::ConstCharArrayDetector<T1>::length,
2677 libreoffice_internal::ConstCharArrayDetector<T2>::toPointer(to),
2678 libreoffice_internal::ConstCharArrayDetector<T2>::length);
2679 return OUString(s, SAL_NO_ACQUIRE);
2680 }
2681
2682 /**
2683 Converts from this string all ASCII uppercase characters (65-90)
2684 to ASCII lowercase characters (97-122).
2685
2686 This function can't be used for language specific conversion.
2687 If the string doesn't contain characters which must be converted,
2688 then the new string is assigned with str.
2689
2690 @return the string, converted to ASCII lowercase.
2691 */
2692 SAL_WARN_UNUSED_RESULT[[nodiscard]] OUString toAsciiLowerCase() const
2693 {
2694 rtl_uString* pNew = NULL__null;
2695 rtl_uString_newToAsciiLowerCase( &pNew, pData );
2696 return OUString( pNew, SAL_NO_ACQUIRE );
2697 }
2698
2699 /**
2700 Converts from this string all ASCII lowercase characters (97-122)
2701 to ASCII uppercase characters (65-90).
2702
2703 This function can't be used for language specific conversion.
2704 If the string doesn't contain characters which must be converted,
2705 then the new string is assigned with str.
2706
2707 @return the string, converted to ASCII uppercase.
2708 */
2709 SAL_WARN_UNUSED_RESULT[[nodiscard]] OUString toAsciiUpperCase() const
2710 {
2711 rtl_uString* pNew = NULL__null;
2712 rtl_uString_newToAsciiUpperCase( &pNew, pData );
2713 return OUString( pNew, SAL_NO_ACQUIRE );
2714 }
2715
2716 /**
2717 Returns a new string resulting from removing white space from both ends
2718 of the string.
2719
2720 All characters that have codes less than or equal to
2721 32 (the space character), and Unicode General Punctuation area Space
2722 and some Control characters are considered to be white space (see
2723 rtl_ImplIsWhitespace).
2724 If the string doesn't contain white spaces at both ends,
2725 then the new string is assigned with str.
2726
2727 @return the string, with white space removed from the front and end.
2728 */
2729 SAL_WARN_UNUSED_RESULT[[nodiscard]] OUString trim() const
2730 {
2731 rtl_uString* pNew = NULL__null;
2732 rtl_uString_newTrim( &pNew, pData );
2733 return OUString( pNew, SAL_NO_ACQUIRE );
2734 }
2735
2736 /**
2737 Returns a token in the string.
2738
2739 Example:
2740 sal_Int32 nIndex = 0;
2741 do
2742 {
2743 ...
2744 OUString aToken = aStr.getToken( 0, ';', nIndex );
2745 ...
2746 }
2747 while ( nIndex >= 0 );
2748
2749 @param token the number of the token to return
2750 @param cTok the character which separate the tokens.
2751 @param index the position at which the token is searched in the
2752 string.
2753 The index must not be greater than the length of the
2754 string.
2755 This param is set to the position of the
2756 next token or to -1, if it is the last token.
2757 @return the token; if either token or index is negative, an empty token
2758 is returned (and index is set to -1)
2759 */
2760 OUString getToken( sal_Int32 token, sal_Unicode cTok, sal_Int32& index ) const
2761 {
2762 rtl_uString * pNew = NULL__null;
2763 index = rtl_uString_getToken( &pNew, pData, token, cTok, index );
2764 return OUString( pNew, SAL_NO_ACQUIRE );
2765 }
2766
2767 /**
2768 Returns a token from the string.
2769
2770 The same as getToken(sal_Int32, sal_Unicode, sal_Int32 &), but always
2771 passing in 0 as the start index in the third argument.
2772
2773 @param count the number of the token to return, starting with 0
2774 @param separator the character which separates the tokens
2775
2776 @return the given token, or an empty string
2777
2778 @since LibreOffice 3.6
2779 */
2780 OUString getToken(sal_Int32 count, sal_Unicode separator) const {
2781 sal_Int32 n = 0;
2782 return getToken(count, separator, n);
2783 }
2784
2785 /**
2786 Returns the Boolean value from this string.
2787
2788 This function can't be used for language specific conversion.
2789
2790 @return true, if the string is 1 or "True" in any ASCII case.
2791 false in any other case.
2792 */
2793 bool toBoolean() const
2794 {
2795 return rtl_ustr_toBoolean( pData->buffer );
2796 }
2797
2798 /**
2799 Returns the first character from this string.
2800
2801 @return the first character from this string or 0, if this string
2802 is empty.
2803 */
2804 sal_Unicode toChar() const
2805 {
2806 return pData->buffer[0];
2807 }
2808
2809 /**
2810 Returns the int32 value from this string.
2811
2812 This function can't be used for language specific conversion.
2813
2814 @param radix the radix (between 2 and 36)
2815 @return the int32 represented from this string.
2816 0 if this string represents no number or one of too large
2817 magnitude.
2818 */
2819 sal_Int32 toInt32( sal_Int16 radix = 10 ) const
2820 {
2821 return rtl_ustr_toInt32( pData->buffer, radix );
2822 }
2823
2824 /**
2825 Returns the uint32 value from this string.
2826
2827 This function can't be used for language specific conversion.
2828
2829 @param radix the radix (between 2 and 36)
2830 @return the uint32 represented from this string.
2831 0 if this string represents no number or one of too large
2832 magnitude.
2833
2834 @since LibreOffice 4.2
2835 */
2836 sal_uInt32 toUInt32( sal_Int16 radix = 10 ) const
2837 {
2838 return rtl_ustr_toUInt32( pData->buffer, radix );
2839 }
2840
2841 /**
2842 Returns the int64 value from this string.
2843
2844 This function can't be used for language specific conversion.
2845
2846 @param radix the radix (between 2 and 36)
2847 @return the int64 represented from this string.
2848 0 if this string represents no number or one of too large
2849 magnitude.
2850 */
2851 sal_Int64 toInt64( sal_Int16 radix = 10 ) const
2852 {
2853 return rtl_ustr_toInt64( pData->buffer, radix );
2854 }
2855
2856 /**
2857 Returns the uint64 value from this string.
2858
2859 This function can't be used for language specific conversion.
2860
2861 @param radix the radix (between 2 and 36)
2862 @return the uint64 represented from this string.
2863 0 if this string represents no number or one of too large
2864 magnitude.
2865
2866 @since LibreOffice 4.1
2867 */
2868 sal_uInt64 toUInt64( sal_Int16 radix = 10 ) const
2869 {
2870 return rtl_ustr_toUInt64( pData->buffer, radix );
2871 }
2872
2873 /**
2874 Returns the float value from this string.
2875
2876 This function can't be used for language specific conversion.
2877
2878 @return the float represented from this string.
2879 0.0 if this string represents no number.
2880 */
2881 float toFloat() const
2882 {
2883 return rtl_ustr_toFloat( pData->buffer );
2884 }
2885
2886 /**
2887 Returns the double value from this string.
2888
2889 This function can't be used for language specific conversion.
2890
2891 @return the double represented from this string.
2892 0.0 if this string represents no number.
2893 */
2894 double toDouble() const
2895 {
2896 return rtl_ustr_toDouble( pData->buffer );
2897 }
2898
2899
2900 /**
2901 Return a canonical representation for a string.
2902
2903 A pool of strings, initially empty is maintained privately
2904 by the string class. On invocation, if present in the pool
2905 the original string will be returned. Otherwise this string,
2906 or a copy thereof will be added to the pool and returned.
2907
2908 @return
2909 a version of the string from the pool.
2910
2911 @exception std::bad_alloc is thrown if an out-of-memory condition occurs
2912
2913 @since UDK 3.2.7
2914 */
2915 OUString intern() const
2916 {
2917 rtl_uString * pNew = NULL__null;
2918 rtl_uString_intern( &pNew, pData );
2919 if (pNew == NULL__null) {
2920 throw std::bad_alloc();
2921 }
2922 return OUString( pNew, SAL_NO_ACQUIRE );
2923 }
2924
2925 /**
2926 Return a canonical representation for a converted string.
2927
2928 A pool of strings, initially empty is maintained privately
2929 by the string class. On invocation, if present in the pool
2930 the original string will be returned. Otherwise this string,
2931 or a copy thereof will be added to the pool and returned.
2932
2933 @param value a 8-Bit character array.
2934 @param length the number of character which should be converted.
2935 The 8-Bit character array length must be
2936 greater than or equal to this value.
2937 @param encoding the text encoding from which the 8-Bit character
2938 sequence should be converted.
2939 @param convertFlags flags which controls the conversion.
2940 see RTL_TEXTTOUNICODE_FLAGS_...
2941 @param pInfo pointer to return conversion status or NULL.
2942
2943 @return
2944 a version of the converted string from the pool.
2945
2946 @exception std::bad_alloc is thrown if an out-of-memory condition occurs
2947
2948 @since UDK 3.2.7
2949 */
2950 static OUString intern( const char * value, sal_Int32 length,
2951 rtl_TextEncoding encoding,
2952 sal_uInt32 convertFlags = OSTRING_TO_OUSTRING_CVTFLAGS(((sal_uInt32)0x0003) | ((sal_uInt32)0x0030) | ((sal_uInt32)0x0300
))
,
2953 sal_uInt32 *pInfo = NULL__null )
2954 {
2955 rtl_uString * pNew = NULL__null;
2956 rtl_uString_internConvert( &pNew, value, length, encoding,
2957 convertFlags, pInfo );
2958 if (pNew == NULL__null) {
2959 throw std::bad_alloc();
2960 }
2961 return OUString( pNew, SAL_NO_ACQUIRE );
2962 }
2963
2964 /**
2965 Converts to an OString, signalling failure.
2966
2967 @param pTarget
2968 An out parameter receiving the converted OString. Must not be null; the
2969 contents are not modified if conversion fails (convertToOString returns
2970 false).
2971
2972 @param nEncoding
2973 The text encoding to convert into. Must be an octet encoding (i.e.,
2974 rtl_isOctetTextEncoding(nEncoding) must return true).
2975
2976 @param nFlags
2977 A combination of RTL_UNICODETOTEXT_FLAGS that detail how to do the
2978 conversion (see rtl_convertUnicodeToText). RTL_UNICODETOTEXT_FLAGS_FLUSH
2979 need not be included, it is implicitly assumed. Typical uses are either
2980 RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR |
2981 RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR (fail if a Unicode character cannot
2982 be converted to the target nEncoding) or OUSTRING_TO_OSTRING_CVTFLAGS
2983 (make a best efforts conversion).
2984
2985 @return
2986 True if the conversion succeeded, false otherwise.
2987 */
2988 bool convertToString(OString * pTarget, rtl_TextEncoding nEncoding,
2989 sal_uInt32 nFlags) const
2990 {
2991 return rtl_convertUStringToString(&pTarget->pData, pData->buffer,
2992 pData->length, nEncoding, nFlags);
2993 }
2994
2995 /** Iterate through this string based on code points instead of UTF-16 code
2996 units.
2997
2998 See Chapter 3 of The Unicode Standard 5.0 (Addison--Wesley, 2006) for
2999 definitions of the various terms used in this description.
3000
3001 This string is interpreted as a sequence of zero or more UTF-16 code
3002 units. For each index into this sequence (from zero to one less than
3003 the length of the sequence, inclusive), a code point represented
3004 starting at the given index is computed as follows:
3005
3006 - If the UTF-16 code unit addressed by the index constitutes a
3007 well-formed UTF-16 code unit sequence, the computed code point is the
3008 scalar value encoded by that UTF-16 code unit sequence.
3009
3010 - Otherwise, if the index is at least two UTF-16 code units away from
3011 the end of the sequence, and the sequence of two UTF-16 code units
3012 addressed by the index constitutes a well-formed UTF-16 code unit
3013 sequence, the computed code point is the scalar value encoded by that
3014 UTF-16 code unit sequence.
3015
3016 - Otherwise, the computed code point is the UTF-16 code unit addressed
3017 by the index. (This last case catches unmatched surrogates as well as
3018 indices pointing into the middle of surrogate pairs.)
3019
3020 @param indexUtf16
3021 pointer to a UTF-16 based index into this string; must not be null. On
3022 entry, the index must be in the range from zero to the length of this
3023 string (in UTF-16 code units), inclusive. Upon successful return, the
3024 index will be updated to address the UTF-16 code unit that is the given
3025 incrementCodePoints away from the initial index.
3026
3027 @param incrementCodePoints
3028 the number of code points to move the given *indexUtf16. If
3029 non-negative, moving is done after determining the code point at the
3030 index. If negative, moving is done before determining the code point
3031 at the (then updated) index. The value must be such that the resulting
3032 UTF-16 based index is in the range from zero to the length of this
3033 string (in UTF-16 code units), inclusive.
3034
3035 @return
3036 the code point (an integer in the range from 0 to 0x10FFFF, inclusive)
3037 that is represented within this string starting at the index computed as
3038 follows: If incrementCodePoints is non-negative, the index is the
3039 initial value of *indexUtf16; if incrementCodePoints is negative, the
3040 index is the updated value of *indexUtf16. In either case, the computed
3041 index must be in the range from zero to one less than the length of this
3042 string (in UTF-16 code units), inclusive.
3043
3044 @since UDK 3.2.7
3045 */
3046 sal_uInt32 iterateCodePoints(
3047 sal_Int32 * indexUtf16, sal_Int32 incrementCodePoints = 1) const
3048 {
3049 return rtl_uString_iterateCodePoints(
3050 pData, indexUtf16, incrementCodePoints);
3051 }
3052
3053 /**
3054 * Convert an OString to an OUString, assuming that the OString is
3055 * UTF-8-encoded.
3056 *
3057 * @param rSource
3058 * an OString to convert
3059 *
3060 * @since LibreOffice 4.4
3061 */
3062 static OUString fromUtf8(const OString& rSource)
3063 {
3064 OUString aTarget;
3065 bool bSuccess = rtl_convertStringToUString(&aTarget.pData,
3066 rSource.getStr(),
3067 rSource.getLength(),
3068 RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76)),
3069 RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR((sal_uInt32)0x0001)|RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR((sal_uInt32)0x0010)|RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR((sal_uInt32)0x0100));
3070 (void) bSuccess;
3071 assert(bSuccess)(static_cast <bool> (bSuccess) ? void (0) : __assert_fail
("bSuccess", "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 3071, __extension__ __PRETTY_FUNCTION__))
;
3072 return aTarget;
3073 }
3074
3075 /**
3076 * Convert this string to an OString, assuming that the string can be
3077 * UTF-8-encoded successfully.
3078 *
3079 * In other words, you must not use this method on a random sequence of
3080 * UTF-16 code units, but only at places where it is assumed that the
3081 * content is a proper string.
3082 *
3083 * @since LibreOffice 4.4
3084 */
3085 OString toUtf8() const
3086 {
3087 OString aTarget;
3088 bool bSuccess = rtl_convertUStringToString(&aTarget.pData,
3089 getStr(),
3090 getLength(),
3091 RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76)),
3092 RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR((sal_uInt32)0x0001)|RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR((sal_uInt32)0x0010));
3093 (void) bSuccess;
3094 assert(bSuccess)(static_cast <bool> (bSuccess) ? void (0) : __assert_fail
("bSuccess", "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 3094, __extension__ __PRETTY_FUNCTION__))
;
3095 return aTarget;
3096 }
3097
3098#ifdef LIBO_INTERNAL_ONLY1 // "RTL_FAST_STRING"
3099
3100 static OUStringNumber< int > number( int i, sal_Int16 radix = 10 )
3101 {
3102 return OUStringNumber< int >( i, radix );
3103 }
3104 static OUStringNumber< long long > number( long long ll, sal_Int16 radix = 10 )
3105 {
3106 return OUStringNumber< long long >( ll, radix );
3107 }
3108 static OUStringNumber< unsigned long long > number( unsigned long long ll, sal_Int16 radix = 10 )
3109 {
3110 return OUStringNumber< unsigned long long >( ll, radix );
3111 }
3112 static OUStringNumber< unsigned long long > number( unsigned int i, sal_Int16 radix = 10 )
3113 {
3114 return number( static_cast< unsigned long long >( i ), radix );
3115 }
3116 static OUStringNumber< long long > number( long i, sal_Int16 radix = 10)
3117 {
3118 return number( static_cast< long long >( i ), radix );
3119 }
3120 static OUStringNumber< unsigned long long > number( unsigned long i, sal_Int16 radix = 10 )
3121 {
3122 return number( static_cast< unsigned long long >( i ), radix );
3123 }
3124 static OUStringNumber< float > number( float f )
3125 {
3126 return OUStringNumber< float >( f );
3127 }
3128 static OUStringNumber< double > number( double d )
3129 {
3130 return OUStringNumber< double >( d );
3131 }
3132#else
3133 /**
3134 Returns the string representation of the integer argument.
3135
3136 This function can't be used for language specific conversion.
3137
3138 @param i an integer value
3139 @param radix the radix (between 2 and 36)
3140 @return a string with the string representation of the argument.
3141 @since LibreOffice 4.1
3142 */
3143 static OUString number( int i, sal_Int16 radix = 10 )
3144 {
3145 sal_Unicode aBuf[RTL_USTR_MAX_VALUEOFINT3233];
3146 return OUString(aBuf, rtl_ustr_valueOfInt32(aBuf, i, radix));
3147 }
3148 /// @overload
3149 /// @since LibreOffice 4.1
3150 static OUString number( unsigned int i, sal_Int16 radix = 10 )
3151 {
3152 return number( static_cast< unsigned long long >( i ), radix );
3153 }
3154 /// @overload
3155 /// @since LibreOffice 4.1
3156 static OUString number( long i, sal_Int16 radix = 10)
3157 {
3158 return number( static_cast< long long >( i ), radix );
3159 }
3160 /// @overload
3161 /// @since LibreOffice 4.1
3162 static OUString number( unsigned long i, sal_Int16 radix = 10 )
3163 {
3164 return number( static_cast< unsigned long long >( i ), radix );
3165 }
3166 /// @overload
3167 /// @since LibreOffice 4.1
3168 static OUString number( long long ll, sal_Int16 radix = 10 )
3169 {
3170 sal_Unicode aBuf[RTL_USTR_MAX_VALUEOFINT6465];
3171 return OUString(aBuf, rtl_ustr_valueOfInt64(aBuf, ll, radix));
3172 }
3173 /// @overload
3174 /// @since LibreOffice 4.1
3175 static OUString number( unsigned long long ll, sal_Int16 radix = 10 )
3176 {
3177 sal_Unicode aBuf[RTL_USTR_MAX_VALUEOFUINT6465];
3178 return OUString(aBuf, rtl_ustr_valueOfUInt64(aBuf, ll, radix));
3179 }
3180
3181 /**
3182 Returns the string representation of the float argument.
3183
3184 This function can't be used for language specific conversion.
3185
3186 @param f a float.
3187 @return a string with the decimal representation of the argument.
3188 @since LibreOffice 4.1
3189 */
3190 static OUString number( float f )
3191 {
3192 sal_Unicode aBuf[RTL_USTR_MAX_VALUEOFFLOAT15];
3193 return OUString(aBuf, rtl_ustr_valueOfFloat(aBuf, f));
3194 }
3195
3196 /**
3197 Returns the string representation of the double argument.
3198
3199 This function can't be used for language specific conversion.
3200
3201 @param d a double.
3202 @return a string with the decimal representation of the argument.
3203 @since LibreOffice 4.1
3204 */
3205 static OUString number( double d )
3206 {
3207 sal_Unicode aBuf[RTL_USTR_MAX_VALUEOFDOUBLE25];
3208 return OUString(aBuf, rtl_ustr_valueOfDouble(aBuf, d));
3209 }
3210#endif
3211
3212 /**
3213 Returns the string representation of the sal_Bool argument.
3214
3215 If the sal_Bool is true, the string "true" is returned.
3216 If the sal_Bool is false, the string "false" is returned.
3217 This function can't be used for language specific conversion.
3218
3219 @param b a sal_Bool.
3220 @return a string with the string representation of the argument.
3221 @deprecated use boolean()
3222 */
3223 SAL_DEPRECATED("use boolean()")__attribute__((deprecated("use boolean()"))) static OUString valueOf( sal_Bool b )
3224 {
3225 return boolean(b);
3226 }
3227
3228 /**
3229 Returns the string representation of the boolean argument.
3230
3231 If the argument is true, the string "true" is returned.
3232 If the argument is false, the string "false" is returned.
3233 This function can't be used for language specific conversion.
3234
3235 @param b a bool.
3236 @return a string with the string representation of the argument.
3237 @since LibreOffice 4.1
3238 */
3239 static OUString boolean( bool b )
3240 {
3241 sal_Unicode aBuf[RTL_USTR_MAX_VALUEOFBOOLEAN6];
3242 return OUString(aBuf, rtl_ustr_valueOfBoolean(aBuf, b));
3243 }
3244
3245 /**
3246 Returns the string representation of the char argument.
3247
3248 @param c a character.
3249 @return a string with the string representation of the argument.
3250 @deprecated use operator, function or constructor taking char or sal_Unicode argument
3251 */
3252 SAL_DEPRECATED("convert to OUString or use directly")__attribute__((deprecated("convert to OUString or use directly"
)))
static OUString valueOf( sal_Unicode c )
3253 {
3254 return OUString( &c, 1 );
3255 }
3256
3257 /**
3258 Returns the string representation of the int argument.
3259
3260 This function can't be used for language specific conversion.
3261
3262 @param i a int32.
3263 @param radix the radix (between 2 and 36)
3264 @return a string with the string representation of the argument.
3265 @deprecated use number()
3266 */
3267 SAL_DEPRECATED("use number()")__attribute__((deprecated("use number()"))) static OUString valueOf( sal_Int32 i, sal_Int16 radix = 10 )
3268 {
3269 return number( i, radix );
3270 }
3271
3272 /**
3273 Returns the string representation of the long argument.
3274
3275 This function can't be used for language specific conversion.
3276
3277 @param ll a int64.
3278 @param radix the radix (between 2 and 36)
3279 @return a string with the string representation of the argument.
3280 @deprecated use number()
3281 */
3282 SAL_DEPRECATED("use number()")__attribute__((deprecated("use number()"))) static OUString valueOf( sal_Int64 ll, sal_Int16 radix = 10 )
3283 {
3284 return number( ll, radix );
3285 }
3286
3287 /**
3288 Returns the string representation of the float argument.
3289
3290 This function can't be used for language specific conversion.
3291
3292 @param f a float.
3293 @return a string with the string representation of the argument.
3294 @deprecated use number()
3295 */
3296 SAL_DEPRECATED("use number()")__attribute__((deprecated("use number()"))) static OUString valueOf( float f )
3297 {
3298 return number(f);
3299 }
3300
3301 /**
3302 Returns the string representation of the double argument.
3303
3304 This function can't be used for language specific conversion.
3305
3306 @param d a double.
3307 @return a string with the string representation of the argument.
3308 @deprecated use number()
3309 */
3310 SAL_DEPRECATED("use number()")__attribute__((deprecated("use number()"))) static OUString valueOf( double d )
3311 {
3312 return number(d);
3313 }
3314
3315 /**
3316 Returns an OUString copied without conversion from an ASCII
3317 character string.
3318
3319 Since this method is optimized for performance, the ASCII character
3320 values are not converted in any way. The caller has to make sure that
3321 all ASCII characters are in the allowed range between 0 and 127.
3322 The ASCII string must be NULL-terminated.
3323
3324 Note that for string literals it is simpler and more efficient
3325 to directly use the OUString constructor.
3326
3327 @param value the 8-Bit ASCII character string
3328 @return a string with the string representation of the argument.
3329 */
3330 static OUString createFromAscii( const char * value )
3331 {
3332 rtl_uString* pNew = NULL__null;
3333 rtl_uString_newFromAscii( &pNew, value );
3334 return OUString( pNew, SAL_NO_ACQUIRE );
3335 }
3336
3337#if defined LIBO_INTERNAL_ONLY1
3338 static OUString createFromAscii(std::string_view value) {
3339 rtl_uString * p = nullptr;
3340 rtl_uString_newFromLiteral(&p, value.data(), value.size(), 0); //TODO: check for overflow
3341 return OUString(p, SAL_NO_ACQUIRE);
3342 }
3343 #endif
3344
3345#if defined LIBO_INTERNAL_ONLY1
3346 operator std::u16string_view() const { return {getStr(), sal_uInt32(getLength())}; }
3347#endif
3348
3349#if defined LIBO_INTERNAL_ONLY1
3350 // A wrapper for the first expression in an
3351 //
3352 // OUString::Concat(e1) + e2 + ...
3353 //
3354 // concatenation chain, when neither of the first two e1, e2 is one of our rtl string-related
3355 // classes (so something like
3356 //
3357 // OUString s = "a" + (b ? std::u16string_view(u"c") : std::u16string_view(u"dd"));
3358 //
3359 // would not compile):
3360 template<typename T> [[nodiscard]] static
3361 typename std::enable_if_t<
3362 ToStringHelper<T>::allowOUStringConcat, OUStringConcat<OUStringConcatMarker, T>>
3363 Concat(T const & value) { return OUStringConcat<OUStringConcatMarker, T>({}, value); }
3364
3365 // This overload is needed so that an argument of type 'char const[N]' ends up as
3366 // 'OUStringConcat<rtl::OUStringConcatMarker, char const[N]>' rather than as
3367 // 'OUStringConcat<rtl::OUStringConcatMarker, char[N]>':
3368 template<typename T, std::size_t N> [[nodiscard]] static
3369 typename std::enable_if_t<
3370 ToStringHelper<T[N]>::allowOUStringConcat, OUStringConcat<OUStringConcatMarker, T[N]>>
3371 Concat(T (& value)[N]) { return OUStringConcat<OUStringConcatMarker, T[N]>({}, value); }
3372#endif
3373
3374private:
3375 OUString & internalAppend( rtl_uString* pOtherData )
3376 {
3377 rtl_uString* pNewData = NULL__null;
3378 rtl_uString_newConcat( &pNewData, pData, pOtherData );
3379 if (pNewData == NULL__null) {
3380 throw std::bad_alloc();
3381 }
3382 rtl_uString_assign(&pData, pNewData);
3383 rtl_uString_release(pNewData);
3384 return *this;
3385 }
3386
3387};
3388
3389#if defined LIBO_INTERNAL_ONLY1
3390// Prevent the operator ==/!= overloads with 'sal_Unicode const *' parameter from
3391// being selected for nonsensical code like
3392//
3393// if (ouIdAttr == nullptr)
3394//
3395void operator ==(OUString const &, std::nullptr_t) = delete;
3396void operator ==(std::nullptr_t, OUString const &) = delete;
3397void operator !=(OUString const &, std::nullptr_t) = delete;
3398void operator !=(std::nullptr_t, OUString const &) = delete;
3399#endif
3400
3401#if defined LIBO_INTERNAL_ONLY1 // "RTL_FAST_STRING"
3402/// @cond INTERNAL
3403
3404/**
3405 @internal
3406*/
3407template<>
3408struct ToStringHelper< OUString >
3409 {
3410 static std::size_t length( const OUString& s ) { return s.getLength(); }
3411 static sal_Unicode* addData( sal_Unicode* buffer, const OUString& s ) { return addDataHelper( buffer, s.getStr(), s.getLength()); }
3412 static const bool allowOStringConcat = false;
3413 static const bool allowOUStringConcat = true;
3414 };
3415
3416/**
3417 @internal
3418*/
3419template<std::size_t N>
3420struct ToStringHelper< OUStringLiteral<N> >
3421 {
3422 static std::size_t length( const OUStringLiteral<N>& str ) { return str.getLength(); }
3423 static sal_Unicode* addData( sal_Unicode* buffer, const OUStringLiteral<N>& str ) { return addDataHelper( buffer, str.getStr(), str.getLength() ); }
3424 static const bool allowOStringConcat = false;
3425 static const bool allowOUStringConcat = true;
3426 };
3427
3428/**
3429 @internal
3430*/
3431template< typename charT, typename traits, typename T1, typename T2 >
3432inline std::basic_ostream<charT, traits> & operator <<(
3433 std::basic_ostream<charT, traits> & stream, OUStringConcat< T1, T2 >&& concat)
3434{
3435 return stream << OUString( std::move(concat) );
3436}
3437
3438/// @endcond
3439#endif
3440
3441/** A helper to use OUStrings with hash maps.
3442
3443 Instances of this class are unary function objects that can be used as
3444 hash function arguments to std::unordered_map and similar constructs.
3445 */
3446struct OUStringHash
3447{
3448 /** Compute a hash code for a string.
3449
3450 @param rString
3451 a string.
3452
3453 @return
3454 a hash code for the string. This hash code should not be stored
3455 persistently, as its computation may change in later revisions.
3456 */
3457 size_t operator()(const OUString& rString) const
3458 { return static_cast<size_t>(rString.hashCode()); }
3459};
3460
3461/* ======================================================================= */
3462
3463/** Convert an OString to an OUString, using a specific text encoding.
3464
3465 The lengths of the two strings may differ (e.g., for double-byte
3466 encodings, UTF-7, UTF-8).
3467
3468 @param rStr
3469 an OString to convert.
3470
3471 @param encoding
3472 the text encoding to use for conversion.
3473
3474 @param convertFlags
3475 flags which control the conversion. Either use
3476 OSTRING_TO_OUSTRING_CVTFLAGS, or see
3477 <http://udk.openoffice.org/cpp/man/spec/textconversion.html> for more
3478 details.
3479 */
3480inline OUString OStringToOUString( const OString & rStr,
3481 rtl_TextEncoding encoding,
3482 sal_uInt32 convertFlags = OSTRING_TO_OUSTRING_CVTFLAGS(((sal_uInt32)0x0003) | ((sal_uInt32)0x0030) | ((sal_uInt32)0x0300
))
)
3483{
3484 return OUString( rStr.getStr(), rStr.getLength(), encoding, convertFlags );
3485}
3486
3487/** Convert an OUString to an OString, using a specific text encoding.
3488
3489 The lengths of the two strings may differ (e.g., for double-byte
3490 encodings, UTF-7, UTF-8).
3491
3492 @param rUnicode
3493 an OUString to convert.
3494
3495 @param encoding
3496 the text encoding to use for conversion.
3497
3498 @param convertFlags
3499 flags which control the conversion. Either use
3500 OUSTRING_TO_OSTRING_CVTFLAGS, or see
3501 <http://udk.openoffice.org/cpp/man/spec/textconversion.html> for more
3502 details.
3503 */
3504inline OString OUStringToOString( const OUString & rUnicode,
3505 rtl_TextEncoding encoding,
3506 sal_uInt32 convertFlags = OUSTRING_TO_OSTRING_CVTFLAGS(((sal_uInt32)0x0006) | ((sal_uInt32)0x0060) | ((sal_uInt32)0x0100
) | ((sal_uInt32)0x0400))
)
3507{
3508 return OString( rUnicode.getStr(), rUnicode.getLength(), encoding, convertFlags );
3509}
3510
3511/* ======================================================================= */
3512
3513/**
3514 Support for rtl::OUString in std::ostream (and thus in
3515 CPPUNIT_ASSERT or SAL_INFO macros, for example).
3516
3517 The rtl::OUString is converted to UTF-8.
3518
3519 @since LibreOffice 3.5.
3520*/
3521template< typename charT, typename traits >
3522inline std::basic_ostream<charT, traits> & operator <<(
3523 std::basic_ostream<charT, traits> & stream, OUString const & rString)
3524{
3525 return stream <<
3526 OUStringToOString(rString, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76)));
3527 // best effort; potentially loses data due to conversion failures
3528 // (stray surrogate halves) and embedded null characters
3529}
3530
3531} // namespace
3532
3533#ifdef RTL_STRING_UNITTEST
3534namespace rtl
3535{
3536typedef rtlunittest::OUString OUString;
3537}
3538#endif
3539
3540// In internal code, allow to use classes like OUString without having to
3541// explicitly refer to the rtl namespace, which is kind of superfluous given
3542// that OUString itself is namespaced by its OU prefix:
3543#if defined LIBO_INTERNAL_ONLY1 && !defined RTL_STRING_UNITTEST
3544using ::rtl::OUString;
3545using ::rtl::OUStringHash;
3546using ::rtl::OStringToOUString;
3547using ::rtl::OUStringToOString;
3548using ::rtl::OUStringLiteral;
3549using ::rtl::OUStringChar;
3550#endif
3551
3552/// @cond INTERNAL
3553/**
3554 Make OUString hashable by default for use in STL containers.
3555
3556 @since LibreOffice 6.0
3557*/
3558#if defined LIBO_INTERNAL_ONLY1
3559namespace std {
3560
3561template<>
3562struct hash<::rtl::OUString>
3563{
3564 std::size_t operator()(::rtl::OUString const & s) const
3565 { return std::size_t(s.hashCode()); }
3566};
3567
3568}
3569
3570#endif
3571/// @endcond
3572
3573#endif /* _RTL_USTRING_HXX */
3574
3575/* vim:set shiftwidth=4 softtabstop=4 expandtab: */