Version 6.4.0.3, tag libreoffice-6.4.0.3
[LibreOffice.git] / sc / source / filter / excel / xestring.cxx
blob70df7cde57caba44e0a936f31356be84088207d5
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 .
20 #include <algorithm>
21 #include <cassert>
23 #include <osl/diagnose.h>
24 #include <tools/solar.h>
25 #include <xlstyle.hxx>
26 #include <xestyle.hxx>
27 #include <xestream.hxx>
28 #include <xestring.hxx>
29 #include <oox/token/tokens.hxx>
31 using namespace ::oox;
33 namespace {
35 // compare vectors
37 /** Compares two vectors.
38 @return A negative value, if rLeft<rRight; or a positive value, if rLeft>rRight;
39 or 0, if rLeft==rRight. */
40 template< typename Type >
41 int lclCompareVectors( const ::std::vector< Type >& rLeft, const ::std::vector< Type >& rRight )
43 int nResult = 0;
45 // 1st: compare all elements of the vectors
46 auto [aItL, aItR] = std::mismatch(rLeft.begin(), rLeft.end(), rRight.begin(), rRight.end());
47 if ((aItL != rLeft.end()) && (aItR != rRight.end()))
48 nResult = static_cast< int >( *aItL ) - static_cast< int >( *aItR );
49 else
50 // 2nd: compare the vector sizes. Shorter vector is less
51 nResult = static_cast< int >( rLeft.size() ) - static_cast< int >( rRight.size() );
53 return nResult;
56 // hashing helpers
58 /** Base class for value hashers.
59 @descr These function objects are used to hash any value to a sal_uInt32 value. */
60 template< typename Type >
61 struct XclHasher {};
63 template< typename Type >
64 struct XclDirectHasher : public XclHasher< Type >
66 sal_uInt32 operator()( Type nVal ) const { return nVal; }
69 struct XclFormatRunHasher : public XclHasher< const XclFormatRun& >
71 sal_uInt32 operator()( const XclFormatRun& rRun ) const
72 { return (rRun.mnChar << 8) ^ rRun.mnFontIdx; }
75 /** Calculates a hash value from a vector.
76 @descr Uses the passed hasher function object to calculate hash values from
77 all vector elements. */
78 template< typename Type, typename ValueHasher >
79 sal_uInt16 lclHashVector( const ::std::vector< Type >& rVec, const ValueHasher& rHasher )
81 sal_uInt32 nHash = rVec.size();
82 for( const auto& rItem : rVec )
83 nHash = (nHash * 31) + rHasher( rItem );
84 return static_cast< sal_uInt16 >( nHash ^ (nHash >> 16) );
87 /** Calculates a hash value from a vector. Uses XclDirectHasher to hash the vector elements. */
88 template< typename Type >
89 sal_uInt16 lclHashVector( const ::std::vector< Type >& rVec )
91 return lclHashVector( rVec, XclDirectHasher< Type >() );
94 } // namespace
96 // constructors ---------------------------------------------------------------
98 XclExpString::XclExpString( XclStrFlags nFlags, sal_uInt16 nMaxLen )
100 Init( 0, nFlags, nMaxLen, true );
103 XclExpString::XclExpString( const OUString& rString, XclStrFlags nFlags, sal_uInt16 nMaxLen )
105 Assign( rString, nFlags, nMaxLen );
108 // assign ---------------------------------------------------------------------
110 void XclExpString::Assign( const OUString& rString, XclStrFlags nFlags, sal_uInt16 nMaxLen )
112 Build( rString.getStr(), rString.getLength(), nFlags, nMaxLen );
115 void XclExpString::Assign( sal_Unicode cChar )
117 Build( &cChar, 1, XclStrFlags::NONE, EXC_STR_MAXLEN );
120 void XclExpString::AssignByte(
121 const OUString& rString, rtl_TextEncoding eTextEnc, XclStrFlags nFlags, sal_uInt16 nMaxLen )
123 // length may differ from length of rString
124 OString aByteStr(OUStringToOString(rString, eTextEnc));
125 Build(aByteStr.getStr(), aByteStr.getLength(), nFlags, nMaxLen);
128 // append ---------------------------------------------------------------------
130 void XclExpString::Append( const OUString& rString )
132 BuildAppend( rString.getStr(), rString.getLength() );
135 void XclExpString::AppendByte( const OUString& rString, rtl_TextEncoding eTextEnc )
137 if (!rString.isEmpty())
139 // length may differ from length of rString
140 OString aByteStr(OUStringToOString(rString, eTextEnc));
141 BuildAppend(aByteStr.getStr(), aByteStr.getLength());
145 void XclExpString::AppendByte( sal_Unicode cChar, rtl_TextEncoding eTextEnc )
147 if( !cChar )
149 sal_Char cByteChar = 0;
150 BuildAppend( &cByteChar, 1 );
152 else
154 OString aByteStr( &cChar, 1, eTextEnc ); // length may be >1
155 BuildAppend( aByteStr.getStr(), aByteStr.getLength() );
159 // formatting runs ------------------------------------------------------------
161 void XclExpString::AppendFormat( sal_uInt16 nChar, sal_uInt16 nFontIdx, bool bDropDuplicate )
163 OSL_ENSURE( maFormats.empty() || (maFormats.back().mnChar < nChar), "XclExpString::AppendFormat - invalid char index" );
164 size_t nMaxSize = static_cast< size_t >( mbIsBiff8 ? EXC_STR_MAXLEN : EXC_STR_MAXLEN_8BIT );
165 if( maFormats.empty() || ((maFormats.size() < nMaxSize) && (!bDropDuplicate || (maFormats.back().mnFontIdx != nFontIdx))) )
166 maFormats.emplace_back( nChar, nFontIdx );
169 void XclExpString::AppendTrailingFormat( sal_uInt16 nFontIdx )
171 AppendFormat( mnLen, nFontIdx, false );
174 void XclExpString::LimitFormatCount( sal_uInt16 nMaxCount )
176 if( maFormats.size() > nMaxCount )
177 maFormats.erase( maFormats.begin() + nMaxCount, maFormats.end() );
180 sal_uInt16 XclExpString::GetLeadingFont()
182 sal_uInt16 nFontIdx = EXC_FONT_NOTFOUND;
183 if( !maFormats.empty() && (maFormats.front().mnChar == 0) )
185 nFontIdx = maFormats.front().mnFontIdx;
187 return nFontIdx;
190 sal_uInt16 XclExpString::RemoveLeadingFont()
192 sal_uInt16 nFontIdx = GetLeadingFont();
193 if( nFontIdx != EXC_FONT_NOTFOUND )
195 maFormats.erase( maFormats.begin() );
197 return nFontIdx;
200 bool XclExpString::IsEqual( const XclExpString& rCmp ) const
202 return
203 (mnLen == rCmp.mnLen) &&
204 (mbIsBiff8 == rCmp.mbIsBiff8) &&
205 (mbIsUnicode == rCmp.mbIsUnicode) &&
206 (mbWrapped == rCmp.mbWrapped) &&
208 ( mbIsBiff8 && (maUniBuffer == rCmp.maUniBuffer)) ||
209 (!mbIsBiff8 && (maCharBuffer == rCmp.maCharBuffer))
210 ) &&
211 (maFormats == rCmp.maFormats);
214 bool XclExpString::IsLessThan( const XclExpString& rCmp ) const
216 int nResult = mbIsBiff8 ?
217 lclCompareVectors( maUniBuffer, rCmp.maUniBuffer ) :
218 lclCompareVectors( maCharBuffer, rCmp.maCharBuffer );
219 return (nResult != 0) ? (nResult < 0) : (maFormats < rCmp.maFormats);
222 // get data -------------------------------------------------------------------
224 sal_uInt16 XclExpString::GetFormatsCount() const
226 return static_cast< sal_uInt16 >( maFormats.size() );
229 sal_uInt8 XclExpString::GetFlagField() const
231 return (mbIsUnicode ? EXC_STRF_16BIT : 0) | (IsWriteFormats() ? EXC_STRF_RICH : 0);
234 sal_uInt16 XclExpString::GetHeaderSize() const
236 return
237 (mb8BitLen ? 1 : 2) + // length field
238 (IsWriteFlags() ? 1 : 0) + // flag field
239 (IsWriteFormats() ? 2 : 0); // richtext formatting count
242 std::size_t XclExpString::GetBufferSize() const
244 return static_cast<std::size_t>(mnLen) * (mbIsUnicode ? 2 : 1);
247 std::size_t XclExpString::GetSize() const
249 return
250 GetHeaderSize() + // header
251 GetBufferSize() + // character buffer
252 (IsWriteFormats() ? (4 * GetFormatsCount()) : 0); // richtext formatting
255 sal_uInt16 XclExpString::GetChar( sal_uInt16 nCharIdx ) const
257 OSL_ENSURE( nCharIdx < Len(), "XclExpString::GetChar - invalid character index" );
258 return static_cast< sal_uInt16 >( mbIsBiff8 ? maUniBuffer[ nCharIdx ] : maCharBuffer[ nCharIdx ] );
261 sal_uInt16 XclExpString::GetHash() const
263 return
264 (mbIsBiff8 ? lclHashVector( maUniBuffer ) : lclHashVector( maCharBuffer )) ^
265 lclHashVector( maFormats, XclFormatRunHasher() );
268 // streaming ------------------------------------------------------------------
270 void XclExpString::WriteLenField( XclExpStream& rStrm ) const
272 if( mb8BitLen )
273 rStrm << static_cast< sal_uInt8 >( mnLen );
274 else
275 rStrm << mnLen;
278 void XclExpString::WriteFlagField( XclExpStream& rStrm ) const
280 if( mbIsBiff8 )
282 PrepareWrite( rStrm, 1 );
283 rStrm << GetFlagField();
284 rStrm.SetSliceSize( 0 );
288 void XclExpString::WriteHeader( XclExpStream& rStrm ) const
290 OSL_ENSURE( !mb8BitLen || (mnLen < 256), "XclExpString::WriteHeader - string too long" );
291 PrepareWrite( rStrm, GetHeaderSize() );
292 // length
293 WriteLenField( rStrm );
294 // flag field
295 if( IsWriteFlags() )
296 rStrm << GetFlagField();
297 // format run count
298 if( IsWriteFormats() )
299 rStrm << GetFormatsCount();
300 rStrm.SetSliceSize( 0 );
303 void XclExpString::WriteBuffer( XclExpStream& rStrm ) const
305 if( mbIsBiff8 )
306 rStrm.WriteUnicodeBuffer( maUniBuffer, GetFlagField() );
307 else
308 rStrm.WriteCharBuffer( maCharBuffer );
311 void XclExpString::WriteFormats( XclExpStream& rStrm, bool bWriteSize ) const
313 if( IsRich() )
315 if( mbIsBiff8 )
317 if( bWriteSize )
318 rStrm << GetFormatsCount();
319 rStrm.SetSliceSize( 4 );
320 for( const auto& rFormat : maFormats )
321 rStrm << rFormat.mnChar << rFormat.mnFontIdx;
323 else
325 if( bWriteSize )
326 rStrm << static_cast< sal_uInt8 >( GetFormatsCount() );
327 rStrm.SetSliceSize( 2 );
328 for( const auto& rFormat : maFormats )
329 rStrm << static_cast< sal_uInt8 >( rFormat.mnChar ) << static_cast< sal_uInt8 >( rFormat.mnFontIdx );
331 rStrm.SetSliceSize( 0 );
335 void XclExpString::Write( XclExpStream& rStrm ) const
337 if (!mbSkipHeader)
338 WriteHeader( rStrm );
339 WriteBuffer( rStrm );
340 if( IsWriteFormats() ) // only in BIFF8 included in string
341 WriteFormats( rStrm );
344 void XclExpString::WriteHeaderToMem( sal_uInt8* pnMem ) const
346 assert(pnMem);
347 OSL_ENSURE( !mb8BitLen || (mnLen < 256), "XclExpString::WriteHeaderToMem - string too long" );
348 OSL_ENSURE( !IsWriteFormats(), "XclExpString::WriteHeaderToMem - formatted strings not supported" );
349 // length
350 if( mb8BitLen )
352 *pnMem = static_cast< sal_uInt8 >( mnLen );
353 ++pnMem;
355 else
357 ShortToSVBT16( mnLen, pnMem );
358 pnMem += 2;
360 // flag field
361 if( IsWriteFlags() )
362 *pnMem = GetFlagField();
365 void XclExpString::WriteBufferToMem( sal_uInt8* pnMem ) const
367 assert(pnMem);
368 if( !IsEmpty() )
370 if( mbIsBiff8 )
372 for( const sal_uInt16 nChar : maUniBuffer )
374 *pnMem = static_cast< sal_uInt8 >( nChar );
375 ++pnMem;
376 if( mbIsUnicode )
378 *pnMem = static_cast< sal_uInt8 >( nChar >> 8 );
379 ++pnMem;
383 else
384 memcpy( pnMem, maCharBuffer.data(), mnLen );
388 void XclExpString::WriteToMem( sal_uInt8* pnMem ) const
390 WriteHeaderToMem( pnMem );
391 WriteBufferToMem( pnMem + GetHeaderSize() );
394 static sal_uInt16 lcl_WriteRun( XclExpXmlStream& rStrm, const ScfUInt16Vec& rBuffer, sal_uInt16 nStart, sal_Int32 nLength, const XclExpFont* pFont )
396 if( nLength == 0 )
397 return nStart;
399 sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
401 rWorksheet->startElement(XML_r);
402 if( pFont )
404 const XclFontData& rFontData = pFont->GetFontData();
405 rWorksheet->startElement(XML_rPr);
406 XclXmlUtils::WriteFontData( rWorksheet, rFontData, XML_rFont );
407 rWorksheet->endElement( XML_rPr );
409 rWorksheet->startElement(XML_t, FSNS(XML_xml, XML_space), "preserve");
410 rWorksheet->writeEscaped( XclXmlUtils::ToOUString( rBuffer, nStart, nLength ) );
411 rWorksheet->endElement( XML_t );
412 rWorksheet->endElement( XML_r );
413 return nStart + nLength;
416 void XclExpString::WriteXml( XclExpXmlStream& rStrm ) const
418 sax_fastparser::FSHelperPtr rWorksheet = rStrm.GetCurrentStream();
420 if( !IsWriteFormats() )
422 rWorksheet->startElement(XML_t, FSNS(XML_xml, XML_space), "preserve");
423 rWorksheet->writeEscaped( XclXmlUtils::ToOUString( *this ) );
424 rWorksheet->endElement( XML_t );
426 else
428 XclExpFontBuffer& rFonts = rStrm.GetRoot().GetFontBuffer();
430 sal_uInt16 nStart = 0;
431 const XclExpFont* pFont = nullptr;
432 for ( const auto& rFormat : maFormats )
434 nStart = lcl_WriteRun( rStrm, GetUnicodeBuffer(),
435 nStart, rFormat.mnChar-nStart, pFont );
436 pFont = rFonts.GetFont( rFormat.mnFontIdx );
438 lcl_WriteRun( rStrm, GetUnicodeBuffer(),
439 nStart, GetUnicodeBuffer().size() - nStart, pFont );
443 bool XclExpString::IsWriteFlags() const
445 return mbIsBiff8 && (!IsEmpty() || !mbSmartFlags);
448 bool XclExpString::IsWriteFormats() const
450 return mbIsBiff8 && !mbSkipFormats && IsRich();
453 void XclExpString::SetStrLen( sal_Int32 nNewLen )
455 sal_uInt16 nAllowedLen = (mb8BitLen && (mnMaxLen > 255)) ? 255 : mnMaxLen;
456 mnLen = limit_cast< sal_uInt16 >( nNewLen, 0, nAllowedLen );
459 void XclExpString::CharsToBuffer( const sal_Unicode* pcSource, sal_Int32 nBegin, sal_Int32 nLen )
461 OSL_ENSURE( maUniBuffer.size() >= static_cast< size_t >( nBegin + nLen ),
462 "XclExpString::CharsToBuffer - char buffer invalid" );
463 ScfUInt16Vec::iterator aBeg = maUniBuffer.begin() + nBegin;
464 ScfUInt16Vec::iterator aEnd = aBeg + nLen;
465 const sal_Unicode* pcSrcChar = pcSource;
466 for( ScfUInt16Vec::iterator aIt = aBeg; aIt != aEnd; ++aIt, ++pcSrcChar )
468 *aIt = static_cast< sal_uInt16 >( *pcSrcChar );
469 if( *aIt & 0xFF00 )
470 mbIsUnicode = true;
472 if( !mbWrapped )
473 mbWrapped = ::std::find( aBeg, aEnd, EXC_LF ) != aEnd;
476 void XclExpString::CharsToBuffer( const sal_Char* pcSource, sal_Int32 nBegin, sal_Int32 nLen )
478 OSL_ENSURE( maCharBuffer.size() >= static_cast< size_t >( nBegin + nLen ),
479 "XclExpString::CharsToBuffer - char buffer invalid" );
480 ScfUInt8Vec::iterator aBeg = maCharBuffer.begin() + nBegin;
481 ScfUInt8Vec::iterator aEnd = aBeg + nLen;
482 const sal_Char* pcSrcChar = pcSource;
483 for( ScfUInt8Vec::iterator aIt = aBeg; aIt != aEnd; ++aIt, ++pcSrcChar )
484 *aIt = static_cast< sal_uInt8 >( *pcSrcChar );
485 mbIsUnicode = false;
486 if( !mbWrapped )
487 mbWrapped = ::std::find( aBeg, aEnd, EXC_LF_C ) != aEnd;
490 void XclExpString::Init( sal_Int32 nCurrLen, XclStrFlags nFlags, sal_uInt16 nMaxLen, bool bBiff8 )
492 mbIsBiff8 = bBiff8;
493 mbIsUnicode = bBiff8 && ( nFlags & XclStrFlags::ForceUnicode );
494 mb8BitLen = bool( nFlags & XclStrFlags::EightBitLength );
495 mbSmartFlags = bBiff8 && ( nFlags & XclStrFlags::SmartFlags );
496 mbSkipFormats = bool( nFlags & XclStrFlags::SeparateFormats );
497 mbWrapped = false;
498 mbSkipHeader = bool( nFlags & XclStrFlags::NoHeader );
499 mnMaxLen = nMaxLen;
500 SetStrLen( nCurrLen );
502 maFormats.clear();
503 if( mbIsBiff8 )
505 maCharBuffer.clear();
506 maUniBuffer.resize( mnLen );
508 else
510 maUniBuffer.clear();
511 maCharBuffer.resize( mnLen );
515 void XclExpString::Build( const sal_Unicode* pcSource, sal_Int32 nCurrLen, XclStrFlags nFlags, sal_uInt16 nMaxLen )
517 Init( nCurrLen, nFlags, nMaxLen, true );
518 CharsToBuffer( pcSource, 0, mnLen );
521 void XclExpString::Build( const sal_Char* pcSource, sal_Int32 nCurrLen, XclStrFlags nFlags, sal_uInt16 nMaxLen )
523 Init( nCurrLen, nFlags, nMaxLen, false );
524 CharsToBuffer( pcSource, 0, mnLen );
527 void XclExpString::InitAppend( sal_Int32 nAddLen )
529 SetStrLen( static_cast< sal_Int32 >( mnLen ) + nAddLen );
530 if( mbIsBiff8 )
531 maUniBuffer.resize( mnLen );
532 else
533 maCharBuffer.resize( mnLen );
536 void XclExpString::BuildAppend( const sal_Unicode* pcSource, sal_Int32 nAddLen )
538 OSL_ENSURE( mbIsBiff8, "XclExpString::BuildAppend - must not be called at byte strings" );
539 if( mbIsBiff8 )
541 sal_uInt16 nOldLen = mnLen;
542 InitAppend( nAddLen );
543 CharsToBuffer( pcSource, nOldLen, mnLen - nOldLen );
547 void XclExpString::BuildAppend( const sal_Char* pcSource, sal_Int32 nAddLen )
549 OSL_ENSURE( !mbIsBiff8, "XclExpString::BuildAppend - must not be called at unicode strings" );
550 if( !mbIsBiff8 )
552 sal_uInt16 nOldLen = mnLen;
553 InitAppend( nAddLen );
554 CharsToBuffer( pcSource, nOldLen, mnLen - nOldLen );
558 void XclExpString::PrepareWrite( XclExpStream& rStrm, sal_uInt16 nBytes ) const
560 rStrm.SetSliceSize( nBytes + (mbIsUnicode ? 2 : 1) );
563 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */