Bug Summary

File:home/maarten/src/libreoffice/core/sc/source/filter/excel/xechart.cxx
Warning:line 1669, column 24
Assigned value is garbage or undefined

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 xechart.cxx -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D BOOST_ERROR_CODE_HEADER_ONLY -D BOOST_SYSTEM_NO_DEPRECATED -D CPPU_ENV=gcc3 -D LINUX -D OSL_DEBUG_LEVEL=1 -D SAL_LOG_INFO -D SAL_LOG_WARN -D UNIX -D UNX -D X86_64 -D _PTHREADS -D _REENTRANT -D BOOST_ALL_NO_LIB -D BOOST_ALL_NO_LIB -D BOOST_ALL_NO_LIB -D SYSTEM_ZLIB -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/liborcus/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/liborcus/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/mdds/include -I /home/maarten/src/libreoffice/core/external/clew/source/include -I /home/maarten/src/libreoffice/core/external/boost/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/boost -I /home/maarten/src/libreoffice/core/sc/source/core/inc -I /home/maarten/src/libreoffice/core/sc/source/filter/inc -I /home/maarten/src/libreoffice/core/sc/source/ui/inc -I /home/maarten/src/libreoffice/core/sc/inc -I /home/maarten/src/libreoffice/core/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include/linux -I /home/maarten/src/libreoffice/core/config_host -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/udkapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/oovbaapi/normal -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/oox/generated -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/officecfg/registry -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/sc/source/filter/excel/xechart.cxx

/home/maarten/src/libreoffice/core/sc/source/filter/excel/xechart.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 <xechart.hxx>
21
22#include <com/sun/star/i18n/XBreakIterator.hpp>
23#include <com/sun/star/i18n/ScriptType.hpp>
24#include <com/sun/star/drawing/FillStyle.hpp>
25#include <com/sun/star/drawing/XShapes.hpp>
26#include <com/sun/star/chart/XChartDocument.hpp>
27#include <com/sun/star/chart/ChartAxisLabelPosition.hpp>
28#include <com/sun/star/chart/ChartAxisPosition.hpp>
29#include <com/sun/star/chart/ChartLegendExpansion.hpp>
30#include <com/sun/star/chart/DataLabelPlacement.hpp>
31#include <com/sun/star/chart/ErrorBarStyle.hpp>
32#include <com/sun/star/chart/MissingValueTreatment.hpp>
33#include <com/sun/star/chart/TimeInterval.hpp>
34#include <com/sun/star/chart/TimeUnit.hpp>
35#include <com/sun/star/chart/XAxisSupplier.hpp>
36#include <com/sun/star/chart/XDiagramPositioning.hpp>
37#include <com/sun/star/chart2/XChartDocument.hpp>
38#include <com/sun/star/chart2/XDiagram.hpp>
39#include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
40#include <com/sun/star/chart2/XChartTypeContainer.hpp>
41#include <com/sun/star/chart2/XDataSeriesContainer.hpp>
42#include <com/sun/star/chart2/XRegressionCurveContainer.hpp>
43#include <com/sun/star/chart2/XTitled.hpp>
44#include <com/sun/star/chart2/XColorScheme.hpp>
45#include <com/sun/star/chart2/data/XDataSource.hpp>
46#include <com/sun/star/chart2/AxisType.hpp>
47#include <com/sun/star/chart2/CurveStyle.hpp>
48#include <com/sun/star/chart2/DataPointGeometry3D.hpp>
49#include <com/sun/star/chart2/DataPointLabel.hpp>
50#include <com/sun/star/chart2/LegendPosition.hpp>
51#include <com/sun/star/chart2/RelativePosition.hpp>
52#include <com/sun/star/chart2/RelativeSize.hpp>
53#include <com/sun/star/chart2/StackingDirection.hpp>
54#include <com/sun/star/chart2/TickmarkStyle.hpp>
55
56#include <tools/gen.hxx>
57#include <vcl/outdev.hxx>
58#include <filter/msfilter/escherex.hxx>
59
60#include <document.hxx>
61#include <compiler.hxx>
62#include <tokenarray.hxx>
63#include <xeescher.hxx>
64#include <xeformula.hxx>
65#include <xehelper.hxx>
66#include <xepage.hxx>
67#include <xestyle.hxx>
68#include <xltools.hxx>
69
70#include <memory>
71
72using ::com::sun::star::uno::Any;
73using ::com::sun::star::uno::Reference;
74using ::com::sun::star::uno::Sequence;
75using ::com::sun::star::uno::UNO_QUERY;
76using ::com::sun::star::uno::UNO_QUERY_THROW;
77using ::com::sun::star::uno::UNO_SET_THROW;
78using ::com::sun::star::uno::Exception;
79using ::com::sun::star::beans::XPropertySet;
80using ::com::sun::star::i18n::XBreakIterator;
81using ::com::sun::star::frame::XModel;
82using ::com::sun::star::drawing::XShape;
83using ::com::sun::star::drawing::XShapes;
84
85using ::com::sun::star::chart2::IncrementData;
86using ::com::sun::star::chart2::RelativePosition;
87using ::com::sun::star::chart2::RelativeSize;
88using ::com::sun::star::chart2::ScaleData;
89using ::com::sun::star::chart2::SubIncrement;
90using ::com::sun::star::chart2::XAxis;
91using ::com::sun::star::chart2::XChartDocument;
92using ::com::sun::star::chart2::XChartTypeContainer;
93using ::com::sun::star::chart2::XColorScheme;
94using ::com::sun::star::chart2::XCoordinateSystem;
95using ::com::sun::star::chart2::XCoordinateSystemContainer;
96using ::com::sun::star::chart2::XChartType;
97using ::com::sun::star::chart2::XDataSeries;
98using ::com::sun::star::chart2::XDataSeriesContainer;
99using ::com::sun::star::chart2::XDiagram;
100using ::com::sun::star::chart2::XFormattedString;
101using ::com::sun::star::chart2::XLegend;
102using ::com::sun::star::chart2::XRegressionCurve;
103using ::com::sun::star::chart2::XRegressionCurveContainer;
104using ::com::sun::star::chart2::XTitle;
105using ::com::sun::star::chart2::XTitled;
106
107using ::com::sun::star::chart2::data::XDataSequence;
108using ::com::sun::star::chart2::data::XDataSource;
109using ::com::sun::star::chart2::data::XLabeledDataSequence;
110
111using ::formula::FormulaToken;
112using ::formula::FormulaTokenArrayPlainIterator;
113
114namespace cssc = ::com::sun::star::chart;
115namespace cssc2 = ::com::sun::star::chart2;
116
117// Helpers ====================================================================
118
119namespace {
120
121XclExpStream& operator<<( XclExpStream& rStrm, const XclChRectangle& rRect )
122{
123 return rStrm << rRect.mnX << rRect.mnY << rRect.mnWidth << rRect.mnHeight;
124}
125
126void lclSaveRecord( XclExpStream& rStrm, XclExpRecordRef const & xRec )
127{
128 if( xRec )
129 xRec->Save( rStrm );
130}
131
132/** Saves the passed record (group) together with a leading value record. */
133template< typename Type >
134void lclSaveRecord( XclExpStream& rStrm, XclExpRecordRef const & xRec, sal_uInt16 nRecId, Type nValue )
135{
136 if( xRec )
137 {
138 XclExpValueRecord< Type >( nRecId, nValue ).Save( rStrm );
139 xRec->Save( rStrm );
140 }
141}
142
143template<typename ValueType, typename KeyType>
144void lclSaveRecord(XclExpStream& rStrm, ValueType* pRec, sal_uInt16 nRecId, KeyType nValue)
145{
146 if (pRec)
147 {
148 XclExpValueRecord<KeyType>(nRecId, nValue).Save(rStrm);
149 pRec->Save(rStrm);
150 }
151}
152
153void lclWriteChFrBlockRecord( XclExpStream& rStrm, const XclChFrBlock& rFrBlock, bool bBegin )
154{
155 sal_uInt16 nRecId = bBegin ? EXC_ID_CHFRBLOCKBEGIN : EXC_ID_CHFRBLOCKEND;
156 rStrm.StartRecord( nRecId, 12 );
157 rStrm << nRecId << EXC_FUTUREREC_EMPTYFLAGS << rFrBlock.mnType << rFrBlock.mnContext << rFrBlock.mnValue1 << rFrBlock.mnValue2;
158 rStrm.EndRecord();
159}
160
161template< typename Type >
162bool lclIsAutoAnyOrGetValue( Type& rValue, const Any& rAny )
163{
164 return !rAny.hasValue() || !(rAny >>= rValue);
165}
166
167bool lclIsAutoAnyOrGetScaledValue( double& rfValue, const Any& rAny, bool bLogScale )
168{
169 bool bIsAuto = lclIsAutoAnyOrGetValue( rfValue, rAny );
170 if( !bIsAuto && bLogScale )
171 rfValue = log( rfValue ) / log( 10.0 );
172 return bIsAuto;
173}
174
175sal_uInt16 lclGetTimeValue( const XclExpRoot& rRoot, double fSerialDate, sal_uInt16 nTimeUnit )
176{
177 DateTime aDateTime = rRoot.GetDateTimeFromDouble( fSerialDate );
178 switch( nTimeUnit )
179 {
180 case EXC_CHDATERANGE_DAYS:
181 return ::limit_cast< sal_uInt16, double >( fSerialDate, 0, SAL_MAX_UINT16((sal_uInt16) 0xFFFF) );
182 case EXC_CHDATERANGE_MONTHS:
183 return ::limit_cast< sal_uInt16, sal_uInt16 >( 12 * (aDateTime.GetYear() - rRoot.GetBaseYear()) + aDateTime.GetMonth() - 1, 0, SAL_MAX_INT16((sal_Int16) 0x7FFF) );
184 case EXC_CHDATERANGE_YEARS:
185 return ::limit_cast< sal_uInt16, sal_uInt16 >( aDateTime.GetYear() - rRoot.GetBaseYear(), 0, SAL_MAX_INT16((sal_Int16) 0x7FFF) );
186 default:
187 OSL_ENSURE( false, "lclGetTimeValue - unexpected time unit" )do { if (true && (!(false))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/filter/excel/xechart.cxx"
":" "187" ": "), "%s", "lclGetTimeValue - unexpected time unit"
); } } while (false)
;
188 }
189 return ::limit_cast< sal_uInt16, double >( fSerialDate, 0, SAL_MAX_UINT16((sal_uInt16) 0xFFFF) );
190}
191
192bool lclConvertTimeValue( const XclExpRoot& rRoot, sal_uInt16& rnValue, const Any& rAny, sal_uInt16 nTimeUnit )
193{
194 double fSerialDate = 0;
195 bool bAuto = lclIsAutoAnyOrGetValue( fSerialDate, rAny );
196 if( !bAuto )
197 rnValue = lclGetTimeValue( rRoot, fSerialDate, nTimeUnit );
198 return bAuto;
199}
200
201sal_uInt16 lclGetTimeUnit( sal_Int32 nApiTimeUnit )
202{
203 switch( nApiTimeUnit )
204 {
205 case cssc::TimeUnit::DAY: return EXC_CHDATERANGE_DAYS;
206 case cssc::TimeUnit::MONTH: return EXC_CHDATERANGE_MONTHS;
207 case cssc::TimeUnit::YEAR: return EXC_CHDATERANGE_YEARS;
208 default: OSL_ENSURE( false, "lclGetTimeUnit - unexpected time unit" )do { if (true && (!(false))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/filter/excel/xechart.cxx"
":" "208" ": "), "%s", "lclGetTimeUnit - unexpected time unit"
); } } while (false)
;
209 }
210 return EXC_CHDATERANGE_DAYS;
211}
212
213bool lclConvertTimeInterval( sal_uInt16& rnValue, sal_uInt16& rnTimeUnit, const Any& rAny )
214{
215 cssc::TimeInterval aInterval;
216 bool bAuto = lclIsAutoAnyOrGetValue( aInterval, rAny );
217 if( !bAuto )
218 {
219 rnValue = ::limit_cast< sal_uInt16, sal_Int32 >( aInterval.Number, 1, SAL_MAX_UINT16((sal_uInt16) 0xFFFF) );
220 rnTimeUnit = lclGetTimeUnit( aInterval.TimeUnit );
221 }
222 return bAuto;
223}
224
225} // namespace
226
227// Common =====================================================================
228
229/** Stores global data needed in various classes of the Chart export filter. */
230struct XclExpChRootData : public XclChRootData
231{
232 typedef ::std::vector< XclChFrBlock > XclChFrBlockVector;
233
234 XclExpChChart& mrChartData; /// The chart data object.
235 XclChFrBlockVector maWrittenFrBlocks; /// Stack of future record levels already written out.
236 XclChFrBlockVector maUnwrittenFrBlocks; /// Stack of future record levels not yet written out.
237
238 explicit XclExpChRootData( XclExpChChart& rChartData ) : mrChartData( rChartData ) {}
239
240 /** Registers a new future record level. */
241 void RegisterFutureRecBlock( const XclChFrBlock& rFrBlock );
242 /** Initializes the current future record level (writes all unwritten CHFRBLOCKBEGIN records). */
243 void InitializeFutureRecBlock( XclExpStream& rStrm );
244 /** Finalizes the current future record level (writes CHFRBLOCKEND record if needed). */
245 void FinalizeFutureRecBlock( XclExpStream& rStrm );
246};
247
248void XclExpChRootData::RegisterFutureRecBlock( const XclChFrBlock& rFrBlock )
249{
250 maUnwrittenFrBlocks.push_back( rFrBlock );
251}
252
253void XclExpChRootData::InitializeFutureRecBlock( XclExpStream& rStrm )
254{
255 // first call from a future record writes all missing CHFRBLOCKBEGIN records
256 if( maUnwrittenFrBlocks.empty() )
257 return;
258
259 // write the leading CHFRINFO record
260 if( maWrittenFrBlocks.empty() )
261 {
262 rStrm.StartRecord( EXC_ID_CHFRINFO, 20 );
263 rStrm << EXC_ID_CHFRINFO << EXC_FUTUREREC_EMPTYFLAGS << EXC_CHFRINFO_EXCELXP2003 << EXC_CHFRINFO_EXCELXP2003 << sal_uInt16( 3 );
264 rStrm << sal_uInt16( 0x0850 ) << sal_uInt16( 0x085A ) << sal_uInt16( 0x0861 ) << sal_uInt16( 0x0861 ) << sal_uInt16( 0x086A ) << sal_uInt16( 0x086B );
265 rStrm.EndRecord();
266 }
267 // write all unwritten CHFRBLOCKBEGIN records
268 for( const auto& rUnwrittenFrBlock : maUnwrittenFrBlocks )
269 {
270 OSL_ENSURE( rUnwrittenFrBlock.mnType != EXC_CHFRBLOCK_TYPE_UNKNOWN, "XclExpChRootData::InitializeFutureRecBlock - unknown future record block type" )do { if (true && (!(rUnwrittenFrBlock.mnType != EXC_CHFRBLOCK_TYPE_UNKNOWN
))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sc/source/filter/excel/xechart.cxx"
":" "270" ": "), "%s", "XclExpChRootData::InitializeFutureRecBlock - unknown future record block type"
); } } while (false)
;
271 lclWriteChFrBlockRecord( rStrm, rUnwrittenFrBlock, true );
272 }
273 // move all record infos to vector of written blocks
274 maWrittenFrBlocks.insert( maWrittenFrBlocks.end(), maUnwrittenFrBlocks.begin(), maUnwrittenFrBlocks.end() );
275 maUnwrittenFrBlocks.clear();
276}
277
278void XclExpChRootData::FinalizeFutureRecBlock( XclExpStream& rStrm )
279{
280 OSL_ENSURE( !maUnwrittenFrBlocks.empty() || !maWrittenFrBlocks.empty(), "XclExpChRootData::FinalizeFutureRecBlock - no future record level found" )do { if (true && (!(!maUnwrittenFrBlocks.empty() || !
maWrittenFrBlocks.empty()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/filter/excel/xechart.cxx"
":" "280" ": "), "%s", "XclExpChRootData::FinalizeFutureRecBlock - no future record level found"
); } } while (false)
;
281 if( !maUnwrittenFrBlocks.empty() )
282 {
283 // no future record has been written, just forget the topmost level
284 maUnwrittenFrBlocks.pop_back();
285 }
286 else if( !maWrittenFrBlocks.empty() )
287 {
288 // write the CHFRBLOCKEND record for the topmost block and delete it
289 lclWriteChFrBlockRecord( rStrm, maWrittenFrBlocks.back(), false );
290 maWrittenFrBlocks.pop_back();
291 }
292}
293
294XclExpChRoot::XclExpChRoot( const XclExpRoot& rRoot, XclExpChChart& rChartData ) :
295 XclExpRoot( rRoot ),
296 mxChData( std::make_shared<XclExpChRootData>( rChartData ) )
297{
298}
299
300XclExpChRoot::~XclExpChRoot()
301{
302}
303
304Reference< XChartDocument > const & XclExpChRoot::GetChartDocument() const
305{
306 return mxChData->mxChartDoc;
307}
308
309XclExpChChart& XclExpChRoot::GetChartData() const
310{
311 return mxChData->mrChartData;
312}
313
314const XclChTypeInfo& XclExpChRoot::GetChartTypeInfo( XclChTypeId eType ) const
315{
316 return mxChData->mxTypeInfoProv->GetTypeInfo( eType );
317}
318
319const XclChTypeInfo& XclExpChRoot::GetChartTypeInfo( const OUString& rServiceName ) const
320{
321 return mxChData->mxTypeInfoProv->GetTypeInfoFromService( rServiceName );
322}
323
324const XclChFormatInfo& XclExpChRoot::GetFormatInfo( XclChObjectType eObjType ) const
325{
326 return mxChData->mxFmtInfoProv->GetFormatInfo( eObjType );
327}
328
329void XclExpChRoot::InitConversion( css::uno::Reference< css::chart2::XChartDocument > const & xChartDoc, const tools::Rectangle& rChartRect ) const
330{
331 mxChData->InitConversion( GetRoot(), xChartDoc, rChartRect );
332}
333
334void XclExpChRoot::FinishConversion() const
335{
336 mxChData->FinishConversion();
337}
338
339bool XclExpChRoot::IsSystemColor( const Color& rColor, sal_uInt16 nSysColorIdx ) const
340{
341 XclExpPalette& rPal = GetPalette();
342 return rPal.IsSystemColor( nSysColorIdx ) && (rColor == rPal.GetDefColor( nSysColorIdx ));
343}
344
345void XclExpChRoot::SetSystemColor( Color& rColor, sal_uInt32& rnColorId, sal_uInt16 nSysColorIdx ) const
346{
347 OSL_ENSURE( GetPalette().IsSystemColor( nSysColorIdx ), "XclExpChRoot::SetSystemColor - invalid color index" )do { if (true && (!(GetPalette().IsSystemColor( nSysColorIdx
)))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sc/source/filter/excel/xechart.cxx"
":" "347" ": "), "%s", "XclExpChRoot::SetSystemColor - invalid color index"
); } } while (false)
;
348 rColor = GetPalette().GetDefColor( nSysColorIdx );
349 rnColorId = XclExpPalette::GetColorIdFromIndex( nSysColorIdx );
350}
351
352sal_Int32 XclExpChRoot::CalcChartXFromHmm( sal_Int32 nPosX ) const
353{
354 return ::limit_cast< sal_Int32, double >( (nPosX - mxChData->mnBorderGapX) / mxChData->mfUnitSizeX, 0, EXC_CHART_TOTALUNITS );
355}
356
357sal_Int32 XclExpChRoot::CalcChartYFromHmm( sal_Int32 nPosY ) const
358{
359 return ::limit_cast< sal_Int32, double >( (nPosY - mxChData->mnBorderGapY) / mxChData->mfUnitSizeY, 0, EXC_CHART_TOTALUNITS );
360}
361
362XclChRectangle XclExpChRoot::CalcChartRectFromHmm( const css::awt::Rectangle& rRect ) const
363{
364 XclChRectangle aRect;
365 aRect.mnX = CalcChartXFromHmm( rRect.X );
366 aRect.mnY = CalcChartYFromHmm( rRect.Y );
367 aRect.mnWidth = CalcChartXFromHmm( rRect.Width );
368 aRect.mnHeight = CalcChartYFromHmm( rRect.Height );
369 return aRect;
370}
371
372void XclExpChRoot::ConvertLineFormat( XclChLineFormat& rLineFmt,
373 const ScfPropertySet& rPropSet, XclChPropertyMode ePropMode ) const
374{
375 GetChartPropSetHelper().ReadLineProperties(
376 rLineFmt, *mxChData->mxLineDashTable, rPropSet, ePropMode );
377}
378
379bool XclExpChRoot::ConvertAreaFormat( XclChAreaFormat& rAreaFmt,
380 const ScfPropertySet& rPropSet, XclChPropertyMode ePropMode ) const
381{
382 return GetChartPropSetHelper().ReadAreaProperties( rAreaFmt, rPropSet, ePropMode );
383}
384
385void XclExpChRoot::ConvertEscherFormat(
386 XclChEscherFormat& rEscherFmt, XclChPicFormat& rPicFmt,
387 const ScfPropertySet& rPropSet, XclChPropertyMode ePropMode ) const
388{
389 GetChartPropSetHelper().ReadEscherProperties( rEscherFmt, rPicFmt,
390 *mxChData->mxGradientTable, *mxChData->mxHatchTable, *mxChData->mxBitmapTable, rPropSet, ePropMode );
391}
392
393sal_uInt16 XclExpChRoot::ConvertFont( const ScfPropertySet& rPropSet, sal_Int16 nScript ) const
394{
395 XclFontData aFontData;
396 GetFontPropSetHelper().ReadFontProperties( aFontData, rPropSet, EXC_FONTPROPSET_CHART, nScript );
397 return GetFontBuffer().Insert( aFontData, EXC_COLOR_CHARTTEXT );
398}
399
400sal_uInt16 XclExpChRoot::ConvertPieRotation( const ScfPropertySet& rPropSet )
401{
402 sal_Int32 nApiRot = 0;
403 rPropSet.GetProperty( nApiRot, EXC_CHPROP_STARTINGANGLE"StartingAngle" );
404 return static_cast< sal_uInt16 >( (450 - (nApiRot % 360)) % 360 );
405}
406
407void XclExpChRoot::RegisterFutureRecBlock( const XclChFrBlock& rFrBlock )
408{
409 mxChData->RegisterFutureRecBlock( rFrBlock );
410}
411
412void XclExpChRoot::InitializeFutureRecBlock( XclExpStream& rStrm )
413{
414 mxChData->InitializeFutureRecBlock( rStrm );
415}
416
417void XclExpChRoot::FinalizeFutureRecBlock( XclExpStream& rStrm )
418{
419 mxChData->FinalizeFutureRecBlock( rStrm );
420}
421
422XclExpChGroupBase::XclExpChGroupBase( const XclExpChRoot& rRoot,
423 sal_uInt16 nFrType, sal_uInt16 nRecId, std::size_t nRecSize ) :
424 XclExpRecord( nRecId, nRecSize ),
425 XclExpChRoot( rRoot ),
426 maFrBlock( nFrType )
427{
428}
429
430XclExpChGroupBase::~XclExpChGroupBase()
431{
432}
433
434void XclExpChGroupBase::Save( XclExpStream& rStrm )
435{
436 // header record
437 XclExpRecord::Save( rStrm );
438 // group records
439 if( !HasSubRecords() )
440 return;
441
442 // register the future record context corresponding to this record group
443 RegisterFutureRecBlock( maFrBlock );
444 // CHBEGIN record
445 XclExpEmptyRecord( EXC_ID_CHBEGIN ).Save( rStrm );
446 // embedded records
447 WriteSubRecords( rStrm );
448 // finalize the future records, must be done before the closing CHEND
449 FinalizeFutureRecBlock( rStrm );
450 // CHEND record
451 XclExpEmptyRecord( EXC_ID_CHEND ).Save( rStrm );
452}
453
454bool XclExpChGroupBase::HasSubRecords() const
455{
456 return true;
457}
458
459void XclExpChGroupBase::SetFutureRecordContext( sal_uInt16 nFrContext, sal_uInt16 nFrValue1, sal_uInt16 nFrValue2 )
460{
461 maFrBlock.mnContext = nFrContext;
462 maFrBlock.mnValue1 = nFrValue1;
463 maFrBlock.mnValue2 = nFrValue2;
464}
465
466XclExpChFutureRecordBase::XclExpChFutureRecordBase( const XclExpChRoot& rRoot,
467 XclFutureRecType eRecType, sal_uInt16 nRecId, std::size_t nRecSize ) :
468 XclExpFutureRecord( eRecType, nRecId, nRecSize ),
469 XclExpChRoot( rRoot )
470{
471}
472
473void XclExpChFutureRecordBase::Save( XclExpStream& rStrm )
474{
475 InitializeFutureRecBlock( rStrm );
476 XclExpFutureRecord::Save( rStrm );
477}
478
479// Frame formatting ===========================================================
480
481XclExpChFramePos::XclExpChFramePos( sal_uInt16 nTLMode ) :
482 XclExpRecord( EXC_ID_CHFRAMEPOS, 20 )
483{
484 maData.mnTLMode = nTLMode;
485 maData.mnBRMode = EXC_CHFRAMEPOS_PARENT;
486}
487
488void XclExpChFramePos::WriteBody( XclExpStream& rStrm )
489{
490 rStrm << maData.mnTLMode << maData.mnBRMode << maData.maRect;
491}
492
493XclExpChLineFormat::XclExpChLineFormat( const XclExpChRoot& rRoot ) :
494 XclExpRecord( EXC_ID_CHLINEFORMAT, (rRoot.GetBiff() == EXC_BIFF8) ? 12 : 10 ),
495 mnColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWTEXT ) )
496{
497}
498
499void XclExpChLineFormat::SetDefault( XclChFrameType eDefFrameType )
500{
501 switch( eDefFrameType )
502 {
503 case EXC_CHFRAMETYPE_AUTO:
504 SetAuto( true );
505 break;
506 case EXC_CHFRAMETYPE_INVISIBLE:
507 SetAuto( false );
508 maData.mnPattern = EXC_CHLINEFORMAT_NONE;
509 break;
510 default:
511 OSL_FAIL( "XclExpChLineFormat::SetDefault - unknown frame type" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/filter/excel/xechart.cxx"
":" "511" ": "), "%s", "XclExpChLineFormat::SetDefault - unknown frame type"
); } } while (false)
;
512 }
513}
514
515void XclExpChLineFormat::Convert( const XclExpChRoot& rRoot,
516 const ScfPropertySet& rPropSet, XclChObjectType eObjType )
517{
518 const XclChFormatInfo& rFmtInfo = rRoot.GetFormatInfo( eObjType );
519 rRoot.ConvertLineFormat( maData, rPropSet, rFmtInfo.mePropMode );
520 if( HasLine() )
521 {
522 // detect system color, set color identifier (TODO: detect automatic series line)
523 if( (eObjType != EXC_CHOBJTYPE_LINEARSERIES) && rRoot.IsSystemColor( maData.maColor, rFmtInfo.mnAutoLineColorIdx ) )
524 {
525 // store color index from automatic format data
526 mnColorId = XclExpPalette::GetColorIdFromIndex( rFmtInfo.mnAutoLineColorIdx );
527 // try to set automatic mode
528 bool bAuto = (maData.mnPattern == EXC_CHLINEFORMAT_SOLID) && (maData.mnWeight == rFmtInfo.mnAutoLineWeight);
529 ::set_flag( maData.mnFlags, EXC_CHLINEFORMAT_AUTO, bAuto );
530 }
531 else
532 {
533 // user defined color - register in palette
534 mnColorId = rRoot.GetPalette().InsertColor( maData.maColor, EXC_COLOR_CHARTLINE );
535 }
536 }
537 else
538 {
539 // no line - set default system color
540 rRoot.SetSystemColor( maData.maColor, mnColorId, EXC_COLOR_CHWINDOWTEXT );
541 }
542}
543
544bool XclExpChLineFormat::IsDefault( XclChFrameType eDefFrameType ) const
545{
546 return
547 ((eDefFrameType == EXC_CHFRAMETYPE_INVISIBLE) && !HasLine()) ||
548 ((eDefFrameType == EXC_CHFRAMETYPE_AUTO) && IsAuto());
549}
550
551void XclExpChLineFormat::WriteBody( XclExpStream& rStrm )
552{
553 rStrm << maData.maColor << maData.mnPattern << maData.mnWeight << maData.mnFlags;
554 if( rStrm.GetRoot().GetBiff() == EXC_BIFF8 )
555 rStrm << rStrm.GetRoot().GetPalette().GetColorIndex( mnColorId );
556}
557
558namespace {
559
560/** Creates a CHLINEFORMAT record from the passed property set. */
561XclExpChLineFormatRef lclCreateLineFormat( const XclExpChRoot& rRoot,
562 const ScfPropertySet& rPropSet, XclChObjectType eObjType )
563{
564 XclExpChLineFormatRef xLineFmt = new XclExpChLineFormat( rRoot );
565 xLineFmt->Convert( rRoot, rPropSet, eObjType );
566 const XclChFormatInfo& rFmtInfo = rRoot.GetFormatInfo( eObjType );
567 if( rFmtInfo.mbDeleteDefFrame && xLineFmt->IsDefault( rFmtInfo.meDefFrameType ) )
568 xLineFmt.clear();
569 return xLineFmt;
570}
571
572} // namespace
573
574XclExpChAreaFormat::XclExpChAreaFormat( const XclExpChRoot& rRoot ) :
575 XclExpRecord( EXC_ID_CHAREAFORMAT, (rRoot.GetBiff() == EXC_BIFF8) ? 16 : 12 ),
576 mnPattColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWBACK ) ),
577 mnBackColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWTEXT ) )
578{
579}
580
581bool XclExpChAreaFormat::Convert( const XclExpChRoot& rRoot,
582 const ScfPropertySet& rPropSet, XclChObjectType eObjType )
583{
584 const XclChFormatInfo& rFmtInfo = rRoot.GetFormatInfo( eObjType );
585 bool bComplexFill = rRoot.ConvertAreaFormat( maData, rPropSet, rFmtInfo.mePropMode );
586 if( HasArea() )
587 {
588 bool bSolid = maData.mnPattern == EXC_PATT_SOLID;
589 // detect system color, set color identifier (TODO: detect automatic series area)
590 if( (eObjType != EXC_CHOBJTYPE_FILLEDSERIES) && rRoot.IsSystemColor( maData.maPattColor, rFmtInfo.mnAutoPattColorIdx ) )
591 {
592 // store color index from automatic format data
593 mnPattColorId = XclExpPalette::GetColorIdFromIndex( rFmtInfo.mnAutoPattColorIdx );
594 // set automatic mode
595 ::set_flag( maData.mnFlags, EXC_CHAREAFORMAT_AUTO, bSolid );
596 }
597 else
598 {
599 // user defined color - register color in palette
600 mnPattColorId = rRoot.GetPalette().InsertColor( maData.maPattColor, EXC_COLOR_CHARTAREA );
601 }
602 // background color (default system color for solid fills)
603 if( bSolid )
604 rRoot.SetSystemColor( maData.maBackColor, mnBackColorId, EXC_COLOR_CHWINDOWTEXT );
605 else
606 mnBackColorId = rRoot.GetPalette().InsertColor( maData.maBackColor, EXC_COLOR_CHARTAREA );
607 }
608 else
609 {
610 // no area - set default system colors
611 rRoot.SetSystemColor( maData.maPattColor, mnPattColorId, EXC_COLOR_CHWINDOWBACK );
612 rRoot.SetSystemColor( maData.maBackColor, mnBackColorId, EXC_COLOR_CHWINDOWTEXT );
613 }
614 return bComplexFill;
615}
616
617void XclExpChAreaFormat::SetDefault( XclChFrameType eDefFrameType )
618{
619 switch( eDefFrameType )
620 {
621 case EXC_CHFRAMETYPE_AUTO:
622 SetAuto( true );
623 break;
624 case EXC_CHFRAMETYPE_INVISIBLE:
625 SetAuto( false );
626 maData.mnPattern = EXC_PATT_NONE;
627 break;
628 default:
629 OSL_FAIL( "XclExpChAreaFormat::SetDefault - unknown frame type" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/filter/excel/xechart.cxx"
":" "629" ": "), "%s", "XclExpChAreaFormat::SetDefault - unknown frame type"
); } } while (false)
;
630 }
631}
632
633bool XclExpChAreaFormat::IsDefault( XclChFrameType eDefFrameType ) const
634{
635 return
636 ((eDefFrameType == EXC_CHFRAMETYPE_INVISIBLE) && !HasArea()) ||
637 ((eDefFrameType == EXC_CHFRAMETYPE_AUTO) && IsAuto());
638}
639
640void XclExpChAreaFormat::WriteBody( XclExpStream& rStrm )
641{
642 rStrm << maData.maPattColor << maData.maBackColor << maData.mnPattern << maData.mnFlags;
643 if( rStrm.GetRoot().GetBiff() == EXC_BIFF8 )
644 {
645 const XclExpPalette& rPal = rStrm.GetRoot().GetPalette();
646 rStrm << rPal.GetColorIndex( mnPattColorId ) << rPal.GetColorIndex( mnBackColorId );
647 }
648}
649
650XclExpChEscherFormat::XclExpChEscherFormat( const XclExpChRoot& rRoot ) :
651 XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_UNKNOWN, EXC_ID_CHESCHERFORMAT ),
652 mnColor1Id( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWBACK ) ),
653 mnColor2Id( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWBACK ) )
654{
655 OSL_ENSURE_BIFF( GetBiff() == EXC_BIFF8 )do { if (true && (!(GetBiff() == EXC_BIFF8))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/filter/excel/xechart.cxx"
":" "655" ": "), "%s", "Unknown BIFF type!"); } } while (false
)
;
656}
657
658void XclExpChEscherFormat::Convert( const ScfPropertySet& rPropSet, XclChObjectType eObjType )
659{
660 const XclChFormatInfo& rFmtInfo = GetFormatInfo( eObjType );
661 ConvertEscherFormat( maData, maPicFmt, rPropSet, rFmtInfo.mePropMode );
662 // register colors in palette
663 mnColor1Id = RegisterColor( ESCHER_Prop_fillColor385 );
664 mnColor2Id = RegisterColor( ESCHER_Prop_fillBackColor387 );
665}
666
667bool XclExpChEscherFormat::IsValid() const
668{
669 return static_cast< bool >(maData.mxEscherSet);
670}
671
672void XclExpChEscherFormat::Save( XclExpStream& rStrm )
673{
674 if( maData.mxEscherSet )
675 {
676 // replace RGB colors with palette indexes in the Escher container
677 const XclExpPalette& rPal = GetPalette();
678 maData.mxEscherSet->AddOpt( ESCHER_Prop_fillColor385, 0x08000000 | rPal.GetColorIndex( mnColor1Id ) );
679 maData.mxEscherSet->AddOpt( ESCHER_Prop_fillBackColor387, 0x08000000 | rPal.GetColorIndex( mnColor2Id ) );
680
681 // save the record group
682 XclExpChGroupBase::Save( rStrm );
683 }
684}
685
686bool XclExpChEscherFormat::HasSubRecords() const
687{
688 // no subrecords for gradients
689 return maPicFmt.mnBmpMode != EXC_CHPICFORMAT_NONE;
690}
691
692void XclExpChEscherFormat::WriteSubRecords( XclExpStream& rStrm )
693{
694 rStrm.StartRecord( EXC_ID_CHPICFORMAT, 14 );
695 rStrm << maPicFmt.mnBmpMode << sal_uInt16( 0 ) << maPicFmt.mnFlags << maPicFmt.mfScale;
696 rStrm.EndRecord();
697}
698
699sal_uInt32 XclExpChEscherFormat::RegisterColor( sal_uInt16 nPropId )
700{
701 sal_uInt32 nBGRValue;
702 if( maData.mxEscherSet && maData.mxEscherSet->GetOpt( nPropId, nBGRValue ) )
703 {
704 // swap red and blue
705 Color aColor( nBGRValue & 0xff, (nBGRValue >> 8) & 0xff, (nBGRValue >> 16) & 0xff );
706 return GetPalette().InsertColor( aColor, EXC_COLOR_CHARTAREA );
707 }
708 return XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWBACK );
709}
710
711void XclExpChEscherFormat::WriteBody( XclExpStream& rStrm )
712{
713 OSL_ENSURE( maData.mxEscherSet, "XclExpChEscherFormat::WriteBody - missing property container" )do { if (true && (!(maData.mxEscherSet))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/filter/excel/xechart.cxx"
":" "713" ": "), "%s", "XclExpChEscherFormat::WriteBody - missing property container"
); } } while (false)
;
714 // write Escher property container via temporary memory stream
715 SvMemoryStream aMemStrm;
716 maData.mxEscherSet->Commit( aMemStrm );
717 aMemStrm.Flush();
718 aMemStrm.Seek( STREAM_SEEK_TO_BEGIN0L );
719 rStrm.CopyFromStream( aMemStrm );
720}
721
722XclExpChFrameBase::XclExpChFrameBase()
723{
724}
725
726XclExpChFrameBase::~XclExpChFrameBase()
727{
728}
729
730void XclExpChFrameBase::ConvertFrameBase( const XclExpChRoot& rRoot,
731 const ScfPropertySet& rPropSet, XclChObjectType eObjType )
732{
733 // line format
734 mxLineFmt = new XclExpChLineFormat( rRoot );
735 mxLineFmt->Convert( rRoot, rPropSet, eObjType );
736 // area format (only for frame objects)
737 if( !rRoot.GetFormatInfo( eObjType ).mbIsFrame )
738 return;
739
740 mxAreaFmt = new XclExpChAreaFormat( rRoot );
741 bool bComplexFill = mxAreaFmt->Convert( rRoot, rPropSet, eObjType );
742 if( (rRoot.GetBiff() == EXC_BIFF8) && bComplexFill )
743 {
744 mxEscherFmt = new XclExpChEscherFormat( rRoot );
745 mxEscherFmt->Convert( rPropSet, eObjType );
746 if( mxEscherFmt->IsValid() )
747 mxAreaFmt->SetAuto( false );
748 else
749 mxEscherFmt.clear();
750 }
751}
752
753void XclExpChFrameBase::SetDefaultFrameBase( const XclExpChRoot& rRoot,
754 XclChFrameType eDefFrameType, bool bIsFrame )
755{
756 // line format
757 mxLineFmt = new XclExpChLineFormat( rRoot );
758 mxLineFmt->SetDefault( eDefFrameType );
759 // area format (only for frame objects)
760 if( bIsFrame )
761 {
762 mxAreaFmt = new XclExpChAreaFormat( rRoot );
763 mxAreaFmt->SetDefault( eDefFrameType );
764 mxEscherFmt.clear();
765 }
766}
767
768bool XclExpChFrameBase::IsDefaultFrameBase( XclChFrameType eDefFrameType ) const
769{
770 return
771 (!mxLineFmt || mxLineFmt->IsDefault( eDefFrameType )) &&
772 (!mxAreaFmt || mxAreaFmt->IsDefault( eDefFrameType ));
773}
774
775void XclExpChFrameBase::WriteFrameRecords( XclExpStream& rStrm )
776{
777 lclSaveRecord( rStrm, mxLineFmt );
778 lclSaveRecord( rStrm, mxAreaFmt );
779 lclSaveRecord( rStrm, mxEscherFmt );
780}
781
782XclExpChFrame::XclExpChFrame( const XclExpChRoot& rRoot, XclChObjectType eObjType ) :
783 XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_FRAME, EXC_ID_CHFRAME, 4 ),
784 meObjType( eObjType )
785{
786}
787
788void XclExpChFrame::Convert( const ScfPropertySet& rPropSet )
789{
790 ConvertFrameBase( GetChRoot(), rPropSet, meObjType );
791}
792
793void XclExpChFrame::SetAutoFlags( bool bAutoPos, bool bAutoSize )
794{
795 ::set_flag( maData.mnFlags, EXC_CHFRAME_AUTOPOS, bAutoPos );
796 ::set_flag( maData.mnFlags, EXC_CHFRAME_AUTOSIZE, bAutoSize );
797}
798
799bool XclExpChFrame::IsDefault() const
800{
801 return IsDefaultFrameBase( GetFormatInfo( meObjType ).meDefFrameType );
802}
803
804bool XclExpChFrame::IsDeleteable() const
805{
806 return IsDefault() && GetFormatInfo( meObjType ).mbDeleteDefFrame;
807}
808
809void XclExpChFrame::Save( XclExpStream& rStrm )
810{
811 switch( meObjType )
812 {
813 // wall/floor frame without CHFRAME header record
814 case EXC_CHOBJTYPE_WALL3D:
815 case EXC_CHOBJTYPE_FLOOR3D:
816 WriteFrameRecords( rStrm );
817 break;
818 default:
819 XclExpChGroupBase::Save( rStrm );
820 }
821}
822
823void XclExpChFrame::WriteSubRecords( XclExpStream& rStrm )
824{
825 WriteFrameRecords( rStrm );
826}
827
828void XclExpChFrame::WriteBody( XclExpStream& rStrm )
829{
830 rStrm << maData.mnFormat << maData.mnFlags;
831}
832
833namespace {
834
835/** Creates a CHFRAME record from the passed property set. */
836XclExpChFrameRef lclCreateFrame( const XclExpChRoot& rRoot,
837 const ScfPropertySet& rPropSet, XclChObjectType eObjType )
838{
839 XclExpChFrameRef xFrame = new XclExpChFrame( rRoot, eObjType );
840 xFrame->Convert( rPropSet );
841 if( xFrame->IsDeleteable() )
842 xFrame.clear();
843 return xFrame;
844}
845
846} // namespace
847
848// Source links ===============================================================
849
850namespace {
851
852void lclAddDoubleRefData(
853 ScTokenArray& orArray, const FormulaToken& rToken,
854 SCTAB nScTab1, SCCOL nScCol1, SCROW nScRow1,
855 SCTAB nScTab2, SCCOL nScCol2, SCROW nScRow2 )
856{
857 ScComplexRefData aComplexRef;
858 aComplexRef.InitRange(ScRange(nScCol1,nScRow1,nScTab1,nScCol2,nScRow2,nScTab2));
859 aComplexRef.Ref1.SetFlag3D( true );
860
861 if( orArray.GetLen() > 0 )
862 orArray.AddOpCode( ocUnion );
863
864 OSL_ENSURE( (rToken.GetType() == ::formula::svDoubleRef) || (rToken.GetType() == ::formula::svExternalDoubleRef),do { if (true && (!((rToken.GetType() == ::formula::svDoubleRef
) || (rToken.GetType() == ::formula::svExternalDoubleRef)))) {
sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sc/source/filter/excel/xechart.cxx"
":" "865" ": "), "%s", "lclAddDoubleRefData - double reference token expected"
); } } while (false)
865 "lclAddDoubleRefData - double reference token expected")do { if (true && (!((rToken.GetType() == ::formula::svDoubleRef
) || (rToken.GetType() == ::formula::svExternalDoubleRef)))) {
sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sc/source/filter/excel/xechart.cxx"
":" "865" ": "), "%s", "lclAddDoubleRefData - double reference token expected"
); } } while (false)
;
866 if( rToken.GetType() == ::formula::svExternalDoubleRef )
867 orArray.AddExternalDoubleReference(
868 rToken.GetIndex(), rToken.GetString(), aComplexRef);
869 else
870 orArray.AddDoubleReference( aComplexRef );
871}
872
873} // namespace
874
875XclExpChSourceLink::XclExpChSourceLink( const XclExpChRoot& rRoot, sal_uInt8 nDestType ) :
876 XclExpRecord( EXC_ID_CHSOURCELINK ),
877 XclExpChRoot( rRoot )
878{
879 maData.mnDestType = nDestType;
880 maData.mnLinkType = EXC_CHSRCLINK_DIRECTLY;
881}
882
883sal_uInt16 XclExpChSourceLink::ConvertDataSequence( Reference< XDataSequence > const & xDataSeq, bool bSplitToColumns, sal_uInt16 nDefCount )
884{
885 mxLinkFmla.reset();
886 maData.mnLinkType = EXC_CHSRCLINK_DEFAULT;
887
888 if( !xDataSeq.is() )
889 return nDefCount;
890
891 // Compile the range representation string into token array. Note that the
892 // source range text depends on the current grammar.
893 OUString aRangeRepr = xDataSeq->getSourceRangeRepresentation();
894 ScCompiler aComp( GetDoc(), ScAddress(), GetDoc().GetGrammar() );
895 std::unique_ptr<ScTokenArray> pArray(aComp.CompileString(aRangeRepr));
896 if( !pArray )
897 return nDefCount;
898
899 ScTokenArray aArray(GetRoot().GetDoc());
900 sal_uInt32 nValueCount = 0;
901 FormulaTokenArrayPlainIterator aIter(*pArray);
902 for( const FormulaToken* pToken = aIter.First(); pToken; pToken = aIter.Next() )
903 {
904 switch( pToken->GetType() )
905 {
906 case ::formula::svSingleRef:
907 case ::formula::svExternalSingleRef:
908 // for a single ref token, just add it to the new token array as is
909 if( aArray.GetLen() > 0 )
910 aArray.AddOpCode( ocUnion );
911 aArray.AddToken( *pToken );
912 ++nValueCount;
913 break;
914
915 case ::formula::svDoubleRef:
916 case ::formula::svExternalDoubleRef:
917 {
918 // split 3-dimensional ranges into single sheets
919 const ScComplexRefData& rComplexRef = *pToken->GetDoubleRef();
920 ScAddress aAbs1 = rComplexRef.Ref1.toAbs(GetRoot().GetDoc(), ScAddress());
921 ScAddress aAbs2 = rComplexRef.Ref2.toAbs(GetRoot().GetDoc(), ScAddress());
922 for (SCTAB nScTab = aAbs1.Tab(); nScTab <= aAbs2.Tab(); ++nScTab)
923 {
924 // split 2-dimensional ranges into single columns
925 if (bSplitToColumns && (aAbs1.Col() < aAbs2.Col()) && (aAbs1.Row() < aAbs2.Row()))
926 for (SCCOL nScCol = aAbs1.Col(); nScCol <= aAbs2.Col(); ++nScCol)
927 lclAddDoubleRefData(aArray, *pToken, nScTab, nScCol, aAbs1.Row(), nScTab, nScCol, aAbs2.Row());
928 else
929 lclAddDoubleRefData(aArray, *pToken, nScTab, aAbs1.Col(), aAbs1.Row(), nScTab, aAbs2.Col(), aAbs2.Row());
930 }
931 sal_uInt32 nTabs = static_cast<sal_uInt32>(aAbs2.Tab() - aAbs1.Tab() + 1);
932 sal_uInt32 nCols = static_cast<sal_uInt32>(aAbs2.Col() - aAbs1.Col() + 1);
933 sal_uInt32 nRows = static_cast<sal_uInt32>(aAbs2.Row() - aAbs1.Row() + 1);
934 nValueCount += nCols * nRows * nTabs;
935 }
936 break;
937
938 default:;
939 }
940 }
941
942 const ScAddress aBaseCell;
943 mxLinkFmla = GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_CHART, aArray, &aBaseCell );
944 maData.mnLinkType = EXC_CHSRCLINK_WORKSHEET;
945 return ulimit_cast< sal_uInt16 >( nValueCount, EXC_CHDATAFORMAT_MAXPOINTCOUNT );
946}
947
948void XclExpChSourceLink::ConvertString( const OUString& aString )
949{
950 mxString = XclExpStringHelper::CreateString( GetRoot(), aString, XclStrFlags::ForceUnicode | XclStrFlags::EightBitLength | XclStrFlags::SeparateFormats );
951}
952
953sal_uInt16 XclExpChSourceLink::ConvertStringSequence( const Sequence< Reference< XFormattedString > >& rStringSeq )
954{
955 mxString.reset();
956 sal_uInt16 nFontIdx = EXC_FONT_APP;
957 if( rStringSeq.hasElements() )
958 {
959 mxString = XclExpStringHelper::CreateString( GetRoot(), OUString(), XclStrFlags::ForceUnicode | XclStrFlags::EightBitLength | XclStrFlags::SeparateFormats );
960 Reference< XBreakIterator > xBreakIt = GetDoc().GetBreakIterator();
961 namespace ApiScriptType = ::com::sun::star::i18n::ScriptType;
962
963 // convert all formatted string entries from the sequence
964 for( const Reference< XFormattedString >& rString : rStringSeq )
965 {
966 if( rString.is() )
967 {
968 sal_uInt16 nWstrnFontIdx = EXC_FONT_NOTFOUND;
969 sal_uInt16 nAsianFontIdx = EXC_FONT_NOTFOUND;
970 sal_uInt16 nCmplxFontIdx = EXC_FONT_NOTFOUND;
971 OUString aText = rString->getString();
972 ScfPropertySet aStrProp( rString );
973
974 // #i63255# get script type for leading weak characters
975 sal_Int16 nLastScript = XclExpStringHelper::GetLeadingScriptType( GetRoot(), aText );
976
977 // process all script portions
978 sal_Int32 nPortionPos = 0;
979 sal_Int32 nTextLen = aText.getLength();
980 while( nPortionPos < nTextLen )
981 {
982 // get script type and end position of next script portion
983 sal_Int16 nScript = xBreakIt->getScriptType( aText, nPortionPos );
984 sal_Int32 nPortionEnd = xBreakIt->endOfScript( aText, nPortionPos, nScript );
985
986 // reuse previous script for following weak portions
987 if( nScript == ApiScriptType::WEAK )
988 nScript = nLastScript;
989
990 // Excel start position of this portion
991 sal_uInt16 nXclPortionStart = mxString->Len();
992 // add portion text to Excel string
993 XclExpStringHelper::AppendString( *mxString, GetRoot(), aText.copy( nPortionPos, nPortionEnd - nPortionPos ) );
994 if( nXclPortionStart < mxString->Len() )
995 {
996 // find font index variable dependent on script type
997 sal_uInt16& rnFontIdx = (nScript == ApiScriptType::COMPLEX) ? nCmplxFontIdx :
998 ((nScript == ApiScriptType::ASIAN) ? nAsianFontIdx : nWstrnFontIdx);
999
1000 // insert font into buffer (if not yet done)
1001 if( rnFontIdx == EXC_FONT_NOTFOUND )
1002 rnFontIdx = ConvertFont( aStrProp, nScript );
1003
1004 // insert font index into format run vector
1005 mxString->AppendFormat( nXclPortionStart, rnFontIdx );
1006 }
1007
1008 // go to next script portion
1009 nLastScript = nScript;
1010 nPortionPos = nPortionEnd;
1011 }
1012 }
1013 }
1014 if( !mxString->IsEmpty() )
1015 {
1016 // get leading font index
1017 const XclFormatRunVec& rFormats = mxString->GetFormats();
1018 OSL_ENSURE( !rFormats.empty() && (rFormats.front().mnChar == 0),do { if (true && (!(!rFormats.empty() && (rFormats
.front().mnChar == 0)))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/filter/excel/xechart.cxx"
":" "1019" ": "), "%s", "XclExpChSourceLink::ConvertStringSequenc - missing leading format"
); } } while (false)
1019 "XclExpChSourceLink::ConvertStringSequenc - missing leading format" )do { if (true && (!(!rFormats.empty() && (rFormats
.front().mnChar == 0)))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/filter/excel/xechart.cxx"
":" "1019" ": "), "%s", "XclExpChSourceLink::ConvertStringSequenc - missing leading format"
); } } while (false)
;
1020 // remove leading format run, if entire string is equally formatted
1021 if( rFormats.size() == 1 )
1022 nFontIdx = mxString->RemoveLeadingFont();
1023 else if( !rFormats.empty() )
1024 nFontIdx = rFormats.front().mnFontIdx;
1025 // add trailing format run, if string is rich-formatted
1026 if( mxString->IsRich() )
1027 mxString->AppendTrailingFormat( EXC_FONT_APP );
1028 }
1029 }
1030 return nFontIdx;
1031}
1032
1033void XclExpChSourceLink::ConvertNumFmt( const ScfPropertySet& rPropSet, bool bPercent )
1034{
1035 sal_Int32 nApiNumFmt = 0;
1036 if( bPercent ? rPropSet.GetProperty( nApiNumFmt, EXC_CHPROP_PERCENTAGENUMFMT"PercentageNumberFormat" ) : rPropSet.GetProperty( nApiNumFmt, EXC_CHPROP_NUMBERFORMAT"NumberFormat" ) )
1037 {
1038 ::set_flag( maData.mnFlags, EXC_CHSRCLINK_NUMFMT );
1039 maData.mnNumFmtIdx = GetNumFmtBuffer().Insert( static_cast< sal_uInt32 >( nApiNumFmt ) );
1040 }
1041}
1042
1043void XclExpChSourceLink::AppendString( const OUString& rStr )
1044{
1045 if (!mxString)
1046 return;
1047 XclExpStringHelper::AppendString( *mxString, GetRoot(), rStr );
1048}
1049
1050void XclExpChSourceLink::Save( XclExpStream& rStrm )
1051{
1052 // CHFORMATRUNS record
1053 if( mxString && mxString->IsRich() )
1054 {
1055 std::size_t nRecSize = (1 + mxString->GetFormatsCount()) * ((GetBiff() == EXC_BIFF8) ? 2 : 1);
1056 rStrm.StartRecord( EXC_ID_CHFORMATRUNS, nRecSize );
1057 mxString->WriteFormats( rStrm, true );
1058 rStrm.EndRecord();
1059 }
1060 // CHSOURCELINK record
1061 XclExpRecord::Save( rStrm );
1062 // CHSTRING record
1063 if( mxString && !mxString->IsEmpty() )
1064 {
1065 rStrm.StartRecord( EXC_ID_CHSTRING, 2 + mxString->GetSize() );
1066 rStrm << sal_uInt16( 0 ) << *mxString;
1067 rStrm.EndRecord();
1068 }
1069}
1070
1071void XclExpChSourceLink::WriteBody( XclExpStream& rStrm )
1072{
1073 rStrm << maData.mnDestType
1074 << maData.mnLinkType
1075 << maData.mnFlags
1076 << maData.mnNumFmtIdx
1077 << mxLinkFmla;
1078}
1079
1080// Text =======================================================================
1081
1082XclExpChFont::XclExpChFont( sal_uInt16 nFontIdx ) :
1083 XclExpUInt16Record( EXC_ID_CHFONT, nFontIdx )
1084{
1085}
1086
1087XclExpChObjectLink::XclExpChObjectLink( sal_uInt16 nLinkTarget, const XclChDataPointPos& rPointPos ) :
1088 XclExpRecord( EXC_ID_CHOBJECTLINK, 6 )
1089{
1090 maData.mnTarget = nLinkTarget;
1091 maData.maPointPos = rPointPos;
1092}
1093
1094void XclExpChObjectLink::WriteBody( XclExpStream& rStrm )
1095{
1096 rStrm << maData.mnTarget << maData.maPointPos.mnSeriesIdx << maData.maPointPos.mnPointIdx;
1097}
1098
1099XclExpChFrLabelProps::XclExpChFrLabelProps( const XclExpChRoot& rRoot ) :
1100 XclExpChFutureRecordBase( rRoot, EXC_FUTUREREC_UNUSEDREF, EXC_ID_CHFRLABELPROPS, 4 )
1101{
1102}
1103
1104void XclExpChFrLabelProps::Convert( const ScfPropertySet& rPropSet,
1105 bool bShowCateg, bool bShowValue, bool bShowPercent, bool bShowBubble )
1106{
1107 // label value flags
1108 ::set_flag( maData.mnFlags, EXC_CHFRLABELPROPS_SHOWSERIES, false );
1109 ::set_flag( maData.mnFlags, EXC_CHFRLABELPROPS_SHOWCATEG, bShowCateg );
1110 ::set_flag( maData.mnFlags, EXC_CHFRLABELPROPS_SHOWVALUE, bShowValue );
1111 ::set_flag( maData.mnFlags, EXC_CHFRLABELPROPS_SHOWPERCENT, bShowPercent );
1112 ::set_flag( maData.mnFlags, EXC_CHFRLABELPROPS_SHOWBUBBLE, bShowBubble );
1113
1114 // label value separator
1115 maData.maSeparator = rPropSet.GetStringProperty( EXC_CHPROP_LABELSEPARATOR"LabelSeparator" );
1116 if( maData.maSeparator.isEmpty() )
1117 maData.maSeparator = " ";
1118}
1119
1120void XclExpChFrLabelProps::WriteBody( XclExpStream& rStrm )
1121{
1122 XclExpString aXclSep( maData.maSeparator, XclStrFlags::ForceUnicode | XclStrFlags::SmartFlags );
1123 rStrm << maData.mnFlags << aXclSep;
1124}
1125
1126XclExpChFontBase::~XclExpChFontBase()
1127{
1128}
1129
1130void XclExpChFontBase::ConvertFontBase( const XclExpChRoot& rRoot, sal_uInt16 nFontIdx )
1131{
1132 if( const XclExpFont* pFont = rRoot.GetFontBuffer().GetFont( nFontIdx ) )
1133 {
1134 XclExpChFontRef xFont = new XclExpChFont( nFontIdx );
1135 SetFont( xFont, pFont->GetFontData().maColor, pFont->GetFontColorId() );
1136 }
1137}
1138
1139void XclExpChFontBase::ConvertFontBase( const XclExpChRoot& rRoot, const ScfPropertySet& rPropSet )
1140{
1141 ConvertFontBase( rRoot, rRoot.ConvertFont( rPropSet, rRoot.GetDefApiScript() ) );
1142}
1143
1144void XclExpChFontBase::ConvertRotationBase(const ScfPropertySet& rPropSet, bool bSupportsStacked )
1145{
1146 sal_uInt16 nRotation = XclChPropSetHelper::ReadRotationProperties( rPropSet, bSupportsStacked );
1147 SetRotation( nRotation );
1148}
1149
1150XclExpChText::XclExpChText( const XclExpChRoot& rRoot ) :
1151 XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_TEXT, EXC_ID_CHTEXT, (rRoot.GetBiff() == EXC_BIFF8) ? 32 : 26 ),
1152 mnTextColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWTEXT ) )
1153{
1154}
1155
1156void XclExpChText::SetFont( XclExpChFontRef xFont, const Color& rColor, sal_uInt32 nColorId )
1157{
1158 mxFont = xFont;
1159 maData.maTextColor = rColor;
1160 ::set_flag( maData.mnFlags, EXC_CHTEXT_AUTOCOLOR, rColor == COL_AUTO );
1161 mnTextColorId = nColorId;
1162}
1163
1164void XclExpChText::SetRotation( sal_uInt16 nRotation )
1165{
1166 maData.mnRotation = nRotation;
1167 ::insert_value( maData.mnFlags, XclTools::GetXclOrientFromRot( nRotation ), 8, 3 );
1168}
1169
1170void XclExpChText::ConvertTitle( Reference< XTitle > const & xTitle, sal_uInt16 nTarget, const OUString* pSubTitle )
1171{
1172 switch( nTarget )
1173 {
1174 case EXC_CHOBJLINK_TITLE: SetFutureRecordContext( EXC_CHFRBLOCK_TEXT_TITLE ); break;
1175 case EXC_CHOBJLINK_YAXIS: SetFutureRecordContext( EXC_CHFRBLOCK_TEXT_AXISTITLE, 1 ); break;
1176 case EXC_CHOBJLINK_XAXIS: SetFutureRecordContext( EXC_CHFRBLOCK_TEXT_AXISTITLE ); break;
1177 case EXC_CHOBJLINK_ZAXIS: SetFutureRecordContext( EXC_CHFRBLOCK_TEXT_AXISTITLE, 2 ); break;
1178 }
1179
1180 mxSrcLink.clear();
1181 mxObjLink = new XclExpChObjectLink( nTarget, XclChDataPointPos( 0, 0 ) );
1182
1183 if( xTitle.is() )
1184 {
1185 // title frame formatting
1186 ScfPropertySet aTitleProp( xTitle );
1187 mxFrame = lclCreateFrame( GetChRoot(), aTitleProp, EXC_CHOBJTYPE_TEXT );
1188
1189 // string sequence
1190 mxSrcLink = new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_TITLE );
1191 sal_uInt16 nFontIdx = mxSrcLink->ConvertStringSequence( xTitle->getText() );
1192 if (pSubTitle)
1193 {
1194 // append subtitle as the 2nd line of the title.
1195 OUString aSubTitle = "\n" + *pSubTitle;
1196 mxSrcLink->AppendString(aSubTitle);
1197 }
1198
1199 ConvertFontBase( GetChRoot(), nFontIdx );
1200
1201 // rotation
1202 ConvertRotationBase( aTitleProp, true );
1203
1204 // manual text position - only for main title
1205 mxFramePos = new XclExpChFramePos( EXC_CHFRAMEPOS_PARENT );
1206 if( nTarget == EXC_CHOBJLINK_TITLE )
1207 {
1208 Any aRelPos;
1209 if( aTitleProp.GetAnyProperty( aRelPos, EXC_CHPROP_RELATIVEPOSITION"RelativePosition" ) && aRelPos.has< RelativePosition >() ) try
1210 {
1211 // calculate absolute position for CHTEXT record
1212 Reference< cssc::XChartDocument > xChart1Doc( GetChartDocument(), UNO_QUERY_THROW );
1213 Reference< XShape > xTitleShape( xChart1Doc->getTitle(), UNO_SET_THROW );
1214 css::awt::Point aPos = xTitleShape->getPosition();
1215 css::awt::Size aSize = xTitleShape->getSize();
1216 css::awt::Rectangle aRect( aPos.X, aPos.Y, aSize.Width, aSize.Height );
1217 maData.maRect = CalcChartRectFromHmm( aRect );
1218 ::insert_value( maData.mnFlags2, EXC_CHTEXT_POS_MOVED, 0, 4 );
1219 // manual title position implies manual plot area
1220 GetChartData().SetManualPlotArea();
1221 // calculate the default title position in chart units
1222 sal_Int32 nDefPosX = ::std::max< sal_Int32 >( (EXC_CHART_TOTALUNITS - maData.maRect.mnWidth) / 2, 0 );
1223 sal_Int32 nDefPosY = 85;
1224 // set the position relative to the standard position
1225 XclChRectangle& rFrameRect = mxFramePos->GetFramePosData().maRect;
1226 rFrameRect.mnX = maData.maRect.mnX - nDefPosX;
1227 rFrameRect.mnY = maData.maRect.mnY - nDefPosY;
1228 }
1229 catch( Exception& )
1230 {
1231 }
1232 }
1233 }
1234 else
1235 {
1236 ::set_flag( maData.mnFlags, EXC_CHTEXT_DELETED );
1237 }
1238}
1239
1240void XclExpChText::ConvertLegend( const ScfPropertySet& rPropSet )
1241{
1242 ::set_flag( maData.mnFlags, EXC_CHTEXT_AUTOTEXT );
1243 ::set_flag( maData.mnFlags, EXC_CHTEXT_AUTOGEN );
1244 ConvertFontBase( GetChRoot(), rPropSet );
1245}
1246
1247bool XclExpChText::ConvertDataLabel( const ScfPropertySet& rPropSet,
1248 const XclChTypeInfo& rTypeInfo, const XclChDataPointPos& rPointPos )
1249{
1250 SetFutureRecordContext( EXC_CHFRBLOCK_TEXT_DATALABEL, rPointPos.mnPointIdx, rPointPos.mnSeriesIdx );
1251
1252 cssc2::DataPointLabel aPointLabel;
1253 if( !rPropSet.GetProperty( aPointLabel, EXC_CHPROP_LABEL"Label" ) )
1254 return false;
1255
1256 // percentage only allowed in pie and donut charts
1257 bool bIsPie = rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_PIE;
1258 // bubble sizes only allowed in bubble charts
1259 bool bIsBubble = rTypeInfo.meTypeId == EXC_CHTYPEID_BUBBLES;
1260 OSL_ENSURE( (GetBiff() == EXC_BIFF8) || !bIsBubble, "XclExpChText::ConvertDataLabel - bubble charts only in BIFF8" )do { if (true && (!((GetBiff() == EXC_BIFF8) || !bIsBubble
))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sc/source/filter/excel/xechart.cxx"
":" "1260" ": "), "%s", "XclExpChText::ConvertDataLabel - bubble charts only in BIFF8"
); } } while (false)
;
1261
1262 // raw show flags
1263 bool bShowValue = !bIsBubble && aPointLabel.ShowNumber; // Chart2 uses 'ShowNumber' for bubble size
1264 bool bShowPercent = bIsPie && aPointLabel.ShowNumberInPercent; // percentage only in pie/donut charts
1265 bool bShowCateg = aPointLabel.ShowCategoryName;
1266 bool bShowBubble = bIsBubble && aPointLabel.ShowNumber; // Chart2 uses 'ShowNumber' for bubble size
1267 bool bShowAny = bShowValue || bShowPercent || bShowCateg || bShowBubble;
1268
1269 // create the CHFRLABELPROPS record for extended settings in BIFF8
1270 if( bShowAny && (GetBiff() == EXC_BIFF8) )
1271 {
1272 mxLabelProps = new XclExpChFrLabelProps( GetChRoot() );
1273 mxLabelProps->Convert( rPropSet, bShowCateg, bShowValue, bShowPercent, bShowBubble );
1274 }
1275
1276 // restrict to combinations allowed in CHTEXT
1277 if( bShowPercent ) bShowValue = false; // percent wins over value
1278 if( bShowValue ) bShowCateg = false; // value wins over category
1279 if( bShowValue || bShowCateg ) bShowBubble = false; // value or category wins over bubble size
1280
1281 // set all flags
1282 ::set_flag( maData.mnFlags, EXC_CHTEXT_AUTOTEXT );
1283 ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWVALUE, bShowValue );
1284 ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWPERCENT, bShowPercent );
1285 ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWCATEG, bShowCateg );
1286 ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWCATEGPERC, bShowPercent && bShowCateg );
1287 ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWBUBBLE, bShowBubble );
1288 ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWSYMBOL, bShowAny && aPointLabel.ShowLegendSymbol );
1289 ::set_flag( maData.mnFlags, EXC_CHTEXT_DELETED, !bShowAny );
1290
1291 if( bShowAny )
1292 {
1293 // font settings
1294 ConvertFontBase( GetChRoot(), rPropSet );
1295 ConvertRotationBase( rPropSet, false );
1296 // label placement
1297 sal_Int32 nPlacement = 0;
1298 sal_uInt16 nLabelPos = EXC_CHTEXT_POS_AUTO;
1299 if( rPropSet.GetProperty( nPlacement, EXC_CHPROP_LABELPLACEMENT"LabelPlacement" ) )
1300 {
1301 using namespace cssc::DataLabelPlacement;
1302 if( nPlacement == rTypeInfo.mnDefaultLabelPos )
1303 {
1304 nLabelPos = EXC_CHTEXT_POS_DEFAULT;
1305 }
1306 else switch( nPlacement )
1307 {
1308 case AVOID_OVERLAP: nLabelPos = EXC_CHTEXT_POS_AUTO; break;
1309 case CENTER: nLabelPos = EXC_CHTEXT_POS_CENTER; break;
1310 case TOP: nLabelPos = EXC_CHTEXT_POS_ABOVE; break;
1311 case TOP_LEFT: nLabelPos = EXC_CHTEXT_POS_LEFT; break;
1312 case LEFT: nLabelPos = EXC_CHTEXT_POS_LEFT; break;
1313 case BOTTOM_LEFT: nLabelPos = EXC_CHTEXT_POS_LEFT; break;
1314 case BOTTOM: nLabelPos = EXC_CHTEXT_POS_BELOW; break;
1315 case BOTTOM_RIGHT: nLabelPos = EXC_CHTEXT_POS_RIGHT; break;
1316 case RIGHT: nLabelPos = EXC_CHTEXT_POS_RIGHT; break;
1317 case TOP_RIGHT: nLabelPos = EXC_CHTEXT_POS_RIGHT; break;
1318 case INSIDE: nLabelPos = EXC_CHTEXT_POS_INSIDE; break;
1319 case OUTSIDE: nLabelPos = EXC_CHTEXT_POS_OUTSIDE; break;
1320 case NEAR_ORIGIN: nLabelPos = EXC_CHTEXT_POS_AXIS; break;
1321 default: OSL_FAIL( "XclExpChText::ConvertDataLabel - unknown label placement type" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/filter/excel/xechart.cxx"
":" "1321" ": "), "%s", "XclExpChText::ConvertDataLabel - unknown label placement type"
); } } while (false)
;
1322 }
1323 }
1324 ::insert_value( maData.mnFlags2, nLabelPos, 0, 4 );
1325 // source link (contains number format)
1326 mxSrcLink = new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_TITLE );
1327 if( bShowValue || bShowPercent )
1328 // percentage format wins over value format
1329 mxSrcLink->ConvertNumFmt( rPropSet, bShowPercent );
1330 // object link
1331 mxObjLink = new XclExpChObjectLink( EXC_CHOBJLINK_DATA, rPointPos );
1332 }
1333
1334 /* Return true to indicate valid label settings:
1335 - for existing labels at entire series
1336 - for any settings at single data point (to be able to delete a point label) */
1337 return bShowAny || (rPointPos.mnPointIdx != EXC_CHDATAFORMAT_ALLPOINTS);
1338}
1339
1340void XclExpChText::ConvertTrendLineEquation( const ScfPropertySet& rPropSet, const XclChDataPointPos& rPointPos )
1341{
1342 // required flags
1343 ::set_flag( maData.mnFlags, EXC_CHTEXT_AUTOTEXT );
1344 if( GetBiff() == EXC_BIFF8 )
1345 ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWCATEG ); // must set this to make equation visible in Excel
1346 // frame formatting
1347 mxFrame = lclCreateFrame( GetChRoot(), rPropSet, EXC_CHOBJTYPE_TEXT );
1348 // font settings
1349 maData.mnHAlign = EXC_CHTEXT_ALIGN_TOPLEFT;
1350 maData.mnVAlign = EXC_CHTEXT_ALIGN_TOPLEFT;
1351 ConvertFontBase( GetChRoot(), rPropSet );
1352 // source link (contains number format)
1353 mxSrcLink = new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_TITLE );
1354 mxSrcLink->ConvertNumFmt( rPropSet, false );
1355 // object link
1356 mxObjLink = new XclExpChObjectLink( EXC_CHOBJLINK_DATA, rPointPos );
1357}
1358
1359sal_uInt16 XclExpChText::GetAttLabelFlags() const
1360{
1361 sal_uInt16 nFlags = 0;
1362 ::set_flag( nFlags, EXC_CHATTLABEL_SHOWVALUE, ::get_flag( maData.mnFlags, EXC_CHTEXT_SHOWVALUE ) );
1363 ::set_flag( nFlags, EXC_CHATTLABEL_SHOWPERCENT, ::get_flag( maData.mnFlags, EXC_CHTEXT_SHOWPERCENT ) );
1364 ::set_flag( nFlags, EXC_CHATTLABEL_SHOWCATEGPERC, ::get_flag( maData.mnFlags, EXC_CHTEXT_SHOWCATEGPERC ) );
1365 ::set_flag( nFlags, EXC_CHATTLABEL_SHOWCATEG, ::get_flag( maData.mnFlags, EXC_CHTEXT_SHOWCATEG ) );
1366 return nFlags;
1367}
1368
1369void XclExpChText::WriteSubRecords( XclExpStream& rStrm )
1370{
1371 // CHFRAMEPOS record
1372 lclSaveRecord( rStrm, mxFramePos );
1373 // CHFONT record
1374 lclSaveRecord( rStrm, mxFont );
1375 // CHSOURCELINK group
1376 lclSaveRecord( rStrm, mxSrcLink );
1377 // CHFRAME group
1378 lclSaveRecord( rStrm, mxFrame );
1379 // CHOBJECTLINK record
1380 lclSaveRecord( rStrm, mxObjLink );
1381 // CHFRLABELPROPS record
1382 lclSaveRecord( rStrm, mxLabelProps );
1383}
1384
1385void XclExpChText::WriteBody( XclExpStream& rStrm )
1386{
1387 rStrm << maData.mnHAlign
1388 << maData.mnVAlign
1389 << maData.mnBackMode
1390 << maData.maTextColor
1391 << maData.maRect
1392 << maData.mnFlags;
1393
1394 if( GetBiff() == EXC_BIFF8 )
1395 {
1396 rStrm << GetPalette().GetColorIndex( mnTextColorId )
1397 << maData.mnFlags2
1398 << maData.mnRotation;
1399 }
1400}
1401
1402namespace {
1403
1404/** Creates and returns an Excel text object from the passed title. */
1405XclExpChTextRef lclCreateTitle( const XclExpChRoot& rRoot, Reference< XTitled > const & xTitled, sal_uInt16 nTarget,
1406 const OUString* pSubTitle = nullptr )
1407{
1408 Reference< XTitle > xTitle;
1409 if( xTitled.is() )
1410 xTitle = xTitled->getTitleObject();
1411
1412 XclExpChTextRef xText = new XclExpChText( rRoot );
1413 xText->ConvertTitle( xTitle, nTarget, pSubTitle );
1414 /* Do not delete the CHTEXT group for the main title. A missing CHTEXT
1415 will be interpreted as auto-generated title showing the series title in
1416 charts that contain exactly one data series. */
1417 if( (nTarget != EXC_CHOBJLINK_TITLE) && !xText->HasString() )
1418 xText.clear();
1419
1420 return xText;
1421}
1422
1423}
1424
1425// Data series ================================================================
1426
1427XclExpChMarkerFormat::XclExpChMarkerFormat( const XclExpChRoot& rRoot ) :
1428 XclExpRecord( EXC_ID_CHMARKERFORMAT, (rRoot.GetBiff() == EXC_BIFF8) ? 20 : 12 ),
1429 mnLineColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWTEXT ) ),
1430 mnFillColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWBACK ) )
1431{
1432}
1433
1434void XclExpChMarkerFormat::Convert( const XclExpChRoot& rRoot,
1435 const ScfPropertySet& rPropSet, sal_uInt16 nFormatIdx )
1436{
1437 XclChPropSetHelper::ReadMarkerProperties( maData, rPropSet, nFormatIdx );
1438 /* Set marker line/fill color to series line color.
1439 TODO: remove this if OOChart supports own colors in markers. */
1440 Color aLineColor;
1441 if( rPropSet.GetColorProperty( aLineColor, EXC_CHPROP_COLOR"Color" ) )
1442 maData.maLineColor = maData.maFillColor = aLineColor;
1443 // register colors in palette
1444 RegisterColors( rRoot );
1445}
1446
1447void XclExpChMarkerFormat::ConvertStockSymbol( const XclExpChRoot& rRoot,
1448 const ScfPropertySet& rPropSet, bool bCloseSymbol )
1449{
1450 // clear the automatic flag
1451 ::set_flag( maData.mnFlags, EXC_CHMARKERFORMAT_AUTO, false );
1452 // symbol type and color
1453 if( bCloseSymbol )
1454 {
1455 // set symbol type for the 'close' data series
1456 maData.mnMarkerType = EXC_CHMARKERFORMAT_DOWJ;
1457 maData.mnMarkerSize = EXC_CHMARKERFORMAT_DOUBLESIZE;
1458 // set symbol line/fill color to series line color
1459 Color aLineColor;
1460 if( rPropSet.GetColorProperty( aLineColor, EXC_CHPROP_COLOR"Color" ) )
1461 {
1462 maData.maLineColor = maData.maFillColor = aLineColor;
1463 RegisterColors( rRoot );
1464 }
1465 }
1466 else
1467 {
1468 // set invisible symbol
1469 maData.mnMarkerType = EXC_CHMARKERFORMAT_NOSYMBOL;
1470 }
1471}
1472
1473void XclExpChMarkerFormat::RegisterColors( const XclExpChRoot& rRoot )
1474{
1475 if( HasMarker() )
1476 {
1477 if( HasLineColor() )
1478 mnLineColorId = rRoot.GetPalette().InsertColor( maData.maLineColor, EXC_COLOR_CHARTLINE );
1479 if( HasFillColor() )
1480 mnFillColorId = rRoot.GetPalette().InsertColor( maData.maFillColor, EXC_COLOR_CHARTAREA );
1481 }
1482}
1483
1484void XclExpChMarkerFormat::WriteBody( XclExpStream& rStrm )
1485{
1486 rStrm << maData.maLineColor << maData.maFillColor << maData.mnMarkerType << maData.mnFlags;
1487 if( rStrm.GetRoot().GetBiff() == EXC_BIFF8 )
1488 {
1489 const XclExpPalette& rPal = rStrm.GetRoot().GetPalette();
1490 rStrm << rPal.GetColorIndex( mnLineColorId ) << rPal.GetColorIndex( mnFillColorId ) << maData.mnMarkerSize;
1491 }
1492}
1493
1494XclExpChPieFormat::XclExpChPieFormat() :
1495 XclExpUInt16Record( EXC_ID_CHPIEFORMAT, 0 )
1496{
1497}
1498
1499void XclExpChPieFormat::Convert( const ScfPropertySet& rPropSet )
1500{
1501 double fApiDist(0.0);
1502 if( rPropSet.GetProperty( fApiDist, EXC_CHPROP_OFFSET"Offset" ) )
1503 SetValue( limit_cast< sal_uInt16 >( fApiDist * 100.0, 0, 100 ) );
1504}
1505
1506XclExpCh3dDataFormat::XclExpCh3dDataFormat() :
1507 XclExpRecord( EXC_ID_CH3DDATAFORMAT, 2 )
1508{
1509}
1510
1511void XclExpCh3dDataFormat::Convert( const ScfPropertySet& rPropSet )
1512{
1513 sal_Int32 nApiType(0);
1514 if( !rPropSet.GetProperty( nApiType, EXC_CHPROP_GEOMETRY3D"Geometry3D" ) )
1515 return;
1516
1517 using namespace cssc2::DataPointGeometry3D;
1518 switch( nApiType )
1519 {
1520 case CUBOID:
1521 maData.mnBase = EXC_CH3DDATAFORMAT_RECT;
1522 maData.mnTop = EXC_CH3DDATAFORMAT_STRAIGHT;
1523 break;
1524 case PYRAMID:
1525 maData.mnBase = EXC_CH3DDATAFORMAT_RECT;
1526 maData.mnTop = EXC_CH3DDATAFORMAT_SHARP;
1527 break;
1528 case CYLINDER:
1529 maData.mnBase = EXC_CH3DDATAFORMAT_CIRC;
1530 maData.mnTop = EXC_CH3DDATAFORMAT_STRAIGHT;
1531 break;
1532 case CONE:
1533 maData.mnBase = EXC_CH3DDATAFORMAT_CIRC;
1534 maData.mnTop = EXC_CH3DDATAFORMAT_SHARP;
1535 break;
1536 default:
1537 OSL_FAIL( "XclExpCh3dDataFormat::Convert - unknown 3D bar format" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/filter/excel/xechart.cxx"
":" "1537" ": "), "%s", "XclExpCh3dDataFormat::Convert - unknown 3D bar format"
); } } while (false)
;
1538 }
1539}
1540
1541void XclExpCh3dDataFormat::WriteBody( XclExpStream& rStrm )
1542{
1543 rStrm << maData.mnBase << maData.mnTop;
1544}
1545
1546XclExpChAttachedLabel::XclExpChAttachedLabel( sal_uInt16 nFlags ) :
1547 XclExpUInt16Record( EXC_ID_CHATTACHEDLABEL, nFlags )
1548{
1549}
1550
1551XclExpChDataFormat::XclExpChDataFormat( const XclExpChRoot& rRoot,
1552 const XclChDataPointPos& rPointPos, sal_uInt16 nFormatIdx ) :
1553 XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_DATAFORMAT, EXC_ID_CHDATAFORMAT, 8 )
1554{
1555 maData.maPointPos = rPointPos;
1556 maData.mnFormatIdx = nFormatIdx;
1557}
1558
1559void XclExpChDataFormat::ConvertDataSeries( const ScfPropertySet& rPropSet, const XclChExtTypeInfo& rTypeInfo )
1560{
1561 // line and area formatting
1562 ConvertFrameBase( GetChRoot(), rPropSet, rTypeInfo.GetSeriesObjectType() );
1563
1564 // data point symbols
1565 bool bIsFrame = rTypeInfo.IsSeriesFrameFormat();
1566 if( !bIsFrame )
1567 {
1568 mxMarkerFmt = new XclExpChMarkerFormat( GetChRoot() );
1569 mxMarkerFmt->Convert( GetChRoot(), rPropSet, maData.mnFormatIdx );
1570 }
1571
1572 // pie segments
1573 if( rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_PIE )
1574 {
1575 mxPieFmt = new XclExpChPieFormat();
1576 mxPieFmt->Convert( rPropSet );
1577 }
1578
1579 // 3D bars (only allowed for entire series in BIFF8)
1580 if( IsSeriesFormat() && (GetBiff() == EXC_BIFF8) && rTypeInfo.mb3dChart && (rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_BAR) )
1581 {
1582 mx3dDataFmt = new XclExpCh3dDataFormat();
1583 mx3dDataFmt->Convert( rPropSet );
1584 }
1585
1586 // spline
1587 if( IsSeriesFormat() && rTypeInfo.mbSpline && !bIsFrame )
1588 mxSeriesFmt = new XclExpUInt16Record( EXC_ID_CHSERIESFORMAT, EXC_CHSERIESFORMAT_SMOOTHED );
1589
1590 // data point labels
1591 XclExpChTextRef xLabel = new XclExpChText( GetChRoot() );
1592 if( xLabel->ConvertDataLabel( rPropSet, rTypeInfo, maData.maPointPos ) )
1593 {
1594 // CHTEXT groups for data labels are stored in global CHCHART group
1595 GetChartData().SetDataLabel( xLabel );
1596 mxAttLabel = new XclExpChAttachedLabel( xLabel->GetAttLabelFlags() );
1597 }
1598}
1599
1600void XclExpChDataFormat::ConvertStockSeries( const ScfPropertySet& rPropSet, bool bCloseSymbol )
1601{
1602 // set line format to invisible
1603 SetDefaultFrameBase( GetChRoot(), EXC_CHFRAMETYPE_INVISIBLE, false );
1604 // set symbols to invisible or to 'close' series symbol
1605 mxMarkerFmt = new XclExpChMarkerFormat( GetChRoot() );
1606 mxMarkerFmt->ConvertStockSymbol( GetChRoot(), rPropSet, bCloseSymbol );
1607}
1608
1609void XclExpChDataFormat::ConvertLine( const ScfPropertySet& rPropSet, XclChObjectType eObjType )
1610{
1611 ConvertFrameBase( GetChRoot(), rPropSet, eObjType );
1612}
1613
1614void XclExpChDataFormat::WriteSubRecords( XclExpStream& rStrm )
1615{
1616 lclSaveRecord( rStrm, mx3dDataFmt );
1617 WriteFrameRecords( rStrm );
1618 lclSaveRecord( rStrm, mxPieFmt );
1619 lclSaveRecord( rStrm, mxMarkerFmt );
1620 lclSaveRecord( rStrm, mxSeriesFmt );
1621 lclSaveRecord( rStrm, mxAttLabel );
1622}
1623
1624void XclExpChDataFormat::WriteBody( XclExpStream& rStrm )
1625{
1626 rStrm << maData.maPointPos.mnPointIdx
1627 << maData.maPointPos.mnSeriesIdx
1628 << maData.mnFormatIdx
1629 << maData.mnFlags;
1630}
1631
1632XclExpChSerTrendLine::XclExpChSerTrendLine( const XclExpChRoot& rRoot ) :
1633 XclExpRecord( EXC_ID_CHSERTRENDLINE, 28 ),
1634 XclExpChRoot( rRoot )
1635{
1636}
1637
1638bool XclExpChSerTrendLine::Convert( Reference< XRegressionCurve > const & xRegCurve, sal_uInt16 nSeriesIdx )
1639{
1640 if( !xRegCurve.is() )
5
Calling 'BaseReference::is'
8
Returning from 'BaseReference::is'
9
Taking false branch
1641 return false;
1642
1643 // trend line type
1644 ScfPropertySet aCurveProp( xRegCurve );
1645
1646 OUString aService = aCurveProp.GetServiceName();
1647 if( aService == "com.sun.star.chart2.LinearRegressionCurve" )
10
Calling 'operator==<char const[42]>'
19
Returning from 'operator==<char const[42]>'
20
Taking false branch
1648 {
1649 maData.mnLineType = EXC_CHSERTREND_POLYNOMIAL;
1650 maData.mnOrder = 1;
1651 }
1652 else if( aService == "com.sun.star.chart2.ExponentialRegressionCurve" )
21
Calling 'operator==<char const[47]>'
30
Returning from 'operator==<char const[47]>'
31
Taking false branch
1653 {
1654 maData.mnLineType = EXC_CHSERTREND_EXPONENTIAL;
1655 }
1656 else if( aService == "com.sun.star.chart2.LogarithmicRegressionCurve" )
32
Calling 'operator==<char const[47]>'
40
Returning from 'operator==<char const[47]>'
41
Taking false branch
1657 {
1658 maData.mnLineType = EXC_CHSERTREND_LOGARITHMIC;
1659 }
1660 else if( aService == "com.sun.star.chart2.PotentialRegressionCurve" )
42
Calling 'operator==<char const[45]>'
51
Returning from 'operator==<char const[45]>'
52
Taking false branch
1661 {
1662 maData.mnLineType = EXC_CHSERTREND_POWER;
1663 }
1664 else if( aService == "com.sun.star.chart2.PolynomialRegressionCurve" )
53
Calling 'operator==<char const[46]>'
62
Returning from 'operator==<char const[46]>'
63
Assuming the condition is true
64
Taking true branch
1665 {
1666 maData.mnLineType = EXC_CHSERTREND_POLYNOMIAL;
1667 sal_Int32 aDegree;
65
'aDegree' declared without an initial value
1668 aCurveProp.GetProperty(aDegree, EXC_CHPROP_POLYNOMIAL_DEGREE"PolynomialDegree");
66
Calling 'ScfPropertySet::GetProperty'
69
Returning from 'ScfPropertySet::GetProperty'
1669 maData.mnOrder = static_cast<sal_uInt8> (aDegree);
70
Assigned value is garbage or undefined
1670 }
1671 else if( aService == "com.sun.star.chart2.MovingAverageRegressionCurve" )
1672 {
1673 maData.mnLineType = EXC_CHSERTREND_MOVING_AVG;
1674 sal_Int32 aPeriod;
1675 aCurveProp.GetProperty(aPeriod, EXC_CHPROP_MOVING_AVERAGE_PERIOD"MovingAveragePeriod");
1676 maData.mnOrder = static_cast<sal_uInt8> (aPeriod);
1677 }
1678 else
1679 {
1680 return false;
1681 }
1682
1683 aCurveProp.GetProperty(maData.mfForecastFor, EXC_CHPROP_EXTRAPOLATE_FORWARD"ExtrapolateForward");
1684 aCurveProp.GetProperty(maData.mfForecastBack, EXC_CHPROP_EXTRAPOLATE_BACKWARD"ExtrapolateBackward");
1685 bool bIsForceIntercept = false;
1686 aCurveProp.GetProperty(bIsForceIntercept, EXC_CHPROP_FORCE_INTERCEPT"ForceIntercept");
1687 if (bIsForceIntercept)
1688 aCurveProp.GetProperty(maData.mfIntercept, EXC_CHPROP_INTERCEPT_VALUE"InterceptValue");
1689
1690 // line formatting
1691 XclChDataPointPos aPointPos( nSeriesIdx );
1692 mxDataFmt = new XclExpChDataFormat( GetChRoot(), aPointPos, 0 );
1693 mxDataFmt->ConvertLine( aCurveProp, EXC_CHOBJTYPE_TRENDLINE );
1694
1695 // #i83100# show equation and correlation coefficient
1696 ScfPropertySet aEquationProp( xRegCurve->getEquationProperties() );
1697 maData.mnShowEquation = aEquationProp.GetBoolProperty( EXC_CHPROP_SHOWEQUATION"ShowEquation" ) ? 1 : 0;
1698 maData.mnShowRSquared = aEquationProp.GetBoolProperty( EXC_CHPROP_SHOWCORRELATION"ShowCorrelationCoefficient" ) ? 1 : 0;
1699
1700 // #i83100# formatting of the equation text box
1701 if( (maData.mnShowEquation != 0) || (maData.mnShowRSquared != 0) )
1702 {
1703 mxLabel = new XclExpChText( GetChRoot() );
1704 mxLabel->ConvertTrendLineEquation( aEquationProp, aPointPos );
1705 }
1706
1707 // missing features
1708 // #i5085# manual trend line size
1709 // #i34093# manual crossing point
1710 return true;
1711}
1712
1713void XclExpChSerTrendLine::WriteBody( XclExpStream& rStrm )
1714{
1715 rStrm << maData.mnLineType
1716 << maData.mnOrder
1717 << maData.mfIntercept
1718 << maData.mnShowEquation
1719 << maData.mnShowRSquared
1720 << maData.mfForecastFor
1721 << maData.mfForecastBack;
1722}
1723
1724XclExpChSerErrorBar::XclExpChSerErrorBar( const XclExpChRoot& rRoot, sal_uInt8 nBarType ) :
1725 XclExpRecord( EXC_ID_CHSERERRORBAR, 14 ),
1726 XclExpChRoot( rRoot )
1727{
1728 maData.mnBarType = nBarType;
1729}
1730
1731bool XclExpChSerErrorBar::Convert( XclExpChSourceLink& rValueLink, sal_uInt16& rnValueCount, const ScfPropertySet& rPropSet )
1732{
1733 sal_Int32 nBarStyle = 0;
1734 bool bOk = rPropSet.GetProperty( nBarStyle, EXC_CHPROP_ERRORBARSTYLE"ErrorBarStyle" );
1735 if( bOk )
1736 {
1737 switch( nBarStyle )
1738 {
1739 case cssc::ErrorBarStyle::ABSOLUTE:
1740 maData.mnSourceType = EXC_CHSERERR_FIXED;
1741 rPropSet.GetProperty( maData.mfValue, EXC_CHPROP_POSITIVEERROR"PositiveError" );
1742 break;
1743 case cssc::ErrorBarStyle::RELATIVE:
1744 maData.mnSourceType = EXC_CHSERERR_PERCENT;
1745 rPropSet.GetProperty( maData.mfValue, EXC_CHPROP_POSITIVEERROR"PositiveError" );
1746 break;
1747 case cssc::ErrorBarStyle::STANDARD_DEVIATION:
1748 maData.mnSourceType = EXC_CHSERERR_STDDEV;
1749 rPropSet.GetProperty( maData.mfValue, EXC_CHPROP_WEIGHT"Weight" );
1750 break;
1751 case cssc::ErrorBarStyle::STANDARD_ERROR:
1752 maData.mnSourceType = EXC_CHSERERR_STDERR;
1753 break;
1754 case cssc::ErrorBarStyle::FROM_DATA:
1755 {
1756 bOk = false;
1757 maData.mnSourceType = EXC_CHSERERR_CUSTOM;
1758 Reference< XDataSource > xDataSource( rPropSet.GetApiPropertySet(), UNO_QUERY );
1759 if( xDataSource.is() )
1760 {
1761 // find first sequence with current role
1762 OUString aRole = XclChartHelper::GetErrorBarValuesRole( maData.mnBarType );
1763 Reference< XDataSequence > xValueSeq;
1764
1765 const Sequence< Reference< XLabeledDataSequence > > aLabeledSeqVec = xDataSource->getDataSequences();
1766 for( const Reference< XLabeledDataSequence >& rLabeledSeq : aLabeledSeqVec )
1767 {
1768 Reference< XDataSequence > xTmpValueSeq = rLabeledSeq->getValues();
1769 ScfPropertySet aValueProp( xTmpValueSeq );
1770 OUString aCurrRole;
1771 if( aValueProp.GetProperty( aCurrRole, EXC_CHPROP_ROLE"Role" ) && (aCurrRole == aRole) )
1772 {
1773 xValueSeq = xTmpValueSeq;
1774 break;
1775 }
1776 }
1777 if( xValueSeq.is() )
1778 {
1779 // #i86465# pass value count back to series
1780 rnValueCount = maData.mnValueCount = rValueLink.ConvertDataSequence( xValueSeq, true );
1781 bOk = maData.mnValueCount > 0;
1782 }
1783 }
1784 }
1785 break;
1786 default:
1787 bOk = false;
1788 }
1789 }
1790 return bOk;
1791}
1792
1793void XclExpChSerErrorBar::WriteBody( XclExpStream& rStrm )
1794{
1795 rStrm << maData.mnBarType
1796 << maData.mnSourceType
1797 << maData.mnLineEnd
1798 << sal_uInt8( 1 ) // must be 1 to make line visible
1799 << maData.mfValue
1800 << maData.mnValueCount;
1801}
1802
1803namespace {
1804
1805/** Returns the property set of the specified data point. */
1806ScfPropertySet lclGetPointPropSet( Reference< XDataSeries > const & xDataSeries, sal_Int32 nPointIdx )
1807{
1808 ScfPropertySet aPropSet;
1809 try
1810 {
1811 aPropSet.Set( xDataSeries->getDataPointByIndex( nPointIdx ) );
1812 }
1813 catch( Exception& )
1814 {
1815 OSL_FAIL( "lclGetPointPropSet - no data point property set" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/filter/excel/xechart.cxx"
":" "1815" ": "), "%s", "lclGetPointPropSet - no data point property set"
); } } while (false)
;
1816 }
1817 return aPropSet;
1818}
1819
1820} // namespace
1821
1822XclExpChSeries::XclExpChSeries( const XclExpChRoot& rRoot, sal_uInt16 nSeriesIdx ) :
1823 XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_SERIES, EXC_ID_CHSERIES, (rRoot.GetBiff() == EXC_BIFF8) ? 12 : 8 ),
1824 mnGroupIdx( EXC_CHSERGROUP_NONE ),
1825 mnSeriesIdx( nSeriesIdx ),
1826 mnParentIdx( EXC_CHSERIES_INVALID )
1827{
1828 // CHSOURCELINK records are always required, even if unused
1829 mxTitleLink = new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_TITLE );
1830 mxValueLink = new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_VALUES );
1831 mxCategLink = new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_CATEGORY );
1832 if( GetBiff() == EXC_BIFF8 )
1833 mxBubbleLink = new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_BUBBLES );
1834}
1835
1836bool XclExpChSeries::ConvertDataSeries(
1837 Reference< XDiagram > const & xDiagram, Reference< XDataSeries > const & xDataSeries,
1838 const XclChExtTypeInfo& rTypeInfo, sal_uInt16 nGroupIdx, sal_uInt16 nFormatIdx )
1839{
1840 bool bOk = false;
1841 Reference< XDataSource > xDataSource( xDataSeries, UNO_QUERY );
1842 if( xDataSource.is() )
1843 {
1844 Reference< XDataSequence > xYValueSeq, xTitleSeq, xXValueSeq, xBubbleSeq;
1845
1846 // find first sequence with role 'values-y'
1847 const Sequence< Reference< XLabeledDataSequence > > aLabeledSeqVec = xDataSource->getDataSequences();
1848 for( const Reference< XLabeledDataSequence >& rLabeledSeq : aLabeledSeqVec )
1849 {
1850 Reference< XDataSequence > xTmpValueSeq = rLabeledSeq->getValues();
1851 ScfPropertySet aValueProp( xTmpValueSeq );
1852 OUString aRole;
1853 if( aValueProp.GetProperty( aRole, EXC_CHPROP_ROLE"Role" ) )
1854 {
1855 if( !xYValueSeq.is() && (aRole == EXC_CHPROP_ROLE_YVALUES"values-y") )
1856 {
1857 xYValueSeq = xTmpValueSeq;
1858 if( !xTitleSeq.is() )
1859 xTitleSeq = rLabeledSeq->getLabel(); // ignore role of label sequence
1860 }
1861 else if( !xXValueSeq.is() && !rTypeInfo.mbCategoryAxis && (aRole == EXC_CHPROP_ROLE_XVALUES"values-x") )
1862 {
1863 xXValueSeq = xTmpValueSeq;
1864 }
1865 else if( !xBubbleSeq.is() && (rTypeInfo.meTypeId == EXC_CHTYPEID_BUBBLES) && (aRole == EXC_CHPROP_ROLE_SIZEVALUES"values-size") )
1866 {
1867 xBubbleSeq = xTmpValueSeq;
1868 xTitleSeq = rLabeledSeq->getLabel(); // ignore role of label sequence
1869 }
1870 }
1871 }
1872
1873 bOk = xYValueSeq.is();
1874 if( bOk )
1875 {
1876 // chart type group index
1877 mnGroupIdx = nGroupIdx;
1878
1879 // convert source links
1880 maData.mnValueCount = mxValueLink->ConvertDataSequence( xYValueSeq, true );
1881 mxTitleLink->ConvertDataSequence( xTitleSeq, true );
1882
1883 // X values of XY charts
1884 maData.mnCategCount = mxCategLink->ConvertDataSequence( xXValueSeq, false, maData.mnValueCount );
1885
1886 // size values of bubble charts
1887 if( mxBubbleLink )
1888 mxBubbleLink->ConvertDataSequence( xBubbleSeq, false, maData.mnValueCount );
1889
1890 // series formatting
1891 XclChDataPointPos aPointPos( mnSeriesIdx );
1892 ScfPropertySet aSeriesProp( xDataSeries );
1893 mxSeriesFmt = new XclExpChDataFormat( GetChRoot(), aPointPos, nFormatIdx );
1894 mxSeriesFmt->ConvertDataSeries( aSeriesProp, rTypeInfo );
1895
1896 // trend lines
1897 CreateTrendLines( xDataSeries );
1898
1899 // error bars
1900 CreateErrorBars( aSeriesProp, EXC_CHPROP_ERRORBARX"ErrorBarX", EXC_CHSERERR_XPLUS, EXC_CHSERERR_XMINUS );
1901 CreateErrorBars( aSeriesProp, EXC_CHPROP_ERRORBARY"ErrorBarY", EXC_CHSERERR_YPLUS, EXC_CHSERERR_YMINUS );
1902
1903 if( maData.mnValueCount > 0 )
1904 {
1905 const sal_Int32 nMaxPointCount = maData.mnValueCount;
1906
1907 /* #i91063# Create missing fill properties in pie/doughnut charts.
1908 If freshly created (never saved to ODF), these charts show
1909 varying point colors but do not return these points via API. */
1910 if( xDiagram.is() && (rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_PIE) )
1911 {
1912 Reference< XColorScheme > xColorScheme = xDiagram->getDefaultColorScheme();
1913 if( xColorScheme.is() )
1914 {
1915 const OUString aFillStyleName = "FillStyle";
1916 const OUString aColorName = "Color";
1917 namespace cssd = ::com::sun::star::drawing;
1918 for( sal_Int32 nPointIdx = 0; nPointIdx < nMaxPointCount; ++nPointIdx )
1919 {
1920 aPointPos.mnPointIdx = static_cast< sal_uInt16 >( nPointIdx );
1921 ScfPropertySet aPointProp = lclGetPointPropSet( xDataSeries, nPointIdx );
1922 // test that the point fill style is solid, but no color is set
1923 cssd::FillStyle eFillStyle = cssd::FillStyle_NONE;
1924 if( aPointProp.GetProperty( eFillStyle, aFillStyleName ) &&
1925 (eFillStyle == cssd::FillStyle_SOLID) &&
1926 !aPointProp.HasProperty( aColorName ) )
1927 {
1928 aPointProp.SetProperty( aColorName, xColorScheme->getColorByIndex( nPointIdx ) );
1929 }
1930 }
1931 }
1932 }
1933
1934 // data point formatting
1935 Sequence< sal_Int32 > aPointIndexes;
1936 if( aSeriesProp.GetProperty( aPointIndexes, EXC_CHPROP_ATTRIBDATAPOINTS"AttributedDataPoints" ) && aPointIndexes.hasElements() )
1937 {
1938 for( const sal_Int32 nPointIndex : aPointIndexes )
1939 {
1940 if (nPointIndex >= nMaxPointCount)
1941 break;
1942 aPointPos.mnPointIdx = static_cast< sal_uInt16 >( nPointIndex );
1943 ScfPropertySet aPointProp = lclGetPointPropSet( xDataSeries, nPointIndex );
1944 XclExpChDataFormatRef xPointFmt = new XclExpChDataFormat( GetChRoot(), aPointPos, nFormatIdx );
1945 xPointFmt->ConvertDataSeries( aPointProp, rTypeInfo );
1946 maPointFmts.AppendRecord( xPointFmt );
1947 }
1948 }
1949 }
1950 }
1951 }
1952 return bOk;
1953}
1954
1955bool XclExpChSeries::ConvertStockSeries( css::uno::Reference< css::chart2::XDataSeries > const & xDataSeries,
1956 const OUString& rValueRole, sal_uInt16 nGroupIdx, sal_uInt16 nFormatIdx, bool bCloseSymbol )
1957{
1958 bool bOk = false;
1959 Reference< XDataSource > xDataSource( xDataSeries, UNO_QUERY );
1960 if( xDataSource.is() )
1961 {
1962 Reference< XDataSequence > xYValueSeq, xTitleSeq;
1963
1964 // find first sequence with passed role
1965 const Sequence< Reference< XLabeledDataSequence > > aLabeledSeqVec = xDataSource->getDataSequences();
1966 for( const Reference< XLabeledDataSequence >& rLabeledSeq : aLabeledSeqVec )
1967 {
1968 Reference< XDataSequence > xTmpValueSeq = rLabeledSeq->getValues();
1969 ScfPropertySet aValueProp( xTmpValueSeq );
1970 OUString aRole;
1971 if( aValueProp.GetProperty( aRole, EXC_CHPROP_ROLE"Role" ) && (aRole == rValueRole) )
1972 {
1973 xYValueSeq = xTmpValueSeq;
1974 xTitleSeq = rLabeledSeq->getLabel(); // ignore role of label sequence
1975 break;
1976 }
1977 }
1978
1979 bOk = xYValueSeq.is();
1980 if( bOk )
1981 {
1982 // chart type group index
1983 mnGroupIdx = nGroupIdx;
1984 // convert source links
1985 maData.mnValueCount = mxValueLink->ConvertDataSequence( xYValueSeq, true );
1986 mxTitleLink->ConvertDataSequence( xTitleSeq, true );
1987 // series formatting
1988 ScfPropertySet aSeriesProp( xDataSeries );
1989 mxSeriesFmt = new XclExpChDataFormat( GetChRoot(), XclChDataPointPos( mnSeriesIdx ), nFormatIdx );
1990 mxSeriesFmt->ConvertStockSeries( aSeriesProp, bCloseSymbol );
1991 }
1992 }
1993 return bOk;
1994}
1995
1996bool XclExpChSeries::ConvertTrendLine( const XclExpChSeries& rParent, Reference< XRegressionCurve > const & xRegCurve )
1997{
1998 InitFromParent( rParent );
1999
2000 mxTrendLine = new XclExpChSerTrendLine( GetChRoot() );
2001 bool bOk = mxTrendLine->Convert( xRegCurve, mnSeriesIdx );
4
Calling 'XclExpChSerTrendLine::Convert'
2002 if( bOk )
2003 {
2004 OUString aName;
2005 ScfPropertySet aProperties( xRegCurve );
2006 aProperties.GetProperty(aName, EXC_CHPROP_CURVENAME"CurveName");
2007 mxTitleLink->ConvertString(aName);
2008
2009 mxSeriesFmt = mxTrendLine->GetDataFormat();
2010 GetChartData().SetDataLabel( mxTrendLine->GetDataLabel() );
2011 }
2012 return bOk;
2013}
2014
2015bool XclExpChSeries::ConvertErrorBar( const XclExpChSeries& rParent, const ScfPropertySet& rPropSet, sal_uInt8 nBarId )
2016{
2017 InitFromParent( rParent );
2018 // error bar settings
2019 mxErrorBar = new XclExpChSerErrorBar( GetChRoot(), nBarId );
2020 bool bOk = mxErrorBar->Convert( *mxValueLink, maData.mnValueCount, rPropSet );
2021 if( bOk )
2022 {
2023 // error bar formatting
2024 mxSeriesFmt = new XclExpChDataFormat( GetChRoot(), XclChDataPointPos( mnSeriesIdx ), 0 );
2025 mxSeriesFmt->ConvertLine( rPropSet, EXC_CHOBJTYPE_ERRORBAR );
2026 }
2027 return bOk;
2028}
2029
2030void XclExpChSeries::ConvertCategSequence( Reference< XLabeledDataSequence > const & xCategSeq )
2031{
2032 if( xCategSeq.is() )
2033 maData.mnCategCount = mxCategLink->ConvertDataSequence( xCategSeq->getValues(), false );
2034}
2035
2036void XclExpChSeries::WriteSubRecords( XclExpStream& rStrm )
2037{
2038 lclSaveRecord( rStrm, mxTitleLink );
2039 lclSaveRecord( rStrm, mxValueLink );
2040 lclSaveRecord( rStrm, mxCategLink );
2041 lclSaveRecord( rStrm, mxBubbleLink );
2042 lclSaveRecord( rStrm, mxSeriesFmt );
2043 maPointFmts.Save( rStrm );
2044 if( mnGroupIdx != EXC_CHSERGROUP_NONE )
2045 XclExpUInt16Record( EXC_ID_CHSERGROUP, mnGroupIdx ).Save( rStrm );
2046 if( mnParentIdx != EXC_CHSERIES_INVALID )
2047 XclExpUInt16Record( EXC_ID_CHSERPARENT, mnParentIdx ).Save( rStrm );
2048 lclSaveRecord( rStrm, mxTrendLine );
2049 lclSaveRecord( rStrm, mxErrorBar );
2050}
2051
2052void XclExpChSeries::InitFromParent( const XclExpChSeries& rParent )
2053{
2054 // index to parent series is stored 1-based
2055 mnParentIdx = rParent.mnSeriesIdx + 1;
2056 /* #i86465# MSO2007 SP1 expects correct point counts in child series
2057 (there was no problem in Excel2003 or Excel2007 without SP1...) */
2058 maData.mnCategCount = rParent.maData.mnCategCount;
2059 maData.mnValueCount = rParent.maData.mnValueCount;
2060}
2061
2062void XclExpChSeries::CreateTrendLines( css::uno::Reference< css::chart2::XDataSeries > const & xDataSeries )
2063{
2064 Reference< XRegressionCurveContainer > xRegCurveCont( xDataSeries, UNO_QUERY );
2065 if( xRegCurveCont.is() )
1
Taking true branch
2066 {
2067 const Sequence< Reference< XRegressionCurve > > aRegCurveSeq = xRegCurveCont->getRegressionCurves();
2068 for( const Reference< XRegressionCurve >& rRegCurve : aRegCurveSeq )
2
Assuming '__begin2' is not equal to '__end2'
2069 {
2070 XclExpChSeriesRef xSeries = GetChartData().CreateSeries();
2071 if( xSeries && !xSeries->ConvertTrendLine( *this, rRegCurve ) )
3
Calling 'XclExpChSeries::ConvertTrendLine'
2072 GetChartData().RemoveLastSeries();
2073 }
2074 }
2075}
2076
2077void XclExpChSeries::CreateErrorBars( const ScfPropertySet& rPropSet,
2078 const OUString& rBarPropName, sal_uInt8 nPosBarId, sal_uInt8 nNegBarId )
2079{
2080 Reference< XPropertySet > xErrorBar;
2081 if( rPropSet.GetProperty( xErrorBar, rBarPropName ) && xErrorBar.is() )
2082 {
2083 ScfPropertySet aErrorProp( xErrorBar );
2084 CreateErrorBar( aErrorProp, EXC_CHPROP_SHOWPOSITIVEERROR"ShowPositiveError", nPosBarId );
2085 CreateErrorBar( aErrorProp, EXC_CHPROP_SHOWNEGATIVEERROR"ShowNegativeError", nNegBarId );
2086 }
2087}
2088
2089void XclExpChSeries::CreateErrorBar( const ScfPropertySet& rPropSet,
2090 const OUString& rShowPropName, sal_uInt8 nBarId )
2091{
2092 if( rPropSet.GetBoolProperty( rShowPropName ) )
2093 {
2094 XclExpChSeriesRef xSeries = GetChartData().CreateSeries();
2095 if( xSeries && !xSeries->ConvertErrorBar( *this, rPropSet, nBarId ) )
2096 GetChartData().RemoveLastSeries();
2097 }
2098}
2099
2100void XclExpChSeries::WriteBody( XclExpStream& rStrm )
2101{
2102 rStrm << maData.mnCategType << maData.mnValueType << maData.mnCategCount << maData.mnValueCount;
2103 if( GetBiff() == EXC_BIFF8 )
2104 rStrm << maData.mnBubbleType << maData.mnBubbleCount;
2105}
2106
2107// Chart type groups ==========================================================
2108
2109XclExpChType::XclExpChType( const XclExpChRoot& rRoot ) :
2110 XclExpRecord( EXC_ID_CHUNKNOWN ),
2111 XclExpChRoot( rRoot ),
2112 maTypeInfo( rRoot.GetChartTypeInfo( EXC_CHTYPEID_UNKNOWN ) )
2113{
2114}
2115
2116void XclExpChType::Convert( Reference< XDiagram > const & xDiagram, Reference< XChartType > const & xChartType,
2117 sal_Int32 nApiAxesSetIdx, bool bSwappedAxesSet, bool bHasXLabels )
2118{
2119 if( !xChartType.is() )
2120 return;
2121
2122 maTypeInfo = GetChartTypeInfo( xChartType->getChartType() );
2123 // special handling for some chart types
2124 switch( maTypeInfo.meTypeCateg )
2125 {
2126 case EXC_CHTYPECATEG_BAR:
2127 {
2128 maTypeInfo = GetChartTypeInfo( bSwappedAxesSet ? EXC_CHTYPEID_HORBAR : EXC_CHTYPEID_BAR );
2129 ::set_flag( maData.mnFlags, EXC_CHBAR_HORIZONTAL, bSwappedAxesSet );
2130 ScfPropertySet aTypeProp( xChartType );
2131 Sequence< sal_Int32 > aInt32Seq;
2132 maData.mnOverlap = 0;
2133 if( aTypeProp.GetProperty( aInt32Seq, EXC_CHPROP_OVERLAPSEQ"OverlapSequence" ) && (nApiAxesSetIdx < aInt32Seq.getLength()) )
2134 maData.mnOverlap = limit_cast< sal_Int16 >( -aInt32Seq[ nApiAxesSetIdx ], -100, 100 );
2135 maData.mnGap = 150;
2136 if( aTypeProp.GetProperty( aInt32Seq, EXC_CHPROP_GAPWIDTHSEQ"GapwidthSequence" ) && (nApiAxesSetIdx < aInt32Seq.getLength()) )
2137 maData.mnGap = limit_cast< sal_uInt16 >( aInt32Seq[ nApiAxesSetIdx ], 0, 500 );
2138 }
2139 break;
2140 case EXC_CHTYPECATEG_RADAR:
2141 ::set_flag( maData.mnFlags, EXC_CHRADAR_AXISLABELS, bHasXLabels );
2142 break;
2143 case EXC_CHTYPECATEG_PIE:
2144 {
2145 ScfPropertySet aTypeProp( xChartType );
2146 bool bDonut = aTypeProp.GetBoolProperty( EXC_CHPROP_USERINGS"UseRings" );
2147 maTypeInfo = GetChartTypeInfo( bDonut ? EXC_CHTYPEID_DONUT : EXC_CHTYPEID_PIE );
2148 maData.mnPieHole = bDonut ? 50 : 0;
2149 // #i85166# starting angle of first pie slice
2150 ScfPropertySet aDiaProp( xDiagram );
2151 maData.mnRotation = XclExpChRoot::ConvertPieRotation( aDiaProp );
2152 }
2153 break;
2154 case EXC_CHTYPECATEG_SCATTER:
2155 if( GetBiff() == EXC_BIFF8 )
2156 ::set_flag( maData.mnFlags, EXC_CHSCATTER_BUBBLES, maTypeInfo.meTypeId == EXC_CHTYPEID_BUBBLES );
2157 break;
2158 default:;
2159 }
2160 SetRecId( maTypeInfo.mnRecId );
2161}
2162
2163void XclExpChType::SetStacked( bool bPercent )
2164{
2165 switch( maTypeInfo.meTypeCateg )
2166 {
2167 case EXC_CHTYPECATEG_LINE:
2168 ::set_flag( maData.mnFlags, EXC_CHLINE_STACKED );
2169 ::set_flag( maData.mnFlags, EXC_CHLINE_PERCENT, bPercent );
2170 break;
2171 case EXC_CHTYPECATEG_BAR:
2172 ::set_flag( maData.mnFlags, EXC_CHBAR_STACKED );
2173 ::set_flag( maData.mnFlags, EXC_CHBAR_PERCENT, bPercent );
2174 maData.mnOverlap = -100;
2175 break;
2176 default:;
2177 }
2178}
2179
2180void XclExpChType::WriteBody( XclExpStream& rStrm )
2181{
2182 switch( GetRecId() )
2183 {
2184 case EXC_ID_CHBAR:
2185 rStrm << maData.mnOverlap << maData.mnGap << maData.mnFlags;
2186 break;
2187
2188 case EXC_ID_CHLINE:
2189 case EXC_ID_CHAREA:
2190 case EXC_ID_CHRADARLINE:
2191 case EXC_ID_CHRADARAREA:
2192 rStrm << maData.mnFlags;
2193 break;
2194
2195 case EXC_ID_CHPIE:
2196 rStrm << maData.mnRotation << maData.mnPieHole;
2197 if( GetBiff() == EXC_BIFF8 )
2198 rStrm << maData.mnFlags;
2199 break;
2200
2201 case EXC_ID_CHSCATTER:
2202 if( GetBiff() == EXC_BIFF8 )
2203 rStrm << maData.mnBubbleSize << maData.mnBubbleType << maData.mnFlags;
2204 break;
2205
2206 default:
2207 OSL_FAIL( "XclExpChType::WriteBody - unknown chart type" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/filter/excel/xechart.cxx"
":" "2207" ": "), "%s", "XclExpChType::WriteBody - unknown chart type"
); } } while (false)
;
2208 }
2209}
2210
2211XclExpChChart3d::XclExpChChart3d() :
2212 XclExpRecord( EXC_ID_CHCHART3D, 14 )
2213{
2214}
2215
2216void XclExpChChart3d::Convert( const ScfPropertySet& rPropSet, bool b3dWallChart )
2217{
2218 sal_Int32 nRotationY = 0;
2219 rPropSet.GetProperty( nRotationY, EXC_CHPROP_ROTATIONVERTICAL"RotationVertical" );
2220 sal_Int32 nRotationX = 0;
2221 rPropSet.GetProperty( nRotationX, EXC_CHPROP_ROTATIONHORIZONTAL"RotationHorizontal" );
2222 sal_Int32 nPerspective = 15;
2223 rPropSet.GetProperty( nPerspective, EXC_CHPROP_PERSPECTIVE"Perspective" );
2224
2225 if( b3dWallChart )
2226 {
2227 // Y rotation (Excel [0..359], Chart2 [-179,180])
2228 if( nRotationY < 0 ) nRotationY += 360;
2229 maData.mnRotation = static_cast< sal_uInt16 >( nRotationY );
2230 // X rotation a.k.a. elevation (Excel [-90..90], Chart2 [-179,180])
2231 maData.mnElevation = limit_cast< sal_Int16 >( nRotationX, -90, 90 );
2232 // perspective (Excel and Chart2 [0,100])
2233 maData.mnEyeDist = limit_cast< sal_uInt16 >( nPerspective, 0, 100 );
2234 // flags
2235 maData.mnFlags = 0;
2236 ::set_flag( maData.mnFlags, EXC_CHCHART3D_REAL3D, !rPropSet.GetBoolProperty( EXC_CHPROP_RIGHTANGLEDAXES"RightAngledAxes" ) );
2237 ::set_flag( maData.mnFlags, EXC_CHCHART3D_AUTOHEIGHT );
2238 ::set_flag( maData.mnFlags, EXC_CHCHART3D_HASWALLS );
2239 }
2240 else
2241 {
2242 // Y rotation not used in pie charts, but 'first pie slice angle'
2243 maData.mnRotation = XclExpChRoot::ConvertPieRotation( rPropSet );
2244 // X rotation a.k.a. elevation (map Chart2 [-80,-10] to Excel [10..80])
2245 maData.mnElevation = limit_cast< sal_Int16 >( (nRotationX + 270) % 180, 10, 80 );
2246 // perspective (Excel and Chart2 [0,100])
2247 maData.mnEyeDist = limit_cast< sal_uInt16 >( nPerspective, 0, 100 );
2248 // flags
2249 maData.mnFlags = 0;
2250 }
2251}
2252
2253void XclExpChChart3d::WriteBody( XclExpStream& rStrm )
2254{
2255 rStrm << maData.mnRotation
2256 << maData.mnElevation
2257 << maData.mnEyeDist
2258 << maData.mnRelHeight
2259 << maData.mnRelDepth
2260 << maData.mnDepthGap
2261 << maData.mnFlags;
2262}
2263
2264XclExpChLegend::XclExpChLegend( const XclExpChRoot& rRoot ) :
2265 XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_LEGEND, EXC_ID_CHLEGEND, 20 )
2266{
2267}
2268
2269void XclExpChLegend::Convert( const ScfPropertySet& rPropSet )
2270{
2271 // frame properties
2272 mxFrame = lclCreateFrame( GetChRoot(), rPropSet, EXC_CHOBJTYPE_LEGEND );
2273 // text properties
2274 mxText = new XclExpChText( GetChRoot() );
2275 mxText->ConvertLegend( rPropSet );
2276
2277 // legend position and size
2278 Any aRelPosAny, aRelSizeAny;
2279 rPropSet.GetAnyProperty( aRelPosAny, EXC_CHPROP_RELATIVEPOSITION"RelativePosition" );
2280 rPropSet.GetAnyProperty( aRelSizeAny, EXC_CHPROP_RELATIVESIZE"RelativeSize" );
2281 cssc::ChartLegendExpansion eApiExpand = cssc::ChartLegendExpansion_CUSTOM;
2282 rPropSet.GetProperty( eApiExpand, EXC_CHPROP_EXPANSION"Expansion" );
2283 if( aRelPosAny.has< RelativePosition >() || ((eApiExpand == cssc::ChartLegendExpansion_CUSTOM) && aRelSizeAny.has< RelativeSize >()) )
2284 {
2285 try
2286 {
2287 /* The 'RelativePosition' or 'RelativeSize' properties are used as
2288 indicator of manually changed legend position/size, but due to
2289 the different anchor modes used by this property (in the
2290 RelativePosition.Anchor member) it cannot be used to calculate
2291 the position easily. For this, the Chart1 API will be used
2292 instead. */
2293 Reference< cssc::XChartDocument > xChart1Doc( GetChartDocument(), UNO_QUERY_THROW );
2294 Reference< XShape > xChart1Legend( xChart1Doc->getLegend(), UNO_SET_THROW );
2295 // coordinates in CHLEGEND record written but not used by Excel
2296 mxFramePos = new XclExpChFramePos( EXC_CHFRAMEPOS_CHARTSIZE );
2297 XclChFramePos& rFramePos = mxFramePos->GetFramePosData();
2298 rFramePos.mnTLMode = EXC_CHFRAMEPOS_CHARTSIZE;
2299 css::awt::Point aLegendPos = xChart1Legend->getPosition();
2300 rFramePos.maRect.mnX = maData.maRect.mnX = CalcChartXFromHmm( aLegendPos.X );
2301 rFramePos.maRect.mnY = maData.maRect.mnY = CalcChartYFromHmm( aLegendPos.Y );
2302 // legend size, Excel expects points in CHFRAMEPOS record
2303 rFramePos.mnBRMode = EXC_CHFRAMEPOS_ABSSIZE_POINTS;
2304 css::awt::Size aLegendSize = xChart1Legend->getSize();
2305 rFramePos.maRect.mnWidth = static_cast< sal_uInt16 >( aLegendSize.Width * EXC_POINTS_PER_HMM + 0.5 );
2306 rFramePos.maRect.mnHeight = static_cast< sal_uInt16 >( aLegendSize.Height * EXC_POINTS_PER_HMM + 0.5 );
2307 maData.maRect.mnWidth = CalcChartXFromHmm( aLegendSize.Width );
2308 maData.maRect.mnHeight = CalcChartYFromHmm( aLegendSize.Height );
2309 eApiExpand = cssc::ChartLegendExpansion_CUSTOM;
2310 // manual legend position implies manual plot area
2311 GetChartData().SetManualPlotArea();
2312 maData.mnDockMode = EXC_CHLEGEND_NOTDOCKED;
2313 // a CHFRAME record with cleared auto flags is needed
2314 if( !mxFrame )
2315 mxFrame = new XclExpChFrame( GetChRoot(), EXC_CHOBJTYPE_LEGEND );
2316 mxFrame->SetAutoFlags( false, false );
2317 }
2318 catch( Exception& )
2319 {
2320 OSL_FAIL( "XclExpChLegend::Convert - cannot get legend shape" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/filter/excel/xechart.cxx"
":" "2320" ": "), "%s", "XclExpChLegend::Convert - cannot get legend shape"
); } } while (false)
;
2321 maData.mnDockMode = EXC_CHLEGEND_RIGHT;
2322 eApiExpand = cssc::ChartLegendExpansion_HIGH;
2323 }
2324 }
2325 else
2326 {
2327 cssc2::LegendPosition eApiPos = cssc2::LegendPosition_LINE_END;
2328 rPropSet.GetProperty( eApiPos, EXC_CHPROP_ANCHORPOSITION"AnchorPosition" );
2329 switch( eApiPos )
2330 {
2331 case cssc2::LegendPosition_LINE_START: maData.mnDockMode = EXC_CHLEGEND_LEFT; break;
2332 case cssc2::LegendPosition_LINE_END: maData.mnDockMode = EXC_CHLEGEND_RIGHT; break;
2333 case cssc2::LegendPosition_PAGE_START: maData.mnDockMode = EXC_CHLEGEND_TOP; break;
2334 case cssc2::LegendPosition_PAGE_END: maData.mnDockMode = EXC_CHLEGEND_BOTTOM; break;
2335 default:
2336 OSL_FAIL( "XclExpChLegend::Convert - unrecognized legend position" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/filter/excel/xechart.cxx"
":" "2336" ": "), "%s", "XclExpChLegend::Convert - unrecognized legend position"
); } } while (false)
;
2337 maData.mnDockMode = EXC_CHLEGEND_RIGHT;
2338 eApiExpand = cssc::ChartLegendExpansion_HIGH;
2339 }
2340 }
2341 ::set_flag( maData.mnFlags, EXC_CHLEGEND_STACKED, eApiExpand == cssc::ChartLegendExpansion_HIGH );
2342
2343 // other flags
2344 ::set_flag( maData.mnFlags, EXC_CHLEGEND_AUTOSERIES );
2345 const sal_uInt16 nAutoFlags = EXC_CHLEGEND_DOCKED | EXC_CHLEGEND_AUTOPOSX | EXC_CHLEGEND_AUTOPOSY;
2346 ::set_flag( maData.mnFlags, nAutoFlags, maData.mnDockMode != EXC_CHLEGEND_NOTDOCKED );
2347}
2348
2349void XclExpChLegend::WriteSubRecords( XclExpStream& rStrm )
2350{
2351 lclSaveRecord( rStrm, mxFramePos );
2352 lclSaveRecord( rStrm, mxText );
2353 lclSaveRecord( rStrm, mxFrame );
2354}
2355
2356void XclExpChLegend::WriteBody( XclExpStream& rStrm )
2357{
2358 rStrm << maData.maRect << maData.mnDockMode << maData.mnSpacing << maData.mnFlags;
2359}
2360
2361XclExpChDropBar::XclExpChDropBar( const XclExpChRoot& rRoot, XclChObjectType eObjType ) :
2362 XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_DROPBAR, EXC_ID_CHDROPBAR, 2 ),
2363 meObjType( eObjType )
2364{
2365}
2366
2367void XclExpChDropBar::Convert( const ScfPropertySet& rPropSet )
2368{
2369 if( rPropSet.Is() )
2370 ConvertFrameBase( GetChRoot(), rPropSet, meObjType );
2371 else
2372 SetDefaultFrameBase( GetChRoot(), EXC_CHFRAMETYPE_INVISIBLE, true );
2373}
2374
2375void XclExpChDropBar::WriteSubRecords( XclExpStream& rStrm )
2376{
2377 WriteFrameRecords( rStrm );
2378}
2379
2380void XclExpChDropBar::WriteBody( XclExpStream& rStrm )
2381{
2382 rStrm << sal_uInt16(100); // Distance between bars (CHDROPBAR record).
2383}
2384
2385XclExpChTypeGroup::XclExpChTypeGroup( const XclExpChRoot& rRoot, sal_uInt16 nGroupIdx ) :
2386 XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_TYPEGROUP, EXC_ID_CHTYPEGROUP, 20 ),
2387 maType( rRoot ),
2388 maTypeInfo( maType.GetTypeInfo() )
2389{
2390 maData.mnGroupIdx = nGroupIdx;
2391}
2392
2393void XclExpChTypeGroup::ConvertType(
2394 Reference< XDiagram > const & xDiagram, Reference< XChartType > const & xChartType,
2395 sal_Int32 nApiAxesSetIdx, bool b3dChart, bool bSwappedAxesSet, bool bHasXLabels )
2396{
2397 // chart type settings
2398 maType.Convert( xDiagram, xChartType, nApiAxesSetIdx, bSwappedAxesSet, bHasXLabels );
2399
2400 // spline - TODO: get from single series (#i66858#)
2401 ScfPropertySet aTypeProp( xChartType );
2402 cssc2::CurveStyle eCurveStyle;
2403 bool bSpline = aTypeProp.GetProperty( eCurveStyle, EXC_CHPROP_CURVESTYLE"CurveStyle" ) &&
2404 (eCurveStyle != cssc2::CurveStyle_LINES);
2405
2406 // extended type info
2407 maTypeInfo.Set( maType.GetTypeInfo(), b3dChart, bSpline );
2408
2409 // 3d chart settings
2410 if( maTypeInfo.mb3dChart ) // only true, if Excel chart supports 3d mode
2411 {
2412 mxChart3d = new XclExpChChart3d();
2413 ScfPropertySet aDiaProp( xDiagram );
2414 mxChart3d->Convert( aDiaProp, Is3dWallChart() );
2415 }
2416}
2417
2418void XclExpChTypeGroup::ConvertSeries(
2419 Reference< XDiagram > const & xDiagram, Reference< XChartType > const & xChartType,
2420 sal_Int32 nGroupAxesSetIdx, bool bPercent, bool bConnectBars )
2421{
2422 Reference< XDataSeriesContainer > xSeriesCont( xChartType, UNO_QUERY );
2423 if( !xSeriesCont.is() )
2424 return;
2425
2426 std::vector< Reference< XDataSeries > > aSeriesVec;
2427
2428 // copy data series attached to the current axes set to the vector
2429 const Sequence< Reference< XDataSeries > > aSeriesSeq = xSeriesCont->getDataSeries();
2430 for( const Reference< XDataSeries >& rSeries : aSeriesSeq )
2431 {
2432 ScfPropertySet aSeriesProp( rSeries );
2433 sal_Int32 nSeriesAxesSetIdx(0);
2434 if( aSeriesProp.GetProperty( nSeriesAxesSetIdx, EXC_CHPROP_ATTAXISINDEX"AttachedAxisIndex" ) && (nSeriesAxesSetIdx == nGroupAxesSetIdx) )
2435 aSeriesVec.push_back( rSeries );
2436 }
2437
2438 // Are there any series in the current axes set?
2439 if( aSeriesVec.empty() )
2440 return;
2441
2442 // stacking direction (stacked/percent/deep 3d) from first series
2443 ScfPropertySet aSeriesProp( aSeriesVec.front() );
2444 cssc2::StackingDirection eStacking;
2445 if( !aSeriesProp.GetProperty( eStacking, EXC_CHPROP_STACKINGDIR"StackingDirection" ) )
2446 eStacking = cssc2::StackingDirection_NO_STACKING;
2447
2448 // stacked or percent chart
2449 if( maTypeInfo.mbSupportsStacking && (eStacking == cssc2::StackingDirection_Y_STACKING) )
2450 {
2451 // percent overrides simple stacking
2452 maType.SetStacked( bPercent );
2453
2454 // connected data points (only in stacked bar charts)
2455 if (bConnectBars && (maTypeInfo.meTypeCateg == EXC_CHTYPECATEG_BAR))
2456 {
2457 sal_uInt16 nKey = EXC_CHCHARTLINE_CONNECT;
2458 m_ChartLines.insert(std::make_pair(nKey, std::make_unique<XclExpChLineFormat>(GetChRoot())));
2459 }
2460 }
2461 else
2462 {
2463 // reverse series order for some unstacked 2D chart types
2464 if( maTypeInfo.mbReverseSeries && !Is3dChart() )
2465 ::std::reverse( aSeriesVec.begin(), aSeriesVec.end() );
2466 }
2467
2468 // deep 3d chart or clustered 3d chart (stacked is not clustered)
2469 if( (eStacking == cssc2::StackingDirection_NO_STACKING) && Is3dWallChart() )
2470 mxChart3d->SetClustered();
2471
2472 // varied point colors
2473 ::set_flag( maData.mnFlags, EXC_CHTYPEGROUP_VARIEDCOLORS, aSeriesProp.GetBoolProperty( EXC_CHPROP_VARYCOLORSBY"VaryColorsByPoint" ) );
2474
2475 // process all series
2476 for( const auto& rxSeries : aSeriesVec )
2477 {
2478 // create Excel series object, stock charts need special processing
2479 if( maTypeInfo.meTypeId == EXC_CHTYPEID_STOCK )
2480 CreateAllStockSeries( xChartType, rxSeries );
2481 else
2482 CreateDataSeries( xDiagram, rxSeries );
2483 }
2484}
2485
2486void XclExpChTypeGroup::ConvertCategSequence( Reference< XLabeledDataSequence > const & xCategSeq )
2487{
2488 for( size_t nIdx = 0, nSize = maSeries.GetSize(); nIdx < nSize; ++nIdx )
2489 maSeries.GetRecord( nIdx )->ConvertCategSequence( xCategSeq );
2490}
2491
2492void XclExpChTypeGroup::ConvertLegend( const ScfPropertySet& rPropSet )
2493{
2494 if( rPropSet.GetBoolProperty( EXC_CHPROP_SHOW"Show" ) )
2495 {
2496 mxLegend = new XclExpChLegend( GetChRoot() );
2497 mxLegend->Convert( rPropSet );
2498 }
2499}
2500
2501void XclExpChTypeGroup::WriteSubRecords( XclExpStream& rStrm )
2502{
2503 maType.Save( rStrm );
2504 lclSaveRecord( rStrm, mxChart3d );
2505 lclSaveRecord( rStrm, mxLegend );
2506 lclSaveRecord( rStrm, mxUpBar );
2507 lclSaveRecord( rStrm, mxDownBar );
2508 for (auto const& it : m_ChartLines)
2509 {
2510 lclSaveRecord( rStrm, it.second.get(), EXC_ID_CHCHARTLINE, it.first );
2511 }
2512}
2513
2514sal_uInt16 XclExpChTypeGroup::GetFreeFormatIdx() const
2515{
2516 return static_cast< sal_uInt16 >( maSeries.GetSize() );
2517}
2518
2519void XclExpChTypeGroup::CreateDataSeries(
2520 Reference< XDiagram > const & xDiagram, Reference< XDataSeries > const & xDataSeries )
2521{
2522 // let chart create series object with correct series index
2523 XclExpChSeriesRef xSeries = GetChartData().CreateSeries();
2524 if( xSeries )
2525 {
2526 if( xSeries->ConvertDataSeries( xDiagram, xDataSeries, maTypeInfo, GetGroupIdx(), GetFreeFormatIdx() ) )
2527 maSeries.AppendRecord( xSeries );
2528 else
2529 GetChartData().RemoveLastSeries();
2530 }
2531}
2532
2533void XclExpChTypeGroup::CreateAllStockSeries(
2534 Reference< XChartType > const & xChartType, Reference< XDataSeries > const & xDataSeries )
2535{
2536 // create existing series objects
2537 bool bHasOpen = CreateStockSeries( xDataSeries, EXC_CHPROP_ROLE_OPENVALUES"values-first", false );
2538 bool bHasHigh = CreateStockSeries( xDataSeries, EXC_CHPROP_ROLE_HIGHVALUES"values-max", false );
2539 bool bHasLow = CreateStockSeries( xDataSeries, EXC_CHPROP_ROLE_LOWVALUES"values-min", false );
2540 bool bHasClose = CreateStockSeries( xDataSeries, EXC_CHPROP_ROLE_CLOSEVALUES"values-last", !bHasOpen );
2541
2542 // formatting of special stock chart elements
2543 ScfPropertySet aTypeProp( xChartType );
2544 // hi-lo lines
2545 if( bHasHigh && bHasLow && aTypeProp.GetBoolProperty( EXC_CHPROP_SHOWHIGHLOW"ShowHighLow" ) )
2546 {
2547 ScfPropertySet aSeriesProp( xDataSeries );
2548 XclExpChLineFormatRef xLineFmt = new XclExpChLineFormat( GetChRoot() );
2549 xLineFmt->Convert( GetChRoot(), aSeriesProp, EXC_CHOBJTYPE_HILOLINE );
2550 sal_uInt16 nKey = EXC_CHCHARTLINE_HILO;
2551 m_ChartLines.insert(std::make_pair(nKey, std::make_unique<XclExpChLineFormat>(GetChRoot())));
2552 }
2553 // dropbars
2554 if( !(bHasOpen && bHasClose) )
2555 return;
2556
2557 // dropbar type is dependent on position in the file - always create both
2558 Reference< XPropertySet > xWhitePropSet, xBlackPropSet;
2559 // white dropbar format
2560 aTypeProp.GetProperty( xWhitePropSet, EXC_CHPROP_WHITEDAY"WhiteDay" );
2561 ScfPropertySet aWhiteProp( xWhitePropSet );
2562 mxUpBar = new XclExpChDropBar( GetChRoot(), EXC_CHOBJTYPE_WHITEDROPBAR );
2563 mxUpBar->Convert( aWhiteProp );
2564 // black dropbar format
2565 aTypeProp.GetProperty( xBlackPropSet, EXC_CHPROP_BLACKDAY"BlackDay" );
2566 ScfPropertySet aBlackProp( xBlackPropSet );
2567 mxDownBar = new XclExpChDropBar( GetChRoot(), EXC_CHOBJTYPE_BLACKDROPBAR );
2568 mxDownBar->Convert( aBlackProp );
2569}
2570
2571bool XclExpChTypeGroup::CreateStockSeries( Reference< XDataSeries > const & xDataSeries,
2572 const OUString& rValueRole, bool bCloseSymbol )
2573{
2574 bool bOk = false;
2575 // let chart create series object with correct series index
2576 XclExpChSeriesRef xSeries = GetChartData().CreateSeries();
2577 if( xSeries )
2578 {
2579 bOk = xSeries->ConvertStockSeries( xDataSeries,
2580 rValueRole, GetGroupIdx(), GetFreeFormatIdx(), bCloseSymbol );
2581 if( bOk )
2582 maSeries.AppendRecord( xSeries );
2583 else
2584 GetChartData().RemoveLastSeries();
2585 }
2586 return bOk;
2587}
2588
2589void XclExpChTypeGroup::WriteBody( XclExpStream& rStrm )
2590{
2591 rStrm.WriteZeroBytes( 16 );
2592 rStrm << maData.mnFlags << maData.mnGroupIdx;
2593}
2594
2595// Axes =======================================================================
2596
2597XclExpChLabelRange::XclExpChLabelRange( const XclExpChRoot& rRoot ) :
2598 XclExpRecord( EXC_ID_CHLABELRANGE, 8 ),
2599 XclExpChRoot( rRoot )
2600{
2601}
2602
2603void XclExpChLabelRange::Convert( const ScaleData& rScaleData, const ScfPropertySet& rChart1Axis, bool bMirrorOrient )
2604{
2605 /* Base time unit (using the property 'ExplicitTimeIncrement' from the old
2606 chart API allows to detect axis type (date axis, if property exists),
2607 and to receive the base time unit currently used in case the base time
2608 unit is set to 'automatic'. */
2609 cssc::TimeIncrement aTimeIncrement;
2610 if( rChart1Axis.GetProperty( aTimeIncrement, EXC_CHPROP_EXPTIMEINCREMENT"ExplicitTimeIncrement" ) )
2611 {
2612 // property exists -> this is a date axis currently
2613 ::set_flag( maDateData.mnFlags, EXC_CHDATERANGE_DATEAXIS );
2614
2615 // automatic base time unit, if the UNO Any 'rScaleData.TimeIncrement.TimeResolution' does not contain a valid value...
2616 bool bAutoBase = !rScaleData.TimeIncrement.TimeResolution.has< cssc::TimeIncrement >();
2617 ::set_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOBASE, bAutoBase );
2618
2619 // ...but get the current base time unit from the property of the old chart API
2620 sal_Int32 nApiTimeUnit = 0;
2621 bool bValidBaseUnit = aTimeIncrement.TimeResolution >>= nApiTimeUnit;
2622 OSL_ENSURE( bValidBaseUnit, "XclExpChLabelRange::Convert - cannot get base time unit" )do { if (true && (!(bValidBaseUnit))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/filter/excel/xechart.cxx"
":" "2622" ": "), "%s", "XclExpChLabelRange::Convert - cannot get base time unit"
); } } while (false)
;
2623 maDateData.mnBaseUnit = bValidBaseUnit ? lclGetTimeUnit( nApiTimeUnit ) : EXC_CHDATERANGE_DAYS;
2624
2625 /* Min/max values depend on base time unit, they specify the number of
2626 days, months, or years starting from null date. */
2627 bool bAutoMin = lclConvertTimeValue( GetRoot(), maDateData.mnMinDate, rScaleData.Minimum, maDateData.mnBaseUnit );
2628 ::set_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOMIN, bAutoMin );
2629 bool bAutoMax = lclConvertTimeValue( GetRoot(), maDateData.mnMaxDate, rScaleData.Maximum, maDateData.mnBaseUnit );
2630 ::set_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOMAX, bAutoMax );
2631 }
2632
2633 // automatic axis type detection
2634 ::set_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTODATE, rScaleData.AutoDateAxis );
2635
2636 // increment
2637 bool bAutoMajor = lclConvertTimeInterval( maDateData.mnMajorStep, maDateData.mnMajorUnit, rScaleData.TimeIncrement.MajorTimeInterval );
2638 ::set_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOMAJOR, bAutoMajor );
2639 bool bAutoMinor = lclConvertTimeInterval( maDateData.mnMinorStep, maDateData.mnMinorUnit, rScaleData.TimeIncrement.MinorTimeInterval );
2640 ::set_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOMINOR, bAutoMinor );
2641
2642 // origin
2643 double fOrigin = 0.0;
2644 if( !lclIsAutoAnyOrGetValue( fOrigin, rScaleData.Origin ) )
2645 maLabelData.mnCross = limit_cast< sal_uInt16 >( fOrigin, 1, 31999 );
2646
2647 // reverse order
2648 if( (rScaleData.Orientation == cssc2::AxisOrientation_REVERSE) != bMirrorOrient )
2649 ::set_flag( maLabelData.mnFlags, EXC_CHLABELRANGE_REVERSE );
2650}
2651
2652void XclExpChLabelRange::ConvertAxisPosition( const ScfPropertySet& rPropSet )
2653{
2654 cssc::ChartAxisPosition eAxisPos = cssc::ChartAxisPosition_VALUE;
2655 rPropSet.GetProperty( eAxisPos, EXC_CHPROP_CROSSOVERPOSITION"CrossoverPosition" );
2656 double fCrossingPos = 1.0;
2657 rPropSet.GetProperty( fCrossingPos, EXC_CHPROP_CROSSOVERVALUE"CrossoverValue" );
2658
2659 bool bDateAxis = ::get_flag( maDateData.mnFlags, EXC_CHDATERANGE_DATEAXIS );
2660 switch( eAxisPos )
2661 {
2662 case cssc::ChartAxisPosition_ZERO:
2663 case cssc::ChartAxisPosition_START:
2664 maLabelData.mnCross = 1;
2665 ::set_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOCROSS );
2666 break;
2667 case cssc::ChartAxisPosition_END:
2668 ::set_flag( maLabelData.mnFlags, EXC_CHLABELRANGE_MAXCROSS );
2669 break;
2670 case cssc::ChartAxisPosition_VALUE:
2671 maLabelData.mnCross = limit_cast< sal_uInt16 >( fCrossingPos, 1, 31999 );
2672 ::set_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOCROSS, false );
2673 if( bDateAxis )
2674 maDateData.mnCross = lclGetTimeValue( GetRoot(), fCrossingPos, maDateData.mnBaseUnit );
2675 break;
2676 default:
2677 maLabelData.mnCross = 1;
2678 ::set_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOCROSS );
2679 }
2680}
2681
2682void XclExpChLabelRange::Save( XclExpStream& rStrm )
2683{
2684 // the CHLABELRANGE record
2685 XclExpRecord::Save( rStrm );
2686
2687 // the CHDATERANGE record with date axis settings (BIFF8 only)
2688 if( GetBiff() != EXC_BIFF8 )
2689 return;
2690
2691 rStrm.StartRecord( EXC_ID_CHDATERANGE, 18 );
2692 rStrm << maDateData.mnMinDate
2693 << maDateData.mnMaxDate
2694 << maDateData.mnMajorStep
2695 << maDateData.mnMajorUnit
2696 << maDateData.mnMinorStep
2697 << maDateData.mnMinorUnit
2698 << maDateData.mnBaseUnit
2699 << maDateData.mnCross
2700 << maDateData.mnFlags;
2701 rStrm.EndRecord();
2702}
2703
2704void XclExpChLabelRange::WriteBody( XclExpStream& rStrm )
2705{
2706 rStrm << maLabelData.mnCross << maLabelData.mnLabelFreq << maLabelData.mnTickFreq << maLabelData.mnFlags;
2707}
2708
2709XclExpChValueRange::XclExpChValueRange( const XclExpChRoot& rRoot ) :
2710 XclExpRecord( EXC_ID_CHVALUERANGE, 42 ),
2711 XclExpChRoot( rRoot )
2712{
2713}
2714
2715void XclExpChValueRange::Convert( const ScaleData& rScaleData )
2716{
2717 // scaling algorithm
2718 bool bLogScale = ScfApiHelper::GetServiceName( rScaleData.Scaling ) == "com.sun.star.chart2.LogarithmicScaling";
2719 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_LOGSCALE, bLogScale );
2720
2721 // min/max
2722 bool bAutoMin = lclIsAutoAnyOrGetScaledValue( maData.mfMin, rScaleData.Minimum, bLogScale );
2723 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOMIN, bAutoMin );
2724 bool bAutoMax = lclIsAutoAnyOrGetScaledValue( maData.mfMax, rScaleData.Maximum, bLogScale );
2725 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOMAX, bAutoMax );
2726
2727 // origin
2728 bool bAutoCross = lclIsAutoAnyOrGetScaledValue( maData.mfCross, rScaleData.Origin, bLogScale );
2729 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOCROSS, bAutoCross );
2730
2731 // major increment
2732 const IncrementData& rIncrementData = rScaleData.IncrementData;
2733 const bool bAutoMajor = lclIsAutoAnyOrGetValue( maData.mfMajorStep, rIncrementData.Distance ) || (maData.mfMajorStep <= 0.0);
2734 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOMAJOR, bAutoMajor );
2735 // minor increment
2736 const Sequence< SubIncrement >& rSubIncrementSeq = rIncrementData.SubIncrements;
2737 sal_Int32 nCount = 0;
2738
2739 // tdf#114168 If IntervalCount is 5, then enable automatic minor calculation.
2740 // During import, if minorUnit is set and majorUnit not, then it is impossible
2741 // to calculate IntervalCount.
2742 const bool bAutoMinor = bLogScale || bAutoMajor || !rSubIncrementSeq.hasElements() ||
2743 lclIsAutoAnyOrGetValue( nCount, rSubIncrementSeq[ 0 ].IntervalCount ) || (nCount < 1) || (nCount == 5);
2744
2745 if( maData.mfMajorStep && !bAutoMinor )
2746 maData.mfMinorStep = maData.mfMajorStep / nCount;
2747 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOMINOR, bAutoMinor );
2748
2749 // reverse order
2750 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_REVERSE, rScaleData.Orientation == cssc2::AxisOrientation_REVERSE );
2751}
2752
2753void XclExpChValueRange::ConvertAxisPosition( const ScfPropertySet& rPropSet )
2754{
2755 cssc::ChartAxisPosition eAxisPos = cssc::ChartAxisPosition_VALUE;
2756 double fCrossingPos = 0.0;
2757 if( !(rPropSet.GetProperty( eAxisPos, EXC_CHPROP_CROSSOVERPOSITION"CrossoverPosition" ) && rPropSet.GetProperty( fCrossingPos, EXC_CHPROP_CROSSOVERVALUE"CrossoverValue" )) )
2758 return;
2759
2760 switch( eAxisPos )
2761 {
2762 case cssc::ChartAxisPosition_ZERO:
2763 case cssc::ChartAxisPosition_START:
2764 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOCROSS );
2765 break;
2766 case cssc::ChartAxisPosition_END:
2767 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_MAXCROSS );
2768 break;
2769 case cssc::ChartAxisPosition_VALUE:
2770 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOCROSS, false );
2771 maData.mfCross = ::get_flagvalue< double >( maData.mnFlags, EXC_CHVALUERANGE_LOGSCALE, log( fCrossingPos ) / log( 10.0 ), fCrossingPos );
2772 break;
2773 default:
2774 ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOCROSS );
2775 }
2776}
2777
2778void XclExpChValueRange::WriteBody( XclExpStream& rStrm )
2779{
2780 rStrm << maData.mfMin
2781 << maData.mfMax
2782 << maData.mfMajorStep
2783 << maData.mfMinorStep
2784 << maData.mfCross
2785 << maData.mnFlags;
2786}
2787
2788namespace {
2789
2790sal_uInt8 lclGetXclTickPos( sal_Int32 nApiTickmarks )
2791{
2792 using namespace cssc2::TickmarkStyle;
2793 sal_uInt8 nXclTickPos = 0;
2794 ::set_flag( nXclTickPos, EXC_CHTICK_INSIDE, ::get_flag( nApiTickmarks, INNER ) );
2795 ::set_flag( nXclTickPos, EXC_CHTICK_OUTSIDE, ::get_flag( nApiTickmarks, OUTER ) );
2796 return nXclTickPos;
2797}
2798
2799} // namespace
2800
2801XclExpChTick::XclExpChTick( const XclExpChRoot& rRoot ) :
2802 XclExpRecord( EXC_ID_CHTICK, (rRoot.GetBiff() == EXC_BIFF8) ? 30 : 26 ),
2803 XclExpChRoot( rRoot ),
2804 mnTextColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWTEXT ) )
2805{
2806}
2807
2808void XclExpChTick::Convert( const ScfPropertySet& rPropSet, const XclChExtTypeInfo& rTypeInfo, sal_uInt16 nAxisType )
2809{
2810 // tick mark style
2811 sal_Int32 nApiTickmarks = 0;
2812 if( rPropSet.GetProperty( nApiTickmarks, EXC_CHPROP_MAJORTICKS"MajorTickmarks" ) )
2813 maData.mnMajor = lclGetXclTickPos( nApiTickmarks );
2814 if( rPropSet.GetProperty( nApiTickmarks, EXC_CHPROP_MINORTICKS"MinorTickmarks" ) )
2815 maData.mnMinor = lclGetXclTickPos( nApiTickmarks );
2816
2817 // axis labels
2818 if( (rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_RADAR) && (nAxisType == EXC_CHAXIS_X) )
2819 {
2820 /* Radar charts disable their category labels via chart type, not via
2821 axis, and axis labels are always 'near axis'. */
2822 maData.mnLabelPos = EXC_CHTICK_NEXT;
2823 }
2824 else if( !rPropSet.GetBoolProperty( EXC_CHPROP_DISPLAYLABELS"DisplayLabels" ) )
2825 {
2826 // no labels
2827 maData.mnLabelPos = EXC_CHTICK_NOLABEL;
2828 }
2829 else if( rTypeInfo.mb3dChart && (nAxisType == EXC_CHAXIS_Y) )
2830 {
2831 // Excel expects 'near axis' at Y axes in 3D charts
2832 maData.mnLabelPos = EXC_CHTICK_NEXT;
2833 }
2834 else
2835 {
2836 cssc::ChartAxisLabelPosition eApiLabelPos = cssc::ChartAxisLabelPosition_NEAR_AXIS;
2837 rPropSet.GetProperty( eApiLabelPos, EXC_CHPROP_LABELPOSITION"LabelPosition" );
2838 switch( eApiLabelPos )
2839 {
2840 case cssc::ChartAxisLabelPosition_NEAR_AXIS:
2841 case cssc::ChartAxisLabelPosition_NEAR_AXIS_OTHER_SIDE: maData.mnLabelPos = EXC_CHTICK_NEXT; break;
2842 case cssc::ChartAxisLabelPosition_OUTSIDE_START: maData.mnLabelPos = EXC_CHTICK_LOW; break;
2843 case cssc::ChartAxisLabelPosition_OUTSIDE_END: maData.mnLabelPos = EXC_CHTICK_HIGH; break;
2844 default: maData.mnLabelPos = EXC_CHTICK_NEXT;
2845 }
2846 }
2847}
2848
2849void XclExpChTick::SetFontColor( const Color& rColor, sal_uInt32 nColorId )
2850{
2851 maData.maTextColor = rColor;
2852 ::set_flag( maData.mnFlags, EXC_CHTICK_AUTOCOLOR, rColor == COL_AUTO );
2853 mnTextColorId = nColorId;
2854}
2855
2856void XclExpChTick::SetRotation( sal_uInt16 nRotation )
2857{
2858 maData.mnRotation = nRotation;
2859 ::set_flag( maData.mnFlags, EXC_CHTICK_AUTOROT, false );
2860 ::insert_value( maData.mnFlags, XclTools::GetXclOrientFromRot( nRotation ), 2, 3 );
2861}
2862
2863void XclExpChTick::WriteBody( XclExpStream& rStrm )
2864{
2865 rStrm << maData.mnMajor
2866 << maData.mnMinor
2867 << maData.mnLabelPos
2868 << maData.mnBackMode;
2869 rStrm.WriteZeroBytes( 16 );
2870 rStrm << maData.maTextColor
2871 << maData.mnFlags;
2872 if( GetBiff() == EXC_BIFF8 )
2873 rStrm << GetPalette().GetColorIndex( mnTextColorId ) << maData.mnRotation;
2874}
2875
2876namespace {
2877
2878/** Returns an API axis object from the passed coordinate system. */
2879Reference< XAxis > lclGetApiAxis( Reference< XCoordinateSystem > const & xCoordSystem,
2880 sal_Int32 nApiAxisDim, sal_Int32 nApiAxesSetIdx )
2881{
2882 Reference< XAxis > xAxis;
2883 if( (nApiAxisDim >= 0) && xCoordSystem.is() ) try
2884 {
2885 xAxis = xCoordSystem->getAxisByDimension( nApiAxisDim, nApiAxesSetIdx );
2886 }
2887 catch( Exception& )
2888 {
2889 }
2890 return xAxis;
2891}
2892
2893Reference< cssc::XAxis > lclGetApiChart1Axis( Reference< XChartDocument > const & xChartDoc,
2894 sal_Int32 nApiAxisDim, sal_Int32 nApiAxesSetIdx )
2895{
2896 Reference< cssc::XAxis > xChart1Axis;
2897 try
2898 {
2899 Reference< cssc::XChartDocument > xChart1Doc( xChartDoc, UNO_QUERY_THROW );
2900 Reference< cssc::XAxisSupplier > xChart1AxisSupp( xChart1Doc->getDiagram(), UNO_QUERY_THROW );
2901 switch( nApiAxesSetIdx )
2902 {
2903 case EXC_CHART_AXESSET_PRIMARY:
2904 xChart1Axis = xChart1AxisSupp->getAxis( nApiAxisDim );
2905 break;
2906 case EXC_CHART_AXESSET_SECONDARY:
2907 xChart1Axis = xChart1AxisSupp->getSecondaryAxis( nApiAxisDim );
2908 break;
2909 }
2910 }
2911 catch( Exception& )
2912 {
2913 }
2914 return xChart1Axis;
2915}
2916
2917} // namespace
2918
2919XclExpChAxis::XclExpChAxis( const XclExpChRoot& rRoot, sal_uInt16 nAxisType ) :
2920 XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_AXIS, EXC_ID_CHAXIS, 18 ),
2921 mnNumFmtIdx( EXC_FORMAT_NOTFOUND )
2922{
2923 maData.mnType = nAxisType;
2924}
2925
2926void XclExpChAxis::SetFont( XclExpChFontRef xFont, const Color& rColor, sal_uInt32 nColorId )
2927{
2928 mxFont = xFont;
2929 if( mxTick )
2930 mxTick->SetFontColor( rColor, nColorId );
2931}
2932
2933void XclExpChAxis::SetRotation( sal_uInt16 nRotation )
2934{
2935 if( mxTick )
2936 mxTick->SetRotation( nRotation );
2937}
2938
2939void XclExpChAxis::Convert( Reference< XAxis > const & xAxis, Reference< XAxis > const & xCrossingAxis,
2940 Reference< cssc::XAxis > const & xChart1Axis, const XclChExtTypeInfo& rTypeInfo )
2941{
2942 ScfPropertySet aAxisProp( xAxis );
2943 bool bCategoryAxis = ((GetAxisType() == EXC_CHAXIS_X) && rTypeInfo.mbCategoryAxis) || (GetAxisType() == EXC_CHAXIS_Z);
2944
2945 // axis line format -------------------------------------------------------
2946
2947 mxAxisLine = new XclExpChLineFormat( GetChRoot() );
2948 mxAxisLine->Convert( GetChRoot(), aAxisProp, EXC_CHOBJTYPE_AXISLINE );
2949 // #i58688# axis enabled
2950 mxAxisLine->SetShowAxis( aAxisProp.GetBoolProperty( EXC_CHPROP_SHOW"Show" ) );
2951
2952 // axis scaling and increment ---------------------------------------------
2953
2954 ScfPropertySet aCrossingProp( xCrossingAxis );
2955 if( bCategoryAxis )
2956 {
2957 mxLabelRange = new XclExpChLabelRange( GetChRoot() );
2958 mxLabelRange->SetTicksBetweenCateg( rTypeInfo.mbTicksBetweenCateg );
2959 if( xAxis.is() )
2960 {
2961 ScfPropertySet aChart1AxisProp( xChart1Axis );
2962 // #i71684# radar charts have reversed rotation direction
2963 mxLabelRange->Convert( xAxis->getScaleData(), aChart1AxisProp, (GetAxisType() == EXC_CHAXIS_X) && (rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_RADAR) );
2964 }
2965 // get position of crossing axis on this axis from passed axis object
2966 if( aCrossingProp.Is() )
2967 mxLabelRange->ConvertAxisPosition( aCrossingProp );
2968 }
2969 else
2970 {
2971 mxValueRange = new XclExpChValueRange( GetChRoot() );
2972 if( xAxis.is() )
2973 mxValueRange->Convert( xAxis->getScaleData() );
2974 // get position of crossing axis on this axis from passed axis object
2975 if( aCrossingProp.Is() )
2976 mxValueRange->ConvertAxisPosition( aCrossingProp );
2977 }
2978
2979 // axis caption text ------------------------------------------------------
2980
2981 // axis ticks properties
2982 mxTick = new XclExpChTick( GetChRoot() );
2983 mxTick->Convert( aAxisProp, rTypeInfo, GetAxisType() );
2984
2985 // axis label formatting and rotation
2986 ConvertFontBase( GetChRoot(), aAxisProp );
2987 ConvertRotationBase( aAxisProp, true );
2988
2989 // axis number format
2990 sal_Int32 nApiNumFmt = 0;
2991 if( !bCategoryAxis && aAxisProp.GetProperty( nApiNumFmt, EXC_CHPROP_NUMBERFORMAT"NumberFormat" ) )
2992 {
2993 bool bLinkNumberFmtToSource = false;
2994 if ( !aAxisProp.GetProperty( bLinkNumberFmtToSource, EXC_CHPROP_NUMBERFORMAT_LINKSRC"LinkNumberFormatToSource" ) || !bLinkNumberFmtToSource )
2995 mnNumFmtIdx = GetNumFmtBuffer().Insert( static_cast< sal_uInt32 >( nApiNumFmt ) );
2996 }
2997
2998 // grid -------------------------------------------------------------------
2999
3000 if( !xAxis.is() )
3001 return;
3002
3003 // main grid
3004 ScfPropertySet aGridProp( xAxis->getGridProperties() );
3005 if( aGridProp.GetBoolProperty( EXC_CHPROP_SHOW"Show" ) )
3006 mxMajorGrid = lclCreateLineFormat( GetChRoot(), aGridProp, EXC_CHOBJTYPE_GRIDLINE );
3007 // sub grid
3008 Sequence< Reference< XPropertySet > > aSubGridPropSeq = xAxis->getSubGridProperties();
3009 if( aSubGridPropSeq.hasElements() )
3010 {
3011 ScfPropertySet aSubGridProp( aSubGridPropSeq[ 0 ] );
3012 if( aSubGridProp.GetBoolProperty( EXC_CHPROP_SHOW"Show" ) )
3013 mxMinorGrid = lclCreateLineFormat( GetChRoot(), aSubGridProp, EXC_CHOBJTYPE_GRIDLINE );
3014 }
3015}
3016
3017void XclExpChAxis::ConvertWall( css::uno::Reference< css::chart2::XDiagram > const & xDiagram )
3018{
3019 if( !xDiagram.is() )
3020 return;
3021
3022 switch( GetAxisType() )
3023 {
3024 case EXC_CHAXIS_X:
3025 {
3026 ScfPropertySet aWallProp( xDiagram->getWall() );
3027 mxWallFrame = lclCreateFrame( GetChRoot(), aWallProp, EXC_CHOBJTYPE_WALL3D );
3028 }
3029 break;
3030 case EXC_CHAXIS_Y:
3031 {
3032 ScfPropertySet aFloorProp( xDiagram->getFloor() );
3033 mxWallFrame = lclCreateFrame( GetChRoot(), aFloorProp, EXC_CHOBJTYPE_FLOOR3D );
3034 }
3035 break;
3036 default:
3037 mxWallFrame.clear();
3038 }
3039}
3040
3041void XclExpChAxis::WriteSubRecords( XclExpStream& rStrm )
3042{
3043 lclSaveRecord( rStrm, mxLabelRange );
3044 lclSaveRecord( rStrm, mxValueRange );
3045 if( mnNumFmtIdx != EXC_FORMAT_NOTFOUND )
3046 XclExpUInt16Record( EXC_ID_CHFORMAT, mnNumFmtIdx ).Save( rStrm );
3047 lclSaveRecord( rStrm, mxTick );
3048 lclSaveRecord( rStrm, mxFont );
3049 lclSaveRecord( rStrm, mxAxisLine, EXC_ID_CHAXISLINE, EXC_CHAXISLINE_AXISLINE );
3050 lclSaveRecord( rStrm, mxMajorGrid, EXC_ID_CHAXISLINE, EXC_CHAXISLINE_MAJORGRID );
3051 lclSaveRecord( rStrm, mxMinorGrid, EXC_ID_CHAXISLINE, EXC_CHAXISLINE_MINORGRID );
3052 lclSaveRecord( rStrm, mxWallFrame, EXC_ID_CHAXISLINE, EXC_CHAXISLINE_WALLS );
3053}
3054
3055void XclExpChAxis::WriteBody( XclExpStream& rStrm )
3056{
3057 rStrm << maData.mnType;
3058 rStrm.WriteZeroBytes( 16 );
3059}
3060
3061XclExpChAxesSet::XclExpChAxesSet( const XclExpChRoot& rRoot, sal_uInt16 nAxesSetId ) :
3062 XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_AXESSET, EXC_ID_CHAXESSET, 18 )
3063{
3064 maData.mnAxesSetId = nAxesSetId;
3065 SetFutureRecordContext( 0, nAxesSetId );
3066
3067 /* Need to set a reasonable size for the plot area, otherwise Excel will
3068 move away embedded shapes while auto-sizing the plot area. This is just
3069 a wild guess, but will be fixed with implementing manual positioning of
3070 chart elements. */
3071 maData.maRect.mnX = 262;
3072 maData.maRect.mnY = 626;
3073 maData.maRect.mnWidth = 3187;
3074 maData.maRect.mnHeight = 2633;
3075}
3076
3077sal_uInt16 XclExpChAxesSet::Convert( Reference< XDiagram > const & xDiagram, sal_uInt16 nFirstGroupIdx )
3078{
3079 /* First unused chart type group index is passed to be able to continue
3080 counting of chart type groups for secondary axes set. */
3081 sal_uInt16 nGroupIdx = nFirstGroupIdx;
3082 Reference< XCoordinateSystemContainer > xCoordSysCont( xDiagram, UNO_QUERY );
3083 if( xCoordSysCont.is() )
3084 {
3085 Sequence< Reference< XCoordinateSystem > > aCoordSysSeq = xCoordSysCont->getCoordinateSystems();
3086 if( aCoordSysSeq.hasElements() )
3087 {
3088 /* Process first coordinate system only. Import filter puts all
3089 chart types into one coordinate system. */
3090 Reference< XCoordinateSystem > xCoordSystem = aCoordSysSeq[ 0 ];
3091 sal_Int32 nApiAxesSetIdx = GetApiAxesSetIndex();
3092
3093 // 3d mode
3094 bool b3dChart = xCoordSystem.is() && (xCoordSystem->getDimension() == 3);
3095
3096 // percent charts
3097 namespace ApiAxisType = cssc2::AxisType;
3098 Reference< XAxis > xApiYAxis = lclGetApiAxis( xCoordSystem, EXC_CHART_AXIS_Y, nApiAxesSetIdx );
3099 bool bPercent = xApiYAxis.is() && (xApiYAxis->getScaleData().AxisType == ApiAxisType::PERCENT);
3100
3101 // connector lines in bar charts
3102 ScfPropertySet aDiaProp( xDiagram );
3103 bool bConnectBars = aDiaProp.GetBoolProperty( EXC_CHPROP_CONNECTBARS"ConnectBars" );
3104
3105 // swapped axes sets
3106 ScfPropertySet aCoordSysProp( xCoordSystem );
3107 bool bSwappedAxesSet = aCoordSysProp.GetBoolProperty( EXC_CHPROP_SWAPXANDYAXIS"SwapXAndYAxis" );
3108
3109 // X axis for later use
3110 Reference< XAxis > xApiXAxis = lclGetApiAxis( xCoordSystem, EXC_CHART_AXIS_X, nApiAxesSetIdx );
3111 // X axis labels
3112 ScfPropertySet aXAxisProp( xApiXAxis );
3113 bool bHasXLabels = aXAxisProp.GetBoolProperty( EXC_CHPROP_DISPLAYLABELS"DisplayLabels" );
3114
3115 // process chart types
3116 Reference< XChartTypeContainer > xChartTypeCont( xCoordSystem, UNO_QUERY );
3117 if( xChartTypeCont.is() )
3118 {
3119 const Sequence< Reference< XChartType > > aChartTypeSeq = xChartTypeCont->getChartTypes();
3120 for( const Reference< XChartType >& rChartType : aChartTypeSeq )
3121 {
3122 XclExpChTypeGroupRef xTypeGroup = new XclExpChTypeGroup( GetChRoot(), nGroupIdx );
3123 xTypeGroup->ConvertType( xDiagram, rChartType, nApiAxesSetIdx, b3dChart, bSwappedAxesSet, bHasXLabels );
3124 /* If new chart type group cannot be inserted into a combination
3125 chart with existing type groups, insert all series into last
3126 contained chart type group instead of creating a new group. */
3127 XclExpChTypeGroupRef xLastGroup = GetLastTypeGroup();
3128 if( xLastGroup && !(xTypeGroup->IsCombinable2d() && xLastGroup->IsCombinable2d()) )
3129 {
3130 xLastGroup->ConvertSeries( xDiagram, rChartType, nApiAxesSetIdx, bPercent, bConnectBars );
3131 }
3132 else
3133 {
3134 xTypeGroup->ConvertSeries( xDiagram, rChartType, nApiAxesSetIdx, bPercent, bConnectBars );
3135 if( xTypeGroup->IsValidGroup() )
3136 {
3137 maTypeGroups.AppendRecord( xTypeGroup );
3138 ++nGroupIdx;
3139 }
3140 }
3141 }
3142 }
3143
3144 if( XclExpChTypeGroup* pGroup = GetFirstTypeGroup().get() )
3145 {
3146 const XclChExtTypeInfo& rTypeInfo = pGroup->GetTypeInfo();
3147
3148 // create axes according to chart type (no axes for pie and donut charts)
3149 if( rTypeInfo.meTypeCateg != EXC_CHTYPECATEG_PIE )
3150 {
3151 ConvertAxis( mxXAxis, EXC_CHAXIS_X, mxXAxisTitle, EXC_CHOBJLINK_XAXIS, xCoordSystem, rTypeInfo, EXC_CHART_AXIS_Y );
3152 ConvertAxis( mxYAxis, EXC_CHAXIS_Y, mxYAxisTitle, EXC_CHOBJLINK_YAXIS, xCoordSystem, rTypeInfo, EXC_CHART_AXIS_X );
3153 if( pGroup->Is3dDeepChart() )
3154 ConvertAxis( mxZAxis, EXC_CHAXIS_Z, mxZAxisTitle, EXC_CHOBJLINK_ZAXIS, xCoordSystem, rTypeInfo, EXC_CHART_AXIS_NONE );
3155 }
3156
3157 // X axis category ranges
3158 if( rTypeInfo.mbCategoryAxis && xApiXAxis.is() )
3159 {
3160 const ScaleData aScaleData = xApiXAxis->getScaleData();
3161 for( size_t nIdx = 0, nSize = maTypeGroups.GetSize(); nIdx < nSize; ++nIdx )
3162 maTypeGroups.GetRecord( nIdx )->ConvertCategSequence( aScaleData.Categories );
3163 }
3164
3165 // legend
3166 if( xDiagram.is() && (GetAxesSetId() == EXC_CHAXESSET_PRIMARY) )
3167 {
3168 Reference< XLegend > xLegend = xDiagram->getLegend();
3169 if( xLegend.is() )
3170 {
3171 ScfPropertySet aLegendProp( xLegend );
3172 pGroup->ConvertLegend( aLegendProp );
3173 }
3174 }
3175 }
3176 }
3177 }
3178
3179 // wall/floor/diagram frame formatting
3180 if( xDiagram.is() && (GetAxesSetId() == EXC_CHAXESSET_PRIMARY) )
3181 {
3182 XclExpChTypeGroupRef xTypeGroup = GetFirstTypeGroup();
3183 if( xTypeGroup && xTypeGroup->Is3dWallChart() )
3184 {
3185 // wall/floor formatting (3D charts)
3186 if( mxXAxis )
3187 mxXAxis->ConvertWall( xDiagram );
3188 if( mxYAxis )
3189 mxYAxis->ConvertWall( xDiagram );
3190 }
3191 else
3192 {
3193 // diagram background formatting
3194 ScfPropertySet aWallProp( xDiagram->getWall() );
3195 mxPlotFrame = lclCreateFrame( GetChRoot(), aWallProp, EXC_CHOBJTYPE_PLOTFRAME );
3196 }
3197 }
3198
3199 // inner and outer plot area position and size
3200 try
3201 {
3202 Reference< cssc::XChartDocument > xChart1Doc( GetChartDocument(), UNO_QUERY_THROW );
3203 Reference< cssc::XDiagramPositioning > xPositioning( xChart1Doc->getDiagram(), UNO_QUERY_THROW );
3204 // set manual flag in chart data
3205 if( !xPositioning->isAutomaticDiagramPositioning() )
3206 GetChartData().SetManualPlotArea();
3207 // the CHAXESSET record contains the inner plot area
3208 maData.maRect = CalcChartRectFromHmm( xPositioning->calculateDiagramPositionExcludingAxes() );
3209 // the embedded CHFRAMEPOS record contains the outer plot area
3210 mxFramePos = new XclExpChFramePos( EXC_CHFRAMEPOS_PARENT );
3211 // for pie charts, always use inner plot area size to exclude the data labels as Excel does
3212 const XclExpChTypeGroup* pFirstTypeGroup = GetFirstTypeGroup().get();
3213 bool bPieChart = pFirstTypeGroup && (pFirstTypeGroup->GetTypeInfo().meTypeCateg == EXC_CHTYPECATEG_PIE);
3214 mxFramePos->GetFramePosData().maRect = bPieChart ? maData.maRect :
3215 CalcChartRectFromHmm( xPositioning->calculateDiagramPositionIncludingAxes() );
3216 }
3217 catch( Exception& )
3218 {
3219 }
3220
3221 // return first unused chart type group index for next axes set
3222 return nGroupIdx;
3223}
3224
3225bool XclExpChAxesSet::Is3dChart() const
3226{
3227 XclExpChTypeGroupRef xTypeGroup = GetFirstTypeGroup();
3228 return xTypeGroup && xTypeGroup->Is3dChart();
3229}
3230
3231void XclExpChAxesSet::WriteSubRecords( XclExpStream& rStrm )
3232{
3233 lclSaveRecord( rStrm, mxFramePos );
3234 lclSaveRecord( rStrm, mxXAxis );
3235 lclSaveRecord( rStrm, mxYAxis );
3236 lclSaveRecord( rStrm, mxZAxis );
3237 lclSaveRecord( rStrm, mxXAxisTitle );
3238 lclSaveRecord( rStrm, mxYAxisTitle );
3239 lclSaveRecord( rStrm, mxZAxisTitle );
3240 if( mxPlotFrame )
3241 {
3242 XclExpEmptyRecord( EXC_ID_CHPLOTFRAME ).Save( rStrm );
3243 mxPlotFrame->Save( rStrm );
3244 }
3245 maTypeGroups.Save( rStrm );
3246}
3247
3248XclExpChTypeGroupRef XclExpChAxesSet::GetFirstTypeGroup() const
3249{
3250 return maTypeGroups.GetFirstRecord();
3251}
3252
3253XclExpChTypeGroupRef XclExpChAxesSet::GetLastTypeGroup() const
3254{
3255 return maTypeGroups.GetLastRecord();
3256}
3257
3258void XclExpChAxesSet::ConvertAxis(
3259 XclExpChAxisRef& rxChAxis, sal_uInt16 nAxisType,
3260 XclExpChTextRef& rxChAxisTitle, sal_uInt16 nTitleTarget,
3261 Reference< XCoordinateSystem > const & xCoordSystem, const XclChExtTypeInfo& rTypeInfo,
3262 sal_Int32 nCrossingAxisDim )
3263{
3264 // create and convert axis object
3265 rxChAxis = new XclExpChAxis( GetChRoot(), nAxisType );
3266 sal_Int32 nApiAxisDim = rxChAxis->GetApiAxisDimension();
3267 sal_Int32 nApiAxesSetIdx = GetApiAxesSetIndex();
3268 Reference< XAxis > xAxis = lclGetApiAxis( xCoordSystem, nApiAxisDim, nApiAxesSetIdx );
3269 Reference< XAxis > xCrossingAxis = lclGetApiAxis( xCoordSystem, nCrossingAxisDim, nApiAxesSetIdx );
3270 Reference< cssc::XAxis > xChart1Axis = lclGetApiChart1Axis( GetChartDocument(), nApiAxisDim, nApiAxesSetIdx );
3271 rxChAxis->Convert( xAxis, xCrossingAxis, xChart1Axis, rTypeInfo );
3272
3273 // create and convert axis title
3274 Reference< XTitled > xTitled( xAxis, UNO_QUERY );
3275 rxChAxisTitle = lclCreateTitle( GetChRoot(), xTitled, nTitleTarget );
3276}
3277
3278void XclExpChAxesSet::WriteBody( XclExpStream& rStrm )
3279{
3280 rStrm << maData.mnAxesSetId << maData.maRect;
3281}
3282
3283// The chart object ===========================================================
3284
3285static void lcl_getChartSubTitle(const Reference<XChartDocument>& xChartDoc,
3286 OUString& rSubTitle)
3287{
3288 Reference< css::chart::XChartDocument > xChartDoc1(xChartDoc, UNO_QUERY);
3289 if (!xChartDoc1.is())
3290 return;
3291
3292 Reference< XPropertySet > xProp(xChartDoc1->getSubTitle(), UNO_QUERY);
3293 if (!xProp.is())
3294 return;
3295
3296 OUString aTitle;
3297 Any any = xProp->getPropertyValue("String");
3298 if (any >>= aTitle)
3299 rSubTitle = aTitle;
3300}
3301
3302XclExpChChart::XclExpChChart( const XclExpRoot& rRoot,
3303 Reference< XChartDocument > const & xChartDoc, const tools::Rectangle& rChartRect ) :
3304 XclExpChGroupBase( XclExpChRoot( rRoot, *this ), EXC_CHFRBLOCK_TYPE_CHART, EXC_ID_CHCHART, 16 )
3305{
3306 Size aPtSize = OutputDevice::LogicToLogic( rChartRect.GetSize(), MapMode( MapUnit::Map100thMM ), MapMode( MapUnit::MapPoint ) );
3307 // rectangle is stored in 16.16 fixed-point format
3308 maRect.mnX = maRect.mnY = 0;
3309 maRect.mnWidth = static_cast< sal_Int32 >( aPtSize.Width() << 16 );
3310 maRect.mnHeight = static_cast< sal_Int32 >( aPtSize.Height() << 16 );
3311
3312 // global chart properties (default values)
3313 ::set_flag( maProps.mnFlags, EXC_CHPROPS_SHOWVISIBLEONLY, false );
3314 ::set_flag( maProps.mnFlags, EXC_CHPROPS_MANPLOTAREA );
3315 maProps.mnEmptyMode = EXC_CHPROPS_EMPTY_SKIP;
3316
3317 // always create both axes set objects
3318 mxPrimAxesSet = std::make_shared<XclExpChAxesSet>( GetChRoot(), EXC_CHAXESSET_PRIMARY );
3319 mxSecnAxesSet = std::make_shared<XclExpChAxesSet>( GetChRoot(), EXC_CHAXESSET_SECONDARY );
3320
3321 if( !xChartDoc.is() )
3322 return;
3323
3324 Reference< XDiagram > xDiagram = xChartDoc->getFirstDiagram();
3325
3326 // global chart properties (only 'include hidden cells' attribute for now)
3327 ScfPropertySet aDiagramProp( xDiagram );
3328 bool bIncludeHidden = aDiagramProp.GetBoolProperty( EXC_CHPROP_INCLUDEHIDDENCELLS"IncludeHiddenCells" );
3329 ::set_flag( maProps.mnFlags, EXC_CHPROPS_SHOWVISIBLEONLY, !bIncludeHidden );
3330
3331 // initialize API conversion (remembers xChartDoc and rChartRect internally)
3332 InitConversion( xChartDoc, rChartRect );
3333
3334 // chart frame
3335 ScfPropertySet aFrameProp( xChartDoc->getPageBackground() );
3336 mxFrame = lclCreateFrame( GetChRoot(), aFrameProp, EXC_CHOBJTYPE_BACKGROUND );
3337
3338 // chart title
3339 Reference< XTitled > xTitled( xChartDoc, UNO_QUERY );
3340 OUString aSubTitle;
3341 lcl_getChartSubTitle(xChartDoc, aSubTitle);
3342 mxTitle = lclCreateTitle( GetChRoot(), xTitled, EXC_CHOBJLINK_TITLE,
3343 !aSubTitle.isEmpty() ? &aSubTitle : nullptr );
3344
3345 // diagrams (axes sets)
3346 sal_uInt16 nFreeGroupIdx = mxPrimAxesSet->Convert( xDiagram, 0 );
3347 if( !mxPrimAxesSet->Is3dChart() )
3348 mxSecnAxesSet->Convert( xDiagram, nFreeGroupIdx );
3349
3350 // treatment of missing values
3351 ScfPropertySet aDiaProp( xDiagram );
3352 sal_Int32 nMissingValues = 0;
3353 if( aDiaProp.GetProperty( nMissingValues, EXC_CHPROP_MISSINGVALUETREATMENT"MissingValueTreatment" ) )
3354 {
3355 using namespace cssc::MissingValueTreatment;
3356 switch( nMissingValues )
3357 {
3358 case LEAVE_GAP: maProps.mnEmptyMode = EXC_CHPROPS_EMPTY_SKIP; break;
3359 case USE_ZERO: maProps.mnEmptyMode = EXC_CHPROPS_EMPTY_ZERO; break;
3360 case CONTINUE: maProps.mnEmptyMode = EXC_CHPROPS_EMPTY_INTERPOLATE; break;
3361 }
3362 }
3363
3364 // finish API conversion
3365 FinishConversion();
3366}
3367
3368XclExpChSeriesRef XclExpChChart::CreateSeries()
3369{
3370 XclExpChSeriesRef xSeries;
3371 sal_uInt16 nSeriesIdx = static_cast< sal_uInt16 >( maSeries.GetSize() );
3372 if( nSeriesIdx <= EXC_CHSERIES_MAXSERIES )
3373 {
3374 xSeries = new XclExpChSeries( GetChRoot(), nSeriesIdx );
3375 maSeries.AppendRecord( xSeries );
3376 }
3377 return xSeries;
3378}
3379
3380void XclExpChChart::RemoveLastSeries()
3381{
3382 if( !maSeries.IsEmpty() )
3383 maSeries.RemoveRecord( maSeries.GetSize() - 1 );
3384}
3385
3386void XclExpChChart::SetDataLabel( XclExpChTextRef const & xText )
3387{
3388 if( xText )
3389 maLabels.AppendRecord( xText );
3390}
3391
3392void XclExpChChart::SetManualPlotArea()
3393{
3394 // this flag does not exist in BIFF5
3395 if( GetBiff() == EXC_BIFF8 )
3396 ::set_flag( maProps.mnFlags, EXC_CHPROPS_USEMANPLOTAREA );
3397}
3398
3399void XclExpChChart::WriteSubRecords( XclExpStream& rStrm )
3400{
3401 // background format
3402 lclSaveRecord( rStrm, mxFrame );
3403
3404 // data series
3405 maSeries.Save( rStrm );
3406
3407 // CHPROPERTIES record
3408 rStrm.StartRecord( EXC_ID_CHPROPERTIES, 4 );
3409 rStrm << maProps.mnFlags << maProps.mnEmptyMode << sal_uInt8( 0 );
3410 rStrm.EndRecord();
3411
3412 // axes sets (always save primary axes set)
3413 sal_uInt16 nUsedAxesSets = mxSecnAxesSet->IsValidAxesSet() ? 2 : 1;
3414 XclExpUInt16Record( EXC_ID_CHUSEDAXESSETS, nUsedAxesSets ).Save( rStrm );
3415 mxPrimAxesSet->Save( rStrm );
3416 if( mxSecnAxesSet->IsValidAxesSet() )
3417 mxSecnAxesSet->Save( rStrm );
3418
3419 // chart title and data labels
3420 lclSaveRecord( rStrm, mxTitle );
3421 maLabels.Save( rStrm );
3422}
3423
3424void XclExpChChart::WriteBody( XclExpStream& rStrm )
3425{
3426 rStrm << maRect;
3427}
3428
3429XclExpChartDrawing::XclExpChartDrawing( const XclExpRoot& rRoot,
3430 const Reference< XModel >& rxModel, const Size& rChartSize ) :
3431 XclExpRoot( rRoot )
3432{
3433 if( rChartSize.IsEmpty() )
3434 return;
3435
3436 ScfPropertySet aPropSet( rxModel );
3437 Reference< XShapes > xShapes;
3438 if( !(aPropSet.GetProperty( xShapes, EXC_CHPROP_ADDITIONALSHAPES"AdditionalShapes" ) && xShapes.is() && (xShapes->getCount() > 0)) )
3439 return;
3440
3441 /* Create a new independent object manager with own DFF stream for the
3442 DGCONTAINER, pass global manager as parent for shared usage of
3443 global DFF data (picture container etc.). */
3444 mxObjMgr = std::make_shared<XclExpEmbeddedObjectManager>( GetObjectManager(), rChartSize, EXC_CHART_TOTALUNITS, EXC_CHART_TOTALUNITS );
3445 // initialize the drawing object list
3446 mxObjMgr->StartSheet();
3447 // process the draw page (convert all shapes)
3448 mxObjRecs = mxObjMgr->ProcessDrawing( xShapes );
3449 // finalize the DFF stream
3450 mxObjMgr->EndDocument();
3451}
3452
3453XclExpChartDrawing::~XclExpChartDrawing()
3454{
3455}
3456
3457void XclExpChartDrawing::Save( XclExpStream& rStrm )
3458{
3459 if( mxObjRecs )
3460 mxObjRecs->Save( rStrm );
3461}
3462
3463XclExpChart::XclExpChart( const XclExpRoot& rRoot, Reference< XModel > const & xModel, const tools::Rectangle& rChartRect ) :
3464 XclExpSubStream( EXC_BOF_CHART ),
3465 XclExpRoot( rRoot )
3466{
3467 AppendNewRecord( new XclExpChartPageSettings( rRoot ) );
3468 AppendNewRecord( new XclExpBoolRecord( EXC_ID_PROTECT, false ) );
3469 AppendNewRecord( new XclExpChartDrawing( rRoot, xModel, rChartRect.GetSize() ) );
3470 AppendNewRecord( new XclExpUInt16Record( EXC_ID_CHUNITS, EXC_CHUNITS_TWIPS ) );
3471
3472 Reference< XChartDocument > xChartDoc( xModel, UNO_QUERY );
3473 AppendNewRecord( new XclExpChChart( rRoot, xChartDoc, rChartRect ) );
3474}
3475
3476/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/include/com/sun/star/uno/Reference.h

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_COM_SUN_STAR_UNO_REFERENCE_H
20#define INCLUDED_COM_SUN_STAR_UNO_REFERENCE_H
21
22#include "sal/config.h"
23
24#include <cassert>
25#include <cstddef>
26
27#if defined LIBO_INTERNAL_ONLY1
28#include <type_traits>
29#endif
30
31#include "rtl/alloc.h"
32
33namespace com
34{
35namespace sun
36{
37namespace star
38{
39namespace uno
40{
41
42class RuntimeException;
43class XInterface;
44class Type;
45class Any;
46
47/** Enum defining UNO_REF_NO_ACQUIRE for setting reference without acquiring a given interface.
48 Deprecated, please use SAL_NO_ACQUIRE.
49 @deprecated
50*/
51enum UnoReference_NoAcquire
52{
53 /** This enum value can be used for creating a reference granting a given interface,
54 i.e. transferring ownership to it.
55 */
56 UNO_REF_NO_ACQUIRE
57};
58
59/** This base class serves as a base class for all template reference classes and
60 has been introduced due to compiler problems with templated operators ==, =!.
61*/
62class BaseReference
63{
64protected:
65 /** the interface pointer
66 */
67 XInterface * _pInterface;
68
69 /** Queries given interface for type rType.
70
71 @param pInterface interface pointer
72 @param rType interface type
73 @return interface of demanded type (may be null)
74 */
75 inline static XInterface * SAL_CALL iquery( XInterface * pInterface, const Type & rType );
76 /** Queries given interface for type rType.
77 Throws a RuntimeException if the demanded interface cannot be queried.
78
79 @param pInterface interface pointer
80 @param rType interface type
81 @return interface of demanded type
82 */
83 inline static XInterface * SAL_CALL iquery_throw( XInterface * pInterface, const Type & rType );
84
85public:
86 /** Gets interface pointer. This call does not acquire the interface.
87
88 @return UNacquired interface pointer
89 */
90 XInterface * SAL_CALL get() const
91 { return _pInterface; }
92
93 /** Checks if reference is null.
94
95 @return true if reference acquires an interface, i.e. true if it is not null
96 */
97 bool SAL_CALL is() const
98 { return (NULL__null != _pInterface); }
6
Assuming NULL is not equal to field '_pInterface'
7
Returning the value 1, which participates in a condition later
99
100#if defined LIBO_INTERNAL_ONLY1
101 /** Checks if reference is null.
102
103 @return true if reference acquires an interface, i.e. true if it is not null
104 */
105 explicit operator bool() const
106 { return is(); }
107#endif
108
109 /** Equality operator: compares two interfaces
110 Checks if both references are null or refer to the same object.
111
112 @param pInterface another interface
113 @return true if both references are null or refer to the same object, false otherwise
114 */
115 inline bool SAL_CALL operator == ( XInterface * pInterface ) const;
116 /** Inequality operator: compares two interfaces
117 Checks if both references are null or refer to the same object.
118
119 @param pInterface another interface
120 @return false if both references are null or refer to the same object, true otherwise
121 */
122 inline bool SAL_CALL operator != ( XInterface * pInterface ) const;
123
124 /** Equality operator: compares two interfaces
125 Checks if both references are null or refer to the same object.
126
127 @param rRef another reference
128 @return true if both references are null or refer to the same object, false otherwise
129 */
130 inline bool SAL_CALL operator == ( const BaseReference & rRef ) const;
131 /** Inequality operator: compares two interfaces
132 Checks if both references are null or refer to the same object.
133
134 @param rRef another reference
135 @return false if both references are null or refer to the same object, true otherwise
136 */
137 inline bool SAL_CALL operator != ( const BaseReference & rRef ) const;
138
139 /** Needed by some STL containers.
140
141 @param rRef another reference
142 @return true, if this reference is less than rRef
143 */
144 inline bool SAL_CALL operator < ( const BaseReference & rRef ) const;
145};
146
147/** Enum defining UNO_QUERY for implicit interface query.
148*/
149enum UnoReference_Query
150{
151 /** This enum value can be used for implicit interface query.
152 */
153 UNO_QUERY
154};
155/** Enum defining UNO_QUERY_THROW for implicit interface query.
156 If the demanded interface is unavailable, then a RuntimeException is thrown.
157*/
158enum UnoReference_QueryThrow
159{
160 /** This enum value can be used for implicit interface query.
161 */
162 UNO_QUERY_THROW
163};
164/** Enum defining UNO_SET_THROW for throwing if attempts are made to assign a null
165 interface
166
167 @since UDK 3.2.8
168*/
169enum UnoReference_SetThrow
170{
171 UNO_SET_THROW
172};
173
174/** Template reference class for interface type derived from BaseReference.
175 A special constructor given the UNO_QUERY identifier queries interfaces
176 for reference type.
177*/
178template< class interface_type >
179class SAL_DLLPUBLIC_RTTI__attribute__ ((type_visibility("default"))) Reference : public BaseReference
180{
181 /** Queries given interface for type interface_type.
182
183 @param pInterface interface pointer
184 @return interface of demanded type (may be null)
185 */
186 inline static XInterface * SAL_CALL iquery( XInterface * pInterface );
187 /** Queries given interface for type interface_type.
188 Throws a RuntimeException if the demanded interface cannot be queried.
189
190 @param pInterface interface pointer
191 @return interface of demanded type
192 */
193 inline static XInterface * SAL_CALL iquery_throw( XInterface * pInterface );
194 /** Returns the given interface if it is not <NULL/>, throws a RuntimeException otherwise.
195
196 @param pInterface interface pointer
197 @return pInterface
198 */
199 inline static interface_type * SAL_CALL iset_throw( interface_type * pInterface );
200
201 /** Cast from an "interface pointer" (e.g., BaseReference::_pInterface) to a
202 pointer to this interface_type.
203
204 To work around ambiguities in the case of multiple-inheritance interface
205 types (which inherit XInterface more than once), use reinterpret_cast
206 (resp. a sequence of two static_casts, to avoid warnings about
207 reinterpret_cast used between related classes) to switch from a pointer
208 to XInterface to a pointer to this derived interface_type. In
209 principle, this is not guaranteed to work. In practice, it seems to
210 work on all supported platforms.
211 */
212 static interface_type * castFromXInterface(XInterface * p) {
213 return static_cast< interface_type * >(static_cast< void * >(p));
214 }
215
216 /** Cast from a pointer to this interface_type to an "interface pointer"
217 (e.g., BaseReference::_pInterface).
218
219 To work around ambiguities in the case of multiple-inheritance interface
220 types (which inherit XInterface more than once), use reinterpret_cast
221 (resp. a sequence of two static_casts, to avoid warnings about
222 reinterpret_cast used between related classes) to switch from a pointer
223 to this derived interface_type to a pointer to XInterface. In
224 principle, this is not guaranteed to work. In practice, it seems to
225 work on all supported platforms.
226 */
227 static XInterface * castToXInterface(interface_type * p) {
228 return static_cast< XInterface * >(static_cast< void * >(p));
229 }
230
231public:
232 /// @cond INTERNAL
233 // these are here to force memory de/allocation to sal lib.
234 static void * SAL_CALL operator new ( ::size_t nSize )
235 { return ::rtl_allocateMemory( nSize ); }
236 static void SAL_CALL operator delete ( void * pMem )
237 { ::rtl_freeMemory( pMem ); }
238 static void * SAL_CALL operator new ( ::size_t, void * pMem )
239 { return pMem; }
240 static void SAL_CALL operator delete ( void *, void * )
241 {}
242 /// @endcond
243
244 /** Destructor: Releases interface if set.
245 */
246 inline ~Reference() COVERITY_NOEXCEPT_FALSE;
247
248 /** Default Constructor: Sets null reference.
249 */
250 inline Reference();
251
252 /** Copy constructor: Copies interface reference.
253
254 @param rRef another reference
255 */
256 inline Reference( const Reference< interface_type > & rRef );
257
258#if defined LIBO_INTERNAL_ONLY1
259 /** Move constructor
260
261 @param rRef another reference
262 */
263 inline Reference( Reference< interface_type > && rRef ) noexcept;
264
265 /** Up-casting conversion constructor: Copies interface reference.
266
267 Does not work for up-casts to ambiguous bases. For the special case of
268 up-casting to Reference< XInterface >, see the corresponding conversion
269 operator.
270
271 @param rRef another reference
272 */
273 template< class derived_type >
274 inline Reference(
275 const Reference< derived_type > & rRef,
276 std::enable_if_t<
277 std::is_base_of_v<interface_type, derived_type>
278 && !std::is_same_v<interface_type, XInterface>, void *> = nullptr);
279#endif
280
281 /** Constructor: Sets given interface pointer.
282
283 @param pInterface an interface pointer
284 */
285 inline Reference( interface_type * pInterface );
286
287 /** Constructor: Sets given interface pointer without acquiring it.
288
289 @param pInterface another reference
290 @param dummy SAL_NO_ACQUIRE to force obvious distinction to other constructors
291 */
292 inline Reference( interface_type * pInterface, __sal_NoAcquire dummy);
293 /** Constructor: Sets given interface pointer without acquiring it.
294 Deprecated, please use SAL_NO_ACQUIRE version.
295
296 @deprecated
297 @param pInterface another reference
298 @param dummy UNO_REF_NO_ACQUIRE to force obvious distinction to other constructors
299 */
300 inline SAL_DEPRECATED("use SAL_NO_ACQUIRE version")__attribute__((deprecated("use SAL_NO_ACQUIRE version"))) Reference( interface_type * pInterface, UnoReference_NoAcquire dummy );
301
302 /** Constructor: Queries given interface for reference interface type (interface_type).
303
304 @param rRef another reference
305 @param dummy UNO_QUERY to force obvious distinction to other constructors
306 */
307 inline Reference( const BaseReference & rRef, UnoReference_Query dummy );
308 /** Constructor: Queries given interface for reference interface type (interface_type).
309
310 @param pInterface an interface pointer
311 @param dummy UNO_QUERY to force obvious distinction to other constructors
312 */
313 inline Reference( XInterface * pInterface, UnoReference_Query dummy);
314 /** Constructor: Queries given any for reference interface type (interface_type).
315
316 @param rAny an any
317 @param dummy UNO_QUERY to force obvious distinction to other constructors
318 */
319 inline Reference( const Any & rAny, UnoReference_Query dummy);
320 /** Constructor: Queries given interface for reference interface type (interface_type).
321 Throws a RuntimeException if the demanded interface cannot be queried.
322
323 @param rRef another reference
324 @param dummy UNO_QUERY_THROW to force obvious distinction
325 to other constructors
326 */
327 inline Reference( const BaseReference & rRef, UnoReference_QueryThrow dummy );
328#ifdef LIBO_INTERNAL_ONLY1
329 /**
330 Prevent code from calling the QUERY_THROW constructor, when they meant to use the SET_THROW constructor.
331 */
332 Reference( const Reference< interface_type > & rRef, UnoReference_QueryThrow dummy ) = delete;
333#endif
334 /** Constructor: Queries given interface for reference interface type (interface_type).
335 Throws a RuntimeException if the demanded interface cannot be queried.
336
337 @param pInterface an interface pointer
338 @param dummy UNO_QUERY_THROW to force obvious distinction
339 to other constructors
340 */
341 inline Reference( XInterface * pInterface, UnoReference_QueryThrow dummy );
342 /** Constructor: Queries given any for reference interface type (interface_type).
343 Throws a RuntimeException if the demanded interface cannot be queried.
344
345 @param rAny an any
346 @param dummy UNO_QUERY_THROW to force obvious distinction
347 to other constructors
348 */
349 inline Reference( const Any & rAny, UnoReference_QueryThrow dummy );
350 /** Constructor: assigns from the given interface of the same type. Throws a RuntimeException
351 if the source interface is NULL.
352
353 @param rRef another interface reference of the same type
354 @param dummy UNO_SET_THROW to distinguish from default copy constructor
355
356 @since UDK 3.2.8
357 */
358 inline Reference( const Reference< interface_type > & rRef, UnoReference_SetThrow dummy );
359 /** Constructor: assigns from the given interface of the same type. Throws a RuntimeException
360 if the source interface is NULL.
361
362 @param pInterface an interface pointer
363 @param dummy UNO_SET_THROW to distinguish from default assignment constructor
364
365 @since UDK 3.2.8
366 */
367 inline Reference( interface_type * pInterface, UnoReference_SetThrow dummy );
368
369 /** Cast operator to Reference< XInterface >: Reference objects are binary compatible and
370 any interface must be derived from com.sun.star.uno.XInterface.
371 This a useful direct cast possibility.
372 */
373 SAL_CALL operator const Reference< XInterface > & () const
374 { return * reinterpret_cast< const Reference< XInterface > * >( this ); }
375
376 /** Dereference operator: Used to call interface methods.
377
378 @return UNacquired interface pointer
379 */
380 interface_type * SAL_CALL operator -> () const {
381 assert(_pInterface != NULL)(static_cast <bool> (_pInterface != __null) ? void (0) :
__assert_fail ("_pInterface != NULL", "/home/maarten/src/libreoffice/core/include/com/sun/star/uno/Reference.h"
, 381, __extension__ __PRETTY_FUNCTION__))
;
382 return castFromXInterface(_pInterface);
383 }
384
385 /** Indirection operator.
386
387 @since LibreOffice 6.3
388 @return UNacquired interface reference
389 */
390 interface_type & SAL_CALL operator * () const {
391 assert(_pInterface != NULL)(static_cast <bool> (_pInterface != __null) ? void (0) :
__assert_fail ("_pInterface != NULL", "/home/maarten/src/libreoffice/core/include/com/sun/star/uno/Reference.h"
, 391, __extension__ __PRETTY_FUNCTION__))
;
392 return *castFromXInterface(_pInterface);
393 }
394
395 /** Gets interface pointer. This call does not acquire the interface.
396
397 @return UNacquired interface pointer
398 */
399 interface_type * SAL_CALL get() const
400 { return castFromXInterface(_pInterface); }
401
402 /** Clears reference, i.e. releases interface. Reference is null after clear() call.
403 */
404 inline void SAL_CALL clear();
405
406 /** Sets the given interface. An interface already set will be released.
407
408 @param rRef another reference
409 @return true, if non-null interface was set
410 */
411 inline bool SAL_CALL set( const Reference< interface_type > & rRef );
412 /** Sets the given interface. An interface already set will be released.
413
414 @param pInterface another interface
415 @return true, if non-null interface was set
416 */
417 inline bool SAL_CALL set( interface_type * pInterface );
418
419 /** Sets interface pointer without acquiring it. An interface already set will be released.
420
421 @param pInterface an interface pointer
422 @param dummy SAL_NO_ACQUIRE to force obvious distinction to set methods
423 @return true, if non-null interface was set
424 */
425 inline bool SAL_CALL set( interface_type * pInterface, __sal_NoAcquire dummy);
426 /** Sets interface pointer without acquiring it. An interface already set will be released.
427 Deprecated, please use SAL_NO_ACQUIRE version.
428
429 @deprecated
430 @param pInterface an interface pointer
431 @param dummy UNO_REF_NO_ACQUIRE to force obvious distinction to set methods
432 @return true, if non-null interface was set
433 */
434 inline SAL_DEPRECATED("use SAL_NO_ACQUIRE version")__attribute__((deprecated("use SAL_NO_ACQUIRE version"))) bool SAL_CALL set( interface_type * pInterface, UnoReference_NoAcquire dummy);
435
436 /** Queries given interface for reference interface type (interface_type) and sets it.
437 An interface already set will be released.
438
439 @param pInterface an interface pointer
440 @param dummy UNO_QUERY to force obvious distinction to set methods
441 @return true, if non-null interface was set
442 */
443 inline bool SAL_CALL set( XInterface * pInterface, UnoReference_Query dummy );
444 /** Queries given interface for reference interface type (interface_type) and sets it.
445 An interface already set will be released.
446
447 @param rRef another reference
448 @param dummy UNO_QUERY to force obvious distinction to set methods
449 @return true, if non-null interface was set
450 */
451 inline bool SAL_CALL set( const BaseReference & rRef, UnoReference_Query dummy);
452
453 /** Queries given any for reference interface type (interface_type)
454 and sets it. An interface already set will be released.
455
456 @param rAny
457 an Any containing an interface
458 @param dummy
459 UNO_QUERY to force obvious distinction
460 to set methods
461 @return
462 true, if non-null interface was set
463 */
464 inline bool set( Any const & rAny, UnoReference_Query dummy );
465
466 /** Queries given interface for reference interface type (interface_type) and sets it.
467 An interface already set will be released.
468 Throws a RuntimeException if the demanded interface cannot be set.
469
470 @param pInterface an interface pointer
471 @param dummy UNO_QUERY_THROW to force obvious distinction
472 to set methods
473 */
474 inline void SAL_CALL set( XInterface * pInterface, UnoReference_QueryThrow dummy );
475 /** Queries given interface for reference interface type (interface_type) and sets it.
476 An interface already set will be released.
477 Throws a RuntimeException if the demanded interface cannot be set.
478
479 @param rRef another reference
480 @param dummy UNO_QUERY_THROW to force obvious distinction
481 to set methods
482 */
483 inline void SAL_CALL set( const BaseReference & rRef, UnoReference_QueryThrow dummy );
484#ifdef LIBO_INTERNAL_ONLY1
485 /**
486 Prevent code from calling the QUERY_THROW version, when they meant to use the SET_THROW version.
487 */
488 void set( const Reference< interface_type > & rRef, UnoReference_QueryThrow dummy ) = delete;
489#endif
490
491 /** Queries given any for reference interface type (interface_type) and
492 sets it. An interface already set will be released.
493 Throws a RuntimeException if the demanded interface cannot be set.
494
495 @param rAny
496 an Any containing an interface
497 @param dummy
498 UNO_QUERY_THROW to force obvious distinction to set methods
499 */
500 inline void set( Any const & rAny, UnoReference_QueryThrow dummy);
501 /** sets the given interface
502 An interface already set will be released.
503 Throws a RuntimeException if the source interface is @b NULL.
504
505 @param pInterface an interface pointer
506 @param dummy UNO_SET_THROW to force obvious distinction to other set methods
507
508 @since UDK 3.2.8
509 */
510 inline void SAL_CALL set( interface_type * pInterface, UnoReference_SetThrow dummy);
511 /** sets the given interface
512 An interface already set will be released.
513 Throws a RuntimeException if the source interface is @b NULL.
514
515 @param rRef an interface reference
516 @param dummy UNO_SET_THROW to force obvious distinction to other set methods
517
518 @since UDK 3.2.8
519 */
520 inline void SAL_CALL set( const Reference< interface_type > & rRef, UnoReference_SetThrow dummy);
521
522
523 /** Assignment operator: Acquires given interface pointer and sets reference.
524 An interface already set will be released.
525
526 @param pInterface an interface pointer
527 @return this reference
528 */
529 inline Reference< interface_type > & SAL_CALL operator = ( interface_type * pInterface );
530 /** Assignment operator: Acquires given interface reference and sets reference.
531 An interface already set will be released.
532
533 @param rRef an interface reference
534 @return this reference
535 */
536 inline Reference< interface_type > & SAL_CALL operator = ( const Reference< interface_type > & rRef );
537#if defined LIBO_INTERNAL_ONLY1
538 /** Assignment move operator: Acquires given interface reference and sets reference.
539 An interface already set will be released.
540
541 @param rRef an interface reference
542 @return this reference
543 */
544 inline Reference< interface_type > & SAL_CALL operator = ( Reference< interface_type > && rRef ) noexcept;
545#endif
546 /** Queries given interface reference for type interface_type.
547
548 @param rRef interface reference
549 @return interface reference of demanded type (may be null)
550 */
551 SAL_WARN_UNUSED_RESULT[[nodiscard]] inline static Reference< interface_type > SAL_CALL query( const BaseReference & rRef );
552 /** Queries given interface for type interface_type.
553
554 @param pInterface interface pointer
555 @return interface reference of demanded type (may be null)
556 */
557 SAL_WARN_UNUSED_RESULT[[nodiscard]] inline static Reference< interface_type > SAL_CALL query( XInterface * pInterface );
558};
559
560}
561}
562}
563}
564
565#endif
566
567/* 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;
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
35.1
'asciiStrLength' is not equal to field 'length'
35.1
'asciiStrLength' is not equal to field 'length'
35.1
'asciiStrLength' is not equal to field 'length'
35.1
'asciiStrLength' is not equal to field 'length'
)
14
Assuming 'asciiStrLength' is not equal to field 'length'
15
Taking true branch
25
Assuming 'asciiStrLength' is not equal to field 'length'
26
Taking true branch
36
Taking true branch
46
Assuming 'asciiStrLength' is not equal to field 'length'
47
Taking true branch
57
Assuming 'asciiStrLength' is equal to field 'length'
58
Taking false branch
1194 return false;
16
Returning zero, which participates in a condition later
27
Returning zero, which participates in a condition later
37
Returning zero, which participates in a condition later
48
Returning zero, which participates in a condition later
1195
1196 return rtl_ustr_asciil_reverseEquals_WithLength(
59
Returning value, which participates in a condition later
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__))
11
Assuming the condition is true
12
'?' condition is true
22
Assuming the condition is true
23
'?' condition is true
33
Assuming the condition is true
34
'?' condition is true
43
Assuming the condition is true
44
'?' condition is true
54
Assuming the condition is true
55
'?' condition is true
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(
13
Calling 'OUString::equalsAsciiL'
17
Returning from 'OUString::equalsAsciiL'
18
Returning zero, which participates in a condition later
24
Calling 'OUString::equalsAsciiL'
28
Returning from 'OUString::equalsAsciiL'
29
Returning zero, which participates in a condition later
35
Calling 'OUString::equalsAsciiL'
38
Returning from 'OUString::equalsAsciiL'
39
Returning zero, which participates in a condition later
45
Calling 'OUString::equalsAsciiL'
49
Returning from 'OUString::equalsAsciiL'
50
Returning zero, which participates in a condition later
56
Calling 'OUString::equalsAsciiL'
60
Returning from 'OUString::equalsAsciiL'
61
Returning value, which participates in a condition later
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/sc/source/filter/inc/fapihelper.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_SC_SOURCE_FILTER_INC_FAPIHELPER_HXX
21#define INCLUDED_SC_SOURCE_FILTER_INC_FAPIHELPER_HXX
22
23#include <com/sun/star/uno/Any.hxx>
24#include <com/sun/star/uno/Reference.hxx>
25#include <com/sun/star/uno/Sequence.hxx>
26#include <osl/diagnose.h>
27#include <tools/color.hxx>
28#include "ftools.hxx"
29
30namespace com::sun::star {
31 namespace lang { class XMultiServiceFactory; }
32}
33
34namespace com::sun::star::beans { struct NamedValue; }
35namespace com::sun::star::beans { class XPropertySet; }
36namespace com::sun::star::beans { class XMultiPropertySet; }
37
38namespace comphelper { class IDocPasswordVerifier; }
39
40// Static helper functions ====================================================
41
42class SfxMedium;
43class SfxObjectShell;
44
45/** Static API helper functions. */
46class ScfApiHelper
47{
48public:
49 /** Converts a non-empty vector into a UNO sequence containing elements of the same type. */
50 template< typename Type >
51 static css::uno::Sequence< Type >
52 VectorToSequence( const ::std::vector< Type >& rVector );
53
54 /** Returns the service name provided via the XServiceName interface, or an empty string on error. */
55 static OUString GetServiceName( const css::uno::Reference< css::uno::XInterface >& xInt );
56
57 /** Returns the multi service factory from a document shell. */
58 static css::uno::Reference< css::lang::XMultiServiceFactory > GetServiceFactory( const SfxObjectShell* pShell );
59
60 /** Creates an instance from the passed service name, using the passed service factory. */
61 static css::uno::Reference< css::uno::XInterface > CreateInstance(
62 const css::uno::Reference< css::lang::XMultiServiceFactory >& xFactory,
63 const OUString& rServiceName );
64
65 /** Creates an instance from the passed service name, using the service factory of the passed object. */
66 static css::uno::Reference< css::uno::XInterface > CreateInstance(
67 const SfxObjectShell* pShell,
68 const OUString& rServiceName );
69
70 /** Creates an instance from the passed service name, using the process service factory. */
71 static css::uno::Reference< css::uno::XInterface > CreateInstance( const OUString& rServiceName );
72
73 /** Opens a password dialog and returns the encryption data.
74 @return The encryption data or an empty sequence on 'Cancel' or any error. */
75 static css::uno::Sequence< css::beans::NamedValue > QueryEncryptionDataForMedium( SfxMedium& rMedium,
76 ::comphelper::IDocPasswordVerifier& rVerifier,
77 const ::std::vector< OUString >* pDefaultPasswords );
78};
79
80template< typename Type >
81css::uno::Sequence< Type > ScfApiHelper::VectorToSequence( const ::std::vector< Type >& rVector )
82{
83 OSL_ENSURE( !rVector.empty(), "ScfApiHelper::VectorToSequence - vector is empty" )do { if (true && (!(!rVector.empty()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/filter/inc/fapihelper.hxx"
":" "83" ": "), "%s", "ScfApiHelper::VectorToSequence - vector is empty"
); } } while (false)
;
84 return css::uno::Sequence<Type>(rVector.data(), static_cast< sal_Int32 >(rVector.size()));
85}
86
87// Property sets ==============================================================
88
89/** A wrapper for a UNO property set.
90
91 This class provides functions to silently get and set properties (without
92 exceptions, without the need to check validity of the UNO property set).
93
94 An instance is constructed with the reference to a UNO property set or any
95 other interface (the constructor will query for the XPropertySet interface
96 then). The reference to the property set will be kept as long as the
97 instance of this class is alive.
98
99 The functions GetProperties() and SetProperties() try to handle all passed
100 values at once, using the XMultiPropertySet interface. If the
101 implementation does not support the XMultiPropertySet interface, all
102 properties are handled separately in a loop.
103 */
104class ScfPropertySet
105{
106public:
107 explicit ScfPropertySet() {}
108 /** Constructs a property set wrapper with the passed UNO property set. */
109 explicit ScfPropertySet( const css::uno::Reference< css::beans::XPropertySet > & xPropSet ) { Set( xPropSet ); }
110 /** Constructs a property set wrapper after querying the XPropertySet interface. */
111 template< typename InterfaceType >
112 explicit ScfPropertySet( const css::uno::Reference< InterfaceType >& xInterface ) { Set( xInterface ); }
113
114 ~ScfPropertySet();
115 //TODO:
116 ScfPropertySet(ScfPropertySet const &) = default;
117 ScfPropertySet(ScfPropertySet &&) = default;
118 ScfPropertySet & operator =(ScfPropertySet const &) = default;
119 ScfPropertySet & operator =(ScfPropertySet &&) = default;
120
121 /** Sets the passed UNO property set and releases the old UNO property set. */
122 void Set( css::uno::Reference< css::beans::XPropertySet > const & xPropSet );
123 /** Queries the passed interface for an XPropertySet and releases the old UNO property set. */
124 template< typename InterfaceType >
125 void Set( css::uno::Reference< InterfaceType > xInterface )
126 { Set( css::uno::Reference< css::beans::XPropertySet >( xInterface, css::uno::UNO_QUERY ) ); }
127
128 /** Returns true, if the contained XPropertySet interface is valid. */
129 bool Is() const { return mxPropSet.is(); }
130
131 /** Returns the contained XPropertySet interface. */
132 const css::uno::Reference< css::beans::XPropertySet >& GetApiPropertySet() const { return mxPropSet; }
133
134 /** Returns the service name provided via the XServiceName interface, or an empty string on error. */
135 OUString GetServiceName() const;
136
137 // Get properties ---------------------------------------------------------
138
139 /** Returns true, if the property set contains the specified property. */
140 bool HasProperty( const OUString& rPropName ) const;
141
142 /** Gets the specified property from the property set.
143 @return true, if the Any could be filled with the property value. */
144 bool GetAnyProperty( css::uno::Any& rValue, const OUString& rPropName ) const;
145
146 /** Gets the specified property from the property set.
147 @return true, if the passed variable could be filled with the property value. */
148 template< typename Type >
149 bool GetProperty( Type& rValue, const OUString& rPropName ) const
150 { css::uno::Any aAny; return GetAnyProperty( aAny, rPropName ) && (aAny >>= rValue); }
67
Assuming the condition is false
68
Returning without writing to 'rValue'
151
152 /** Gets the specified Boolean property from the property set.
153 @return true = property contains true; false = property contains false or error occurred. */
154 bool GetBoolProperty( const OUString& rPropName ) const;
155
156 /** Gets the specified Boolean property from the property set. */
157 OUString GetStringProperty( const OUString& rPropName ) const;
158
159 /** Gets the specified color property from the property set.
160 @return true, if the passed color variable could be filled with the property value. */
161 bool GetColorProperty( Color& rColor, const OUString& rPropName ) const;
162
163 /** Gets the specified properties from the property set. Tries to use the XMultiPropertySet interface.
164 @param rPropNames The property names. MUST be ordered alphabetically.
165 @param rValues The related property values. */
166 void GetProperties( css::uno::Sequence< css::uno::Any >& rValues, const css::uno::Sequence< OUString >& rPropNames ) const;
167
168 // Set properties ---------------------------------------------------------
169
170 /** Puts the passed Any into the property set. */
171 void SetAnyProperty( const OUString& rPropName, const css::uno::Any& rValue );
172
173 /** Puts the passed value into the property set. */
174 template< typename Type >
175 void SetProperty( const OUString& rPropName, const Type& rValue )
176 { SetAnyProperty( rPropName, css::uno::makeAny( rValue ) ); }
177
178 /** Puts the passed Boolean value into the property set. */
179 void SetBoolProperty( const OUString& rPropName, bool bValue )
180 { SetAnyProperty( rPropName, css::uno::Any( bValue ) ); }
181
182 /** Puts the passed string into the property set. */
183 void SetStringProperty( const OUString& rPropName, const OUString& rValue )
184 { SetProperty( rPropName, rValue ); }
185
186 /** Puts the passed color into the property set. */
187 void SetColorProperty( const OUString& rPropName, const Color& rColor )
188 { SetProperty( rPropName, sal_Int32( rColor ) ); }
189
190 /** Puts the passed properties into the property set. Tries to use the XMultiPropertySet interface.
191 @param rPropNames The property names. MUST be ordered alphabetically.
192 @param rValues The related property values. */
193 void SetProperties( const css::uno::Sequence< OUString > & rPropNames, const css::uno::Sequence< css::uno::Any >& rValues );
194
195private:
196 css::uno::Reference< css::beans::XPropertySet > mxPropSet; /// The mandatory property set interface.
197 css::uno::Reference< css::beans::XMultiPropertySet > mxMultiPropSet; /// The optional multi property set interface.
198};
199
200/** Generic helper class for reading from and writing to property sets.
201
202 Usage:
203 1) Call the constructor with a null-terminated array of ASCII strings.
204 2a) Read properties from a property set: Call the ReadFromPropertySet()
205 function, then get the properties with the ReadValue() functions or the
206 operator>> stream operator. The properties are returned in order of the
207 array of property names passed in the constructor.
208 2b) Write properties to a property set: Call InitializeWrite() to start a
209 new cycle. Set the values with the WriteValue() functions or the
210 operator<< stream operator. The order of the properties is equal to the
211 array of property names passed in the constructor. Finally, call the
212 WriteToPropertySet() function.
213 */
214class ScfPropSetHelper
215{
216public:
217 /** @param ppPropNames A null-terminated array of ASCII property names. */
218 explicit ScfPropSetHelper( const char* const* ppcPropNames );
219
220 // read properties --------------------------------------------------------
221
222 /** Reads all values from the passed property set. */
223 void ReadFromPropertySet( const ScfPropertySet& rPropSet );
224
225 /** Reads the next value from the value sequence. */
226 template< typename Type >
227 void ReadValue( Type& rValue );
228 /** Reads an Any from the value sequence. */
229 void ReadValue( css::uno::Any& rAny );
230 /** Reads a color value from the value sequence. */
231 void ReadValue( Color& rColor );
232 /** Reads a C++ boolean value from the value sequence. */
233 void ReadValue( bool& rbValue );
234
235 // write properties -------------------------------------------------------
236
237 /** Must be called before reading or storing property values in the helper. */
238 void InitializeWrite();
239
240 /** Writes the next value to the value sequence. */
241 template< typename Type >
242 void WriteValue( const Type& rValue );
243 /** Writes an Any to the value sequence. */
244 void WriteValue( const css::uno::Any& rAny );
245 /** Writes a color value to the value sequence. */
246 void WriteValue( const Color& rColor )
247 { WriteValue( sal_Int32( rColor ) ); }
248 /** Writes a C++ boolean value to the value sequence. */
249 void WriteValue( bool rbValue );
250
251 /** Writes all values to the passed property set. */
252 void WriteToPropertySet( ScfPropertySet& rPropSet ) const;
253
254private:
255 /** Returns a pointer to the next Any to be written to. */
256 css::uno::Any* GetNextAny();
257
258private:
259 css::uno::Sequence< OUString > maNameSeq; /// Sequence of property names.
260 css::uno::Sequence< css::uno::Any > maValueSeq; /// Sequence of property values.
261 ScfInt32Vec maNameOrder; /// Maps initial order to alphabetical order.
262 size_t mnNextIdx; /// Counter for next Any to be processed.
263};
264
265template< typename Type >
266void ScfPropSetHelper::ReadValue( Type& rValue )
267{
268 css::uno::Any* pAny = GetNextAny();
269 if (pAny)
270 *pAny >>= rValue;
271}
272
273template< typename Type >
274void ScfPropSetHelper::WriteValue( const Type& rValue )
275{
276 css::uno::Any* pAny = GetNextAny();
277 if( pAny )
278 *pAny <<= rValue;
279}
280
281template< typename Type >
282ScfPropSetHelper& operator>>( ScfPropSetHelper& rPropSetHelper, Type& rValue )
283{
284 rPropSetHelper.ReadValue( rValue );
285 return rPropSetHelper;
286}
287
288template< typename Type >
289ScfPropSetHelper& operator<<( ScfPropSetHelper& rPropSetHelper, const Type& rValue )
290{
291 rPropSetHelper.WriteValue( rValue );
292 return rPropSetHelper;
293}
294
295#endif
296
297/* vim:set shiftwidth=4 softtabstop=4 expandtab: */