xref: /trunk/main/oox/source/xls/richstring.cxx (revision c0670b14)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 #include "oox/xls/richstring.hxx"
23 
24 #include <com/sun/star/text/XText.hpp>
25 #include <rtl/ustrbuf.hxx>
26 #include "oox/helper/attributelist.hxx"
27 #include "oox/helper/propertyset.hxx"
28 #include "oox/xls/biffinputstream.hxx"
29 
30 namespace oox {
31 namespace xls {
32 
33 // ============================================================================
34 
35 using namespace ::com::sun::star::text;
36 using namespace ::com::sun::star::uno;
37 
38 using ::rtl::OString;
39 using ::rtl::OUString;
40 using ::rtl::OUStringBuffer;
41 
42 // ============================================================================
43 
44 namespace {
45 
46 const sal_uInt8 BIFF12_STRINGFLAG_FONTS         = 0x01;
47 const sal_uInt8 BIFF12_STRINGFLAG_PHONETICS     = 0x02;
48 
lclNeedsRichTextFormat(const Font * pFont)49 inline bool lclNeedsRichTextFormat( const Font* pFont )
50 {
51     return pFont && pFont->needsRichTextFormat();
52 }
53 
54 } // namespace
55 
56 // ============================================================================
57 
RichStringPortion(const WorkbookHelper & rHelper)58 RichStringPortion::RichStringPortion( const WorkbookHelper& rHelper ) :
59     WorkbookHelper( rHelper ),
60     mnFontId( -1 ),
61     mbConverted( false )
62 {
63 }
64 
setText(const OUString & rText)65 void RichStringPortion::setText( const OUString& rText )
66 {
67     maText = rText;
68 }
69 
createFont()70 FontRef RichStringPortion::createFont()
71 {
72     mxFont.reset( new Font( *this, false ) );
73     return mxFont;
74 }
75 
setFontId(sal_Int32 nFontId)76 void RichStringPortion::setFontId( sal_Int32 nFontId )
77 {
78     mnFontId = nFontId;
79 }
80 
finalizeImport()81 void RichStringPortion::finalizeImport()
82 {
83     if( mxFont.get() )
84         mxFont->finalizeImport();
85     else if( mnFontId >= 0 )
86         mxFont = getStyles().getFont( mnFontId );
87 }
88 
convert(const Reference<XText> & rxText,const Font * pFont,bool bReplace)89 void RichStringPortion::convert( const Reference< XText >& rxText, const Font* pFont, bool bReplace )
90 {
91     if ( mbConverted )
92         return;
93 
94     Reference< XTextRange > xRange;
95     if( bReplace )
96         xRange.set( rxText, UNO_QUERY );
97     else
98         xRange = rxText->getEnd();
99     OSL_ENSURE( xRange.is(), "RichStringPortion::convert - cannot get text range interface" );
100 
101     if( xRange.is() )
102     {
103         xRange->setString( maText );
104         if( mxFont.get() )
105         {
106             PropertySet aPropSet( xRange );
107             mxFont->writeToPropertySet( aPropSet, FONT_PROPTYPE_TEXT );
108         }
109         /*  Some font attributes cannot be set to cell formatting in Calc but
110             require to use rich formatting, e.g. font escapement. But do not
111             use the passed font if this portion has its own font. */
112         else if( lclNeedsRichTextFormat( pFont ) )
113         {
114             PropertySet aPropSet( xRange );
115             pFont->writeToPropertySet( aPropSet, FONT_PROPTYPE_TEXT );
116         }
117     }
118 
119     mbConverted = true;
120 }
121 
122 // ----------------------------------------------------------------------------
123 
read(SequenceInputStream & rStrm)124 void FontPortionModel::read( SequenceInputStream& rStrm )
125 {
126     mnPos = rStrm.readuInt16();
127     mnFontId = rStrm.readuInt16();
128 }
129 
read(BiffInputStream & rStrm,BiffFontPortionMode eMode)130 void FontPortionModel::read( BiffInputStream& rStrm, BiffFontPortionMode eMode )
131 {
132     switch( eMode )
133     {
134         case BIFF_FONTPORTION_8BIT:
135             mnPos = rStrm.readuInt8();
136             mnFontId = rStrm.readuInt8();
137         break;
138         case BIFF_FONTPORTION_16BIT:
139             mnPos = rStrm.readuInt16();
140             mnFontId = rStrm.readuInt16();
141         break;
142         case BIFF_FONTPORTION_OBJ:
143             mnPos = rStrm.readuInt16();
144             mnFontId = rStrm.readuInt16();
145             rStrm.skip( 4 );
146         break;
147     }
148 }
149 
150 // ----------------------------------------------------------------------------
151 
appendPortion(const FontPortionModel & rPortion)152 void FontPortionModelList::appendPortion( const FontPortionModel& rPortion )
153 {
154     // #i33341# real life -- same character index may occur several times
155     OSL_ENSURE( empty() || (back().mnPos <= rPortion.mnPos), "FontPortionModelList::appendPortion - wrong char order" );
156     if( empty() || (back().mnPos < rPortion.mnPos) )
157         push_back( rPortion );
158     else
159         back().mnFontId = rPortion.mnFontId;
160 }
161 
importPortions(SequenceInputStream & rStrm)162 void FontPortionModelList::importPortions( SequenceInputStream& rStrm )
163 {
164     sal_Int32 nCount = rStrm.readInt32();
165     clear();
166     if( nCount > 0 )
167     {
168         reserve( getLimitedValue< size_t, sal_Int64 >( nCount, 0, rStrm.getRemaining() / 4 ) );
169         /*  #i33341# real life -- same character index may occur several times
170             -> use appendPortion() to validate string position. */
171         FontPortionModel aPortion;
172         for( sal_Int32 nIndex = 0; !rStrm.isEof() && (nIndex < nCount); ++nIndex )
173         {
174             aPortion.read( rStrm );
175             appendPortion( aPortion );
176         }
177     }
178 }
179 
importPortions(BiffInputStream & rStrm,sal_uInt16 nCount,BiffFontPortionMode eMode)180 void FontPortionModelList::importPortions( BiffInputStream& rStrm, sal_uInt16 nCount, BiffFontPortionMode eMode )
181 {
182     clear();
183     reserve( nCount );
184     /*  #i33341# real life -- same character index may occur several times
185         -> use appendPortion() to validate string position. */
186     FontPortionModel aPortion;
187     for( sal_uInt16 nIndex = 0; !rStrm.isEof() && (nIndex < nCount); ++nIndex )
188     {
189         aPortion.read( rStrm, eMode );
190         appendPortion( aPortion );
191     }
192 }
193 
importPortions(BiffInputStream & rStrm,bool b16Bit)194 void FontPortionModelList::importPortions( BiffInputStream& rStrm, bool b16Bit )
195 {
196     sal_uInt16 nCount = b16Bit ? rStrm.readuInt16() : rStrm.readuInt8();
197     importPortions( rStrm, nCount, b16Bit ? BIFF_FONTPORTION_16BIT : BIFF_FONTPORTION_8BIT );
198 }
199 
200 // ============================================================================
201 
PhoneticDataModel()202 PhoneticDataModel::PhoneticDataModel() :
203     mnFontId( -1 ),
204     mnType( XML_fullwidthKatakana ),
205     mnAlignment( XML_left )
206 {
207 }
208 
setBiffData(sal_Int32 nType,sal_Int32 nAlignment)209 void PhoneticDataModel::setBiffData( sal_Int32 nType, sal_Int32 nAlignment )
210 {
211     static const sal_Int32 spnTypeIds[] = { XML_halfwidthKatakana, XML_fullwidthKatakana, XML_hiragana, XML_noConversion };
212     mnType = STATIC_ARRAY_SELECT( spnTypeIds, nType, XML_fullwidthKatakana );
213 
214     static const sal_Int32 spnAlignments[] = { XML_noControl, XML_left, XML_center, XML_distributed };
215     mnAlignment = STATIC_ARRAY_SELECT( spnAlignments, nAlignment, XML_left );
216 }
217 
218 // ----------------------------------------------------------------------------
219 
PhoneticSettings(const WorkbookHelper & rHelper)220 PhoneticSettings::PhoneticSettings( const WorkbookHelper& rHelper ) :
221     WorkbookHelper( rHelper )
222 {
223 }
224 
importPhoneticPr(const AttributeList & rAttribs)225 void PhoneticSettings::importPhoneticPr( const AttributeList& rAttribs )
226 {
227     maModel.mnFontId    = rAttribs.getInteger( XML_fontId, -1 );
228     maModel.mnType      = rAttribs.getToken( XML_type, XML_fullwidthKatakana );
229     maModel.mnAlignment = rAttribs.getToken( XML_alignment, XML_left );
230 }
231 
importPhoneticPr(SequenceInputStream & rStrm)232 void PhoneticSettings::importPhoneticPr( SequenceInputStream& rStrm )
233 {
234     sal_uInt16 nFontId;
235     sal_Int32 nType, nAlignment;
236     rStrm >> nFontId >> nType >> nAlignment;
237     maModel.mnFontId = nFontId;
238     maModel.setBiffData( nType, nAlignment );
239 }
240 
importPhoneticPr(BiffInputStream & rStrm)241 void PhoneticSettings::importPhoneticPr( BiffInputStream& rStrm )
242 {
243     sal_uInt16 nFontId, nFlags;
244     rStrm >> nFontId >> nFlags;
245     maModel.mnFontId = nFontId;
246     maModel.setBiffData( extractValue< sal_Int32 >( nFlags, 0, 2 ), extractValue< sal_Int32 >( nFlags, 2, 2 ) );
247     // following: range list with cells showing phonetic text
248 }
249 
importStringData(SequenceInputStream & rStrm)250 void PhoneticSettings::importStringData( SequenceInputStream& rStrm )
251 {
252     sal_uInt16 nFontId, nFlags;
253     rStrm >> nFontId >> nFlags;
254     maModel.mnFontId = nFontId;
255     maModel.setBiffData( extractValue< sal_Int32 >( nFlags, 0, 2 ), extractValue< sal_Int32 >( nFlags, 2, 2 ) );
256 }
257 
importStringData(BiffInputStream & rStrm)258 void PhoneticSettings::importStringData( BiffInputStream& rStrm )
259 {
260     sal_uInt16 nFontId, nFlags;
261     rStrm >> nFontId >> nFlags;
262     maModel.mnFontId = nFontId;
263     maModel.setBiffData( extractValue< sal_Int32 >( nFlags, 0, 2 ), extractValue< sal_Int32 >( nFlags, 2, 2 ) );
264 }
265 
266 // ============================================================================
267 
RichStringPhonetic(const WorkbookHelper & rHelper)268 RichStringPhonetic::RichStringPhonetic( const WorkbookHelper& rHelper ) :
269     WorkbookHelper( rHelper ),
270     mnBasePos( -1 ),
271     mnBaseEnd( -1 )
272 {
273 }
274 
setText(const OUString & rText)275 void RichStringPhonetic::setText( const OUString& rText )
276 {
277     maText = rText;
278 }
279 
importPhoneticRun(const AttributeList & rAttribs)280 void RichStringPhonetic::importPhoneticRun( const AttributeList& rAttribs )
281 {
282     mnBasePos = rAttribs.getInteger( XML_sb, -1 );
283     mnBaseEnd = rAttribs.getInteger( XML_eb, -1 );
284 }
285 
setBaseRange(sal_Int32 nBasePos,sal_Int32 nBaseEnd)286 void RichStringPhonetic::setBaseRange( sal_Int32 nBasePos, sal_Int32 nBaseEnd )
287 {
288     mnBasePos = nBasePos;
289     mnBaseEnd = nBaseEnd;
290 }
291 
292 // ----------------------------------------------------------------------------
293 
read(SequenceInputStream & rStrm)294 void PhoneticPortionModel::read( SequenceInputStream& rStrm )
295 {
296     mnPos = rStrm.readuInt16();
297     mnBasePos = rStrm.readuInt16();
298     mnBaseLen = rStrm.readuInt16();
299 }
300 
read(BiffInputStream & rStrm)301 void PhoneticPortionModel::read( BiffInputStream& rStrm )
302 {
303     mnPos = rStrm.readuInt16();
304     mnBasePos = rStrm.readuInt16();
305     mnBaseLen = rStrm.readuInt16();
306 }
307 
308 // ----------------------------------------------------------------------------
309 
appendPortion(const PhoneticPortionModel & rPortion)310 void PhoneticPortionModelList::appendPortion( const PhoneticPortionModel& rPortion )
311 {
312     // same character index may occur several times
313     OSL_ENSURE( empty() || ((back().mnPos <= rPortion.mnPos) &&
314         (back().mnBasePos + back().mnBaseLen <= rPortion.mnBasePos)),
315         "PhoneticPortionModelList::appendPortion - wrong char order" );
316     if( empty() || (back().mnPos < rPortion.mnPos) )
317     {
318         push_back( rPortion );
319     }
320     else if( back().mnPos == rPortion.mnPos )
321     {
322         back().mnBasePos = rPortion.mnBasePos;
323         back().mnBaseLen = rPortion.mnBaseLen;
324     }
325 }
326 
importPortions(SequenceInputStream & rStrm)327 void PhoneticPortionModelList::importPortions( SequenceInputStream& rStrm )
328 {
329     sal_Int32 nCount = rStrm.readInt32();
330     clear();
331     if( nCount > 0 )
332     {
333         reserve( getLimitedValue< size_t, sal_Int64 >( nCount, 0, rStrm.getRemaining() / 6 ) );
334         PhoneticPortionModel aPortion;
335         for( sal_Int32 nIndex = 0; !rStrm.isEof() && (nIndex < nCount); ++nIndex )
336         {
337             aPortion.read( rStrm );
338             appendPortion( aPortion );
339         }
340     }
341 }
342 
importPortions(BiffInputStream & rStrm,sal_Int32 nPhoneticSize)343 OUString PhoneticPortionModelList::importPortions( BiffInputStream& rStrm, sal_Int32 nPhoneticSize )
344 {
345     OUString aPhoneticText;
346     sal_uInt16 nPortionCount, nTextLen1, nTextLen2;
347     rStrm >> nPortionCount >> nTextLen1 >> nTextLen2;
348     OSL_ENSURE( nTextLen1 == nTextLen2, "PhoneticPortionModelList::importPortions - wrong phonetic text length" );
349     if( (nTextLen1 == nTextLen2) && (nTextLen1 > 0) )
350     {
351         sal_Int32 nMinSize = 2 * nTextLen1 + 6 * nPortionCount + 14;
352         OSL_ENSURE( nMinSize <= nPhoneticSize, "PhoneticPortionModelList::importPortions - wrong size of phonetic data" );
353         if( nMinSize <= nPhoneticSize )
354         {
355             aPhoneticText = rStrm.readUnicodeArray( nTextLen1 );
356             clear();
357             reserve( nPortionCount );
358             PhoneticPortionModel aPortion;
359             for( sal_uInt16 nPortion = 0; nPortion < nPortionCount; ++nPortion )
360             {
361                 aPortion.read( rStrm );
362                 appendPortion( aPortion );
363             }
364         }
365     }
366     return aPhoneticText;
367 }
368 
369 // ============================================================================
370 
RichString(const WorkbookHelper & rHelper)371 RichString::RichString( const WorkbookHelper& rHelper ) :
372     WorkbookHelper( rHelper ),
373     maPhonSettings( rHelper )
374 {
375 }
376 
importText(const AttributeList &)377 RichStringPortionRef RichString::importText( const AttributeList& )
378 {
379     return createPortion();
380 }
381 
importRun(const AttributeList &)382 RichStringPortionRef RichString::importRun( const AttributeList& )
383 {
384     return createPortion();
385 }
386 
importPhoneticRun(const AttributeList & rAttribs)387 RichStringPhoneticRef RichString::importPhoneticRun( const AttributeList& rAttribs )
388 {
389     RichStringPhoneticRef xPhonetic = createPhonetic();
390     xPhonetic->importPhoneticRun( rAttribs );
391     return xPhonetic;
392 }
393 
importPhoneticPr(const AttributeList & rAttribs)394 void RichString::importPhoneticPr( const AttributeList& rAttribs )
395 {
396     maPhonSettings.importPhoneticPr( rAttribs );
397 }
398 
importString(SequenceInputStream & rStrm,bool bRich)399 void RichString::importString( SequenceInputStream& rStrm, bool bRich )
400 {
401     sal_uInt8 nFlags = bRich ? rStrm.readuInt8() : 0;
402     OUString aBaseText = BiffHelper::readString( rStrm );
403 
404     if( !rStrm.isEof() && getFlag( nFlags, BIFF12_STRINGFLAG_FONTS ) )
405     {
406         FontPortionModelList aPortions;
407         aPortions.importPortions( rStrm );
408         createTextPortions( aBaseText, aPortions );
409     }
410     else
411     {
412         createPortion()->setText( aBaseText );
413     }
414 
415     if( !rStrm.isEof() && getFlag( nFlags, BIFF12_STRINGFLAG_PHONETICS ) )
416     {
417         OUString aPhoneticText = BiffHelper::readString( rStrm );
418         PhoneticPortionModelList aPortions;
419         aPortions.importPortions( rStrm );
420         maPhonSettings.importStringData( rStrm );
421         createPhoneticPortions( aPhoneticText, aPortions, aBaseText.getLength() );
422     }
423 }
424 
importCharArray(BiffInputStream & rStrm,sal_uInt16 nChars,rtl_TextEncoding eTextEnc)425 void RichString::importCharArray( BiffInputStream& rStrm, sal_uInt16 nChars, rtl_TextEncoding eTextEnc )
426 {
427     createPortion()->setText( rStrm.readCharArrayUC( nChars, eTextEnc ) );
428 }
429 
importByteString(BiffInputStream & rStrm,rtl_TextEncoding eTextEnc,BiffStringFlags nFlags)430 void RichString::importByteString( BiffInputStream& rStrm, rtl_TextEncoding eTextEnc, BiffStringFlags nFlags )
431 {
432     OSL_ENSURE( !getFlag( nFlags, BIFF_STR_KEEPFONTS ), "RichString::importString - keep fonts not implemented" );
433     OSL_ENSURE( !getFlag( nFlags, static_cast< BiffStringFlags >( ~(BIFF_STR_8BITLENGTH | BIFF_STR_EXTRAFONTS) ) ), "RichString::importByteString - unknown flag" );
434     bool b8BitLength = getFlag( nFlags, BIFF_STR_8BITLENGTH );
435 
436     OString aBaseText = rStrm.readByteString( !b8BitLength );
437 
438     if( !rStrm.isEof() && getFlag( nFlags, BIFF_STR_EXTRAFONTS ) )
439     {
440         FontPortionModelList aPortions;
441         aPortions.importPortions( rStrm, false );
442         createTextPortions( aBaseText, eTextEnc, aPortions );
443     }
444     else
445     {
446         createPortion()->setText( OStringToOUString( aBaseText, eTextEnc ) );
447     }
448 }
449 
importUniString(BiffInputStream & rStrm,BiffStringFlags nFlags)450 void RichString::importUniString( BiffInputStream& rStrm, BiffStringFlags nFlags )
451 {
452     OSL_ENSURE( !getFlag( nFlags, BIFF_STR_KEEPFONTS ), "RichString::importUniString - keep fonts not implemented" );
453     OSL_ENSURE( !getFlag( nFlags, static_cast< BiffStringFlags >( ~(BIFF_STR_8BITLENGTH | BIFF_STR_SMARTFLAGS) ) ), "RichString::importUniString - unknown flag" );
454     bool b8BitLength = getFlag( nFlags, BIFF_STR_8BITLENGTH );
455 
456     // --- string header ---
457     sal_uInt16 nChars = b8BitLength ? rStrm.readuInt8() : rStrm.readuInt16();
458     sal_uInt8 nFlagField = 0;
459     if( (nChars > 0) || !getFlag( nFlags, BIFF_STR_SMARTFLAGS ) )
460         rStrm >> nFlagField;
461     bool b16Bit    = getFlag( nFlagField, BIFF_STRF_16BIT );
462     bool bFonts    = getFlag( nFlagField, BIFF_STRF_RICH );
463     bool bPhonetic = getFlag( nFlagField, BIFF_STRF_PHONETIC );
464     sal_uInt16 nFontCount = bFonts ? rStrm.readuInt16() : 0;
465     sal_Int32 nPhoneticSize = bPhonetic ? rStrm.readInt32() : 0;
466 
467     // --- character array ---
468     OUString aBaseText = rStrm.readUniStringChars( nChars, b16Bit );
469 
470     // --- formatting ---
471     // #122185# bRich flag may be set, but format runs may be missing
472     if( !rStrm.isEof() && (nFontCount > 0) )
473     {
474         FontPortionModelList aPortions;
475         aPortions.importPortions( rStrm, nFontCount, BIFF_FONTPORTION_16BIT );
476         createTextPortions( aBaseText, aPortions );
477     }
478     else
479     {
480         createPortion()->setText( aBaseText );
481     }
482 
483     // --- Asian phonetic information ---
484     // #122185# bPhonetic flag may be set, but phonetic info may be missing
485     if( !rStrm.isEof() && (nPhoneticSize > 0) )
486     {
487         sal_Int64 nPhoneticEnd = rStrm.tell() + nPhoneticSize;
488         OSL_ENSURE( nPhoneticSize > 14, "RichString::importUniString - wrong size of phonetic data" );
489         if( nPhoneticSize > 14 )
490         {
491             sal_uInt16 nId, nSize;
492             rStrm >> nId >> nSize;
493             OSL_ENSURE( nId == 1, "RichString::importUniString - unknown phonetic data identifier" );
494             sal_Int32 nMinSize = nSize + 4;
495             OSL_ENSURE( nMinSize <= nPhoneticSize, "RichString::importUniString - wrong size of phonetic data" );
496             if( (nId == 1) && (nMinSize <= nPhoneticSize) )
497             {
498                 maPhonSettings.importStringData( rStrm );
499                 PhoneticPortionModelList aPortions;
500                 OUString aPhoneticText = aPortions.importPortions( rStrm, nPhoneticSize );
501                 createPhoneticPortions( aPhoneticText, aPortions, aBaseText.getLength() );
502             }
503         }
504         rStrm.seek( nPhoneticEnd );
505     }
506 }
507 
finalizeImport()508 void RichString::finalizeImport()
509 {
510     maTextPortions.forEachMem( &RichStringPortion::finalizeImport );
511 }
512 
extractPlainString(OUString & orString,const Font * pFirstPortionFont) const513 bool RichString::extractPlainString( OUString& orString, const Font* pFirstPortionFont ) const
514 {
515     if( !maPhonPortions.empty() )
516         return false;
517     if( maTextPortions.empty() )
518     {
519         orString = OUString();
520         return true;
521     }
522     if( (maTextPortions.size() == 1) && !maTextPortions.front()->hasFont() && !lclNeedsRichTextFormat( pFirstPortionFont ) )
523     {
524         orString = maTextPortions.front()->getText();
525         return orString.indexOf( '\x0A' ) < 0;
526     }
527     return false;
528 }
529 
convert(const Reference<XText> & rxText,bool bReplaceOld,const Font * pFirstPortionFont) const530 void RichString::convert( const Reference< XText >& rxText, bool bReplaceOld, const Font* pFirstPortionFont ) const
531 {
532     for( PortionVector::const_iterator aIt = maTextPortions.begin(), aEnd = maTextPortions.end(); aIt != aEnd; ++aIt )
533     {
534         (*aIt)->convert( rxText, pFirstPortionFont, bReplaceOld );
535         pFirstPortionFont = 0;  // use passed font for first portion only
536         bReplaceOld = false;    // do not replace first portion text with following portions
537     }
538 }
539 
540 // private --------------------------------------------------------------------
541 
createPortion()542 RichStringPortionRef RichString::createPortion()
543 {
544     RichStringPortionRef xPortion( new RichStringPortion( *this ) );
545     maTextPortions.push_back( xPortion );
546     return xPortion;
547 }
548 
createPhonetic()549 RichStringPhoneticRef RichString::createPhonetic()
550 {
551     RichStringPhoneticRef xPhonetic( new RichStringPhonetic( *this ) );
552     maPhonPortions.push_back( xPhonetic );
553     return xPhonetic;
554 }
555 
createTextPortions(const OString & rText,rtl_TextEncoding eTextEnc,FontPortionModelList & rPortions)556 void RichString::createTextPortions( const OString& rText, rtl_TextEncoding eTextEnc, FontPortionModelList& rPortions )
557 {
558     maTextPortions.clear();
559     sal_Int32 nStrLen = rText.getLength();
560     if( nStrLen > 0 )
561     {
562         // add leading and trailing string position to ease the following loop
563         if( rPortions.empty() || (rPortions.front().mnPos > 0) )
564             rPortions.insert( rPortions.begin(), FontPortionModel( 0, -1 ) );
565         if( rPortions.back().mnPos < nStrLen )
566             rPortions.push_back( FontPortionModel( nStrLen, -1 ) );
567 
568         // create all string portions according to the font id vector
569         for( FontPortionModelList::const_iterator aIt = rPortions.begin(); aIt->mnPos < nStrLen; ++aIt )
570         {
571             sal_Int32 nPortionLen = (aIt + 1)->mnPos - aIt->mnPos;
572             if( (0 < nPortionLen) && (aIt->mnPos + nPortionLen <= nStrLen) )
573             {
574                 // convert byte string to unicode string, using current font encoding
575                 FontRef xFont = getStyles().getFont( aIt->mnFontId );
576                 rtl_TextEncoding eFontEnc = xFont.get() ? xFont->getFontEncoding() : eTextEnc;
577                 OUString aUniStr = OStringToOUString( rText.copy( aIt->mnPos, nPortionLen ), eFontEnc );
578                 // create string portion
579                 RichStringPortionRef xPortion = createPortion();
580                 xPortion->setText( aUniStr );
581                 xPortion->setFontId( aIt->mnFontId );
582             }
583         }
584     }
585 }
586 
createTextPortions(const OUString & rText,FontPortionModelList & rPortions)587 void RichString::createTextPortions( const OUString& rText, FontPortionModelList& rPortions )
588 {
589     maTextPortions.clear();
590     sal_Int32 nStrLen = rText.getLength();
591     if( nStrLen > 0 )
592     {
593         // add leading and trailing string position to ease the following loop
594         if( rPortions.empty() || (rPortions.front().mnPos > 0) )
595             rPortions.insert( rPortions.begin(), FontPortionModel( 0, -1 ) );
596         if( rPortions.back().mnPos < nStrLen )
597             rPortions.push_back( FontPortionModel( nStrLen, -1 ) );
598 
599         // create all string portions according to the font id vector
600         for( FontPortionModelList::const_iterator aIt = rPortions.begin(); aIt->mnPos < nStrLen; ++aIt )
601         {
602             sal_Int32 nPortionLen = (aIt + 1)->mnPos - aIt->mnPos;
603             if( (0 < nPortionLen) && (aIt->mnPos + nPortionLen <= nStrLen) )
604             {
605                 RichStringPortionRef xPortion = createPortion();
606                 xPortion->setText( rText.copy( aIt->mnPos, nPortionLen ) );
607                 xPortion->setFontId( aIt->mnFontId );
608             }
609         }
610     }
611 }
612 
createPhoneticPortions(const::rtl::OUString & rText,PhoneticPortionModelList & rPortions,sal_Int32 nBaseLen)613 void RichString::createPhoneticPortions( const ::rtl::OUString& rText, PhoneticPortionModelList& rPortions, sal_Int32 nBaseLen )
614 {
615     maPhonPortions.clear();
616     sal_Int32 nStrLen = rText.getLength();
617     if( nStrLen > 0 )
618     {
619         // no portions - assign phonetic text to entire base text
620         if( rPortions.empty() )
621             rPortions.push_back( PhoneticPortionModel( 0, 0, nBaseLen ) );
622         // add trailing string position to ease the following loop
623         if( rPortions.back().mnPos < nStrLen )
624             rPortions.push_back( PhoneticPortionModel( nStrLen, nBaseLen, 0 ) );
625 
626         // create all phonetic portions according to the portions vector
627         for( PhoneticPortionModelList::const_iterator aIt = rPortions.begin(); aIt->mnPos < nStrLen; ++aIt )
628         {
629             sal_Int32 nPortionLen = (aIt + 1)->mnPos - aIt->mnPos;
630             if( (0 < nPortionLen) && (aIt->mnPos + nPortionLen <= nStrLen) )
631             {
632                 RichStringPhoneticRef xPhonetic = createPhonetic();
633                 xPhonetic->setText( rText.copy( aIt->mnPos, nPortionLen ) );
634                 xPhonetic->setBaseRange( aIt->mnBasePos, aIt->mnBasePos + aIt->mnBaseLen );
635             }
636         }
637     }
638 }
639 
640 // ============================================================================
641 
642 } // namespace xls
643 } // namespace oox
644