use insert function instead of for loop
[LibreOffice.git] / sc / source / filter / excel / xestring.cxx
blob5715227cf12771fdfb317e9e6128fa9e1de53fb1
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 <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;
34 namespace {
36 // compare vectors
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 )
44 int nResult = 0;
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 );
50 else
51 // 2nd: compare the vector sizes. Shorter vector is less
52 nResult = static_cast< int >( rLeft.size() ) - static_cast< int >( rRight.size() );
54 return nResult;
57 // hashing helpers
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 >
62 struct XclHasher {};
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 >() );
95 } // namespace
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,
123 sal_uInt16 nMaxLen )
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 )
149 if( !cChar )
151 char cByteChar = 0;
152 BuildAppend( std::string_view(&cByteChar, 1) );
154 else
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;
189 return nFontIdx;
192 sal_uInt16 XclExpString::RemoveLeadingFont()
194 sal_uInt16 nFontIdx = GetLeadingFont();
195 if( nFontIdx != EXC_FONT_NOTFOUND )
197 maFormats.erase( maFormats.begin() );
199 return nFontIdx;
202 bool XclExpString::IsEqual( const XclExpString& rCmp ) const
204 return
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))
212 ) &&
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
238 return
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
251 return
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
265 return
266 (mbIsBiff8 ? lclHashVector( maUniBuffer ) : lclHashVector( maCharBuffer )) ^
267 lclHashVector( maFormats, XclFormatRunHasher() );
270 // streaming ------------------------------------------------------------------
272 void XclExpString::WriteLenField( XclExpStream& rStrm ) const
274 if( mb8BitLen )
275 rStrm << static_cast< sal_uInt8 >( mnLen );
276 else
277 rStrm << mnLen;
280 void XclExpString::WriteFlagField( XclExpStream& rStrm ) const
282 if( mbIsBiff8 )
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() );
294 // length
295 WriteLenField( rStrm );
296 // flag field
297 if( IsWriteFlags() )
298 rStrm << GetFlagField();
299 // format run count
300 if( IsWriteFormats() )
301 rStrm << GetFormatsCount();
302 rStrm.SetSliceSize( 0 );
305 void XclExpString::WriteBuffer( XclExpStream& rStrm ) const
307 if( mbIsBiff8 )
308 rStrm.WriteUnicodeBuffer( maUniBuffer, GetFlagField() );
309 else
310 rStrm.WriteCharBuffer( maCharBuffer );
313 void XclExpString::WriteFormats( XclExpStream& rStrm, bool bWriteSize ) const
315 if( !IsRich() )
316 return;
318 if( mbIsBiff8 )
320 if( bWriteSize )
321 rStrm << GetFormatsCount();
322 rStrm.SetSliceSize( 4 );
323 for( const auto& rFormat : maFormats )
324 rStrm << rFormat.mnChar << rFormat.mnFontIdx;
326 else
328 if( bWriteSize )
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
339 if (!mbSkipHeader)
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
348 assert(pnMem);
349 OSL_ENSURE( !mb8BitLen || (mnLen < 256), "XclExpString::WriteHeaderToMem - string too long" );
350 OSL_ENSURE( !IsWriteFormats(), "XclExpString::WriteHeaderToMem - formatted strings not supported" );
351 // length
352 if( mb8BitLen )
354 *pnMem = static_cast< sal_uInt8 >( mnLen );
355 ++pnMem;
357 else
359 ShortToSVBT16( mnLen, pnMem );
360 pnMem += 2;
362 // flag field
363 if( IsWriteFlags() )
364 *pnMem = GetFlagField();
367 void XclExpString::WriteBufferToMem( sal_uInt8* pnMem ) const
369 assert(pnMem);
370 if( IsEmpty() )
371 return;
373 if( mbIsBiff8 )
375 for( const sal_uInt16 nChar : maUniBuffer )
377 *pnMem = static_cast< sal_uInt8 >( nChar );
378 ++pnMem;
379 if( mbIsUnicode )
381 *pnMem = static_cast< sal_uInt8 >( nChar >> 8 );
382 ++pnMem;
386 else
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 )
398 if( nLength == 0 )
399 return nStart;
401 sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
403 rWorksheet->startElement(XML_r);
404 if( pFont )
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 );
428 else
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 );
471 if( *aIt & 0xFF00 )
472 mbIsUnicode = true;
474 if (!mbHasNewline)
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 );
487 mbIsUnicode = false;
488 if (!mbHasNewline)
489 mbHasNewline = std::find(aBeg, aEnd, EXC_LF_C) != aEnd;
492 void XclExpString::Init( sal_Int32 nCurrLen, XclStrFlags nFlags, sal_uInt16 nMaxLen, bool bBiff8 )
494 mbIsBiff8 = 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 );
502 mnMaxLen = nMaxLen;
503 SetStrLen( nCurrLen );
505 maFormats.clear();
506 if( mbIsBiff8 )
508 maCharBuffer.clear();
509 maUniBuffer.resize( mnLen );
511 else
513 maUniBuffer.clear();
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 );
533 if( mbIsBiff8 )
534 maUniBuffer.resize( mnLen );
535 else
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" );
542 if( mbIsBiff8 )
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" );
553 if( !mbIsBiff8 )
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: */