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