1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
23 #include <o3tl/safeint.hxx>
24 #include <osl/diagnose.h>
25 #include <tools/solar.h>
26 #include <xlstyle.hxx>
27 #include <xestyle.hxx>
28 #include <xestream.hxx>
29 #include <xestring.hxx>
30 #include <oox/token/tokens.hxx>
32 using namespace ::oox
;
38 /** Compares two vectors.
39 @return A negative value, if rLeft<rRight; or a positive value, if rLeft>rRight;
40 or 0, if rLeft==rRight. */
41 template< typename Type
>
42 int lclCompareVectors( const ::std::vector
< Type
>& rLeft
, const ::std::vector
< Type
>& rRight
)
46 // 1st: compare all elements of the vectors
47 auto [aItL
, aItR
] = std::mismatch(rLeft
.begin(), rLeft
.end(), rRight
.begin(), rRight
.end());
48 if ((aItL
!= rLeft
.end()) && (aItR
!= rRight
.end()))
49 nResult
= static_cast< int >( *aItL
) - static_cast< int >( *aItR
);
51 // 2nd: compare the vector sizes. Shorter vector is less
52 nResult
= static_cast< int >( rLeft
.size() ) - static_cast< int >( rRight
.size() );
59 /** Base class for value hashers.
60 @descr These function objects are used to hash any value to a sal_uInt32 value. */
61 template< typename Type
>
64 template< typename Type
>
65 struct XclDirectHasher
: public XclHasher
< Type
>
67 sal_uInt32
operator()( Type nVal
) const { return nVal
; }
70 struct XclFormatRunHasher
: public XclHasher
< const XclFormatRun
& >
72 sal_uInt32
operator()( const XclFormatRun
& rRun
) const
73 { return (rRun
.mnChar
<< 8) ^ rRun
.mnFontIdx
; }
76 /** Calculates a hash value from a vector.
77 @descr Uses the passed hasher function object to calculate hash values from
78 all vector elements. */
79 template< typename Type
, typename ValueHasher
>
80 sal_uInt16
lclHashVector( const ::std::vector
< Type
>& rVec
, const ValueHasher
& rHasher
)
82 sal_uInt32 nHash
= rVec
.size();
83 for( const auto& rItem
: rVec
)
84 nHash
= (nHash
* 31) + rHasher( rItem
);
85 return static_cast< sal_uInt16
>( nHash
^ (nHash
>> 16) );
88 /** Calculates a hash value from a vector. Uses XclDirectHasher to hash the vector elements. */
89 template< typename Type
>
90 sal_uInt16
lclHashVector( const ::std::vector
< Type
>& rVec
)
92 return lclHashVector( rVec
, XclDirectHasher
< Type
>() );
97 // constructors ---------------------------------------------------------------
99 XclExpString::XclExpString( XclStrFlags nFlags
, sal_uInt16 nMaxLen
)
101 Init( 0, nFlags
, nMaxLen
, true );
104 XclExpString::XclExpString( const OUString
& rString
, XclStrFlags nFlags
, sal_uInt16 nMaxLen
)
106 Assign( rString
, nFlags
, nMaxLen
);
109 // assign ---------------------------------------------------------------------
111 void XclExpString::Assign( const OUString
& rString
, XclStrFlags nFlags
, sal_uInt16 nMaxLen
)
113 Build( rString
.getStr(), rString
.getLength(), nFlags
, nMaxLen
);
116 void XclExpString::Assign( sal_Unicode cChar
)
118 Build( &cChar
, 1, XclStrFlags::NONE
, EXC_STR_MAXLEN
);
121 void XclExpString::AssignByte(
122 std::u16string_view rString
, rtl_TextEncoding eTextEnc
, XclStrFlags nFlags
,
125 // length may differ from length of rString
126 OString
aByteStr(OUStringToOString(rString
, eTextEnc
));
127 Build(aByteStr
.getStr(), aByteStr
.getLength(), nFlags
, nMaxLen
);
130 // append ---------------------------------------------------------------------
132 void XclExpString::Append( std::u16string_view rString
)
134 BuildAppend( rString
);
137 void XclExpString::AppendByte( std::u16string_view rString
, rtl_TextEncoding eTextEnc
)
139 if (!rString
.empty())
141 // length may differ from length of rString
142 OString
aByteStr(OUStringToOString(rString
, eTextEnc
));
143 BuildAppend(aByteStr
);
147 void XclExpString::AppendByte( sal_Unicode cChar
, rtl_TextEncoding eTextEnc
)
152 BuildAppend( std::string_view(&cByteChar
, 1) );
156 OString
aByteStr( &cChar
, 1, eTextEnc
); // length may be >1
157 BuildAppend( aByteStr
);
161 // formatting runs ------------------------------------------------------------
163 void XclExpString::AppendFormat( sal_uInt16 nChar
, sal_uInt16 nFontIdx
, bool bDropDuplicate
)
165 OSL_ENSURE( maFormats
.empty() || (maFormats
.back().mnChar
< nChar
), "XclExpString::AppendFormat - invalid char index" );
166 size_t nMaxSize
= static_cast< size_t >( mbIsBiff8
? EXC_STR_MAXLEN
: EXC_STR_MAXLEN_8BIT
);
167 if( maFormats
.empty() || ((maFormats
.size() < nMaxSize
) && (!bDropDuplicate
|| (maFormats
.back().mnFontIdx
!= nFontIdx
))) )
168 maFormats
.emplace_back( nChar
, nFontIdx
);
171 void XclExpString::AppendTrailingFormat( sal_uInt16 nFontIdx
)
173 AppendFormat( mnLen
, nFontIdx
, false );
176 void XclExpString::LimitFormatCount( sal_uInt16 nMaxCount
)
178 if( maFormats
.size() > nMaxCount
)
179 maFormats
.erase( maFormats
.begin() + nMaxCount
, maFormats
.end() );
182 sal_uInt16
XclExpString::GetLeadingFont()
184 sal_uInt16 nFontIdx
= EXC_FONT_NOTFOUND
;
185 if( !maFormats
.empty() && (maFormats
.front().mnChar
== 0) )
187 nFontIdx
= maFormats
.front().mnFontIdx
;
192 sal_uInt16
XclExpString::RemoveLeadingFont()
194 sal_uInt16 nFontIdx
= GetLeadingFont();
195 if( nFontIdx
!= EXC_FONT_NOTFOUND
)
197 maFormats
.erase( maFormats
.begin() );
202 bool XclExpString::IsEqual( const XclExpString
& rCmp
) const
205 (mnLen
== rCmp
.mnLen
) &&
206 (mbIsBiff8
== rCmp
.mbIsBiff8
) &&
207 (mbIsUnicode
== rCmp
.mbIsUnicode
) &&
208 (mbHasNewline
== rCmp
.mbHasNewline
) &&
210 ( mbIsBiff8
&& (maUniBuffer
== rCmp
.maUniBuffer
)) ||
211 (!mbIsBiff8
&& (maCharBuffer
== rCmp
.maCharBuffer
))
213 (maFormats
== rCmp
.maFormats
);
216 bool XclExpString::IsLessThan( const XclExpString
& rCmp
) const
218 int nResult
= mbIsBiff8
?
219 lclCompareVectors( maUniBuffer
, rCmp
.maUniBuffer
) :
220 lclCompareVectors( maCharBuffer
, rCmp
.maCharBuffer
);
221 return (nResult
!= 0) ? (nResult
< 0) : (maFormats
< rCmp
.maFormats
);
224 // get data -------------------------------------------------------------------
226 sal_uInt16
XclExpString::GetFormatsCount() const
228 return static_cast< sal_uInt16
>( maFormats
.size() );
231 sal_uInt8
XclExpString::GetFlagField() const
233 return (mbIsUnicode
? EXC_STRF_16BIT
: 0) | (IsWriteFormats() ? EXC_STRF_RICH
: 0);
236 sal_uInt16
XclExpString::GetHeaderSize() const
239 (mb8BitLen
? 1 : 2) + // length field
240 (IsWriteFlags() ? 1 : 0) + // flag field
241 (IsWriteFormats() ? 2 : 0); // richtext formatting count
244 std::size_t XclExpString::GetBufferSize() const
246 return static_cast<std::size_t>(mnLen
) * (mbIsUnicode
? 2 : 1);
249 std::size_t XclExpString::GetSize() const
252 GetHeaderSize() + // header
253 GetBufferSize() + // character buffer
254 (IsWriteFormats() ? (4 * GetFormatsCount()) : 0); // richtext formatting
257 sal_uInt16
XclExpString::GetChar( sal_uInt16 nCharIdx
) const
259 OSL_ENSURE( nCharIdx
< Len(), "XclExpString::GetChar - invalid character index" );
260 return static_cast< sal_uInt16
>( mbIsBiff8
? maUniBuffer
[ nCharIdx
] : maCharBuffer
[ nCharIdx
] );
263 sal_uInt16
XclExpString::GetHash() const
266 (mbIsBiff8
? lclHashVector( maUniBuffer
) : lclHashVector( maCharBuffer
)) ^
267 lclHashVector( maFormats
, XclFormatRunHasher() );
270 // streaming ------------------------------------------------------------------
272 void XclExpString::WriteLenField( XclExpStream
& rStrm
) const
275 rStrm
<< static_cast< sal_uInt8
>( mnLen
);
280 void XclExpString::WriteFlagField( XclExpStream
& rStrm
) const
284 PrepareWrite( rStrm
, 1 );
285 rStrm
<< GetFlagField();
286 rStrm
.SetSliceSize( 0 );
290 void XclExpString::WriteHeader( XclExpStream
& rStrm
) const
292 OSL_ENSURE( !mb8BitLen
|| (mnLen
< 256), "XclExpString::WriteHeader - string too long" );
293 PrepareWrite( rStrm
, GetHeaderSize() );
295 WriteLenField( rStrm
);
298 rStrm
<< GetFlagField();
300 if( IsWriteFormats() )
301 rStrm
<< GetFormatsCount();
302 rStrm
.SetSliceSize( 0 );
305 void XclExpString::WriteBuffer( XclExpStream
& rStrm
) const
308 rStrm
.WriteUnicodeBuffer( maUniBuffer
, GetFlagField() );
310 rStrm
.WriteCharBuffer( maCharBuffer
);
313 void XclExpString::WriteFormats( XclExpStream
& rStrm
, bool bWriteSize
) const
321 rStrm
<< GetFormatsCount();
322 rStrm
.SetSliceSize( 4 );
323 for( const auto& rFormat
: maFormats
)
324 rStrm
<< rFormat
.mnChar
<< rFormat
.mnFontIdx
;
329 rStrm
<< static_cast< sal_uInt8
>( GetFormatsCount() );
330 rStrm
.SetSliceSize( 2 );
331 for( const auto& rFormat
: maFormats
)
332 rStrm
<< static_cast< sal_uInt8
>( rFormat
.mnChar
) << static_cast< sal_uInt8
>( rFormat
.mnFontIdx
);
334 rStrm
.SetSliceSize( 0 );
337 void XclExpString::Write( XclExpStream
& rStrm
) const
340 WriteHeader( rStrm
);
341 WriteBuffer( rStrm
);
342 if( IsWriteFormats() ) // only in BIFF8 included in string
343 WriteFormats( rStrm
);
346 void XclExpString::WriteHeaderToMem( sal_uInt8
* pnMem
) const
349 OSL_ENSURE( !mb8BitLen
|| (mnLen
< 256), "XclExpString::WriteHeaderToMem - string too long" );
350 OSL_ENSURE( !IsWriteFormats(), "XclExpString::WriteHeaderToMem - formatted strings not supported" );
354 *pnMem
= static_cast< sal_uInt8
>( mnLen
);
359 ShortToSVBT16( mnLen
, pnMem
);
364 *pnMem
= GetFlagField();
367 void XclExpString::WriteBufferToMem( sal_uInt8
* pnMem
) const
375 for( const sal_uInt16 nChar
: maUniBuffer
)
377 *pnMem
= static_cast< sal_uInt8
>( nChar
);
381 *pnMem
= static_cast< sal_uInt8
>( nChar
>> 8 );
387 memcpy( pnMem
, maCharBuffer
.data(), mnLen
);
390 void XclExpString::WriteToMem( sal_uInt8
* pnMem
) const
392 WriteHeaderToMem( pnMem
);
393 WriteBufferToMem( pnMem
+ GetHeaderSize() );
396 static sal_uInt16
lcl_WriteRun( XclExpXmlStream
& rStrm
, const ScfUInt16Vec
& rBuffer
, sal_uInt16 nStart
, sal_Int32 nLength
, const XclExpFont
* pFont
)
401 sax_fastparser::FSHelperPtr
& rWorksheet
= rStrm
.GetCurrentStream();
403 rWorksheet
->startElement(XML_r
);
406 const XclFontData
& rFontData
= pFont
->GetFontData();
407 rWorksheet
->startElement(XML_rPr
);
408 XclXmlUtils::WriteFontData( rWorksheet
, rFontData
, XML_rFont
);
409 rWorksheet
->endElement( XML_rPr
);
411 rWorksheet
->startElement(XML_t
, FSNS(XML_xml
, XML_space
), "preserve");
412 rWorksheet
->writeEscaped( XclXmlUtils::ToOUString( rBuffer
, nStart
, nLength
) );
413 rWorksheet
->endElement( XML_t
);
414 rWorksheet
->endElement( XML_r
);
415 return nStart
+ nLength
;
418 void XclExpString::WriteXml( XclExpXmlStream
& rStrm
) const
420 sax_fastparser::FSHelperPtr rWorksheet
= rStrm
.GetCurrentStream();
422 if( !IsWriteFormats() )
424 rWorksheet
->startElement(XML_t
, FSNS(XML_xml
, XML_space
), "preserve");
425 rWorksheet
->writeEscaped( XclXmlUtils::ToOUString( *this ) );
426 rWorksheet
->endElement( XML_t
);
430 XclExpFontBuffer
& rFonts
= rStrm
.GetRoot().GetFontBuffer();
432 sal_uInt16 nStart
= 0;
433 const XclExpFont
* pFont
= nullptr;
434 for ( const auto& rFormat
: maFormats
)
436 nStart
= lcl_WriteRun( rStrm
, GetUnicodeBuffer(),
437 nStart
, rFormat
.mnChar
-nStart
, pFont
);
438 pFont
= rFonts
.GetFont( rFormat
.mnFontIdx
);
440 lcl_WriteRun( rStrm
, GetUnicodeBuffer(),
441 nStart
, GetUnicodeBuffer().size() - nStart
, pFont
);
445 bool XclExpString::IsWriteFlags() const
447 return mbIsBiff8
&& (!IsEmpty() || !mbSmartFlags
);
450 bool XclExpString::IsWriteFormats() const
452 return mbIsBiff8
&& !mbSkipFormats
&& IsRich();
455 void XclExpString::SetStrLen( sal_Int32 nNewLen
)
457 sal_uInt16 nAllowedLen
= (mb8BitLen
&& (mnMaxLen
> 255)) ? 255 : mnMaxLen
;
458 mnLen
= limit_cast
< sal_uInt16
>( nNewLen
, 0, nAllowedLen
);
461 void XclExpString::CharsToBuffer( const sal_Unicode
* pcSource
, sal_Int32 nBegin
, sal_Int32 nLen
)
463 OSL_ENSURE( maUniBuffer
.size() >= o3tl::make_unsigned( nBegin
+ nLen
),
464 "XclExpString::CharsToBuffer - char buffer invalid" );
465 ScfUInt16Vec::iterator aBeg
= maUniBuffer
.begin() + nBegin
;
466 ScfUInt16Vec::iterator aEnd
= aBeg
+ nLen
;
467 const sal_Unicode
* pcSrcChar
= pcSource
;
468 for( ScfUInt16Vec::iterator aIt
= aBeg
; aIt
!= aEnd
; ++aIt
, ++pcSrcChar
)
470 *aIt
= static_cast< sal_uInt16
>( *pcSrcChar
);
475 mbHasNewline
= std::find(aBeg
, aEnd
, EXC_LF
) != aEnd
;
478 void XclExpString::CharsToBuffer( const char* pcSource
, sal_Int32 nBegin
, sal_Int32 nLen
)
480 OSL_ENSURE( maCharBuffer
.size() >= o3tl::make_unsigned( nBegin
+ nLen
),
481 "XclExpString::CharsToBuffer - char buffer invalid" );
482 ScfUInt8Vec::iterator aBeg
= maCharBuffer
.begin() + nBegin
;
483 ScfUInt8Vec::iterator aEnd
= aBeg
+ nLen
;
484 const char* pcSrcChar
= pcSource
;
485 for( ScfUInt8Vec::iterator aIt
= aBeg
; aIt
!= aEnd
; ++aIt
, ++pcSrcChar
)
486 *aIt
= static_cast< sal_uInt8
>( *pcSrcChar
);
489 mbHasNewline
= std::find(aBeg
, aEnd
, EXC_LF_C
) != aEnd
;
492 void XclExpString::Init( sal_Int32 nCurrLen
, XclStrFlags nFlags
, sal_uInt16 nMaxLen
, bool bBiff8
)
495 mbIsUnicode
= bBiff8
&& ( nFlags
& XclStrFlags::ForceUnicode
);
496 mb8BitLen
= bool( nFlags
& XclStrFlags::EightBitLength
);
497 mbSmartFlags
= bBiff8
&& ( nFlags
& XclStrFlags::SmartFlags
);
498 mbSkipFormats
= bool( nFlags
& XclStrFlags::SeparateFormats
);
499 mbHasNewline
= false;
500 mbSingleLineForMultipleParagraphs
= false;
501 mbSkipHeader
= bool( nFlags
& XclStrFlags::NoHeader
);
503 SetStrLen( nCurrLen
);
508 maCharBuffer
.clear();
509 maUniBuffer
.resize( mnLen
);
514 maCharBuffer
.resize( mnLen
);
518 void XclExpString::Build( const sal_Unicode
* pcSource
, sal_Int32 nCurrLen
, XclStrFlags nFlags
, sal_uInt16 nMaxLen
)
520 Init( nCurrLen
, nFlags
, nMaxLen
, true );
521 CharsToBuffer( pcSource
, 0, mnLen
);
524 void XclExpString::Build( const char* pcSource
, sal_Int32 nCurrLen
, XclStrFlags nFlags
, sal_uInt16 nMaxLen
)
526 Init( nCurrLen
, nFlags
, nMaxLen
, false );
527 CharsToBuffer( pcSource
, 0, mnLen
);
530 void XclExpString::InitAppend( sal_Int32 nAddLen
)
532 SetStrLen( static_cast< sal_Int32
>( mnLen
) + nAddLen
);
534 maUniBuffer
.resize( mnLen
);
536 maCharBuffer
.resize( mnLen
);
539 void XclExpString::BuildAppend( std::u16string_view rSource
)
541 OSL_ENSURE( mbIsBiff8
, "XclExpString::BuildAppend - must not be called at byte strings" );
544 sal_uInt16 nOldLen
= mnLen
;
545 InitAppend( rSource
.size() );
546 CharsToBuffer( rSource
.data(), nOldLen
, mnLen
- nOldLen
);
550 void XclExpString::BuildAppend( std::string_view rSource
)
552 OSL_ENSURE( !mbIsBiff8
, "XclExpString::BuildAppend - must not be called at unicode strings" );
555 sal_uInt16 nOldLen
= mnLen
;
556 InitAppend( rSource
.size() );
557 CharsToBuffer( rSource
.data(), nOldLen
, mnLen
- nOldLen
);
561 void XclExpString::PrepareWrite( XclExpStream
& rStrm
, sal_uInt16 nBytes
) const
563 rStrm
.SetSliceSize( nBytes
+ (mbIsUnicode
? 2 : 1) );
566 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */