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
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sw.hxx"
26 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil -*- */
27
28 #include <ctype.h>
29 #include <hintids.hxx>
30
31 #ifndef _COM_SUN_STAR_I18N_SCRIPTTYPE_HDL_
32 #include <com/sun/star/i18n/ScriptType.hdl>
33 #endif
34 #ifndef _GRAPH_HXX //autogen
35 #include <vcl/graph.hxx>
36 #endif
37 #include <svl/urihelper.hxx>
38 #include <svtools/rtftoken.h>
39 #include <svl/zforlist.hxx>
40 #include <editeng/fontitem.hxx>
41 #include <editeng/fhgtitem.hxx>
42 #include <editeng/langitem.hxx>
43 #include <editeng/brkitem.hxx>
44 #include <fmtfld.hxx>
45 #include <fmtinfmt.hxx>
46 #include <swtypes.hxx>
47 #include <doc.hxx>
48 #include <pam.hxx>
49 #include <ndtxt.hxx>
50 #include <shellio.hxx>
51 #include <fldbas.hxx>
52 #include <swparrtf.hxx>
53 #include <txatbase.hxx>
54 #include <dbfld.hxx>
55 #include <usrfld.hxx>
56 #include <docufld.hxx>
57 #include <flddat.hxx>
58 #include <charfmt.hxx>
59 #ifndef _fmtruby_HXX
60 #include <fmtruby.hxx>
61 #endif
62 #include <breakit.hxx>
63 #include <reffld.hxx>
64 #include <SwStyleNameMapper.hxx>
65 #include <editeng/charhiddenitem.hxx>
66
67
68 // bestimme, ob es sich um ein IMPORT/TOC - Feld handelt.
69 // return: 0 - weder noch,
70 // 1 - TOC
71 // 2 - IMPORT
72 // 3 - INDEX
73 enum RTF_FLD_TYPES {
74 RTFFLD_UNKNOWN = 0,
75 RTFFLD_TOC,
76 RTFFLD_IMPORT,
77 RTFFLD_INDEX,
78 RTFFLD_SYMBOL,
79 RTFFLD_PAGE,
80 RTFFLD_NUMPAGES,
81 RTFFLD_DATE,
82 RTFFLD_TIME,
83 RTFFLD_DATA,
84 RTFFLD_MERGEFLD,
85 RTFFLD_HYPERLINK,
86 RTFFLD_REF,
87 RTFFLD_PAGEREF,
88 RTFFLD_EQ,
89 RTFFLD_INCLUDETEXT
90 };
91
_WhichFld(String & rName,String & rNext)92 static RTF_FLD_TYPES _WhichFld( String& rName, String& rNext )
93 {
94 // Strings sind PascalStrings; Laenge steht an 1. Stellen, dadurch wird
95 // sich der Aufruf von strlen erspart!!!
96 sal_Char __READONLY_DATA sTOC[]= "\x03""toc";
97 sal_Char __READONLY_DATA sIMPORT[]= "\x06""import";
98 sal_Char __READONLY_DATA sINDEX[]= "\x05""index";
99 sal_Char __READONLY_DATA sSYMBOL[]= "\x06""symbol";
100 sal_Char __READONLY_DATA sPAGE[]= "\x04""page";
101 sal_Char __READONLY_DATA sNUMPAGES[]= "\x08""numpages";
102 sal_Char __READONLY_DATA sDATE[]= "\x04""date";
103 sal_Char __READONLY_DATA sTIME[]= "\x04""time";
104 sal_Char __READONLY_DATA sDATA[]= "\x04""data";
105 sal_Char __READONLY_DATA sMERGEFLD[]= "\x0A""mergefield";
106 sal_Char __READONLY_DATA sIMPORT2[]= "\x0E""includepicture";
107 sal_Char __READONLY_DATA sHYPERLINK[]= "\x09""hyperlink";
108 sal_Char __READONLY_DATA sREF[]= "\x03""ref";
109 sal_Char __READONLY_DATA sPAGEREF[]= "\x07""pageref";
110 sal_Char __READONLY_DATA sEQ[]= "\x02""eq";
111 sal_Char __READONLY_DATA sINCLUDETEXT[]="\x0B""includetext";
112
113 struct _Dummy_RTF_FLD_TYPES
114 {
115 RTF_FLD_TYPES eFldType;
116 const sal_Char* pFldNm;
117 };
118 __READONLY_DATA _Dummy_RTF_FLD_TYPES aFldNmArr[RTFFLD_INCLUDETEXT + 1] = {
119 {RTFFLD_TOC, sTOC},
120 {RTFFLD_IMPORT, sIMPORT},
121 {RTFFLD_INDEX, sINDEX},
122 {RTFFLD_SYMBOL, sSYMBOL},
123 {RTFFLD_PAGE, sPAGE},
124 {RTFFLD_NUMPAGES, sNUMPAGES},
125 {RTFFLD_DATE, sDATE},
126 {RTFFLD_TIME, sTIME},
127 {RTFFLD_DATA, sDATA},
128 {RTFFLD_MERGEFLD, sMERGEFLD},
129 {RTFFLD_IMPORT, sIMPORT2},
130 {RTFFLD_HYPERLINK, sHYPERLINK},
131 {RTFFLD_REF, sREF},
132 {RTFFLD_PAGEREF, sPAGEREF},
133 {RTFFLD_EQ, sEQ},
134 {RTFFLD_INCLUDETEXT, sINCLUDETEXT}
135 };
136
137
138 if( !rName.Len() )
139 return RTFFLD_UNKNOWN;
140
141 String sNm( rName );
142 sNm = sNm.EraseLeadingChars().GetToken(0, ' ');
143 ASSERT( sNm.Len(), "Feldname hat keine Laenge!" );
144 if( !sNm.Len() )
145 return RTFFLD_UNKNOWN;
146
147 xub_StrLen nTokenStt = rName.Search( sNm );
148 sNm.ToLowerAscii();
149
150 for (size_t n = 0; n < sizeof(aFldNmArr) / sizeof(aFldNmArr[0]); ++n)
151 {
152 const sal_Char* pCmp = aFldNmArr[n].pFldNm;
153 int nLen = *pCmp++;
154 xub_StrLen nFndPos = sNm.SearchAscii( pCmp );
155 if( STRING_NOTFOUND != nFndPos &&
156 ( !nFndPos || !isalpha(sNm.GetChar( static_cast< xub_StrLen >(nFndPos-1) )) ) &&
157 ( nFndPos+nLen == sNm.Len() || !isalpha(sNm.GetChar( static_cast< xub_StrLen >(nFndPos+nLen) ) ) ) )
158 {
159 // rName = sNm.Copy( nFndPos, nLen );
160 rName = rName.Copy( nFndPos, static_cast< xub_StrLen >(nLen) );
161 nFndPos += nTokenStt + static_cast< xub_StrLen >(nLen);
162 while ((nFndPos < rNext.Len()) && (rNext.GetChar(nFndPos) == ' '))
163 {
164 ++nFndPos;
165 }
166 rNext.Erase( 0, nFndPos );
167 rNext.EraseTrailingChars();
168 return aFldNmArr[n].eFldType;
169 }
170 }
171 return RTFFLD_UNKNOWN; // nichts gefunden.
172 }
173
CheckNumberFmtStr(const String & rNStr)174 static sal_uInt16 CheckNumberFmtStr( const String& rNStr )
175 {
176 const static sal_Char* aNumberTypeTab[] =
177 {
178 "\x0A""ALPHABETIC", /* CHARS_UPPER_LETTER*/
179 "\x0A""alphabetic", /* CHARS_LOWER_LETTER*/
180 "\x05""ROMAN", /* ROMAN_UPPER */
181 "\x05""roman", /* ROMAN_LOWER */
182 "\x06""ARABIC", /* ARABIC */
183 "\x04""NONE", /* NUMBER_NONE */
184 "\x04""CHAR", /* CHAR_SPECIAL */
185 "\x04""PAGE" /* PAGEDESC */
186 };
187
188 ASSERT(sizeof(aNumberTypeTab) / sizeof(sal_Char *)
189 >= SVX_NUM_PAGEDESC - SVX_NUM_CHARS_UPPER_LETTER, "impossible");
190
191 for (sal_uInt16 n = SVX_NUM_CHARS_UPPER_LETTER; n <= SVX_NUM_PAGEDESC; ++n)
192 {
193 const sal_Char* pCmp = aNumberTypeTab[n - SVX_NUM_CHARS_UPPER_LETTER];
194 int nLen = *pCmp++;
195 if( rNStr.EqualsAscii( pCmp, 0, static_cast< xub_StrLen >(nLen) ))
196 return static_cast< sal_uInt16 >(2 <= n ? n : (n + SVX_NUM_CHARS_UPPER_LETTER_N));
197 }
198 return SVX_NUM_PAGEDESC; // default-Wert
199 }
200
201 class RtfFieldSwitch
202 {
203 String sParam;
204 xub_StrLen nCurPos;
205 public:
206 RtfFieldSwitch( const String& rParam );
207 sal_Unicode GetSwitch( String& rParam );
208
IsAtEnd() const209 sal_Bool IsAtEnd() const { return nCurPos >= sParam.Len(); }
GetCurPos() const210 xub_StrLen GetCurPos() const { return nCurPos; }
Erase(xub_StrLen nEndPos)211 void Erase( xub_StrLen nEndPos ) { sParam.Erase( 0, nEndPos ); }
Insert(const String & rIns)212 void Insert( const String& rIns ) { sParam.Insert( rIns, 0 ); }
GetStr() const213 const String& GetStr() const { return sParam; }
214 };
215
RtfFieldSwitch(const String & rParam)216 RtfFieldSwitch::RtfFieldSwitch( const String& rParam )
217 : sParam( rParam ), nCurPos( 0 )
218 {
219 sParam.EraseTrailingChars().EraseLeadingChars();
220 }
221
GetSwitch(String & rParam)222 sal_Unicode RtfFieldSwitch::GetSwitch( String& rParam )
223 {
224 // beginnt ein Schalter?
225 sal_Unicode c, cKey = 0;
226 if( '\\' == (c = sParam.GetChar( nCurPos )) )
227 {
228 if( '\\' == ( c = sParam.GetChar( ++nCurPos )) )
229 c = sParam.GetChar( ++nCurPos );
230
231 cKey = c;
232
233 while( ++nCurPos < sParam.Len() &&
234 ' ' == ( c = sParam.GetChar( nCurPos )) )
235 ;
236 }
237
238 // dann alles in Hochkommatas oder bis zum naechsten // als
239 // Param returnen
240 sal_uInt16 nOffset;
241 if( '"' != c && '\'' != c )
242 c = '\\', nOffset = 0;
243 else
244 nOffset = 1;
245
246 sParam.Erase( 0, nCurPos + nOffset );
247 rParam = sParam.GetToken( 0, c );
248 sParam.Erase( 0, rParam.Len() + nOffset ).EraseLeadingChars();
249 if( '\\' == c )
250 rParam.EraseTrailingChars();
251 nCurPos = 0;
252
253 return cKey;
254 }
255
256 struct RTF_EquationData
257 {
258 String sFontName, sUp, sDown, sText;
259 sal_Int32 nJustificationCode, nFontSize, nUp, nDown, nStyleNo;
260
RTF_EquationDataRTF_EquationData261 inline RTF_EquationData()
262 : nJustificationCode(0), nFontSize(0), nUp(0), nDown(0),
263 nStyleNo( -1 )
264 {}
265 };
266
lcl_FindEndBracket(const String & rStr)267 xub_StrLen lcl_FindEndBracket( const String& rStr )
268 {
269 xub_StrLen nEnd = rStr.Len(), nRet = STRING_NOTFOUND, nPos = 0;
270 int nOpenCnt = 1;
271 sal_Unicode cCh;
272 for( ; nPos < nEnd; ++nPos )
273 if( ')' == (cCh = rStr.GetChar( nPos )) && !--nOpenCnt )
274 {
275 nRet = nPos;
276 break;
277 }
278 else if( '(' == cCh )
279 ++nOpenCnt;
280
281 return nRet;
282 }
283
lcl_ScanEquationField(const String & rStr,RTF_EquationData & rData,sal_Unicode nSttKey)284 void lcl_ScanEquationField( const String& rStr, RTF_EquationData& rData,
285 sal_Unicode nSttKey )
286 {
287 int nSubSupFlag(0);
288 RtfFieldSwitch aRFS( rStr );
289 while( !aRFS.IsAtEnd() )
290 {
291 String sParam;
292 sal_Unicode cKey = aRFS.GetSwitch( sParam );
293 if( 1 == nSubSupFlag )
294 ++nSubSupFlag;
295 else if( 1 < nSubSupFlag )
296 nSubSupFlag = 0;
297
298 sal_Bool bCheckBracket = sal_False;
299 switch( cKey )
300 {
301 case 0:
302 switch( nSttKey )
303 {
304 case 'u': rData.sUp += sParam; break;
305 case 'd': rData.sDown += sParam; break;
306 default: rData.sText += sParam; break;
307 }
308 break;
309
310 case '*':
311 if( sParam.Len() )
312 {
313 if( sParam.EqualsIgnoreCaseAscii( "jc", 0, 2 ) )
314 rData.nJustificationCode = sParam.Copy( 2 ).ToInt32();
315 else if( sParam.EqualsIgnoreCaseAscii( "hps", 0, 3 ) )
316 rData.nFontSize= sParam.Copy( 3 ).ToInt32();
317 else if( sParam.EqualsIgnoreCaseAscii( "Font:", 0, 5 ) )
318 rData.sFontName = sParam.Copy( 5 );
319 else if( sParam.EqualsIgnoreCaseAscii( "cs", 0, 2 ) )
320 rData.nStyleNo = sParam.Copy( 2 ).ToInt32();
321 }
322 break;
323 case 's' :
324 ++nSubSupFlag;
325 break;
326
327 case 'u':
328 if( sParam.Len() && 'p' == sParam.GetChar( 0 ) &&
329 2 == nSubSupFlag )
330 {
331 rData.nUp = sParam.Copy( 1 ).ToInt32();
332 bCheckBracket = sal_True;
333 }
334 break;
335
336 case 'd':
337 if( sParam.Len() && 'o' == sParam.GetChar( 0 ) &&
338 2 == nSubSupFlag )
339 {
340 rData.nDown = sParam.Copy( 1 ).ToInt32();
341 bCheckBracket = sal_True;
342 }
343 break;
344
345 default:
346 bCheckBracket = sal_True;
347 cKey = 0;
348 break;
349 }
350
351 if( bCheckBracket && sParam.Len() )
352 {
353 xub_StrLen nEnd, nStt = sParam.Search( '(' ),
354 nLen = sParam.Len();
355 if( STRING_NOTFOUND != nStt )
356 {
357 sParam.Erase( 0, nStt + 1 ) += aRFS.GetStr();
358 if( STRING_NOTFOUND !=
359 (nEnd = ::lcl_FindEndBracket( sParam )) )
360 {
361 // end in the added string?
362 if( (nLen - nStt - 1 ) < nEnd )
363 aRFS.Erase( nEnd + 1 - (nLen - nStt - 1));
364 else
365 {
366 // not all handled here, so set new into the RFS
367 aRFS.Insert( sParam.Copy( nEnd + 1,
368 nLen - nStt - nEnd - 2 ));
369 sal_Unicode cCh;
370 if( aRFS.GetStr().Len() &&
371 ( ',' == (cCh = aRFS.GetStr().GetChar(0)) ||
372 ';' == cCh ))
373 aRFS.Erase( 1 );
374 }
375
376 ::lcl_ScanEquationField( sParam.Copy( 0, nEnd ),
377 rData, cKey );
378 }
379 }
380 }
381 }
382 }
383
MakeFieldInst(String & rFieldStr)384 int SwRTFParser::MakeFieldInst( String& rFieldStr )
385 {
386 // sicher den Original-String fuer die FeldNamen (User/Datenbank)
387 String aSaveStr( rFieldStr );
388 SwFieldType * pFldType;
389 int nRet = _WhichFld(rFieldStr, aSaveStr);
390
391 //Strip Mergeformat from fields
392 xub_StrLen nPos=0;
393 while (STRING_NOTFOUND != ( nPos = aSaveStr.SearchAscii("\\*", nPos)))
394 {
395 xub_StrLen nStartDel = nPos;
396 nPos += 2;
397 while ((nPos < aSaveStr.Len()) && (aSaveStr.GetChar(nPos) == ' '))
398 {
399 ++nPos;
400 }
401 if (aSaveStr.EqualsIgnoreCaseAscii("MERGEFORMAT", nPos, 11))
402 {
403 xub_StrLen nNoDel = (nPos + 11 ) - nStartDel;
404 aSaveStr.Erase(nStartDel, nNoDel);
405 nPos -= (nStartDel - nPos);
406 }
407 }
408
409 nPos = 0;
410 switch (nRet)
411 {
412 case RTFFLD_INCLUDETEXT:
413 break;
414 case RTFFLD_IMPORT:
415 {
416 //JP 11.03.96: vertraegt sich nicht so ganz mit Internet!
417 // if( STRING_NOTFOUND != ( nPos = aSaveStr.Search( '.' )))
418 // aSaveStr.Erase( nPos+4 );
419
420 aSaveStr.EraseLeadingAndTrailingChars();
421 if( aSaveStr.Len() )
422 {
423 sal_Unicode c = aSaveStr.GetChar( 0 );
424 if( '"' == c || '\'' == c )
425 {
426 aSaveStr.Erase( 0, 1 );
427 aSaveStr = aSaveStr.GetToken( 0, c );
428 }
429
430 rFieldStr = URIHelper::SmartRel2Abs(
431 INetURLObject(GetBaseURL()), aSaveStr,
432 URIHelper::GetMaybeFileHdl() );
433 }
434 // SkipGroup(); // ueberlese den Rest
435 }
436 break;
437
438 case RTFFLD_NUMPAGES:
439 {
440 SwDocStatField aFld( (SwDocStatFieldType*)pDoc->GetSysFldType( RES_DOCSTATFLD ),
441 DS_PAGE, SVX_NUM_ARABIC );
442 if( STRING_NOTFOUND != ( nPos = aSaveStr.SearchAscii( "\\*" )) )
443 {
444 nPos += 2;
445 while ((nPos < aSaveStr.Len()) &&
446 (aSaveStr.GetChar(nPos) == ' '))
447 { nPos++; }
448 aSaveStr.Erase( 0, nPos );
449
450 // steht jetzt geanu auf dem Format-Namen
451 aFld.ChangeFormat( CheckNumberFmtStr( aSaveStr ));
452 }
453 pDoc->InsertPoolItem( *pPam, SwFmtFld( aFld ), 0 );
454 SkipGroup();
455 }
456 break;
457
458 case RTFFLD_PAGE:
459 {
460 pFldType = pDoc->GetSysFldType( RES_PAGENUMBERFLD );
461 SwPageNumberField aPF( (SwPageNumberFieldType*)pFldType,
462 PG_RANDOM, SVX_NUM_ARABIC);
463 if( STRING_NOTFOUND != ( nPos = aSaveStr.SearchAscii( "\\*" )) )
464 {
465 nPos += 2;
466 while ((nPos < aSaveStr.Len()) &&
467 (aSaveStr.GetChar(nPos) == ' '))
468 { nPos++; }
469 aSaveStr.Erase( 0, nPos );
470
471 // steht jetzt geanu auf dem Format-Namen
472 aPF.ChangeFormat( CheckNumberFmtStr( aSaveStr ));
473 }
474 pDoc->InsertPoolItem( *pPam, SwFmtFld( aPF ), 0 );
475 SkipGroup(); // ueberlese den Rest
476 }
477 break;
478 case RTFFLD_DATE:
479 case RTFFLD_TIME:
480 {
481 if( STRING_NOTFOUND == ( nPos = aSaveStr.SearchAscii( "\\@" )) )
482 {
483 // es fehlt die Format - Angabe: defaulten auf Datum
484 pFldType = pDoc->GetSysFldType( RES_DATETIMEFLD );
485 pDoc->InsertPoolItem( *pPam, SwFmtFld( SwDateTimeField(
486 static_cast<SwDateTimeFieldType*>(pFldType), DATEFLD)), 0);
487 }
488 else
489 {
490 // versuche aus dem Formatstring zu erkennen, ob es ein
491 // Datum oder Zeit oder Datum & Zeit Field ist
492 // nur das Format interressiert
493 aSaveStr.Erase( 0, aSaveStr.Search( '\"' )+1 );
494 // alles hinter dem Format interressiert auch nicht mehr.
495 aSaveStr.Erase( aSaveStr.Search( '\"' ) );
496 aSaveStr.SearchAndReplaceAscii( "AM", aEmptyStr );
497 aSaveStr.SearchAndReplaceAscii( "PM", aEmptyStr );
498
499 // #117892# M.M. Put the word date and time formatter stuff in a common area
500 // and get the rtf filter to use it
501 SwField *pFld = 0;
502 short nNumFmtType = NUMBERFORMAT_UNDEFINED;
503 sal_uLong nFmtIdx = NUMBERFORMAT_UNDEFINED;
504
505 sal_uInt16 rLang(0);
506 RES_CHRATR eLang = maPageDefaults.mbRTLdoc ? RES_CHRATR_CTL_LANGUAGE : RES_CHRATR_LANGUAGE;
507 const SvxLanguageItem *pLang = (SvxLanguageItem*)&pDoc->GetAttrPool().GetDefaultItem( static_cast< sal_uInt16 >(eLang) );
508 rLang = pLang ? pLang->GetValue() : LANGUAGE_ENGLISH_US;
509
510 SvNumberFormatter* pFormatter = pDoc->GetNumberFormatter();
511 bool bHijri = false;
512
513 if( pFormatter )
514 {
515 nFmtIdx = sw::ms::MSDateTimeFormatToSwFormat(aSaveStr, pFormatter, rLang, bHijri);
516 if (nFmtIdx)
517 nNumFmtType = pFormatter->GetType(nFmtIdx);
518 }
519
520 pFldType = pDoc->GetSysFldType( RES_DATETIMEFLD );
521
522 if(nNumFmtType & NUMBERFORMAT_DATE)
523 pFld = new SwDateTimeField( (SwDateTimeFieldType*)pFldType, DATEFLD, nFmtIdx );
524 else if(nNumFmtType == NUMBERFORMAT_TIME)
525 pFld = new SwDateTimeField( (SwDateTimeFieldType*)pFldType, TIMEFLD, nFmtIdx );
526
527 if( pFld )
528 {
529 pDoc->InsertPoolItem( *pPam, SwFmtFld( *pFld ), 0);
530 delete pFld;
531 }
532 }
533 SkipGroup(); // ueberlese den Rest
534 }
535 break;
536
537 case RTFFLD_DATA:
538 {
539 // Datenbank-FileName: nur der Filename interressiert
540 // Zur Zeit werden nur SDF-Files verarbeitet, also suche nach
541 // der Extension
542
543 // im SWG geben die DATA Felder den Namen der Datenbank
544 // an. Dieser kann als Field oder als DBInfo interpretiert
545 // werden:
546 // \\data -> Datenbank-Name als Field
547 // DATA -> Datenbank-Info
548 bool const bField = rFieldStr.Len() && rFieldStr.GetChar(0) != 'D';
549
550 // nur der Name interressiert
551 if( STRING_NOTFOUND != (nPos = aSaveStr.Search( '.' )) )
552 aSaveStr.Erase( nPos );
553 SwDBData aData;
554 aData.sDataSource = aSaveStr;
555 if( bField )
556 {
557 pFldType = pDoc->GetSysFldType( RES_DBNAMEFLD );
558 pDoc->InsertPoolItem( *pPam, SwFmtFld( SwDBNameField(
559 static_cast<SwDBNameFieldType*>(pFldType), SwDBData())), 0);
560 }
561 else
562 pDoc->ChgDBData( aData ); // MS: Keine DBInfo verwenden
563 SkipGroup(); // ueberlese den Rest
564 }
565 break;
566 case RTFFLD_MERGEFLD:
567 {
568 // ein Datenbank - Feld: nur der Name interressiert
569 // bis zum Ende vom String ist das der Feldname
570 SwDBFieldType aTmp( pDoc, aSaveStr, SwDBData() ); //
571 SwDBField aDBFld( (SwDBFieldType*)pDoc->InsertFldType( aTmp ));
572
573 aDBFld.ChangeFormat( UF_STRING );
574 pDoc->InsertPoolItem(*pPam, SwFmtFld( aDBFld ), 0);
575 SkipGroup(); // ueberlese den Rest
576 }
577 break;
578
579 case RTFFLD_SYMBOL:
580 {
581 // loesche fuehrende Blanks
582 if( IsNewGroup() )
583 GetAttrSet();
584 SetNewGroup( sal_True );
585
586 SfxItemSet& rSet = GetAttrSet();
587
588 sal_Bool bCharIns = sal_False;
589 RtfFieldSwitch aRFS( aSaveStr );
590 while( !aRFS.IsAtEnd() )
591 {
592 String sParam;
593 sal_Unicode cKey = aRFS.GetSwitch( sParam );
594 if( sParam.Len() )
595 switch( cKey )
596 {
597 case 0:
598 if( !bCharIns )
599 {
600 sal_Unicode nChar = (sal_Unicode)sParam.ToInt32();
601 if( nChar )
602 {
603 pDoc->InsertString( *pPam, nChar );
604 bCharIns = sal_True;
605 }
606 }
607 break;
608
609 case 'f': case 'F':
610 // Font setzen
611 {
612 SvxRTFFontTbl& rTbl = GetFontTbl();
613 for( Font* pFont = rTbl.First(); pFont;
614 pFont = rTbl.Next() )
615 if( pFont->GetName() == sParam )
616 {
617 rSet.Put( SvxFontItem(
618 pFont->GetFamily(),
619 sParam,
620 pFont->GetStyleName(),
621 pFont->GetPitch(),
622 pFont->GetCharSet(),
623 RES_CHRATR_FONT ));
624 break;
625 }
626 }
627 break;
628 case 'h': case 'H':
629 //??
630 break;
631 case 's': case 'S':
632 // Fontsize setzen
633 {
634 const sal_uInt16 nVal = (sal_uInt16)(sParam.ToInt32() * 20);
635 rSet.Put( SvxFontHeightItem( nVal,
636 100, RES_CHRATR_FONTSIZE ));
637 }
638 break;
639 }
640 }
641
642 if( !IsNewGroup() ) AttrGroupEnd();
643 SetNewGroup( sal_False );
644
645 SkipGroup(); // ueberlese den Rest
646 }
647 break;
648
649 case RTFFLD_HYPERLINK:
650 rFieldStr.Erase();
651 if( aSaveStr.Len() )
652 {
653 // return String ist URL, # Mark, \1 Frame
654 String sMark, sFrame;
655 RtfFieldSwitch aRFS( aSaveStr );
656 while( !aRFS.IsAtEnd() )
657 {
658 String sParam;
659 sal_Unicode cKey = aRFS.GetSwitch( sParam );
660 if( sParam.Len() )
661 switch( cKey )
662 {
663 case 0:
664 if( !rFieldStr.Len() )
665 rFieldStr = URIHelper::SmartRel2Abs(
666 INetURLObject(GetBaseURL()), sParam,
667 URIHelper::GetMaybeFileHdl() );
668 break;
669
670 case 'l': case 'L': sMark = sParam; break;
671 case 't': case 'T': sFrame = sParam; break;
672 }
673 }
674
675 if( sMark.Len() )
676 ( rFieldStr += INET_MARK_TOKEN ) += sMark;
677 if( sFrame.Len() )
678 ( rFieldStr += '\1' ) += sFrame;
679 }
680 break;
681
682 case RTFFLD_EQ:
683 rFieldStr.Erase();
684 if( aSaveStr.Len() )
685 {
686 RTF_EquationData aData;
687 ::lcl_ScanEquationField( aSaveStr, aData, 0 );
688
689 // is it a ruby attr?
690 if( aData.sText.Len() && aData.sFontName.Len() &&
691 aData.nFontSize && aData.sUp.Len() && !aData.sDown.Len() )
692 {
693 //Translate and apply
694 switch( aData.nJustificationCode )
695 {
696 case 0: aData.nJustificationCode = 1; break;
697 case 1: aData.nJustificationCode = 3; break;
698 case 2: aData.nJustificationCode = 4; break;
699 case 4: aData.nJustificationCode = 2; break;
700 // case 3:
701 default: aData.nJustificationCode = 0; break;
702 }
703
704 SwFmtRuby aRuby( aData.sUp );
705 SwCharFmt * pCharFmt = -1 != aData.nStyleNo
706 ? aCharFmtTbl.Get( aData.nStyleNo )
707 : 0;
708
709 if( !pCharFmt )
710 {
711 //Make a guess at which of asian of western we should be setting
712 sal_uInt16 nScript;
713 if (pBreakIt->GetBreakIter().is())
714 nScript = pBreakIt->GetBreakIter()->getScriptType( aData.sUp, 0);
715 else
716 nScript = i18n::ScriptType::ASIAN;
717
718 sal_uInt16 nFntHWhich = GetWhichOfScript( RES_CHRATR_FONTSIZE, nScript ),
719 nFntWhich = GetWhichOfScript( RES_CHRATR_FONT, nScript );
720
721 //Check to see if we already have a ruby charstyle that this fits
722 for(sal_uInt16 i=0; i < aRubyCharFmts.Count(); ++i )
723 {
724 SwCharFmt *pFmt = (SwCharFmt *)aRubyCharFmts[i];
725 const SvxFontHeightItem &rF = (const SvxFontHeightItem &)
726 pFmt->GetFmtAttr( nFntHWhich );
727 if( rF.GetHeight() == sal_uInt16(aData.nFontSize * 10 ))
728 {
729 const SvxFontItem &rFI = (const SvxFontItem &)
730 pFmt->GetFmtAttr( nFntWhich );
731 if( rFI.GetFamilyName().Equals( aData.sFontName ))
732 {
733 pCharFmt = pFmt;
734 break;
735 }
736 }
737 }
738
739 //Create a new char style if necessary
740 if( !pCharFmt )
741 {
742 String sNm;
743 //Take this as the base name
744 SwStyleNameMapper::FillUIName( RES_POOLCHR_RUBYTEXT, sNm );
745 sNm += String::CreateFromInt32( aRubyCharFmts.Count() + 1 );
746 pCharFmt = pDoc->MakeCharFmt( sNm,
747 ( SwCharFmt*)pDoc->GetDfltCharFmt() );
748
749 SvxFontHeightItem aHeightItem( aData.nFontSize * 10, 100, RES_CHRATR_FONTSIZE );
750 aHeightItem.SetWhich( nFntHWhich );
751
752 SvxFontItem aFontItem( FAMILY_DONTKNOW, aData.sFontName,
753 aEmptyStr, PITCH_DONTKNOW, RTL_TEXTENCODING_DONTKNOW, nFntWhich );
754
755 pCharFmt->SetFmtAttr( aHeightItem );
756 pCharFmt->SetFmtAttr( aFontItem );
757 void* p = pCharFmt;
758 aRubyCharFmts.Insert( p, aRubyCharFmts.Count() );
759 }
760 }
761
762 //Set the charstyle and justification
763 aRuby.SetCharFmtName( pCharFmt->GetName() );
764 aRuby.SetCharFmtId( pCharFmt->GetPoolFmtId() );
765 aRuby.SetAdjustment( (sal_uInt16)aData.nJustificationCode );
766
767 // im FieldStr steht der anzuzeigenden Text, im
768 pDoc->InsertString( *pPam, aData.sText );
769 pPam->SetMark();
770 pPam->GetMark()->nContent -= aData.sText.Len();
771 pDoc->InsertPoolItem( *pPam, aRuby,
772 nsSetAttrMode::SETATTR_DONTEXPAND );
773 pPam->DeleteMark();
774 }
775 // or a combined character field?
776 else if( aData.sUp.Len() && aData.sDown.Len() &&
777 !aData.sText.Len() && !aData.sFontName.Len() &&
778 !aData.nFontSize )
779 {
780 String sFld( aData.sUp );
781 sFld += aData.sDown;
782 SwCombinedCharField aFld((SwCombinedCharFieldType*)pDoc->
783 GetSysFldType( RES_COMBINED_CHARS ), sFld );
784 pDoc->InsertPoolItem( *pPam, SwFmtFld( aFld ), 0);
785
786 }
787 SkipGroup(); // ueberlese den Rest
788 }
789 break;
790
791 case RTFFLD_PAGEREF:
792 {
793 String sOrigBkmName;
794 RtfFieldSwitch aRFS( aSaveStr );
795 while( !aRFS.IsAtEnd() )
796 {
797 String sParam;
798 sal_Unicode cKey = aRFS.GetSwitch( sParam );
799 switch( cKey )
800 {
801 // In the case of pageref the only parameter we are
802 // interested in, is the name of the bookmark
803 case 0:
804 if( !sOrigBkmName.Len() ) // get name of bookmark
805 sOrigBkmName = sParam;
806 break;
807 }
808 }
809 SwGetRefField aFld(
810 (SwGetRefFieldType*)pDoc->GetSysFldType( RES_GETREFFLD ),
811 sOrigBkmName,REF_BOOKMARK,0,REF_PAGE);
812
813 if(!bNestedField)
814 {
815 pDoc->InsertPoolItem( *pPam, SwFmtFld( aFld ), 0 );
816 }
817 else
818 bNestedField = false;
819 }
820 break;
821
822 case RTFFLD_REF:
823 {
824 String sOrigBkmName;
825 bool bChapterNr = false;
826 bool bAboveBelow = false;
827
828 RtfFieldSwitch aRFS( aSaveStr );
829 while( !aRFS.IsAtEnd() )
830 {
831 String sParam;
832 sal_Unicode cKey = aRFS.GetSwitch( sParam );
833 switch( cKey )
834 {
835 case 0:
836 if( !sOrigBkmName.Len() ) // get name of bookmark
837 sOrigBkmName = sParam;
838 break;
839
840 case 'n':
841 case 'r':
842 case 'w':
843 bChapterNr = true; // activate flag 'Chapter Number'
844 break;
845
846 case 'p':
847 bAboveBelow = true;
848 break;
849 }
850 }
851 if (!bAboveBelow || bChapterNr)
852 {
853 if (bChapterNr)
854 {
855 SwGetRefField aFld(
856 (SwGetRefFieldType*)pDoc->GetSysFldType( RES_GETREFFLD ),
857 sOrigBkmName,REF_BOOKMARK,0,REF_CHAPTER);
858 pDoc->InsertPoolItem( *pPam, SwFmtFld( aFld ), 0 );
859 }
860 else
861 {
862 SwGetRefField aFld(
863 (SwGetRefFieldType*)pDoc->GetSysFldType( RES_GETREFFLD ),
864 sOrigBkmName,REF_BOOKMARK,0,REF_CONTENT);
865 pDoc->InsertPoolItem( *pPam, SwFmtFld( aFld ), 0 );
866 }
867 }
868
869 if( bAboveBelow )
870 {
871 SwGetRefField aFld( (SwGetRefFieldType*)
872 pDoc->GetSysFldType( RES_GETREFFLD ), sOrigBkmName, REF_BOOKMARK, 0,
873 REF_UPDOWN );
874 pDoc->InsertPoolItem(*pPam, SwFmtFld(aFld), 0);
875 }
876 }
877 break;
878
879 case RTFFLD_TOC:
880 case RTFFLD_INDEX:
881 break;
882
883 default:
884 {
885 // keines von den bekannten Feldern, also eine neues UserField
886 aSaveStr.EraseLeadingChars().EraseTrailingChars();
887 SwUserFieldType aTmp( pDoc, aSaveStr );
888 SwUserField aUFld( (SwUserFieldType*)pDoc->InsertFldType( aTmp ));
889 aUFld.ChangeFormat( UF_STRING );
890 pDoc->InsertPoolItem( *pPam, SwFmtFld( aUFld ), 0);
891 nRet = RTFFLD_UNKNOWN;
892 }
893 break;
894 }
895 return nRet;
896 }
897
898
ReadXEField()899 void SwRTFParser::ReadXEField()
900 {
901 bReadSwFly = false; //#it may be that any uses of this need to be removed and replaced
902 int nNumOpenBrakets = 1;
903 String sFieldStr;
904 sal_uInt8 cCh;
905
906 int nToken;
907 while (nNumOpenBrakets && IsParserWorking())
908 {
909 switch (nToken = GetNextToken())
910 {
911 case '}':
912 {
913 --nNumOpenBrakets;
914
915 if( sFieldStr.Len())
916 {
917 String sXE(sFieldStr);
918 sXE.Insert('\"', 0);
919 sXE.Append('\"');
920
921 // we have to make sure the hidden text flag is not on
922 // otherwise the index will not see this index mark
923 SfxItemSet& rSet = GetAttrSet();
924 const SfxPoolItem* pItem;
925 if( SFX_ITEM_SET == rSet.GetItemState( RES_CHRATR_HIDDEN, sal_True, &pItem ) )
926 {
927 SvxCharHiddenItem aCharHidden(*(SvxCharHiddenItem*)pItem);
928 aCharHidden.SetValue(sal_False);
929 rSet.Put(aCharHidden);
930 }
931
932 sw::ms::ImportXE(*pDoc, *pPam, sXE);
933
934 sFieldStr.Erase();
935 }
936 }
937 break;
938
939 case '{':
940 if( RTF_IGNOREFLAG != GetNextToken() )
941 SkipToken( -1 );
942 // Unknown und alle bekannten nicht ausgewerteten Gruppen
943 // sofort ueberspringen
944 else if( RTF_UNKNOWNCONTROL != GetNextToken() )
945 SkipToken( -2 );
946 else
947 {
948 // gleich herausfiltern
949 ReadUnknownData();
950 if( '}' != GetNextToken() )
951 eState = SVPAR_ERROR;
952 break;
953 }
954 ++nNumOpenBrakets;
955 break;
956
957 case RTF_U:
958 {
959 if( nTokenValue )
960 sFieldStr += (sal_Unicode)nTokenValue;
961 else
962 sFieldStr += aToken;
963 }
964 break;
965
966 case RTF_LINE: cCh = '\n'; goto INSINGLECHAR;
967 case RTF_TAB: cCh = '\t'; goto INSINGLECHAR;
968 case RTF_SUBENTRYINDEX: cCh = ':'; goto INSINGLECHAR;
969 case RTF_EMDASH: cCh = 151; goto INSINGLECHAR;
970 case RTF_ENDASH: cCh = 150; goto INSINGLECHAR;
971 case RTF_BULLET: cCh = 149; goto INSINGLECHAR;
972 case RTF_LQUOTE: cCh = 145; goto INSINGLECHAR;
973 case RTF_RQUOTE: cCh = 146; goto INSINGLECHAR;
974 case RTF_LDBLQUOTE: cCh = 147; goto INSINGLECHAR;
975 case RTF_RDBLQUOTE: cCh = 148; goto INSINGLECHAR;
976 INSINGLECHAR:
977 sFieldStr += ByteString::ConvertToUnicode( cCh,
978 RTL_TEXTENCODING_MS_1252 );
979 break;
980
981 // kein Break, aToken wird als Text gesetzt
982 case RTF_TEXTTOKEN:
983 sFieldStr += aToken;
984 break;
985
986 case RTF_BKMK_KEY:
987 case RTF_TC:
988 case RTF_NEXTFILE:
989 case RTF_TEMPLATE:
990 case RTF_SHPRSLT:
991 SkipGroup();
992 break;
993
994 case RTF_PAR:
995 sFieldStr.Append('\x0a');
996 break;
997 default:
998 SvxRTFParser::NextToken( nToken );
999 break;
1000 }
1001 }
1002
1003 SkipToken( -1 ); // die schliesende Klammer wird "oben" ausgewertet
1004 }
1005
1006
ReadField()1007 void SwRTFParser::ReadField()
1008 {
1009 bReadSwFly = false; //#it may be that any uses of this need to be removed and replaced
1010 int nRet = 0;
1011 int nNumOpenBrakets = 1; // die erste wurde schon vorher erkannt !!
1012 int bFldInst = sal_False, bFldRslt = sal_False;
1013 String sFieldStr, sFieldNm;
1014 sal_uInt8 cCh;
1015
1016 int nToken;
1017 while (nNumOpenBrakets && IsParserWorking())
1018 {
1019 switch (nToken = GetNextToken())
1020 {
1021 case '}':
1022 {
1023 --nNumOpenBrakets;
1024 if( 1 != nNumOpenBrakets || !bFldInst )
1025 break;
1026
1027 if( !bFldRslt )
1028 {
1029 // FieldInst vollstaendig eingelesen, was ist es denn?
1030 nRet = MakeFieldInst( sFieldStr );
1031 switch ( nRet )
1032 {
1033 case RTFFLD_INCLUDETEXT:
1034 case RTFFLD_TOC:
1035 case RTFFLD_INDEX:
1036 // erstmal Index/Inhaltsverzeichniss ueberspringen
1037 // und als normalen Text einfuegen. Spaeter mal auch dem
1038 // SwPaM darum aufspannen.
1039 return ;
1040
1041 case RTFFLD_IMPORT:
1042 case RTFFLD_HYPERLINK:
1043 sFieldNm = sFieldStr;
1044 break;
1045 }
1046 sFieldStr.Erase();
1047 }
1048 else if (RTFFLD_UNKNOWN == nRet)
1049 {
1050 // FieldResult wurde eingelesen
1051 if (SwTxtNode* pTxtNd = pPam->GetPoint()->nNode.GetNode().GetTxtNode())
1052 {
1053 SwTxtAttr* const pFldAttr =
1054 pTxtNd->GetTxtAttrForCharAt(
1055 pPam->GetPoint()->nContent.GetIndex()-1 );
1056
1057 if (pFldAttr)
1058 {
1059 const SwField *pFld = pFldAttr->GetFmtFld().GetField();
1060 SwFieldType *pTyp = pFld ? pFld->GetTyp() : 0;
1061 ASSERT(pTyp->Which() == RES_USERFLD, "expected a user field");
1062 if (pTyp->Which() == RES_USERFLD)
1063 {
1064 SwUserFieldType *pUsrTyp = (SwUserFieldType*)pTyp;
1065 pUsrTyp->SetContent(sFieldStr);
1066 }
1067 }
1068 }
1069 }
1070 else if( sFieldNm.Len() )
1071 {
1072 switch ( nRet )
1073 {
1074 case RTFFLD_IMPORT:
1075 // Grafik einfuegen
1076 InsPicture( sFieldNm );
1077 nRet = INT_MAX;
1078 break;
1079 case RTFFLD_HYPERLINK:
1080 if( sFieldStr.Len() )
1081 {
1082 if(sNestedFieldStr.Len())
1083 sFieldStr.Insert(sNestedFieldStr);
1084
1085 sNestedFieldStr.Erase();
1086 // im FieldStr steht der anzuzeigenden Text, im
1087 pDoc->InsertString( *pPam, sFieldStr );
1088
1089 String sTarget( sFieldNm.GetToken( 1, '\1' ));
1090 if( sTarget.Len() )
1091 sFieldNm.Erase( sFieldNm.Len() - sTarget.Len() -1 );
1092
1093 // oder ueber den Stack setzen??
1094 pPam->SetMark();
1095 pPam->GetMark()->nContent -= sFieldStr.Len();
1096 pDoc->InsertPoolItem( *pPam,
1097 SwFmtINetFmt( sFieldNm, sTarget ),
1098 nsSetAttrMode::SETATTR_DONTEXPAND );
1099 pPam->DeleteMark();
1100 // #i117947#: insert result only once in case
1101 // field result is followed by invalid tokens
1102 sFieldStr.Erase();
1103 }
1104 break;
1105 }
1106 }
1107 else if(bNestedField)
1108 {
1109 if(nRet == RTFFLD_PAGEREF)
1110 {
1111 // #17371 Nasty hack to get a pageref within a hyperlink working
1112 sNestedFieldStr = sFieldStr;
1113 }
1114
1115 }
1116
1117 }
1118 break;
1119
1120 case '{':
1121 if( RTF_IGNOREFLAG != GetNextToken() )
1122 SkipToken( -1 );
1123 // Unknown und alle bekannten nicht ausgewerteten Gruppen
1124 // sofort ueberspringen
1125 else if( RTF_UNKNOWNCONTROL != GetNextToken() )
1126 SkipToken( -2 );
1127 else
1128 {
1129 // gleich herausfiltern
1130 ReadUnknownData();
1131 if( '}' != GetNextToken() )
1132 eState = SVPAR_ERROR;
1133 break;
1134 }
1135 ++nNumOpenBrakets;
1136 break;
1137
1138 case RTF_DATAFIELD:
1139 SkipGroup();
1140 break;
1141
1142 case RTF_FIELD:
1143 bNestedField = true;
1144 ReadField();
1145 break;
1146
1147 case RTF_FLDINST:
1148 bFldInst = sal_True;
1149 break;
1150
1151 case RTF_FLDRSLT:
1152 bFldRslt = sal_True;
1153 break;
1154
1155 case RTF_U:
1156 {
1157 if( nTokenValue )
1158 sFieldStr += (sal_Unicode)nTokenValue;
1159 else
1160 sFieldStr += aToken;
1161 }
1162 break;
1163
1164 case RTF_LINE: cCh = '\n'; goto INSINGLECHAR;
1165 case RTF_TAB: cCh = '\t'; goto INSINGLECHAR;
1166 case RTF_SUBENTRYINDEX: cCh = ':'; goto INSINGLECHAR;
1167 case RTF_EMDASH: cCh = 151; goto INSINGLECHAR;
1168 case RTF_ENDASH: cCh = 150; goto INSINGLECHAR;
1169 case RTF_BULLET: cCh = 149; goto INSINGLECHAR;
1170 case RTF_LQUOTE: cCh = 145; goto INSINGLECHAR;
1171 case RTF_RQUOTE: cCh = 146; goto INSINGLECHAR;
1172 case RTF_LDBLQUOTE: cCh = 147; goto INSINGLECHAR;
1173 case RTF_RDBLQUOTE: cCh = 148; goto INSINGLECHAR;
1174 INSINGLECHAR:
1175 sFieldStr += ByteString::ConvertToUnicode( cCh,
1176 RTL_TEXTENCODING_MS_1252 );
1177 break;
1178
1179 // kein Break, aToken wird als Text gesetzt
1180 case RTF_TEXTTOKEN:
1181 sFieldStr += aToken;
1182 break;
1183
1184 case RTF_PICT: // Pic-Daten einlesen!
1185 if( RTFFLD_IMPORT == nRet )
1186 {
1187 Graphic aGrf;
1188 SvxRTFPictureType aPicType;
1189 if( ReadBmpData( aGrf, aPicType ) )
1190 {
1191 InsPicture( sFieldNm, &aGrf, &aPicType );
1192 nRet = INT_MAX;
1193 }
1194 SkipGroup();
1195 }
1196 break;
1197
1198 case RTF_BKMK_KEY:
1199 case RTF_XE:
1200 case RTF_TC:
1201 case RTF_NEXTFILE:
1202 case RTF_TEMPLATE:
1203 case RTF_SHPRSLT:
1204 SkipGroup();
1205 break;
1206
1207 case RTF_CS:
1208 // we write every time "EQ "
1209 if( bFldInst && 0 == sFieldStr.SearchAscii( "EQ " ))
1210 {
1211 // insert behind the EQ the "\*cs<NO> " string. This is utilize
1212 // in the MakeFieldInst
1213 String sTmp;
1214 (sTmp.AssignAscii( "\\* cs" )
1215 += String::CreateFromInt32( nTokenValue )) += ' ';
1216 sFieldStr.Insert( sTmp, 3 );
1217 }
1218 break;
1219 case RTF_FFNAME:
1220 case RTF_FORMFIELD:
1221 break;
1222 case RTF_PAR:
1223 sFieldStr.Append('\x0a');
1224 break;
1225 default:
1226 SvxRTFParser::NextToken( nToken );
1227 break;
1228 }
1229 }
1230
1231 // Grafik einfuegen
1232 if (RTFFLD_IMPORT == nRet && sFieldNm.Len())
1233 InsPicture( sFieldNm );
1234
1235 SkipToken( -1 ); // die schliesende Klammer wird "oben" ausgewertet
1236 }
1237
1238 /* vi:set tabstop=4 shiftwidth=4 expandtab: */
1239