xref: /aoo4110/main/sw/source/filter/rtf/rtffld.cxx (revision b1cdbd2c)
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