Bug Summary

File:home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx
Warning:line 1524, 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 dbmgr.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 -isystem /usr/include/libxml2 -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 SW_DLLIMPLEMENTATION -D SWUI_DLL_NAME="libswuilo.so" -D SYSTEM_LIBXML -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/i18n -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/common -I /home/maarten/src/libreoffice/core/external/boost/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/boost -I /home/maarten/src/libreoffice/core/sw/source/core/inc -I /home/maarten/src/libreoffice/core/sw/source/filter/inc -I /home/maarten/src/libreoffice/core/sw/source/uibase/inc -I /home/maarten/src/libreoffice/core/sw/inc -I /home/maarten/src/libreoffice/core/workdir/SdiTarget/sw/sdi -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/CustomTarget/officecfg/registry -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/sw/generated -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/udkapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/oovbaapi/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/sw/source/uibase/dbui/dbmgr.cxx

/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.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 <sal/config.h>
21
22#include <cassert>
23
24#include <unotxdoc.hxx>
25#include <sfx2/app.hxx>
26#include <com/sun/star/sdb/CommandType.hpp>
27#include <com/sun/star/sdb/XDocumentDataSource.hpp>
28#include <com/sun/star/lang/DisposedException.hpp>
29#include <com/sun/star/lang/XEventListener.hpp>
30#include <com/sun/star/uri/UriReferenceFactory.hpp>
31#include <com/sun/star/uri/VndSunStarPkgUrlReferenceFactory.hpp>
32#include <com/sun/star/util/NumberFormatter.hpp>
33#include <com/sun/star/sdb/DatabaseContext.hpp>
34#include <com/sun/star/sdb/TextConnectionSettings.hpp>
35#include <com/sun/star/sdb/XCompletedConnection.hpp>
36#include <com/sun/star/sdb/XCompletedExecution.hpp>
37#include <com/sun/star/container/XChild.hpp>
38#include <com/sun/star/text/MailMergeEvent.hpp>
39#include <com/sun/star/frame/XStorable.hpp>
40#include <com/sun/star/task/InteractionHandler.hpp>
41#include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
42#include <com/sun/star/ui/dialogs/XFilePicker3.hpp>
43#include <com/sun/star/beans/XPropertySet.hpp>
44#include <vcl/errinf.hxx>
45#include <vcl/print.hxx>
46#include <vcl/scheduler.hxx>
47#include <sfx2/fcontnr.hxx>
48#include <sfx2/filedlghelper.hxx>
49#include <sfx2/viewfrm.hxx>
50#include <dbconfig.hxx>
51#include <unotools/tempfile.hxx>
52#include <unotools/pathoptions.hxx>
53#include <svl/zforlist.hxx>
54#include <svl/stritem.hxx>
55#include <sfx2/docfile.hxx>
56#include <sfx2/docfilt.hxx>
57#include <sfx2/progress.hxx>
58#include <sfx2/dispatch.hxx>
59#include <cmdid.h>
60#include <swmodule.hxx>
61#include <view.hxx>
62#include <docsh.hxx>
63#include <edtwin.hxx>
64#include <wrtsh.hxx>
65#include <fldbas.hxx>
66#include <dbui.hxx>
67#include <dbmgr.hxx>
68#include <doc.hxx>
69#include <IDocumentLinksAdministration.hxx>
70#include <IDocumentFieldsAccess.hxx>
71#include <IDocumentUndoRedo.hxx>
72#include <swwait.hxx>
73#include <swunohelper.hxx>
74#include <strings.hrc>
75#include <mmconfigitem.hxx>
76#include <com/sun/star/sdbc/XRowSet.hpp>
77#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
78#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
79#include <com/sun/star/sdb/XQueriesSupplier.hpp>
80#include <com/sun/star/sdb/XColumn.hpp>
81#include <com/sun/star/sdbc/DataType.hpp>
82#include <com/sun/star/sdbc/ResultSetType.hpp>
83#include <com/sun/star/sdbc/SQLException.hpp>
84#include <com/sun/star/mail/MailAttachment.hpp>
85#include <comphelper/processfactory.hxx>
86#include <comphelper/property.hxx>
87#include <comphelper/storagehelper.hxx>
88#include <comphelper/string.hxx>
89#include <comphelper/types.hxx>
90#include <mailmergehelper.hxx>
91#include <maildispatcher.hxx>
92#include <svtools/htmlcfg.hxx>
93#include <i18nlangtag/languagetag.hxx>
94#include <com/sun/star/util/XNumberFormatTypes.hpp>
95#include <svl/numuno.hxx>
96#include <connectivity/dbtools.hxx>
97#include <connectivity/dbconversion.hxx>
98#include <unotools/charclass.hxx>
99#include <tools/diagnose_ex.h>
100
101#include <unomailmerge.hxx>
102#include <sfx2/event.hxx>
103#include <svx/dataaccessdescriptor.hxx>
104#include <osl/mutex.hxx>
105#include <rtl/textenc.h>
106#include <rtl/tencinfo.h>
107#include <cppuhelper/implbase.hxx>
108#include <ndindex.hxx>
109#include <swevent.hxx>
110#include <sal/log.hxx>
111#include <swabstdlg.hxx>
112#include <vector>
113#include <section.hxx>
114#include <rootfrm.hxx>
115#include <calc.hxx>
116#include <dbfld.hxx>
117#include <IDocumentState.hxx>
118#include <imaildsplistener.hxx>
119#include <iodetect.hxx>
120#include <IDocumentDeviceAccess.hxx>
121
122#include <memory>
123#include <comphelper/propertysequence.hxx>
124
125using namespace ::com::sun::star;
126using namespace sw;
127
128namespace {
129
130void lcl_emitEvent(SfxEventHintId nEventId, sal_Int32 nStrId, SfxObjectShell* pDocShell)
131{
132 SfxGetpApp()->NotifyEvent(SfxEventHint(nEventId,
133 SwDocShell::GetEventName(nStrId),
134 pDocShell));
135}
136
137}
138
139std::vector<std::pair<SwDocShell*, OUString>> SwDBManager::m_aUncommittedRegistrations;
140
141namespace {
142
143enum class SwDBNextRecord { NEXT, FIRST };
144
145}
146
147static bool lcl_ToNextRecord( SwDSParam* pParam, const SwDBNextRecord action = SwDBNextRecord::NEXT );
148
149namespace {
150
151enum class WorkingDocType { SOURCE, TARGET, COPY };
152
153}
154
155static SfxObjectShell* lcl_CreateWorkingDocument(
156 const WorkingDocType aType, const SwWrtShell &rSourceWrtShell,
157 const vcl::Window *pSourceWindow,
158 SwDBManager** const ppDBManager,
159 SwView** const pView, SwWrtShell** const pWrtShell, SwDoc** const pDoc );
160
161static bool lcl_getCountFromResultSet( sal_Int32& rCount, const SwDSParam* pParam )
162{
163 rCount = pParam->aSelection.getLength();
164 if ( rCount > 0 )
165 return true;
166
167 uno::Reference<beans::XPropertySet> xPrSet(pParam->xResultSet, uno::UNO_QUERY);
168 if ( xPrSet.is() )
169 {
170 try
171 {
172 bool bFinal = false;
173 uno::Any aFinal = xPrSet->getPropertyValue("IsRowCountFinal");
174 aFinal >>= bFinal;
175 if(!bFinal)
176 {
177 pParam->xResultSet->last();
178 pParam->xResultSet->first();
179 }
180 uno::Any aCount = xPrSet->getPropertyValue("RowCount");
181 if( aCount >>= rCount )
182 return true;
183 }
184 catch(const uno::Exception&)
185 {
186 }
187 }
188 return false;
189}
190
191class SwDBManager::ConnectionDisposedListener_Impl
192 : public cppu::WeakImplHelper< lang::XEventListener >
193{
194private:
195 SwDBManager * m_pDBManager;
196
197 virtual void SAL_CALL disposing( const lang::EventObject& Source ) override;
198
199public:
200 explicit ConnectionDisposedListener_Impl(SwDBManager& rMgr);
201
202 void Dispose() { m_pDBManager = nullptr; }
203
204};
205
206namespace {
207
208/// Listens to removed data sources, and if it's one that's embedded into this document, triggers embedding removal.
209class SwDataSourceRemovedListener : public cppu::WeakImplHelper<sdb::XDatabaseRegistrationsListener>
210{
211 uno::Reference<sdb::XDatabaseContext> m_xDatabaseContext;
212 SwDBManager* m_pDBManager;
213
214public:
215 explicit SwDataSourceRemovedListener(SwDBManager& rDBManager);
216 virtual ~SwDataSourceRemovedListener() override;
217 virtual void SAL_CALL registeredDatabaseLocation(const sdb::DatabaseRegistrationEvent& rEvent) override;
218 virtual void SAL_CALL revokedDatabaseLocation(const sdb::DatabaseRegistrationEvent& rEvent) override;
219 virtual void SAL_CALL changedDatabaseLocation(const sdb::DatabaseRegistrationEvent& rEvent) override;
220 virtual void SAL_CALL disposing(const lang::EventObject& rObject) override;
221 void Dispose();
222};
223
224}
225
226SwDataSourceRemovedListener::SwDataSourceRemovedListener(SwDBManager& rDBManager)
227 : m_pDBManager(&rDBManager)
228{
229 uno::Reference<uno::XComponentContext> xComponentContext(comphelper::getProcessComponentContext());
230 m_xDatabaseContext = sdb::DatabaseContext::create(xComponentContext);
231 m_xDatabaseContext->addDatabaseRegistrationsListener(this);
232}
233
234SwDataSourceRemovedListener::~SwDataSourceRemovedListener()
235{
236 if (m_xDatabaseContext.is())
237 m_xDatabaseContext->removeDatabaseRegistrationsListener(this);
238}
239
240void SAL_CALL SwDataSourceRemovedListener::registeredDatabaseLocation(const sdb::DatabaseRegistrationEvent& /*rEvent*/)
241{
242}
243
244void SAL_CALL SwDataSourceRemovedListener::revokedDatabaseLocation(const sdb::DatabaseRegistrationEvent& rEvent)
245{
246 if (!m_pDBManager || m_pDBManager->getEmbeddedName().isEmpty())
247 return;
248
249 SwDoc* pDoc = m_pDBManager->getDoc();
250 if (!pDoc)
251 return;
252
253 SwDocShell* pDocShell = pDoc->GetDocShell();
254 if (!pDocShell)
255 return;
256
257 OUString aOwnURL = pDocShell->GetMedium()->GetURLObject().GetMainURL(INetURLObject::DecodeMechanism::WithCharset);
258 OUString sTmpName = "vnd.sun.star.pkg://" +
259 INetURLObject::encode(aOwnURL, INetURLObject::PART_AUTHORITY, INetURLObject::EncodeMechanism::All);
260 sTmpName += "/" + m_pDBManager->getEmbeddedName();
261
262 if (sTmpName != rEvent.OldLocation)
263 return;
264
265 // The revoked database location is inside this document, then remove the
266 // embedding, as otherwise it would be back on the next reload of the
267 // document.
268 pDocShell->GetStorage()->removeElement(m_pDBManager->getEmbeddedName());
269 m_pDBManager->setEmbeddedName(OUString(), *pDocShell);
270}
271
272void SAL_CALL SwDataSourceRemovedListener::changedDatabaseLocation(const sdb::DatabaseRegistrationEvent& rEvent)
273{
274 if (rEvent.OldLocation != rEvent.NewLocation)
275 revokedDatabaseLocation(rEvent);
276}
277
278void SwDataSourceRemovedListener::disposing(const lang::EventObject& /*rObject*/)
279{
280 m_xDatabaseContext.clear();
281}
282
283void SwDataSourceRemovedListener::Dispose()
284{
285 m_pDBManager = nullptr;
286}
287
288struct SwDBManager::SwDBManager_Impl
289{
290 std::unique_ptr<SwDSParam> pMergeData;
291 VclPtr<AbstractMailMergeDlg> pMergeDialog;
292 rtl::Reference<SwDBManager::ConnectionDisposedListener_Impl> m_xDisposeListener;
293 rtl::Reference<SwDataSourceRemovedListener> m_xDataSourceRemovedListener;
294 osl::Mutex m_aAllEmailSendMutex;
295 uno::Reference< mail::XMailMessage> m_xLastMessage;
296
297 explicit SwDBManager_Impl(SwDBManager& rDBManager)
298 : m_xDisposeListener(new ConnectionDisposedListener_Impl(rDBManager))
299 {}
300
301 ~SwDBManager_Impl()
302 {
303 m_xDisposeListener->Dispose();
304 if (m_xDataSourceRemovedListener.is())
305 m_xDataSourceRemovedListener->Dispose();
306 }
307};
308
309static void lcl_InitNumberFormatter(SwDSParam& rParam, uno::Reference<sdbc::XDataSource> const & xSource)
310{
311 uno::Reference<uno::XComponentContext> xContext = ::comphelper::getProcessComponentContext();
312 rParam.xFormatter = util::NumberFormatter::create(xContext);
313 uno::Reference<beans::XPropertySet> xSourceProps(
314 (xSource.is()
315 ? xSource
316 : SwDBManager::getDataSourceAsParent(
317 rParam.xConnection, rParam.sDataSource)),
318 uno::UNO_QUERY);
319 if(!xSourceProps.is())
320 return;
321
322 uno::Any aFormats = xSourceProps->getPropertyValue("NumberFormatsSupplier");
323 if(!aFormats.hasValue())
324 return;
325
326 uno::Reference<util::XNumberFormatsSupplier> xSuppl;
327 aFormats >>= xSuppl;
328 if(xSuppl.is())
329 {
330 uno::Reference< beans::XPropertySet > xSettings = xSuppl->getNumberFormatSettings();
331 uno::Any aNull = xSettings->getPropertyValue("NullDate");
332 aNull >>= rParam.aNullDate;
333 if(rParam.xFormatter.is())
334 rParam.xFormatter->attachNumberFormatsSupplier(xSuppl);
335 }
336}
337
338static bool lcl_MoveAbsolute(SwDSParam* pParam, long nAbsPos)
339{
340 bool bRet = false;
341 try
342 {
343 if(pParam->aSelection.hasElements())
344 {
345 if(pParam->aSelection.getLength() <= nAbsPos)
346 {
347 pParam->bEndOfDB = true;
348 bRet = false;
349 }
350 else
351 {
352 pParam->nSelectionIndex = nAbsPos;
353 sal_Int32 nPos = 0;
354 pParam->aSelection.getConstArray()[ pParam->nSelectionIndex ] >>= nPos;
355 pParam->bEndOfDB = !pParam->xResultSet->absolute( nPos );
356 bRet = !pParam->bEndOfDB;
357 }
358 }
359 else if(pParam->bScrollable)
360 {
361 bRet = pParam->xResultSet->absolute( nAbsPos );
362 }
363 else
364 {
365 OSL_FAIL("no absolute positioning available")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "365" ": "), "%s", "no absolute positioning available");
} } while (false)
;
366 }
367 }
368 catch(const uno::Exception&)
369 {
370 }
371 return bRet;
372}
373
374static void lcl_GetColumnCnt(SwDSParam *pParam,
375 const uno::Reference< beans::XPropertySet > &rColumnProps,
376 LanguageType nLanguage, OUString &rResult, double* pNumber)
377{
378 SwDBFormatData aFormatData;
379 if(!pParam->xFormatter.is())
380 {
381 uno::Reference<sdbc::XDataSource> xSource = SwDBManager::getDataSourceAsParent(
382 pParam->xConnection,pParam->sDataSource);
383 lcl_InitNumberFormatter(*pParam, xSource );
384 }
385 aFormatData.aNullDate = pParam->aNullDate;
386 aFormatData.xFormatter = pParam->xFormatter;
387
388 aFormatData.aLocale = LanguageTag( nLanguage ).getLocale();
389
390 rResult = SwDBManager::GetDBField( rColumnProps, aFormatData, pNumber);
391}
392
393static bool lcl_GetColumnCnt(SwDSParam* pParam, const OUString& rColumnName,
394 LanguageType nLanguage, OUString& rResult, double* pNumber)
395{
396 uno::Reference< sdbcx::XColumnsSupplier > xColsSupp( pParam->xResultSet, uno::UNO_QUERY );
397 uno::Reference<container::XNameAccess> xCols;
398 try
399 {
400 xCols = xColsSupp->getColumns();
401 }
402 catch(const lang::DisposedException&)
403 {
404 }
405 if(!xCols.is() || !xCols->hasByName(rColumnName))
406 return false;
407 uno::Any aCol = xCols->getByName(rColumnName);
408 uno::Reference< beans::XPropertySet > xColumnProps;
409 aCol >>= xColumnProps;
410 lcl_GetColumnCnt( pParam, xColumnProps, nLanguage, rResult, pNumber );
411 return true;
412};
413
414// import data
415bool SwDBManager::Merge( const SwMergeDescriptor& rMergeDesc )
416{
417 assert( !m_bInMerge && !m_pImpl->pMergeData && "merge already activated!" )(static_cast <bool> (!m_bInMerge && !m_pImpl->
pMergeData && "merge already activated!") ? void (0) :
__assert_fail ("!m_bInMerge && !m_pImpl->pMergeData && \"merge already activated!\""
, "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
, 417, __extension__ __PRETTY_FUNCTION__))
;
418
419 SfxObjectShellLock xWorkObjSh;
420 SwWrtShell *pWorkShell = nullptr;
421 SwDoc *pWorkDoc = nullptr;
422 SwDBManager *pWorkDocOrigDBManager = nullptr;
423
424 switch( rMergeDesc.nMergeType )
425 {
426 case DBMGR_MERGE_PRINTER:
427 case DBMGR_MERGE_EMAIL:
428 case DBMGR_MERGE_FILE:
429 case DBMGR_MERGE_SHELL:
430 {
431 SwDocShell *pSourceDocSh = rMergeDesc.rSh.GetView().GetDocShell();
432 if( pSourceDocSh->IsModified() )
433 {
434 pWorkDocOrigDBManager = this;
435 xWorkObjSh = lcl_CreateWorkingDocument(
436 WorkingDocType::SOURCE, rMergeDesc.rSh, nullptr,
437 &pWorkDocOrigDBManager, nullptr, &pWorkShell, &pWorkDoc );
438 }
439 [[fallthrough]];
440 }
441
442 default:
443 if( !xWorkObjSh.Is() )
444 pWorkShell = &rMergeDesc.rSh;
445 break;
446 }
447
448 SwDBData aData;
449 aData.nCommandType = sdb::CommandType::TABLE;
450 uno::Reference<sdbc::XResultSet> xResSet;
451 uno::Sequence<uno::Any> aSelection;
452 uno::Reference< sdbc::XConnection> xConnection;
453
454 aData.sDataSource = rMergeDesc.rDescriptor.getDataSource();
455 rMergeDesc.rDescriptor[svx::DataAccessDescriptorProperty::Command] >>= aData.sCommand;
456 rMergeDesc.rDescriptor[svx::DataAccessDescriptorProperty::CommandType] >>= aData.nCommandType;
457
458 if ( rMergeDesc.rDescriptor.has(svx::DataAccessDescriptorProperty::Cursor) )
459 rMergeDesc.rDescriptor[svx::DataAccessDescriptorProperty::Cursor] >>= xResSet;
460 if ( rMergeDesc.rDescriptor.has(svx::DataAccessDescriptorProperty::Selection) )
461 rMergeDesc.rDescriptor[svx::DataAccessDescriptorProperty::Selection] >>= aSelection;
462 if ( rMergeDesc.rDescriptor.has(svx::DataAccessDescriptorProperty::Connection) )
463 rMergeDesc.rDescriptor[svx::DataAccessDescriptorProperty::Connection] >>= xConnection;
464
465 if((aData.sDataSource.isEmpty() || aData.sCommand.isEmpty()) && !xResSet.is())
466 {
467 return false;
468 }
469
470 m_pImpl->pMergeData.reset(new SwDSParam(aData, xResSet, aSelection));
471 SwDSParam* pTemp = FindDSData(aData, false);
472 if(pTemp)
473 *pTemp = *m_pImpl->pMergeData;
474 else
475 {
476 // calls from the calculator may have added a connection with an invalid commandtype
477 //"real" data base connections added here have to re-use the already available
478 //DSData and set the correct CommandType
479 aData.nCommandType = -1;
480 pTemp = FindDSData(aData, false);
481 if(pTemp)
482 *pTemp = *m_pImpl->pMergeData;
483 else
484 {
485 m_DataSourceParams.push_back(std::make_unique<SwDSParam>(*m_pImpl->pMergeData));
486 try
487 {
488 uno::Reference<lang::XComponent> xComponent(m_DataSourceParams.back()->xConnection, uno::UNO_QUERY);
489 if(xComponent.is())
490 xComponent->addEventListener(m_pImpl->m_xDisposeListener.get());
491 }
492 catch(const uno::Exception&)
493 {
494 }
495 }
496 }
497 if(!m_pImpl->pMergeData->xConnection.is())
498 m_pImpl->pMergeData->xConnection = xConnection;
499 // add an XEventListener
500
501 lcl_ToNextRecord(m_pImpl->pMergeData.get(), SwDBNextRecord::FIRST);
502
503 uno::Reference<sdbc::XDataSource> xSource = SwDBManager::getDataSourceAsParent(xConnection,aData.sDataSource);
504
505 lcl_InitNumberFormatter(*m_pImpl->pMergeData, xSource);
506
507 pWorkShell->ChgDBData(aData);
508 m_bInMerge = true;
509
510 if (IsInitDBFields())
511 {
512 // with database fields without DB-Name, use DB-Name from Doc
513 std::vector<OUString> aDBNames;
514 aDBNames.emplace_back();
515 SwDBData aInsertData = pWorkShell->GetDBData();
516 OUString sDBName = aInsertData.sDataSource
517 + OUStringChar(DB_DELIMu'\x00ff') + aInsertData.sCommand
518 + OUStringChar(DB_DELIMu'\x00ff')
519 + OUString::number(aInsertData.nCommandType);
520 pWorkShell->ChangeDBFields( aDBNames, sDBName);
521 SetInitDBFields(false);
522 }
523
524 bool bRet = true;
525 switch(rMergeDesc.nMergeType)
526 {
527 case DBMGR_MERGE:
528 pWorkShell->StartAllAction();
529 pWorkShell->SwViewShell::UpdateFields( true );
530 pWorkShell->SetModified();
531 pWorkShell->EndAllAction();
532 break;
533
534 case DBMGR_MERGE_PRINTER:
535 case DBMGR_MERGE_EMAIL:
536 case DBMGR_MERGE_FILE:
537 case DBMGR_MERGE_SHELL:
538 // save files and send them as e-Mail if required
539 bRet = MergeMailFiles(pWorkShell, rMergeDesc);
540 break;
541
542 default:
543 // insert selected entries
544 // (was: InsertRecord)
545 ImportFromConnection(pWorkShell);
546 break;
547 }
548
549 m_pImpl->pMergeData.reset();
550
551 if( xWorkObjSh.Is() )
552 {
553 pWorkDoc->SetDBManager( pWorkDocOrigDBManager );
554 xWorkObjSh->DoClose();
555 }
556
557 m_bInMerge = false;
558
559 return bRet;
560}
561
562void SwDBManager::ImportFromConnection( SwWrtShell* pSh )
563{
564 if(!m_pImpl->pMergeData || m_pImpl->pMergeData->bEndOfDB)
565 return;
566
567 pSh->StartAllAction();
568 pSh->StartUndo();
569 bool bGroupUndo(pSh->DoesGroupUndo());
570 pSh->DoGroupUndo(false);
571
572 if( pSh->HasSelection() )
573 pSh->DelRight();
574
575 std::unique_ptr<SwWait> pWait;
576
577 {
578 sal_uLong i = 0;
579 do {
580
581 ImportDBEntry(pSh);
582 if( 10 == ++i )
583 pWait.reset(new SwWait( *pSh->GetView().GetDocShell(), true));
584
585 } while(ToNextMergeRecord());
586 }
587
588 pSh->DoGroupUndo(bGroupUndo);
589 pSh->EndUndo();
590 pSh->EndAllAction();
591}
592
593void SwDBManager::ImportDBEntry(SwWrtShell* pSh)
594{
595 if(!m_pImpl->pMergeData || m_pImpl->pMergeData->bEndOfDB)
596 return;
597
598 uno::Reference< sdbcx::XColumnsSupplier > xColsSupp( m_pImpl->pMergeData->xResultSet, uno::UNO_QUERY );
599 uno::Reference<container::XNameAccess> xCols = xColsSupp->getColumns();
600 OUStringBuffer sStr;
601 uno::Sequence<OUString> aColNames = xCols->getElementNames();
602 const OUString* pColNames = aColNames.getConstArray();
603 long nLength = aColNames.getLength();
604 for(long i = 0; i < nLength; i++)
605 {
606 uno::Any aCol = xCols->getByName(pColNames[i]);
607 uno::Reference< beans::XPropertySet > xColumnProp;
608 aCol >>= xColumnProp;
609 SwDBFormatData aDBFormat;
610 sStr.append(GetDBField( xColumnProp, aDBFormat));
611 if (i < nLength - 1)
612 sStr.append("\t");
613 }
614 pSh->SwEditShell::Insert2(sStr.makeStringAndClear());
615 pSh->SwFEShell::SplitNode(); // line feed
616}
617
618bool SwDBManager::GetTableNames(weld::ComboBox& rBox, const OUString& rDBName)
619{
620 bool bRet = false;
621 OUString sOldTableName(rBox.get_active_text());
622 rBox.clear();
623 SwDSParam* pParam = FindDSConnection(rDBName, false);
624 uno::Reference< sdbc::XConnection> xConnection;
625 if (pParam && pParam->xConnection.is())
626 xConnection = pParam->xConnection;
627 else
628 {
629 if ( !rDBName.isEmpty() )
630 xConnection = RegisterConnection( rDBName );
631 }
632 if (xConnection.is())
633 {
634 uno::Reference<sdbcx::XTablesSupplier> xTSupplier(xConnection, uno::UNO_QUERY);
635 if(xTSupplier.is())
636 {
637 uno::Reference<container::XNameAccess> xTables = xTSupplier->getTables();
638 const uno::Sequence<OUString> aTables = xTables->getElementNames();
639 for (const OUString& rTable : aTables)
640 rBox.append("0", rTable);
641 }
642 uno::Reference<sdb::XQueriesSupplier> xQSupplier(xConnection, uno::UNO_QUERY);
643 if(xQSupplier.is())
644 {
645 uno::Reference<container::XNameAccess> xQueries = xQSupplier->getQueries();
646 const uno::Sequence<OUString> aQueries = xQueries->getElementNames();
647 for (const OUString& rQuery : aQueries)
648 rBox.append("1", rQuery);
649 }
650 if (!sOldTableName.isEmpty())
651 rBox.set_active_text(sOldTableName);
652 bRet = true;
653 }
654 return bRet;
655}
656
657// fill Listbox with column names of a database
658void SwDBManager::GetColumnNames(weld::ComboBox& rBox,
659 const OUString& rDBName, const OUString& rTableName)
660{
661 SwDBData aData;
662 aData.sDataSource = rDBName;
663 aData.sCommand = rTableName;
664 aData.nCommandType = -1;
665 SwDSParam* pParam = FindDSData(aData, false);
666 uno::Reference< sdbc::XConnection> xConnection;
667 if(pParam && pParam->xConnection.is())
668 xConnection = pParam->xConnection;
669 else
670 {
671 xConnection = RegisterConnection( rDBName );
672 }
673 GetColumnNames(rBox, xConnection, rTableName);
674}
675
676void SwDBManager::GetColumnNames(weld::ComboBox& rBox,
677 uno::Reference< sdbc::XConnection> const & xConnection,
678 const OUString& rTableName)
679{
680 rBox.clear();
681 uno::Reference< sdbcx::XColumnsSupplier> xColsSupp = SwDBManager::GetColumnSupplier(xConnection, rTableName);
682 if(xColsSupp.is())
683 {
684 uno::Reference<container::XNameAccess> xCols = xColsSupp->getColumns();
685 const uno::Sequence<OUString> aColNames = xCols->getElementNames();
686 for (const OUString& rColName : aColNames)
687 {
688 rBox.append_text(rColName);
689 }
690 ::comphelper::disposeComponent( xColsSupp );
691 }
692}
693
694SwDBManager::SwDBManager(SwDoc* pDoc)
695 : m_aMergeStatus( MergeStatus::Ok )
696 , m_bInitDBFields(false)
697 , m_bInMerge(false)
698 , m_bMergeSilent(false)
699 , m_pImpl(new SwDBManager_Impl(*this))
700 , m_pMergeEvtSrc(nullptr)
701 , m_pDoc(pDoc)
702{
703}
704
705SwDBManager::~SwDBManager() COVERITY_NOEXCEPT_FALSE
706{
707 RevokeLastRegistrations();
708
709 // copy required, m_DataSourceParams can be modified while disposing components
710 std::vector<uno::Reference<sdbc::XConnection>> aCopiedConnections;
711 for (const auto & pParam : m_DataSourceParams)
712 {
713 if(pParam->xConnection.is())
714 {
715 aCopiedConnections.push_back(pParam->xConnection);
716 }
717 }
718 for (const auto & xConnection : aCopiedConnections)
719 {
720 try
721 {
722 uno::Reference<lang::XComponent> xComp(xConnection, uno::UNO_QUERY);
723 if(xComp.is())
724 xComp->dispose();
725 }
726 catch(const uno::RuntimeException&)
727 {
728 //may be disposed already since multiple entries may have used the same connection
729 }
730 }
731}
732
733static void lcl_RemoveSectionLinks( SwWrtShell& rWorkShell )
734{
735 //reset all links of the sections of synchronized labels
736 size_t nSections = rWorkShell.GetSectionFormatCount();
737 for (size_t nSection = 0; nSection < nSections; ++nSection)
738 {
739 SwSectionData aSectionData( *rWorkShell.GetSectionFormat( nSection ).GetSection() );
740 if( aSectionData.GetType() == SectionType::FileLink )
741 {
742 aSectionData.SetType( SectionType::Content );
743 aSectionData.SetLinkFileName( OUString() );
744 rWorkShell.UpdateSection( nSection, aSectionData );
745 }
746 }
747 rWorkShell.SetLabelDoc( false );
748}
749
750static void lcl_SaveDebugDoc( SfxObjectShell *xTargetDocShell,
751 const char *name, int no = 0 )
752{
753 static OUString sTempDirURL;
754 if( sTempDirURL.isEmpty() )
755 {
756 SvtPathOptions aPathOpt;
757 utl::TempFile aTempDir( &aPathOpt.GetTempPath(), true );
758 if( aTempDir.IsValid() )
759 {
760 INetURLObject aTempDirURL( aTempDir.GetURL() );
761 sTempDirURL = aTempDirURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
762 SAL_INFO( "sw.mailmerge", "Dump directory: " << sTempDirURL )do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "sw.mailmerge")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "Dump directory: " <<
sTempDirURL) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "762" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "Dump directory: " << sTempDirURL
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Dump directory: " << sTempDirURL; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "762" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Dump directory: " << sTempDirURL) == 1) { ::
sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.mailmerge"
), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "762" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "Dump directory: " << sTempDirURL
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Dump directory: " << sTempDirURL; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "762" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
763 }
764 }
765 if( sTempDirURL.isEmpty() )
766 return;
767
768 const OUString sExt( ".odt" );
769 OUString basename = OUString::createFromAscii( name );
770 if (no > 0)
771 basename += OUString::number(no) + "-";
772 // aTempFile is not deleted, but that seems to be intentional
773 utl::TempFile aTempFile( basename, true, &sExt, &sTempDirURL );
774 INetURLObject aTempFileURL( aTempFile.GetURL() );
775 auto pDstMed = std::make_unique<SfxMedium>(
776 aTempFileURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ),
777 StreamMode::STD_READWRITE );
778 bool bAnyError = !xTargetDocShell->DoSaveAs( *pDstMed );
779 // xObjectShell->DoSaveCompleted crashes the mail merge unit tests, so skip it
780 bAnyError |= (ERRCODE_NONEErrCode(0) != xTargetDocShell->GetError());
781 if( bAnyError )
782 SAL_WARN( "sw.mailmerge", "Error saving: " << aTempFile.GetURL() )do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sw.mailmerge")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "Error saving: " <<
aTempFile.GetURL()) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "782" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "Error saving: " << aTempFile.GetURL
()), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Error saving: " << aTempFile.GetURL(); ::sal
::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"
), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "782" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Error saving: " << aTempFile.GetURL()) == 1
) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"
), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "782" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "Error saving: " << aTempFile.GetURL
()), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Error saving: " << aTempFile.GetURL(); ::sal
::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"
), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "782" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
783 else
784 SAL_INFO( "sw.mailmerge", "Saved doc as: " << aTempFile.GetURL() )do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "sw.mailmerge")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "Saved doc as: " <<
aTempFile.GetURL()) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "784" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "Saved doc as: " << aTempFile.GetURL
()), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Saved doc as: " << aTempFile.GetURL(); ::sal
::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.mailmerge"
), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "784" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Saved doc as: " << aTempFile.GetURL()) == 1
) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.mailmerge"
), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "784" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "Saved doc as: " << aTempFile.GetURL
()), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Saved doc as: " << aTempFile.GetURL(); ::sal
::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.mailmerge"
), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "784" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
785}
786
787static bool lcl_SaveDoc(
788 const INetURLObject* pFileURL,
789 const std::shared_ptr<const SfxFilter>& pStoreToFilter,
790 const OUString* pStoreToFilterOptions,
791 const uno::Sequence< beans::PropertyValue >* pSaveToFilterData,
792 const bool bIsPDFexport,
793 SfxObjectShell* xObjectShell,
794 SwWrtShell& rWorkShell,
795 OUString * const decodedURL = nullptr )
796{
797 OUString url = pFileURL->GetMainURL( INetURLObject::DecodeMechanism::NONE );
798 if( decodedURL )
799 (*decodedURL) = url;
800
801 SfxMedium* pDstMed = new SfxMedium( url, StreamMode::STD_READWRITE );
802 pDstMed->SetFilter( pStoreToFilter );
803 if( pDstMed->GetItemSet() )
804 {
805 if( pStoreToFilterOptions )
806 pDstMed->GetItemSet()->Put( SfxStringItem(SID_FILE_FILTEROPTIONS(5000 + 527),
807 *pStoreToFilterOptions));
808 if( pSaveToFilterData->hasElements() )
809 pDstMed->GetItemSet()->Put( SfxUnoAnyItem(SID_FILTER_DATA(5000 + 1375),
810 uno::makeAny(*pSaveToFilterData)));
811 }
812
813 // convert fields to text if we are exporting to PDF.
814 // this prevents a second merge while updating the fields
815 // in SwXTextDocument::getRendererCount()
816 if( bIsPDFexport )
817 rWorkShell.ConvertFieldsToText();
818
819 bool bAnyError = !xObjectShell->DoSaveAs(*pDstMed);
820 // Actually this should be a bool... so in case of email and individual
821 // files, where this is set, we skip the recently used handling
822 bAnyError |= !xObjectShell->DoSaveCompleted( pDstMed, !decodedURL );
823 bAnyError |= (ERRCODE_NONEErrCode(0) != xObjectShell->GetError());
824 if( bAnyError )
825 {
826 // error message ??
827 ErrorHandler::HandleError( xObjectShell->GetError() );
828 }
829 return !bAnyError;
830}
831
832static void lcl_PreparePrinterOptions(
833 const uno::Sequence< beans::PropertyValue >& rInPrintOptions,
834 uno::Sequence< beans::PropertyValue >& rOutPrintOptions)
835{
836 // printing should be done synchronously otherwise the document
837 // might already become invalid during the process
838
839 const sal_Int32 nOffset = 1;
840 rOutPrintOptions.realloc( nOffset );
841 rOutPrintOptions[ 0 ].Name = "Wait";
842 rOutPrintOptions[ 0 ].Value <<= true;
843
844 // copy print options
845 sal_Int32 nIndex = nOffset;
846 for( const beans::PropertyValue& rOption : rInPrintOptions)
847 {
848 if( rOption.Name == "CopyCount" || rOption.Name == "FileName"
849 || rOption.Name == "Collate" || rOption.Name == "Pages"
850 || rOption.Name == "Wait" || rOption.Name == "PrinterName" )
851 {
852 // add an option
853 rOutPrintOptions.realloc( nIndex + 1 );
854 rOutPrintOptions[ nIndex ].Name = rOption.Name;
855 rOutPrintOptions[ nIndex++ ].Value = rOption.Value ;
856 }
857 }
858}
859
860static void lcl_PrepareSaveFilterDataOptions(
861 const uno::Sequence< beans::PropertyValue >& rInSaveFilterDataptions,
862 uno::Sequence< beans::PropertyValue >& rOutSaveFilterDataOptions,
863 const OUString& sPassword)
864{
865 const sal_Int32 nOffset = 2;
866 rOutSaveFilterDataOptions.realloc( nOffset );
867 rOutSaveFilterDataOptions[ 0 ].Name = "EncryptFile";
868 rOutSaveFilterDataOptions[ 0 ].Value <<= true;
869 rOutSaveFilterDataOptions[ 1 ].Name = "DocumentOpenPassword";
870 rOutSaveFilterDataOptions[ 1 ].Value <<= sPassword;
871
872 // copy other options
873 sal_Int32 nIndex = nOffset;
874 for( const beans::PropertyValue& rOption : rInSaveFilterDataptions)
875 {
876 rOutSaveFilterDataOptions.realloc( nIndex + 1 );
877 rOutSaveFilterDataOptions[ nIndex ].Name = rOption.Name;
878 rOutSaveFilterDataOptions[ nIndex++ ].Value = rOption.Value ;
879 }
880
881}
882
883
884static SfxObjectShell* lcl_CreateWorkingDocument(
885 // input
886 const WorkingDocType aType, const SwWrtShell &rSourceWrtShell,
887 // optional input
888 const vcl::Window *pSourceWindow,
889 // optional in and output to swap the DB manager
890 SwDBManager** const ppDBManager,
891 // optional output
892 SwView** const pView, SwWrtShell** const pWrtShell, SwDoc** const pDoc )
893{
894 const SwDoc *pSourceDoc = rSourceWrtShell.GetDoc();
895 SfxObjectShellRef xWorkObjectShell = pSourceDoc->CreateCopy( true, (aType == WorkingDocType::TARGET) );
896 SfxViewFrame* pWorkFrame = SfxViewFrame::LoadHiddenDocument( *xWorkObjectShell, SFX_INTERFACE_NONE );
897
898 if( pSourceWindow )
899 {
900 // the created window has to be located at the same position as the source window
901 vcl::Window& rTargetWindow = pWorkFrame->GetFrame().GetWindow();
902 rTargetWindow.SetPosPixel( pSourceWindow->GetPosPixel() );
903 }
904
905 SwView* pWorkView = static_cast< SwView* >( pWorkFrame->GetViewShell() );
906 SwWrtShell* pWorkWrtShell = pWorkView->GetWrtShellPtr();
907 pWorkWrtShell->GetViewOptions()->SetIdle( false );
908 pWorkView->AttrChangedNotify(nullptr);// in order for SelectShell to be called
909 SwDoc* pWorkDoc = pWorkWrtShell->GetDoc();
910 pWorkDoc->GetIDocumentUndoRedo().DoUndo( false );
911 pWorkDoc->ReplaceDocumentProperties( *pSourceDoc );
912
913 // import print settings
914 const SwPrintData &rPrintData = pSourceDoc->getIDocumentDeviceAccess().getPrintData();
915 pWorkDoc->getIDocumentDeviceAccess().setPrintData(rPrintData);
916 const JobSetup *pJobSetup = pSourceDoc->getIDocumentDeviceAccess().getJobsetup();
917 if (pJobSetup)
918 pWorkDoc->getIDocumentDeviceAccess().setJobsetup(*pJobSetup);
919
920 if( aType == WorkingDocType::TARGET )
921 {
922 assert( !ppDBManager )(static_cast <bool> (!ppDBManager) ? void (0) : __assert_fail
("!ppDBManager", "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
, 922, __extension__ __PRETTY_FUNCTION__))
;
923 pWorkDoc->SetInMailMerge( true );
924 pWorkWrtShell->SetLabelDoc( false );
925 }
926 else
927 {
928 // We have to swap the DBmanager of the new doc, so we also need input
929 assert(ppDBManager && *ppDBManager)(static_cast <bool> (ppDBManager && *ppDBManager
) ? void (0) : __assert_fail ("ppDBManager && *ppDBManager"
, "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
, 929, __extension__ __PRETTY_FUNCTION__))
;
930 SwDBManager *pWorkDBManager = pWorkDoc->GetDBManager();
931 pWorkDoc->SetDBManager( *ppDBManager );
932 *ppDBManager = pWorkDBManager;
933
934 if( aType == WorkingDocType::SOURCE )
935 {
936 // the GetDBData call constructs the data, if it's missing - kind of const...
937 pWorkWrtShell->ChgDBData( const_cast<SwDoc*>(pSourceDoc)->GetDBData() );
938 // some DocumentSettings are currently not copied by SwDoc::CreateCopy
939 pWorkWrtShell->SetLabelDoc( rSourceWrtShell.IsLabelDoc() );
940 pWorkDoc->getIDocumentState().ResetModified();
941 }
942 else
943 pWorkDoc->getIDocumentLinksAdministration().EmbedAllLinks();
944 }
945
946 if( pView ) *pView = pWorkView;
947 if( pWrtShell ) *pWrtShell = pWorkWrtShell;
948 if( pDoc ) *pDoc = pWorkDoc;
949
950 return xWorkObjectShell.get();
951}
952
953static SwMailMessage* lcl_CreateMailFromDoc(
954 const SwMergeDescriptor &rMergeDescriptor,
955 const OUString &sFileURL, const OUString &sMailRecipient,
956 const OUString &sMailBodyMimeType, rtl_TextEncoding sMailEncoding,
957 const OUString &sAttachmentMimeType )
958{
959 SwMailMessage* pMessage = new SwMailMessage;
960 if( rMergeDescriptor.pMailMergeConfigItem->IsMailReplyTo() )
961 pMessage->setReplyToAddress(rMergeDescriptor.pMailMergeConfigItem->GetMailReplyTo());
962 pMessage->addRecipient( sMailRecipient );
963 pMessage->SetSenderAddress( rMergeDescriptor.pMailMergeConfigItem->GetMailAddress() );
964
965 OUStringBuffer sBody;
966 if( rMergeDescriptor.bSendAsAttachment )
967 {
968 sBody = rMergeDescriptor.sMailBody;
969 mail::MailAttachment aAttach;
970 aAttach.Data = new SwMailTransferable( sFileURL,
971 rMergeDescriptor.sAttachmentName, sAttachmentMimeType );
972 aAttach.ReadableName = rMergeDescriptor.sAttachmentName;
973 pMessage->addAttachment( aAttach );
974 }
975 else
976 {
977 //read in the temporary file and use it as mail body
978 SfxMedium aMedium( sFileURL, StreamMode::READ );
979 SvStream* pInStream = aMedium.GetInStream();
980 assert( pInStream && "no output file created?" )(static_cast <bool> (pInStream && "no output file created?"
) ? void (0) : __assert_fail ("pInStream && \"no output file created?\""
, "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
, 980, __extension__ __PRETTY_FUNCTION__))
;
981 if( !pInStream )
982 return pMessage;
983
984 pInStream->SetStreamCharSet( sMailEncoding );
985 OString sLine;
986 while ( pInStream->ReadLine( sLine ) )
987 {
988 sBody.append(OStringToOUString( sLine, sMailEncoding ));
989 sBody.append("\n");
990 }
991 }
992 pMessage->setSubject( rMergeDescriptor.sSubject );
993 uno::Reference< datatransfer::XTransferable> xBody =
994 new SwMailTransferable( sBody.makeStringAndClear(), sMailBodyMimeType );
995 pMessage->setBody( xBody );
996
997 for( const OUString& sCcRecipient : rMergeDescriptor.aCopiesTo )
998 pMessage->addCcRecipient( sCcRecipient );
999 for( const OUString& sBccRecipient : rMergeDescriptor.aBlindCopiesTo )
1000 pMessage->addBccRecipient( sBccRecipient );
1001
1002 return pMessage;
1003}
1004
1005class SwDBManager::MailDispatcherListener_Impl : public IMailDispatcherListener
1006{
1007 SwDBManager &m_rDBManager;
1008
1009public:
1010 explicit MailDispatcherListener_Impl( SwDBManager &rDBManager )
1011 : m_rDBManager( rDBManager ) {}
1012
1013 virtual void idle() override {}
1014
1015 virtual void mailDelivered( uno::Reference< mail::XMailMessage> xMessage ) override
1016 {
1017 osl::MutexGuard aGuard( m_rDBManager.m_pImpl->m_aAllEmailSendMutex );
1018 if ( m_rDBManager.m_pImpl->m_xLastMessage == xMessage )
1019 m_rDBManager.m_pImpl->m_xLastMessage.clear();
1020 }
1021
1022 virtual void mailDeliveryError( ::rtl::Reference<MailDispatcher> xMailDispatcher,
1023 uno::Reference< mail::XMailMessage>, const OUString& ) override
1024 {
1025 osl::MutexGuard aGuard( m_rDBManager.m_pImpl->m_aAllEmailSendMutex );
1026 m_rDBManager.m_aMergeStatus = MergeStatus::Error;
1027 m_rDBManager.m_pImpl->m_xLastMessage.clear();
1028 xMailDispatcher->stop();
1029 }
1030};
1031
1032/**
1033 * Please have a look at the README in the same directory, before you make
1034 * larger changes in this function!
1035 */
1036bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
1037 const SwMergeDescriptor& rMergeDescriptor)
1038{
1039 // deconstruct mail merge type for better readability.
1040 // uppercase naming is intentional!
1041 const bool bMT_EMAIL = rMergeDescriptor.nMergeType == DBMGR_MERGE_EMAIL;
1
Assuming field 'nMergeType' is not equal to DBMGR_MERGE_EMAIL
1042 const bool bMT_SHELL = rMergeDescriptor.nMergeType == DBMGR_MERGE_SHELL;
2
Assuming field 'nMergeType' is not equal to DBMGR_MERGE_SHELL
1043 const bool bMT_PRINTER = rMergeDescriptor.nMergeType == DBMGR_MERGE_PRINTER;
3
Assuming field 'nMergeType' is not equal to DBMGR_MERGE_PRINTER
1044 const bool bMT_FILE = rMergeDescriptor.nMergeType == DBMGR_MERGE_FILE;
4
Assuming field 'nMergeType' is not equal to DBMGR_MERGE_FILE
1045
1046 //check if the doc is synchronized and contains at least one linked section
1047 const bool bSynchronizedDoc = pSourceShell->IsLabelDoc() && pSourceShell->GetSectionFormatCount() > 1;
5
Assuming the condition is false
1048 const bool bNeedsTempFiles = ( bMT_EMAIL
5.1
'bMT_EMAIL' is false
5.1
'bMT_EMAIL' is false
5.1
'bMT_EMAIL' is false
|| bMT_FILE );
1049 const bool bIsMergeSilent = IsMergeSilent();
1050
1051 bool bCheckSingleFile_ = rMergeDescriptor.bCreateSingleFile;
1052 OUString sPrefix_ = rMergeDescriptor.sPrefix;
1053 if( bMT_EMAIL
5.2
'bMT_EMAIL' is false
5.2
'bMT_EMAIL' is false
5.2
'bMT_EMAIL' is false
)
6
Taking false branch
1054 {
1055 assert( !rMergeDescriptor.bPrefixIsFilename )(static_cast <bool> (!rMergeDescriptor.bPrefixIsFilename
) ? void (0) : __assert_fail ("!rMergeDescriptor.bPrefixIsFilename"
, "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
, 1055, __extension__ __PRETTY_FUNCTION__))
;
1056 assert(!bCheckSingleFile_)(static_cast <bool> (!bCheckSingleFile_) ? void (0) : __assert_fail
("!bCheckSingleFile_", "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
, 1056, __extension__ __PRETTY_FUNCTION__))
;
1057 bCheckSingleFile_ = false;
1058 }
1059 else if( bMT_SHELL
6.1
'bMT_SHELL' is false
6.1
'bMT_SHELL' is false
6.1
'bMT_SHELL' is false
|| bMT_PRINTER
6.2
'bMT_PRINTER' is false
6.2
'bMT_PRINTER' is false
6.2
'bMT_PRINTER' is false
)
7
Taking false branch
1060 {
1061 assert(bCheckSingleFile_)(static_cast <bool> (bCheckSingleFile_) ? void (0) : __assert_fail
("bCheckSingleFile_", "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
, 1061, __extension__ __PRETTY_FUNCTION__))
;
1062 bCheckSingleFile_ = true;
1063 assert(sPrefix_.isEmpty())(static_cast <bool> (sPrefix_.isEmpty()) ? void (0) : __assert_fail
("sPrefix_.isEmpty()", "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
, 1063, __extension__ __PRETTY_FUNCTION__))
;
1064 sPrefix_.clear();
1065 }
1066 const bool bCreateSingleFile = bCheckSingleFile_;
1067 const OUString sDescriptorPrefix = sPrefix_;
1068
1069 // Setup for dumping debugging documents
1070 static const sal_Int32 nMaxDumpDocs = []() {
1071 if (const char* sEnv = getenv("SW_DEBUG_MAILMERGE_DOCS"))
1072 return OUString(sEnv, strlen(sEnv), osl_getThreadTextEncoding()).toInt32();
1073 else
1074 return sal_Int32(0);
1075 }();
1076
1077 ::rtl::Reference< MailDispatcher > xMailDispatcher;
1078 ::rtl::Reference< IMailDispatcherListener > xMailListener;
1079 OUString sMailBodyMimeType;
1080 rtl_TextEncoding sMailEncoding = ::osl_getThreadTextEncoding();
1081
1082 uno::Reference< beans::XPropertySet > xColumnProp;
1083 uno::Reference< beans::XPropertySet > xPasswordColumnProp;
1084
1085 // Check for (mandatory) email or (optional) filename column
1086 SwDBFormatData aColumnDBFormat;
1087 bool bColumnName = !rMergeDescriptor.sDBcolumn.isEmpty();
8
Calling 'OUString::isEmpty'
11
Returning from 'OUString::isEmpty'
1088 bool bPasswordColumnName = !rMergeDescriptor.sDBPasswordColumn.isEmpty();
1089
1090 if( ! bColumnName
11.1
'bColumnName' is false
11.1
'bColumnName' is false
11.1
'bColumnName' is false
)
12
Taking true branch
1091 {
1092 if( bMT_EMAIL
12.1
'bMT_EMAIL' is false
12.1
'bMT_EMAIL' is false
12.1
'bMT_EMAIL' is false
)
13
Taking false branch
1093 return false;
1094 }
1095 else
1096 {
1097 uno::Reference< sdbcx::XColumnsSupplier > xColsSupp( m_pImpl->pMergeData->xResultSet, uno::UNO_QUERY );
1098 uno::Reference<container::XNameAccess> xCols = xColsSupp->getColumns();
1099 if( !xCols->hasByName( rMergeDescriptor.sDBcolumn ) )
1100 return false;
1101 uno::Any aCol = xCols->getByName( rMergeDescriptor.sDBcolumn );
1102 aCol >>= xColumnProp;
1103
1104 if(bPasswordColumnName)
1105 {
1106 aCol = xCols->getByName( rMergeDescriptor.sDBPasswordColumn );
1107 aCol >>= xPasswordColumnProp;
1108 }
1109
1110 aColumnDBFormat.xFormatter = m_pImpl->pMergeData->xFormatter;
1111 aColumnDBFormat.aNullDate = m_pImpl->pMergeData->aNullDate;
1112
1113 if( bMT_EMAIL )
1114 {
1115 // Reset internal mail accounting data
1116 m_pImpl->m_xLastMessage.clear();
1117
1118 xMailDispatcher.set( new MailDispatcher(rMergeDescriptor.xSmtpServer) );
1119 xMailListener = new MailDispatcherListener_Impl( *this );
1120 xMailDispatcher->addListener( xMailListener );
1121 if(!rMergeDescriptor.bSendAsAttachment && rMergeDescriptor.bSendAsHTML)
1122 {
1123 sMailBodyMimeType = "text/html; charset=" + OUString::createFromAscii(
1124 rtl_getBestMimeCharsetFromTextEncoding( sMailEncoding ));
1125 SvxHtmlOptions& rHtmlOptions = SvxHtmlOptions::Get();
1126 sMailEncoding = rHtmlOptions.GetTextEncoding();
1127 }
1128 else
1129 sMailBodyMimeType = "text/plain; charset=UTF-8; format=flowed";
1130 }
1131 }
1132
1133 SwDocShell *pSourceDocSh = pSourceShell->GetView().GetDocShell();
1134
1135 // setup the output format
1136 std::shared_ptr<const SfxFilter> pStoreToFilter = SwIoSystem::GetFileFilter(
1137 pSourceDocSh->GetMedium()->GetURLObject().GetMainURL(INetURLObject::DecodeMechanism::NONE));
1138 SfxFilterContainer* pFilterContainer = SwDocShell::Factory().GetFilterContainer();
1139 const OUString* pStoreToFilterOptions = nullptr;
1140
1141 // if a save_to filter is set then use it - otherwise use the default
1142 if( bMT_EMAIL
13.1
'bMT_EMAIL' is false
13.1
'bMT_EMAIL' is false
13.1
'bMT_EMAIL' is false
&& !rMergeDescriptor.bSendAsAttachment )
1143 {
1144 OUString sExtension = rMergeDescriptor.bSendAsHTML ? OUString("html") : OUString("txt");
1145 pStoreToFilter = pFilterContainer->GetFilter4Extension(sExtension, SfxFilterFlags::EXPORT);
1146 }
1147 else if( !rMergeDescriptor.sSaveToFilter.isEmpty())
14
Taking false branch
1148 {
1149 std::shared_ptr<const SfxFilter> pFilter =
1150 pFilterContainer->GetFilter4FilterName( rMergeDescriptor.sSaveToFilter );
1151 if(pFilter)
1152 {
1153 pStoreToFilter = pFilter;
1154 if(!rMergeDescriptor.sSaveToFilterOptions.isEmpty())
1155 pStoreToFilterOptions = &rMergeDescriptor.sSaveToFilterOptions;
1156 }
1157 }
1158 const bool bIsPDFexport = pStoreToFilter && pStoreToFilter->GetFilterName() == "writer_pdf_Export";
1159
1160 m_aMergeStatus = MergeStatus::Ok;
1161
1162 // in case of creating a single resulting file this has to be created here
1163 SwView* pTargetView = rMergeDescriptor.pMailMergeConfigItem ?
15
Assuming field 'pMailMergeConfigItem' is null
16
'?' condition is false
1164 rMergeDescriptor.pMailMergeConfigItem->GetTargetView() : nullptr;
1165 SwWrtShell* pTargetShell = nullptr;
1166 SwDoc* pTargetDoc = nullptr;
1167 SfxObjectShellRef xTargetDocShell;
1168
1169 std::unique_ptr< utl::TempFile > aTempFile;
1170 sal_uInt16 nStartingPageNo = 0;
1171
1172 std::shared_ptr<weld::GenericDialogController> xProgressDlg;
1173
1174 try
1175 {
1176 vcl::Window *pSourceWindow = nullptr;
1177 if( !bIsMergeSilent )
17
Assuming 'bIsMergeSilent' is false
18
Taking true branch
1178 {
1179 // construct the process dialog
1180 pSourceWindow = &pSourceShell->GetView().GetEditWin();
1181 if (!bMT_PRINTER
18.1
'bMT_PRINTER' is false
18.1
'bMT_PRINTER' is false
18.1
'bMT_PRINTER' is false
)
19
Taking true branch
1182 xProgressDlg = std::make_shared<CreateMonitor>(pSourceWindow->GetFrameWeld());
1183 else
1184 {
1185 xProgressDlg = std::make_shared<PrintMonitor>(pSourceWindow->GetFrameWeld());
1186 static_cast<PrintMonitor*>(xProgressDlg.get())->set_title(
1187 pSourceDocSh->GetTitle(22));
1188 }
1189 weld::DialogController::runAsync(xProgressDlg, [this, &xProgressDlg](sal_Int32 nResult){
1190 if (nResult == RET_CANCEL)
1191 MergeCancel();
1192 xProgressDlg.reset();
1193 });
1194
1195 Application::Reschedule( true );
1196 }
1197
1198 if( bCreateSingleFile && !pTargetView )
20
Assuming 'bCreateSingleFile' is false
1199 {
1200 // create a target docshell to put the merged document into
1201 xTargetDocShell = lcl_CreateWorkingDocument( WorkingDocType::TARGET,
1202 *pSourceShell, bMT_SHELL ? pSourceWindow : nullptr,
1203 nullptr, &pTargetView, &pTargetShell, &pTargetDoc );
1204
1205 if (nMaxDumpDocs)
1206 lcl_SaveDebugDoc( xTargetDocShell.get(), "MergeDoc" );
1207 }
1208 else if( pTargetView
20.1
'pTargetView' is null
20.1
'pTargetView' is null
20.1
'pTargetView' is null
)
21
Taking false branch
1209 {
1210 pTargetShell = pTargetView->GetWrtShellPtr();
1211 pTargetDoc = pTargetShell->GetDoc();
1212 xTargetDocShell = pTargetView->GetDocShell();
1213 }
1214
1215 if( bCreateSingleFile
21.1
'bCreateSingleFile' is false
21.1
'bCreateSingleFile' is false
21.1
'bCreateSingleFile' is false
)
22
Taking false branch
1216 {
1217 // determine the page style and number used at the start of the source document
1218 pSourceShell->SttEndDoc(true);
1219 nStartingPageNo = pSourceShell->GetVirtPageNum();
1220 }
1221
1222 // Progress, to prohibit KeyInputs
1223 SfxProgress aProgress(pSourceDocSh, OUString(), 1);
1224
1225 // lock all dispatchers
1226 SfxViewFrame* pViewFrame = SfxViewFrame::GetFirst(pSourceDocSh);
1227 while (pViewFrame)
23
Loop condition is false. Execution continues on line 1233
1228 {
1229 pViewFrame->GetDispatcher()->Lock(true);
1230 pViewFrame = SfxViewFrame::GetNext(*pViewFrame, pSourceDocSh);
1231 }
1232
1233 sal_Int32 nDocNo = 1;
1234
1235 // For single file mode, the number of pages in the target document so far, which is used
1236 // by AppendDoc() to adjust position of page-bound objects. Getting this information directly
1237 // from the target doc would require repeated layouts of the doc, which is expensive, but
1238 // it can be manually computed from the source documents (for which we do layouts, so the page
1239 // count is known, and there is a blank page between each of them in the target document).
1240 int targetDocPageCount = 0;
1241
1242 if( !bIsMergeSilent
23.1
'bIsMergeSilent' is false
23.1
'bIsMergeSilent' is false
23.1
'bIsMergeSilent' is false
&& !bMT_PRINTER
23.2
'bMT_PRINTER' is false
23.2
'bMT_PRINTER' is false
23.2
'bMT_PRINTER' is false
)
24
Taking true branch
1243 {
1244 sal_Int32 nRecordCount = 1;
1245 lcl_getCountFromResultSet( nRecordCount, m_pImpl->pMergeData.get() );
1246
1247 // Synchronized docs don't auto-advance the record set, but there is a
1248 // "security" check, which will always advance the record set, if there
1249 // is no "next record" field in a synchronized doc => nRecordPerDoc > 0
1250 sal_Int32 nRecordPerDoc = pSourceShell->GetDoc()
1251 ->getIDocumentFieldsAccess().GetRecordsPerDocument();
1252 if ( bSynchronizedDoc
24.1
'bSynchronizedDoc' is false
24.1
'bSynchronizedDoc' is false
24.1
'bSynchronizedDoc' is false
&& (nRecordPerDoc > 1) )
1253 --nRecordPerDoc;
1254 assert( nRecordPerDoc > 0 )(static_cast <bool> (nRecordPerDoc > 0) ? void (0) :
__assert_fail ("nRecordPerDoc > 0", "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
, 1254, __extension__ __PRETTY_FUNCTION__))
;
25
Assuming 'nRecordPerDoc' is > 0
26
'?' condition is true
1255
1256 sal_Int32 nMaxDocs = nRecordCount / nRecordPerDoc;
1257 if ( 0 != nRecordCount % nRecordPerDoc )
27
Assuming the condition is false
28
Taking false branch
1258 nMaxDocs += 1;
1259 static_cast<CreateMonitor*>(xProgressDlg.get())->SetTotalCount(nMaxDocs);
1260 }
1261
1262 long nStartRow, nEndRow;
1263 bool bFreezedLayouts = false;
1264 // to collect temporary email files
1265 std::vector< OUString> aFilesToRemove;
1266
1267 // The SfxObjectShell will be closed explicitly later but
1268 // it is more safe to use SfxObjectShellLock here
1269 SfxObjectShellLock xWorkDocSh;
1270 SwView* pWorkView = nullptr;
1271 SwDoc* pWorkDoc = nullptr;
29
'pWorkDoc' initialized to a null pointer value
1272 SwDBManager* pWorkDocOrigDBManager = nullptr;
1273 SwWrtShell* pWorkShell = nullptr;
1274 bool bWorkDocInitialized = false;
1275
1276 do
40
Loop condition is false. Exiting loop
1277 {
1278 nStartRow = m_pImpl->pMergeData ? m_pImpl->pMergeData->xResultSet->getRow() : 0;
30
'?' condition is true
1279
1280 OUString sColumnData;
1281
1282 // Read the indicated data column, which should contain a valid mail
1283 // address or an optional file name
1284 if( bMT_EMAIL
30.1
'bMT_EMAIL' is false
30.1
'bMT_EMAIL' is false
30.1
'bMT_EMAIL' is false
|| bColumnName
30.2
'bColumnName' is false
30.2
'bColumnName' is false
30.2
'bColumnName' is false
)
31
Taking false branch
1285 {
1286 sColumnData = GetDBField( xColumnProp, aColumnDBFormat );
1287 }
1288
1289 // create a new temporary file name - only done once in case of bCreateSingleFile
1290 if( bNeedsTempFiles
31.1
'bNeedsTempFiles' is false
31.1
'bNeedsTempFiles' is false
31.1
'bNeedsTempFiles' is false
&& ( !bWorkDocInitialized || !bCreateSingleFile ))
1291 {
1292 OUString sPrefix = sDescriptorPrefix;
1293 OUString sLeading;
1294
1295 //#i97667# if the name is from a database field then it will be used _as is_
1296 if( bColumnName && !bMT_EMAIL )
1297 {
1298 if (!sColumnData.isEmpty())
1299 sLeading = sColumnData;
1300 else
1301 sLeading = "_";
1302 }
1303 else
1304 {
1305 INetURLObject aEntry( sPrefix );
1306 sLeading = aEntry.GetBase();
1307 aEntry.removeSegment();
1308 sPrefix = aEntry.GetMainURL( INetURLObject::DecodeMechanism::NONE );
1309 }
1310
1311 OUString sExt(comphelper::string::stripStart(pStoreToFilter->GetDefaultExtension(), '*'));
1312 aTempFile.reset( new utl::TempFile(sLeading, sColumnData.isEmpty(), &sExt, &sPrefix, true) );
1313 if( !aTempFile->IsValid() )
1314 {
1315 ErrorHandler::HandleError( ERRCODE_IO_NOTSUPPORTEDErrCode( ErrCodeArea::Io, ErrCodeClass::NotSupported, 12 ) );
1316 m_aMergeStatus = MergeStatus::Error;
1317 }
1318 }
1319
1320 uno::Sequence< beans::PropertyValue > aSaveToFilterDataOptions( rMergeDescriptor.aSaveToFilterData );
1321
1322 if( bMT_EMAIL
31.2
'bMT_EMAIL' is false
31.2
'bMT_EMAIL' is false
31.2
'bMT_EMAIL' is false
|| bPasswordColumnName
31.3
'bPasswordColumnName' is true
31.3
'bPasswordColumnName' is true
31.3
'bPasswordColumnName' is true
)
32
Taking true branch
1323 {
1324 OUString sPasswordColumnData = GetDBField( xPasswordColumnProp, aColumnDBFormat );
1325 lcl_PrepareSaveFilterDataOptions( rMergeDescriptor.aSaveToFilterData, aSaveToFilterDataOptions, sPasswordColumnData );
1326 }
1327
1328 if( IsMergeOk() )
33
Calling 'SwDBManager::IsMergeOk'
36
Returning from 'SwDBManager::IsMergeOk'
37
Taking false branch
1329 {
1330 std::unique_ptr< INetURLObject > aTempFileURL;
1331 if( bNeedsTempFiles )
1332 aTempFileURL.reset( new INetURLObject(aTempFile->GetURL()));
1333 if( !bIsMergeSilent ) {
1334 if( !bMT_PRINTER )
1335 static_cast<CreateMonitor*>(xProgressDlg.get())->SetCurrentPosition(nDocNo);
1336 else {
1337 PrintMonitor *pPrintMonDlg = static_cast<PrintMonitor*>(xProgressDlg.get());
1338 pPrintMonDlg->m_xPrinter->set_label(bNeedsTempFiles
1339 ? aTempFileURL->GetBase() : pSourceDocSh->GetTitle( 2));
1340 OUString sStat = SwResId(STR_STATSTR_LETTERreinterpret_cast<char const *>("STR_STATSTR_LETTER" "\004"
u8"Letter")
) + " " + OUString::number( nDocNo );
1341 pPrintMonDlg->m_xPrintInfo->set_label(sStat);
1342 }
1343 //TODO xProgressDlg->queue_draw();
1344 }
1345
1346 Scheduler::ProcessEventsToIdle();
1347
1348 // Create a copy of the source document and work with that one instead of the source.
1349 // If we're not in the single file mode (which requires modifying the document for the merging),
1350 // it is enough to do this just once. Currently PDF also has to be treated special.
1351 if( !bWorkDocInitialized || bCreateSingleFile || bIsPDFexport )
1352 {
1353 assert( !xWorkDocSh.Is())(static_cast <bool> (!xWorkDocSh.Is()) ? void (0) : __assert_fail
("!xWorkDocSh.Is()", "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
, 1353, __extension__ __PRETTY_FUNCTION__))
;
1354 pWorkDocOrigDBManager = this;
1355 xWorkDocSh = lcl_CreateWorkingDocument( WorkingDocType::COPY,
1356 *pSourceShell, nullptr, &pWorkDocOrigDBManager,
1357 &pWorkView, &pWorkShell, &pWorkDoc );
1358 if ( (nMaxDumpDocs < 0) || (nDocNo <= nMaxDumpDocs) )
1359 lcl_SaveDebugDoc( xWorkDocSh, "WorkDoc", nDocNo );
1360
1361 // #i69458# lock fields to prevent access to the result set while calculating layout
1362 // tdf#92324: and do not unlock: keep document locked during printing to avoid
1363 // ExpFields update during printing, generation of preview, etc.
1364 pWorkShell->LockExpFields();
1365 pWorkShell->CalcLayout();
1366 // tdf#121168: Now force correct page descriptions applied to page frames. Without
1367 // this, e.g., page frames starting with sections could have page descriptions set
1368 // wrong. This would lead to wrong page styles applied in SwDoc::AppendDoc below.
1369 pWorkShell->GetViewOptions()->SetIdle(true);
1370 for (auto aLayout : pWorkShell->GetDoc()->GetAllLayouts())
1371 {
1372 aLayout->FreezeLayout(false);
1373 aLayout->AllCheckPageDescs();
1374 }
1375 }
1376
1377 lcl_emitEvent(SfxEventHintId::SwEventFieldMerge, STR_SW_EVENT_FIELD_MERGE3, xWorkDocSh);
1378
1379 // tdf#92324: Allow ExpFields update only by explicit instruction to avoid
1380 // database cursor movement on any other fields update, for example during
1381 // print preview and other operations
1382 if ( pWorkShell->IsExpFieldsLocked() )
1383 pWorkShell->UnlockExpFields();
1384 pWorkShell->SwViewShell::UpdateFields();
1385 pWorkShell->LockExpFields();
1386
1387 lcl_emitEvent(SfxEventHintId::SwEventFieldMergeFinished, STR_SW_EVENT_FIELD_MERGE_FINISHED4, xWorkDocSh);
1388
1389 // also emit MailMergeEvent on XInterface if possible
1390 const SwXMailMerge *pEvtSrc = GetMailMergeEvtSrc();
1391 if(pEvtSrc)
1392 {
1393 rtl::Reference< SwXMailMerge > xRef(
1394 const_cast<SwXMailMerge*>(pEvtSrc) );
1395 text::MailMergeEvent aEvt( static_cast<text::XMailMergeBroadcaster*>(xRef.get()), xWorkDocSh->GetModel() );
1396 SolarMutexReleaser rel;
1397 xRef->LaunchMailMergeEvent( aEvt );
1398 }
1399
1400 // working copy is merged - prepare final steps depending on merge options
1401
1402 if( bCreateSingleFile )
1403 {
1404 assert( pTargetShell && "no target shell available!" )(static_cast <bool> (pTargetShell && "no target shell available!"
) ? void (0) : __assert_fail ("pTargetShell && \"no target shell available!\""
, "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
, 1404, __extension__ __PRETTY_FUNCTION__))
;
1405
1406 // prepare working copy and target to append
1407
1408 pWorkDoc->RemoveInvisibleContent();
1409 // remove of invisible content has influence on page count and so on fields for page count,
1410 // therefore layout has to be updated before fields are converted to text
1411 pWorkShell->CalcLayout();
1412 pWorkShell->ConvertFieldsToText();
1413 pWorkShell->SetNumberingRestart();
1414 if( bSynchronizedDoc )
1415 {
1416 lcl_RemoveSectionLinks( *pWorkShell );
1417 }
1418
1419 if ( (nMaxDumpDocs < 0) || (nDocNo <= nMaxDumpDocs) )
1420 lcl_SaveDebugDoc( xWorkDocSh, "WorkDoc", nDocNo );
1421
1422 // append the working document to the target document
1423 if( targetDocPageCount % 2 == 1 )
1424 ++targetDocPageCount; // Docs always start on odd pages (so offset must be even).
1425 SwNodeIndex appendedDocStart = pTargetDoc->AppendDoc( *pWorkDoc,
1426 nStartingPageNo, !bWorkDocInitialized, targetDocPageCount, nDocNo);
1427 targetDocPageCount += pWorkShell->GetPageCnt();
1428
1429 if ( (nMaxDumpDocs < 0) || (nDocNo <= nMaxDumpDocs) )
1430 lcl_SaveDebugDoc( xTargetDocShell.get(), "MergeDoc" );
1431
1432 if (bMT_SHELL)
1433 {
1434 SwDocMergeInfo aMergeInfo;
1435 // Name of the mark is actually irrelevant, UNO bookmarks have internals names.
1436 aMergeInfo.startPageInTarget = pTargetDoc->getIDocumentMarkAccess()->makeMark(
1437 appendedDocStart, "", IDocumentMarkAccess::MarkType::UNO_BOOKMARK,
1438 ::sw::mark::InsertMode::New);
1439 aMergeInfo.nDBRow = nStartRow;
1440 rMergeDescriptor.pMailMergeConfigItem->AddMergedDocument( aMergeInfo );
1441 }
1442 }
1443 else
1444 {
1445 assert( bNeedsTempFiles )(static_cast <bool> (bNeedsTempFiles) ? void (0) : __assert_fail
("bNeedsTempFiles", "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
, 1445, __extension__ __PRETTY_FUNCTION__))
;
1446 assert( pWorkShell->IsExpFieldsLocked() )(static_cast <bool> (pWorkShell->IsExpFieldsLocked()
) ? void (0) : __assert_fail ("pWorkShell->IsExpFieldsLocked()"
, "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
, 1446, __extension__ __PRETTY_FUNCTION__))
;
1447
1448 // fields are locked, so it's fine to
1449 // restore the old / empty DB manager for save
1450 pWorkDoc->SetDBManager( pWorkDocOrigDBManager );
1451
1452 // save merged document
1453 OUString sFileURL;
1454 if( !lcl_SaveDoc( aTempFileURL.get(), pStoreToFilter, pStoreToFilterOptions,
1455 &aSaveToFilterDataOptions, bIsPDFexport,
1456 xWorkDocSh, *pWorkShell, &sFileURL ) )
1457 {
1458 m_aMergeStatus = MergeStatus::Error;
1459 }
1460
1461 // back to the MM DB manager
1462 pWorkDoc->SetDBManager( this );
1463
1464 if( bMT_EMAIL && !IsMergeError() )
1465 {
1466 // schedule file for later removal
1467 aFilesToRemove.push_back( sFileURL );
1468
1469 if( !SwMailMergeHelper::CheckMailAddress( sColumnData ) )
1470 {
1471 OSL_FAIL("invalid e-Mail address in database column")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "1471" ": "), "%s", "invalid e-Mail address in database column"
); } } while (false)
;
1472 }
1473 else
1474 {
1475 uno::Reference< mail::XMailMessage > xMessage = lcl_CreateMailFromDoc(
1476 rMergeDescriptor, sFileURL, sColumnData, sMailBodyMimeType,
1477 sMailEncoding, pStoreToFilter->GetMimeType() );
1478 if( xMessage.is() )
1479 {
1480 osl::MutexGuard aGuard( m_pImpl->m_aAllEmailSendMutex );
1481 m_pImpl->m_xLastMessage.set( xMessage );
1482 xMailDispatcher->enqueueMailMessage( xMessage );
1483 if( !xMailDispatcher->isStarted() )
1484 xMailDispatcher->start();
1485 }
1486 }
1487 }
1488 }
1489 if( bCreateSingleFile || bIsPDFexport )
1490 {
1491 pWorkDoc->SetDBManager( pWorkDocOrigDBManager );
1492 xWorkDocSh->DoClose();
1493 xWorkDocSh = nullptr;
1494 }
1495 }
1496
1497 bWorkDocInitialized = true;
1498 nDocNo++;
1499 nEndRow = m_pImpl->pMergeData ? m_pImpl->pMergeData->xResultSet->getRow() : 0;
38
'?' condition is true
1500
1501 // Freeze the layouts of the target document after the first inserted
1502 // sub-document, to get the correct PageDesc.
1503 if(!bFreezedLayouts
38.1
'bFreezedLayouts' is false
38.1
'bFreezedLayouts' is false
38.1
'bFreezedLayouts' is false
&& bCreateSingleFile
38.2
'bCreateSingleFile' is false
38.2
'bCreateSingleFile' is false
38.2
'bCreateSingleFile' is false
)
39
Taking false branch
1504 {
1505 for ( auto aLayout : pTargetShell->GetDoc()->GetAllLayouts() )
1506 aLayout->FreezeLayout(true);
1507 bFreezedLayouts = true;
1508 }
1509 } while( IsMergeOk() &&
1510 ((bSynchronizedDoc && (nStartRow != nEndRow)) ? IsValidMergeRecord() : ToNextMergeRecord()));
1511
1512 if ( xWorkDocSh.Is() && pWorkView->GetWrtShell().IsExpFieldsLocked() )
1513 {
1514 // Unlock document fields after merge complete
1515 pWorkView->GetWrtShell().UnlockExpFields();
1516 }
1517
1518 if( !bCreateSingleFile
40.1
'bCreateSingleFile' is false
40.1
'bCreateSingleFile' is false
40.1
'bCreateSingleFile' is false
)
41
Taking true branch
1519 {
1520 if( bMT_PRINTER
41.1
'bMT_PRINTER' is false
41.1
'bMT_PRINTER' is false
41.1
'bMT_PRINTER' is false
)
42
Taking false branch
1521 Printer::FinishPrintJob( pWorkView->GetPrinterController());
1522 if( !bIsPDFexport
42.1
'bIsPDFexport' is false
42.1
'bIsPDFexport' is false
42.1
'bIsPDFexport' is false
)
43
Taking true branch
1523 {
1524 pWorkDoc->SetDBManager( pWorkDocOrigDBManager );
44
Called C++ object pointer is null
1525 xWorkDocSh->DoClose();
1526 }
1527 }
1528 else if( IsMergeOk() ) // && bCreateSingleFile
1529 {
1530 Application::Reschedule( true );
1531
1532 // sw::DocumentLayoutManager::CopyLayoutFormat() did not generate
1533 // unique fly names, do it here once.
1534 pTargetDoc->SetInMailMerge(false);
1535 pTargetDoc->SetAllUniqueFlyNames();
1536
1537 // Unfreeze target document layouts and correct all PageDescs.
1538 SAL_INFO( "sw.pageframe", "(MergeMailFiles pTargetShell->CalcLayout in" )do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "sw.pageframe")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "(MergeMailFiles pTargetShell->CalcLayout in"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.pageframe"
), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "1538" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "(MergeMailFiles pTargetShell->CalcLayout in"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "(MergeMailFiles pTargetShell->CalcLayout in"; ::
sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.pageframe"
), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "1538" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "(MergeMailFiles pTargetShell->CalcLayout in")
== 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.pageframe"
), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "1538" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "(MergeMailFiles pTargetShell->CalcLayout in"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "(MergeMailFiles pTargetShell->CalcLayout in"; ::
sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.pageframe"
), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "1538" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1539 pTargetShell->CalcLayout();
1540 SAL_INFO( "sw.pageframe", "MergeMailFiles pTargetShell->CalcLayout out)" )do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "sw.pageframe")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "MergeMailFiles pTargetShell->CalcLayout out)"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.pageframe"
), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "1540" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "MergeMailFiles pTargetShell->CalcLayout out)"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "MergeMailFiles pTargetShell->CalcLayout out)"; ::
sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.pageframe"
), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "1540" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "MergeMailFiles pTargetShell->CalcLayout out)"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.pageframe"
), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "1540" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "MergeMailFiles pTargetShell->CalcLayout out)"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "MergeMailFiles pTargetShell->CalcLayout out)"; ::
sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.pageframe"
), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "1540" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1541 pTargetShell->GetViewOptions()->SetIdle( true );
1542 pTargetDoc->GetIDocumentUndoRedo().DoUndo( true );
1543 for ( auto aLayout : pTargetShell->GetDoc()->GetAllLayouts() )
1544 {
1545 aLayout->FreezeLayout(false);
1546 aLayout->AllCheckPageDescs();
1547 }
1548
1549 Application::Reschedule( true );
1550
1551 if( IsMergeOk() && bMT_FILE )
1552 {
1553 // save merged document
1554 assert( aTempFile )(static_cast <bool> (aTempFile) ? void (0) : __assert_fail
("aTempFile", "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
, 1554, __extension__ __PRETTY_FUNCTION__))
;
1555 INetURLObject aTempFileURL;
1556 if (sDescriptorPrefix.isEmpty() || !rMergeDescriptor.bPrefixIsFilename)
1557 aTempFileURL.SetURL( aTempFile->GetURL() );
1558 else
1559 {
1560 aTempFileURL.SetURL(sDescriptorPrefix);
1561 // remove the unneeded temporary file
1562 aTempFile->EnableKillingFile();
1563 }
1564 if( !lcl_SaveDoc( &aTempFileURL, pStoreToFilter,
1565 pStoreToFilterOptions, &rMergeDescriptor.aSaveToFilterData,
1566 bIsPDFexport, xTargetDocShell.get(), *pTargetShell ) )
1567 {
1568 m_aMergeStatus = MergeStatus::Error;
1569 }
1570 }
1571 else if( IsMergeOk() && bMT_PRINTER )
1572 {
1573 // print the target document
1574 uno::Sequence< beans::PropertyValue > aOptions( rMergeDescriptor.aPrintOptions );
1575 lcl_PreparePrinterOptions( rMergeDescriptor.aPrintOptions, aOptions );
1576 pTargetView->ExecPrint( aOptions, bIsMergeSilent, false/*bPrintAsync*/ );
1577 }
1578 }
1579
1580 // we also show canceled documents, as long as there was no error
1581 if( !IsMergeError() && bMT_SHELL )
1582 // leave docshell available for caller (e.g. MM wizard)
1583 rMergeDescriptor.pMailMergeConfigItem->SetTargetView( pTargetView );
1584 else if( xTargetDocShell.is() )
1585 xTargetDocShell->DoClose();
1586
1587 Application::Reschedule( true );
1588
1589 if (xProgressDlg)
1590 {
1591 xProgressDlg->response(RET_OK);
1592 }
1593
1594 // unlock all dispatchers
1595 pViewFrame = SfxViewFrame::GetFirst(pSourceDocSh);
1596 while (pViewFrame)
1597 {
1598 pViewFrame->GetDispatcher()->Lock(false);
1599 pViewFrame = SfxViewFrame::GetNext(*pViewFrame, pSourceDocSh);
1600 }
1601
1602 SW_MOD()( static_cast<SwModule*>(SfxApplication::GetModule(SfxToolsModule
::Writer)))
->SetView(&pSourceShell->GetView());
1603
1604 if( xMailDispatcher.is() )
1605 {
1606 if( IsMergeOk() )
1607 {
1608 // TODO: Instead of polling via an AutoTimer, post an Idle event,
1609 // if the main loop has been made thread-safe.
1610 AutoTimer aEmailDispatcherPollTimer;
1611 aEmailDispatcherPollTimer.SetDebugName(
1612 "sw::SwDBManager aEmailDispatcherPollTimer" );
1613 aEmailDispatcherPollTimer.SetTimeout( 500 );
1614 aEmailDispatcherPollTimer.Start();
1615 while( IsMergeOk() && m_pImpl->m_xLastMessage.is() )
1616 Application::Yield();
1617 aEmailDispatcherPollTimer.Stop();
1618 }
1619 xMailDispatcher->stop();
1620 xMailDispatcher->shutdown();
1621 }
1622
1623 // remove the temporary files
1624 // has to be done after xMailDispatcher is finished, as mails may be
1625 // delivered as message attachments!
1626 for( const OUString &sFileURL : aFilesToRemove )
1627 SWUnoHelper::UCB_DeleteFile( sFileURL );
1628 }
1629 catch (const uno::Exception&)
1630 {
1631 if (xProgressDlg)
1632 {
1633 xProgressDlg->response(RET_CANCEL);
1634 }
1635 }
1636
1637 return !IsMergeError();
1638}
1639
1640void SwDBManager::MergeCancel()
1641{
1642 if (m_aMergeStatus < MergeStatus::Cancel)
1643 m_aMergeStatus = MergeStatus::Cancel;
1644}
1645
1646// determine the column's Numberformat and transfer to the forwarded Formatter,
1647// if applicable.
1648sal_uLong SwDBManager::GetColumnFormat( const OUString& rDBName,
1649 const OUString& rTableName,
1650 const OUString& rColNm,
1651 SvNumberFormatter* pNFormatr,
1652 LanguageType nLanguage )
1653{
1654 sal_uLong nRet = 0;
1655 if(pNFormatr)
1656 {
1657 uno::Reference< sdbc::XDataSource> xSource;
1658 uno::Reference< sdbc::XConnection> xConnection;
1659 bool bUseMergeData = false;
1660 uno::Reference< sdbcx::XColumnsSupplier> xColsSupp;
1661 bool bDisposeConnection = false;
1662 if(m_pImpl->pMergeData &&
1663 ((m_pImpl->pMergeData->sDataSource == rDBName && m_pImpl->pMergeData->sCommand == rTableName) ||
1664 (rDBName.isEmpty() && rTableName.isEmpty())))
1665 {
1666 xConnection = m_pImpl->pMergeData->xConnection;
1667 xSource = SwDBManager::getDataSourceAsParent(xConnection,rDBName);
1668 bUseMergeData = true;
1669 xColsSupp.set(m_pImpl->pMergeData->xResultSet, css::uno::UNO_QUERY);
1670 }
1671 if(!xConnection.is())
1672 {
1673 SwDBData aData;
1674 aData.sDataSource = rDBName;
1675 aData.sCommand = rTableName;
1676 aData.nCommandType = -1;
1677 SwDSParam* pParam = FindDSData(aData, false);
1678 if(pParam && pParam->xConnection.is())
1679 {
1680 xConnection = pParam->xConnection;
1681 xColsSupp.set(pParam->xResultSet, css::uno::UNO_QUERY);
1682 }
1683 else
1684 {
1685 xConnection = RegisterConnection( rDBName );
1686 bDisposeConnection = true;
1687 }
1688 if(bUseMergeData)
1689 m_pImpl->pMergeData->xConnection = xConnection;
1690 }
1691 bool bDispose = !xColsSupp.is();
1692 if(bDispose)
1693 {
1694 xColsSupp = SwDBManager::GetColumnSupplier(xConnection, rTableName);
1695 }
1696 if(xColsSupp.is())
1697 {
1698 uno::Reference<container::XNameAccess> xCols;
1699 try
1700 {
1701 xCols = xColsSupp->getColumns();
1702 }
1703 catch (const uno::Exception&)
1704 {
1705 TOOLS_WARN_EXCEPTION("sw.mailmerge", "Exception in getColumns()")do { css::uno::Any tools_warn_exception( DbgGetCaughtException
() ); do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sw.mailmerge")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "Exception in getColumns()"
<< " " << exceptionToString(tools_warn_exception
)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "1705" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "Exception in getColumns()" <<
" " << exceptionToString(tools_warn_exception)), 0); }
else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Exception in getColumns()" << " " << exceptionToString
(tools_warn_exception); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "1705" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Exception in getColumns()" << " " <<
exceptionToString(tools_warn_exception)) == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "1705" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "Exception in getColumns()" <<
" " << exceptionToString(tools_warn_exception)), 0); }
else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Exception in getColumns()" << " " << exceptionToString
(tools_warn_exception); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "1705" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false); } while (false)
;
1706 }
1707 if(!xCols.is() || !xCols->hasByName(rColNm))
1708 return nRet;
1709 uno::Any aCol = xCols->getByName(rColNm);
1710 uno::Reference< beans::XPropertySet > xColumn;
1711 aCol >>= xColumn;
1712 nRet = GetColumnFormat(xSource, xConnection, xColumn, pNFormatr, nLanguage);
1713 if(bDispose)
1714 {
1715 ::comphelper::disposeComponent( xColsSupp );
1716 }
1717 if(bDisposeConnection)
1718 {
1719 ::comphelper::disposeComponent( xConnection );
1720 }
1721 }
1722 else
1723 nRet = pNFormatr->GetFormatIndex( NF_NUMBER_STANDARD, LANGUAGE_SYSTEMLanguageType(0x0000) );
1724 }
1725 return nRet;
1726}
1727
1728sal_uLong SwDBManager::GetColumnFormat( uno::Reference< sdbc::XDataSource> const & xSource_in,
1729 uno::Reference< sdbc::XConnection> const & xConnection,
1730 uno::Reference< beans::XPropertySet> const & xColumn,
1731 SvNumberFormatter* pNFormatr,
1732 LanguageType nLanguage )
1733{
1734 auto xSource = xSource_in;
1735
1736 // set the NumberFormat in the doc if applicable
1737 sal_uLong nRet = 0;
1738
1739 if(!xSource.is())
1740 {
1741 uno::Reference<container::XChild> xChild(xConnection, uno::UNO_QUERY);
1742 if ( xChild.is() )
1743 xSource.set(xChild->getParent(), uno::UNO_QUERY);
1744 }
1745 if(xSource.is() && xConnection.is() && xColumn.is() && pNFormatr)
1746 {
1747 SvNumberFormatsSupplierObj* pNumFormat = new SvNumberFormatsSupplierObj( pNFormatr );
1748 uno::Reference< util::XNumberFormatsSupplier > xDocNumFormatsSupplier = pNumFormat;
1749 uno::Reference< util::XNumberFormats > xDocNumberFormats = xDocNumFormatsSupplier->getNumberFormats();
1750 uno::Reference< util::XNumberFormatTypes > xDocNumberFormatTypes(xDocNumberFormats, uno::UNO_QUERY);
1751
1752 css::lang::Locale aLocale( LanguageTag( nLanguage ).getLocale());
1753
1754 //get the number formatter of the data source
1755 uno::Reference<beans::XPropertySet> xSourceProps(xSource, uno::UNO_QUERY);
1756 uno::Reference< util::XNumberFormats > xNumberFormats;
1757 if(xSourceProps.is())
1758 {
1759 uno::Any aFormats = xSourceProps->getPropertyValue("NumberFormatsSupplier");
1760 if(aFormats.hasValue())
1761 {
1762 uno::Reference<util::XNumberFormatsSupplier> xSuppl;
1763 aFormats >>= xSuppl;
1764 if(xSuppl.is())
1765 {
1766 xNumberFormats = xSuppl->getNumberFormats();
1767 }
1768 }
1769 }
1770 bool bUseDefault = true;
1771 try
1772 {
1773 uno::Any aFormatKey = xColumn->getPropertyValue("FormatKey");
1774 if(aFormatKey.hasValue())
1775 {
1776 sal_Int32 nFormat = 0;
1777 aFormatKey >>= nFormat;
1778 if(xNumberFormats.is())
1779 {
1780 try
1781 {
1782 uno::Reference<beans::XPropertySet> xNumProps = xNumberFormats->getByKey( nFormat );
1783 uno::Any aFormatString = xNumProps->getPropertyValue("FormatString");
1784 uno::Any aLocaleVal = xNumProps->getPropertyValue("Locale");
1785 OUString sFormat;
1786 aFormatString >>= sFormat;
1787 lang::Locale aLoc;
1788 aLocaleVal >>= aLoc;
1789 nFormat = xDocNumberFormats->queryKey( sFormat, aLoc, false );
1790 if(NUMBERFORMAT_ENTRY_NOT_FOUND == sal::static_int_cast< sal_uInt32, sal_Int32>(nFormat))
1791 nFormat = xDocNumberFormats->addNew( sFormat, aLoc );
1792 nRet = nFormat;
1793 bUseDefault = false;
1794 }
1795 catch (const uno::Exception&)
1796 {
1797 TOOLS_WARN_EXCEPTION("sw.mailmerge", "illegal number format key")do { css::uno::Any tools_warn_exception( DbgGetCaughtException
() ); do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sw.mailmerge")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "illegal number format key"
<< " " << exceptionToString(tools_warn_exception
)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "1797" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "illegal number format key" <<
" " << exceptionToString(tools_warn_exception)), 0); }
else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "illegal number format key" << " " << exceptionToString
(tools_warn_exception); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "1797" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "illegal number format key" << " " <<
exceptionToString(tools_warn_exception)) == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "1797" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "illegal number format key" <<
" " << exceptionToString(tools_warn_exception)), 0); }
else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "illegal number format key" << " " << exceptionToString
(tools_warn_exception); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "1797" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false); } while (false)
;
1798 }
1799 }
1800 }
1801 }
1802 catch(const uno::Exception&)
1803 {
1804 SAL_WARN("sw.mailmerge", "no FormatKey property found")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sw.mailmerge")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "no FormatKey property found"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"
), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "1804" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "no FormatKey property found"), 0); }
else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "no FormatKey property found"; ::sal::detail::log( (
::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "1804" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "no FormatKey property found") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "1804" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "no FormatKey property found"), 0); }
else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "no FormatKey property found"; ::sal::detail::log( (
::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "1804" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1805 }
1806 if(bUseDefault)
1807 nRet = dbtools::getDefaultNumberFormat(xColumn, xDocNumberFormatTypes, aLocale);
1808 }
1809 return nRet;
1810}
1811
1812sal_Int32 SwDBManager::GetColumnType( const OUString& rDBName,
1813 const OUString& rTableName,
1814 const OUString& rColNm )
1815{
1816 sal_Int32 nRet = sdbc::DataType::SQLNULL;
1817 SwDBData aData;
1818 aData.sDataSource = rDBName;
1819 aData.sCommand = rTableName;
1820 aData.nCommandType = -1;
1821 SwDSParam* pParam = FindDSData(aData, false);
1822 uno::Reference< sdbc::XConnection> xConnection;
1823 uno::Reference< sdbcx::XColumnsSupplier > xColsSupp;
1824 bool bDispose = false;
1825 if(pParam && pParam->xConnection.is())
1826 {
1827 xConnection = pParam->xConnection;
1828 xColsSupp.set( pParam->xResultSet, uno::UNO_QUERY );
1829 }
1830 else
1831 {
1832 xConnection = RegisterConnection( rDBName );
1833 }
1834 if( !xColsSupp.is() )
1835 {
1836 xColsSupp = SwDBManager::GetColumnSupplier(xConnection, rTableName);
1837 bDispose = true;
1838 }
1839 if(xColsSupp.is())
1840 {
1841 uno::Reference<container::XNameAccess> xCols = xColsSupp->getColumns();
1842 if(xCols->hasByName(rColNm))
1843 {
1844 uno::Any aCol = xCols->getByName(rColNm);
1845 uno::Reference<beans::XPropertySet> xCol;
1846 aCol >>= xCol;
1847 uno::Any aType = xCol->getPropertyValue("Type");
1848 aType >>= nRet;
1849 }
1850 if(bDispose)
1851 ::comphelper::disposeComponent( xColsSupp );
1852 }
1853 return nRet;
1854}
1855
1856uno::Reference< sdbc::XConnection> SwDBManager::GetConnection(const OUString& rDataSource,
1857 uno::Reference<sdbc::XDataSource>& rxSource, const SwView *pView)
1858{
1859 uno::Reference< sdbc::XConnection> xConnection;
1860 uno::Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
1861 try
1862 {
1863 uno::Reference<sdb::XCompletedConnection> xComplConnection(dbtools::getDataSource(rDataSource, xContext), uno::UNO_QUERY);
1864 if ( xComplConnection.is() )
1865 {
1866 rxSource.set(xComplConnection, uno::UNO_QUERY);
1867 weld::Window* pWindow = pView ? pView->GetFrameWeld() : nullptr;
1868 uno::Reference< task::XInteractionHandler > xHandler( task::InteractionHandler::createWithParent(xContext, pWindow ? pWindow->GetXWindow() : nullptr), uno::UNO_QUERY_THROW );
1869 xConnection = xComplConnection->connectWithCompletion( xHandler );
1870 }
1871 }
1872 catch(const uno::Exception&)
1873 {
1874 }
1875
1876 return xConnection;
1877}
1878
1879uno::Reference< sdbcx::XColumnsSupplier> SwDBManager::GetColumnSupplier(uno::Reference<sdbc::XConnection> const & xConnection,
1880 const OUString& rTableOrQuery,
1881 SwDBSelect eTableOrQuery)
1882{
1883 uno::Reference< sdbcx::XColumnsSupplier> xRet;
1884 try
1885 {
1886 if(eTableOrQuery == SwDBSelect::UNKNOWN)
1887 {
1888 //search for a table with the given command name
1889 uno::Reference<sdbcx::XTablesSupplier> xTSupplier(xConnection, uno::UNO_QUERY);
1890 if(xTSupplier.is())
1891 {
1892 uno::Reference<container::XNameAccess> xTables = xTSupplier->getTables();
1893 eTableOrQuery = xTables->hasByName(rTableOrQuery) ?
1894 SwDBSelect::TABLE : SwDBSelect::QUERY;
1895 }
1896 }
1897 sal_Int32 nCommandType = SwDBSelect::TABLE == eTableOrQuery ?
1898 sdb::CommandType::TABLE : sdb::CommandType::QUERY;
1899 uno::Reference< lang::XMultiServiceFactory > xMgr( ::comphelper::getProcessServiceFactory() );
1900 uno::Reference<sdbc::XRowSet> xRowSet(xMgr->createInstance("com.sun.star.sdb.RowSet"), uno::UNO_QUERY);
1901
1902 OUString sDataSource;
1903 uno::Reference<sdbc::XDataSource> xSource = SwDBManager::getDataSourceAsParent(xConnection, sDataSource);
1904 uno::Reference<beans::XPropertySet> xSourceProperties(xSource, uno::UNO_QUERY);
1905 if(xSourceProperties.is())
1906 {
1907 xSourceProperties->getPropertyValue("Name") >>= sDataSource;
1908 }
1909
1910 uno::Reference<beans::XPropertySet> xRowProperties(xRowSet, uno::UNO_QUERY);
1911 xRowProperties->setPropertyValue("DataSourceName", uno::makeAny(sDataSource));
1912 xRowProperties->setPropertyValue("Command", uno::makeAny(rTableOrQuery));
1913 xRowProperties->setPropertyValue("CommandType", uno::makeAny(nCommandType));
1914 xRowProperties->setPropertyValue("FetchSize", uno::makeAny(sal_Int32(10)));
1915 xRowProperties->setPropertyValue("ActiveConnection", uno::makeAny(xConnection));
1916 xRowSet->execute();
1917 xRet.set( xRowSet, uno::UNO_QUERY );
1918 }
1919 catch (const uno::Exception&)
1920 {
1921 TOOLS_WARN_EXCEPTION("sw.mailmerge", "Exception in SwDBManager::GetColumnSupplier")do { css::uno::Any tools_warn_exception( DbgGetCaughtException
() ); do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sw.mailmerge")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "Exception in SwDBManager::GetColumnSupplier"
<< " " << exceptionToString(tools_warn_exception
)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "1921" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "Exception in SwDBManager::GetColumnSupplier"
<< " " << exceptionToString(tools_warn_exception
)), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Exception in SwDBManager::GetColumnSupplier" <<
" " << exceptionToString(tools_warn_exception); ::sal::
detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"),
("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "1921" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Exception in SwDBManager::GetColumnSupplier" <<
" " << exceptionToString(tools_warn_exception)) == 1) {
::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"
), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "1921" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "Exception in SwDBManager::GetColumnSupplier"
<< " " << exceptionToString(tools_warn_exception
)), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Exception in SwDBManager::GetColumnSupplier" <<
" " << exceptionToString(tools_warn_exception); ::sal::
detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"),
("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "1921" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false); } while (false)
;
1922 }
1923
1924 return xRet;
1925}
1926
1927OUString SwDBManager::GetDBField(uno::Reference<beans::XPropertySet> const & xColumnProps,
1928 const SwDBFormatData& rDBFormatData,
1929 double* pNumber)
1930{
1931 uno::Reference< sdb::XColumn > xColumn(xColumnProps, uno::UNO_QUERY);
1932 OUString sRet;
1933 assert( xColumn.is() && "SwDBManager::::ImportDBField: illegal arguments" )(static_cast <bool> (xColumn.is() && "SwDBManager::::ImportDBField: illegal arguments"
) ? void (0) : __assert_fail ("xColumn.is() && \"SwDBManager::::ImportDBField: illegal arguments\""
, "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
, 1933, __extension__ __PRETTY_FUNCTION__))
;
1934 if(!xColumn.is())
1935 return sRet;
1936
1937 uno::Any aType = xColumnProps->getPropertyValue("Type");
1938 sal_Int32 eDataType = sdbc::DataType::SQLNULL;
1939 aType >>= eDataType;
1940 switch(eDataType)
1941 {
1942 case sdbc::DataType::CHAR:
1943 case sdbc::DataType::VARCHAR:
1944 case sdbc::DataType::LONGVARCHAR:
1945 try
1946 {
1947 sRet = xColumn->getString();
1948 sRet = sRet.replace( '\xb', '\n' ); // MSWord uses \xb as a newline
1949 }
1950 catch(const sdbc::SQLException&)
1951 {
1952 }
1953 break;
1954 case sdbc::DataType::BIT:
1955 case sdbc::DataType::BOOLEAN:
1956 case sdbc::DataType::TINYINT:
1957 case sdbc::DataType::SMALLINT:
1958 case sdbc::DataType::INTEGER:
1959 case sdbc::DataType::BIGINT:
1960 case sdbc::DataType::FLOAT:
1961 case sdbc::DataType::REAL:
1962 case sdbc::DataType::DOUBLE:
1963 case sdbc::DataType::NUMERIC:
1964 case sdbc::DataType::DECIMAL:
1965 case sdbc::DataType::DATE:
1966 case sdbc::DataType::TIME:
1967 case sdbc::DataType::TIMESTAMP:
1968 {
1969
1970 try
1971 {
1972 sRet = dbtools::DBTypeConversion::getFormattedValue(
1973 xColumnProps,
1974 rDBFormatData.xFormatter,
1975 rDBFormatData.aLocale,
1976 rDBFormatData.aNullDate);
1977 if (pNumber)
1978 {
1979 double fVal = xColumn->getDouble();
1980 if(!xColumn->wasNull())
1981 {
1982 *pNumber = fVal;
1983 }
1984 }
1985 }
1986 catch (const uno::Exception&)
1987 {
1988 TOOLS_WARN_EXCEPTION("sw.mailmerge", "")do { css::uno::Any tools_warn_exception( DbgGetCaughtException
() ); do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sw.mailmerge")) { 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), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "1988" ": "), ::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
), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "1988" ": "), 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), (
"sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "1988" ": "), ::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
), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "1988" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false); } while (false)
;
1989 }
1990
1991 }
1992 break;
1993 }
1994
1995 return sRet;
1996}
1997
1998// checks if a desired data source table or query is open
1999bool SwDBManager::IsDataSourceOpen(const OUString& rDataSource,
2000 const OUString& rTableOrQuery, bool bMergeShell)
2001{
2002 if(m_pImpl->pMergeData)
2003 {
2004 return ((rDataSource == m_pImpl->pMergeData->sDataSource
2005 && rTableOrQuery == m_pImpl->pMergeData->sCommand)
2006 || (rDataSource.isEmpty() && rTableOrQuery.isEmpty()))
2007 && m_pImpl->pMergeData->xResultSet.is();
2008 }
2009 else if(!bMergeShell)
2010 {
2011 SwDBData aData;
2012 aData.sDataSource = rDataSource;
2013 aData.sCommand = rTableOrQuery;
2014 aData.nCommandType = -1;
2015 SwDSParam* pFound = FindDSData(aData, false);
2016 return (pFound && pFound->xResultSet.is());
2017 }
2018 return false;
2019}
2020
2021// read column data at a specified position
2022bool SwDBManager::GetColumnCnt(const OUString& rSourceName, const OUString& rTableName,
2023 const OUString& rColumnName, sal_uInt32 nAbsRecordId,
2024 LanguageType nLanguage,
2025 OUString& rResult, double* pNumber)
2026{
2027 bool bRet = false;
2028 SwDSParam* pFound = nullptr;
2029 //check if it's the merge data source
2030 if(m_pImpl->pMergeData &&
2031 rSourceName == m_pImpl->pMergeData->sDataSource &&
2032 rTableName == m_pImpl->pMergeData->sCommand)
2033 {
2034 pFound = m_pImpl->pMergeData.get();
2035 }
2036 else
2037 {
2038 SwDBData aData;
2039 aData.sDataSource = rSourceName;
2040 aData.sCommand = rTableName;
2041 aData.nCommandType = -1;
2042 pFound = FindDSData(aData, false);
2043 }
2044 if (!pFound)
2045 return false;
2046 //check validity of supplied record Id
2047 if(pFound->aSelection.hasElements())
2048 {
2049 //the destination has to be an element of the selection
2050 bool bFound = std::any_of(pFound->aSelection.begin(), pFound->aSelection.end(),
2051 [nAbsRecordId](const uno::Any& rSelection) {
2052 sal_Int32 nSelection = 0;
2053 rSelection >>= nSelection;
2054 return nSelection == static_cast<sal_Int32>(nAbsRecordId);
2055 });
2056 if(!bFound)
2057 return false;
2058 }
2059 if( pFound->HasValidRecord() )
2060 {
2061 sal_Int32 nOldRow = 0;
2062 try
2063 {
2064 nOldRow = pFound->xResultSet->getRow();
2065 }
2066 catch(const uno::Exception&)
2067 {
2068 return false;
2069 }
2070 //position to the desired index
2071 bool bMove = true;
2072 if ( nOldRow != static_cast<sal_Int32>(nAbsRecordId) )
2073 bMove = lcl_MoveAbsolute(pFound, nAbsRecordId);
2074 if(bMove)
2075 bRet = lcl_GetColumnCnt(pFound, rColumnName, nLanguage, rResult, pNumber);
2076 if ( nOldRow != static_cast<sal_Int32>(nAbsRecordId) )
2077 lcl_MoveAbsolute(pFound, nOldRow);
2078 }
2079 return bRet;
2080}
2081
2082// reads the column data at the current position
2083bool SwDBManager::GetMergeColumnCnt(const OUString& rColumnName, LanguageType nLanguage,
2084 OUString &rResult, double *pNumber)
2085{
2086 if( !IsValidMergeRecord() )
2087 {
2088 rResult.clear();
2089 return false;
2090 }
2091
2092 bool bRet = lcl_GetColumnCnt(m_pImpl->pMergeData.get(), rColumnName, nLanguage, rResult, pNumber);
2093 return bRet;
2094}
2095
2096bool SwDBManager::ToNextMergeRecord()
2097{
2098 assert( m_pImpl->pMergeData && m_pImpl->pMergeData->xResultSet.is() && "no data source in merge" )(static_cast <bool> (m_pImpl->pMergeData && m_pImpl
->pMergeData->xResultSet.is() && "no data source in merge"
) ? void (0) : __assert_fail ("m_pImpl->pMergeData && m_pImpl->pMergeData->xResultSet.is() && \"no data source in merge\""
, "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
, 2098, __extension__ __PRETTY_FUNCTION__))
;
2099 return lcl_ToNextRecord( m_pImpl->pMergeData.get() );
2100}
2101
2102bool SwDBManager::FillCalcWithMergeData( SvNumberFormatter *pDocFormatter,
2103 LanguageType nLanguage, SwCalc &rCalc )
2104{
2105 if( !IsValidMergeRecord() )
2106 return false;
2107
2108 uno::Reference< sdbcx::XColumnsSupplier > xColsSupp( m_pImpl->pMergeData->xResultSet, uno::UNO_QUERY );
2109 if( !xColsSupp.is() )
2110 return false;
2111
2112 {
2113 uno::Reference<container::XNameAccess> xCols = xColsSupp->getColumns();
2114 const uno::Sequence<OUString> aColNames = xCols->getElementNames();
2115 OUString aString;
2116
2117 // add the "record number" variable, as SwCalc::VarLook would.
2118 rCalc.VarChange( GetAppCharClass().lowercase(
2119 SwFieldType::GetTypeStr(SwFieldTypesEnum::DatabaseSetNumber) ), GetSelectedRecordId() );
2120
2121 for( const OUString& rColName : aColNames )
2122 {
2123 // get the column type
2124 sal_Int32 nColumnType = sdbc::DataType::SQLNULL;
2125 uno::Any aCol = xCols->getByName( rColName );
2126 uno::Reference<beans::XPropertySet> xColumnProps;
2127 aCol >>= xColumnProps;
2128 uno::Any aType = xColumnProps->getPropertyValue( "Type" );
2129 aType >>= nColumnType;
2130 double aNumber = DBL_MAX1.7976931348623157e+308;
2131
2132 lcl_GetColumnCnt( m_pImpl->pMergeData.get(), xColumnProps, nLanguage, aString, &aNumber );
2133
2134 sal_uInt32 nFormat = GetColumnFormat( m_pImpl->pMergeData->sDataSource,
2135 m_pImpl->pMergeData->sCommand,
2136 rColName, pDocFormatter, nLanguage );
2137 // aNumber is overwritten by SwDBField::FormatValue, so store initial status
2138 bool colIsNumber = aNumber != DBL_MAX1.7976931348623157e+308;
2139 bool bValidValue = SwDBField::FormatValue( pDocFormatter, aString, nFormat,
2140 aNumber, nColumnType );
2141 if( colIsNumber )
2142 {
2143 if( bValidValue )
2144 {
2145 SwSbxValue aValue;
2146 aValue.PutDouble( aNumber );
2147 aValue.SetDBvalue( true );
2148 SAL_INFO( "sw.ui", "'" << rColName << "': " << aNumber << " / " << aString )do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "sw.ui")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "'" << rColName << "': " << aNumber
<< " / " << aString) == 1) { ::sal_detail_log( (
::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.ui"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "2148" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "'" << rColName << "': "
<< aNumber << " / " << aString), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"'" << rColName << "': " << aNumber <<
" / " << aString; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("sw.ui"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "2148" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "'" << rColName << "': " << aNumber
<< " / " << aString) == 1) { ::sal_detail_log( (
::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.ui"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "2148" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "'" << rColName << "': "
<< aNumber << " / " << aString), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"'" << rColName << "': " << aNumber <<
" / " << aString; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("sw.ui"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "2148" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
2149 rCalc.VarChange( rColName, aValue );
2150 }
2151 }
2152 else
2153 {
2154 SwSbxValue aValue;
2155 aValue.PutString( aString );
2156 aValue.SetDBvalue( true );
2157 SAL_INFO( "sw.ui", "'" << rColName << "': " << aString )do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "sw.ui")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "'" << rColName << "': " << aString
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.ui"
), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "2157" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "'" << rColName << "': "
<< aString), 0); } else { ::std::ostringstream sal_detail_stream
; sal_detail_stream << "'" << rColName << "': "
<< aString; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("sw.ui"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "2157" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "'" << rColName << "': " << aString
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.ui"
), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "2157" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "'" << rColName << "': "
<< aString), 0); } else { ::std::ostringstream sal_detail_stream
; sal_detail_stream << "'" << rColName << "': "
<< aString; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("sw.ui"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "2157" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
2158 rCalc.VarChange( rColName, aValue );
2159 }
2160 }
2161 }
2162
2163 return true;
2164}
2165
2166void SwDBManager::ToNextRecord(
2167 const OUString& rDataSource, const OUString& rCommand)
2168{
2169 SwDSParam* pFound = nullptr;
2170 if(m_pImpl->pMergeData &&
2171 rDataSource == m_pImpl->pMergeData->sDataSource &&
2172 rCommand == m_pImpl->pMergeData->sCommand)
2173 {
2174 pFound = m_pImpl->pMergeData.get();
2175 }
2176 else
2177 {
2178 SwDBData aData;
2179 aData.sDataSource = rDataSource;
2180 aData.sCommand = rCommand;
2181 aData.nCommandType = -1;
2182 pFound = FindDSData(aData, false);
2183 }
2184 lcl_ToNextRecord( pFound );
2185}
2186
2187static bool lcl_ToNextRecord( SwDSParam* pParam, const SwDBNextRecord action )
2188{
2189 bool bRet = true;
2190
2191 assert( SwDBNextRecord::NEXT == action ||(static_cast <bool> (SwDBNextRecord::NEXT == action || (
SwDBNextRecord::FIRST == action && pParam)) ? void (0
) : __assert_fail ("SwDBNextRecord::NEXT == action || (SwDBNextRecord::FIRST == action && pParam)"
, "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
, 2192, __extension__ __PRETTY_FUNCTION__))
2192 (SwDBNextRecord::FIRST == action && pParam) )(static_cast <bool> (SwDBNextRecord::NEXT == action || (
SwDBNextRecord::FIRST == action && pParam)) ? void (0
) : __assert_fail ("SwDBNextRecord::NEXT == action || (SwDBNextRecord::FIRST == action && pParam)"
, "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
, 2192, __extension__ __PRETTY_FUNCTION__))
;
2193 if( nullptr == pParam )
2194 return false;
2195
2196 if( action == SwDBNextRecord::FIRST )
2197 {
2198 pParam->nSelectionIndex = 0;
2199 pParam->bEndOfDB = false;
2200 }
2201
2202 if( !pParam->HasValidRecord() )
2203 return false;
2204
2205 try
2206 {
2207 if( pParam->aSelection.hasElements() )
2208 {
2209 if( pParam->nSelectionIndex >= pParam->aSelection.getLength() )
2210 pParam->bEndOfDB = true;
2211 else
2212 {
2213 sal_Int32 nPos = 0;
2214 pParam->aSelection.getConstArray()[ pParam->nSelectionIndex ] >>= nPos;
2215 pParam->bEndOfDB = !pParam->xResultSet->absolute( nPos );
2216 }
2217 }
2218 else if( action == SwDBNextRecord::FIRST )
2219 {
2220 pParam->bEndOfDB = !pParam->xResultSet->first();
2221 }
2222 else
2223 {
2224 sal_Int32 nBefore = pParam->xResultSet->getRow();
2225 pParam->bEndOfDB = !pParam->xResultSet->next();
2226 if( !pParam->bEndOfDB && nBefore == pParam->xResultSet->getRow() )
2227 {
2228 // next returned true but it didn't move
2229 ::dbtools::throwFunctionSequenceException( pParam->xResultSet );
2230 }
2231 }
2232
2233 ++pParam->nSelectionIndex;
2234 bRet = !pParam->bEndOfDB;
2235 }
2236 catch( const uno::Exception & )
2237 {
2238 // we allow merging with empty databases, so don't warn on init
2239 TOOLS_WARN_EXCEPTION_IF(action == SwDBNextRecord::NEXT,do { css::uno::Any tools_warn_exception( DbgGetCaughtException
() ); do { if (true && (action == SwDBNextRecord::NEXT
)) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sw.mailmerge")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "exception in ToNextRecord()"
<< " " << exceptionToString(tools_warn_exception
)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "2240" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "exception in ToNextRecord()" <<
" " << exceptionToString(tools_warn_exception)), 0); }
else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "exception in ToNextRecord()" << " " <<
exceptionToString(tools_warn_exception); ::sal::detail::log(
(::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "2240" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "exception in ToNextRecord()" << " " <<
exceptionToString(tools_warn_exception)) == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "2240" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "exception in ToNextRecord()" <<
" " << exceptionToString(tools_warn_exception)), 0); }
else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "exception in ToNextRecord()" << " " <<
exceptionToString(tools_warn_exception); ::sal::detail::log(
(::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "2240" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false); } while (false)
2240 "sw.mailmerge", "exception in ToNextRecord()")do { css::uno::Any tools_warn_exception( DbgGetCaughtException
() ); do { if (true && (action == SwDBNextRecord::NEXT
)) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sw.mailmerge")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "exception in ToNextRecord()"
<< " " << exceptionToString(tools_warn_exception
)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "2240" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "exception in ToNextRecord()" <<
" " << exceptionToString(tools_warn_exception)), 0); }
else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "exception in ToNextRecord()" << " " <<
exceptionToString(tools_warn_exception); ::sal::detail::log(
(::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "2240" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "exception in ToNextRecord()" << " " <<
exceptionToString(tools_warn_exception)) == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "2240" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "exception in ToNextRecord()" <<
" " << exceptionToString(tools_warn_exception)), 0); }
else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "exception in ToNextRecord()" << " " <<
exceptionToString(tools_warn_exception); ::sal::detail::log(
(::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "2240" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false); } while (false)
;
2241 pParam->bEndOfDB = true;
2242 bRet = false;
2243 }
2244 return bRet;
2245}
2246
2247// synchronized labels contain a next record field at their end
2248// to assure that the next page can be created in mail merge
2249// the cursor position must be validated
2250bool SwDBManager::IsValidMergeRecord() const
2251{
2252 return( m_pImpl->pMergeData && m_pImpl->pMergeData->HasValidRecord() );
2253}
2254
2255sal_uInt32 SwDBManager::GetSelectedRecordId()
2256{
2257 sal_uInt32 nRet = 0;
2258 assert( m_pImpl->pMergeData &&(static_cast <bool> (m_pImpl->pMergeData && m_pImpl
->pMergeData->xResultSet.is() && "no data source in merge"
) ? void (0) : __assert_fail ("m_pImpl->pMergeData && m_pImpl->pMergeData->xResultSet.is() && \"no data source in merge\""
, "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
, 2259, __extension__ __PRETTY_FUNCTION__))
2259 m_pImpl->pMergeData->xResultSet.is() && "no data source in merge" )(static_cast <bool> (m_pImpl->pMergeData && m_pImpl
->pMergeData->xResultSet.is() && "no data source in merge"
) ? void (0) : __assert_fail ("m_pImpl->pMergeData && m_pImpl->pMergeData->xResultSet.is() && \"no data source in merge\""
, "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
, 2259, __extension__ __PRETTY_FUNCTION__))
;
2260 if(!m_pImpl->pMergeData || !m_pImpl->pMergeData->xResultSet.is())
2261 return 0;
2262 try
2263 {
2264 nRet = m_pImpl->pMergeData->xResultSet->getRow();
2265 }
2266 catch(const uno::Exception&)
2267 {
2268 }
2269 return nRet;
2270}
2271
2272bool SwDBManager::ToRecordId(sal_Int32 nSet)
2273{
2274 assert( m_pImpl->pMergeData &&(static_cast <bool> (m_pImpl->pMergeData && m_pImpl
->pMergeData->xResultSet.is() && "no data source in merge"
) ? void (0) : __assert_fail ("m_pImpl->pMergeData && m_pImpl->pMergeData->xResultSet.is() && \"no data source in merge\""
, "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
, 2275, __extension__ __PRETTY_FUNCTION__))
2275 m_pImpl->pMergeData->xResultSet.is() && "no data source in merge" )(static_cast <bool> (m_pImpl->pMergeData && m_pImpl
->pMergeData->xResultSet.is() && "no data source in merge"
) ? void (0) : __assert_fail ("m_pImpl->pMergeData && m_pImpl->pMergeData->xResultSet.is() && \"no data source in merge\""
, "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
, 2275, __extension__ __PRETTY_FUNCTION__))
;
2276 if(!m_pImpl->pMergeData || !m_pImpl->pMergeData->xResultSet.is()|| nSet < 0)
2277 return false;
2278 bool bRet = false;
2279 sal_Int32 nAbsPos = nSet;
2280 assert(nAbsPos >= 0)(static_cast <bool> (nAbsPos >= 0) ? void (0) : __assert_fail
("nAbsPos >= 0", "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
, 2280, __extension__ __PRETTY_FUNCTION__))
;
2281 bRet = lcl_MoveAbsolute(m_pImpl->pMergeData.get(), nAbsPos);
2282 m_pImpl->pMergeData->bEndOfDB = !bRet;
2283 return bRet;
2284}
2285
2286bool SwDBManager::OpenDataSource(const OUString& rDataSource, const OUString& rTableOrQuery)
2287{
2288 SwDBData aData;
2289 aData.sDataSource = rDataSource;
2290 aData.sCommand = rTableOrQuery;
2291 aData.nCommandType = -1;
2292
2293 SwDSParam* pFound = FindDSData(aData, true);
2294 if(pFound->xResultSet.is())
2295 return true;
2296 SwDSParam* pParam = FindDSConnection(rDataSource, false);
2297 if(pParam && pParam->xConnection.is())
2298 pFound->xConnection = pParam->xConnection;
2299 if(pFound->xConnection.is())
2300 {
2301 try
2302 {
2303 uno::Reference< sdbc::XDatabaseMetaData > xMetaData = pFound->xConnection->getMetaData();
2304 try
2305 {
2306 pFound->bScrollable = xMetaData
2307 ->supportsResultSetType(sal_Int32(sdbc::ResultSetType::SCROLL_INSENSITIVE));
2308 }
2309 catch(const uno::Exception&)
2310 {
2311 // DB driver may not be ODBC 3.0 compliant
2312 pFound->bScrollable = true;
2313 }
2314 pFound->xStatement = pFound->xConnection->createStatement();
2315 OUString aQuoteChar = xMetaData->getIdentifierQuoteString();
2316 OUString sStatement = "SELECT * FROM " + aQuoteChar + rTableOrQuery + aQuoteChar;
2317 pFound->xResultSet = pFound->xStatement->executeQuery( sStatement );
2318
2319 //after executeQuery the cursor must be positioned
2320 pFound->bEndOfDB = !pFound->xResultSet->next();
2321 ++pFound->nSelectionIndex;
2322 }
2323 catch (const uno::Exception&)
2324 {
2325 pFound->xResultSet = nullptr;
2326 pFound->xStatement = nullptr;
2327 pFound->xConnection = nullptr;
2328 }
2329 }
2330 return pFound->xResultSet.is();
2331}
2332
2333uno::Reference< sdbc::XConnection> const & SwDBManager::RegisterConnection(OUString const& rDataSource)
2334{
2335 SwDSParam* pFound = SwDBManager::FindDSConnection(rDataSource, true);
2336 uno::Reference< sdbc::XDataSource> xSource;
2337 if(!pFound->xConnection.is())
2338 {
2339 SwView* pView = (m_pDoc && m_pDoc->GetDocShell()) ? m_pDoc->GetDocShell()->GetView() : nullptr;
2340 pFound->xConnection = SwDBManager::GetConnection(rDataSource, xSource, pView);
2341 try
2342 {
2343 uno::Reference<lang::XComponent> xComponent(pFound->xConnection, uno::UNO_QUERY);
2344 if(xComponent.is())
2345 xComponent->addEventListener(m_pImpl->m_xDisposeListener.get());
2346 }
2347 catch(const uno::Exception&)
2348 {
2349 }
2350 }
2351 return pFound->xConnection;
2352}
2353
2354sal_uInt32 SwDBManager::GetSelectedRecordId(
2355 const OUString& rDataSource, const OUString& rTableOrQuery, sal_Int32 nCommandType)
2356{
2357 sal_uInt32 nRet = 0xffffffff;
2358 //check for merge data source first
2359 if(m_pImpl->pMergeData &&
2360 ((rDataSource == m_pImpl->pMergeData->sDataSource &&
2361 rTableOrQuery == m_pImpl->pMergeData->sCommand) ||
2362 (rDataSource.isEmpty() && rTableOrQuery.isEmpty())) &&
2363 (nCommandType == -1 || nCommandType == m_pImpl->pMergeData->nCommandType) &&
2364 m_pImpl->pMergeData->xResultSet.is())
2365 {
2366 nRet = GetSelectedRecordId();
2367 }
2368 else
2369 {
2370 SwDBData aData;
2371 aData.sDataSource = rDataSource;
2372 aData.sCommand = rTableOrQuery;
2373 aData.nCommandType = nCommandType;
2374 SwDSParam* pFound = FindDSData(aData, false);
2375 if(pFound && pFound->xResultSet.is())
2376 {
2377 try
2378 { //if a selection array is set the current row at the result set may not be set yet
2379 if(pFound->aSelection.hasElements())
2380 {
2381 sal_Int32 nSelIndex = pFound->nSelectionIndex;
2382 if(nSelIndex >= pFound->aSelection.getLength())
2383 nSelIndex = pFound->aSelection.getLength() -1;
2384 pFound->aSelection.getConstArray()[nSelIndex] >>= nRet;
2385
2386 }
2387 else
2388 nRet = pFound->xResultSet->getRow();
2389 }
2390 catch(const uno::Exception&)
2391 {
2392 }
2393 }
2394 }
2395 return nRet;
2396}
2397
2398// close all data sources - after fields were updated
2399void SwDBManager::CloseAll(bool bIncludingMerge)
2400{
2401 //the only thing done here is to reset the selection index
2402 //all connections stay open
2403 for (auto & pParam : m_DataSourceParams)
2404 {
2405 if (bIncludingMerge || pParam.get() != m_pImpl->pMergeData.get())
2406 {
2407 pParam->nSelectionIndex = 0;
2408 pParam->bEndOfDB = false;
2409 try
2410 {
2411 if(!m_bInMerge && pParam->xResultSet.is())
2412 pParam->xResultSet->first();
2413 }
2414 catch(const uno::Exception&)
2415 {}
2416 }
2417 }
2418}
2419
2420SwDSParam* SwDBManager::FindDSData(const SwDBData& rData, bool bCreate)
2421{
2422 //prefer merge data if available
2423 if(m_pImpl->pMergeData &&
2424 ((rData.sDataSource == m_pImpl->pMergeData->sDataSource &&
2425 rData.sCommand == m_pImpl->pMergeData->sCommand) ||
2426 (rData.sDataSource.isEmpty() && rData.sCommand.isEmpty())) &&
2427 (rData.nCommandType == -1 || rData.nCommandType == m_pImpl->pMergeData->nCommandType ||
2428 (bCreate && m_pImpl->pMergeData->nCommandType == -1)))
2429 {
2430 return m_pImpl->pMergeData.get();
2431 }
2432
2433 SwDSParam* pFound = nullptr;
2434 for (size_t nPos = m_DataSourceParams.size(); nPos; nPos--)
2435 {
2436 SwDSParam* pParam = m_DataSourceParams[nPos - 1].get();
2437 if(rData.sDataSource == pParam->sDataSource &&
2438 rData.sCommand == pParam->sCommand &&
2439 (rData.nCommandType == -1 || rData.nCommandType == pParam->nCommandType ||
2440 (bCreate && pParam->nCommandType == -1)))
2441 {
2442 // calls from the calculator may add a connection with an invalid commandtype
2443 //later added "real" data base connections have to re-use the already available
2444 //DSData and set the correct CommandType
2445 if(bCreate && pParam->nCommandType == -1)
2446 pParam->nCommandType = rData.nCommandType;
2447 pFound = pParam;
2448 break;
2449 }
2450 }
2451 if(bCreate && !pFound)
2452 {
2453 pFound = new SwDSParam(rData);
2454 m_DataSourceParams.push_back(std::unique_ptr<SwDSParam>(pFound));
2455 try
2456 {
2457 uno::Reference<lang::XComponent> xComponent(pFound->xConnection, uno::UNO_QUERY);
2458 if(xComponent.is())
2459 xComponent->addEventListener(m_pImpl->m_xDisposeListener.get());
2460 }
2461 catch(const uno::Exception&)
2462 {
2463 }
2464 }
2465 return pFound;
2466}
2467
2468SwDSParam* SwDBManager::FindDSConnection(const OUString& rDataSource, bool bCreate)
2469{
2470 //prefer merge data if available
2471 if(m_pImpl->pMergeData && rDataSource == m_pImpl->pMergeData->sDataSource )
2472 {
2473 SetAsUsed(rDataSource);
2474 return m_pImpl->pMergeData.get();
2475 }
2476 SwDSParam* pFound = nullptr;
2477 for (const auto & pParam : m_DataSourceParams)
2478 {
2479 if(rDataSource == pParam->sDataSource)
2480 {
2481 SetAsUsed(rDataSource);
2482 pFound = pParam.get();
2483 break;
2484 }
2485 }
2486 if(bCreate && !pFound)
2487 {
2488 SwDBData aData;
2489 aData.sDataSource = rDataSource;
2490 pFound = new SwDSParam(aData);
2491 SetAsUsed(rDataSource);
2492 m_DataSourceParams.push_back(std::unique_ptr<SwDSParam>(pFound));
2493 try
2494 {
2495 uno::Reference<lang::XComponent> xComponent(pFound->xConnection, uno::UNO_QUERY);
2496 if(xComponent.is())
2497 xComponent->addEventListener(m_pImpl->m_xDisposeListener.get());
2498 }
2499 catch(const uno::Exception&)
2500 {
2501 }
2502 }
2503 return pFound;
2504}
2505
2506const SwDBData& SwDBManager::GetAddressDBName()
2507{
2508 return SW_MOD()( static_cast<SwModule*>(SfxApplication::GetModule(SfxToolsModule
::Writer)))
->GetDBConfig()->GetAddressSource();
2509}
2510
2511uno::Sequence<OUString> SwDBManager::GetExistingDatabaseNames()
2512{
2513 uno::Reference<uno::XComponentContext> xContext( ::comphelper::getProcessComponentContext() );
2514 uno::Reference<sdb::XDatabaseContext> xDBContext = sdb::DatabaseContext::create(xContext);
2515 return xDBContext->getElementNames();
2516}
2517
2518namespace sw
2519{
2520DBConnURIType GetDBunoType(const INetURLObject &rURL)
2521{
2522 OUString sExt(rURL.GetFileExtension());
2523 DBConnURIType type = DBConnURIType::UNKNOWN;
2524
2525 if (sExt == "odb")
2526 {
2527 type = DBConnURIType::ODB;
2528 }
2529 else if (sExt.equalsIgnoreAsciiCase("sxc")
2530 || sExt.equalsIgnoreAsciiCase("ods")
2531 || sExt.equalsIgnoreAsciiCase("xls")
2532 || sExt.equalsIgnoreAsciiCase("xlsx"))
2533 {
2534 type = DBConnURIType::CALC;
2535 }
2536 else if (sExt.equalsIgnoreAsciiCase("sxw") || sExt.equalsIgnoreAsciiCase("odt") || sExt.equalsIgnoreAsciiCase("doc") || sExt.equalsIgnoreAsciiCase("docx"))
2537 {
2538 type = DBConnURIType::WRITER;
2539 }
2540 else if (sExt.equalsIgnoreAsciiCase("dbf"))
2541 {
2542 type = DBConnURIType::DBASE;
2543 }
2544 else if (sExt.equalsIgnoreAsciiCase("csv") || sExt.equalsIgnoreAsciiCase("txt"))
2545 {
2546 type = DBConnURIType::FLAT;
2547 }
2548#ifdef _WIN32
2549 else if (sExt.equalsIgnoreAsciiCase("mdb") || sExt.equalsIgnoreAsciiCase("mde"))
2550 {
2551 type = DBConnURIType::MSJET;
2552 }
2553 else if (sExt.equalsIgnoreAsciiCase("accdb") || sExt.equalsIgnoreAsciiCase("accde"))
2554 {
2555 type = DBConnURIType::MSACE;
2556 }
2557#endif
2558 return type;
2559}
2560}
2561
2562namespace
2563{
2564uno::Any GetDBunoURI(const INetURLObject &rURL, DBConnURIType& rType)
2565{
2566 uno::Any aURLAny;
2567
2568 if (rType == DBConnURIType::UNKNOWN)
2569 rType = GetDBunoType(rURL);
2570
2571 switch (rType) {
2572 case DBConnURIType::UNKNOWN:
2573 case DBConnURIType::ODB:
2574 break;
2575 case DBConnURIType::CALC:
2576 {
2577 OUString sDBURL = "sdbc:calc:" +
2578 rURL.GetMainURL(INetURLObject::DecodeMechanism::NONE);
2579 aURLAny <<= sDBURL;
2580 }
2581 break;
2582 case DBConnURIType::WRITER:
2583 {
2584 OUString sDBURL = "sdbc:writer:" +
2585 rURL.GetMainURL(INetURLObject::DecodeMechanism::NONE);
2586 aURLAny <<= sDBURL;
2587 }
2588 break;
2589 case DBConnURIType::DBASE:
2590 {
2591 INetURLObject aUrlTmp(rURL);
2592 aUrlTmp.removeSegment();
2593 aUrlTmp.removeFinalSlash();
2594 OUString sDBURL = "sdbc:dbase:" +
2595 aUrlTmp.GetMainURL(INetURLObject::DecodeMechanism::NONE);
2596 aURLAny <<= sDBURL;
2597 }
2598 break;
2599 case DBConnURIType::FLAT:
2600 {
2601 INetURLObject aUrlTmp(rURL);
2602 aUrlTmp.removeSegment();
2603 aUrlTmp.removeFinalSlash();
2604 OUString sDBURL = "sdbc:flat:" +
2605 //only the 'path' has to be added
2606 aUrlTmp.GetMainURL(INetURLObject::DecodeMechanism::NONE);
2607 aURLAny <<= sDBURL;
2608 }
2609 break;
2610 case DBConnURIType::MSJET:
2611#ifdef _WIN32
2612 {
2613 OUString sDBURL("sdbc:ado:access:PROVIDER=Microsoft.Jet.OLEDB.4.0;DATA SOURCE=" + rURL.PathToFileName());
2614 aURLAny <<= sDBURL;
2615 }
2616#endif
2617 break;
2618 case DBConnURIType::MSACE:
2619#ifdef _WIN32
2620 {
2621 OUString sDBURL("sdbc:ado:PROVIDER=Microsoft.ACE.OLEDB.12.0;DATA SOURCE=" + rURL.PathToFileName());
2622 aURLAny <<= sDBURL;
2623 }
2624#endif
2625 break;
2626 }
2627 return aURLAny;
2628}
2629
2630/// Returns the URL of this SwDoc.
2631OUString getOwnURL(SfxObjectShell const * pDocShell)
2632{
2633 OUString aRet;
2634
2635 if (!pDocShell)
2636 return aRet;
2637
2638 const INetURLObject& rURLObject = pDocShell->GetMedium()->GetURLObject();
2639 aRet = rURLObject.GetMainURL(INetURLObject::DecodeMechanism::NONE);
2640 return aRet;
2641}
2642
2643/**
2644Loads a data source from file and registers it.
2645
2646In case of success it returns the registered name, otherwise an empty string.
2647Optionally add a prefix to the registered DB name.
2648*/
2649OUString LoadAndRegisterDataSource_Impl(DBConnURIType type, const uno::Reference< beans::XPropertySet > *pSettings,
2650 const INetURLObject &rURL, const OUString *pDestDir, SfxObjectShell* pDocShell)
2651{
2652 OUString sExt(rURL.GetFileExtension());
2653 uno::Any aTableFilterAny;
2654 uno::Any aSuppressVersionsAny;
2655 uno::Any aInfoAny;
2656 bool bStore = true;
2657 OUString sFind;
2658 uno::Sequence<OUString> aFilters(1);
2659
2660 uno::Any aURLAny = GetDBunoURI(rURL, type);
2661 switch (type) {
2662 case DBConnURIType::UNKNOWN:
2663 case DBConnURIType::CALC:
2664 case DBConnURIType::WRITER:
2665 break;
2666 case DBConnURIType::ODB:
2667 bStore = false;
2668 break;
2669 case DBConnURIType::FLAT:
2670 case DBConnURIType::DBASE:
2671 //set the filter to the file name without extension
2672 aFilters[0] = rURL.getBase(INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::WithCharset);
2673 aTableFilterAny <<= aFilters;
2674 break;
2675 case DBConnURIType::MSJET:
2676 case DBConnURIType::MSACE:
2677 aSuppressVersionsAny <<= true;
2678 break;
2679 }
2680
2681 try
2682 {
2683 uno::Reference<uno::XComponentContext> xContext(::comphelper::getProcessComponentContext());
2684 uno::Reference<sdb::XDatabaseContext> xDBContext = sdb::DatabaseContext::create(xContext);
2685
2686 OUString sNewName = rURL.getName(
2687 INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::Unambiguous);
2688 sal_Int32 nExtLen = sExt.getLength();
2689 sNewName = sNewName.replaceAt(sNewName.getLength() - nExtLen - 1, nExtLen + 1, "");
2690
2691 //find a unique name if sNewName already exists
2692 sFind = sNewName;
2693 sal_Int32 nIndex = 0;
2694 while (xDBContext->hasByName(sFind))
2695 sFind = sNewName + OUString::number(++nIndex);
2696
2697 uno::Reference<uno::XInterface> xNewInstance;
2698 if (!bStore)
2699 {
2700 //odb-file
2701 uno::Any aDataSource = xDBContext->getByName(rURL.GetMainURL(INetURLObject::DecodeMechanism::NONE));
2702 aDataSource >>= xNewInstance;
2703 }
2704 else
2705 {
2706 xNewInstance = xDBContext->createInstance();
2707 uno::Reference<beans::XPropertySet> xDataProperties(xNewInstance, uno::UNO_QUERY);
2708
2709 if (aURLAny.hasValue())
2710 xDataProperties->setPropertyValue("URL", aURLAny);
2711 if (aTableFilterAny.hasValue())
2712 xDataProperties->setPropertyValue("TableFilter", aTableFilterAny);
2713 if (aSuppressVersionsAny.hasValue())
2714 xDataProperties->setPropertyValue("SuppressVersionColumns", aSuppressVersionsAny);
2715 if (aInfoAny.hasValue())
2716 xDataProperties->setPropertyValue("Info", aInfoAny);
2717
2718 if (DBConnURIType::FLAT == type && pSettings)
2719 {
2720 uno::Any aSettings = xDataProperties->getPropertyValue("Settings");
2721 uno::Reference < beans::XPropertySet > xDSSettings;
2722 aSettings >>= xDSSettings;
2723 ::comphelper::copyProperties(*pSettings, xDSSettings);
2724 xDSSettings->setPropertyValue("Extension", uno::makeAny(sExt));
2725 }
2726
2727 uno::Reference<sdb::XDocumentDataSource> xDS(xNewInstance, uno::UNO_QUERY_THROW);
2728 uno::Reference<frame::XStorable> xStore(xDS->getDatabaseDocument(), uno::UNO_QUERY_THROW);
2729 OUString aOwnURL = getOwnURL(pDocShell);
2730 if (aOwnURL.isEmpty())
2731 {
2732 // Cannot embed, as embedded data source would need the URL of the parent document.
2733 OUString const sOutputExt = ".odb";
2734 OUString sHomePath(SvtPathOptions().GetWorkPath());
2735 utl::TempFile aTempFile(sNewName, true, &sOutputExt, pDestDir ? pDestDir : &sHomePath);
2736 const OUString& sTmpName = aTempFile.GetURL();
2737 xStore->storeAsURL(sTmpName, uno::Sequence<beans::PropertyValue>());
2738 }
2739 else
2740 {
2741 // Embed.
2742 OUString aStreamRelPath = "EmbeddedDatabase";
2743 uno::Reference<embed::XStorage> xStorage = pDocShell->GetStorage();
2744
2745 // Refer to the sub-storage name in the document settings, so
2746 // we can load it again next time the file is imported.
2747 uno::Reference<lang::XMultiServiceFactory> xFactory(pDocShell->GetModel(), uno::UNO_QUERY);
2748 uno::Reference<beans::XPropertySet> xPropertySet(xFactory->createInstance("com.sun.star.document.Settings"), uno::UNO_QUERY);
2749 xPropertySet->setPropertyValue("EmbeddedDatabaseName", uno::makeAny(aStreamRelPath));
2750
2751 // Store it only after setting the above property, so that only one data source gets registered.
2752 SwDBManager::StoreEmbeddedDataSource(xStore, xStorage, aStreamRelPath, aOwnURL);
2753 }
2754 }
2755 xDBContext->registerObject(sFind, xNewInstance);
2756 }
2757 catch (const uno::Exception&)
2758 {
2759 sFind.clear();
2760 }
2761 return sFind;
2762}
2763
2764// Construct vnd.sun.star.pkg:// URL
2765OUString ConstructVndSunStarPkgUrl(const OUString& rMainURL, const OUString& rStreamRelPath)
2766{
2767 auto xContext(comphelper::getProcessComponentContext());
2768 auto xUri = css::uri::UriReferenceFactory::create(xContext)->parse(rMainURL);
2769 assert(xUri.is())(static_cast <bool> (xUri.is()) ? void (0) : __assert_fail
("xUri.is()", "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
, 2769, __extension__ __PRETTY_FUNCTION__))
;
2770 xUri = css::uri::VndSunStarPkgUrlReferenceFactory::create(xContext)
2771 ->createVndSunStarPkgUrlReference(xUri);
2772 assert(xUri.is())(static_cast <bool> (xUri.is()) ? void (0) : __assert_fail
("xUri.is()", "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
, 2772, __extension__ __PRETTY_FUNCTION__))
;
2773 return xUri->getUriReference() + "/"
2774 + INetURLObject::encode(
2775 rStreamRelPath, INetURLObject::PART_FPATH,
2776 INetURLObject::EncodeMechanism::All);
2777}
2778}
2779
2780OUString SwDBManager::LoadAndRegisterDataSource(weld::Window* pParent, SwDocShell* pDocShell)
2781{
2782 sfx2::FileDialogHelper aDlgHelper(ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE, FileDialogFlags::NONE, pParent);
2783 uno::Reference < ui::dialogs::XFilePicker3 > xFP = aDlgHelper.GetFilePicker();
2784
2785 OUString sHomePath(SvtPathOptions().GetWorkPath());
2786 aDlgHelper.SetDisplayDirectory( sHomePath );
2787
2788 OUString sFilterAll(SwResId(STR_FILTER_ALLreinterpret_cast<char const *>("STR_FILTER_ALL" "\004" u8"All files"
)
));
2789 OUString sFilterAllData(SwResId(STR_FILTER_ALL_DATAreinterpret_cast<char const *>("STR_FILTER_ALL_DATA" "\004"
u8"Address lists(*.*)")
));
2790 OUString sFilterSXB(SwResId(STR_FILTER_SXBreinterpret_cast<char const *>("STR_FILTER_SXB" "\004" u8"%PRODUCTNAME Base (*.odb)"
)
));
2791 OUString sFilterSXC(SwResId(STR_FILTER_SXCreinterpret_cast<char const *>("STR_FILTER_SXC" "\004" u8"%PRODUCTNAME Calc (*.ods;*.sxc)"
)
));
2792 OUString sFilterSXW(SwResId(STR_FILTER_SXWreinterpret_cast<char const *>("STR_FILTER_SXW" "\004" u8"%PRODUCTNAME Writer (*.odt;*.sxw)"
)
));
2793 OUString sFilterDBF(SwResId(STR_FILTER_DBFreinterpret_cast<char const *>("STR_FILTER_DBF" "\004" u8"dBase (*.dbf)"
)
));
2794 OUString sFilterXLS(SwResId(STR_FILTER_XLSreinterpret_cast<char const *>("STR_FILTER_XLS" "\004" u8"Microsoft Excel (*.xls;*.xlsx)"
)
));
2795 OUString sFilterDOC(SwResId(STR_FILTER_DOCreinterpret_cast<char const *>("STR_FILTER_DOC" "\004" u8"Microsoft Word (*.doc;*.docx)"
)
));
2796 OUString sFilterTXT(SwResId(STR_FILTER_TXTreinterpret_cast<char const *>("STR_FILTER_TXT" "\004" u8"Plain text (*.txt)"
)
));
2797 OUString sFilterCSV(SwResId(STR_FILTER_CSVreinterpret_cast<char const *>("STR_FILTER_CSV" "\004" u8"Text Comma Separated (*.csv)"
)
));
2798#ifdef _WIN32
2799 OUString sFilterMDB(SwResId(STR_FILTER_MDBreinterpret_cast<char const *>("STR_FILTER_MDB" "\004" u8"Microsoft Access (*.mdb;*.mde)"
)
));
2800 OUString sFilterACCDB(SwResId(STR_FILTER_ACCDBreinterpret_cast<char const *>("STR_FILTER_ACCDB" "\004"
u8"Microsoft Access 2007 (*.accdb,*.accde)")
));
2801#endif
2802 xFP->appendFilter( sFilterAll, "*" );
2803 xFP->appendFilter( sFilterAllData, "*.ods;*.sxc;*.odt;*.sxw;*.dbf;*.xls;*.xlsx;*.doc;*.docx;*.txt;*.csv");
2804
2805 xFP->appendFilter( sFilterSXB, "*.odb" );
2806 xFP->appendFilter( sFilterSXC, "*.ods;*.sxc" );
2807 xFP->appendFilter( sFilterSXW, "*.odt;*.sxw" );
2808 xFP->appendFilter( sFilterDBF, "*.dbf" );
2809 xFP->appendFilter( sFilterXLS, "*.xls;*.xlsx" );
2810 xFP->appendFilter( sFilterDOC, "*.doc;*.docx" );
2811 xFP->appendFilter( sFilterTXT, "*.txt" );
2812 xFP->appendFilter( sFilterCSV, "*.csv" );
2813#ifdef _WIN32
2814 xFP->appendFilter(sFilterMDB, "*.mdb;*.mde");
2815 xFP->appendFilter(sFilterACCDB, "*.accdb;*.accde");
2816#endif
2817
2818 xFP->setCurrentFilter( sFilterAll ) ;
2819 OUString sFind;
2820 if( ERRCODE_NONEErrCode(0) == aDlgHelper.Execute() )
2821 {
2822 uno::Reference< beans::XPropertySet > aSettings;
2823 const INetURLObject aURL( xFP->getSelectedFiles().getConstArray()[0] );
2824 const DBConnURIType type = GetDBunoType( aURL );
2825
2826 if( DBConnURIType::FLAT == type )
2827 {
2828 uno::Reference<uno::XComponentContext> xContext( ::comphelper::getProcessComponentContext() );
2829 uno::Reference < sdb::XTextConnectionSettings > xSettingsDlg = sdb::TextConnectionSettings::create(xContext);
2830 if( xSettingsDlg->execute() )
2831 aSettings.set( uno::Reference < beans::XPropertySet >( xSettingsDlg, uno::UNO_QUERY_THROW ) );
2832 }
2833 sFind = LoadAndRegisterDataSource_Impl( type, DBConnURIType::FLAT == type ? &aSettings : nullptr, aURL, nullptr, pDocShell );
2834
2835 m_aUncommittedRegistrations.push_back(std::pair<SwDocShell*, OUString>(pDocShell, sFind));
2836 }
2837 return sFind;
2838}
2839
2840void SwDBManager::StoreEmbeddedDataSource(const uno::Reference<frame::XStorable>& xStorable,
2841 const uno::Reference<embed::XStorage>& xStorage,
2842 const OUString& rStreamRelPath,
2843 const OUString& rOwnURL, bool bCopyTo)
2844{
2845 // Construct vnd.sun.star.pkg:// URL for later loading, and TargetStorage/StreamRelPath for storing.
2846 OUString const sTmpName = ConstructVndSunStarPkgUrl(rOwnURL, rStreamRelPath);
2847
2848 uno::Sequence<beans::PropertyValue> aSequence = comphelper::InitPropertySequence(
2849 {
2850 {"TargetStorage", uno::makeAny(xStorage)},
2851 {"StreamRelPath", uno::makeAny(rStreamRelPath)},
2852 {"BaseURI", uno::makeAny(rOwnURL)}
2853 });
2854 if (bCopyTo)
2855 xStorable->storeToURL(sTmpName, aSequence);
2856 else
2857 xStorable->storeAsURL(sTmpName, aSequence);
2858}
2859
2860OUString SwDBManager::LoadAndRegisterDataSource(const OUString &rURI, const OUString *pDestDir)
2861{
2862 return LoadAndRegisterDataSource_Impl( DBConnURIType::UNKNOWN, nullptr, INetURLObject(rURI), pDestDir, nullptr );
2863}
2864
2865namespace
2866{
2867 // tdf#117824 switch the embedded database away from using its current storage and point it to temporary storage
2868 // which allows the original storage to be deleted
2869 void switchEmbeddedDatabaseStorage(const uno::Reference<sdb::XDatabaseContext>& rDatabaseContext, const OUString& rName)
2870 {
2871 uno::Reference<sdb::XDocumentDataSource> xDS(rDatabaseContext->getByName(rName), uno::UNO_QUERY);
2872 if (!xDS)
2873 return;
2874 uno::Reference<document::XStorageBasedDocument> xStorageDoc(xDS->getDatabaseDocument(), uno::UNO_QUERY);
2875 if (!xStorageDoc)
2876 return;
2877 xStorageDoc->switchToStorage(comphelper::OStorageHelper::GetTemporaryStorage());
2878 }
2879}
2880
2881void SwDBManager::RevokeDataSource(const OUString& rName)
2882{
2883 uno::Reference<sdb::XDatabaseContext> xDatabaseContext = sdb::DatabaseContext::create(comphelper::getProcessComponentContext());
2884 if (xDatabaseContext->hasByName(rName))
2885 {
2886 switchEmbeddedDatabaseStorage(xDatabaseContext, rName);
2887 xDatabaseContext->revokeObject(rName);
2888 }
2889}
2890
2891void SwDBManager::LoadAndRegisterEmbeddedDataSource(const SwDBData& rData, const SwDocShell& rDocShell)
2892{
2893 uno::Reference<sdb::XDatabaseContext> xDatabaseContext = sdb::DatabaseContext::create(comphelper::getProcessComponentContext());
2894
2895 OUString sDataSource = rData.sDataSource;
2896
2897 // Fallback, just in case the document would contain an embedded data source, but no DB fields.
2898 if (sDataSource.isEmpty())
2899 sDataSource = "EmbeddedDatabase";
2900
2901 SwDBManager::RevokeDataSource( sDataSource );
2902
2903 // Encode the stream name and the real path into a single URL.
2904 const INetURLObject& rURLObject = rDocShell.GetMedium()->GetURLObject();
2905 OUString const aURL = ConstructVndSunStarPkgUrl(
2906 rURLObject.GetMainURL(INetURLObject::DecodeMechanism::NONE),
2907 m_sEmbeddedName);
2908
2909 uno::Reference<uno::XInterface> xDataSource(xDatabaseContext->getByName(aURL), uno::UNO_QUERY);
2910 xDatabaseContext->registerObject( sDataSource, xDataSource );
2911
2912 // temp file - don't remember connection
2913 if (rData.sDataSource.isEmpty())
2914 m_aUncommittedRegistrations.push_back(std::pair<SwDocShell*, OUString>(nullptr, sDataSource));
2915}
2916
2917void SwDBManager::ExecuteFormLetter( SwWrtShell& rSh,
2918 const uno::Sequence<beans::PropertyValue>& rProperties)
2919{
2920 //prevent second call
2921 if(m_pImpl->pMergeDialog)
2922 return ;
2923 OUString sDataSource, sDataTableOrQuery;
2924 uno::Sequence<uno::Any> aSelection;
2925
2926 sal_Int32 nCmdType = sdb::CommandType::TABLE;
2927 uno::Reference< sdbc::XConnection> xConnection;
2928
2929 svx::ODataAccessDescriptor aDescriptor(rProperties);
2930 sDataSource = aDescriptor.getDataSource();
2931 OSL_VERIFY(aDescriptor[svx::DataAccessDescriptorProperty::Command] >>= sDataTableOrQuery)do { if (!(aDescriptor[svx::DataAccessDescriptorProperty::Command
] >>= sDataTableOrQuery)) do { if (true && (!(0
))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "2931" ": "), "OSL_ASSERT: %s", "0"); } } while (false);
} while (0)
;
2932 OSL_VERIFY(aDescriptor[svx::DataAccessDescriptorProperty::CommandType] >>= nCmdType)do { if (!(aDescriptor[svx::DataAccessDescriptorProperty::CommandType
] >>= nCmdType)) do { if (true && (!(0))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "2932" ": "), "OSL_ASSERT: %s", "0"); } } while (false);
} while (0)
;
2933
2934 if ( aDescriptor.has(svx::DataAccessDescriptorProperty::Selection) )
2935 aDescriptor[svx::DataAccessDescriptorProperty::Selection] >>= aSelection;
2936 if ( aDescriptor.has(svx::DataAccessDescriptorProperty::Connection) )
2937 aDescriptor[svx::DataAccessDescriptorProperty::Connection] >>= xConnection;
2938
2939 if(sDataSource.isEmpty() || sDataTableOrQuery.isEmpty())
2940 {
2941 OSL_FAIL("PropertyValues missing or unset")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "2941" ": "), "%s", "PropertyValues missing or unset"); }
} while (false)
;
2942 return;
2943 }
2944
2945 //always create a connection for the dialog and dispose it after the dialog has been closed
2946 SwDSParam* pFound = nullptr;
2947 if(!xConnection.is())
2948 {
2949 xConnection = SwDBManager::RegisterConnection(sDataSource);
2950 pFound = FindDSConnection(sDataSource, true);
2951 }
2952 SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create();
2953 m_pImpl->pMergeDialog = pFact->CreateMailMergeDlg(rSh.GetView().GetViewFrame()->GetWindow().GetFrameWeld(), rSh,
2954 sDataSource,
2955 sDataTableOrQuery,
2956 nCmdType,
2957 xConnection);
2958 if(m_pImpl->pMergeDialog->Execute() == RET_OK)
2959 {
2960 aDescriptor[svx::DataAccessDescriptorProperty::Selection] <<= m_pImpl->pMergeDialog->GetSelection();
2961
2962 uno::Reference<sdbc::XResultSet> xResSet = m_pImpl->pMergeDialog->GetResultSet();
2963 if(xResSet.is())
2964 aDescriptor[svx::DataAccessDescriptorProperty::Cursor] <<= xResSet;
2965
2966 // SfxObjectShellRef is ok, since there should be no control over the document lifetime here
2967 SfxObjectShellRef xDocShell = rSh.GetView().GetViewFrame()->GetObjectShell();
2968
2969 lcl_emitEvent(SfxEventHintId::SwMailMerge, STR_SW_EVENT_MAIL_MERGE1, xDocShell.get());
2970
2971 // prepare mail merge descriptor
2972 SwMergeDescriptor aMergeDesc( m_pImpl->pMergeDialog->GetMergeType(), rSh, aDescriptor );
2973 aMergeDesc.sSaveToFilter = m_pImpl->pMergeDialog->GetSaveFilter();
2974 aMergeDesc.bCreateSingleFile = m_pImpl->pMergeDialog->IsSaveSingleDoc();
2975 aMergeDesc.bPrefixIsFilename = aMergeDesc.bCreateSingleFile;
2976 aMergeDesc.sPrefix = m_pImpl->pMergeDialog->GetTargetURL();
2977
2978 if(!aMergeDesc.bCreateSingleFile)
2979 {
2980 if(m_pImpl->pMergeDialog->IsGenerateFromDataBase())
2981 aMergeDesc.sDBcolumn = m_pImpl->pMergeDialog->GetColumnName();
2982
2983 if(m_pImpl->pMergeDialog->IsFileEncryptedFromDataBase())
2984 aMergeDesc.sDBPasswordColumn = m_pImpl->pMergeDialog->GetPasswordColumnName();
2985 }
2986
2987 Merge( aMergeDesc );
2988
2989 lcl_emitEvent(SfxEventHintId::SwMailMergeEnd, STR_SW_EVENT_MAIL_MERGE_END2, xDocShell.get());
2990
2991 // reset the cursor inside
2992 xResSet = nullptr;
2993 aDescriptor[svx::DataAccessDescriptorProperty::Cursor] <<= xResSet;
2994 }
2995 if(pFound)
2996 {
2997 for (const auto & pParam : m_DataSourceParams)
2998 {
2999 if (pParam.get() == pFound)
3000 {
3001 try
3002 {
3003 uno::Reference<lang::XComponent> xComp(pParam->xConnection, uno::UNO_QUERY);
3004 if(xComp.is())
3005 xComp->dispose();
3006 }
3007 catch(const uno::RuntimeException&)
3008 {
3009 //may be disposed already since multiple entries may have used the same connection
3010 }
3011 break;
3012 }
3013 //pFound doesn't need to be removed/deleted -
3014 //this has been done by the SwConnectionDisposedListener_Impl already
3015 }
3016 }
3017 m_pImpl->pMergeDialog.disposeAndClear();
3018}
3019
3020void SwDBManager::InsertText(SwWrtShell& rSh,
3021 const uno::Sequence< beans::PropertyValue>& rProperties)
3022{
3023 OUString sDataSource, sDataTableOrQuery;
3024 uno::Reference<sdbc::XResultSet> xResSet;
3025 uno::Sequence<uno::Any> aSelection;
3026 sal_Int16 nCmdType = sdb::CommandType::TABLE;
3027 uno::Reference< sdbc::XConnection> xConnection;
3028 for(const beans::PropertyValue& rValue : rProperties)
3029 {
3030 if ( rValue.Name == "DataSourceName" )
3031 rValue.Value >>= sDataSource;
3032 else if ( rValue.Name == "Command" )
3033 rValue.Value >>= sDataTableOrQuery;
3034 else if ( rValue.Name == "Cursor" )
3035 rValue.Value >>= xResSet;
3036 else if ( rValue.Name == "Selection" )
3037 rValue.Value >>= aSelection;
3038 else if ( rValue.Name == "CommandType" )
3039 rValue.Value >>= nCmdType;
3040 else if ( rValue.Name == "ActiveConnection" )
3041 rValue.Value >>= xConnection;
3042 }
3043 if(sDataSource.isEmpty() || sDataTableOrQuery.isEmpty() || !xResSet.is())
3044 {
3045 OSL_FAIL("PropertyValues missing or unset")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "3045" ": "), "%s", "PropertyValues missing or unset"); }
} while (false)
;
3046 return;
3047 }
3048 uno::Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
3049 uno::Reference<sdbc::XDataSource> xSource;
3050 uno::Reference<container::XChild> xChild(xConnection, uno::UNO_QUERY);
3051 if(xChild.is())
3052 xSource.set(xChild->getParent(), uno::UNO_QUERY);
3053 if(!xSource.is())
3054 xSource = dbtools::getDataSource(sDataSource, xContext);
3055 uno::Reference< sdbcx::XColumnsSupplier > xColSupp( xResSet, uno::UNO_QUERY );
3056 SwDBData aDBData;
3057 aDBData.sDataSource = sDataSource;
3058 aDBData.sCommand = sDataTableOrQuery;
3059 aDBData.nCommandType = nCmdType;
3060
3061 SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create();
3062 ScopedVclPtr<AbstractSwInsertDBColAutoPilot> pDlg(pFact->CreateSwInsertDBColAutoPilot( rSh.GetView(),
3063 xSource,
3064 xColSupp,
3065 aDBData ));
3066 if( RET_OK != pDlg->Execute() )
3067 return;
3068
3069 OUString sDummy;
3070 if(!xConnection.is())
3071 xConnection = xSource->getConnection(sDummy, sDummy);
3072 try
3073 {
3074 pDlg->DataToDoc( aSelection , xSource, xConnection, xResSet);
3075 }
3076 catch (const uno::Exception&)
3077 {
3078 TOOLS_WARN_EXCEPTION("sw.mailmerge", "")do { css::uno::Any tools_warn_exception( DbgGetCaughtException
() ); do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sw.mailmerge")) { 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), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "3078" ": "), ::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
), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "3078" ": "), 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), (
"sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "3078" ": "), ::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
), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "3078" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false); } while (false)
;
3079 }
3080}
3081
3082uno::Reference<sdbc::XDataSource> SwDBManager::getDataSourceAsParent(const uno::Reference< sdbc::XConnection>& _xConnection,const OUString& _sDataSourceName)
3083{
3084 uno::Reference<sdbc::XDataSource> xSource;
3085 try
3086 {
3087 uno::Reference<container::XChild> xChild(_xConnection, uno::UNO_QUERY);
3088 if ( xChild.is() )
3089 xSource.set(xChild->getParent(), uno::UNO_QUERY);
3090 if ( !xSource.is() )
3091 xSource = dbtools::getDataSource(_sDataSourceName, ::comphelper::getProcessComponentContext());
3092 }
3093 catch (const uno::Exception&)
3094 {
3095 TOOLS_WARN_EXCEPTION("sw.mailmerge", "getDataSourceAsParent()")do { css::uno::Any tools_warn_exception( DbgGetCaughtException
() ); do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sw.mailmerge")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "getDataSourceAsParent()"
<< " " << exceptionToString(tools_warn_exception
)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "3095" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "getDataSourceAsParent()" << " "
<< exceptionToString(tools_warn_exception)), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"getDataSourceAsParent()" << " " << exceptionToString
(tools_warn_exception); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "3095" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "getDataSourceAsParent()" << " " << exceptionToString
(tools_warn_exception)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "3095" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "getDataSourceAsParent()" << " "
<< exceptionToString(tools_warn_exception)), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"getDataSourceAsParent()" << " " << exceptionToString
(tools_warn_exception); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "3095" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false); } while (false)
;
3096 }
3097 return xSource;
3098}
3099
3100uno::Reference<sdbc::XResultSet> SwDBManager::createCursor(const OUString& _sDataSourceName,
3101 const OUString& _sCommand,
3102 sal_Int32 _nCommandType,
3103 const uno::Reference<sdbc::XConnection>& _xConnection,
3104 const SwView* pView)
3105{
3106 uno::Reference<sdbc::XResultSet> xResultSet;
3107 try
3108 {
3109 uno::Reference< lang::XMultiServiceFactory > xMgr( ::comphelper::getProcessServiceFactory() );
3110 if( xMgr.is() )
3111 {
3112 uno::Reference<uno::XInterface> xInstance = xMgr->createInstance("com.sun.star.sdb.RowSet");
3113 uno::Reference<beans::XPropertySet> xRowSetPropSet(xInstance, uno::UNO_QUERY);
3114 if(xRowSetPropSet.is())
3115 {
3116 xRowSetPropSet->setPropertyValue("DataSourceName", uno::makeAny(_sDataSourceName));
3117 xRowSetPropSet->setPropertyValue("ActiveConnection", uno::makeAny(_xConnection));
3118 xRowSetPropSet->setPropertyValue("Command", uno::makeAny(_sCommand));
3119 xRowSetPropSet->setPropertyValue("CommandType", uno::makeAny(_nCommandType));
3120
3121 uno::Reference< sdb::XCompletedExecution > xRowSet(xInstance, uno::UNO_QUERY);
3122
3123 if ( xRowSet.is() )
3124 {
3125 weld::Window* pWindow = pView ? pView->GetFrameWeld() : nullptr;
3126 uno::Reference< task::XInteractionHandler > xHandler( task::InteractionHandler::createWithParent(comphelper::getComponentContext(xMgr), pWindow ? pWindow->GetXWindow() : nullptr), uno::UNO_QUERY_THROW );
3127 xRowSet->executeWithCompletion(xHandler);
3128 }
3129 xResultSet.set(xRowSet, uno::UNO_QUERY);
3130 }
3131 }
3132 }
3133 catch (const uno::Exception&)
3134 {
3135 TOOLS_WARN_EXCEPTION("sw.mailmerge", "Caught exception while creating a new RowSet")do { css::uno::Any tools_warn_exception( DbgGetCaughtException
() ); do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sw.mailmerge")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "Caught exception while creating a new RowSet"
<< " " << exceptionToString(tools_warn_exception
)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "3135" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "Caught exception while creating a new RowSet"
<< " " << exceptionToString(tools_warn_exception
)), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Caught exception while creating a new RowSet" <<
" " << exceptionToString(tools_warn_exception); ::sal::
detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"),
("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "3135" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Caught exception while creating a new RowSet" <<
" " << exceptionToString(tools_warn_exception)) == 1) {
::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"
), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "3135" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "Caught exception while creating a new RowSet"
<< " " << exceptionToString(tools_warn_exception
)), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Caught exception while creating a new RowSet" <<
" " << exceptionToString(tools_warn_exception); ::sal::
detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"),
("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "3135" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false); } while (false)
;
3136 }
3137 return xResultSet;
3138}
3139
3140void SwDBManager::setEmbeddedName(const OUString& rEmbeddedName, SwDocShell& rDocShell)
3141{
3142 bool bLoad = m_sEmbeddedName != rEmbeddedName && !rEmbeddedName.isEmpty();
3143 bool bRegisterListener = m_sEmbeddedName.isEmpty() && !rEmbeddedName.isEmpty();
3144
3145 m_sEmbeddedName = rEmbeddedName;
3146
3147 if (bLoad)
3148 {
3149 uno::Reference<embed::XStorage> xStorage = rDocShell.GetStorage();
3150 // It's OK that we don't have the named sub-storage yet, in case
3151 // we're in the process of creating it.
3152 if (xStorage->hasByName(rEmbeddedName))
3153 LoadAndRegisterEmbeddedDataSource(rDocShell.GetDoc()->GetDBData(), rDocShell);
3154 }
3155
3156 if (bRegisterListener)
3157 // Register a remove listener, so we know when the embedded data source is removed.
3158 m_pImpl->m_xDataSourceRemovedListener = new SwDataSourceRemovedListener(*this);
3159}
3160
3161const OUString& SwDBManager::getEmbeddedName() const
3162{
3163 return m_sEmbeddedName;
3164}
3165
3166SwDoc* SwDBManager::getDoc() const
3167{
3168 return m_pDoc;
3169}
3170
3171void SwDBManager::releaseRevokeListener()
3172{
3173 if (m_pImpl->m_xDataSourceRemovedListener.is())
3174 {
3175 m_pImpl->m_xDataSourceRemovedListener->Dispose();
3176 m_pImpl->m_xDataSourceRemovedListener.clear();
3177 }
3178}
3179
3180SwDBManager::ConnectionDisposedListener_Impl::ConnectionDisposedListener_Impl(SwDBManager& rManager)
3181 : m_pDBManager(&rManager)
3182{
3183}
3184
3185void SwDBManager::ConnectionDisposedListener_Impl::disposing( const lang::EventObject& rSource )
3186{
3187 ::SolarMutexGuard aGuard;
3188
3189 if (!m_pDBManager) return; // we're disposed too!
3190
3191 uno::Reference<sdbc::XConnection> xSource(rSource.Source, uno::UNO_QUERY);
3192 for (size_t nPos = m_pDBManager->m_DataSourceParams.size(); nPos; nPos--)
3193 {
3194 SwDSParam* pParam = m_pDBManager->m_DataSourceParams[nPos - 1].get();
3195 if(pParam->xConnection.is() &&
3196 (xSource == pParam->xConnection))
3197 {
3198 m_pDBManager->m_DataSourceParams.erase(
3199 m_pDBManager->m_DataSourceParams.begin() + nPos - 1);
3200 }
3201 }
3202}
3203
3204std::shared_ptr<SwMailMergeConfigItem> SwDBManager::PerformMailMerge(SwView const * pView)
3205{
3206 std::shared_ptr<SwMailMergeConfigItem> xConfigItem = pView->GetMailMergeConfigItem();
3207 if (!xConfigItem)
3208 return xConfigItem;
3209
3210 svx::ODataAccessDescriptor aDescriptor;
3211 aDescriptor.setDataSource(xConfigItem->GetCurrentDBData().sDataSource);
3212 aDescriptor[ svx::DataAccessDescriptorProperty::Connection ] <<= xConfigItem->GetConnection().getTyped();
3213 aDescriptor[ svx::DataAccessDescriptorProperty::Cursor ] <<= xConfigItem->GetResultSet();
3214 aDescriptor[ svx::DataAccessDescriptorProperty::Command ] <<= xConfigItem->GetCurrentDBData().sCommand;
3215 aDescriptor[ svx::DataAccessDescriptorProperty::CommandType ] <<= xConfigItem->GetCurrentDBData().nCommandType;
3216 aDescriptor[ svx::DataAccessDescriptorProperty::Selection ] <<= xConfigItem->GetSelection();
3217
3218 SwWrtShell& rSh = pView->GetWrtShell();
3219 xConfigItem->SetTargetView(nullptr);
3220
3221 SwMergeDescriptor aMergeDesc(DBMGR_MERGE_SHELL, rSh, aDescriptor);
3222 aMergeDesc.pMailMergeConfigItem = xConfigItem.get();
3223 aMergeDesc.bCreateSingleFile = true;
3224 rSh.GetDBManager()->Merge(aMergeDesc);
3225
3226 return xConfigItem;
3227}
3228
3229void SwDBManager::RevokeLastRegistrations()
3230{
3231 if (m_aUncommittedRegistrations.empty())
3232 return;
3233
3234 SwView* pView = ( m_pDoc && m_pDoc->GetDocShell() ) ? m_pDoc->GetDocShell()->GetView() : nullptr;
3235 if (pView)
3236 {
3237 const std::shared_ptr<SwMailMergeConfigItem>& xConfigItem = pView->GetMailMergeConfigItem();
3238 if (xConfigItem)
3239 {
3240 xConfigItem->DisposeResultSet();
3241 xConfigItem->DocumentReloaded();
3242 }
3243 }
3244
3245 for (auto it = m_aUncommittedRegistrations.begin(); it != m_aUncommittedRegistrations.end();)
3246 {
3247 if ((m_pDoc && it->first == m_pDoc->GetDocShell()) || it->first == nullptr)
3248 {
3249 RevokeDataSource(it->second);
3250 it = m_aUncommittedRegistrations.erase(it);
3251 }
3252 else
3253 ++it;
3254 }
3255}
3256
3257void SwDBManager::CommitLastRegistrations()
3258{
3259 for (auto aIt = m_aUncommittedRegistrations.begin(); aIt != m_aUncommittedRegistrations.end();)
3260 {
3261 if (aIt->first == m_pDoc->GetDocShell() || aIt->first == nullptr)
3262 {
3263 m_aNotUsedConnections.push_back(aIt->second);
3264 aIt = m_aUncommittedRegistrations.erase(aIt);
3265 }
3266 else
3267 aIt++;
3268 }
3269}
3270
3271void SwDBManager::SetAsUsed(const OUString& rName)
3272{
3273 auto aFound = std::find(m_aNotUsedConnections.begin(), m_aNotUsedConnections.end(), rName);
3274 if (aFound != m_aNotUsedConnections.end())
3275 m_aNotUsedConnections.erase(aFound);
3276}
3277
3278void SwDBManager::RevokeNotUsedConnections()
3279{
3280 for (auto aIt = m_aNotUsedConnections.begin(); aIt != m_aNotUsedConnections.end();)
3281 {
3282 RevokeDataSource(*aIt);
3283 aIt = m_aNotUsedConnections.erase(aIt);
3284 }
3285}
3286
3287/* 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;
9
Assuming field 'length' is equal to 0
10
Returning the value 1, 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: */

/home/maarten/src/libreoffice/core/sw/inc/dbmgr.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#ifndef INCLUDED_SW_INC_DBMGR_HXX
20#define INCLUDED_SW_INC_DBMGR_HXX
21
22#include <rtl/ustring.hxx>
23#include <tools/solar.h>
24#include <i18nlangtag/lang.h>
25#include <com/sun/star/util/Date.hpp>
26#include "swdllapi.h"
27#include "swdbdata.hxx"
28#include <com/sun/star/uno/Reference.h>
29#include <com/sun/star/uno/Sequence.hxx>
30#include <com/sun/star/lang/Locale.hpp>
31#include <com/sun/star/beans/PropertyValue.hpp>
32
33#include <memory>
34#include <vector>
35
36namespace com::sun::star{
37 namespace sdbc{
38 class XConnection;
39 class XStatement;
40 class XDataSource;
41 class XResultSet;
42 }
43 namespace beans{
44
45 class XPropertySet;
46 }
47 namespace sdbcx{
48 class XColumnsSupplier;
49 }
50 namespace util{
51 class XNumberFormatter;
52 }
53 namespace mail{
54 class XSmtpService;
55 }
56 namespace embed { class XStorage; }
57 namespace frame { class XStorable; }
58}
59namespace svx {
60 class ODataAccessDescriptor;
61}
62
63struct SwDBFormatData
64{
65 css::util::Date aNullDate;
66 css::uno::Reference< css::util::XNumberFormatter> xFormatter;
67 css::lang::Locale aLocale;
68};
69
70namespace weld {
71 class ComboBox;
72 class Window;
73}
74
75class SwView;
76class SwWrtShell;
77class ListBox;
78class SvNumberFormatter;
79class SwXMailMerge;
80class SwMailMergeConfigItem;
81class SwCalc;
82class INetURLObject;
83class SwDocShell;
84
85enum DBManagerOptions
86{
87 DBMGR_MERGE, ///< Data records in fields.
88 DBMGR_MERGE_PRINTER, ///< Print mail merge.
89 DBMGR_MERGE_EMAIL, ///< Send mail merge as email.
90 DBMGR_MERGE_FILE, ///< Save mail merge as files.
91 DBMGR_MERGE_SHELL ///< Create merge doc and keep the doc shell.
92};
93
94// Administration of (new) logical databases.
95enum class SwDBSelect
96{
97 UNKNOWN, TABLE, QUERY
98};
99
100struct SwDSParam : public SwDBData
101{
102 css::util::Date aNullDate;
103
104 css::uno::Reference<css::util::XNumberFormatter> xFormatter;
105 css::uno::Reference< css::sdbc::XConnection> xConnection;
106 css::uno::Reference< css::sdbc::XStatement> xStatement;
107 css::uno::Reference< css::sdbc::XResultSet> xResultSet;
108 css::uno::Sequence< css::uno::Any > aSelection;
109 bool bScrollable;
110 bool bEndOfDB;
111 long nSelectionIndex;
112
113 SwDSParam(const SwDBData& rData) :
114 SwDBData(rData),
115 bScrollable(false),
116 bEndOfDB(false),
117 nSelectionIndex(0)
118 {}
119
120 SwDSParam(const SwDBData& rData,
121 const css::uno::Reference< css::sdbc::XResultSet>& xResSet,
122 const css::uno::Sequence< css::uno::Any >& rSelection) :
123 SwDBData(rData),
124 xResultSet(xResSet),
125 aSelection(rSelection),
126 bScrollable(true),
127 bEndOfDB(false),
128 nSelectionIndex(0)
129 {}
130
131 bool HasValidRecord() const
132 { return( !bEndOfDB && xResultSet.is() ); }
133};
134
135typedef std::vector<std::unique_ptr<SwDSParam>> SwDSParams_t;
136
137struct SwMergeDescriptor
138{
139 const DBManagerOptions nMergeType;
140 SwWrtShell& rSh;
141 const svx::ODataAccessDescriptor& rDescriptor;
142
143 /**
144 * Create a single or multiple results
145 *
146 * This currently just affects FILE, as EMAIL is always
147 * multiple and SHELL and PRINTER are always single.
148 */
149 bool bCreateSingleFile;
150
151 /**
152 * @defgroup save Export filter settings
153 * @addtogroup save
154 * @{ */
155 OUString sSaveToFilter;
156 OUString sSaveToFilterOptions;
157 css::uno::Sequence< css::beans::PropertyValue > aSaveToFilterData;
158 /** @} */
159
160 /**
161 * @defgroup file Mail merge as File settings
162 * @addtogroup file
163 * @{ */
164
165 /**
166 * Basename incl. the path for the generated files.
167 *
168 * The final filename will be created by concatenating a number to prevent
169 * overwriting an existing file and the extension based on the filter
170 * settings.
171 */
172 OUString sPrefix;
173 /**
174 * Use the sPrefix as the target filename also overwriting an existing
175 * target file.
176 *
177 * Just used for the internal mail merge dialogs as mail merge never
178 * overwrites existing files (see SwDBManager::ExecuteFormLetter).
179 */
180 bool bPrefixIsFilename;
181 /** @} */
182
183 /**
184 * @defgroup email Mail merge as eMail settings
185 * @addtogroup email
186 * @{ */
187 OUString sSubject;
188 OUString sMailBody;
189 OUString sAttachmentName;
190 css::uno::Sequence< OUString > aCopiesTo;
191 css::uno::Sequence< OUString > aBlindCopiesTo;
192 css::uno::Reference< css::mail::XSmtpService > xSmtpServer;
193 bool bSendAsHTML;
194 bool bSendAsAttachment;
195 /** @} */
196
197 /**
198 * @addtogroup file email
199 * @{ */
200
201 /** DB column to fetch EMail of Filename from
202 */
203 OUString sDBcolumn;
204
205 /** DB column to fetch password
206 */
207 OUString sDBPasswordColumn;
208
209 /** @} */
210
211 /**
212 * @defgroup print Mail merge to Printer
213 * @addtogroup print
214 * @{ */
215 css::uno::Sequence< css::beans::PropertyValue > aPrintOptions;
216 /** @} */
217
218 SwMailMergeConfigItem* pMailMergeConfigItem;
219
220 SwMergeDescriptor( const DBManagerOptions nType,
221 SwWrtShell& rShell,
222 const svx::ODataAccessDescriptor& rDesc ) :
223 nMergeType(nType),
224 rSh(rShell),
225 rDescriptor(rDesc),
226 bCreateSingleFile( false ),
227 bPrefixIsFilename( false ),
228 bSendAsHTML( true ),
229 bSendAsAttachment( false ),
230 pMailMergeConfigItem( nullptr )
231 {
232 if( nType == DBMGR_MERGE_SHELL || nType == DBMGR_MERGE_PRINTER )
233 bCreateSingleFile = true;
234 }
235};
236
237class SwDoc;
238
239class SW_DLLPUBLIC__attribute__ ((visibility("default"))) SwDBManager
240{
241 struct SwDBManager_Impl;
242 class SAL_DLLPRIVATE__attribute__ ((visibility("hidden"))) ConnectionDisposedListener_Impl;
243 class MailDispatcherListener_Impl;
244
245 enum class MergeStatus
246 {
247 Ok = 0, Cancel, Error
248 };
249
250 MergeStatus m_aMergeStatus; ///< current / last merge status
251 bool m_bInitDBFields : 1;
252 bool m_bInMerge : 1; ///< merge process active
253 bool m_bMergeSilent : 1; ///< suppress display of dialogs/boxes (used when called over API)
254 SwDSParams_t m_DataSourceParams;
255 std::unique_ptr<SwDBManager_Impl> m_pImpl;
256 const SwXMailMerge* m_pMergeEvtSrc; ///< != 0 if mail merge events are to be send
257 /// Name of the embedded database that's included in the current document.
258 OUString m_sEmbeddedName;
259
260 /// Store last registrations to revoke or commit
261 static std::vector<std::pair<SwDocShell*, OUString>> m_aUncommittedRegistrations;
262
263 /// Not used connections.
264 std::vector<OUString> m_aNotUsedConnections;
265
266 /// Set connection as used.
267 void SetAsUsed(const OUString& rName);
268
269 /// The document that owns this manager.
270 SwDoc* m_pDoc;
271
272 SAL_DLLPRIVATE__attribute__ ((visibility("hidden"))) SwDSParam* FindDSData(const SwDBData& rData, bool bCreate);
273 SAL_DLLPRIVATE__attribute__ ((visibility("hidden"))) SwDSParam* FindDSConnection(const OUString& rSource, bool bCreate);
274
275 /// Insert data record as text into document.
276 SAL_DLLPRIVATE__attribute__ ((visibility("hidden"))) void ImportFromConnection( SwWrtShell* pSh);
277
278 /// Insert a single data record as text into document.
279 SAL_DLLPRIVATE__attribute__ ((visibility("hidden"))) void ImportDBEntry(SwWrtShell* pSh);
280
281 /// Run the mail merge for defined modes, except DBMGR_MERGE
282 SAL_DLLPRIVATE__attribute__ ((visibility("hidden"))) bool MergeMailFiles( SwWrtShell* pSh,
283 const SwMergeDescriptor& rMergeDescriptor );
284
285 SAL_DLLPRIVATE__attribute__ ((visibility("hidden"))) bool ToNextMergeRecord();
286 SAL_DLLPRIVATE__attribute__ ((visibility("hidden"))) bool IsValidMergeRecord() const;
287
288 SwDBManager(SwDBManager const&) = delete;
289 SwDBManager& operator=(SwDBManager const&) = delete;
290
291public:
292 SwDBManager(SwDoc* pDoc);
293 ~SwDBManager() COVERITY_NOEXCEPT_FALSE;
294
295 /// MailMergeEvent source
296 const SwXMailMerge * GetMailMergeEvtSrc() const { return m_pMergeEvtSrc; }
297 void SetMailMergeEvtSrc( const SwXMailMerge *pSrc ) { m_pMergeEvtSrc = pSrc; }
298
299 bool IsMergeSilent() const { return m_bMergeSilent; }
300 void SetMergeSilent( bool bVal ) { m_bMergeSilent = bVal; }
301
302 /// Merging of data records into fields.
303 bool Merge( const SwMergeDescriptor& rMergeDesc );
304 void MergeCancel();
305
306 bool IsMergeOk() const { return MergeStatus::Ok == m_aMergeStatus; }
34
Assuming Ok is not equal to field 'm_aMergeStatus'
35
Returning zero, which participates in a condition later
307 bool IsMergeError() const { return MergeStatus::Error <= m_aMergeStatus; }
308
309 static std::shared_ptr<SwMailMergeConfigItem> PerformMailMerge(SwView const * pView);
310
311 /// Initialize data fields that lack name of database.
312 bool IsInitDBFields() const { return m_bInitDBFields; }
313 void SetInitDBFields(bool b) { m_bInitDBFields = b; }
314
315 /// Fill listbox with all table names of a database.
316 bool GetTableNames(weld::ComboBox& rBox, const OUString& rDBName);
317
318 /// Fill listbox with all column names of a database table.
319 void GetColumnNames(weld::ComboBox& rBox,
320 const OUString& rDBName, const OUString& rTableName);
321 static void GetColumnNames(weld::ComboBox& rBox,
322 css::uno::Reference< css::sdbc::XConnection> const & xConnection,
323 const OUString& rTableName);
324
325 static sal_uLong GetColumnFormat( css::uno::Reference< css::sdbc::XDataSource> const & xSource,
326 css::uno::Reference< css::sdbc::XConnection> const & xConnection,
327 css::uno::Reference< css::beans::XPropertySet> const & xColumn,
328 SvNumberFormatter* pNFormatr,
329 LanguageType nLanguage );
330
331 sal_uLong GetColumnFormat( const OUString& rDBName,
332 const OUString& rTableName,
333 const OUString& rColNm,
334 SvNumberFormatter* pNFormatr,
335 LanguageType nLanguage );
336 sal_Int32 GetColumnType( const OUString& rDBName,
337 const OUString& rTableName,
338 const OUString& rColNm );
339
340 bool IsInMerge() const { return m_bInMerge; }
341
342 void ExecuteFormLetter(SwWrtShell& rSh,
343 const css::uno::Sequence< css::beans::PropertyValue>& rProperties);
344
345 static void InsertText(SwWrtShell& rSh,
346 const css::uno::Sequence< css::beans::PropertyValue>& rProperties);
347
348 /// check if a data source is open
349 bool IsDataSourceOpen(const OUString& rDataSource,
350 const OUString& rTableOrQuery, bool bMergeShell);
351
352 /// open the source while fields are updated - for the calculator only!
353 bool OpenDataSource(const OUString& rDataSource, const OUString& rTableOrQuery);
354 sal_uInt32 GetSelectedRecordId(const OUString& rDataSource, const OUString& rTableOrQuery, sal_Int32 nCommandType = -1);
355 bool GetColumnCnt(const OUString& rSourceName, const OUString& rTableName,
356 const OUString& rColumnName, sal_uInt32 nAbsRecordId, LanguageType nLanguage,
357 OUString& rResult, double* pNumber);
358 /** create and store or find an already stored connection to a data source for use
359 in SwFieldMgr and SwDBTreeList */
360 css::uno::Reference< css::sdbc::XConnection> const &
361 RegisterConnection(OUString const& rSource);
362
363 void CreateDSData(const SwDBData& rData)
364 { FindDSData(rData, true); }
365 const SwDSParams_t& GetDSParamArray() const { return m_DataSourceParams; }
366
367 /// close all data sources - after fields were updated
368 void CloseAll(bool bIncludingMerge = true);
369
370 bool GetMergeColumnCnt(const OUString& rColumnName, LanguageType nLanguage,
371 OUString &rResult, double *pNumber);
372 bool FillCalcWithMergeData(SvNumberFormatter *pDocFormatter,
373 LanguageType nLanguage, SwCalc &aCalc);
374 void ToNextRecord(const OUString& rDataSource, const OUString& rTableOrQuery);
375
376 sal_uInt32 GetSelectedRecordId();
377 bool ToRecordId(sal_Int32 nSet);
378
379 static const SwDBData& GetAddressDBName();
380
381 static OUString GetDBField(
382 css::uno::Reference< css::beans::XPropertySet > const & xColumnProp,
383 const SwDBFormatData& rDBFormatData,
384 double *pNumber = nullptr);
385
386 static css::uno::Reference< css::sdbc::XConnection>
387 GetConnection(const OUString& rDataSource,
388 css::uno::Reference< css::sdbc::XDataSource>& rxSource,
389 const SwView* pView);
390
391 static css::uno::Reference< css::sdbcx::XColumnsSupplier>
392 GetColumnSupplier(css::uno::Reference< css::sdbc::XConnection> const & xConnection,
393 const OUString& rTableOrQuery,
394 SwDBSelect eTableOrQuery = SwDBSelect::UNKNOWN);
395
396 static css::uno::Sequence<OUString> GetExistingDatabaseNames();
397
398 /**
399 Loads a data source from file and registers it.
400
401 This function requires GUI interaction, as it loads the data source from
402 the filename returned by a file picker and additional settings dialog.
403 In case of success it returns the registered name, otherwise an empty string.
404 */
405 static OUString LoadAndRegisterDataSource(weld::Window* pParent, SwDocShell* pDocShell = nullptr);
406
407 /**
408 Loads a data source from file and registers it.
409
410 Convenience function, which calls GetDBunoURI and has just one mandatory parameter.
411 In case of success it returns the registered name, otherwise an empty string.
412 */
413 static OUString LoadAndRegisterDataSource(const OUString& rURI, const OUString *pDestDir);
414
415 /// Load the embedded data source of the document and also register it.
416 void LoadAndRegisterEmbeddedDataSource(const SwDBData& rData, const SwDocShell& rDocShell);
417
418 /// Unregister a data source.
419 static void RevokeDataSource(const OUString& rName);
420
421 /** try to get the data source from the given connection through the XChild interface.
422 If this is not possible, the data source will be created through its name.
423 @param _xConnection
424 The connection which should support the XChild interface. (not a must)
425 @param _sDataSourceName
426 The data source name will be used to create the data source when the connection can not be used for it.
427 @return
428 The data source.
429 */
430 static css::uno::Reference< css::sdbc::XDataSource>
431 getDataSourceAsParent(const css::uno::Reference< css::sdbc::XConnection>& _xConnection,const OUString& _sDataSourceName);
432
433 /** creates a RowSet, which must be disposed after use.
434 @param _sDataSourceName
435 The data source name
436 @param _sCommand
437 The command.
438 @param _nCommandType
439 The type of the command.
440 @param _xConnection
441 The active connection which may be <NULL/>.
442 @return
443 The new created RowSet.
444
445 */
446 static css::uno::Reference< css::sdbc::XResultSet>
447 createCursor(const OUString& _sDataSourceName,
448 const OUString& _sCommand,
449 sal_Int32 _nCommandType,
450 const css::uno::Reference< css::sdbc::XConnection>& _xConnection,
451 const SwView* pView);
452
453 void setEmbeddedName(const OUString& rEmbeddedName, SwDocShell& rDocShell);
454 const OUString& getEmbeddedName() const;
455
456 // rOwnURL should be taken using INetURLObject::GetMainURL(INetURLObject::DecodeMechanism::NONE)
457 static void StoreEmbeddedDataSource(const css::uno::Reference<css::frame::XStorable>& xStorable,
458 const css::uno::Reference<css::embed::XStorage>& xStorage,
459 const OUString& rStreamRelPath,
460 const OUString& rOwnURL, bool bCopyTo = false);
461
462 SwDoc* getDoc() const;
463 /// Stop reacting to removed database registrations.
464 void releaseRevokeListener();
465
466 /// Revoke not committed registrations in case of mail merge cancel
467 void RevokeLastRegistrations();
468
469 /// Accept not committed registrations
470 void CommitLastRegistrations();
471
472 /// Remove not used connections.
473 void RevokeNotUsedConnections();
474};
475
476namespace sw
477{
478enum class DBConnURIType
479{
480 UNKNOWN = 0,
481 ODB,
482 CALC,
483 DBASE,
484 FLAT,
485 MSJET,
486 MSACE,
487 WRITER
488};
489
490DBConnURIType SW_DLLPUBLIC__attribute__ ((visibility("default"))) GetDBunoType(const INetURLObject &rURL);
491}
492
493#endif
494
495/* vim:set shiftwidth=4 softtabstop=4 expandtab: */