cmcfixes76: #i113073# redundant dereferences
[LibreOffice.git] / sw / source / filter / rtf / rtffld.cxx
blob90bb9e6682617b17701ba986cb963e14c52af4b5
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sw.hxx"
30 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil -*- */
32 #include <ctype.h>
33 #include <hintids.hxx>
35 #ifndef _COM_SUN_STAR_I18N_SCRIPTTYPE_HDL_
36 #include <com/sun/star/i18n/ScriptType.hdl>
37 #endif
38 #ifndef _GRAPH_HXX //autogen
39 #include <vcl/graph.hxx>
40 #endif
41 #include <svl/urihelper.hxx>
42 #include <svtools/rtftoken.h>
43 #include <svl/zforlist.hxx>
44 #include <editeng/fontitem.hxx>
45 #include <editeng/fhgtitem.hxx>
46 #include <editeng/langitem.hxx>
47 #include <editeng/brkitem.hxx>
48 #include <fmtfld.hxx>
49 #include <fmtinfmt.hxx>
50 #include <swtypes.hxx>
51 #include <doc.hxx>
52 #include <pam.hxx>
53 #include <ndtxt.hxx>
54 #include <shellio.hxx>
55 #include <fldbas.hxx>
56 #include <swparrtf.hxx>
57 #include <txatbase.hxx>
58 #include <dbfld.hxx>
59 #include <usrfld.hxx>
60 #include <docufld.hxx>
61 #include <flddat.hxx>
62 #include <charfmt.hxx>
63 #ifndef _fmtruby_HXX
64 #include <fmtruby.hxx>
65 #endif
66 #include <breakit.hxx>
67 #include <reffld.hxx>
68 #include <SwStyleNameMapper.hxx>
69 #include <editeng/charhiddenitem.hxx>
72 // bestimme, ob es sich um ein IMPORT/TOC - Feld handelt.
73 // return: 0 - weder noch,
74 // 1 - TOC
75 // 2 - IMPORT
76 // 3 - INDEX
77 enum RTF_FLD_TYPES {
78 RTFFLD_UNKNOWN = 0,
79 RTFFLD_TOC,
80 RTFFLD_IMPORT,
81 RTFFLD_INDEX,
82 RTFFLD_SYMBOL,
83 RTFFLD_PAGE,
84 RTFFLD_NUMPAGES,
85 RTFFLD_DATE,
86 RTFFLD_TIME,
87 RTFFLD_DATA,
88 RTFFLD_MERGEFLD,
89 RTFFLD_HYPERLINK,
90 RTFFLD_REF,
91 RTFFLD_PAGEREF,
92 RTFFLD_EQ,
93 RTFFLD_INCLUDETEXT
96 static RTF_FLD_TYPES _WhichFld( String& rName, String& rNext )
98 // Strings sind PascalStrings; Laenge steht an 1. Stellen, dadurch wird
99 // sich der Aufruf von strlen erspart!!!
100 sal_Char __READONLY_DATA sTOC[]= "\x03""toc";
101 sal_Char __READONLY_DATA sIMPORT[]= "\x06""import";
102 sal_Char __READONLY_DATA sINDEX[]= "\x05""index";
103 sal_Char __READONLY_DATA sSYMBOL[]= "\x06""symbol";
104 sal_Char __READONLY_DATA sPAGE[]= "\x04""page";
105 sal_Char __READONLY_DATA sNUMPAGES[]= "\x08""numpages";
106 sal_Char __READONLY_DATA sDATE[]= "\x04""date";
107 sal_Char __READONLY_DATA sTIME[]= "\x04""time";
108 sal_Char __READONLY_DATA sDATA[]= "\x04""data";
109 sal_Char __READONLY_DATA sMERGEFLD[]= "\x0A""mergefield";
110 sal_Char __READONLY_DATA sIMPORT2[]= "\x0E""includepicture";
111 sal_Char __READONLY_DATA sHYPERLINK[]= "\x09""hyperlink";
112 sal_Char __READONLY_DATA sREF[]= "\x03""ref";
113 sal_Char __READONLY_DATA sPAGEREF[]= "\x07""pageref";
114 sal_Char __READONLY_DATA sEQ[]= "\x02""eq";
115 sal_Char __READONLY_DATA sINCLUDETEXT[]="\x0B""includetext";
117 struct _Dummy_RTF_FLD_TYPES
119 RTF_FLD_TYPES eFldType;
120 const sal_Char* pFldNm;
122 __READONLY_DATA _Dummy_RTF_FLD_TYPES aFldNmArr[RTFFLD_INCLUDETEXT + 1] = {
123 {RTFFLD_TOC, sTOC},
124 {RTFFLD_IMPORT, sIMPORT},
125 {RTFFLD_INDEX, sINDEX},
126 {RTFFLD_SYMBOL, sSYMBOL},
127 {RTFFLD_PAGE, sPAGE},
128 {RTFFLD_NUMPAGES, sNUMPAGES},
129 {RTFFLD_DATE, sDATE},
130 {RTFFLD_TIME, sTIME},
131 {RTFFLD_DATA, sDATA},
132 {RTFFLD_MERGEFLD, sMERGEFLD},
133 {RTFFLD_IMPORT, sIMPORT2},
134 {RTFFLD_HYPERLINK, sHYPERLINK},
135 {RTFFLD_REF, sREF},
136 {RTFFLD_PAGEREF, sPAGEREF},
137 {RTFFLD_EQ, sEQ},
138 {RTFFLD_INCLUDETEXT, sINCLUDETEXT}
142 if( !rName.Len() )
143 return RTFFLD_UNKNOWN;
145 String sNm( rName );
146 sNm = sNm.EraseLeadingChars().GetToken(0, ' ');
147 ASSERT( sNm.Len(), "Feldname hat keine Laenge!" );
148 if( !sNm.Len() )
149 return RTFFLD_UNKNOWN;
151 xub_StrLen nTokenStt = rName.Search( sNm );
152 sNm.ToLowerAscii();
154 for (size_t n = 0; n < sizeof(aFldNmArr) / sizeof(aFldNmArr[0]); ++n)
156 const sal_Char* pCmp = aFldNmArr[n].pFldNm;
157 int nLen = *pCmp++;
158 xub_StrLen nFndPos = sNm.SearchAscii( pCmp );
159 if( STRING_NOTFOUND != nFndPos &&
160 ( !nFndPos || !isalpha(sNm.GetChar( static_cast< xub_StrLen >(nFndPos-1) )) ) &&
161 ( nFndPos+nLen == sNm.Len() || !isalpha(sNm.GetChar( static_cast< xub_StrLen >(nFndPos+nLen) ) ) ) )
163 // rName = sNm.Copy( nFndPos, nLen );
164 rName = rName.Copy( nFndPos, static_cast< xub_StrLen >(nLen) );
165 nFndPos += nTokenStt + static_cast< xub_StrLen >(nLen);
166 while( rNext.GetChar( nFndPos ) == ' ' ) ++nFndPos;
167 rNext.Erase( 0, nFndPos );
168 rNext.EraseTrailingChars();
169 return aFldNmArr[n].eFldType;
172 return RTFFLD_UNKNOWN; // nichts gefunden.
175 static USHORT CheckNumberFmtStr( const String& rNStr )
177 const static sal_Char* aNumberTypeTab[] =
179 "\x0A""ALPHABETIC", /* CHARS_UPPER_LETTER*/
180 "\x0A""alphabetic", /* CHARS_LOWER_LETTER*/
181 "\x05""ROMAN", /* ROMAN_UPPER */
182 "\x05""roman", /* ROMAN_LOWER */
183 "\x06""ARABIC", /* ARABIC */
184 "\x04""NONE", /* NUMBER_NONE */
185 "\x04""CHAR", /* CHAR_SPECIAL */
186 "\x04""PAGE" /* PAGEDESC */
189 ASSERT(sizeof(aNumberTypeTab) / sizeof(sal_Char *)
190 >= SVX_NUM_PAGEDESC - SVX_NUM_CHARS_UPPER_LETTER, "impossible");
192 for (USHORT n = SVX_NUM_CHARS_UPPER_LETTER; n <= SVX_NUM_PAGEDESC; ++n)
194 const sal_Char* pCmp = aNumberTypeTab[n - SVX_NUM_CHARS_UPPER_LETTER];
195 int nLen = *pCmp++;
196 if( rNStr.EqualsAscii( pCmp, 0, static_cast< xub_StrLen >(nLen) ))
197 return static_cast< USHORT >(2 <= n ? n : (n + SVX_NUM_CHARS_UPPER_LETTER_N));
199 return SVX_NUM_PAGEDESC; // default-Wert
202 class RtfFieldSwitch
204 String sParam;
205 xub_StrLen nCurPos;
206 public:
207 RtfFieldSwitch( const String& rParam );
208 sal_Unicode GetSwitch( String& rParam );
210 BOOL IsAtEnd() const { return nCurPos >= sParam.Len(); }
211 xub_StrLen GetCurPos() const { return nCurPos; }
212 void Erase( xub_StrLen nEndPos ) { sParam.Erase( 0, nEndPos ); }
213 void Insert( const String& rIns ) { sParam.Insert( rIns, 0 ); }
214 const String& GetStr() const { return sParam; }
217 RtfFieldSwitch::RtfFieldSwitch( const String& rParam )
218 : sParam( rParam ), nCurPos( 0 )
220 sParam.EraseTrailingChars().EraseLeadingChars();
223 sal_Unicode RtfFieldSwitch::GetSwitch( String& rParam )
225 // beginnt ein Schalter?
226 sal_Unicode c, cKey = 0;
227 if( '\\' == (c = sParam.GetChar( nCurPos )) )
229 if( '\\' == ( c = sParam.GetChar( ++nCurPos )) )
230 c = sParam.GetChar( ++nCurPos );
232 cKey = c;
234 while( ++nCurPos < sParam.Len() &&
235 ' ' == ( c = sParam.GetChar( nCurPos )) )
239 // dann alles in Hochkommatas oder bis zum naechsten // als
240 // Param returnen
241 USHORT nOffset;
242 if( '"' != c && '\'' != c )
243 c = '\\', nOffset = 0;
244 else
245 nOffset = 1;
247 sParam.Erase( 0, nCurPos + nOffset );
248 rParam = sParam.GetToken( 0, c );
249 sParam.Erase( 0, rParam.Len() + nOffset ).EraseLeadingChars();
250 if( '\\' == c )
251 rParam.EraseTrailingChars();
252 nCurPos = 0;
254 return cKey;
257 struct RTF_EquationData
259 String sFontName, sUp, sDown, sText;
260 sal_Int32 nJustificationCode, nFontSize, nUp, nDown, nStyleNo;
262 inline RTF_EquationData()
263 : nJustificationCode(0), nFontSize(0), nUp(0), nDown(0),
264 nStyleNo( -1 )
268 xub_StrLen lcl_FindEndBracket( const String& rStr )
270 xub_StrLen nEnd = rStr.Len(), nRet = STRING_NOTFOUND, nPos = 0;
271 int nOpenCnt = 1;
272 sal_Unicode cCh;
273 for( ; nPos < nEnd; ++nPos )
274 if( ')' == (cCh = rStr.GetChar( nPos )) && !--nOpenCnt )
276 nRet = nPos;
277 break;
279 else if( '(' == cCh )
280 ++nOpenCnt;
282 return nRet;
285 void lcl_ScanEquationField( const String& rStr, RTF_EquationData& rData,
286 sal_Unicode nSttKey )
288 int nSubSupFlag(0);
289 RtfFieldSwitch aRFS( rStr );
290 while( !aRFS.IsAtEnd() )
292 String sParam;
293 sal_Unicode cKey = aRFS.GetSwitch( sParam );
294 if( 1 == nSubSupFlag )
295 ++nSubSupFlag;
296 else if( 1 < nSubSupFlag )
297 nSubSupFlag = 0;
299 BOOL bCheckBracket = FALSE;
300 switch( cKey )
302 case 0:
303 switch( nSttKey )
305 case 'u': rData.sUp += sParam; break;
306 case 'd': rData.sDown += sParam; break;
307 default: rData.sText += sParam; break;
309 break;
311 case '*':
312 if( sParam.Len() )
314 if( sParam.EqualsIgnoreCaseAscii( "jc", 0, 2 ) )
315 rData.nJustificationCode = sParam.Copy( 2 ).ToInt32();
316 else if( sParam.EqualsIgnoreCaseAscii( "hps", 0, 3 ) )
317 rData.nFontSize= sParam.Copy( 3 ).ToInt32();
318 else if( sParam.EqualsIgnoreCaseAscii( "Font:", 0, 5 ) )
319 rData.sFontName = sParam.Copy( 5 );
320 else if( sParam.EqualsIgnoreCaseAscii( "cs", 0, 2 ) )
321 rData.nStyleNo = sParam.Copy( 2 ).ToInt32();
323 break;
324 case 's' :
325 ++nSubSupFlag;
326 break;
328 case 'u':
329 if( sParam.Len() && 'p' == sParam.GetChar( 0 ) &&
330 2 == nSubSupFlag )
332 rData.nUp = sParam.Copy( 1 ).ToInt32();
333 bCheckBracket = TRUE;
335 break;
337 case 'd':
338 if( sParam.Len() && 'o' == sParam.GetChar( 0 ) &&
339 2 == nSubSupFlag )
341 rData.nDown = sParam.Copy( 1 ).ToInt32();
342 bCheckBracket = TRUE;
344 break;
346 default:
347 bCheckBracket = TRUE;
348 cKey = 0;
349 break;
352 if( bCheckBracket && sParam.Len() )
354 xub_StrLen nEnd, nStt = sParam.Search( '(' ),
355 nLen = sParam.Len();
356 if( STRING_NOTFOUND != nStt )
358 sParam.Erase( 0, nStt + 1 ) += aRFS.GetStr();
359 if( STRING_NOTFOUND !=
360 (nEnd = ::lcl_FindEndBracket( sParam )) )
362 // end in the added string?
363 if( (nLen - nStt - 1 ) < nEnd )
364 aRFS.Erase( nEnd + 1 - (nLen - nStt - 1));
365 else
367 // not all handled here, so set new into the RFS
368 aRFS.Insert( sParam.Copy( nEnd + 1,
369 nLen - nStt - nEnd - 2 ));
370 sal_Unicode cCh;
371 if( aRFS.GetStr().Len() &&
372 ( ',' == (cCh = aRFS.GetStr().GetChar(0)) ||
373 ';' == cCh ))
374 aRFS.Erase( 1 );
377 ::lcl_ScanEquationField( sParam.Copy( 0, nEnd ),
378 rData, cKey );
385 int SwRTFParser::MakeFieldInst( String& rFieldStr )
387 // sicher den Original-String fuer die FeldNamen (User/Datenbank)
388 String aSaveStr( rFieldStr );
389 SwFieldType * pFldType;
390 int nRet = _WhichFld(rFieldStr, aSaveStr);
392 //Strip Mergeformat from fields
393 xub_StrLen nPos=0;
394 while (STRING_NOTFOUND != ( nPos = aSaveStr.SearchAscii("\\*", nPos)))
396 xub_StrLen nStartDel = nPos;
397 nPos += 2;
398 while (aSaveStr.GetChar(nPos) == ' ')
399 ++nPos;
400 if (aSaveStr.EqualsIgnoreCaseAscii("MERGEFORMAT", nPos, 11))
402 xub_StrLen nNoDel = (nPos + 11 ) - nStartDel;
403 aSaveStr.Erase(nStartDel, nNoDel);
404 nPos -= (nStartDel - nPos);
408 nPos = 0;
409 switch (nRet)
411 case RTFFLD_INCLUDETEXT:
412 break;
413 case RTFFLD_IMPORT:
415 //JP 11.03.96: vertraegt sich nicht so ganz mit Internet!
416 // if( STRING_NOTFOUND != ( nPos = aSaveStr.Search( '.' )))
417 // aSaveStr.Erase( nPos+4 );
419 aSaveStr.EraseLeadingAndTrailingChars();
420 if( aSaveStr.Len() )
422 sal_Unicode c = aSaveStr.GetChar( 0 );
423 if( '"' == c || '\'' == c )
425 aSaveStr.Erase( 0, 1 );
426 aSaveStr = aSaveStr.GetToken( 0, c );
429 rFieldStr = URIHelper::SmartRel2Abs(
430 INetURLObject(GetBaseURL()), aSaveStr,
431 URIHelper::GetMaybeFileHdl() );
433 // SkipGroup(); // ueberlese den Rest
435 break;
437 case RTFFLD_NUMPAGES:
439 SwDocStatField aFld( (SwDocStatFieldType*)pDoc->GetSysFldType( RES_DOCSTATFLD ),
440 DS_PAGE, SVX_NUM_ARABIC );
441 if( STRING_NOTFOUND != ( nPos = aSaveStr.SearchAscii( "\\*" )) )
443 nPos += 2;
444 while( aSaveStr.GetChar(nPos) == ' ' ) nPos++;
445 aSaveStr.Erase( 0, nPos );
447 // steht jetzt geanu auf dem Format-Namen
448 aFld.ChangeFormat( CheckNumberFmtStr( aSaveStr ));
450 pDoc->InsertPoolItem( *pPam, SwFmtFld( aFld ), 0 );
451 SkipGroup();
453 break;
455 case RTFFLD_PAGE:
457 pFldType = pDoc->GetSysFldType( RES_PAGENUMBERFLD );
458 SwPageNumberField aPF( (SwPageNumberFieldType*)pFldType,
459 PG_RANDOM, SVX_NUM_ARABIC);
460 if( STRING_NOTFOUND != ( nPos = aSaveStr.SearchAscii( "\\*" )) )
462 nPos += 2;
463 while( aSaveStr.GetChar(nPos) == ' ' ) nPos++;
464 aSaveStr.Erase( 0, nPos );
466 // steht jetzt geanu auf dem Format-Namen
467 aPF.ChangeFormat( CheckNumberFmtStr( aSaveStr ));
469 pDoc->InsertPoolItem( *pPam, SwFmtFld( aPF ), 0 );
470 SkipGroup(); // ueberlese den Rest
472 break;
473 case RTFFLD_DATE:
474 case RTFFLD_TIME:
476 if( STRING_NOTFOUND == ( nPos = aSaveStr.SearchAscii( "\\@" )) )
478 // es fehlt die Format - Angabe: defaulten auf Datum
479 pFldType = pDoc->GetSysFldType( RES_DATETIMEFLD );
480 pDoc->InsertPoolItem( *pPam, SwFmtFld( SwDateTimeField(
481 static_cast<SwDateTimeFieldType*>(pFldType), DATEFLD)), 0);
483 else
485 // versuche aus dem Formatstring zu erkennen, ob es ein
486 // Datum oder Zeit oder Datum & Zeit Field ist
487 // nur das Format interressiert
488 aSaveStr.Erase( 0, aSaveStr.Search( '\"' )+1 );
489 // alles hinter dem Format interressiert auch nicht mehr.
490 aSaveStr.Erase( aSaveStr.Search( '\"' ) );
491 aSaveStr.SearchAndReplaceAscii( "AM", aEmptyStr );
492 aSaveStr.SearchAndReplaceAscii( "PM", aEmptyStr );
494 // #117892# M.M. Put the word date and time formatter stuff in a common area
495 // and get the rtf filter to use it
496 SwField *pFld = 0;
497 short nNumFmtType = NUMBERFORMAT_UNDEFINED;
498 ULONG nFmtIdx = NUMBERFORMAT_UNDEFINED;
500 USHORT rLang(0);
501 RES_CHRATR eLang = maPageDefaults.mbRTLdoc ? RES_CHRATR_CTL_LANGUAGE : RES_CHRATR_LANGUAGE;
502 const SvxLanguageItem *pLang = (SvxLanguageItem*)&pDoc->GetAttrPool().GetDefaultItem( static_cast< USHORT >(eLang) );
503 rLang = pLang ? pLang->GetValue() : LANGUAGE_ENGLISH_US;
505 SvNumberFormatter* pFormatter = pDoc->GetNumberFormatter();
506 bool bHijri = false;
508 if( pFormatter )
510 nFmtIdx = sw::ms::MSDateTimeFormatToSwFormat(aSaveStr, pFormatter, rLang, bHijri);
511 if (nFmtIdx)
512 nNumFmtType = pFormatter->GetType(nFmtIdx);
515 pFldType = pDoc->GetSysFldType( RES_DATETIMEFLD );
517 if(nNumFmtType & NUMBERFORMAT_DATE)
518 pFld = new SwDateTimeField( (SwDateTimeFieldType*)pFldType, DATEFLD, nFmtIdx );
519 else if(nNumFmtType == NUMBERFORMAT_TIME)
520 pFld = new SwDateTimeField( (SwDateTimeFieldType*)pFldType, TIMEFLD, nFmtIdx );
522 if( pFld )
524 pDoc->InsertPoolItem( *pPam, SwFmtFld( *pFld ), 0);
525 delete pFld;
528 SkipGroup(); // ueberlese den Rest
530 break;
532 case RTFFLD_DATA:
534 // Datenbank-FileName: nur der Filename interressiert
535 // Zur Zeit werden nur SDF-Files verarbeitet, also suche nach
536 // der Extension
538 // im SWG geben die DATA Felder den Namen der Datenbank
539 // an. Dieser kann als Field oder als DBInfo interpretiert
540 // werden:
541 // \\data -> Datenbank-Name als Field
542 // DATA -> Datenbank-Info
543 BOOL bField = rFieldStr.GetChar( 0 ) != 'D';
545 // nur der Name interressiert
546 if( STRING_NOTFOUND != (nPos = aSaveStr.Search( '.' )) )
547 aSaveStr.Erase( nPos );
548 SwDBData aData;
549 aData.sDataSource = aSaveStr;
550 if( bField )
552 pFldType = pDoc->GetSysFldType( RES_DBNAMEFLD );
553 pDoc->InsertPoolItem( *pPam, SwFmtFld( SwDBNameField(
554 static_cast<SwDBNameFieldType*>(pFldType), SwDBData())), 0);
556 else
557 pDoc->ChgDBData( aData ); // MS: Keine DBInfo verwenden
558 SkipGroup(); // ueberlese den Rest
560 break;
561 case RTFFLD_MERGEFLD:
563 // ein Datenbank - Feld: nur der Name interressiert
564 // bis zum Ende vom String ist das der Feldname
565 SwDBFieldType aTmp( pDoc, aSaveStr, SwDBData() ); //
566 SwDBField aDBFld( (SwDBFieldType*)pDoc->InsertFldType( aTmp ));
568 aDBFld.ChangeFormat( UF_STRING );
569 pDoc->InsertPoolItem(*pPam, SwFmtFld( aDBFld ), 0);
570 SkipGroup(); // ueberlese den Rest
572 break;
574 case RTFFLD_SYMBOL:
576 // loesche fuehrende Blanks
577 if( IsNewGroup() )
578 GetAttrSet();
579 SetNewGroup( TRUE );
581 SfxItemSet& rSet = GetAttrSet();
583 BOOL bCharIns = FALSE;
584 RtfFieldSwitch aRFS( aSaveStr );
585 while( !aRFS.IsAtEnd() )
587 String sParam;
588 sal_Unicode cKey = aRFS.GetSwitch( sParam );
589 if( sParam.Len() )
590 switch( cKey )
592 case 0:
593 if( !bCharIns )
595 sal_Unicode nChar = (sal_Unicode)sParam.ToInt32();
596 if( nChar )
598 pDoc->InsertString( *pPam, nChar );
599 bCharIns = TRUE;
602 break;
604 case 'f': case 'F':
605 // Font setzen
607 SvxRTFFontTbl& rTbl = GetFontTbl();
608 for( Font* pFont = rTbl.First(); pFont;
609 pFont = rTbl.Next() )
610 if( pFont->GetName() == sParam )
612 rSet.Put( SvxFontItem(
613 pFont->GetFamily(),
614 sParam,
615 pFont->GetStyleName(),
616 pFont->GetPitch(),
617 pFont->GetCharSet(),
618 RES_CHRATR_FONT ));
619 break;
622 break;
623 case 'h': case 'H':
624 //??
625 break;
626 case 's': case 'S':
627 // Fontsize setzen
629 const USHORT nVal = (USHORT)(sParam.ToInt32() * 20);
630 rSet.Put( SvxFontHeightItem( nVal,
631 100, RES_CHRATR_FONTSIZE ));
633 break;
637 if( !IsNewGroup() ) AttrGroupEnd();
638 SetNewGroup( FALSE );
640 SkipGroup(); // ueberlese den Rest
642 break;
644 case RTFFLD_HYPERLINK:
645 rFieldStr.Erase();
646 if( aSaveStr.Len() )
648 // return String ist URL, # Mark, \1 Frame
649 String sMark, sFrame;
650 RtfFieldSwitch aRFS( aSaveStr );
651 while( !aRFS.IsAtEnd() )
653 String sParam;
654 sal_Unicode cKey = aRFS.GetSwitch( sParam );
655 if( sParam.Len() )
656 switch( cKey )
658 case 0:
659 if( !rFieldStr.Len() )
660 rFieldStr = URIHelper::SmartRel2Abs(
661 INetURLObject(GetBaseURL()), sParam,
662 URIHelper::GetMaybeFileHdl() );
663 break;
665 case 'l': case 'L': sMark = sParam; break;
666 case 't': case 'T': sFrame = sParam; break;
670 if( sMark.Len() )
671 ( rFieldStr += INET_MARK_TOKEN ) += sMark;
672 if( sFrame.Len() )
673 ( rFieldStr += '\1' ) += sFrame;
675 break;
677 case RTFFLD_EQ:
678 rFieldStr.Erase();
679 if( aSaveStr.Len() )
681 RTF_EquationData aData;
682 ::lcl_ScanEquationField( aSaveStr, aData, 0 );
684 // is it a ruby attr?
685 if( aData.sText.Len() && aData.sFontName.Len() &&
686 aData.nFontSize && aData.sUp.Len() && !aData.sDown.Len() )
688 //Translate and apply
689 switch( aData.nJustificationCode )
691 case 0: aData.nJustificationCode = 1; break;
692 case 1: aData.nJustificationCode = 3; break;
693 case 2: aData.nJustificationCode = 4; break;
694 case 4: aData.nJustificationCode = 2; break;
695 // case 3:
696 default: aData.nJustificationCode = 0; break;
699 SwFmtRuby aRuby( aData.sUp );
700 SwCharFmt * pCharFmt = -1 != aData.nStyleNo
701 ? aCharFmtTbl.Get( aData.nStyleNo )
702 : 0;
704 if( !pCharFmt )
706 //Make a guess at which of asian of western we should be setting
707 USHORT nScript;
708 if (pBreakIt->GetBreakIter().is())
709 nScript = pBreakIt->GetBreakIter()->getScriptType( aData.sUp, 0);
710 else
711 nScript = i18n::ScriptType::ASIAN;
713 USHORT nFntHWhich = GetWhichOfScript( RES_CHRATR_FONTSIZE, nScript ),
714 nFntWhich = GetWhichOfScript( RES_CHRATR_FONT, nScript );
716 //Check to see if we already have a ruby charstyle that this fits
717 for(USHORT i=0; i < aRubyCharFmts.Count(); ++i )
719 SwCharFmt *pFmt = (SwCharFmt *)aRubyCharFmts[i];
720 const SvxFontHeightItem &rF = (const SvxFontHeightItem &)
721 pFmt->GetFmtAttr( nFntHWhich );
722 if( rF.GetHeight() == USHORT(aData.nFontSize * 10 ))
724 const SvxFontItem &rFI = (const SvxFontItem &)
725 pFmt->GetFmtAttr( nFntWhich );
726 if( rFI.GetFamilyName().Equals( aData.sFontName ))
728 pCharFmt = pFmt;
729 break;
734 //Create a new char style if necessary
735 if( !pCharFmt )
737 String sNm;
738 //Take this as the base name
739 SwStyleNameMapper::FillUIName( RES_POOLCHR_RUBYTEXT, sNm );
740 sNm += String::CreateFromInt32( aRubyCharFmts.Count() + 1 );
741 pCharFmt = pDoc->MakeCharFmt( sNm,
742 ( SwCharFmt*)pDoc->GetDfltCharFmt() );
744 SvxFontHeightItem aHeightItem( aData.nFontSize * 10, 100, RES_CHRATR_FONTSIZE );
745 aHeightItem.SetWhich( nFntHWhich );
747 SvxFontItem aFontItem( FAMILY_DONTKNOW, aData.sFontName,
748 aEmptyStr, PITCH_DONTKNOW, RTL_TEXTENCODING_DONTKNOW, nFntWhich );
750 pCharFmt->SetFmtAttr( aHeightItem );
751 pCharFmt->SetFmtAttr( aFontItem );
752 void* p = pCharFmt;
753 aRubyCharFmts.Insert( p, aRubyCharFmts.Count() );
757 //Set the charstyle and justification
758 aRuby.SetCharFmtName( pCharFmt->GetName() );
759 aRuby.SetCharFmtId( pCharFmt->GetPoolFmtId() );
760 aRuby.SetAdjustment( (USHORT)aData.nJustificationCode );
762 // im FieldStr steht der anzuzeigenden Text, im
763 pDoc->InsertString( *pPam, aData.sText );
764 pPam->SetMark();
765 pPam->GetMark()->nContent -= aData.sText.Len();
766 pDoc->InsertPoolItem( *pPam, aRuby,
767 nsSetAttrMode::SETATTR_DONTEXPAND );
768 pPam->DeleteMark();
770 // or a combined character field?
771 else if( aData.sUp.Len() && aData.sDown.Len() &&
772 !aData.sText.Len() && !aData.sFontName.Len() &&
773 !aData.nFontSize )
775 String sFld( aData.sUp );
776 sFld += aData.sDown;
777 SwCombinedCharField aFld((SwCombinedCharFieldType*)pDoc->
778 GetSysFldType( RES_COMBINED_CHARS ), sFld );
779 pDoc->InsertPoolItem( *pPam, SwFmtFld( aFld ), 0);
782 SkipGroup(); // ueberlese den Rest
784 break;
786 case RTFFLD_PAGEREF:
788 String sOrigBkmName;
789 RtfFieldSwitch aRFS( aSaveStr );
790 while( !aRFS.IsAtEnd() )
792 String sParam;
793 sal_Unicode cKey = aRFS.GetSwitch( sParam );
794 switch( cKey )
796 // In the case of pageref the only parameter we are
797 // interested in, is the name of the bookmark
798 case 0:
799 if( !sOrigBkmName.Len() ) // get name of bookmark
800 sOrigBkmName = sParam;
801 break;
804 SwGetRefField aFld(
805 (SwGetRefFieldType*)pDoc->GetSysFldType( RES_GETREFFLD ),
806 sOrigBkmName,REF_BOOKMARK,0,REF_PAGE);
808 if(!bNestedField)
810 pDoc->InsertPoolItem( *pPam, SwFmtFld( aFld ), 0 );
812 else
813 bNestedField = false;
815 break;
817 case RTFFLD_REF:
819 String sOrigBkmName;
820 bool bChapterNr = false;
821 bool bAboveBelow = false;
823 RtfFieldSwitch aRFS( aSaveStr );
824 while( !aRFS.IsAtEnd() )
826 String sParam;
827 sal_Unicode cKey = aRFS.GetSwitch( sParam );
828 switch( cKey )
830 case 0:
831 if( !sOrigBkmName.Len() ) // get name of bookmark
832 sOrigBkmName = sParam;
833 break;
835 case 'n':
836 case 'r':
837 case 'w':
838 bChapterNr = true; // activate flag 'Chapter Number'
839 break;
841 case 'p':
842 bAboveBelow = true;
843 break;
846 if (!bAboveBelow || bChapterNr)
848 if (bChapterNr)
850 SwGetRefField aFld(
851 (SwGetRefFieldType*)pDoc->GetSysFldType( RES_GETREFFLD ),
852 sOrigBkmName,REF_BOOKMARK,0,REF_CHAPTER);
853 pDoc->InsertPoolItem( *pPam, SwFmtFld( aFld ), 0 );
855 else
857 SwGetRefField aFld(
858 (SwGetRefFieldType*)pDoc->GetSysFldType( RES_GETREFFLD ),
859 sOrigBkmName,REF_BOOKMARK,0,REF_CONTENT);
860 pDoc->InsertPoolItem( *pPam, SwFmtFld( aFld ), 0 );
864 if( bAboveBelow )
866 SwGetRefField aFld( (SwGetRefFieldType*)
867 pDoc->GetSysFldType( RES_GETREFFLD ), sOrigBkmName, REF_BOOKMARK, 0,
868 REF_UPDOWN );
869 pDoc->InsertPoolItem(*pPam, SwFmtFld(aFld), 0);
872 break;
874 case RTFFLD_TOC:
875 case RTFFLD_INDEX:
876 break;
878 default:
880 // keines von den bekannten Feldern, also eine neues UserField
881 aSaveStr.EraseLeadingChars().EraseTrailingChars();
882 SwUserFieldType aTmp( pDoc, aSaveStr );
883 SwUserField aUFld( (SwUserFieldType*)pDoc->InsertFldType( aTmp ));
884 aUFld.ChangeFormat( UF_STRING );
885 pDoc->InsertPoolItem( *pPam, SwFmtFld( aUFld ), 0);
886 nRet = RTFFLD_UNKNOWN;
888 break;
890 return nRet;
894 void SwRTFParser::ReadXEField()
896 bReadSwFly = false; //#it may be that any uses of this need to be removed and replaced
897 int nNumOpenBrakets = 1;
898 String sFieldStr;
899 BYTE cCh;
901 int nToken;
902 while (nNumOpenBrakets && IsParserWorking())
904 switch (nToken = GetNextToken())
906 case '}':
908 --nNumOpenBrakets;
910 if( sFieldStr.Len())
912 String sXE(sFieldStr);
913 sXE.Insert('\"', 0);
914 sXE.Append('\"');
916 // we have to make sure the hidden text flag is not on
917 // otherwise the index will not see this index mark
918 SfxItemSet& rSet = GetAttrSet();
919 const SfxPoolItem* pItem;
920 if( SFX_ITEM_SET == rSet.GetItemState( RES_CHRATR_HIDDEN, sal_True, &pItem ) )
922 SvxCharHiddenItem aCharHidden(*(SvxCharHiddenItem*)pItem);
923 aCharHidden.SetValue(FALSE);
924 rSet.Put(aCharHidden);
927 sw::ms::ImportXE(*pDoc, *pPam, sXE);
929 sFieldStr.Erase();
932 break;
934 case '{':
935 if( RTF_IGNOREFLAG != GetNextToken() )
936 SkipToken( -1 );
937 // Unknown und alle bekannten nicht ausgewerteten Gruppen
938 // sofort ueberspringen
939 else if( RTF_UNKNOWNCONTROL != GetNextToken() )
940 SkipToken( -2 );
941 else
943 // gleich herausfiltern
944 ReadUnknownData();
945 if( '}' != GetNextToken() )
946 eState = SVPAR_ERROR;
947 break;
949 ++nNumOpenBrakets;
950 break;
952 case RTF_U:
954 if( nTokenValue )
955 sFieldStr += (sal_Unicode)nTokenValue;
956 else
957 sFieldStr += aToken;
959 break;
961 case RTF_LINE: cCh = '\n'; goto INSINGLECHAR;
962 case RTF_TAB: cCh = '\t'; goto INSINGLECHAR;
963 case RTF_SUBENTRYINDEX: cCh = ':'; goto INSINGLECHAR;
964 case RTF_EMDASH: cCh = 151; goto INSINGLECHAR;
965 case RTF_ENDASH: cCh = 150; goto INSINGLECHAR;
966 case RTF_BULLET: cCh = 149; goto INSINGLECHAR;
967 case RTF_LQUOTE: cCh = 145; goto INSINGLECHAR;
968 case RTF_RQUOTE: cCh = 146; goto INSINGLECHAR;
969 case RTF_LDBLQUOTE: cCh = 147; goto INSINGLECHAR;
970 case RTF_RDBLQUOTE: cCh = 148; goto INSINGLECHAR;
971 INSINGLECHAR:
972 sFieldStr += ByteString::ConvertToUnicode( cCh,
973 RTL_TEXTENCODING_MS_1252 );
974 break;
976 // kein Break, aToken wird als Text gesetzt
977 case RTF_TEXTTOKEN:
978 sFieldStr += aToken;
979 break;
981 case RTF_BKMK_KEY:
982 case RTF_TC:
983 case RTF_NEXTFILE:
984 case RTF_TEMPLATE:
985 case RTF_SHPRSLT:
986 SkipGroup();
987 break;
989 case RTF_PAR:
990 sFieldStr.Append('\x0a');
991 break;
992 default:
993 SvxRTFParser::NextToken( nToken );
994 break;
998 SkipToken( -1 ); // die schliesende Klammer wird "oben" ausgewertet
1002 void SwRTFParser::ReadField()
1004 bReadSwFly = false; //#it may be that any uses of this need to be removed and replaced
1005 int nRet = 0;
1006 int nNumOpenBrakets = 1; // die erste wurde schon vorher erkannt !!
1007 int bFldInst = FALSE, bFldRslt = FALSE;
1008 String sFieldStr, sFieldNm;
1009 BYTE cCh;
1011 int nToken;
1012 while (nNumOpenBrakets && IsParserWorking())
1014 switch (nToken = GetNextToken())
1016 case '}':
1018 --nNumOpenBrakets;
1019 if( 1 != nNumOpenBrakets || !bFldInst )
1020 break;
1022 if( !bFldRslt )
1024 // FieldInst vollstaendig eingelesen, was ist es denn?
1025 nRet = MakeFieldInst( sFieldStr );
1026 switch ( nRet )
1028 case RTFFLD_INCLUDETEXT:
1029 case RTFFLD_TOC:
1030 case RTFFLD_INDEX:
1031 // erstmal Index/Inhaltsverzeichniss ueberspringen
1032 // und als normalen Text einfuegen. Spaeter mal auch dem
1033 // SwPaM darum aufspannen.
1034 return ;
1036 case RTFFLD_IMPORT:
1037 case RTFFLD_HYPERLINK:
1038 sFieldNm = sFieldStr;
1039 break;
1041 sFieldStr.Erase();
1043 else if (RTFFLD_UNKNOWN == nRet)
1045 // FieldResult wurde eingelesen
1046 if (SwTxtNode* pTxtNd = pPam->GetPoint()->nNode.GetNode().GetTxtNode())
1048 SwTxtAttr* const pFldAttr =
1049 pTxtNd->GetTxtAttrForCharAt(
1050 pPam->GetPoint()->nContent.GetIndex()-1 );
1052 if (pFldAttr)
1054 const SwField *pFld = pFldAttr->GetFld().GetFld();
1055 SwFieldType *pTyp = pFld ? pFld->GetTyp() : 0;
1056 ASSERT(pTyp->Which() == RES_USERFLD, "expected a user field");
1057 if (pTyp->Which() == RES_USERFLD)
1059 SwUserFieldType *pUsrTyp = (SwUserFieldType*)pTyp;
1060 pUsrTyp->SetContent(sFieldStr);
1065 else if( sFieldNm.Len() )
1067 switch ( nRet )
1069 case RTFFLD_IMPORT:
1070 // Grafik einfuegen
1071 InsPicture( sFieldNm );
1072 nRet = INT_MAX;
1073 break;
1074 case RTFFLD_HYPERLINK:
1075 if( sFieldStr.Len() )
1077 if(sNestedFieldStr.Len())
1078 sFieldStr.Insert(sNestedFieldStr);
1080 sNestedFieldStr.Erase();
1081 // im FieldStr steht der anzuzeigenden Text, im
1082 pDoc->InsertString( *pPam, sFieldStr );
1084 String sTarget( sFieldNm.GetToken( 1, '\1' ));
1085 if( sTarget.Len() )
1086 sFieldNm.Erase( sFieldNm.Len() - sTarget.Len() -1 );
1088 // oder ueber den Stack setzen??
1089 pPam->SetMark();
1090 pPam->GetMark()->nContent -= sFieldStr.Len();
1091 pDoc->InsertPoolItem( *pPam,
1092 SwFmtINetFmt( sFieldNm, sTarget ),
1093 nsSetAttrMode::SETATTR_DONTEXPAND );
1094 pPam->DeleteMark();
1097 break;
1100 else if(bNestedField)
1102 if(nRet == RTFFLD_PAGEREF)
1104 // #17371 Nasty hack to get a pageref within a hyperlink working
1105 sNestedFieldStr = sFieldStr;
1111 break;
1113 case '{':
1114 if( RTF_IGNOREFLAG != GetNextToken() )
1115 SkipToken( -1 );
1116 // Unknown und alle bekannten nicht ausgewerteten Gruppen
1117 // sofort ueberspringen
1118 else if( RTF_UNKNOWNCONTROL != GetNextToken() )
1119 SkipToken( -2 );
1120 else
1122 // gleich herausfiltern
1123 ReadUnknownData();
1124 if( '}' != GetNextToken() )
1125 eState = SVPAR_ERROR;
1126 break;
1128 ++nNumOpenBrakets;
1129 break;
1131 case RTF_DATAFIELD:
1132 SkipGroup();
1133 break;
1135 case RTF_FIELD:
1136 bNestedField = true;
1137 ReadField();
1138 break;
1140 case RTF_FLDINST:
1141 bFldInst = TRUE;
1142 break;
1144 case RTF_FLDRSLT:
1145 bFldRslt = TRUE;
1146 break;
1148 case RTF_U:
1150 if( nTokenValue )
1151 sFieldStr += (sal_Unicode)nTokenValue;
1152 else
1153 sFieldStr += aToken;
1155 break;
1157 case RTF_LINE: cCh = '\n'; goto INSINGLECHAR;
1158 case RTF_TAB: cCh = '\t'; goto INSINGLECHAR;
1159 case RTF_SUBENTRYINDEX: cCh = ':'; goto INSINGLECHAR;
1160 case RTF_EMDASH: cCh = 151; goto INSINGLECHAR;
1161 case RTF_ENDASH: cCh = 150; goto INSINGLECHAR;
1162 case RTF_BULLET: cCh = 149; goto INSINGLECHAR;
1163 case RTF_LQUOTE: cCh = 145; goto INSINGLECHAR;
1164 case RTF_RQUOTE: cCh = 146; goto INSINGLECHAR;
1165 case RTF_LDBLQUOTE: cCh = 147; goto INSINGLECHAR;
1166 case RTF_RDBLQUOTE: cCh = 148; goto INSINGLECHAR;
1167 INSINGLECHAR:
1168 sFieldStr += ByteString::ConvertToUnicode( cCh,
1169 RTL_TEXTENCODING_MS_1252 );
1170 break;
1172 // kein Break, aToken wird als Text gesetzt
1173 case RTF_TEXTTOKEN:
1174 sFieldStr += aToken;
1175 break;
1177 case RTF_PICT: // Pic-Daten einlesen!
1178 if( RTFFLD_IMPORT == nRet )
1180 Graphic aGrf;
1181 SvxRTFPictureType aPicType;
1182 if( ReadBmpData( aGrf, aPicType ) )
1184 InsPicture( sFieldNm, &aGrf, &aPicType );
1185 nRet = INT_MAX;
1187 SkipGroup();
1189 break;
1191 case RTF_BKMK_KEY:
1192 case RTF_XE:
1193 case RTF_TC:
1194 case RTF_NEXTFILE:
1195 case RTF_TEMPLATE:
1196 case RTF_SHPRSLT:
1197 SkipGroup();
1198 break;
1200 case RTF_CS:
1201 // we write every time "EQ "
1202 if( bFldInst && 0 == sFieldStr.SearchAscii( "EQ " ))
1204 // insert behind the EQ the "\*cs<NO> " string. This is utilize
1205 // in the MakeFieldInst
1206 String sTmp;
1207 (sTmp.AssignAscii( "\\* cs" )
1208 += String::CreateFromInt32( nTokenValue )) += ' ';
1209 sFieldStr.Insert( sTmp, 3 );
1211 break;
1212 case RTF_FFNAME:
1213 case RTF_FORMFIELD:
1214 break;
1215 case RTF_PAR:
1216 sFieldStr.Append('\x0a');
1217 break;
1218 default:
1219 SvxRTFParser::NextToken( nToken );
1220 break;
1224 // Grafik einfuegen
1225 if (RTFFLD_IMPORT == nRet && sFieldNm.Len())
1226 InsPicture( sFieldNm );
1228 SkipToken( -1 ); // die schliesende Klammer wird "oben" ausgewertet
1231 /* vi:set tabstop=4 shiftwidth=4 expandtab: */