1 /* -*- c-basic-offset: 4; tab-width: 4; indent-tabs-mode: t -*- */
2 
3 /* AbiWord
4  * Copyright (C) 1999 AbiSource, Inc.
5  * Copyright (C) 2003 Tomas Frydrych <tomas@frydrych.uklinux.net>
6  * Copyright (C) 2003 Martin Sevior <msevior@physics.unimelb.edu.au>
7  * Copyright (C) 2001, 2004, 2009, 2011 Hubert Figuiere <hub@figuiere.net>
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22  * 02110-1301 USA.
23  */
24 
25 /* RTF importer by Peter Arnold <petera@intrinsica.co.uk> */
26 
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30 
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <stddef.h>
35 #include <ctype.h>
36 #include <math.h>
37 
38 #include "fl_TableLayout.h"
39 #include "ut_locale.h"
40 #include "ut_iconv.h"
41 #include "ut_types.h"
42 #include "ut_assert.h"
43 #include "ut_debugmsg.h"
44 #include "ut_math.h"
45 #include "ut_path.h"
46 #include "ut_string.h"
47 #include "ut_string_class.h"
48 #include "ut_units.h"
49 #include "ut_std_vector.h"
50 #include "ie_types.h"
51 #include "ie_impexp_RTF.h"
52 #include "ie_imp_RTF.h"
53 #include "pd_Document.h"
54 #include "pd_DocumentRDF.h"
55 #include "pd_RDFSupport.h"
56 #include "xap_EncodingManager.h"
57 #include "ie_impGraphic.h"
58 #include "fg_Graphic.h"
59 #include "fg_GraphicRaster.h"
60 #include "fg_GraphicVector.h"
61 #include "ut_bytebuf.h"
62 #include "ut_rand.h"
63 #include "pd_Style.h"
64 #include "fv_View.h"
65 #include "fl_AutoLists.h"
66 #include "pf_Frag.h"
67 #include "pf_Frag_Strux.h"
68 #include "xap_App.h"
69 #include "xap_Frame.h"
70 #include "fp_Run.h"
71 #include "wv.h" // for wvLIDToLangConverter
72 #include "ut_std_string.h"
73 
74 #include "ie_imp_RTFParse.h"
75 
76 #include <sstream>
77 
78 class fl_AutoNum;
79 
80 
81 /** Ensure on input from RTF the list level is 0-8 */
_sanitizeListLevel(UT_sint32 level)82 inline UT_sint32 _sanitizeListLevel(UT_sint32 level)
83 {
84 	if(level > 8) {
85 		level = 8;
86 	}
87 	else if(level < 0) {
88 		level = 0;
89 	}
90 	return level;
91 }
92 
93 
94 /*!
95   This macros allow the use of an iconv fallback name if needed.
96  */
97 #define CPNAME_OR_FALLBACK(destination,name,fallbackname) \
98 {  \
99 	static const char* cpname = NULL; \
100 	if (!cpname)    \
101 	{       \
102 		UT_iconv_t cd = UT_iconv_open(name,name);     \
103 		if (!UT_iconv_isValid(cd)) \
104 		{ \
105 			cpname = fallbackname;\
106 		} \
107 		else \
108 		{ \
109 			cpname = name;  \
110 			UT_iconv_close(cd); \
111 		} \
112 	} \
113 	destination = cpname;  \
114 }
115 
116 
117 // This should probably be defined in pt_Types.h
118 // this used to be 8, which way to small ...
119 static const UT_uint32 PT_MAX_ATTRIBUTES = 20;
120 
121 
122 static char g_dbgLastKeyword [256];
123 static UT_sint32 g_dbgLastParam;
124 
125 
126 UT_sint32 ABI_RTF_Annotation::sAnnotationNumber = 0;
127 
newNumber()128 UT_sint32 ABI_RTF_Annotation::newNumber()
129 {
130 	++sAnnotationNumber;
131 	return sAnnotationNumber;
132 }
133 
134 
135 //////////////////////////////////////////////////////////////////
136 //////////////////////////////////////////////////////////////////
137 
IE_Imp_RTF_Sniffer()138 IE_Imp_RTF_Sniffer::IE_Imp_RTF_Sniffer ()
139 	: IE_ImpSniffer(IE_IMPEXPNAME_RTF, true)
140 {
141 	//
142 }
143 
144 // supported suffixes
145 static IE_SuffixConfidence IE_Imp_RTF_Sniffer__SuffixConfidence[] = {
146 	{ "rtf", 	UT_CONFIDENCE_PERFECT 	},
147 	{ "doc", 	UT_CONFIDENCE_SOSO 		},
148 	{ "", 	UT_CONFIDENCE_ZILCH 	}
149 };
150 
getSuffixConfidence()151 const IE_SuffixConfidence * IE_Imp_RTF_Sniffer::getSuffixConfidence ()
152 {
153 	return IE_Imp_RTF_Sniffer__SuffixConfidence;
154 }
155 
156 
157 // supported mimetypes
158 static IE_MimeConfidence IE_Imp_RTF_Sniffer__MimeConfidence[] = {
159 	{ IE_MIME_MATCH_FULL, 	IE_MIMETYPE_RTF, 		UT_CONFIDENCE_GOOD 	},
160 	{ IE_MIME_MATCH_FULL, 	"application/richtext",	UT_CONFIDENCE_GOOD 	},
161 	{ IE_MIME_MATCH_FULL, 	"text/richtext", 		UT_CONFIDENCE_GOOD 	},
162 	{ IE_MIME_MATCH_FULL, 	"text/rtf", 			UT_CONFIDENCE_GOOD 	},
163 	{ IE_MIME_MATCH_BOGUS, 	"", 					UT_CONFIDENCE_ZILCH }
164 };
165 
getMimeConfidence()166 const IE_MimeConfidence * IE_Imp_RTF_Sniffer::getMimeConfidence ()
167 {
168 	return IE_Imp_RTF_Sniffer__MimeConfidence;
169 }
170 
recognizeContents(const char * szBuf,UT_uint32 iNumbytes)171 UT_Confidence_t IE_Imp_RTF_Sniffer::recognizeContents(const char * szBuf,
172 													  UT_uint32 iNumbytes)
173 {
174 	if ( iNumbytes < 5 )
175 	{
176 		return(UT_CONFIDENCE_ZILCH);
177 	}
178 	if ( strncmp( szBuf, "{\\rtf", 5 ) == 0 )
179 	{
180 		return(UT_CONFIDENCE_PERFECT) ;
181 	}
182 	return(UT_CONFIDENCE_ZILCH);
183 }
184 
constructImporter(PD_Document * pDocument,IE_Imp ** ppie)185 UT_Error IE_Imp_RTF_Sniffer::constructImporter(PD_Document * pDocument,
186 											   IE_Imp ** ppie)
187 {
188 	IE_Imp_RTF * p = new IE_Imp_RTF(pDocument);
189 	*ppie = p;
190 	return UT_OK;
191 }
192 
getDlgLabels(const char ** pszDesc,const char ** pszSuffixList,IEFileType * ft)193 bool	IE_Imp_RTF_Sniffer::getDlgLabels(const char ** pszDesc,
194 										 const char ** pszSuffixList,
195 										 IEFileType * ft)
196 {
197 	*pszDesc = "Rich Text Format (.rtf)";
198 	*pszSuffixList = "*.rtf";
199 	*ft = getFileType();
200 	return true;
201 }
202 
203 //////////////////////////////////////////////////////////////////
204 // List class definitions
205 //////////////////////////////////////////////////////////////////
RTF_msword97_level(RTF_msword97_list * pmsword97List,UT_uint32 level)206 RTF_msword97_level::RTF_msword97_level(RTF_msword97_list * pmsword97List, UT_uint32 level)
207 	: m_pParaProps(NULL)
208 	, m_pCharProps(NULL)
209 	, m_pbParaProps(NULL)
210 	, m_pbCharProps(NULL)
211 
212 {
213 	m_levelStartAt = 1;
214 #if 0
215 	m_AbiLevelID = UT_rand();
216 	while(m_AbiLevelID < 10000)
217 		m_AbiLevelID = UT_rand();
218 #else
219 	//m_AbiLevelID = m_sLastAssignedLevelID++;
220 	UT_return_if_fail(pmsword97List);
221 	m_AbiLevelID = pmsword97List->m_pie_rtf->getDoc()->getUID(UT_UniqueId::List);
222 #endif
223 	m_pMSWord97_list = pmsword97List;
224 	m_localLevel = level;
225 	m_bStartNewList = false;
226 	m_listDelim = "%L";
227 	m_cLevelFollow = '\0';
228 	m_bRestart = true;
229 }
230 
231 // Static data members must be initialized at file scope.
232 //UT_uint32 RTF_msword97_level::m_sLastAssignedLevelID = 100000;
233 UT_uint32 RTF_msword97_level::m_sPreviousLevel =0;
234 
235 
~RTF_msword97_level(void)236 RTF_msword97_level::~RTF_msword97_level(void)
237 {
238 	DELETEP(m_pParaProps);
239 	DELETEP(m_pCharProps);
240 	DELETEP(m_pbParaProps);
241 	DELETEP(m_pbCharProps);
242 }
243 
buildAbiListProperties(const char ** szListID,const char ** szParentID,const char ** szLevel,const char ** szStartat,const char ** szFieldFont,const char ** szListDelim,const char ** szListDecimal,const char ** szAlign,const char ** szIndent,const char ** szListStyle)244 void RTF_msword97_level::buildAbiListProperties( const char ** szListID,
245 								 const char ** szParentID,
246 								 const char ** szLevel,
247 								 const char ** szStartat,
248 								 const char ** szFieldFont,
249 								 const char ** szListDelim,
250 								 const char ** szListDecimal,
251 								 const char ** szAlign,
252 								 const char ** szIndent,
253 								 const char ** szListStyle)
254 {
255 	static std::string buf;
256 	static std::string ListID, ParentID, Level, StartAt, FieldFont, ListDelim, ListDecimal,Align,Indent;
257 //
258 // Start with List ID.
259 //
260 //
261 // HACKALERT - this is ugly. We need to restart the list numbering if
262 //   - m_bRestart is set AND
263 //   - the previous list inserted into the document was a higher level.
264 //   I use a static member variable to determine what level list was
265 //   entered previously.
266 //   TODO: this assumes that the document is not structured like
267 //   1. Some level one text
268 //      a. Some level two text
269 //   2. Some more level one text
270 //          i. Some level three text
271 //      b. Some more level two text - note the label was not reset!!!
272 //
273 	if (m_bRestart && (m_sPreviousLevel < m_localLevel))
274 	{
275 		//m_AbiLevelID = m_sLastAssignedLevelID++;
276 		m_AbiLevelID = m_pMSWord97_list->m_pie_rtf->getDoc()->getUID(UT_UniqueId::List);
277 	}
278 	m_sPreviousLevel = m_localLevel;
279 	ListID = UT_std_string_sprintf("%d",m_AbiLevelID);
280 	*szListID = ListID.c_str();
281 //
282 // Now Parent ID.
283 //
284 	UT_uint32 iParentID = 0;
285 	// http://bugzilla.abisource.com/show_bug.cgi?id=12880
286 	// Check that m_pMSWord97_list is not NULL or kaboom. Assume this restart the list.
287 	if(m_localLevel> 0 && !m_bStartNewList && m_pMSWord97_list)
288 	{
289 		iParentID = m_pMSWord97_list->m_RTF_level[m_localLevel-1]->m_AbiLevelID;
290 	}
291 	ParentID = 	UT_std_string_sprintf("%d", iParentID);
292     *szParentID = ParentID.c_str();
293 //
294 // level
295 //
296     Level = UT_std_string_sprintf("%d",m_localLevel);
297     *szLevel = Level.c_str();
298 //
299 // Start At.
300 //
301     StartAt = UT_std_string_sprintf("%d",m_levelStartAt);
302     *szStartat = StartAt.c_str();
303 //
304 // List Style
305 //
306     FL_ListType abiListType;
307 	if(m_RTFListType == 0)
308     {
309         abiListType = NUMBERED_LIST;
310 	}
311 	else if( m_RTFListType == 1)
312 	{
313         abiListType = UPPERROMAN_LIST;
314 	}
315     else if(m_RTFListType == 2)
316 	{
317         abiListType = LOWERROMAN_LIST;
318 	}
319     else if( m_RTFListType == 3)
320 	{
321         abiListType = UPPERCASE_LIST;
322 	}
323 	else if (m_RTFListType == 4)
324 	{
325         abiListType = LOWERCASE_LIST;
326 	}
327     else if (m_RTFListType == 5)
328 	{
329         abiListType = UPPERCASE_LIST;
330 	}
331     else if (m_RTFListType == 23)
332 	{
333 		*szStartat = "1";
334         abiListType = BULLETED_LIST;
335 	}
336     else if (m_RTFListType == 23 + IMPLIES_LIST)
337 	{
338 		*szStartat = "1";
339         abiListType = IMPLIES_LIST;
340 	}
341 	else if (m_RTFListType == 45)
342 	{
343 		abiListType = HEBREW_LIST;
344 	}
345 	else
346 	{
347 		abiListType = NUMBERED_LIST;
348 	}
349 
350 
351 	fl_AutoLists al;
352     *szListStyle = al.getXmlList(abiListType);
353 //
354 // Field Font
355 //
356 	FieldFont = "NULL";
357 	if(m_pParaProps &&  m_pParaProps->m_pszFieldFont)
358 	{
359 		FieldFont = m_pParaProps->m_pszFieldFont;
360 	}
361 
362 	*szFieldFont = FieldFont.c_str();
363 
364 //
365 // List Delim
366 //
367     *szListDelim = m_listDelim.c_str();
368 //
369 // List Decimal
370 //
371 	*szListDecimal = ".";
372 //
373 // szAlign - left position of the paragraph
374 //
375 	if(m_pbParaProps && m_pbParaProps->bm_indentLeft)
376 	{
377 		Align = UT_convertInchesToDimensionString(DIM_IN, static_cast<double>(m_pParaProps->m_indentLeft)/1440);
378 	}
379 	else
380 	{
381 		Align = UT_convertInchesToDimensionString(DIM_IN, (static_cast<double>(m_localLevel))*0.5);
382 	}
383 	*szAlign = Align.c_str();
384 //
385 // szIndent - offset from the left position for the listlabel
386 //
387 	if(m_pbParaProps && m_pbParaProps->bm_indentLeft)
388 	{
389 		Indent = UT_convertInchesToDimensionString(DIM_IN, static_cast<double>(m_pParaProps->m_indentFirst)/1440);
390 	}
391 	else
392 	{
393 		Indent = "-0.3in";
394 	}
395 	*szIndent = Indent.c_str();
396 }
397 
398 /*!
399   Parse the leveltext and levelnumbers values.
400   The idea is to translate the strings into AbiWord compatible format.
401 
402   From the RTF standard: "... a level three number such as '1.a.(i)' would
403   generate the following RTF: '{\leveltext \'07\'00.\'01.(\'02)'}' where \'07
404   is the string length, the \'00 \'01 and \'02 are level place holders, and the
405   rest is surrounding text. The corresponding levelnumbers would be
406   {\levelnumbers \'01\'03\'06} because the level place holders have indices
407   1,3,6.
408 
409   In AbiWord, either this level resuses the parent label and adds on more text, or
410   starts a new label. So we can only get 1.a.(i) if the parent label is 1.a. or 1.a
411 
412   \todo look up the parent label and be more precise about what is added by this label.
413  */
ParseLevelText(const std::string & szLevelText,const std::string &,UT_uint32 iLevel)414 bool RTF_msword97_level::ParseLevelText(const std::string & szLevelText,const std::string & /*szLevelNumbers*/, UT_uint32 iLevel)
415 {
416 	//read the text string into a int array, set the place holders to
417 	//values less than zero.
418 	UT_sint32 iLevelText[1000];
419 	char const * pText = szLevelText.c_str();
420 	UT_sint32 ilength = 0;
421 	UT_sint32 icurrent = 0;
422 	UT_sint32 istrlen = szLevelText.size();
423 	bool bIsUnicode;
424 	while (pText[0] != '\0' && icurrent < 1000)
425 	{
426 		bIsUnicode = ((pText[0] == '\\') && (pText[1] == '\'') && UT_UCS4_isdigit(pText[2]) && UT_UCS4_isdigit(pText[3]));
427 		// A broken exporter writes some junk at the beginning of the string.
428 		// Look for the first \'nn string
429 		if ((bIsUnicode) && (ilength == 0))
430 		{
431 			ilength = 10*(pText[2] - '0') + (pText[3] - '0');
432 			pText += 3;
433 		}
434 		else if (ilength >0)
435 		{
436 			// I have read the string length, I can read off the values.
437 			if (bIsUnicode)
438 			{
439 				iLevelText[icurrent++] = -10*(pText[2] - '0') - (pText[3] - '0');
440 				pText += 3;
441 			}
442 			else
443 			{
444 				iLevelText[icurrent++] = pText[0];
445 			}
446 		}
447 		// sanity check
448 		if (istrlen <= pText - szLevelText.c_str())
449 		{
450 			UT_DEBUGMSG(("RTF: parsed past the end of leveltext string %s\n",szLevelText.c_str()));
451 			return false;
452 		}
453 		pText++;
454 	}
455 	if(ilength != icurrent)
456 	{
457 		ilength = icurrent;
458 	}
459 	// Find the occurance of a previous level place holder
460 	for (icurrent = ilength-1; icurrent>=0; icurrent--)
461 	{
462 		if(-iLevelText[icurrent] >= 0 && (-iLevelText[icurrent] < static_cast<UT_sint32>(iLevel)))
463 		{
464 			break;
465 		}
466 	}
467 	if (icurrent < 0)
468 	{
469 		// No previous level place holder
470 		UT_DEBUGMSG(("RTF Import: No previous level - restart list \n"));
471 		m_bStartNewList = true;
472 	}
473 	else
474 	{
475 		//TODO - find the end of the previous level place holder label
476 	}
477 	// Stuff the rest of the string in JUST this level in listDelim
478 
479 	m_listDelim = "";
480 	bool bFound = false;
481 	for (icurrent++; icurrent < ilength; icurrent++)
482 	{
483 		if (iLevelText[icurrent]<=0 && !bFound)
484 		{
485 
486 #if 0
487 // Matti's code
488 			m_listDelim += "%L";
489 			UT_return_val_if_fail(-iLevelText[icurrent] == static_cast<UT_sint32>(iLevel), false);
490 #endif
491 			if(-iLevelText[icurrent] == static_cast<UT_sint32>(iLevel))
492 			{
493 				m_listDelim += "%L";
494 				bFound = true;
495 				continue;
496 			}
497 		}
498 		else if ( bFound && (iLevelText[icurrent] >= 0))
499 		{
500 			m_listDelim += static_cast<char>(iLevelText[icurrent]);
501 		}
502 		else if(bFound && iLevelText[icurrent] < 0)
503 		{
504 			break;
505 		}
506 	}
507 	return true;
508 }
509 
510 ///////////////////////////////
511 // Paste Table class
512 ///////////////////////////////
ABI_Paste_Table(void)513 ABI_Paste_Table::ABI_Paste_Table(void):
514 	m_bHasPastedTableStrux(false),
515 	m_bHasPastedCellStrux(false),
516 	m_iRowNumberAtPaste(0),
517 	m_bHasPastedBlockStrux(false),
518 	m_iMaxRightCell(0),
519 	m_iCurRightCell(0),
520 	m_iCurTopCell(0),
521 	m_bPasteAfterRow(false),
522 	m_iPrevPasteTop(0),
523 	m_iNumRows(1)
524 {
525 }
526 
~ABI_Paste_Table(void)527 ABI_Paste_Table::~ABI_Paste_Table(void)
528 {
529 }
530 
ABI_RTF_Annotation(void)531 ABI_RTF_Annotation::ABI_RTF_Annotation(void):
532 	m_iAnnNumber(0),
533 	m_sAuthor(""),
534 	m_sDate(""),
535 	m_sTitle(""),
536 	m_pInsertFrag(NULL),
537 	m_Annpos(0),
538 	m_iRTFLevel(0)
539 {
540 }
541 
542 /////////////////////////////////////////////////////////////////////////////////////////
543 
RTF_msword97_list(IE_Imp_RTF * pie_rtf)544 RTF_msword97_list::RTF_msword97_list(IE_Imp_RTF * pie_rtf)
545 {
546 	m_RTF_listID = 0;
547 	m_RTF_listTemplateID = 0;
548 	m_pie_rtf = pie_rtf;
549 	for(UT_uint32 i=0; i< 9 ; i++)
550 	{
551 		m_RTF_level[i] = new RTF_msword97_level(this,i);
552 	}
553 }
554 
~RTF_msword97_list(void)555 RTF_msword97_list::~RTF_msword97_list(void)
556 {
557 	m_RTF_listID = 0;
558 	m_RTF_listTemplateID = 0;
559 	for(UT_uint32 i=0; i< 9 ; i++)
560 	{
561 		delete m_RTF_level[i];
562 	}
563 }
564 
565 //////////////////////////////////////////////////////////////////////////////////////////
566 
RTF_msword97_listOverride(IE_Imp_RTF * pie_rtf)567 RTF_msword97_listOverride::RTF_msword97_listOverride(IE_Imp_RTF * pie_rtf )
568 {
569 	// Ideally, the default ID should be 0 which is a reserved ID in
570 	// the spec, but OpenOffice uses it, so use -1 instead (which
571 	// should be OK: spec sez 1-2000 is valid).
572 	m_RTF_listID = (UT_uint32)-1;
573 
574 	m_OverrideCount = 0;
575 	m_pParaProps = NULL;
576 	m_pCharProps = NULL;
577 	m_pbParaProps = NULL;
578 	m_pbCharProps = NULL;
579 	m_pie_rtf = pie_rtf;
580 	m_pList = NULL;
581 }
582 
~RTF_msword97_listOverride(void)583 RTF_msword97_listOverride::~RTF_msword97_listOverride(void)
584 {
585 	DELETEP(m_pParaProps);
586 	DELETEP(m_pCharProps);
587 	DELETEP(m_pbParaProps);
588 	DELETEP(m_pbCharProps);
589 }
590 
591 /*!
592  * This function sets the pointer to the list structure for this override.
593  * It just scans the defined lists and looks for a matching Identifier.
594  */
setList(void)595 bool RTF_msword97_listOverride::setList(void)
596 {
597 	UT_sint32 count = m_pie_rtf->get_vecWord97ListsCount();
598 	UT_sint32 i = 0;
599 	for(i=0; i< count; i++)
600 	{
601 		RTF_msword97_list * pList = m_pie_rtf->get_vecWord97NthList(i);
602 		if(pList->m_RTF_listID == m_RTF_listID)
603 		{
604 			m_pList = pList;
605 			return true;
606 		}
607 	}
608 	return false;
609 }
610 /*!
611  * This returns returns a pointer to the tabstop vector defined in the list level.
612  */
getTabStopVect(UT_uint32 iLevel)613 std::vector<UT_sint32>* RTF_msword97_listOverride::getTabStopVect(UT_uint32 iLevel)
614 {
615 	RTF_msword97_level * pLevel = m_pList->m_RTF_level[iLevel];
616 	return &(pLevel->m_pParaProps->m_tabStops);
617 }
618 /*!
619  * This returns returns a pointer to the tab Type vector defined in the list level.
620  */
getTabTypeVect(UT_uint32 iLevel)621 std::vector<eTabType>* RTF_msword97_listOverride::getTabTypeVect(UT_uint32 iLevel)
622 {
623 	RTF_msword97_level * pLevel = m_pList->m_RTF_level[iLevel];
624 	return &(pLevel->m_pParaProps->m_tabTypes);
625 }
626 /*!
627  * This returns returns a pointer to the tab Leadervector defined in the list level.
628  */
getTabLeaderVect(UT_uint32 iLevel)629 std::vector<eTabLeader>* RTF_msword97_listOverride::getTabLeaderVect(UT_uint32 iLevel)
630 {
631 	RTF_msword97_level * pLevel = m_pList->m_RTF_level[iLevel];
632 	return &(pLevel->m_pParaProps->m_tabLeader);
633 }
634 /*!
635  * This function returns true is there is a tab defined in the list definition.
636  */
isTab(UT_uint32 iLevel)637 bool RTF_msword97_listOverride::isTab(UT_uint32 iLevel)
638 {
639 	RTF_msword97_level * pLevel = m_pList->m_RTF_level[iLevel];
640 	UT_return_val_if_fail(pLevel && pLevel->m_pbParaProps, false);
641 	return (pLevel->m_pbParaProps->bm_tabStops);
642 }
643 /*!
644  * This function returns true if deleted is changed in the list definition.
645  */
isDeletedChanged(UT_uint32 iLevel)646 bool RTF_msword97_listOverride::isDeletedChanged(UT_uint32 iLevel)
647 {
648 	RTF_msword97_level * pLevel = m_pList->m_RTF_level[iLevel];
649 	return (pLevel->m_pbCharProps->bm_deleted);
650 }
651 /*!
652  * This function returns the Deleted state in the list definition
653  */
getDeleted(UT_uint32 iLevel)654 bool RTF_msword97_listOverride::getDeleted(UT_uint32 iLevel)
655 {
656 	RTF_msword97_level * pLevel = m_pList->m_RTF_level[iLevel];
657 	return (pLevel->m_pCharProps->m_deleted);
658 }
659 /*!
660  * This function returns true if Bold is changed in the list definition.
661  */
isBoldChanged(UT_uint32 iLevel)662 bool RTF_msword97_listOverride::isBoldChanged(UT_uint32 iLevel)
663 {
664 	RTF_msword97_level * pLevel = m_pList->m_RTF_level[iLevel];
665 	UT_return_val_if_fail(pLevel && pLevel->m_pbCharProps, false);
666 	return (pLevel->m_pbCharProps->bm_bold);
667 }
668 /*!
669  * This function the bold state in the List definition.
670  */
getBold(UT_uint32 iLevel)671 bool RTF_msword97_listOverride::getBold(UT_uint32 iLevel)
672 {
673 	RTF_msword97_level * pLevel = m_pList->m_RTF_level[iLevel];
674 	return (pLevel->m_pCharProps->m_bold);
675 }
676 /*!
677  * This function returns true if Italic is changed in the list definition.
678  */
isItalicChanged(UT_uint32 iLevel)679 bool RTF_msword97_listOverride::isItalicChanged(UT_uint32 iLevel)
680 {
681 	RTF_msword97_level * pLevel = m_pList->m_RTF_level[iLevel];
682 	UT_return_val_if_fail(pLevel && pLevel->m_pbCharProps, false);
683 	return (pLevel->m_pbCharProps->bm_italic);
684 }
685 /*!
686  * This function returns the Italic state in the list definition.
687  */
getItalic(UT_uint32 iLevel)688 bool RTF_msword97_listOverride::getItalic(UT_uint32 iLevel)
689 {
690 	RTF_msword97_level * pLevel = m_pList->m_RTF_level[iLevel];
691 	return (pLevel->m_pCharProps->m_italic);
692 }
693 /*!
694  * This function returns true if Underline is changed in the list definition.
695  */
isUnderlineChanged(UT_uint32 iLevel)696 bool RTF_msword97_listOverride::isUnderlineChanged(UT_uint32 iLevel)
697 {
698 	RTF_msword97_level * pLevel = m_pList->m_RTF_level[iLevel];
699 	UT_return_val_if_fail(pLevel && pLevel->m_pbCharProps, false);
700 	return (pLevel->m_pbCharProps->bm_underline);
701 }
702 /*!
703  * This function returns the Underline state in the list definition.
704  */
getUnderline(UT_uint32 iLevel)705 bool RTF_msword97_listOverride::getUnderline(UT_uint32 iLevel)
706 {
707 
708 	RTF_msword97_level * pLevel = m_pList->m_RTF_level[iLevel];
709 	return (pLevel->m_pCharProps->m_underline);
710 }
711 /*!
712  * This function returns true if Strikeout is changed in the list definition.
713  */
isStrikeoutChanged(UT_uint32 iLevel)714 bool RTF_msword97_listOverride::isStrikeoutChanged(UT_uint32 iLevel)
715 {
716 	RTF_msword97_level * pLevel = m_pList->m_RTF_level[iLevel];
717 	UT_return_val_if_fail(pLevel && pLevel->m_pbCharProps, false);
718 	return (pLevel->m_pbCharProps->bm_strikeout);
719 }
720 /*!
721  * This function returns the Strikeout state in the list definition.
722  */
getStrikeout(UT_uint32 iLevel)723 bool RTF_msword97_listOverride::getStrikeout(UT_uint32 iLevel)
724 {
725 	RTF_msword97_level * pLevel = m_pList->m_RTF_level[iLevel];
726 	return (pLevel->m_pCharProps->m_strikeout);
727 }
728 /*!
729  * This function returns true if Superscript is changed in the list definition.
730  */
isSuperscriptChanged(UT_uint32 iLevel)731 bool RTF_msword97_listOverride::isSuperscriptChanged(UT_uint32 iLevel)
732 {
733 	RTF_msword97_level * pLevel = m_pList->m_RTF_level[iLevel];
734 	UT_return_val_if_fail(pLevel && pLevel->m_pbCharProps, false);
735 	return (pLevel->m_pbCharProps->bm_superscript);
736 }
737 /*!
738  * This function returns the Superscript state in the list definition.
739  */
getSuperscript(UT_uint32 iLevel)740 bool RTF_msword97_listOverride::getSuperscript(UT_uint32 iLevel)
741 {
742 	RTF_msword97_level * pLevel = m_pList->m_RTF_level[iLevel];
743 	return (pLevel->m_pCharProps->m_superscript);
744 }
745 /*!
746  * This function returns true if Superscript Position is changed in the list
747  * definition.
748  */
isSuperscriptPosChanged(UT_uint32 iLevel)749 bool RTF_msword97_listOverride::isSuperscriptPosChanged(UT_uint32 iLevel)
750 {
751 	RTF_msword97_level * pLevel = m_pList->m_RTF_level[iLevel];
752 	return (pLevel->m_pbCharProps->bm_superscript_pos);
753 }
754 /*!
755  * This function returns the Superscript Position in the list definition.
756  */
getSuperscriptPos(UT_uint32 iLevel)757 double RTF_msword97_listOverride::getSuperscriptPos(UT_uint32 iLevel)
758 {
759 	RTF_msword97_level * pLevel = m_pList->m_RTF_level[iLevel];
760 	return (pLevel->m_pCharProps->m_superscript_pos);
761 }
762 /*!
763  * This function returns true if Subscript is changed in the list definition.
764  */
isSubscriptChanged(UT_uint32 iLevel)765 bool RTF_msword97_listOverride::isSubscriptChanged(UT_uint32 iLevel)
766 {
767 	RTF_msword97_level * pLevel = m_pList->m_RTF_level[iLevel];
768 	UT_return_val_if_fail(pLevel && pLevel->m_pbCharProps, false);
769 	return (pLevel->m_pbCharProps->bm_subscript);
770 }
771 /*!
772  * This function returns the Subscript state in the list definition.
773  */
getSubscript(UT_uint32 iLevel)774 bool RTF_msword97_listOverride::getSubscript(UT_uint32 iLevel)
775 {
776 	RTF_msword97_level * pLevel = m_pList->m_RTF_level[iLevel];
777 	return (pLevel->m_pCharProps->m_subscript);
778 }
779 /*!
780  * This function returns the Subscript state in the list definition.
781  */
isSubscriptPosChanged(UT_uint32 iLevel)782 bool RTF_msword97_listOverride::isSubscriptPosChanged(UT_uint32 iLevel)
783 {
784 	RTF_msword97_level * pLevel = m_pList->m_RTF_level[iLevel];
785 	return (pLevel->m_pbCharProps->bm_subscript_pos);
786 }
787 /*!
788  * This function returns the Subscript state in the list definition.
789  */
getSubscriptPos(UT_uint32 iLevel)790 double RTF_msword97_listOverride::getSubscriptPos(UT_uint32 iLevel)
791 {
792 	RTF_msword97_level * pLevel = m_pList->m_RTF_level[iLevel];
793 	return (pLevel->m_pCharProps->m_subscript_pos);
794 }
795 /*!
796  * This function returns true if Fontsize is changed in the list definition.
797  */
isFontSizeChanged(UT_uint32 iLevel)798 bool RTF_msword97_listOverride::isFontSizeChanged(UT_uint32 iLevel)
799 {
800 	RTF_msword97_level * pLevel = m_pList->m_RTF_level[iLevel];
801 	UT_return_val_if_fail(pLevel && pLevel->m_pbCharProps, false);
802 	return (pLevel->m_pbCharProps->bm_fontSize);
803 }
804 /*!
805  * This function returns the Fontsize in the list definition.
806  */
getFontSize(UT_uint32 iLevel)807 double RTF_msword97_listOverride::getFontSize(UT_uint32 iLevel)
808 {
809 	RTF_msword97_level * pLevel = m_pList->m_RTF_level[iLevel];
810 	return (pLevel->m_pCharProps->m_fontSize);
811 }
812 /*!
813  * This function returns true if the Hascolor state has changed.
814  */
isHasColourChanged(UT_uint32 iLevel)815 bool RTF_msword97_listOverride::isHasColourChanged(UT_uint32 iLevel)
816 {
817 	RTF_msword97_level * pLevel = m_pList->m_RTF_level[iLevel];
818 	UT_return_val_if_fail(pLevel && pLevel->m_pbCharProps, false);
819 	return (pLevel->m_pbCharProps->bm_hasColour);
820 }
821 /*!
822  * This function returns the Hascolor state in the list definition.
823  */
getHasColour(UT_uint32 iLevel)824 bool RTF_msword97_listOverride::getHasColour(UT_uint32 iLevel)
825 {
826 	RTF_msword97_level * pLevel = m_pList->m_RTF_level[iLevel];
827 	return (pLevel->m_pCharProps->m_hasColour);
828 }
829 /*!
830  * This function returns true if ColourNumber is changed in the list definition.
831  */
isColourNumberChanged(UT_uint32 iLevel)832 bool RTF_msword97_listOverride::isColourNumberChanged(UT_uint32 iLevel)
833 {
834 	RTF_msword97_level * pLevel = m_pList->m_RTF_level[iLevel];
835 	UT_return_val_if_fail(pLevel && pLevel->m_pbCharProps, false);
836 	return (pLevel->m_pbCharProps->bm_colourNumber);
837 }
838 /*!
839  * This function returns the ColourNumber in the list definition.
840  */
getColourNumber(UT_uint32 iLevel)841 UT_uint32 RTF_msword97_listOverride::getColourNumber(UT_uint32 iLevel)
842 {
843 	RTF_msword97_level * pLevel = m_pList->m_RTF_level[iLevel];
844 	return (pLevel->m_pCharProps->m_colourNumber);
845 }
846 /*!
847  * This function returns true if HasBgcolour is changed in the list definition.
848  */
isHasBgColourChanged(UT_uint32 iLevel)849 bool RTF_msword97_listOverride::isHasBgColourChanged(UT_uint32 iLevel)
850 {
851 	RTF_msword97_level * pLevel = m_pList->m_RTF_level[iLevel];
852 	UT_return_val_if_fail(pLevel && pLevel->m_pbCharProps, false);
853 	return (pLevel->m_pbCharProps->bm_hasBgColour);
854 }
855 /*!
856  * This function returns the HasBgcolour state in the list definition.
857  */
getHasBgColour(UT_uint32 iLevel)858 bool RTF_msword97_listOverride::getHasBgColour(UT_uint32 iLevel)
859 {
860 	RTF_msword97_level * pLevel = m_pList->m_RTF_level[iLevel];
861 	return (pLevel->m_pCharProps->m_hasBgColour);
862 }
863 /*!
864  * This function returns true if BgColourNumber is changed in the list definition.
865  */
isBgColourNumberChanged(UT_uint32 iLevel)866 bool RTF_msword97_listOverride::isBgColourNumberChanged(UT_uint32 iLevel)
867 {
868 	RTF_msword97_level * pLevel = m_pList->m_RTF_level[iLevel];
869 	UT_return_val_if_fail(pLevel && pLevel->m_pbCharProps, false);
870 	return (pLevel->m_pbCharProps->bm_bgcolourNumber);
871 }
872 /*!
873  * This function returns the BgColourNumber  in the list definition.
874  */
getBgColourNumber(UT_uint32 iLevel)875 UT_uint32 RTF_msword97_listOverride::getBgColourNumber(UT_uint32 iLevel)
876 {
877 	RTF_msword97_level * pLevel = m_pList->m_RTF_level[iLevel];
878 	return (pLevel->m_pCharProps->m_bgcolourNumber);
879 }
880 /*!
881  * This function returns true if FontNumber is changed in the list definition.
882  */
isFontNumberChanged(UT_uint32 iLevel)883 bool RTF_msword97_listOverride::isFontNumberChanged(UT_uint32 iLevel)
884 {
885 	RTF_msword97_level * pLevel = m_pList->m_RTF_level[iLevel];
886 	UT_return_val_if_fail(pLevel && pLevel->m_pbCharProps, false);
887 	return (pLevel->m_pbCharProps->bm_fontNumber);
888 }
889 /*!
890  * This function returns the FontNumber if changed in the list definition.
891  */
getFontNumber(UT_uint32 iLevel)892 UT_uint32 RTF_msword97_listOverride::getFontNumber(UT_uint32 iLevel)
893 {
894 	RTF_msword97_level * pLevel = m_pList->m_RTF_level[iLevel];
895 	return (pLevel->m_pCharProps->m_fontNumber);
896 }
897 
898 
899 /*!
900  * This method returns all the stuff Abi needs to reconstruct a list
901  */
buildAbiListProperties(const char ** szListID,const char ** szParentID,const char ** szLevel,const char ** szStartat,const char ** szFieldFont,const char ** szListDelim,const char ** szListDecimal,const char ** szAlign,const char ** szIndent,const char ** szListStyle,UT_uint32 iLevel)902 void RTF_msword97_listOverride::buildAbiListProperties( const char ** szListID,
903 								 const char ** szParentID,
904 								 const char ** szLevel,
905 								 const char ** szStartat,
906 								 const char ** szFieldFont,
907 								 const char ** szListDelim,
908 								 const char ** szListDecimal,
909 								 const char ** szAlign,
910 								 const char ** szIndent,
911 								 const char ** szListStyle,
912 								 UT_uint32 iLevel)
913 {
914 	m_pList->m_RTF_level[iLevel]->buildAbiListProperties(szListID, szParentID, szLevel, szStartat, szFieldFont,
915 									 szListDelim, szListDecimal, szAlign, szIndent, szListStyle);
916 
917 }
918 
919 // constructor class to tell if a character property has been defined in a list structure.
RTFProps_bCharProps(void)920 RTFProps_bCharProps::RTFProps_bCharProps(void):
921 	bm_deleted(false),
922 	bm_bold(false),
923 	bm_italic(false),
924 	bm_underline(false),
925 	bm_overline(false),
926 	bm_strikeout(false),
927 	bm_topline(false),
928 	bm_botline(false),
929 	bm_superscript(false),
930 	bm_superscript_pos(false),
931 	bm_subscript(false),
932 	bm_subscript_pos(false),
933 	bm_fontSize(false),
934 	bm_fontNumber(false),
935 	bm_hasColour(false),
936 	bm_colourNumber(false),
937 	bm_hasBgColour(false),
938 	bm_bgcolourNumber(false),
939 	bm_listTag(false),
940 	bm_RTL(false),
941 	bm_dirOverride(false)
942 {
943 }
944 
~RTFProps_bCharProps(void)945 RTFProps_bCharProps::~RTFProps_bCharProps(void)
946 {
947 }
948 
949 // These are set true if changed in list definitions.
RTFProps_bParaProps(void)950 RTFProps_bParaProps::RTFProps_bParaProps(void):
951     bm_justification(false),
952 	bm_spaceBefore(false),
953 	bm_spaceAfter(false),
954 	bm_indentLeft(false),
955 	bm_indentRight(false),
956 	bm_indentFirst(false),
957 	bm_lineSpaceVal(false),
958 	bm_lineSpaceExact(false),
959 	bm_tabStops(false),
960 	bm_tabTypes(false),
961 	bm_tabLeader(false),
962 	bm_curTabType(false),
963 	bm_curTabLeader(false),
964 	bm_rtfListTable(false),
965 	bm_dom_dir(false)
966 {
967 }
968 
~RTFProps_bParaProps(void)969 RTFProps_bParaProps::~RTFProps_bParaProps(void)
970 {
971 }
972 
973 //////////////////////////////////////////////////////////////////////////
974 // End List definitions
975 //////////////////////////////////////////////////////////////////////////
976 
977 
978 
979 // Font table items
RTFFontTableItem(FontFamilyEnum fontFamily,int charSet,int codepage,FontPitch pitch,const char * panose,const char * pFontName,const char * pAlternativeFontName)980 RTFFontTableItem::RTFFontTableItem(FontFamilyEnum fontFamily, int charSet,
981                                    int codepage, FontPitch pitch,
982                                    const char* panose, const char*
983                                    pFontName, const char* pAlternativeFontName)
984 {
985 	m_family = fontFamily;
986 	m_charSet = charSet;
987 	m_codepage = codepage;
988 	m_szEncoding = 0;
989 	m_pitch = pitch;
990 	if (panose)
991 		memcpy(m_panose, panose, 10*sizeof(unsigned char));
992 	// TODO KAY: If we run out of memory then m_pFontName and m_pAlternativeFontName,
993 	// get left as NULL. Could we throw an exception from here?
994 	m_pFontName = g_strdup(pFontName);
995 	m_pAlternativeFontName = g_strdup(pAlternativeFontName);
996 
997 	// Set charset/codepage converter
998 	if (m_codepage && m_charSet)
999 	{
1000 		UT_DEBUGMSG(("RTF Font has codepage *and* charset\n"));
1001 		UT_ASSERT_NOT_REACHED();
1002 	}
1003 	else if (m_codepage)
1004 	{
1005 		// These are the valid values from the documentation:
1006 		// TODO Many are not supported by iconv
1007 		switch (m_codepage)
1008 		{
1009 			// 708	Arabic (ASMO 708)
1010 		case 708:
1011 			m_szEncoding = "ASMO-708";	// ISO-8859-6
1012 			break;
1013 			// 709	Arabic (ASMO 449+, BCON V4)
1014 			// 710	Arabic (Transparent Arabic)
1015 			// 711	Arabic (Nafitha Enhanced)
1016 			// 720	Arabic (Transparent ASMO)
1017 			// 819	Windows 3.1 (United States & Western Europe)
1018 		case 819:
1019 			m_szEncoding = "CP819";	// ISO-8859-1
1020 			break;
1021 
1022 			// 437: IBM
1023 		case 437:
1024 			m_szEncoding = "CP437";
1025 			break;
1026 
1027 			// 850	IBM Multilingual
1028 		case 850:
1029 			m_szEncoding = "CP850";
1030 			break;
1031 			// 852	Eastern European
1032 			// 860	Portuguese
1033 			// 862	Hebrew
1034 			// 863	French Canadian
1035 			// 864	Arabic
1036 			// 865	Norwegian
1037 			// 866	Soviet Union
1038 		case 866:
1039 			m_szEncoding = "CP866";
1040 			break;
1041 			// 932	Japanese
1042 		case 932:
1043 			m_szEncoding = "CP932";
1044 			break;
1045 			// 936  Chinese: Simplified
1046 		case 936:
1047 			CPNAME_OR_FALLBACK(m_szEncoding,"CP936","GBK");
1048 			break;
1049 			// 950  Chinese: Traditional
1050 		case 950:
1051 			CPNAME_OR_FALLBACK(m_szEncoding,"CP950","BIG5");
1052 			break;
1053 			// 1250	Windows 3.1 (Eastern European)
1054 		case 1250:
1055 			m_szEncoding = "CP1250";	// MS-EE
1056 			break;
1057 			// 1251	Windows 3.1 (Soviet Union)
1058 		case 1251:
1059 			m_szEncoding = "CP1251";	// MS-CYRL
1060 			break;
1061 
1062 			// These were produced by MS WordPad 5.0 on Win2K
1063 			// TODO What do we do with negative values?
1064 			// -8534 - Devanagari	(57002)
1065 			// -8533 - Bengali		(57003)
1066 			// -8532 - Tamil		(57004)
1067 			// -8531 - Telugu		(57005)
1068 			// -8530 - Assamese		(57006)
1069 			// -8529 - Oriya		(57007)
1070 			// -8528 - Kannada		(57008)
1071 			// -8527 - Malayalam	(57009)
1072 			// -8526 - Gujarathi	(57010)
1073 			// -8525 - Panjabi		(57011)
1074 			// -7536 - Georgian		(58000)
1075 			// -7535 - Armenian		(58001)
1076 		default:
1077 			m_szEncoding = XAP_EncodingManager::get_instance()->charsetFromCodepage(m_codepage);
1078 		}
1079 	}
1080 	else if (m_charSet != -1)  // -1 indicated "not defined".
1081 	{
1082 		switch (m_charSet)
1083 		{
1084 			case 0:		// ANSI_CHARSET
1085 				m_szEncoding = "CP1252";	// MS-ANSI
1086 				break;
1087 			case 2:		// SYMBOL_CHARSET
1088 				m_szEncoding = NULL;	// MS-ANSI
1089 				UT_DEBUGMSG(("RTF Font charset 'Symbol' worked around \n"));
1090 				break;
1091 			case 77:    // Source Vlad Harchev from OpenOffice
1092 				m_szEncoding = "MACINTOSH";
1093 				break;
1094 			case 78:    // fjf: some kind of Japanese, let's guess:
1095 				m_szEncoding = "SJIS";
1096 				break;
1097 			case 102:    // fjf: some kind of Chinese, let's guess:
1098 				CPNAME_OR_FALLBACK(m_szEncoding,"CP936","GBK");
1099 				break;
1100 			case 128:	// SHIFTJIS_CHARSET
1101 				m_szEncoding = "CP932";
1102 				break;
1103 			case 129:	// Hangul - undocumented?
1104 				m_szEncoding = "CP949";
1105 				break;
1106 			case 130:   // Source Vlad Harchev from OpenOffice
1107 				m_szEncoding = "CP1361";
1108 				break;
1109 			case 134:	// Chinese GB - undocumented?
1110 				CPNAME_OR_FALLBACK(m_szEncoding,"CP936","GBK");
1111 				break;
1112 			case 136:	// Chinese BIG5 - undocumented?
1113 				CPNAME_OR_FALLBACK(m_szEncoding,"CP950","BIG5");
1114 				break;
1115 			case 161:	// GREEK_CHARSET
1116 				m_szEncoding = "CP1253";	// MS-GREEK
1117 				break;
1118 			case 162:	// TURKISH_CHARSET
1119 				m_szEncoding = "CP1254";	// MS-TURK
1120 				break;
1121 			case 163:	// Vietnamese - undocumented?
1122 				m_szEncoding = "CP1258";
1123 				break;
1124 			// TODO What is different?  Iconv only supports one MS Hebrew codepage.
1125 			case 181:	// HEBREWUSER_CHARSET
1126 				UT_DEBUGMSG(("RTF Font charset 'HEBREWUSER'??\n"));
1127 				// fall through (for now)
1128 			case 177:	// HEBREW_CHARSET
1129 				m_szEncoding = "CP1255";	// MS-HEBR
1130 				break;
1131 			// TODO What is different?  Iconv only supports one MS Arabic codepage.
1132 			case 178:	// ARABICSIMPLIFIED_CHARSET
1133 				UT_DEBUGMSG(("RTF Font charset 'ARABICSIMPLIFIED'??\n"));
1134 				m_szEncoding = "CP1256";	// MS-ARAB
1135 				break;
1136 			case 179:	// ARABICTRADITIONAL_CHARSET
1137 				UT_DEBUGMSG(("RTF Font charset 'ARABICTRADITIONAL'??\n"));
1138 				m_szEncoding = "CP1256";	// MS-ARAB
1139 				break;
1140 			case 180:	// ARABICUSER_CHARSET
1141 				UT_DEBUGMSG(("RTF Font charset 'ARABICUSER'??\n"));
1142 				m_szEncoding = "CP1256";	// MS-ARAB
1143 				break;
1144 			case 186:	// Baltic - undocumented?
1145 				m_szEncoding = "CP1257";
1146 				break;
1147 			case 204:	// CYRILLIC_CHARSET
1148 				m_szEncoding = "CP1251";	// MS-CYRL
1149 				break;
1150 			case 222:	// Thai - undocumented?
1151 				m_szEncoding = "CP874";
1152 				break;
1153 			case 238:	// EASTERNEUROPE_CHARSET
1154 				m_szEncoding = "CP1250";	// MS-EE
1155 				break;
1156 			case 254:	// PC437_CHARSET
1157 				m_szEncoding = "CP437";
1158 				break;
1159 			case 255:	// OEM_CHARSET
1160 				// TODO Can iconv do this?
1161 				UT_DEBUGMSG(("RTF Font charset 'OEM'??\n"));
1162 				UT_ASSERT_HARMLESS(UT_NOT_IMPLEMENTED);
1163 				break;
1164 			default:
1165 				UT_DEBUGMSG(("RTF Font charset unknown: %d\n", m_charSet));
1166 				// don't assert like we used to do. just silently ignore.
1167 		}
1168 	}
1169 }
1170 
~RTFFontTableItem()1171 RTFFontTableItem::~RTFFontTableItem()
1172 {
1173 	g_free(m_pFontName);
1174 	g_free(m_pAlternativeFontName);
1175 }
1176 
1177 // Character properties
RTFProps_CharProps(void)1178 RTFProps_CharProps::RTFProps_CharProps(void)
1179 {
1180 	m_deleted = false;
1181 	m_bold = false;
1182 	m_italic = false;
1183 	m_underline = false;
1184 	m_overline = false;
1185 	m_topline = false;
1186 	m_botline = false;
1187 	m_strikeout = false;
1188 	m_superscript = false;
1189 	m_superscript_pos = 0.0;
1190 	m_subscript = false;
1191 	m_subscript_pos = 0.0;
1192 	m_fontSize = 12.0;
1193 	m_fontNumber = 0;
1194 	m_hasColour = false;
1195 	m_colourNumber = 0;
1196 	m_hasBgColour = false;
1197 	m_bgcolourNumber = 0;
1198 	m_styleNumber = -1;
1199 	m_listTag = 0;
1200 	m_szLang = 0;
1201 	m_dir = UT_BIDI_UNSET;
1202 	m_dirOverride = UT_BIDI_UNSET;
1203 	m_Hidden = false;
1204 	m_eRevision = PP_REVISION_NONE;
1205 	m_iCurrentRevisionId = 0;
1206 }
1207 
~RTFProps_CharProps(void)1208 RTFProps_CharProps::~RTFProps_CharProps(void)
1209 {
1210 }
1211 
1212 // Paragraph properties
RTFProps_ParaProps(void)1213 RTFProps_ParaProps::RTFProps_ParaProps(void)
1214 {
1215 	m_justification = pjLeft;
1216 	m_spaceBefore = 0;
1217 	m_spaceAfter = 0;
1218 	m_indentLeft = 0;
1219 	m_indentRight = 0;
1220 	m_indentFirst = 0;
1221 	m_lineSpaceExact = false;
1222 	m_lineSpaceVal = 240;
1223 	m_isList = false;
1224 	m_level = 0;
1225 	memset(&m_pszStyle, 0, sizeof(m_pszStyle));
1226 	m_rawID = 0;
1227 	m_rawParentID = 0;
1228 	memset(m_pszListDecimal,0,sizeof(m_pszListDecimal)) ;
1229 	memset(m_pszListDelim,0,sizeof(m_pszListDelim)) ;
1230 	memset(m_pszFieldFont,0,sizeof(m_pszFieldFont)) ;
1231 	m_startValue = 0;
1232 	m_curTabType = FL_TAB_LEFT;
1233 	m_curTabLeader = FL_LEADER_NONE;
1234 	m_iOverride = 0;
1235 	m_iOverrideLevel = 0;
1236 	m_styleNumber = -1;
1237 	m_dir = UT_BIDI_UNSET;
1238 	m_tableLevel = 1; // Has to be 1 because the RTF spec has itap defaulting
1239 	                  // to this value
1240 	m_bInTable = false;
1241 	m_eRevision = PP_REVISION_NONE;
1242 	m_iCurrentRevisionId = 0;
1243 	m_bMergeBordersShading = false;
1244 	m_bBotBorder = false;
1245 	m_iBotBorderStyle = 0; // Number to represent style of border
1246 	m_iBotBorderCol = 0; // index to color table
1247 	m_iBotBorderWidth = 10;  // Thickness in twips
1248 	m_iBotBorderSpacing = 10; // Spacing to text in twips
1249 	m_bLeftBorder =  false;
1250 	m_iLeftBorderStyle = 0; // Number to represent style of border
1251 	m_iLeftBorderCol = 0; // index to color table
1252 	m_iLeftBorderWidth = 10;  // Thickness in twips
1253 	m_iLeftBorderSpacing = 10; // Spacing to text in twips
1254 	m_bRightBorder = false;
1255 	m_iRightBorderStyle = 0; // Number to represent style of border
1256 	m_iRightBorderCol = 0; // index to color table
1257 	m_iRightBorderWidth = 10;  // Thickness in twips
1258 	m_iRightBorderSpacing = 10; // Spacing to text in twips
1259 	m_bTopBorder = false;
1260 	m_iTopBorderStyle = 0; // Number to represent style of border
1261 	m_iTopBorderCol = 0; // index to color table
1262 	m_iTopBorderWidth = 10;  // Thickness in twips
1263 	m_iTopBorderSpacing = 0; // Spacing to text in twips
1264 	m_iCurBorder = -1; // 0=bot,1=left,2=right,3=top
1265 	m_iShadingPattern = 0; // Number to represent the style of shading
1266 	m_iShadingForeCol = -1; // The Foreground color
1267 	m_iShadingBackCol = -1; // The Background color
1268 
1269 }
1270 
operator =(const RTFProps_ParaProps & other)1271 RTFProps_ParaProps& RTFProps_ParaProps::operator=(const RTFProps_ParaProps& other)
1272 {
1273 	if (this != &other)
1274 	{
1275 		m_tabStops.clear();
1276 		m_tabTypes.clear();
1277 		m_tabLeader.clear();
1278 		m_justification = other.m_justification;
1279 		m_spaceBefore = other.m_spaceBefore;
1280 		m_spaceAfter = other.m_spaceAfter;
1281 		m_indentLeft = other.m_indentLeft;
1282 		m_indentRight = other.m_indentRight;
1283 		m_indentFirst = other.m_indentFirst;
1284 		m_lineSpaceVal = other.m_lineSpaceVal;
1285 		m_lineSpaceExact = other.m_lineSpaceExact;
1286 
1287 		if (!other.m_tabStops.empty())
1288 		{
1289 			m_tabStops.insert(m_tabStops.end(), other.m_tabStops.begin(), other.m_tabStops.end());
1290 		}
1291 		if (!other.m_tabTypes.empty())
1292 		{
1293 			m_tabTypes.insert(m_tabTypes.end(), other.m_tabTypes.begin(), other.m_tabTypes.end());
1294 		}
1295 		if (!other.m_tabLeader.empty())
1296 		{
1297 			m_tabLeader.insert(m_tabLeader.end(), other.m_tabLeader.begin(), other.m_tabLeader.end());
1298 		}
1299 		UT_ASSERT_HARMLESS(m_tabStops.size() ==	other.m_tabTypes.size() );
1300 		UT_ASSERT_HARMLESS(m_tabStops.size() ==	other.m_tabLeader.size() );
1301 
1302 		m_isList = other.m_isList;
1303 		m_level = other.m_level;
1304 		strcpy(static_cast<char *>(m_pszStyle), static_cast<const char *>(other.m_pszStyle));
1305 		m_rawID = other.m_rawID;
1306 		m_rawParentID = other.m_rawParentID;
1307 		strcpy(static_cast<char *>(m_pszListDecimal), static_cast<const char *>(other.m_pszListDecimal));
1308 		strcpy(static_cast<char *>(m_pszListDelim), static_cast<const char *>(other.m_pszListDelim));
1309 		strcpy(static_cast<char *>(m_pszFieldFont), static_cast<const char *>(other.m_pszFieldFont));
1310 		m_startValue = other.m_startValue;
1311 		m_iOverride = other.m_iOverride;
1312 		m_iOverrideLevel = other.m_iOverrideLevel;
1313 		if(!m_tabTypes.empty())
1314 		{
1315 			m_curTabType = m_tabTypes.at(0);
1316 			m_curTabLeader = m_tabLeader.at(0);
1317 		}
1318 		else
1319 		{
1320 			m_curTabType = FL_TAB_LEFT;
1321 			m_curTabLeader = FL_LEADER_NONE;
1322 		}
1323 		m_rtfListTable = other.m_rtfListTable;
1324 		m_styleNumber = other.m_styleNumber;
1325 		m_bInTable = other.m_bInTable;
1326 		m_bMergeBordersShading = other.m_bMergeBordersShading;
1327 		m_bBotBorder = other.m_bBotBorder;
1328 		m_iBotBorderStyle = other.m_iBotBorderStyle;
1329 		m_iBotBorderCol = other.m_iBotBorderCol;
1330 		m_iBotBorderWidth = other.m_iBotBorderWidth;
1331 		m_iBotBorderSpacing = other.m_iBotBorderSpacing;
1332 		m_bLeftBorder = other.m_bLeftBorder;
1333 		m_iLeftBorderStyle = other.m_iLeftBorderStyle;
1334 		m_iLeftBorderCol = other.m_iLeftBorderCol;
1335 		m_iLeftBorderWidth = other.m_iLeftBorderWidth;
1336 		m_iLeftBorderSpacing = other.m_iLeftBorderSpacing;
1337 		m_bRightBorder = other.m_bRightBorder;
1338 		m_iRightBorderStyle = other.m_iRightBorderStyle;
1339 		m_iRightBorderCol = other.m_iRightBorderCol;
1340 		m_iRightBorderWidth = other.m_iRightBorderWidth;
1341 		m_iRightBorderSpacing = other.m_iRightBorderSpacing;
1342 		m_bTopBorder = other.m_bTopBorder;
1343 		m_iTopBorderStyle = other.m_iTopBorderStyle;
1344 		m_iTopBorderCol = other.m_iTopBorderCol;
1345 		m_iTopBorderWidth = other.m_iTopBorderWidth;
1346 		m_iTopBorderSpacing = other.m_iTopBorderSpacing;
1347 		m_iCurBorder= other.m_iCurBorder;
1348 		m_iShadingPattern = other.m_iShadingPattern;
1349 		m_iShadingForeCol = other.m_iShadingForeCol;
1350 		m_iShadingBackCol = other.m_iShadingBackCol;
1351 	}
1352 
1353 	m_dir = other.m_dir;
1354 	m_tableLevel = other.m_tableLevel;
1355 
1356 	return *this;
1357 }
1358 
RTFProps_ImageProps()1359 RTFProps_ImageProps::RTFProps_ImageProps()
1360 {
1361 	sizeType = ipstNone;
1362 	wGoal = hGoal = width = height = 0;
1363 	scaleX = scaleY = 100;
1364 	bCrop = false;
1365 	cropt = cropb = cropl = cropr = 0;
1366 }
1367 
RTFProps_CellProps()1368 RTFProps_CellProps::RTFProps_CellProps()
1369 {
1370 	m_bVerticalMerged = false;
1371 	m_bVerticalMergedFirst = false;
1372 	m_bHorizontalMerged = false;
1373 	m_bHorizontalMergedFirst = false;
1374 	m_sCellProps.clear();
1375 	m_iCurBorder = rtfCellBorderTop;
1376 	m_bLeftBorder = false;
1377 	m_bRightBorder = false;
1378 	m_bTopBorder = false;
1379 	m_bBotBorder= false;
1380 	m_iCellx = 0;
1381 }
1382 
operator =(const RTFProps_CellProps & other)1383 RTFProps_CellProps& RTFProps_CellProps::operator=(const RTFProps_CellProps& other)
1384 {
1385 	if (this != &other)
1386 	{
1387 		 m_bVerticalMerged = other.m_bVerticalMerged;
1388 		 m_bVerticalMergedFirst = other. m_bVerticalMergedFirst;
1389 		 m_bHorizontalMerged = other.m_bHorizontalMerged;
1390 		 m_bHorizontalMergedFirst = other. m_bHorizontalMergedFirst;
1391 		 m_sCellProps = other.m_sCellProps;
1392 		 m_iCurBorder = other.m_iCurBorder;
1393 		 m_bLeftBorder = other.m_bLeftBorder;
1394 		 m_bRightBorder = other.m_bRightBorder;
1395 		 m_bTopBorder = other.m_bTopBorder;
1396 		 m_bBotBorder= other.m_bBotBorder;
1397 		 m_iCellx = other.m_iCellx;
1398 
1399 	}
1400 	return *this;
1401 }
1402 
RTFProps_TableProps()1403 RTFProps_TableProps::RTFProps_TableProps()
1404 {
1405 	m_bAutoFit = false;
1406 }
1407 
operator =(const RTFProps_TableProps & other)1408 RTFProps_TableProps& RTFProps_TableProps::operator=(const RTFProps_TableProps& other)
1409 {
1410 	if (this != &other)
1411 	{
1412 		m_bAutoFit = other.m_bAutoFit;
1413 	}
1414 	return *this;
1415 }
1416 
RTFProps_SectionProps()1417 RTFProps_SectionProps::RTFProps_SectionProps()
1418 {
1419 	m_numCols = 1;
1420 	m_breakType = sbkPage;    /* the default in RTF is page section break */
1421 	m_pageNumFormat = pgDecimal;
1422 	m_bColumnLine = false;
1423 	m_leftMargTwips = 1800;
1424 	m_rightMargTwips = 1800;
1425 	m_topMargTwips = 1440;
1426 	m_bottomMargTwips = 1440;
1427 	m_headerYTwips = 720;
1428 	m_footerYTwips = 720;
1429 	m_gutterTwips = 0;
1430     m_colSpaceTwips = 0;
1431 	m_dir = UT_BIDI_UNSET;
1432 }
1433 
1434 
RTFStateStore()1435 RTFStateStore::RTFStateStore()
1436 {
1437 	m_destinationState = rdsNorm;
1438 	m_internalState = risNorm;
1439 	m_unicodeAlternateSkipCount = 1;
1440 	m_unicodeInAlternate = 0;
1441 	m_bInKeywordStar = false;
1442 }
1443 
1444 
clone(void)1445 RTFStateStore * RTFStateStore::clone(void)
1446 {
1447 	RTFStateStore * pNew = new RTFStateStore();
1448 	pNew->m_destinationState = m_destinationState;
1449 	pNew->m_charProps = m_charProps;
1450 	pNew->m_paraProps = m_paraProps;
1451 	pNew->m_sectionProps = m_sectionProps;
1452 	pNew->m_cellProps = m_cellProps;
1453 	pNew->m_tableProps = m_tableProps;
1454 	pNew->m_unicodeAlternateSkipCount = m_unicodeAlternateSkipCount;
1455 	pNew->m_unicodeInAlternate = m_unicodeInAlternate;
1456 	pNew->m_revAttr = m_revAttr;
1457 	return pNew;
1458 }
1459 
1460 /*****************************************************************/
1461 /*****************************************************************/
1462 
IE_Imp_RTF(PD_Document * pDocument)1463 IE_Imp_RTF::IE_Imp_RTF(PD_Document * pDocument)
1464 :	IE_Imp(pDocument),
1465 	m_gbBlock(1024),
1466 	m_szFileDirName(NULL),
1467 	m_groupCount(0),
1468 	m_newParaFlagged(false),
1469 	m_newSectionFlagged(false),
1470 	m_cbBin(0),
1471 	m_currentHdrID(0),
1472 	m_currentFtrID(0),
1473 	m_currentHdrEvenID(0),
1474 	m_currentFtrEvenID(0),
1475 	m_currentHdrFirstID(0),
1476 	m_currentFtrFirstID(0),
1477 	m_currentHdrLastID(0),
1478 	m_currentFtrLastID(0),
1479 	m_numLists(0),
1480 	m_pImportFile(NULL),
1481 	m_pPasteBuffer(NULL),
1482 	m_lenPasteBuffer(0),
1483 	m_pCurrentCharInPasteBuffer(NULL),
1484 	deflangid(0),
1485 	m_mbtowc (XAP_EncodingManager::get_instance()->getNative8BitEncodingName()),
1486 	m_parsingHdrFtr(false),
1487 	m_icurOverride(0),
1488 	m_icurOverrideLevel(0),
1489 	m_bAppendAnyway(false),
1490 	m_TableControl(pDocument),
1491 	m_lastCellSDH(NULL),
1492 	m_bNestTableProps(false),
1493 	m_bParaWrittenForSection(false),
1494 	m_bCellBlank(true),
1495 	m_bEndTableOpen(false),
1496 	m_bInFootnote(false),
1497 	m_iDepthAtFootnote(0),
1498 	m_iLastFootnoteId((UT_uint32)pDocument->getUID(UT_UniqueId::Footnote)),
1499 	m_iLastEndnoteId((UT_uint32)pDocument->getUID(UT_UniqueId::Endnote)),
1500 	m_iHyperlinkOpen(0),
1501 	m_iRDFAnchorOpen(0),
1502 	m_bBidiMode(false),
1503 	m_bFootnotePending(false),
1504 	m_bFtnReferencePending(false),
1505 	m_bNoteIsFNote(true),
1506 	m_bStyleImportDone(false),
1507 	m_bCellHandled(false),
1508 	m_bContentFlushed(false),
1509 	m_bRowJustPassed(false),
1510 	m_iStackLevelAtRow(0),
1511 	m_bDoCloseTable(false),
1512 	m_iNoCellsSinceLastRow(0),
1513 	m_bFieldRecognized(false),
1514 	m_iIsInHeaderFooter(0),
1515 	m_bSectionHasPara(false),
1516 	m_bStruxInserted(false),
1517 	m_bStruxImage(false),
1518 	m_bFrameStruxIn(false),
1519 	m_iAutoBidiOverride(UT_BIDI_UNSET),
1520 	m_iBidiLastType(UT_BIDI_UNSET),
1521 	m_iBidiNextType(UT_BIDI_UNSET),
1522 	m_szDefaultEncoding(NULL),
1523 	m_iDefaultFontNumber(-1),
1524 	m_dPosBeforeFootnote(0),
1525 	m_bMovedPos(true),
1526 	m_pAnnotation(NULL),
1527 	m_pDelayedFrag(NULL),
1528 	m_posSavedDocPosition(0),
1529 	m_bInAnnotation(false),
1530 	m_bFrameTextBox(false),
1531 	m_bParaActive(false),
1532 	m_bCellActive(false),
1533 	m_ctMoveID("")
1534 {
1535 	UT_DEBUGMSG(("New ie_imp_RTF %p \n",this));
1536 	m_sImageName.clear();
1537 	if (!IE_Imp_RTF::keywordSorted) {
1538 		_initialKeywordSort();
1539 	}
1540 
1541 	if(!m_vecAbiListTable.empty())
1542 	{
1543 		UT_std_vector_purgeall(m_vecAbiListTable);
1544 	}
1545 	m_mbtowc.setInCharset(XAP_EncodingManager::get_instance()->getNativeEncodingName());
1546 	m_hyperlinkBase.clear();
1547 	m_pasteTableStack.push(NULL);
1548 
1549 	m_XMLIDCreatorHandle = getDoc()->makeXMLIDCreator();
1550 }
1551 
1552 
~IE_Imp_RTF()1553 IE_Imp_RTF::~IE_Imp_RTF()
1554 {
1555 	// Empty the state stack
1556 	UT_DEBUGMSG(("In RTF destructor %p \n",this));
1557 	while (m_stateStack.getDepth() > 0)
1558 	{
1559 		RTFStateStore* pItem = NULL;
1560 		m_stateStack.pop((void**)(&pItem));
1561 		UT_DEBUGMSG(("Deleting item %p in RTF destructor \n",pItem));
1562 		delete pItem;
1563 	}
1564 	UT_DEBUGMSG(("Closing pastetable In RTF destructor %p \n",this));
1565 	closePastedTableIfNeeded();
1566 	UT_DEBUGMSG(("Deleting fonts In RTF destructor %p \n",this));
1567 
1568 	// and the font table (can't use the macro as we allow NULLs in the vector
1569 	UT_sint32 size = m_fontTable.size();
1570 	UT_sint32 i =0;
1571 	for (i = size-1; i>=0; i--)
1572 	{
1573 		RTFFontTableItem* pItem = m_fontTable.at(i);
1574 		delete pItem;
1575 	}
1576 
1577 	// and the styleName table.
1578 	UT_DEBUGMSG(("Deleting styles In RTF destructor %p \n",this));
1579 
1580 	UT_DEBUGMSG(("Purging In RTF destructor %p \n",this));
1581 	UT_std_vector_purgeall(m_vecAbiListTable);
1582 	UT_std_vector_purgeall(m_hdrFtrTable);
1583 	UT_std_vector_purgeall(m_vecWord97Lists);
1584 	UT_std_vector_purgeall(m_vecWord97ListOverride);
1585 	UT_DEBUGMSG(("SEVIOR:DOing last close \n"));
1586 	while(getTable() && getTable()->wasTableUsed())
1587 	{
1588 		CloseTable(true);
1589 	}
1590 	FREEP (m_szFileDirName);
1591 }
1592 
_loadFile(GsfInput * fp)1593 UT_Error IE_Imp_RTF::_loadFile(GsfInput * fp)
1594 {
1595 	m_newParaFlagged = true;
1596 	m_newSectionFlagged = true;
1597 
1598 	m_szFileDirName = g_strdup (gsf_input_name (fp));
1599 	if(m_szFileDirName == NULL)
1600 		m_szFileDirName = g_strdup("/tmp");
1601 	// UT_basename returns a point INSIDE the passed string.
1602 	// the trick is to truncate the string by setting the char pointed
1603 	// by tmp to NULL. This IS useful code. (2 LOC)
1604 	char * tmp = const_cast<char *>(UT_basename (m_szFileDirName));
1605 	*tmp = 0;
1606 
1607 	UT_Error error = _writeHeader(fp);
1608 
1609 	if (!error)
1610 	{
1611 		error = _parseFile(fp);
1612 		m_bAppendAnyway = true;
1613 		_appendHdrFtr ();
1614 	}
1615 
1616 	// check if the doc is empty or not
1617 	if (getDoc()->getLastFrag() == NULL)
1618 	{
1619 		error = UT_IE_BOGUSDOCUMENT;
1620 	}
1621 
1622 	return error;
1623 }
1624 
1625 
_writeHeader(GsfInput *)1626 UT_Error IE_Imp_RTF::_writeHeader(GsfInput * /*fp*/)
1627 {
1628 		return UT_OK;
1629 }
1630 
1631 
digVal(char ch,int & value,int base)1632 bool IE_Imp_RTF::digVal(char ch, int& value, int base)
1633 {
1634 	value = ch - '0';
1635 
1636 	return (value >= 0) && (value < base);
1637 }
1638 
hexVal(char c,int & value)1639 bool IE_Imp_RTF::hexVal(char c, int& value)
1640 {
1641 	bool ok = true;
1642 
1643 	if (isdigit(c))
1644 	{
1645 		ok = digVal(c, value, 10);
1646 	}
1647 	else if (islower(c))
1648 	{
1649 		ok = (c >= 'a' && c <= 'f');
1650 		value = c - 'a' + 10;
1651 	}
1652 	else
1653 	{
1654 		ok = (c >= 'A' && c <= 'F');
1655 		value = static_cast<char>(c) - 'A' + 10;
1656 	}
1657 
1658 	return ok;
1659 }
1660 
getCell(void)1661 ie_imp_cell * IE_Imp_RTF::getCell(void)
1662 {
1663 	UT_return_val_if_fail(getTable(),NULL);
1664 	return getTable()->getCurCell();
1665 }
1666 
getTable(void)1667 ie_imp_table * IE_Imp_RTF::getTable(void)
1668 {
1669 	return m_TableControl.getTable();
1670 }
1671 
1672 /*!
1673  * Opens a table by inserting a table and cell strux. The boolean argument
1674  * bDontFlush is false by default. If true the current stored chars are
1675  * not flushed.
1676  */
OpenTable(bool bDontFlush)1677 void IE_Imp_RTF::OpenTable(bool bDontFlush)
1678 {
1679 	if(bUseInsertNotAppend())
1680 	{
1681 		return;
1682 	}
1683 	if(!m_bParaWrittenForSection)
1684 	{
1685 		if(!bDontFlush)
1686 		{
1687 			m_newParaFlagged = false;
1688 			FlushStoredChars(true); // MES 30/3/2005
1689 		}
1690 	}
1691 	else
1692 	{
1693 		if(!bDontFlush)
1694 		{
1695 			FlushStoredChars();
1696 		}
1697 	}
1698 	if(m_bInFootnote)
1699 	{
1700 		UT_DebugOnly<bool> ok =true;
1701 		if(!bUseInsertNotAppend())
1702 		{
1703 			if(m_bNoteIsFNote)
1704 				getDoc()->appendStrux(PTX_EndFootnote,NULL);
1705 			else
1706 				getDoc()->appendStrux(PTX_EndEndnote,NULL);
1707 
1708 		}
1709 		else
1710 		{
1711 			if(m_bNoteIsFNote)
1712 				ok = insertStrux(PTX_EndFootnote);
1713 			else
1714 				ok = insertStrux(PTX_EndEndnote);
1715 			UT_ASSERT(ok);
1716 			if(	m_bMovedPos)
1717 			{
1718 				m_bMovedPos = false;
1719 				m_dposPaste += m_dPosBeforeFootnote; // restore old position
1720 			}
1721 		}
1722 		m_bInFootnote = false;
1723 		m_iDepthAtFootnote = 0;
1724 	}
1725 	m_TableControl.OpenTable();
1726 //
1727 // Need to have a block to append a table to
1728 //
1729 	if((m_TableControl.getNestDepth() > 1) && m_bCellBlank)
1730 	{
1731 			UT_DEBUGMSG(("Append block 6 \n"));
1732 
1733 			getDoc()->appendStrux(PTX_Block,NULL);
1734 	}
1735 	getDoc()->appendStrux(PTX_SectionTable,NULL);
1736 	UT_DEBUGMSG(("SEVIOR: Appending Table strux to doc nestdepth %d \n", m_TableControl.getNestDepth()));
1737 	UT_ASSERT( m_TableControl.getNestDepth() < 2);
1738 	PT_DocPosition posEnd=0;
1739 	getDoc()->getBounds(true,posEnd); // clean frags!
1740 	pf_Frag_Strux* sdh = getDoc()->getLastStruxOfType(PTX_SectionTable);
1741 	UT_DEBUGMSG(("SEVIOR: Table strux sdh is %p \n",sdh));
1742 	getTable()->setTableSDH(sdh);
1743 	getTable()->OpenCell();
1744 	if(!bDontFlush)
1745 	{
1746 		FlushCellProps();
1747 		ResetCellAttributes();
1748 	}
1749 	getDoc()->appendStrux(PTX_SectionCell,NULL);
1750 	getDoc()->getBounds(true,posEnd); // clean frags!
1751 	sdh = getDoc()->getLastStruxOfType(PTX_SectionCell);
1752 	getCell()->setCellSDH(sdh);
1753 	m_currentRTFState.m_cellProps = RTFProps_CellProps();
1754 	m_currentRTFState.m_tableProps = RTFProps_TableProps();
1755 	m_lastCellSDH = NULL; // This is in the table structure and can be deleted from there.
1756 	m_bCellBlank = true;
1757 //	m_iNoCellsSinceLastRow = 0;
1758 }
1759 
1760 /*!
1761  * This Method saves the information about the current row
1762  */
SaveRowInfo(void)1763 void IE_Imp_RTF::SaveRowInfo(void)
1764 {
1765 }
1766 
1767 /*!
1768  * This Method Clears any information about the current row
1769  */
RemoveRowInfo(void)1770 void IE_Imp_RTF::RemoveRowInfo(void)
1771 {
1772 }
1773 
getPasteDepth(void)1774 UT_sint32 IE_Imp_RTF::getPasteDepth(void)
1775 {
1776 	return m_pasteTableStack.getDepth();
1777 }
1778 
1779 /*!
1780  * Close off pasted Tables
1781  */
closePastedTableIfNeeded(void)1782 void IE_Imp_RTF::closePastedTableIfNeeded(void)
1783 {
1784 	while(m_pasteTableStack.getDepth() > 0)
1785 	{
1786 		ABI_Paste_Table * pPaste = NULL;
1787 		m_pasteTableStack.pop((void**)(&pPaste));
1788 		if(pPaste != NULL)
1789 		{
1790 			if(pPaste->m_bHasPastedCellStrux && !pPaste->m_bHasPastedBlockStrux)
1791 			{
1792 				insertStrux(PTX_Block);
1793 				UT_DEBUGMSG(("Paste block in destructor 1 \n"));
1794 			}
1795 			if(pPaste->m_bHasPastedCellStrux)
1796 			{
1797 				insertStrux(PTX_EndCell);
1798 				UT_DEBUGMSG(("Paste EndCell in destructor 1 \n"));
1799 			}
1800 			if(!pPaste->m_bPasteAfterRow)
1801 			{
1802 //
1803 // Now fill out any remaining cells needed to finish the row of the table
1804 //
1805 				UT_sint32 i = pPaste->m_iCurRightCell;
1806 				std::string sTop =  UT_std_string_sprintf("%d",pPaste->m_iCurTopCell);
1807 				std::string sBot =  UT_std_string_sprintf("%d",pPaste->m_iCurTopCell+1);
1808 				std::string sCellProps;
1809 				std::string sVal;
1810 				std::string sDum;
1811 				const gchar * attrs[3] = {"props",NULL,NULL};
1812 				for(i = pPaste->m_iCurRightCell; i<pPaste->m_iMaxRightCell; i++)
1813 				{
1814 					sCellProps.clear();
1815 					sVal = UT_std_string_sprintf("%d",i);
1816 					sDum = "left-attach";
1817 					UT_std_string_setProperty(sCellProps,sDum,sVal);
1818 					sVal = UT_std_string_sprintf("%d",i+1);
1819 					sDum = "right-attach";
1820 					UT_std_string_setProperty(sCellProps,sDum,sVal);
1821 					sDum = "top-attach";
1822 					UT_std_string_setProperty(sCellProps,sDum,sTop);
1823 					sDum = "bot-attach";
1824 					UT_std_string_setProperty(sCellProps,sDum,sBot);
1825 
1826 					attrs[1] = sCellProps.c_str();
1827 					insertStrux(PTX_SectionCell,attrs,NULL);
1828 
1829 					insertStrux(PTX_Block);
1830 
1831 					insertStrux(PTX_EndCell);
1832 				}
1833 				if(pPaste->m_bHasPastedTableStrux)
1834 				{
1835 					insertStrux(PTX_EndTable);
1836 
1837 					insertStrux(PTX_Block);
1838 				}
1839 			}
1840 			else
1841 			{
1842 //
1843 // Close off pasted rows by incrementing the top and botton's of the cell's
1844 // below
1845 //
1846 				UT_sint32 numRows = pPaste->m_iNumRows;
1847 				pf_Frag_Strux* sdhCell = NULL;
1848 				pf_Frag_Strux* sdhTable = NULL;
1849 				pf_Frag_Strux* sdhEndTable = NULL;
1850 				bool b = getDoc()->getStruxOfTypeFromPosition(m_dposPaste,PTX_SectionTable,&sdhTable);
1851 				PT_DocPosition posTable = getDoc()->getStruxPosition(sdhTable);
1852 				UT_ASSERT(b);
1853 				sdhEndTable = getDoc()->getEndTableStruxFromTableSDH(sdhTable);
1854 				UT_ASSERT(sdhEndTable);
1855 				PT_DocPosition posEndTable = getDoc()->getStruxPosition(sdhEndTable);
1856 				b = getDoc()->getStruxOfTypeFromPosition(m_dposPaste-1,PTX_SectionCell,&sdhCell);
1857 				b = getDoc()->getNextStruxOfType(sdhCell,PTX_SectionCell,&sdhCell);
1858 				std::string sTop;
1859 				std::string sBot;
1860 				const char * szVal = NULL;
1861 				const gchar * sProps[5] = {NULL,NULL,NULL,NULL};
1862 				PT_DocPosition posCell = 0;
1863 				if(b)
1864 				{
1865 					posCell = getDoc()->getStruxPosition(sdhCell);
1866 				}
1867 				while(b && (posCell < posEndTable))
1868 				{
1869 					getDoc()->getPropertyFromSDH(sdhCell,
1870 												 true,
1871 												 PD_MAX_REVISION,
1872 												 "top-attach", &szVal);
1873 					UT_ASSERT(szVal);
1874 					UT_sint32 iTop = atoi(szVal);
1875 					iTop += numRows;
1876 					sTop = UT_std_string_sprintf("%d",iTop);
1877 					getDoc()->getPropertyFromSDH(sdhCell,
1878 												 true,
1879 												 PD_MAX_REVISION,
1880 												 "bot-attach", &szVal);
1881 					UT_ASSERT(szVal);
1882 					UT_sint32 iBot = atoi(szVal);
1883 					iBot += numRows;
1884 					sBot = UT_std_string_sprintf("%d",iBot);
1885 					UT_DEBUGMSG(("Change cell top to %d bot to %d \n",iTop,iBot));
1886 					sProps[0] = "top-attach";
1887 					sProps[1] = sTop.c_str();
1888 					sProps[2] = "bot-attach";
1889 					sProps[3] = sBot.c_str();
1890 					getDoc()->changeStruxFmt(PTC_AddFmt,posCell+1,posCell+1,NULL,sProps,PTX_SectionCell);
1891 					b = getDoc()->getNextStruxOfType(sdhCell,PTX_SectionCell,&sdhCell);
1892 					if(b)
1893 					{
1894 						posCell = getDoc()->getStruxPosition(sdhCell);
1895 					}
1896 				}
1897 //
1898 // Now a change strux on the table to make it rebuild.
1899 //
1900 				sProps[0] = "list-tag";
1901 				std::string sVal = UT_std_string_sprintf("%d",getDoc()->getUID(UT_UniqueId::List));
1902 				sProps[1] = sVal.c_str();
1903 				sProps[2] = NULL;
1904 				sProps[3] = NULL;
1905 				getDoc()->changeStruxFmt(PTC_AddFmt,posTable+1,posTable+1,NULL,sProps,PTX_SectionTable);
1906 			}
1907 			delete pPaste;
1908 		}
1909 	}
1910 }
1911 /*!
1912  * Closes the current table. Does all the book keeping of inserting
1913  * endstruxs and deleting used ones.
1914  */
CloseTable(bool bForce)1915 void IE_Imp_RTF::CloseTable(bool bForce /* = false */)
1916 {
1917 //
1918 // Close table removes extraneous struxes like unmatched PTX_SectionCell's
1919 //
1920 	if(!bForce && (bUseInsertNotAppend() || (getTable() == NULL)))
1921 	{
1922 		return;
1923 	}
1924 	if(getTable() && getTable()->wasTableUsed())
1925 	{
1926 		UT_DEBUGMSG(("SEVIOR: Table used appened end Table, block \n"));
1927 		if(m_lastCellSDH != NULL )
1928 		{
1929 			getDoc()->insertStruxNoUpdateBefore(m_lastCellSDH,PTX_EndTable,NULL);
1930 //
1931 // Need this one for dp_Instructions. Sevior
1932 //
1933 			getDoc()->insertStruxNoUpdateBefore(m_lastCellSDH,PTX_Block,NULL);
1934 			pf_Frag_Strux* cellSDH = m_lastCellSDH;
1935 			getDoc()->deleteStruxNoUpdate(cellSDH);
1936 			m_bEndTableOpen = true;
1937 		}
1938 		m_TableControl.CloseTable();
1939 		if(m_lastCellSDH == NULL)
1940 		{
1941 			getDoc()->appendStrux(PTX_EndTable,NULL);
1942 			m_bEndTableOpen = true;
1943 		}
1944 		m_lastCellSDH = NULL;
1945 	}
1946 	else if(getTable())
1947 	{
1948 		if(m_lastCellSDH != NULL )
1949 		{
1950 			pf_Frag_Strux* cellSDH = m_lastCellSDH;
1951 			getDoc()->deleteStruxNoUpdate(cellSDH);
1952 			m_lastCellSDH = NULL;
1953 		}
1954 		m_TableControl.CloseTable();
1955 		m_bEndTableOpen = true;
1956 		UT_DEBUGMSG(("SEVIOR: Table not used. \n"));
1957 	}
1958 	else
1959 	{
1960 		if(m_lastCellSDH != NULL )
1961 		{
1962 			pf_Frag_Strux* cellSDH = m_lastCellSDH;
1963 			getDoc()->deleteStruxNoUpdate(cellSDH);
1964 			m_lastCellSDH = NULL;
1965 		}
1966 	}
1967 }
1968 
HandleCell(void)1969 void IE_Imp_RTF::HandleCell(void)
1970 {
1971 //
1972 // Look if the has been some text output before this with an open row. If
1973 // so, close the table and make copy of the last cells.
1974 //
1975 	UT_DEBUGMSG(("Handle Cell \n"));
1976 	if(m_bRowJustPassed && m_bDoCloseTable && (getTable()!= NULL))
1977 	{
1978 		UT_GenericVector<ie_imp_cell *> vecOldCells;
1979 		UT_GenericVector<ie_imp_cell *> vecCopyCells;
1980 		UT_sint32 row = getTable()->getRow();
1981 		getTable()->getVecOfCellsOnRow(row-1, &vecOldCells);
1982 		UT_sint32 i =0;
1983 		for(i=0; i< vecOldCells.getItemCount();i++)
1984 		{
1985 			ie_imp_cell * pCell = vecOldCells.getNthItem(i);
1986 			ie_imp_cell * pNewCell = new ie_imp_cell(NULL,NULL,NULL,0);
1987 			pNewCell->copyCell(pCell);
1988 			vecCopyCells.addItem(pNewCell);
1989 		}
1990 		UT_ASSERT_HARMLESS(vecOldCells.getItemCount() > 0);
1991 		CloseTable();
1992 		OpenTable(true);
1993 		for(i=0; i< vecCopyCells.getItemCount();i++)
1994 		{
1995 			ie_imp_cell * pCopyCell = vecCopyCells.getNthItem(i);
1996 			if(i>0)
1997 			{
1998 //
1999 // Already open openned from OpenTable()
2000 //
2001 				getTable()->OpenCell();
2002 			}
2003 			ie_imp_cell * pCell = getTable()->getNthCellOnRow(i);
2004 			pCell->copyCell(pCopyCell);
2005 			xxx_UT_DEBUGMSG(("Got Cell number %d CellX %d \n",i,pCell->getCellX()));
2006 		}
2007 		UT_VECTOR_PURGEALL(ie_imp_cell *, vecCopyCells);
2008 	}
2009 	m_bRowJustPassed = false;
2010 	m_bCellHandled = true;
2011 	m_bDoCloseTable = false;
2012 	m_iNoCellsSinceLastRow++;
2013 	UT_DEBUGMSG(("Num Cell on row %d \n",m_iNoCellsSinceLastRow));
2014 	if(bUseInsertNotAppend())
2015 	{
2016 		return;
2017 	}
2018 	if(m_bCellBlank && (m_gbBlock.getLength() == 0))
2019 	{
2020 	    UT_DEBUGMSG(("Append block 7 \n"));
2021 
2022 		getDoc()->appendStrux(PTX_Block,NULL);
2023 	}
2024 	else
2025 	{
2026 //
2027 // Flush out anything we've been holding
2028 //
2029 		FlushStoredChars();
2030 	}
2031 	if(getTable() == NULL)
2032 	{
2033 		OpenTable();
2034 	}
2035 	pf_Frag_Strux* sdh = getDoc()->getLastStruxOfType(PTX_SectionCell);
2036 	ie_imp_cell * pCell = getTable()->getNthCellOnRow(getTable()->getPosOnRow());
2037 	UT_return_if_fail(sdh);
2038 	if(!pCell)
2039 	{
2040 //
2041 // Cell class doesn't exist so create it.
2042 //
2043 		UT_sint32 pos  = getTable()->OpenCell();
2044 		getTable()->setPosOnRow(pos);
2045 		xxx_UT_DEBUGMSG(("SEVIOR: created cell %p for posOnRow %d \n",getCell(),getTable()->getPosOnRow()));
2046 	}
2047 	xxx_UT_DEBUGMSG(("SEVIOR: set cell %p sdh %p  at pos %d on row %d \n",getCell(),sdh,getTable()->getPosOnRow(),getTable()->getRow()));
2048 	getTable()->setNthCellOnThisRow(getTable()->getPosOnRow());
2049 	if(getCell()->isMergedAbove())
2050 	{
2051 		xxx_UT_DEBUGMSG(("Cell %x is merged Above \n"));
2052 	}
2053 	if(getCell()->isMergedLeft())
2054 	{
2055 		xxx_UT_DEBUGMSG(("Cell %x is merged left \n"));
2056 	}
2057 
2058 	if(!getCell()->isMergedAbove() && !getCell()->isMergedLeft())
2059 	{
2060 		getCell()->setCellSDH(sdh);
2061 		xxx_UT_DEBUGMSG(("SEVIOR: At posOnRow %d cellx %d \n",getTable()->getPosOnRow(),getCell()->getCellX()));
2062 		getTable()->incPosOnRow();
2063 		FlushStoredChars();
2064 		xxx_UT_DEBUGMSG(("SEVIOR: Non posonrow %d \n",getTable()->getPosOnRow()));
2065 		getDoc()->appendStrux(PTX_EndCell,NULL);
2066 //
2067 // Look to see if this is just has a cell/endCell with no content. If so
2068 // repair it.
2069 //
2070 		pf_Frag_Strux* sdhEndCell = getDoc()->getLastStruxOfType(PTX_EndCell);
2071 		if(getDoc()->isStruxBeforeThis(sdhEndCell,PTX_SectionCell))
2072 		{
2073 			UT_DEBUGMSG(("Insert Block before frag 1 \n"));
2074 			getDoc()->insertStruxNoUpdateBefore(sdhEndCell,PTX_Block,NULL);
2075 			const pf_Frag * pf = static_cast<const pf_Frag *>(sdhEndCell);
2076 			getDoc()->insertFmtMarkBeforeFrag(const_cast<pf_Frag *>(pf));
2077 		}
2078 		getTable()->CloseCell();
2079 		getDoc()->appendStrux(PTX_SectionCell,NULL);
2080 		m_lastCellSDH = getDoc()->getLastStruxOfType(PTX_SectionCell);
2081 	}
2082 	else
2083 	{
2084 		getTable()->incPosOnRow();
2085 	}
2086 	m_bCellBlank = true;
2087 }
2088 
FlushCellProps(void)2089 void IE_Imp_RTF::FlushCellProps(void)
2090 {
2091 	if(bUseInsertNotAppend())
2092 	{
2093 		return;
2094 	}
2095 	if(m_currentRTFState.m_cellProps.m_bVerticalMerged)
2096 	{
2097 		UT_DEBUGMSG(("Set merged above to cell %p \n",getCell()));
2098 	}
2099 	if(m_currentRTFState.m_cellProps.m_bHorizontalMerged)
2100 	{
2101 		UT_DEBUGMSG(("Set merged left to cell %p \n",getCell()));
2102 	}
2103 	getCell()->setMergeAbove( m_currentRTFState.m_cellProps.m_bVerticalMerged );
2104 	getCell()->setFirstVerticalMerge( m_currentRTFState.m_cellProps.m_bVerticalMergedFirst );
2105 	getCell()->setFirstHorizontalMerge( m_currentRTFState.m_cellProps.m_bHorizontalMergedFirst );
2106 	getCell()->setMergeLeft( m_currentRTFState.m_cellProps.m_bHorizontalMerged );
2107 	std::string sProp;
2108 	std::string sVal;
2109 	if(!m_currentRTFState.m_cellProps.m_bBotBorder)
2110 	{
2111 		sProp = "bot-style";
2112 		sVal = "none";
2113 		UT_std_string_setProperty(m_currentRTFState.m_cellProps.m_sCellProps,sProp,sVal);
2114 	}
2115 	if(!m_currentRTFState.m_cellProps.m_bTopBorder)
2116 	{
2117 		sProp = "top-style";
2118 		sVal = "none";
2119 		UT_std_string_setProperty(m_currentRTFState.m_cellProps.m_sCellProps,sProp,sVal);
2120 	}
2121 	if(!m_currentRTFState.m_cellProps.m_bLeftBorder)
2122 	{
2123 		sProp = "left-style";
2124 		sVal = "none";
2125 		UT_std_string_setProperty(m_currentRTFState.m_cellProps.m_sCellProps,sProp,sVal);
2126 	}
2127 	if(!m_currentRTFState.m_cellProps.m_bRightBorder)
2128 	{
2129 		sProp = "right-style";
2130 		sVal = "none";
2131 		UT_std_string_setProperty(m_currentRTFState.m_cellProps.m_sCellProps,sProp,sVal);
2132 	}
2133 	getCell()->addPropString( m_currentRTFState.m_cellProps.m_sCellProps );
2134 
2135 }
2136 
2137 /*!
2138  * Set a property, value pair in the supplied string. This is just a convience
2139  * wrapper function to use const char * strings
2140  */
_setStringProperty(std::string & sPropsString,const char * szProp,const char * szVal)2141 void IE_Imp_RTF::_setStringProperty(std::string & sPropsString,
2142                                     const char * szProp, const char * szVal)
2143 {
2144 	std::string sProp(szProp);
2145 	std::string sVal(szVal);
2146 	UT_std_string_setProperty(sPropsString,sProp,sVal);
2147 }
2148 
2149 
FlushTableProps(void)2150 void IE_Imp_RTF::FlushTableProps(void)
2151 {
2152 	if(bUseInsertNotAppend())
2153 	{
2154 		return;
2155 	}
2156 	getTable()->setAutoFit( m_currentRTFState.m_tableProps.m_bAutoFit );
2157 }
2158 
HandleCellX(UT_sint32 cellx)2159 void IE_Imp_RTF::HandleCellX(UT_sint32 cellx)
2160 {
2161 	if(bUseInsertNotAppend())
2162 	{
2163 		return;
2164 	}
2165 
2166 	if(getTable() == NULL)
2167 	{
2168 		OpenTable();
2169 	}
2170 //	UT_ASSERT_HARMLESS(cellx != 3652);
2171 	UT_sint32 iRow = 0;
2172 	bool bNewCell = true;
2173 //
2174 // Look to see if a cell with cellx already exists on the current row. If so set the
2175 // current cell pointer to point to it.
2176 //
2177 	UT_DEBUGMSG(("Original cellx %d \n",cellx));
2178 	iRow = getTable()->getRow();
2179 	ie_imp_cell * pOldCell = getTable()->getCellAtRowColX(iRow,cellx);
2180 	if(pOldCell && !m_currentRTFState.m_cellProps.m_bHorizontalMergedFirst && !m_currentRTFState.m_cellProps.m_bHorizontalMerged )
2181 	{
2182 		bNewCell = false;
2183 		getTable()->setCell(pOldCell);
2184 		cellx = pOldCell->getCellX();
2185 	}
2186 	if(!pOldCell)
2187 	{
2188 		pOldCell = getTable()->getNthCellOnRow(getTable()->getCellXOnRow());
2189 		xxx_UT_DEBUGMSG(("SEVIOR: Looking for cellx num %d on row %d found %p \n",getTable()->getCellXOnRow(),iRow,pOldCell));
2190 		if(pOldCell)
2191 		{
2192 			bNewCell = false;
2193 			getTable()->setCell(pOldCell);
2194 		}
2195 	}
2196 	if(bNewCell)
2197 	{
2198 		getTable()->OpenCell();
2199 		xxx_UT_DEBUGMSG(("SEVIOR: created cell %p for cellx %d on row \n",getCell(),cellx,getTable()->getRow()));
2200 	}
2201 	UT_ASSERT_HARMLESS(cellx>1);
2202 	getTable()->setCellX(cellx);
2203 	UT_DEBUGMSG(("set cellx for class %p to %d \n",getCell(),cellx));
2204 	getTable()->incCellXOnRow();
2205 	FlushCellProps();
2206 	ResetCellAttributes();
2207 }
2208 
HandleRow(void)2209 void IE_Imp_RTF::HandleRow(void)
2210 {
2211 	if(bUseInsertNotAppend())
2212 	{
2213 		return;
2214 	}
2215 
2216 	UT_DEBUGMSG(("ie_imp_RTF: Handle Row now NUm cells in row %d \n",m_iNoCellsSinceLastRow));
2217 	if(m_iNoCellsSinceLastRow > 0)
2218 	{
2219 		m_TableControl.NewRow();
2220 	}
2221 	else
2222 	{
2223 		UT_DEBUGMSG(("One of those stupid rows without cells found. \n"));
2224 		UT_DEBUGMSG(("Handle it now. RTF totally sucks. \n"));
2225 		if(getTable()) {
2226 			getTable()->removeCurrentRow();
2227 			getDoc()->miniDump(m_lastCellSDH,8);
2228 		}
2229 
2230 		m_bCellBlank = true;
2231 		UT_ASSERT_HARMLESS(0);
2232 	}
2233 //
2234 // Need these for strange barely legal docs like that in bug 4111
2235 //
2236 	m_bCellHandled = false;
2237 	m_bContentFlushed = false;
2238 	m_bRowJustPassed = true;
2239 	m_iStackLevelAtRow = m_stateStack.getDepth();
2240 	m_bDoCloseTable = false;
2241 	m_iNoCellsSinceLastRow = 0;
2242 }
2243 
2244 
HandleNoteReference(void)2245 void IE_Imp_RTF::HandleNoteReference(void)
2246 {
2247 	// see if we have a reference marker pending ...
2248 	const gchar * attribs[3] ={"footnote-id",NULL,NULL};
2249 
2250 	if(!m_bNoteIsFNote)
2251 	{
2252 		attribs[0] = "endnote-id";
2253 	}
2254 	std::string footpid;
2255 	if(m_bInFootnote && !m_bFtnReferencePending)
2256 	{
2257 		if(m_bNoteIsFNote)
2258 		{
2259 			footpid = UT_std_string_sprintf("%i",m_iLastFootnoteId);
2260 		}
2261 		else
2262 		{
2263 			footpid = UT_std_string_sprintf("%i",m_iLastEndnoteId);
2264 		}
2265 		attribs[1] = footpid.c_str();
2266 		UT_DEBUGMSG(("Note anchor %s \n",footpid.c_str()));
2267 		if(m_bNoteIsFNote)
2268 		{
2269 			_appendField ("footnote_anchor",attribs);
2270 			return;
2271 		}
2272 		else
2273 		{
2274 			_appendField ("endnote_anchor",attribs);
2275 			return;
2276 		}
2277 	}
2278 	else if(m_bInFootnote && m_bFtnReferencePending)
2279 	{
2280 		// we have a pending reference mark; since the \footnote
2281 		// has removed the RTF state, we need to temporarily
2282 		// place the saved RTF state on the stack. We pop it afterwards
2283 		RTFStateStore * pSaved = m_currentRTFState.clone();
2284 		m_stateStack.push(pSaved);
2285 		m_stateStack.push(&m_FootnoteRefState);
2286 		m_currentRTFState = m_FootnoteRefState;
2287 		if(m_bNoteIsFNote)
2288 		{
2289 			m_iLastFootnoteId = getDoc()->getUID(UT_UniqueId::Footnote);
2290 			footpid = UT_std_string_sprintf("%i",m_iLastFootnoteId);
2291 		}
2292 		else
2293 		{
2294 			m_iLastEndnoteId = getDoc()->getUID(UT_UniqueId::Endnote);
2295 			footpid = UT_std_string_sprintf("%i",m_iLastEndnoteId);
2296 		}
2297 		attribs[1] = footpid.c_str();
2298 		UT_DEBUGMSG(("Note reference %s \n",footpid.c_str()));
2299 
2300 		if(m_bNoteIsFNote)
2301 		{
2302 			_appendField ("footnote_ref",attribs);
2303 		}
2304 		else
2305 		{
2306 			_appendField ("endnote_ref",attribs);
2307 		}
2308 
2309 		m_bFtnReferencePending = false;
2310 
2311 		// now we pop the saved state off and restore the current state
2312 		RTFStateStore* pState = NULL;
2313 		m_stateStack.pop(reinterpret_cast<void**>(&pState));
2314 		m_stateStack.pop(reinterpret_cast<void**>(&pState));
2315 		m_currentRTFState = *pState;
2316 		DELETEP(pState);
2317 	}
2318 	else
2319 	{
2320 		m_bFtnReferencePending = true;
2321 //
2322 // Save current RTF state.
2323 //
2324 		m_FootnoteRefState = m_currentRTFState;
2325 	}
2326 }
2327 
HandleNote(void)2328 void IE_Imp_RTF::HandleNote(void)
2329 {
2330 
2331 	m_bInFootnote = true;
2332 	if(m_bFtnReferencePending)
2333 	{
2334 		HandleNoteReference();
2335 	}
2336 	else
2337 	{
2338 		// if there is no reference pending, this is a note with a
2339 		// manually set marker; we have to flush characters before
2340 		// inserting the footnote strux
2341 		FlushStoredChars(true);
2342 	}
2343 
2344 	m_iDepthAtFootnote = m_stateStack.getDepth();
2345 	const gchar * attribs[3] ={"footnote-id",NULL,NULL};
2346 
2347 	if(!m_bNoteIsFNote)
2348 	{
2349 		attribs[0] = "endnote-id";
2350 	}
2351 
2352 	std::string footpid;
2353 	if(m_bNoteIsFNote)
2354 	{
2355 	    footpid = UT_std_string_sprintf("%i",m_iLastFootnoteId);
2356 	}
2357 	else
2358 	{
2359 	    footpid = UT_std_string_sprintf("%i",m_iLastEndnoteId);
2360 	}
2361 	attribs[1] = footpid.c_str();
2362 	UT_DEBUGMSG(("Note Strux ID = %s \n", footpid.c_str()));
2363 	UT_DEBUGMSG(("ie_imp_RTF: Handle Footnote now \n"));
2364 
2365 	if(!bUseInsertNotAppend())
2366 	{
2367 		if(m_bNoteIsFNote)
2368 			getDoc()->appendStrux(PTX_SectionFootnote,attribs);
2369 		else
2370 			getDoc()->appendStrux(PTX_SectionEndnote,attribs);
2371 
2372 		UT_DEBUGMSG(("Append block 8 \n"));
2373 		getDoc()->appendStrux(PTX_Block,NULL);
2374 	}
2375 	else
2376 	{
2377 		if(m_bNoteIsFNote)
2378 			insertStrux(PTX_SectionFootnote,attribs,NULL);
2379 		else
2380 			insertStrux(PTX_SectionEndnote,attribs,NULL);
2381 
2382 		UT_DEBUGMSG((" Insert Block at 7 \n"));
2383 		markPasteBlock();
2384 		insertStrux(PTX_Block);
2385 	}
2386 }
2387 
2388 
HandleAnnotation(void)2389 void IE_Imp_RTF::HandleAnnotation(void)
2390 {
2391 	UT_return_if_fail(m_pAnnotation);
2392 	if(m_bInAnnotation)
2393 	{
2394 		UT_DEBUGMSG(("Recursive call to HandleAnnotion \n"));
2395 		return;
2396 	}
2397 	m_bInAnnotation = true;
2398 	std::string sAnnNum = UT_std_string_sprintf("%d",m_pAnnotation->m_iAnnNumber);
2399 	const char * ann_attrs[5] = {NULL,NULL,NULL,NULL,NULL};
2400 	ann_attrs[0] = "annotation-id";
2401 	ann_attrs[1] = sAnnNum.c_str();
2402 	ann_attrs[2] = 0;
2403 	ann_attrs[3] = 0;
2404 	const char * pszAnn[7] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL};
2405 	UT_sint32 i = 0;
2406 	if(m_pAnnotation->m_sAuthor.size() > 0)
2407 	{
2408 		pszAnn[i] = "annotation-author";
2409 		i++;
2410 		pszAnn[i] = m_pAnnotation->m_sAuthor.utf8_str();
2411 		i++;
2412 	}
2413 	if(m_pAnnotation->m_sTitle.size() > 0)
2414 	{
2415 		pszAnn[i] = "annotation-title";
2416 		i++;
2417 		pszAnn[i] = m_pAnnotation->m_sTitle.utf8_str();
2418 		i++;
2419 	}
2420 	if(m_pAnnotation->m_sDate.size() > 0)
2421 	{
2422 		pszAnn[i] = "annotation-date";
2423 		i++;
2424 		pszAnn[i] = m_pAnnotation->m_sDate.utf8_str();
2425 		i++;
2426 	}
2427 	if(!bUseInsertNotAppend())
2428 	{
2429 		PD_Document * doc = getDoc();
2430 		m_pDelayedFrag = m_pAnnotation->m_pInsertFrag->getNext();
2431 		if(!m_pDelayedFrag)
2432 			m_pDelayedFrag = doc->getLastFrag();
2433 		UT_DEBUGMSG(("Delayed Frag set to %p \n",m_pDelayedFrag));
2434 		ann_attrs[2] = PT_PROPS_ATTRIBUTE_NAME;
2435 		UT_sint32 k = 0;
2436 		std::string sProperties;
2437 		for(k=0; k<i;k++)
2438 		{
2439 			sProperties += pszAnn[k];
2440 			k++;
2441 			sProperties += ":";
2442 			sProperties += pszAnn[k];
2443 			k++;
2444 			if(k < i)
2445 				sProperties += ";";
2446 		}
2447 		ann_attrs[3] = sProperties.c_str();
2448 		UT_DEBUGMSG(("Appending annotation strux, props are %s \n", sProperties.c_str()));
2449 		FlushStoredChars();
2450 		if(!m_pDelayedFrag)
2451 			m_pDelayedFrag = doc->getLastFrag();
2452 		doc->insertStruxBeforeFrag(m_pDelayedFrag,PTX_SectionAnnotation,ann_attrs);
2453 		doc->insertStruxBeforeFrag(m_pDelayedFrag,PTX_Block,NULL);
2454 	}
2455 	else
2456 	{
2457 		m_posSavedDocPosition = m_dposPaste;
2458 		xxx_UT_DEBUGMSG(("Initial Saved doc Postion %d \n",	m_posSavedDocPosition));
2459 		m_dposPaste = m_pAnnotation->m_Annpos+1;
2460 		xxx_UT_DEBUGMSG((" Insert Annotation m_dposPaste %d \n",m_dposPaste));
2461 		insertStrux(PTX_SectionAnnotation,ann_attrs,pszAnn);
2462 		UT_DEBUGMSG((" Insert Block at 7 \n"));
2463 		markPasteBlock();
2464 		insertStrux(PTX_Block);
2465 		xxx_UT_DEBUGMSG(("After first strux insert  Saved doc Postion %d \n",m_posSavedDocPosition));
2466 	}
2467 }
2468 
2469 
2470 
_parseText()2471 UT_Error IE_Imp_RTF::_parseText()
2472 {
2473 	bool ok = true;
2474     int cNibble = 2;
2475 	int b = 0;
2476 	unsigned char c;
2477 
2478 	// remember the depth of stack on entry, and if the depth of stack
2479 	// drops bellow this level return (this is so that we can call
2480 	// this method recursively)
2481 	UT_sint32 iRTFStackDepth = m_stateStack.getDepth();
2482 	UT_DEBUGMSG(("IE_Imp_RTF::_parseText: stack depth %d\n", iRTFStackDepth));
2483 
2484 
2485 	while (ok  &&  m_stateStack.getDepth() >= iRTFStackDepth && ReadCharFromFile(&c))
2486 	{
2487 		if (m_currentRTFState.m_internalState == RTFStateStore::risBin)
2488 		{
2489 			// if we're parsing binary data, handle it directly
2490 			ok = ParseChar(c);
2491 		}
2492 		else
2493 		{
2494 			if(m_bFootnotePending && c != '\\')
2495 			{
2496 				// not followed by a keyword, this is an ordinary
2497 				// footnote
2498 				m_bNoteIsFNote = true;
2499 				HandleNote();
2500 				m_bFootnotePending = false;
2501 			}
2502 			else if(m_bFootnotePending && c == '\\')
2503 			{
2504 				// need to see if the keyword is \ftnalt indicating
2505 				// endnote
2506 				unsigned char keyword[MAX_KEYWORD_LEN];
2507 				UT_sint32 parameter = 0;
2508 				bool parameterUsed = false;
2509 				if (ReadKeyword(keyword, &parameter, &parameterUsed, MAX_KEYWORD_LEN))
2510 				{
2511 					if(0 == strcmp((const char*)&keyword[0], "ftnalt"))
2512 					{
2513 						UT_DEBUGMSG(("Have Endnote \n"));
2514 						// we have an end-note
2515 						m_bNoteIsFNote = false;
2516 						HandleNote();
2517 						m_bFootnotePending = false;
2518 						continue;
2519 					}
2520 					else
2521 					{
2522 						// we have some other keyword ...
2523 						m_bNoteIsFNote = true;
2524 						HandleNote();
2525 						m_bFootnotePending = false;
2526 
2527 						TranslateKeyword(keyword, parameter, parameterUsed);
2528 						continue;
2529 					}
2530 				}
2531 				else
2532 				{
2533 					// something seriously wrong ...
2534 					UT_DEBUGMSG(("RTF: could not read keyword (l: %d)\n", __LINE__));
2535 					continue;
2536 				}
2537 			}
2538 			else if(m_pAnnotation && (m_pAnnotation->m_iRTFLevel > 0) && !m_bInAnnotation && (c != '\\') && (c != '{') && (c != '}'))
2539 			{
2540 				SkipBackChar(c);
2541 				HandleAnnotation();
2542 				continue;
2543 			}
2544 
2545 			switch (c)
2546 			{
2547 			case '{':
2548 				ok = PushRTFState();
2549 				if (!ok) {
2550 					UT_DEBUGMSG(("PushRTFState()\n"));
2551 				}
2552 				break;
2553 			case '}':
2554 			{
2555 				ok = PopRTFState();
2556 				if (!ok) {
2557 					UT_DEBUGMSG(("PopRTFState() bug\n"));
2558 					bool bCont = true;
2559 					char lastc =c;
2560 					while(ReadCharFromFile(&c) && bCont)
2561 					{
2562 						lastc = c;
2563 						bCont = (c == '}');
2564 					}
2565 					if(lastc == '}') // reached end of file with extra "}"
2566 					{
2567 						ok = true;
2568 						break;
2569 					}
2570 					return UT_IE_TRY_RECOVER; // try to finish the import anyway
2571 				}
2572 				setEncoding(); // Reset encoding from current state.
2573 			}
2574 				break;
2575 			case '\\':
2576 			{
2577 				ok = ParseRTFKeyword();
2578 
2579 				if (!ok) {
2580 					UT_DEBUGMSG(("ParseRTFKeyword() failed import aborted \n"));
2581 					UT_DEBUGMSG(("Last valid keyword was %s \n",g_dbgLastKeyword));
2582 				}
2583 				break;
2584 			}
2585 
2586 			default:
2587 				if (m_currentRTFState.m_internalState == RTFStateStore::risNorm)
2588 				{
2589 					ok = ParseChar(c, false);
2590 					if (!ok) {
2591 						UT_DEBUGMSG(("ParseChar()\n"));
2592 					}
2593 				}
2594 				else
2595 				{
2596 					UT_return_val_if_fail(m_currentRTFState.m_internalState == RTFStateStore::risHex, UT_ERROR);
2597 
2598 					b = b << 4;
2599 					int digit;
2600 
2601 					// hexval calls digval
2602  					ok = hexVal(static_cast<char>(c), digit);
2603 					b += digit;
2604 					cNibble--;
2605 					if (!cNibble  &&  ok)
2606 					{
2607 						ok = ParseChar(b, false);
2608 						if (!ok) {
2609 							UT_DEBUGMSG(("ParseChar()\n"));
2610 						}
2611 						cNibble = 2;
2612 						b = 0;
2613 						m_currentRTFState.m_internalState = RTFStateStore::risNorm;
2614 						// actually don't handle the following space since
2615 						// this is NOT a delimiter
2616 						// see bug #886
2617 					}
2618 				}
2619 			}
2620 		}
2621 
2622 		if(getLoadStylesOnly() && m_bStyleImportDone)
2623 			break;
2624 	}
2625 
2626 	if (ok && !getLoadStylesOnly())
2627 	{
2628 		// do not force this -- a correctly formed rtf document should end in \par keyword
2629 		// so m_newParaFlagged will be set, but there will be nothing in the buffer, so no
2630 		// para should be output. If the doc is malformed and there is some stuff after
2631 		// the last \par, it will be output.
2632 		ok = FlushStoredChars(false);
2633 		if (!ok) {
2634 			UT_DEBUGMSG(("FlushStoredChars()\n"));
2635 		}
2636 	}
2637 
2638 	/* m_stateStack.getDepth() == 0 if the functions PushRTFState and PopRTFState
2639 	   have been called the same number of times. Each call to PushRTFState on an
2640 	   opening bracket ("{") should be followed by a call to PopRTFState on the
2641 	   corresponding closing bracket ("}"). This check is done only if the function
2642 	   has not been called recursively (iRTFStackDepth == 0).*/
2643 	UT_ASSERT((m_stateStack.getDepth() == 0) || (iRTFStackDepth > 0));
2644 
2645 //	UT_DEBUGMSG(("dumping document\n"));
2646 //	getDoc()->__dump(stderr);
2647 	return ok ? UT_OK : UT_ERROR;
2648 
2649 }
2650 
2651 /*
2652    Scans the entire document for any rtl tokens and set m_bBidiMode
2653    accordingly. Please note that this results in a minimal performance
2654    loss (a fraction of a second on a 30 page doc), and saves us much
2655    work and time if the document is LTR-only.
2656 */
_isBidiDocument()2657 UT_Error IE_Imp_RTF::_isBidiDocument()
2658 {
2659 	UT_return_val_if_fail(m_pImportFile, UT_ERROR);
2660 
2661 	char buff[8192 + 1];
2662 	char * token = NULL;
2663 
2664 	size_t iBytes = UT_MIN(8192, gsf_input_remaining(m_pImportFile));
2665 	gsf_input_read(m_pImportFile, iBytes, (guint8*)buff);
2666 
2667 	UT_DEBUGMSG(("IE_Imp_RTF::_isBidiDocument: looking for RTL tokens\n"));
2668 	while (iBytes)
2669 	{
2670 		buff[iBytes] = 0;
2671 		token = strstr(buff, "rtlsect");
2672 		if(token)
2673 		{
2674 			break;
2675 		}
2676 
2677 		token = strstr(buff, "rtlpar");
2678 		if(token)
2679 			break;
2680 
2681 		token = strstr(buff, "rtlch");
2682 		if(token)
2683 			break;
2684 
2685 		iBytes = UT_MIN(8192, gsf_input_remaining(m_pImportFile));
2686 		gsf_input_read(m_pImportFile, iBytes, (guint8*)buff);
2687 	}
2688 
2689 	if(token)
2690 	{
2691 		UT_DEBUGMSG(("IE_Imp_RTF::_isBidiDocument: found rtl token [%s]\n", token));
2692 		m_bBidiMode = true;
2693 	}
2694 	else
2695 	{
2696 		UT_DEBUGMSG(("IE_Imp_RTF::_isBidiDocument: no rtl token found\n"));
2697 		m_bBidiMode = false;
2698 	}
2699 
2700 
2701 	// reset the file pointer to the beginning
2702 	if(gsf_input_seek(m_pImportFile, 0, G_SEEK_SET))
2703 		return UT_ERROR;
2704 
2705 	UT_DEBUGMSG(("IE_Imp_RTF::_isBidiDocument: looking for RTL tokens -- done\n"));
2706 	return UT_OK;
2707 }
2708 
2709 
2710 
_parseFile(GsfInput * fp)2711 UT_Error IE_Imp_RTF::_parseFile(GsfInput* fp)
2712 {
2713 	m_pImportFile = fp;
2714 
2715 	m_currentRTFState.m_internalState = RTFStateStore::risNorm;
2716 	m_currentRTFState.m_destinationState = RTFStateStore::rdsNorm;
2717 	m_currentHdrID = 0;
2718 	m_currentFtrID = 0;
2719 	m_currentHdrEvenID = 0;
2720 	m_currentFtrEvenID = 0;
2721 	m_currentHdrFirstID = 0;
2722 	m_currentFtrFirstID = 0;
2723 	m_currentHdrLastID = 0;
2724 	m_currentFtrLastID = 0;
2725 #if 0
2726 	if(m_pImportFile && UT_OK != _isBidiDocument())
2727 		return UT_ERROR;
2728 #endif
2729 	if(m_pImportFile && !getLoadStylesOnly())
2730 	{
2731 		// need to init docs Attributes and props
2732 		getDoc()->setAttrProp(NULL);
2733 	}
2734 
2735 //
2736 // OK Set the Default page size, in case it isn't set in RTF
2737 //
2738 	if(!getLoadStylesOnly() && !m_parsingHdrFtr)
2739 	{
2740 		double width = 12240./1440.; // default width in twips
2741 		double height = 15840./1440; // default height in twips
2742 		if(fp != NULL)
2743 		{
2744 			getDoc()->m_docPageSize.Set(width,height,DIM_IN);
2745 		}
2746 	}
2747 	return _parseText();
2748 }
2749 
2750 /*****************************************************************/
2751 /*****************************************************************/
2752 
HandleParKeyword()2753 bool IE_Imp_RTF::HandleParKeyword()
2754 {
2755 	// NB: the \par keyword really represents '\r' and concludes a paragraph rather than
2756 	// begins it -- some paragraph properties are indicated by formating applied to the
2757 	// \par keyword, for example revisions are. This means that we sometimes have to
2758 	// change fmt of the last block
2759 
2760 	if(!m_bSectionHasPara || m_newParaFlagged)
2761 	{
2762 		if(m_newSectionFlagged)
2763 			ApplySectionAttributes();
2764 
2765 		m_newSectionFlagged = false;
2766 
2767 		ApplyParagraphAttributes();
2768 
2769 		//getDoc()->appendStrux(PTX_Block,NULL); // FIXME 28/3/2005!
2770 		m_newParaFlagged = false;
2771 		m_bSectionHasPara = true;
2772 	}
2773 	std::string sProps;
2774 	int attrsIdx = 0;
2775 	const gchar * attrs[7] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL};
2776 	const gchar * props = NULL;
2777 	std::string rev;
2778 
2779 	UT_return_val_if_fail( buildCharacterProps(sProps), false);
2780 	props = sProps.c_str();
2781 
2782 	if(m_currentRTFState.m_charProps.m_eRevision != PP_REVISION_NONE)
2783 	{
2784 		std::string aStyle;
2785 
2786 		if(m_currentRTFState.m_charProps.m_styleNumber >= 0
2787 		   && static_cast<UT_uint32>(m_currentRTFState.m_charProps.m_styleNumber) < m_styleTable.size())
2788 		{
2789 			aStyle = m_styleTable[m_currentRTFState.m_charProps.m_styleNumber];
2790 		}
2791 
2792 		_formRevisionAttr(rev, sProps, aStyle);
2793 		attrs[attrsIdx++] = "revision";
2794 		attrs[attrsIdx++] = rev.c_str();
2795 		props = NULL;
2796 	}
2797 
2798 	if((props && *props) || attrs[0])
2799 	{
2800 		if(m_pImportFile)
2801 		{
2802 			UT_return_val_if_fail(getDoc()->appendLastStruxFmt(PTX_Block, attrs, props,true), false);
2803 		}
2804 		else
2805 		{
2806 			if(!getDoc()->isEndTableAtPos(m_dposPaste))
2807 			{
2808 				UT_return_val_if_fail(getDoc()->changeLastStruxFmtNoUndo(m_dposPaste, PTX_Block, attrs, props, true),false );
2809 			}
2810 		}
2811 
2812 	}
2813 
2814 	return StartNewPara();
2815 }
2816 
2817 // flush any remaining text in the previous para and flag
2818 // a new para to be started.  Don't actually start a new
2819 // para as it may turn out to be empty
2820 //
StartNewPara()2821 bool IE_Imp_RTF::StartNewPara()
2822 {
2823 	// force this, if new para is flagge:d (so we import empty paragraphs)
2824 	// if it is not, then we do not flagged, then we do not want new block appended (it
2825 	// has already been done somewhere else
2826 	bool ok = FlushStoredChars(m_newParaFlagged);
2827 	m_newParaFlagged = true;
2828 
2829 	// need to reset any left-over direction override
2830 	m_currentRTFState.m_charProps.m_dirOverride = UT_BIDI_UNSET;
2831 	return ok;
2832 }
2833 
2834 
2835 // flush any remaining text in the previous sction and
2836 // flag a new section to be started.  Don't actually
2837 // start a new section as it may turn out to be empty
2838 //
StartNewSection()2839 bool IE_Imp_RTF::StartNewSection()
2840 {
2841 	// force this, if new para is flagged (so we import empty paragraphs)
2842 	// if it is not, then we do not flagged, then we do not want new block appended (it
2843 	// has already been done somewhere else
2844 	bool ok = FlushStoredChars(m_newParaFlagged);
2845 
2846 	m_newSectionFlagged = true;
2847 	m_newParaFlagged = true;
2848 	m_bSectionHasPara = false;
2849 	return ok;
2850 }
2851 
2852 
2853 // add a new character.  Characters are actually cached and
2854 // inserted into the document in batches - see FlushStoredChars
2855 //
AddChar(UT_UCSChar ch)2856 bool IE_Imp_RTF::AddChar(UT_UCSChar ch)
2857 {
2858 	if(!m_gbBlock.ins(m_gbBlock.getLength(), reinterpret_cast<UT_GrowBufElement*>(&ch), 1))
2859 		return false;
2860 
2861 	return true;
2862 }
2863 
2864 /*!
2865  * returns true if we've pasted a table strux and have not yet pasted a cell
2866  * or we've pasted an endcell and have not yet pasted a cell
2867  */
isPastedTableOpen(void)2868 bool IE_Imp_RTF::isPastedTableOpen(void)
2869 {
2870 	ABI_Paste_Table * pPaste = NULL;
2871 	if(m_pasteTableStack.getDepth() == 0)
2872 	{
2873 		return false;
2874 	}
2875 	m_pasteTableStack.viewTop(reinterpret_cast<void **>(&pPaste));
2876 	if(pPaste == NULL)
2877 	{
2878 		return false;
2879 	}
2880 	if(!pPaste->m_bHasPastedCellStrux)
2881 	{
2882 		return true;
2883 	}
2884 	if(!pPaste->m_bHasPastedTableStrux)
2885 	{
2886 		return false;
2887 	}
2888 	return false;
2889 }
2890 
2891 // flush any stored text into the document
2892 //
FlushStoredChars(bool forceInsertPara)2893 bool IE_Imp_RTF::FlushStoredChars(bool forceInsertPara)
2894 {
2895 
2896 	// start a new para if we have to
2897 	bool ok = true;
2898 //
2899 // Don't insert anything if we're between a table strux and a cell or between
2900 // cell's
2901 //
2902 	xxx_UT_DEBUGMSG(("Level at check %d \n",m_stateStack.getDepth()));
2903 	if(isPastedTableOpen() && !forceInsertPara)
2904 	{
2905 		return true;
2906 	}
2907 	if (m_newSectionFlagged && (forceInsertPara || (m_gbBlock.getLength() > 0)) )
2908 	{
2909 		m_bContentFlushed = true;
2910 		ok = ApplySectionAttributes();
2911 		m_newSectionFlagged = false;
2912 	}
2913 	if (ok  && m_newParaFlagged  &&  (forceInsertPara  ||  (m_gbBlock.getLength() > 0)) )
2914 	{
2915 		bool bSave = m_newParaFlagged;
2916 		m_newParaFlagged = false;
2917 		ok = ApplyParagraphAttributes();
2918 		if(m_gbBlock.getLength() == 0)
2919 		{
2920 //
2921 // This forces empty lines to have the same height as the previous line
2922 //
2923 			m_newParaFlagged = bSave;
2924 			if(!bUseInsertNotAppend())
2925 			{
2926 				getDoc()->appendFmtMark();
2927 			}
2928 		}
2929 		m_newParaFlagged = false;
2930 
2931 	}
2932 
2933 	if (ok  &&  (m_gbBlock.getLength() > 0))
2934 	{
2935 		if(ok && m_bCellBlank && (getTable() != NULL))
2936 		{
2937 			ok = ApplyParagraphAttributes();
2938 			if(m_newParaFlagged || m_bCellBlank)
2939 			{
2940 				UT_DEBUGMSG(("Append block 10 \n"));
2941 				if(m_pDelayedFrag)
2942 				{
2943 					getDoc()->insertStruxBeforeFrag(m_pDelayedFrag,PTX_Block,NULL);
2944 				}
2945 				else
2946 				{
2947 					getDoc()->appendStrux(PTX_Block,NULL);
2948 				}
2949 			}
2950 			m_bSectionHasPara = true;
2951 			m_bCellBlank = false;
2952 			m_bEndTableOpen = false;
2953 		}
2954 		else if( ok && m_bEndTableOpen)
2955 		{
2956 			UT_DEBUGMSG(("Append block 11 \n"));
2957 
2958 			if(m_pDelayedFrag)
2959 			{
2960 				getDoc()->insertStruxBeforeFrag(m_pDelayedFrag,PTX_Block,NULL);
2961 			}
2962 			else
2963 			{
2964 				getDoc()->appendStrux(PTX_Block,NULL);
2965 			}
2966 			m_bSectionHasPara = true;
2967 			m_bEndTableOpen = false;
2968 		}
2969 		ok = ApplyCharacterAttributes();
2970 		m_bCellBlank = false;
2971 	}
2972 	if( ok && m_bInFootnote && (m_stateStack.getDepth() < m_iDepthAtFootnote))
2973 	{
2974 		if(!bUseInsertNotAppend())
2975 		{
2976 			if(m_bNoteIsFNote)
2977 				getDoc()->appendStrux(PTX_EndFootnote,NULL);
2978 			else
2979 				getDoc()->appendStrux(PTX_EndEndnote,NULL);
2980 
2981 		}
2982 		else
2983 		{
2984 			if(m_bNoteIsFNote)
2985 				ok = insertStrux(PTX_EndFootnote);
2986 			else
2987 				ok = insertStrux(PTX_EndEndnote);
2988 			if(	m_bMovedPos)
2989 			{
2990 				m_bMovedPos = false;
2991 				m_dposPaste += m_dPosBeforeFootnote; // restore old position
2992 			}
2993 		}
2994 		m_bInFootnote = false;
2995 		m_iDepthAtFootnote = 0;
2996 	}
2997 	xxx_UT_DEBUGMSG(("Annotation level at check %d \n",m_stateStack.getDepth()));
2998     if(ok && m_bInAnnotation && m_pAnnotation && (m_stateStack.getDepth() < m_pAnnotation->m_iRTFLevel))
2999 		{
3000 			//
3001 			// Wind up the annotation
3002 			m_bInAnnotation = false;
3003 			xxx_UT_DEBUGMSG(("Finishing up the annotation depth %d RTFlevel %d \n",m_stateStack.getDepth(), m_pAnnotation->m_iRTFLevel ));
3004 			if(!bUseInsertNotAppend())
3005 			{
3006 				FlushStoredChars();
3007 				getDoc()->insertStruxBeforeFrag(m_pDelayedFrag,PTX_EndAnnotation,NULL);
3008 
3009 			}
3010 			else
3011 			{
3012 				xxx_UT_DEBUGMSG(("Inserting EndAnnoation at %d \n",m_dposPaste));
3013 				getDoc()->insertStrux(m_dposPaste,PTX_EndAnnotation,NULL,NULL);
3014 				if(m_posSavedDocPosition > m_dposPaste)
3015 					m_posSavedDocPosition++;
3016 				m_dposPaste++;
3017 
3018 			}
3019 			EndAnnotation();
3020 			DELETEP(m_pAnnotation);
3021 			m_pDelayedFrag = NULL;
3022 			xxx_UT_DEBUGMSG(("After complete annotation Saved doc Postion %d \n",m_posSavedDocPosition));
3023 			m_dposPaste = m_posSavedDocPosition;
3024 			m_posSavedDocPosition = 0;
3025 			xxx_UT_DEBUGMSG(("Annotation insert complete \n"));
3026 		}
3027 //	if( ok && m_bFrameOpen && (static_cast<UT_sint32>(m_stateStack.getDepth()) < m_iStackDepthAtFrame))
3028 //	{
3029 //		HandleEndShape();
3030 //	}
3031 	return ok;
3032 }
3033 
3034 
3035 // Get a font out of the font table, making sure we dont attempt to access off the end
GetNthTableFont(UT_sint32 fontNum)3036 RTFFontTableItem* IE_Imp_RTF::GetNthTableFont(UT_sint32 fontNum)
3037 {
3038 	if (static_cast<UT_uint32>(fontNum) < m_fontTable.size())
3039 	{
3040 		return m_fontTable.at(fontNum);
3041 	}
3042 	else
3043 	{
3044 		return NULL;
3045 	}
3046 }
3047 
3048 
3049 // Get a colour out of the colour table, making sure we dont attempt to access off the end
GetNthTableColour(UT_sint32 colNum)3050 UT_uint32 IE_Imp_RTF::GetNthTableColour(UT_sint32 colNum)
3051 {
3052 	if (static_cast<UT_uint32>(colNum) < m_colourTable.size())
3053 	{
3054 		return m_colourTable.at(colNum);
3055 	}
3056 	else
3057 	{
3058 		return 0;	// black
3059 	}
3060 }
3061 
GetNthTableBgColour(UT_sint32 colNum)3062 UT_sint32 IE_Imp_RTF::GetNthTableBgColour(UT_sint32 colNum)
3063 {
3064 	if (static_cast<UT_uint32>(colNum) < m_colourTable.size())
3065 	{
3066 		return m_colourTable.at(colNum);
3067 	}
3068 	else
3069 	{
3070 		return -1;	// invalid
3071 	}
3072 }
3073 
3074 
3075 // Process a single character from the RTF stream
3076 //
ParseChar(UT_UCSChar ch,bool no_convert)3077 bool IE_Imp_RTF::ParseChar(UT_UCSChar ch,bool no_convert)
3078 {
3079     // Have we reached the end of the binary skip?
3080 	if (m_currentRTFState.m_internalState == RTFStateStore::risBin  && --m_cbBin <= 0)
3081 	{
3082 		m_currentRTFState.m_internalState = RTFStateStore::risNorm;
3083 	}
3084 	switch (m_currentRTFState.m_destinationState)
3085 	{
3086 		case RTFStateStore::rdsSkip:
3087 			// Toss this character.
3088 			return true;
3089 		case RTFStateStore::rdsNorm:
3090 
3091 			if (m_currentRTFState.m_unicodeInAlternate > 0)
3092 			{
3093 				m_currentRTFState.m_unicodeInAlternate--;
3094 				return true;
3095 			}
3096 			// Insert a character into the story
3097             if ((ch >= 32  ||  ch == 9 || ch == UCS_FF || ch == UCS_LF || ch == UCS_VTAB)  &&  !m_currentRTFState.m_charProps.m_deleted)
3098 			{
3099 				if (!no_convert && ch<=0xff)
3100 				{
3101 					UT_UCS4Char wc;
3102 					// TODO Doesn't handle multibyte encodings (CJK)
3103 					if (m_mbtowc.mbtowc(wc,static_cast<UT_Byte>(ch)))
3104 						return AddChar(wc);
3105 				} else
3106 					return AddChar(ch);
3107 			}
3108 		default:
3109 			// handle other destinations....
3110 			return true;
3111 	}
3112 	UT_DEBUGMSG (("went thru all ParseChar() without doing anything\n"));
3113 	return true;
3114 }
3115 
3116 
3117 /*!
3118   Reads and proccesses a RTF control word and its parameter
3119   \return false if something goes wrong.
3120   \desc Read and handle the RTF keyword. Commands are dispatched by calling
3121   TranslateKeyword
3122   \fixme This is too generic: keywords are most of the time contextual
3123   so context should be taken care of.
3124   \see IE_Imp_RTF::ReadKeyword, IE_Imp_RTF::TranslateKeyword
3125 */
ParseRTFKeyword()3126 bool IE_Imp_RTF::ParseRTFKeyword()
3127 {
3128 	unsigned char keyword[MAX_KEYWORD_LEN];
3129 	UT_sint32 parameter = 0;
3130 	bool parameterUsed = false;
3131 	if (ReadKeyword(keyword, &parameter, &parameterUsed, MAX_KEYWORD_LEN))
3132 	{
3133 		xxx_UT_DEBUGMSG(("SEVIOR: keyword = %s  par= %d \n",keyword,parameter));
3134 		bool bres = TranslateKeyword(keyword, parameter, parameterUsed);
3135 		if(!bres)
3136 		{
3137 			UT_DEBUGMSG(("SEVIOR: error in translation last valid %s \n",g_dbgLastKeyword));
3138 		}
3139 		return bres;
3140 	}
3141 	else
3142 	{
3143 		UT_DEBUGMSG(("Error in ReadKeyword Last vaild %s \n",g_dbgLastKeyword));
3144 		return false;
3145 	}
3146 }
3147 
3148 
3149 /*!
3150   Read a keyword from the file.
3151   \retval pKeyword the keyword buffer whose len is in keywordBuffLen
3152   Can not be NULL on input.
3153   \retval pParam the keyword parameter as specified by the RTF spec. 0
3154   is there is no param.
3155   \retval pParamUsed true if the keyword does really have a param. false
3156   otherwise (pParam is 0 then).
3157   \param keywordBuffLen the length of the pKeyword memory block
3158   \return false if any problem
3159   \desc This function parse and read the keyword. It is called if a
3160   \\ is encountered in the flow. *pKeyword never contains the \\
3161  */
ReadKeyword(unsigned char * pKeyword,UT_sint32 * pParam,bool * pParamUsed,UT_uint32 keywordBuffLen)3162 bool IE_Imp_RTF::ReadKeyword(unsigned char* pKeyword, UT_sint32* pParam, bool* pParamUsed, UT_uint32 keywordBuffLen)
3163 {
3164 	bool fNegative = false;
3165 	*pParam = 0;
3166 	*pParamUsed = false;
3167 	*pKeyword = 0;
3168 	const unsigned int max_param = 256;
3169 	unsigned char parameter[max_param];
3170 	unsigned int count = 0;
3171 	unsigned char * savedKeyword = pKeyword;
3172 
3173 	// Read the first character of the control word
3174 	unsigned char ch;
3175 	if (!ReadCharFromFileWithCRLF(&ch))
3176 		return false;
3177 
3178 	UT_return_val_if_fail(keywordBuffLen > 1, false);
3179 	--keywordBuffLen;
3180 
3181 	// If it's a control symbol there is no delimiter, its just one character
3182 	if (!isalpha(ch))
3183 	{
3184 		pKeyword[0] = ch;
3185 		pKeyword[1] = 0;
3186 		return true;
3187 	}
3188 
3189 	// Read in the rest of the control word
3190 	while (isalpha(ch))
3191 	{
3192 		if (0 == --keywordBuffLen)
3193 		{
3194 			UT_DEBUGMSG(("Keyword too large. Bogus RTF!\n"));
3195 			return false;
3196 		}
3197 		xxx_UT_DEBUGMSG(("|%c|\n",ch));
3198 		*pKeyword = ch;
3199 		pKeyword++;
3200 		if (!ReadCharFromFileWithCRLF(&ch))
3201 			return false;
3202 	}
3203 	*pKeyword = 0;
3204 	xxx_UT_DEBUGMSG(("keyword %s \n",savedKeyword));
3205     // If the delimeter was '-' then the following parameter is negative
3206     if (ch == '-')
3207     {
3208         fNegative = true;
3209 		if (!ReadCharFromFileWithCRLF(&ch))
3210 			return false;
3211     }
3212 
3213     // Read the numeric parameter (if there is one)
3214 	// According to the specs, a dttm parameter (e.g. \revdttm), which is a long, has the
3215 	// individual bytes emited as ASCII characters
3216 	//
3217 	// Some * keywords have the numeric parameter after a space
3218 	// We need to hand this special case. Stupid RTF!!
3219 	//
3220 	bool bLeadSpace = true;
3221 	if (isdigit(ch) || (bLeadSpace && m_currentRTFState.m_bInKeywordStar && (ch == ' ')))
3222 	{
3223 
3224 		if(isdigit(ch))
3225 		{
3226 			bLeadSpace=false;
3227 		}
3228 		*pParamUsed = true;
3229 		while (isdigit(ch) || (bLeadSpace && (ch == ' ' )))
3230 		{
3231 
3232 			if(isdigit(ch))
3233 			{
3234 				bLeadSpace=false;
3235 			}
3236 
3237 			xxx_UT_DEBUGMSG(("|%c|\n",ch));
3238 			// Avoid buffer overflow
3239 			if (count == max_param )
3240 			{
3241 				xxx_UT_DEBUGMSG(("Parameter too large. Bogus RTF!\n"));
3242 				return false;
3243 			}
3244 			if(ch != ' ')
3245 				parameter[count++] = ch;
3246 			if (!ReadCharFromFileWithCRLF(&ch))
3247 				return false;
3248 		}
3249 		parameter[count] = 0;
3250 		xxx_UT_DEBUGMSG(("parameter %s \n",parameter));
3251 		*pParam = atol(reinterpret_cast<char*>(&parameter[0]));
3252 		if (fNegative)
3253 			*pParam = -*pParam;
3254 	}
3255 
3256 	// If the delimeter was non-whitespace then this character is part of the following text!
3257 	if ((ch != ' ') && (ch != 10) && (ch != 13))
3258 	{
3259 		SkipBackChar(ch);
3260 	}
3261 
3262 	strcpy(g_dbgLastKeyword, (const char *)savedKeyword);
3263 	g_dbgLastParam = *pParam;
3264 	xxx_UT_DEBUGMSG(("Valid Keyword %s Here \n",savedKeyword));
3265 	return true;
3266 }
3267 
3268 /*!
3269   Reads a character from the file. Doesn't ignore CR and LF
3270   \retval pCh the char read
3271   \return false if an error occured.
3272   \see IE_Imp_RTF::ReadCharFromFile
3273 */
ReadCharFromFileWithCRLF(unsigned char * pCh)3274 bool IE_Imp_RTF::ReadCharFromFileWithCRLF(unsigned char* pCh)
3275 {
3276 	bool ok = false;
3277 
3278 	if (m_pImportFile)					// if we are reading a file
3279 	{
3280 		if (gsf_input_read(m_pImportFile, 1, pCh) != NULL)
3281 		{
3282 			ok = true;
3283 		}
3284 	}
3285 	else								// else we are pasting from a buffer
3286 	{
3287 		if (m_pCurrentCharInPasteBuffer < m_pPasteBuffer+m_lenPasteBuffer)
3288 		{
3289 			*pCh = *m_pCurrentCharInPasteBuffer++;
3290 			ok = true;
3291 		}
3292 	}
3293 
3294 	return ok;
3295 }
3296 
ReadContentFromFile(UT_UTF8String & str)3297 bool IE_Imp_RTF::ReadContentFromFile(UT_UTF8String & str)
3298 {
3299 	unsigned char pCh = 0;
3300 	do
3301 	{
3302 		if (ReadCharFromFileWithCRLF(&pCh) == false)
3303 		{
3304 			return false;
3305 		}
3306 		if(pCh != 10 &&  pCh != 13 && pCh != '}')
3307 			str += pCh;
3308 	} while ((pCh == 10  ||  pCh == 13)  || (pCh != '}'));
3309 	if(pCh == '}')
3310 		SkipBackChar('}');
3311 	return true;
3312 
3313 }
3314 
3315 /*!
3316   Reads a character from the file ignoring CR and LF
3317   \retval pCh the char read
3318   \return false if an error occured.
3319   \see IE_Imp_RTF::ReadCharFromFileWithCRLF
3320 */
ReadCharFromFile(unsigned char * pCh)3321 bool IE_Imp_RTF::ReadCharFromFile(unsigned char* pCh)
3322 {
3323 	// line feed and cr should be ignored in RTF files
3324 	do
3325 	{
3326 		if (ReadCharFromFileWithCRLF(pCh) == false)
3327 		{
3328 			return false;
3329 		}
3330 	} while (*pCh == 10  ||  *pCh == 13);
3331 
3332 	return true;
3333 
3334 }
3335 
3336 
ReadHexChar(void)3337 UT_UCS4Char IE_Imp_RTF::ReadHexChar(void)
3338 {
3339 	UT_UCS4Char wc = 0;
3340 	unsigned char ch;
3341 	int val;
3342 
3343 	if (ReadCharFromFile(&ch))
3344 	{
3345 		if (hexVal(ch, val)) {
3346 			wc = val << 4;
3347 		}
3348 		else {
3349 			UT_DEBUGMSG(("invalid Hex %c\n", ch));
3350 		}
3351 		if (ReadCharFromFile(&ch))
3352 		{
3353 			if (hexVal(ch, val)) {
3354 				wc += val;
3355 			}
3356 			else {
3357 				UT_DEBUGMSG(("invalid Hex %c\n", ch));
3358 			}
3359 		}
3360 	}
3361 	return wc;
3362 }
3363 
3364 /*!
3365   Push a char back to the stream.
3366   \param ch the char to push back
3367   \return false if any problem
3368   \desc Push back the char ch to the stream so it can be re-read
3369   after. Since we use buffered stdio from lib C, there should be
3370   no noticeable I/O impact.
3371   \fixme check that ungetc() works under MacOS
3372  */
SkipBackChar(unsigned char)3373 bool IE_Imp_RTF::SkipBackChar(unsigned char /*ch*/)
3374 {
3375 	if (m_pImportFile)					// if we are reading a file
3376 	{
3377 		// TODO - I've got a sneaking suspicion that this doesn't work on the Macintosh
3378 		return (!gsf_input_seek(m_pImportFile, -1, G_SEEK_CUR));
3379 	}
3380 	else								// else we are pasting from a buffer
3381 	{
3382 		bool bStatus = (m_pCurrentCharInPasteBuffer > m_pPasteBuffer);
3383 		if (bStatus)
3384 			m_pCurrentCharInPasteBuffer--;
3385 		return bStatus;
3386 	}
3387 }
3388 
3389 
3390 /*!
3391   Skip the current group
3392   \param  bConsumeLastBrace pass true to discard the last }
3393   \return false if any problem raised
3394   \desc This function read until the current group and all nested
3395   subgroups are passed. This allow skipping a chunk of the RTF file
3396   we do not understand.
3397  */
SkipCurrentGroup(bool bConsumeLastBrace)3398 bool IE_Imp_RTF::SkipCurrentGroup(bool bConsumeLastBrace)
3399 {
3400 	int nesting = 1;
3401 	unsigned char ch;
3402 
3403 	do {
3404 		if (!ReadCharFromFileWithCRLF(&ch))
3405 			return false;
3406 
3407 		if (ch == '{')
3408 		{
3409 			++nesting;
3410 		}
3411 		else if (ch == '}')
3412 		{
3413 			--nesting;
3414 		}
3415 	} while (nesting > 0);
3416 
3417 	// to avoid corrupting the state stack
3418 	// ( the caller indicates whether this is necesary or not)
3419 	if (!bConsumeLastBrace)
3420 		SkipBackChar(ch);
3421 
3422 	return true;
3423 }
3424 
3425 
3426 /*!
3427   Stuff the current group into the buffer
3428   \param  buf the buffer to stuff RTF in.
3429   \return false if any problem raised
3430   \desc This function read until the current group and all nested
3431   subgroups are passed and stuff them into the buffer. This allow saving a
3432   chunk of the RTF file for future use.
3433  */
StuffCurrentGroup(UT_ByteBuf & buf)3434 bool IE_Imp_RTF::StuffCurrentGroup(UT_ByteBuf & buf)
3435 {
3436 	int nesting = 1;
3437 	unsigned char ch;
3438 
3439 	// add an intial bracket as it is supposed to have a final
3440 	ch = '{';
3441 	buf.append(&ch, 1);
3442 
3443 	do {
3444 		if (!ReadCharFromFileWithCRLF(&ch))
3445 			return false;
3446 
3447 		if (ch == '{')
3448 		{
3449 			++nesting;
3450 		}
3451 		else if (ch == '}')
3452 		{
3453 			--nesting;
3454 		}
3455 		buf.append(&ch, 1);
3456 	} while (nesting > 0);
3457 
3458 	// we don't want the last }
3459 	SkipBackChar(ch);
3460 
3461 	return true;
3462 }
3463 
3464 
3465 /*!
3466   Handle a RTF field
3467   \return false if failed
3468   \desc Once the \\field has been read, handle the object contained in
3469   the current group. This is really tricky as fields are really
3470   hard to handle since most writers do whatever they want, including
3471   RTF code interleaved with field instruction. Thank you Microsoft
3472   (sorry for the rant). Call IE_Imp_RTF::_parseFldinstBlock to
3473   parse field instructions
3474   See p44 for specs.
3475   \see IE_Imp_RTF::_parseFldinstBlock
3476  */
HandleField()3477 bool IE_Imp_RTF::HandleField()
3478 {
3479 	RTFTokenType tokenType;
3480 	unsigned char keyword[MAX_KEYWORD_LEN];
3481 	UT_sint32 parameter = 0;
3482 	bool paramUsed = false;
3483 	bool bUseResult = false;  // true if field instruction can not be used
3484 	int nested = 0;           // nesting level
3485 
3486 	int rtfFieldAttr = 0;
3487 
3488 	typedef enum {
3489 		fldAttrDirty = 1,
3490 		fldAttrEdit = 2,
3491 		fldAttrLock = 4,
3492 		fldAttrPriv = 8
3493 	} RTFFieldAttr;
3494 
3495 	m_bFieldRecognized = false;
3496 
3497 	UT_uint32 iHyperlinkOpen = m_iHyperlinkOpen;
3498 
3499 	tokenType = NextToken (keyword, &parameter, &paramUsed, MAX_KEYWORD_LEN);
3500 	if (tokenType == RTF_TOKEN_ERROR)
3501 	{
3502 		return false;
3503 	}
3504 
3505 	// read the optional attribute for the field.
3506 	while (tokenType == RTF_TOKEN_KEYWORD)
3507 	{
3508 		if (strcmp (reinterpret_cast<char*>(&keyword[0]), "flddirty") == 0)
3509 		{
3510 			rtfFieldAttr &= fldAttrDirty;
3511 		}
3512 		else if (strcmp (reinterpret_cast<char*>(&keyword[0]), "fldedit") == 0)
3513 		{
3514 			rtfFieldAttr &= fldAttrEdit;
3515 		}
3516 		else if (strcmp (reinterpret_cast<char*>(&keyword[0]), "fldlock") == 0)
3517 		{
3518 			rtfFieldAttr &= fldAttrLock;
3519 		}
3520 		else if (strcmp (reinterpret_cast<char*>(&keyword[0]), "fldpriv") == 0)
3521 		{
3522 			rtfFieldAttr &= fldAttrPriv;
3523 		}
3524 		else
3525 		{
3526 			UT_DEBUGMSG (("RTF: Invalid keyword '%s' in field\n", keyword));
3527 			// don't return as we simply skip it
3528 		}
3529 
3530 
3531 		tokenType = NextToken (keyword, &parameter, &paramUsed, MAX_KEYWORD_LEN);
3532 	}
3533 
3534 	// field instruction
3535 	if (tokenType == RTF_TOKEN_OPEN_BRACE)
3536 	{
3537 		UT_ByteBuf fldBuf;
3538 		gchar * xmlField = NULL;
3539 		bool gotStarKW = false;
3540 		// bUseResult will to be set to false if we encounter a field
3541 		// instruction we know about. Otherwise, we use the result by default
3542 		bUseResult = true;
3543 		// since we enter a brace group, we push the RTFState.
3544 		PushRTFState ();
3545 		nested = 0;
3546 		do
3547 		{
3548 			tokenType = NextToken (keyword, &parameter, &paramUsed, MAX_KEYWORD_LEN,false);
3549 			switch (tokenType)
3550 			{
3551 			case RTF_TOKEN_ERROR:
3552 				UT_ASSERT_NOT_REACHED();
3553 				return false;
3554 				break;
3555 			case RTF_TOKEN_KEYWORD:
3556 				if (strcmp(reinterpret_cast<const char *>(&keyword[0]), "*") == 0)
3557 				{
3558 					if (gotStarKW)
3559 					{
3560 						UT_DEBUGMSG (("RTF: was not supposed to get '*' here\n"));
3561 					}
3562 					gotStarKW = true;
3563 				}
3564 				else if (strcmp(reinterpret_cast<const char *>(&keyword[0]), "fldinst") == 0)
3565 				{
3566 					if (!gotStarKW)
3567 					{
3568 						UT_DEBUGMSG (("Ohoh, we were not supposed to get a 'fldinst' without a '*'. Go ahead.\n"));
3569 					}
3570 				}
3571 				else if (strcmp(reinterpret_cast<const char *>(&keyword[0]), "\\") == 0)
3572 				{
3573 					fldBuf.append (keyword, 1);
3574 				}
3575 				break;
3576 			case RTF_TOKEN_OPEN_BRACE:
3577 				nested++;
3578 				PushRTFState ();
3579 				break;
3580 			case RTF_TOKEN_CLOSE_BRACE:
3581 				nested--;
3582 				PopRTFState ();
3583 				break;
3584 			case RTF_TOKEN_DATA:
3585 				// add data to the field
3586 				fldBuf.append (keyword, 1);
3587 				break;
3588 			default:
3589 				break;
3590 			}
3591 		}
3592 		while ((tokenType != RTF_TOKEN_CLOSE_BRACE) || (nested >= 0));
3593 		bool isXML = false;
3594 		xmlField = _parseFldinstBlock (fldBuf, xmlField, isXML);
3595 		bUseResult = (xmlField == NULL) && (!isXML);
3596 		if (!bUseResult)
3597 		{
3598 			UT_DebugOnly<bool> ok;
3599 			xxx_UT_DEBUGMSG(("Append field type %s \n",xmlField));
3600 			ok = _appendField (xmlField);
3601 			UT_ASSERT_HARMLESS (ok);
3602 			// we own xmlField, so we delete it after use.
3603 			FREEP (xmlField);
3604 		}
3605 	}
3606 	else
3607 	{
3608 		xxx_UT_DEBUGMSG (("RTF: Field instruction not present. Found '%s' in stream\n", keyword));
3609 		UT_ASSERT_HARMLESS (UT_SHOULD_NOT_HAPPEN);
3610 		// continue
3611 	}
3612 
3613 	tokenType = NextToken (keyword, &parameter, &paramUsed, MAX_KEYWORD_LEN,false);
3614 	if (tokenType == RTF_TOKEN_ERROR)
3615 	{
3616 		return false;
3617 	}
3618 
3619 	// field result
3620 	// TODO: push and pop the state as expected.
3621 	if (tokenType == RTF_TOKEN_OPEN_BRACE)
3622 	{
3623 		PushRTFState();
3624 		tokenType = NextToken (keyword, &parameter, &paramUsed, MAX_KEYWORD_LEN);
3625 		if (tokenType == RTF_TOKEN_ERROR)
3626 		{
3627 			return false;
3628 		}
3629 		if (tokenType == RTF_TOKEN_KEYWORD)
3630 		{
3631 			// here we expect fldrslt keyword, nothing else
3632 			if (strcmp (reinterpret_cast<char*>(&keyword[0]), "fldrslt") != 0)
3633 			{
3634 				UT_DEBUGMSG (("RTF: Invalid keyword '%s' in field\n", keyword));
3635 				// don't return as we simply skip it
3636 			}
3637 			else
3638 			{
3639 				if(m_bFieldRecognized && (m_iHyperlinkOpen== 0))
3640 				{
3641 					SkipCurrentGroup(false);
3642 					return true;
3643 				}
3644 			}
3645 		}
3646 
3647 		// The original code parsing the result was not enough: the
3648 		// field result can contain full-blown rtf markup, including
3649 		// other fields, etc. That means that we have to parse it just
3650 		// like we do ordinary text.
3651 		if(bUseResult)
3652 		{
3653 			if(UT_OK != _parseText())
3654 				return false;
3655 		}
3656 	}
3657 	else if(tokenType == RTF_TOKEN_CLOSE_BRACE)
3658 	{
3659 		PopRTFState ();
3660 	}
3661 	else
3662 	{
3663 		UT_DEBUGMSG (("RTF: Field result not present. Found '%s' in stream. Ignoring.\n", keyword));
3664 		// UT_ASSERT_HARMLESS (UT_SHOULD_NOT_HAPPEN);
3665 		// continue
3666 	}
3667 
3668 	if(m_iHyperlinkOpen > iHyperlinkOpen)
3669 	{
3670 		FlushStoredChars(true);
3671 
3672 		if (!bUseInsertNotAppend())
3673 		{
3674 			if(m_bCellBlank || m_bEndTableOpen)
3675 			{
3676 				UT_DEBUGMSG(("Append block 14 \n"));
3677 
3678 				if(m_pDelayedFrag)
3679 				{
3680 					getDoc()->insertStruxBeforeFrag(m_pDelayedFrag,PTX_Block,NULL);
3681 				}
3682 				else
3683 				{
3684 					getDoc()->appendStrux(PTX_Block,NULL);
3685 				}
3686 			m_bCellBlank = false;
3687 				m_bEndTableOpen = false;
3688 			}
3689 			getDoc()->appendObject(PTO_Hyperlink, NULL);
3690 		}
3691 		else
3692 		{
3693 			if(m_iHyperlinkOpen ==1)
3694 			{
3695 				const gchar * props[] = {"list-tag","dummy",NULL};
3696 				getDoc()->insertObject(m_dposPaste, PTO_Hyperlink, props, NULL);
3697 				m_dposPaste++;
3698 			}
3699 			else
3700 			{
3701 				return false;
3702 			}
3703 		}
3704 		m_iHyperlinkOpen--;
3705 		UT_ASSERT_HARMLESS( m_iHyperlinkOpen == iHyperlinkOpen );
3706 	}
3707 
3708 	return true;
3709 }
3710 
3711 
3712 /*!
3713   \param buf the buffer that contains the RTF.
3714   \param xmlField the XML attributes for the field.
3715   \param isXML whether xmlField is used or not.
3716   \see IE_Imp_RTF::HandleField
3717  */
_parseFldinstBlock(UT_ByteBuf & _buf,gchar * xmlField,bool & isXML)3718 gchar *IE_Imp_RTF::_parseFldinstBlock (UT_ByteBuf & _buf, gchar *xmlField, bool & isXML)
3719 {
3720 	// this is quite complex as field instructions are not really document in the RTF specs.
3721 	// we will guess as much us possible.
3722 	// thing that complexify is that a field instruction can contain nested block and
3723 	// DATA blocks. We will try to limit first to the standard fields.
3724 
3725 	// Here are a couple of examples from the spec
3726 	/*
3727 	  {\field {\*\fldinst AUTHOR \\*MERGEFORMAT    }{\fldrslt Joe Smith}}\par\pard
3728 	  {\field{\*\fldinst time \\@ "h:mm AM/PM"}{\fldrslt 8:12 AM}}
3729 	  {\field{\*\fldinst NOTEREF _RefNumber } {\fldrslt 1}}
3730 	  {\field{\*\fldinst NOTEREF _RefNumber \fldalt } {\fldrslt I}}
3731 	*/
3732 	// Here is an example from StarOffice 5.2 export: an Hyperlink
3733 	/*
3734 	  {\field{\*\fldinst HYPERLINK "http://www.sas.com/techsup/download/misc/cleanwork.c" }
3735 	  {\fldrslt \*\cs21\cf1\ul http://www.sas.com/techsup/download/misc/cleanwork.c}}
3736 	*/
3737 	// This time it is an image: StarOffice exports images in .jpg as a separate file
3738 	/*
3739 	  {\field\fldpriv{\*\fldinst{\\import sv8968971.jpg}}{\fldrslt }}
3740 	*/
3741 	/*
3742 	  OpenOffice/StarOffice 6 do this in a similar way. See OpenOffice bug 2244.
3743 	*/
3744 	/* Microsoft doc on field usages in Word is at:
3745 	   <http://support.microsoft.com/support/word/usage/fields/>
3746 	*/
3747 
3748 	/* IMPORTANT: field results can contain full-blown rtf markup,
3749 	   incuding embeded field, etc. For instnace the result for a TOC
3750 	   field contains hyperlinks that allow jumping from the TOC to a
3751 	   relevant page. This means that the result cannot be simply
3752 	   pasted into the document
3753 	*/
3754 
3755 	char *instr;
3756 	char *newBuf;
3757 	std::string Instr;
3758 	UT_uint32  len;
3759 	isXML = false;
3760 
3761 	// buffer is empty, nothing to parse
3762 	if (_buf.getLength() == 0)
3763 	{
3764 		FREEP (xmlField);
3765 		return NULL;
3766 	}
3767 
3768 	len = _buf.getLength ();
3769 	const UT_Byte *pBuf = _buf.getPointer (0);
3770 
3771 	newBuf =  static_cast<char *>(g_try_malloc (sizeof (char) * (len + 1)));
3772 	memcpy (newBuf, pBuf, len);
3773 	newBuf [len] = 0;
3774 	Instr = newBuf;
3775 	instr = const_cast<char *>(Instr.c_str());
3776 	instr = strtok (instr, " \\{}"); // This writes a NULL into Instr somewhere
3777 	                                 // I assume this is OK since the char storage
3778 	                                 // Within the class is contiguous.
3779 	if (instr == NULL)
3780 	{
3781 		g_free (newBuf);
3782 		g_free (xmlField);
3783 		return NULL;
3784 	}
3785 
3786 	switch (*instr)
3787 	{
3788 	case 'A':
3789 		if (strcmp (instr, "AUTHOR") == 0)
3790 		{
3791 			xmlField = g_strdup ("meta_creator");
3792 			UT_ASSERT_HARMLESS (xmlField);
3793 			isXML = (xmlField != NULL);
3794 		}
3795 		break;
3796 	case 'C':
3797 		if (strcmp (instr, "CREATEDATE") == 0)
3798 		{
3799 			xmlField = g_strdup ("meta_date");
3800 			UT_ASSERT_HARMLESS (xmlField);
3801 			isXML = (xmlField != NULL);
3802 		}
3803 		else if (strcmp (instr, "COMMENTS") == 0)
3804 		{
3805 			xmlField = g_strdup ("meta_description");
3806 			UT_ASSERT_HARMLESS (xmlField);
3807 			isXML = (xmlField != NULL);
3808 		}
3809 		break;
3810 	case 'D':
3811 		if (strcmp (instr, "DATE") == 0)
3812 		{
3813 			xmlField = g_strdup ("date");
3814 			UT_ASSERT_HARMLESS (xmlField);
3815 			isXML = (xmlField != NULL);
3816 		}
3817 		break;
3818 	case 'F':
3819 		if (strcmp (instr, "FILENAME") == 0)
3820 		{
3821 			// TODO handle parameters
3822 			xmlField = g_strdup ("file_name");
3823 			UT_ASSERT_HARMLESS (xmlField);
3824 			isXML = (xmlField != NULL);
3825 		}
3826 		break;
3827 	case 'H':
3828 		if (strcmp (instr, "HYPERLINK") == 0)
3829 		{
3830 			xxx_UT_DEBUGMSG (("RTF: HYPERLINK fieldinst not handled yet\n"));
3831 			// set these so that HandleField outputs the result
3832 			xmlField = NULL;
3833 			isXML = false;
3834 
3835 			instr = strtok(0, " \\{}");
3836 			if (instr == NULL)  // ignore empty hyperlinks
3837 				break;
3838 			const gchar *new_atts[3];
3839 
3840 			new_atts[0] = "xlink:href";
3841 			std::string href;
3842 			if ( !strcmp(instr, "l") )
3843 			{
3844 				instr = strtok (NULL, " \\{}");
3845 				href = "#";
3846 			}
3847 			else
3848 			{
3849 				href.clear();
3850 			}
3851 
3852 			// the full address is enclosed in quotation marks,
3853 			// which need to be removed
3854 			if(*instr == '\"')
3855 				instr++;
3856 
3857 			if(instr[strlen(instr)-1])
3858 				instr[strlen(instr)-1] = 0;
3859 
3860 			href += instr;
3861 
3862 			std::string full_href;
3863 
3864 			const char * s = href.c_str();
3865 
3866 			if(*s != '#' && !UT_go_path_is_uri(s))
3867 			{
3868 				// TODO we are dealing with a relative URL; until AW
3869 				// can handle relative URLs we will convert it into an
3870 				// absolute one
3871 				full_href = m_hyperlinkBase;
3872 				const char * s2 = full_href.c_str();
3873 
3874 				if(*s != '/' && s2[strlen(s2)-1] != '/')
3875 				{
3876 					full_href += '/';
3877 					full_href += s;
3878 				}
3879 				else if(*s == '/' && s2[strlen(s2)-1] == '/')
3880 				{
3881 					full_href += (s+1);
3882 				}
3883 				else
3884 				{
3885 					full_href += s;
3886 				}
3887 
3888 				s = full_href.c_str();
3889 			}
3890 
3891 			new_atts[1] = s;
3892 			new_atts[2] = 0;
3893 
3894 			FlushStoredChars(true);
3895 
3896 			if (!bUseInsertNotAppend())
3897 			{
3898 
3899 				if(m_bCellBlank || m_bEndTableOpen)
3900 				{
3901 					UT_DEBUGMSG(("Append block 15 \n"));
3902 
3903 					if(m_pDelayedFrag)
3904 					{
3905 						getDoc()->insertStruxBeforeFrag(m_pDelayedFrag,PTX_Block,NULL);
3906 					}
3907 					else
3908 					{
3909 						getDoc()->appendStrux(PTX_Block,NULL);
3910 					}
3911 					m_bCellBlank = false;
3912 					m_bEndTableOpen = false;
3913 				}
3914 				getDoc()->appendObject(PTO_Hyperlink, new_atts);
3915 			}
3916 			else
3917 			{
3918 				if(getDoc()->isInsertHyperLinkValid(m_dposPaste))
3919 				{
3920 						getDoc()->insertObject(m_dposPaste, PTO_Hyperlink, new_atts, NULL);
3921 						m_dposPaste++;
3922 				}
3923 				else
3924 				{
3925 						break;
3926 				}
3927 			}
3928 			m_iHyperlinkOpen++;
3929 		}
3930 		break;
3931 	case 'I':
3932 		if (strcmp (instr, "INCLUDEPICTURE") == 0)
3933 		{
3934 			UT_DEBUGMSG (("RTF: INCLUDEPICTURE fieldinst not handled yet\n"));
3935 		}
3936 		break;
3937 	case 'K':
3938 		if (strcmp (instr, "KEYWORDS") == 0)
3939 		{
3940 			xmlField = g_strdup ("meta_keywords");
3941 			UT_ASSERT_HARMLESS (xmlField);
3942 			isXML = (xmlField != NULL);
3943 		}
3944 		break;
3945 	case 'P':
3946 		if (strcmp (instr, "PAGE") == 0)
3947 		{
3948 			xmlField = g_strdup ("page_number");
3949 			UT_ASSERT_HARMLESS (xmlField);
3950 			isXML = (xmlField != NULL);
3951 		}
3952 		else if (strcmp (instr, "PRIVATE") == 0)
3953 		{
3954 			UT_DEBUGMSG (("RTF: PRIVATE fieldinst not handled yet\n"));
3955 		}
3956 		break;
3957 	case 'N':
3958 		if (strcmp (instr, "NUMCHARS") == 0)
3959 		{
3960 			xmlField = g_strdup ("char_count");
3961 			UT_ASSERT_HARMLESS (xmlField);
3962 			isXML = (xmlField != NULL);
3963 		}
3964 		// this one have been found with ApplixWare exported RTF.
3965 		else if (strcmp (instr, "NUMPAGES") == 0)
3966 		{
3967 			xmlField = g_strdup ("page_count");
3968 			UT_ASSERT_HARMLESS (xmlField);
3969 			isXML = (xmlField != NULL);
3970 		}
3971 		else if (strcmp (instr, "NUMWORDS") == 0)
3972 		{
3973 			xmlField = g_strdup ("word_count");
3974 			UT_ASSERT_HARMLESS (xmlField);
3975 			isXML = (xmlField != NULL);
3976 		}
3977 		break;
3978 	case 'S':
3979 		if (strcmp (instr, "SAVEDATE") == 0)
3980 		{
3981 			xmlField = g_strdup ("date_dfl");
3982 			UT_ASSERT_HARMLESS (xmlField);
3983 			isXML = (xmlField != NULL);
3984 		}
3985 		else if (strcmp (instr, "SUBJECT") == 0)
3986 		{
3987 			xmlField = g_strdup ("meta_subject");
3988 			UT_ASSERT_HARMLESS (xmlField);
3989 			isXML = (xmlField != NULL);
3990 		}
3991 		break;
3992 	case 'T':
3993 		if (strcmp (instr, "TEXTMETA") == 0)
3994 		{
3995 			std::string xmlid = "";
3996 			const gchar* ppAtts[10] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
3997 
3998 			UT_DEBUGMSG (("RTF: RDF opening text meta with original xmlid:%s\n", xmlid.c_str() ));
3999 			PD_XMLIDCreatorHandle xidc = m_XMLIDCreatorHandle;
4000 			xmlid = xidc->createUniqueXMLID( xmlid );
4001 			UT_DEBUGMSG (("RTF: RDF opening text meta with updated  xmlid:%s\n", xmlid.c_str() ));
4002 
4003 			ppAtts[0] = PT_XMLID;
4004 			ppAtts[1] = xmlid.c_str();
4005 			// sanity check
4006 			ppAtts[2] = "this-is-an-rdf-anchor";
4007 			ppAtts[3] = "yes";
4008 //			ppAtts[4] = PT_RDF_END;
4009 //			ppAtts[5] = "yes";
4010 
4011 			getDoc()->appendObject(PTO_RDFAnchor, ppAtts);
4012 			m_iRDFAnchorOpen++;
4013 
4014 
4015 		}
4016 		if (strcmp (instr, "TIME") == 0)
4017 		{
4018 			// Some Parameters from MS Word 2000 output
4019 
4020 			if(strstr(newBuf,"dddd, MMMM dd, yyyy") != NULL)
4021 			{
4022 				xmlField = g_strdup("date");
4023 				UT_ASSERT_HARMLESS (xmlField);
4024 				isXML = (xmlField != NULL);
4025 			}
4026 			else if( strstr(newBuf,"m/d/yy") != NULL)
4027 			{
4028 				xmlField = g_strdup("date_ddmmyy");
4029 				UT_ASSERT_HARMLESS (xmlField);
4030 				isXML = (xmlField != NULL);
4031 			}
4032 			else if( strstr(newBuf,"MMMM d, yyyy") != NULL)
4033 			{
4034 				xmlField = g_strdup("date_mdy");
4035 				UT_ASSERT_HARMLESS (xmlField);
4036 				isXML = (xmlField != NULL);
4037 			}
4038 			else if( strstr(newBuf,"MMM d, yy") != NULL)
4039 			{
4040 				xmlField = g_strdup("date_mthdy");
4041 				UT_ASSERT_HARMLESS (xmlField);
4042 				isXML = (xmlField != NULL);
4043 			}
4044 			else if( strstr(newBuf,"MMM d, yy") != NULL)
4045 			{
4046 				xmlField = g_strdup("date_mthdy");
4047 				UT_ASSERT_HARMLESS (xmlField);
4048 				isXML = (xmlField != NULL);
4049 			}
4050 			else if( strstr(newBuf,"MM-d-yy") != NULL)
4051 			{
4052 				xmlField = g_strdup("date_ntdfl");
4053 				UT_ASSERT_HARMLESS (xmlField);
4054 				isXML = (xmlField != NULL);
4055 			}
4056 			else if( strstr(newBuf,"HH:mm:ss") != NULL)
4057 			{
4058 				xmlField = g_strdup("time_miltime");
4059 				UT_ASSERT_HARMLESS (xmlField);
4060 				isXML = (xmlField != NULL);
4061 			}
4062 			else if( strstr(newBuf,"h:mm:ss am/pm") != NULL)
4063 			{
4064 				xmlField = g_strdup("time_ampm");
4065 				UT_ASSERT_HARMLESS (xmlField);
4066 				isXML = (xmlField != NULL);
4067 			}
4068 //
4069 // Make this the second last one since it's not unique
4070 //
4071 			else if( strstr(newBuf,"dddd") != NULL)
4072 			{
4073 				xmlField = g_strdup("date_wkday");
4074 				UT_ASSERT_HARMLESS (xmlField);
4075 				isXML = (xmlField != NULL);
4076 			}
4077 			else
4078 			{
4079 				xmlField = g_strdup ("time");
4080 				UT_ASSERT_HARMLESS (xmlField);
4081 				isXML = (xmlField != NULL);
4082 			}
4083 		}
4084 		if (strcmp (instr, "TITLE") == 0)
4085 		{
4086 			xmlField = g_strdup ("meta_title");
4087 			UT_ASSERT_HARMLESS (xmlField);
4088 			isXML = (xmlField != NULL);
4089 		}
4090 		else if (strcmp (instr, "TOC") == 0)
4091 		{
4092 			// Table-of-contents field
4093 			UT_DEBUGMSG (("RTF: TOC fieldinst not fully handled yet\n"));
4094 
4095 #if 0
4096 			if(!m_bParaWrittenForSection)
4097 			{
4098 				getDoc()->appendStrux(PTX_Block, NULL);
4099 				m_bParaWrittenForSection = true;
4100 			}
4101 
4102 			getDoc()->appendStrux(PTX_SectionTOC, NULL);
4103 			getDoc()->appendStrux(PTX_EndTOC, NULL);
4104 
4105 			// DAL: hack
4106 			xmlField = g_strdup ("");
4107 			UT_ASSERT_HARMLESS (xmlField);
4108 			isXML = (xmlField != NULL);
4109 #endif
4110 		}
4111 
4112 		break;
4113 	case 'd':
4114 		if (strcmp (instr, "date") == 0)
4115 		{
4116 			// TODO handle parameters
4117 			xmlField = g_strdup ("date");
4118 			UT_ASSERT_HARMLESS (xmlField);
4119 			isXML = (xmlField != NULL);
4120 		}
4121 		break;
4122 	case '\\':
4123 		/* mostly StarOffice RTF fields */
4124 		if (strcmp (instr, "\\filename") == 0)
4125 		{
4126 			xmlField = g_strdup ("file_name");
4127 			UT_ASSERT_HARMLESS (xmlField);
4128 			isXML = (xmlField != NULL);
4129 		}
4130 		else if (strcmp (instr, "\\import") == 0)
4131 		{
4132 			// need to read the filename.
4133 			UT_DEBUGMSG (("importing StarOffice image\n"));
4134 
4135 			if (m_szFileDirName	!= NULL)
4136 			{
4137 				char * fileName = NULL;
4138 				char * tok  = strtok (NULL, " ");
4139 				fileName = g_build_filename (m_szFileDirName, tok, NULL);
4140 				UT_DEBUGMSG (("fileName is %s\n", fileName));
4141 
4142 				bool ok = FlushStoredChars ();
4143 				if (ok)
4144 				{
4145 					// insert the image in the piece table AFTER flushing
4146 					// current output
4147 					FG_Graphic* pFG;
4148 					UT_Error error = IE_ImpGraphic::loadGraphic(fileName, IEGFT_JPEG, &pFG);
4149 
4150 					// load file to buffer
4151 					if (error == UT_OK && pFG)
4152 					{
4153 						RTFProps_ImageProps imgProps;
4154 						ok = InsertImage (pFG, fileName, imgProps);
4155 					}
4156 					else
4157 					{
4158 						UT_DEBUGMSG (("RTF: error while importing SO image: %d\n", error));
4159 					}
4160 				}
4161 				else
4162 				{
4163 					UT_DEBUGMSG (("RTF: we don't know the current filename path\n"));
4164 				}
4165 				FREEP (fileName);
4166 			}
4167 		}
4168 		else if (strcmp (instr, "\\page") == 0)
4169 		{
4170 			xmlField = g_strdup ("page_number");
4171 			UT_ASSERT_HARMLESS (xmlField);
4172 			isXML = (xmlField != NULL);
4173 		}
4174 		break;
4175 	default:
4176 		UT_DEBUGMSG (("RTF: unhandled fieldinstr %s\n", instr));
4177 		break;
4178 	}
4179 	g_free (newBuf);
4180 	return xmlField;
4181 }
4182 
4183 
4184 /*!
4185   Handle a header
4186   \retvalue header return the created header, for information
4187   purpose since it belongs to the header/footer table
4188   \note it does not set the RTF state.
4189  */
HandleHeaderFooter(RTFHdrFtr::HdrFtrType hftype,UT_uint32 & headerID)4190 bool IE_Imp_RTF::HandleHeaderFooter(RTFHdrFtr::HdrFtrType hftype, UT_uint32 & headerID)
4191 {
4192 	RTFHdrFtr * header;
4193 	UT_DEBUGMSG(("SEVIOR: Doing handle header/footer \n"));
4194 	header = new RTFHdrFtr ();
4195 	header->m_type = hftype;
4196 	UT_uint32 id = getDoc()->getUID(UT_UniqueId::HeaderFtr);
4197 #if 0
4198 	while(id < 10000)
4199 	{
4200 		id  = UT_rand();
4201 	}
4202 #endif
4203 	header->m_id = id;
4204 
4205 	m_hdrFtrTable.push_back(header);
4206 	headerID = header->m_id;
4207 
4208 	switch (hftype)
4209 	{
4210 	case RTFHdrFtr::hftHeader:
4211 		UT_DEBUGMSG(("RTF: \\header stuffed into %d\n",headerID));
4212 		m_currentHdrID = headerID;
4213 		break;
4214 	case RTFHdrFtr::hftHeaderEven:
4215 		UT_DEBUGMSG(("RTF: \\header Even stuffed into %d\n",headerID));
4216 		m_currentHdrEvenID = headerID;
4217 		break;
4218 	case RTFHdrFtr::hftHeaderFirst:
4219 		UT_DEBUGMSG(("RTF: \\header First stuffed into %d\n",headerID));
4220 		m_currentHdrFirstID = headerID;
4221 		break;
4222 	case RTFHdrFtr::hftHeaderLast:
4223 		UT_DEBUGMSG(("RTF: \\header Last stuffed into %d\n",headerID));
4224 		m_currentHdrLastID = headerID;
4225 		break;
4226 	case RTFHdrFtr::hftFooter:
4227 		UT_DEBUGMSG(("RTF: \\footer stuffed into %d\n",headerID));
4228 		m_currentFtrID = headerID;
4229 		break;
4230 	case RTFHdrFtr::hftFooterEven:
4231 		UT_DEBUGMSG(("RTF: \\footer Even stuffed into %d\n",headerID));
4232 		m_currentFtrEvenID = headerID;
4233 		break;
4234 	case RTFHdrFtr::hftFooterFirst:
4235 		UT_DEBUGMSG(("RTF: \\footer stuffed into %d\n",headerID));
4236 		m_currentFtrFirstID = headerID;
4237 		break;
4238 	case RTFHdrFtr::hftFooterLast:
4239 		UT_DEBUGMSG(("RTF: \\footer stuffed into %d\n",headerID));
4240 		m_currentFtrLastID = headerID;
4241 		break;
4242 	default:
4243 		UT_ASSERT_NOT_REACHED();
4244 	}
4245 
4246 	// read the whole group content and put it into a buffer to
4247 	// decode it later, when appending footer to the document.
4248 	return StuffCurrentGroup (header->m_buf);
4249 }
4250 
4251 
4252 // Test the keyword against all the known handlers
TranslateKeyword(unsigned char * pKeyword,UT_sint32 param,bool fParam)4253 bool IE_Imp_RTF::TranslateKeyword(unsigned char* pKeyword, UT_sint32 param, bool fParam)
4254 {
4255 	// switch on the first char to reduce the number of string comparisons
4256 	// NB. all RTF keywords are lowercase.
4257 	// after handling the keyword, return true
4258 
4259 	// When adding keywords expressing document properties, maker sure
4260 	// that if we are only loading styles, these are ignored
4261 	// (the docs say these can be scattered among the header tables)
4262 	xxx_UT_DEBUGMSG(("Translating keyword %s \n",pKeyword));
4263 	RTF_KEYWORD_ID keywordID = KeywordToID(reinterpret_cast<char *>(pKeyword));
4264 	return TranslateKeywordID(keywordID, param, fParam);
4265 }
4266 
4267 
4268 
TranslateKeywordID(RTF_KEYWORD_ID keywordID,UT_sint32 param,bool fParam)4269 bool IE_Imp_RTF::TranslateKeywordID(RTF_KEYWORD_ID keywordID,
4270 								  UT_sint32 param, bool fParam)
4271 {
4272 	switch (keywordID)
4273 	{
4274 	case RTF_KW_ansicpg:
4275 	{
4276 		const char *szEncoding = NULL;
4277 		if(param == -1)
4278 		{
4279 			// IE issues this value on copy (ctrl+c), and I could not find out from anywhere what it is
4280 			// supposed to mean; I will assume it means use the current system page
4281 			szEncoding = XAP_EncodingManager::get_instance()->getNative8BitEncodingName();
4282 		}
4283 		else
4284 		{
4285 			szEncoding = XAP_EncodingManager::get_instance()->charsetFromCodepage(static_cast<UT_uint32>(param));
4286 		}
4287 
4288 		// Store the default encoding and activate it.
4289 		m_szDefaultEncoding = szEncoding;
4290 		setEncoding();
4291 
4292 		if(!getLoadStylesOnly()) {
4293 			getDoc()->setEncodingName(szEncoding);
4294 		}
4295 		return true;
4296 	}
4297 	case RTF_KW_abitopline:
4298 		return HandleTopline(true);
4299 	case RTF_KW_abibotline:
4300 		return HandleBotline(true);
4301 	case RTF_KW_abinodiroverride:
4302 	{
4303 // this keyword will be immediately followed by either the
4304 // ltrch or rtlch keyword, which we need to eat up ...
4305 		unsigned char kwrd[MAX_KEYWORD_LEN];
4306 		UT_sint32 par = 0;
4307 		bool parUsed = false;
4308 		bool ok = true;
4309 		unsigned char c;
4310 
4311 // swallow "\" first
4312 		ok = ReadCharFromFileWithCRLF(&c);
4313 		if (ok && ReadKeyword(kwrd, &par, &parUsed, MAX_KEYWORD_LEN))
4314 		{
4315 			if(!(0 == strncmp((const char*)&kwrd[0],"rtlch",MAX_KEYWORD_LEN) ||
4316 				 0 == strncmp((const char*)&kwrd[0],"ltrch",MAX_KEYWORD_LEN)))
4317 			{
4318 				UT_DEBUGMSG(("RTF import: keyword \\%s found where \\ltrch"
4319 							 " or \\rtlch expected\n", kwrd));
4320 			}
4321 		}
4322 		UT_ASSERT(ok);
4323 		xxx_UT_DEBUGMSG(("abinoveride found - swallowed keyword %s \n",kwrd));
4324 		return true;
4325 	}
4326 	case RTF_KW_ansi:
4327 	{
4328 		// this is charset Windows-1252
4329 		const char *szEncoding = XAP_EncodingManager::get_instance()->charsetFromCodepage(1252);
4330 		m_mbtowc.setInCharset(szEncoding);
4331 		if(!getLoadStylesOnly())
4332 			getDoc()->setEncodingName(szEncoding);
4333 		return true;
4334 	}
4335 	case RTF_KW_abirtl:
4336 	{
4337 		m_currentRTFState.m_charProps.m_dirOverride = UT_BIDI_RTL;
4338 		return true;
4339 	}
4340 	case RTF_KW_abiltr:
4341 	{
4342 		m_currentRTFState.m_charProps.m_dirOverride = UT_BIDI_LTR;
4343 		return true;
4344 	}
4345 	case RTF_KW_aendnotes:
4346 		if(!getLoadStylesOnly())
4347 		{
4348 			const gchar * props[] = {"document-endnote-place-endsection", "1",
4349 										NULL};
4350 			getDoc()->setProperties(&props[0]);
4351 		}
4352 		break;
4353 	case RTF_KW_aenddoc:
4354 		if(!getLoadStylesOnly())
4355 		{
4356 			const gchar * props[] = {"document-endnote-place-enddoc", "1",
4357 										NULL};
4358 			getDoc()->setProperties(&props[0]);
4359 		}
4360 		break;
4361 	case RTF_KW_aftnstart:
4362 		if(!getLoadStylesOnly())
4363 		{
4364 			const gchar * props[] = {"document-endnote-initial", NULL,
4365 										NULL};
4366 			std::string i = UT_std_string_sprintf("%d",param);
4367 			props[1] = i.c_str();
4368 			getDoc()->setProperties(&props[0]);
4369 		}
4370 		break;
4371 	case RTF_KW_aftnrestart:
4372 		if(!getLoadStylesOnly())
4373 		{
4374 
4375 			const gchar * props[] = {"document-endnote-restart-section", "1",
4376 										NULL};
4377 			getDoc()->setProperties(&props[0]);
4378 		}
4379 		break;
4380 	case RTF_KW_aftnnar:
4381 		if(!getLoadStylesOnly())
4382 		{
4383 			const gchar * props[] = {"document-endnote-type", "numeric",
4384 										NULL};
4385 			getDoc()->setProperties(&props[0]);
4386 		}
4387 		break;
4388 	case RTF_KW_aftnnalc:
4389 		if(!getLoadStylesOnly())
4390 		{
4391 			const gchar * props[] = {"document-endnote-type", "lower",
4392 										NULL};
4393 			getDoc()->setProperties(&props[0]);
4394 		}
4395 		break;
4396 	case RTF_KW_aftnnauc:
4397 		if(!getLoadStylesOnly())
4398 		{
4399 			const gchar * props[] = {"document-endnote-type", "upper",
4400 										NULL};
4401 			getDoc()->setProperties(&props[0]);
4402 		}
4403 		break;
4404 	case RTF_KW_aftnnrlc:
4405 		if(!getLoadStylesOnly())
4406 		{
4407 			const gchar * props[] = {"document-endnote-type", "lower-roman",
4408 										NULL};
4409 			getDoc()->setProperties(&props[0]);
4410 		}
4411 		break;
4412 	case RTF_KW_aftnnruc:
4413 		if(!getLoadStylesOnly())
4414 		{
4415 			const gchar * props[] = {"document-footnote-type", "upper-roman",
4416 										NULL};
4417 			getDoc()->setProperties(&props[0]);
4418 		}
4419 		break;
4420 	case RTF_KW_b:
4421 		// bold - either on or off depending on the parameter
4422 		return HandleBold(fParam ? false : true);
4423 	case RTF_KW_bullet:
4424 		return ParseChar(UCS_BULLET);
4425 	case RTF_KW_brdrt:
4426 		UT_DEBUGMSG(("Border Top set \n"));
4427 		m_currentRTFState.m_paraProps.m_iCurBorder = (int) rtfBorderTop;
4428 		m_currentRTFState.m_paraProps.m_bTopBorder = true;
4429 		m_bCellActive = false;
4430 		m_bParaActive = true;
4431 		return true;
4432 	case RTF_KW_brdrl:
4433 		xxx_UT_DEBUGMSG(("Border left set \n"));
4434 		m_currentRTFState.m_paraProps.m_iCurBorder = (int) rtfBorderLeft;
4435 		m_currentRTFState.m_paraProps.m_bLeftBorder = true;
4436 		m_bCellActive = false;
4437 		m_bParaActive = true;
4438 		return true;
4439 	case RTF_KW_brdrb:
4440 		xxx_UT_DEBUGMSG(("Border Bot set \n"));
4441 		m_currentRTFState.m_paraProps.m_iCurBorder = (int) rtfBorderBot;
4442 		m_currentRTFState.m_paraProps.m_bBotBorder = true;
4443 		m_bCellActive = false;
4444 		m_bParaActive = true;
4445 		return true;
4446 	case RTF_KW_brdrr:
4447 		xxx_UT_DEBUGMSG(("Border Right set \n"));
4448 		m_currentRTFState.m_paraProps.m_iCurBorder = (int) rtfBorderRight;
4449 		m_currentRTFState.m_paraProps.m_bRightBorder = true;
4450 		m_bCellActive = false;
4451 		m_bParaActive = true;
4452 		return true;
4453 	case RTF_KW_brdrbtw:
4454 		m_currentRTFState.m_paraProps.m_bMergeBordersShading = true;
4455 		return true;
4456 	case RTF_KW_brdrs:
4457 		if(m_bCellActive)
4458 		{
4459 			if (m_currentRTFState.m_cellProps.m_iCurBorder == rtfCellBorderTop)
4460 			{
4461 				_setStringProperty(m_currentRTFState.m_cellProps.m_sCellProps,"top-style","solid");
4462 			}
4463 			else if (m_currentRTFState.m_cellProps.m_iCurBorder == rtfCellBorderLeft)
4464 			{
4465 				_setStringProperty(m_currentRTFState.m_cellProps.m_sCellProps,"left-style","solid");
4466 			}
4467 			else if (m_currentRTFState.m_cellProps.m_iCurBorder == rtfCellBorderBot)
4468 			{
4469 				_setStringProperty(m_currentRTFState.m_cellProps.m_sCellProps,"bot-style","solid");
4470 			}
4471 			else if (m_currentRTFState.m_cellProps.m_iCurBorder == rtfCellBorderRight)
4472 			{
4473 				_setStringProperty(m_currentRTFState.m_cellProps.m_sCellProps,"right-style","solid");
4474 			}
4475 		}
4476 		else if(m_bParaActive)
4477 		{
4478 			if (m_currentRTFState.m_paraProps.m_iCurBorder == (int) rtfBorderTop)
4479 			{
4480 				m_currentRTFState.m_paraProps.m_iTopBorderStyle = 1;
4481 			}
4482 			else if (m_currentRTFState.m_paraProps.m_iCurBorder == (int) rtfBorderLeft)
4483 			{
4484 				m_currentRTFState.m_paraProps.m_iLeftBorderStyle = 1;
4485 			}
4486 			else if (m_currentRTFState.m_paraProps.m_iCurBorder == (int) rtfBorderBot)
4487 			{
4488 				m_currentRTFState.m_paraProps.m_iBotBorderStyle = 1;
4489 			}
4490 			else if (m_currentRTFState.m_paraProps.m_iCurBorder == (int) rtfBorderRight)
4491 			{
4492 				m_currentRTFState.m_paraProps.m_iRightBorderStyle = 1;
4493 			}
4494 		}
4495 		return true;
4496 	case RTF_KW_brdrdot:
4497 		if(m_bCellActive)
4498 		{
4499 			if (m_currentRTFState.m_cellProps.m_iCurBorder == rtfCellBorderTop)
4500 			{
4501 				_setStringProperty(m_currentRTFState.m_cellProps.m_sCellProps,"top-style","dotted");
4502 			}
4503 			else if (m_currentRTFState.m_cellProps.m_iCurBorder == rtfCellBorderLeft)
4504 			{
4505 				_setStringProperty(m_currentRTFState.m_cellProps.m_sCellProps,"left-style","dotted");
4506 			}
4507 			else if (m_currentRTFState.m_cellProps.m_iCurBorder == rtfCellBorderBot)
4508 			{
4509 				_setStringProperty(m_currentRTFState.m_cellProps.m_sCellProps,"bot-style","dotted");
4510 			}
4511 			else if (m_currentRTFState.m_cellProps.m_iCurBorder == rtfCellBorderRight)
4512 			{
4513 				_setStringProperty(m_currentRTFState.m_cellProps.m_sCellProps,"right-style","dotted");
4514 			}
4515 		}
4516 		else if(m_bParaActive)
4517 		{
4518 			if (m_currentRTFState.m_paraProps.m_iCurBorder == (int) rtfBorderTop)
4519 			{
4520 				m_currentRTFState.m_paraProps.m_iTopBorderStyle = 2;
4521 			}
4522 			else if (m_currentRTFState.m_paraProps.m_iCurBorder == (int) rtfBorderLeft)
4523 			{
4524 				m_currentRTFState.m_paraProps.m_iLeftBorderStyle = 2;
4525 			}
4526 			else if (m_currentRTFState.m_paraProps.m_iCurBorder == (int) rtfBorderBot)
4527 			{
4528 				m_currentRTFState.m_paraProps.m_iBotBorderStyle = 2;
4529 			}
4530 			else if (m_currentRTFState.m_paraProps.m_iCurBorder == (int) rtfBorderRight)
4531 			{
4532 				m_currentRTFState.m_paraProps.m_iRightBorderStyle = 2;
4533 			}
4534 		}
4535 		return true;
4536 	case RTF_KW_brdrdash:
4537 		if(m_bCellActive)
4538 		{
4539 			if (m_currentRTFState.m_cellProps.m_iCurBorder == rtfCellBorderTop)
4540 			{
4541 				_setStringProperty(m_currentRTFState.m_cellProps.m_sCellProps,"top-style","dashed");
4542 			}
4543 			else if (m_currentRTFState.m_cellProps.m_iCurBorder == rtfCellBorderLeft)
4544 			{
4545 				_setStringProperty(m_currentRTFState.m_cellProps.m_sCellProps,"left-style","dashed");
4546 			}
4547 			else if (m_currentRTFState.m_cellProps.m_iCurBorder == rtfCellBorderBot)
4548 			{
4549 				_setStringProperty(m_currentRTFState.m_cellProps.m_sCellProps,"bot-style","dashed");
4550 			}
4551 			else if (m_currentRTFState.m_cellProps.m_iCurBorder == rtfCellBorderRight)
4552 			{
4553 				_setStringProperty(m_currentRTFState.m_cellProps.m_sCellProps,"right-style","dashed");
4554 			}
4555 		}
4556 		else if(m_bParaActive)
4557 		{
4558 			if (m_currentRTFState.m_paraProps.m_iCurBorder == (int) rtfBorderTop)
4559 			{
4560 				m_currentRTFState.m_paraProps.m_iTopBorderStyle = 3;
4561 			}
4562 			else if (m_currentRTFState.m_paraProps.m_iCurBorder == (int) rtfBorderLeft)
4563 			{
4564 				m_currentRTFState.m_paraProps.m_iLeftBorderStyle = 3;
4565 			}
4566 			else if (m_currentRTFState.m_paraProps.m_iCurBorder == (int) rtfBorderBot)
4567 			{
4568 				m_currentRTFState.m_paraProps.m_iBotBorderStyle = 3;
4569 			}
4570 			else if (m_currentRTFState.m_paraProps.m_iCurBorder == (int) rtfBorderRight)
4571 			{
4572 				m_currentRTFState.m_paraProps.m_iRightBorderStyle = 3;
4573 			}
4574 		}
4575 
4576 		return true;
4577 	case RTF_KW_brdrw:
4578 	{
4579 		double dWidth = static_cast<double>(param)/1440; // convert to inches
4580 		std::string sWidth;
4581 		{
4582 			UT_LocaleTransactor t(LC_NUMERIC, "C");
4583 			sWidth = UT_std_string_sprintf("%fin",dWidth);
4584 		}
4585 		if(m_bCellActive)
4586 		{
4587 			if (m_currentRTFState.m_cellProps.m_iCurBorder == rtfCellBorderTop)
4588 			{
4589 				_setStringProperty(m_currentRTFState.m_cellProps.m_sCellProps,"top-thickness",sWidth.c_str());
4590 			}
4591 			else if (m_currentRTFState.m_cellProps.m_iCurBorder == rtfCellBorderLeft)
4592 			{
4593 				_setStringProperty(m_currentRTFState.m_cellProps.m_sCellProps,"left-thickness",sWidth.c_str());
4594 			}
4595 			else if (m_currentRTFState.m_cellProps.m_iCurBorder == rtfCellBorderBot)
4596 			{
4597 				_setStringProperty(m_currentRTFState.m_cellProps.m_sCellProps,"bot-thickness",sWidth.c_str());
4598 			}
4599 			else if (m_currentRTFState.m_cellProps.m_iCurBorder == rtfCellBorderRight)
4600 			{
4601 				_setStringProperty(m_currentRTFState.m_cellProps.m_sCellProps,"right-thickness",sWidth.c_str());
4602 			}
4603 		}
4604 		else if(m_bParaActive)
4605 		{
4606 			if (m_currentRTFState.m_paraProps.m_iCurBorder == (int) rtfBorderTop)
4607 			{
4608 				m_currentRTFState.m_paraProps.m_iTopBorderWidth = (int) param;
4609 			}
4610 			else if (m_currentRTFState.m_paraProps.m_iCurBorder == (int) rtfBorderLeft)
4611 			{
4612 				m_currentRTFState.m_paraProps.m_iLeftBorderWidth = (int) param;
4613 			}
4614 			else if (m_currentRTFState.m_paraProps.m_iCurBorder == (int) rtfBorderBot)
4615 			{
4616 				m_currentRTFState.m_paraProps.m_iBotBorderWidth = (int) param;
4617 			}
4618 			else if (m_currentRTFState.m_paraProps.m_iCurBorder == (int) rtfBorderRight)
4619 			{
4620 				m_currentRTFState.m_paraProps.m_iRightBorderWidth = (int) param;
4621 			}
4622 		}
4623 		return true;
4624 	}
4625 	case RTF_KW_brdrcf:
4626 	{
4627 		UT_sint32 iCol = static_cast<UT_sint32>(param);
4628 		UT_uint32 colour = GetNthTableColour(iCol);
4629 		std::string sColor = UT_std_string_sprintf("%06x", colour);
4630 		if(m_bCellActive)
4631 		{
4632 			if (m_currentRTFState.m_cellProps.m_iCurBorder == rtfCellBorderTop)
4633 			{
4634 				_setStringProperty(m_currentRTFState.m_cellProps.m_sCellProps,"top-color",sColor.c_str());
4635 			}
4636 			else if (m_currentRTFState.m_cellProps.m_iCurBorder == rtfCellBorderLeft)
4637 			{
4638 				_setStringProperty(m_currentRTFState.m_cellProps.m_sCellProps,"left-color",sColor.c_str());
4639 			}
4640 			else if (m_currentRTFState.m_cellProps.m_iCurBorder == rtfCellBorderBot)
4641 			{
4642 				_setStringProperty(m_currentRTFState.m_cellProps.m_sCellProps,"bot-color",sColor.c_str());
4643 			}
4644 			else if (m_currentRTFState.m_cellProps.m_iCurBorder == rtfCellBorderRight)
4645 			{
4646 				_setStringProperty(m_currentRTFState.m_cellProps.m_sCellProps,"right-color",sColor.c_str());
4647 			}
4648 		}
4649 		else if(m_bParaActive)
4650 		{
4651 			if (m_currentRTFState.m_paraProps.m_iCurBorder == (int) rtfBorderTop)
4652 			{
4653 				m_currentRTFState.m_paraProps.m_iTopBorderCol = (int) param;
4654 			}
4655 			else if (m_currentRTFState.m_paraProps.m_iCurBorder == (int) rtfBorderLeft)
4656 			{
4657 				m_currentRTFState.m_paraProps.m_iLeftBorderCol = (int) param;
4658 			}
4659 			else if (m_currentRTFState.m_paraProps.m_iCurBorder == (int) rtfBorderBot)
4660 			{
4661 				m_currentRTFState.m_paraProps.m_iBotBorderCol = (int) param;
4662 			}
4663 			else if (m_currentRTFState.m_paraProps.m_iCurBorder == (int) rtfBorderRight)
4664 			{
4665 				m_currentRTFState.m_paraProps.m_iRightBorderCol = (int) param;
4666 			}
4667 		}
4668 		return true;
4669 	}
4670 	case RTF_KW_brsp:
4671 		if(m_bParaActive)
4672 		{
4673 			if (m_currentRTFState.m_paraProps.m_iCurBorder == (int) rtfBorderTop)
4674 			{
4675 				m_currentRTFState.m_paraProps.m_iTopBorderSpacing = (int) param;
4676 			}
4677 			else if (m_currentRTFState.m_paraProps.m_iCurBorder == (int) rtfBorderLeft)
4678 			{
4679 				m_currentRTFState.m_paraProps.m_iLeftBorderSpacing = (int) param;
4680 			}
4681 			else if (m_currentRTFState.m_paraProps.m_iCurBorder == (int) rtfBorderBot)
4682 			{
4683 				m_currentRTFState.m_paraProps.m_iBotBorderSpacing = (int) param;
4684 			}
4685 			else if (m_currentRTFState.m_paraProps.m_iCurBorder == (int) rtfBorderRight)
4686 			{
4687 				m_currentRTFState.m_paraProps.m_iRightBorderSpacing = (int) param;
4688 			}
4689 		}
4690 		return true;
4691 	case RTF_KW_brdrnone:
4692 		if(m_bCellActive)
4693 		{
4694 			if(m_currentRTFState.m_cellProps.m_iCurBorder == rtfCellBorderRight)
4695 				m_currentRTFState.m_cellProps.m_bRightBorder = false;
4696 			else if(m_currentRTFState.m_cellProps.m_iCurBorder == rtfCellBorderBot)
4697 				m_currentRTFState.m_cellProps.m_bBotBorder = false;
4698 			else if(m_currentRTFState.m_cellProps.m_iCurBorder == rtfCellBorderLeft)
4699 				m_currentRTFState.m_cellProps.m_bLeftBorder = false;
4700 			else if(m_currentRTFState.m_cellProps.m_iCurBorder == rtfCellBorderTop)
4701 				m_currentRTFState.m_cellProps.m_bTopBorder = false;
4702 		}
4703 		if(m_bParaActive)
4704 		{
4705 			if (m_currentRTFState.m_paraProps.m_iCurBorder == (int) rtfBorderTop)
4706 			{
4707 				m_currentRTFState.m_paraProps.m_bTopBorder = false;
4708 				m_currentRTFState.m_paraProps.m_iTopBorderStyle = 0;
4709 			}
4710 			else if (m_currentRTFState.m_paraProps.m_iCurBorder == (int) rtfBorderLeft)
4711 			{
4712 				m_currentRTFState.m_paraProps.m_bLeftBorder = false;
4713 				m_currentRTFState.m_paraProps.m_iLeftBorderStyle = 0;
4714 			}
4715 			else if (m_currentRTFState.m_paraProps.m_iCurBorder == (int) rtfBorderBot)
4716 			{
4717 				m_currentRTFState.m_paraProps.m_bBotBorder = false;
4718 				m_currentRTFState.m_paraProps.m_iBotBorderStyle = 0;
4719 			}
4720 			else if (m_currentRTFState.m_paraProps.m_iCurBorder == (int) rtfBorderRight)
4721 			{
4722 				m_currentRTFState.m_paraProps.m_bRightBorder = false;
4723 				m_currentRTFState.m_paraProps.m_iRightBorderStyle = 0;
4724 			}
4725 		}
4726 
4727 		return true;
4728 
4729 	case RTF_KW_colortbl:
4730 		// It is import that we don't fail if this fail
4731 		// Just continue
4732 		if(!ReadColourTable()) {
4733 			UT_DEBUGMSG(("RTF ERROR: ReadColourTable() failed.\n"));
4734 		}
4735 		// And this does not even warrant an attempt to recover.
4736 		return true;
4737 	case RTF_KW_cf:
4738 		return HandleColour(fParam ? param : 0);
4739 	case RTF_KW_cb:
4740 		return HandleBackgroundColour (fParam ? param : 0);
4741 	case RTF_KW_cols:
4742 		m_currentRTFState.m_sectionProps.m_numCols = static_cast<UT_uint32>(param);
4743 		return true;
4744 	case RTF_KW_colsx:
4745 		m_currentRTFState.m_sectionProps.m_colSpaceTwips = static_cast<UT_uint32>(param);
4746 		return true;
4747 	case RTF_KW_column:
4748 		return ParseChar(UCS_VTAB);
4749 	case RTF_KW_chdate:
4750 		return _appendField ("date");
4751 	case RTF_KW_chtime:
4752 		return _appendField ("time");
4753 	case RTF_KW_chdpl:
4754 	{
4755 		const gchar * attribs[3] ={"param",NULL,NULL};
4756 		attribs[1] = "%A, %B %d, %Y";
4757 		return _appendField ("datetime_custom", attribs);
4758 	}
4759 	case RTF_KW_chdpa:
4760 	{
4761 //		const gchar * attribs[3] ={"param",NULL,NULL};
4762 //		attribs[1] = "%a, %b %d, %Y";
4763 		return _appendField ("datetime_custom");
4764 	}
4765 	case RTF_KW_chpgn:
4766 		return _appendField ("page_number");
4767 	case RTF_KW_chftn:
4768 		HandleNoteReference();
4769 		break;
4770 	case RTF_KW_cs:
4771 		m_currentRTFState.m_charProps.m_styleNumber = param;
4772 		return true;
4773 	case RTF_KW_cell:
4774 		UT_DEBUGMSG(("SEVIOR: Processing cell \n"));
4775 		HandleCell();
4776 		return true;
4777 	case RTF_KW_cellx:
4778 		HandleCellX(param);
4779 		return true;
4780 	case RTF_KW_clvmrg:
4781 		xxx_UT_DEBUGMSG(("Found Vertical merge cell clvmrg \n"));
4782 		m_currentRTFState.m_cellProps.m_bVerticalMerged = true;
4783 		return true;
4784 	case RTF_KW_clvmgf:
4785 		xxx_UT_DEBUGMSG(("Found Vertical merge cell first clvmgf \n"));
4786 		m_currentRTFState.m_cellProps.m_bVerticalMergedFirst = true;
4787 		return true;
4788 	case RTF_KW_clmrg:
4789 		m_currentRTFState.m_cellProps.m_bHorizontalMerged = true;
4790 		return true;
4791 	case RTF_KW_clmgf:
4792 		m_currentRTFState.m_cellProps.m_bHorizontalMergedFirst = true;
4793 		return true;
4794 	case RTF_KW_clbrdrt:
4795 		xxx_UT_DEBUGMSG(("Border Top set \n"));
4796 		m_currentRTFState.m_cellProps.m_iCurBorder = rtfCellBorderTop;
4797 		m_currentRTFState.m_cellProps.m_bTopBorder = true;
4798 		m_bCellActive = true;
4799 		m_bParaActive = false;
4800 		return true;
4801 	case RTF_KW_clbrdrl:
4802 		xxx_UT_DEBUGMSG(("Border left set \n"));
4803 		m_currentRTFState.m_cellProps.m_iCurBorder = rtfCellBorderLeft;
4804 		m_currentRTFState.m_cellProps.m_bLeftBorder = true;
4805 		m_bCellActive = true;
4806 		m_bParaActive = false;
4807 		return true;
4808 	case RTF_KW_clbrdrb:
4809 		xxx_UT_DEBUGMSG(("Border Bot set \n"));
4810 		m_currentRTFState.m_cellProps.m_iCurBorder = rtfCellBorderBot;
4811 		m_currentRTFState.m_cellProps.m_bBotBorder = true;
4812 		m_bCellActive = true;
4813 		m_bParaActive = false;
4814 		return true;
4815 	case RTF_KW_clbrdrr:
4816 		xxx_UT_DEBUGMSG(("Border Right set \n"));
4817 		m_currentRTFState.m_cellProps.m_iCurBorder = rtfCellBorderRight;
4818 		m_currentRTFState.m_cellProps.m_bRightBorder = true;
4819 		m_bCellActive = true;
4820 		m_bParaActive = false;
4821 		return true;
4822 	case RTF_KW_clcbpat:
4823 	{
4824 		UT_sint32 iCol = static_cast<UT_sint32>(param);
4825 		UT_uint32 colour = GetNthTableColour(iCol);
4826 		std::string sColor = UT_std_string_sprintf("%06x", colour);
4827 		xxx_UT_DEBUGMSG(("Writing background color %s to properties \n",sColor.c_str()));
4828 		_setStringProperty(m_currentRTFState.m_cellProps.m_sCellProps,"background-color",sColor.c_str());
4829 	}
4830 	case RTF_KW_cfpat:
4831 	{
4832 		m_currentRTFState.m_paraProps.m_iShadingPattern = 1;
4833 		m_currentRTFState.m_paraProps.m_iShadingForeCol = (int) param;
4834 	}
4835 	case RTF_KW_cbpat:
4836 	{
4837 		m_currentRTFState.m_paraProps.m_iShadingPattern = 1;
4838 		m_currentRTFState.m_paraProps.m_iShadingBackCol = (int) param;
4839 	}
4840 	break;
4841 	case RTF_KW_deff:
4842 		if (fParam) {
4843 			m_iDefaultFontNumber = param;
4844 			m_currentRTFState.m_charProps.m_fontNumber = m_iDefaultFontNumber;
4845 		}
4846 		break;
4847 	case RTF_KW_dn:
4848 		// subscript with position. Default is 6.
4849 		// superscript: see up keyword
4850 		return HandleSubscriptPosition (fParam ? param : 6);
4851 	case RTF_KW_emdash:
4852 		return ParseChar(UCS_EM_DASH);
4853 	case RTF_KW_endash:
4854 		return ParseChar(UCS_EN_DASH);
4855 	case RTF_KW_emspace:
4856 		return ParseChar(UCS_EM_SPACE);
4857 	case RTF_KW_enspace:
4858 		return ParseChar(UCS_EN_SPACE);
4859 	case RTF_KW_endnotes:
4860 	{
4861 		const gchar * props[] = {"document-endnote-place-endsection", "1",
4862 									NULL};
4863 		getDoc()->setProperties(&props[0]);
4864 	}
4865 	break;
4866 	case RTF_KW_enddoc:
4867 	{
4868 		const gchar * props[] = {"document-endnote-place-enddoc", "1",
4869 									NULL};
4870 		getDoc()->setProperties(&props[0]);
4871 	}
4872 	break;
4873 	case RTF_KW_fonttbl:
4874 		// read in the font table
4875 		if(!ReadFontTable()) {
4876 			UT_DEBUGMSG(("RTF ERROR: ReadFontTable() failed\n"));
4877 		}
4878 		return true;
4879 	case RTF_KW_fs:
4880 		return HandleFontSize(fParam ? param : 24);
4881 	case RTF_KW_f:
4882 		return HandleFace(fParam ? param : m_iDefaultFontNumber);
4883 	case RTF_KW_fi:
4884 		m_currentRTFState.m_paraProps.m_indentFirst = param;
4885 		return true;
4886 	case RTF_KW_field:
4887 		return HandleField ();
4888 	case RTF_KW_fldrslt:
4889 		if(m_bFieldRecognized && (m_iHyperlinkOpen== 0))
4890 		{
4891 //
4892 // skip this until the next "}"
4893 //
4894 			SkipCurrentGroup();
4895 		}
4896 		else
4897 		{
4898 //
4899 // Just parse the text found
4900 //
4901 			return true;
4902 		}
4903 		break;
4904 	case RTF_KW_footer:
4905 	{
4906 		UT_uint32 footerID = 0;
4907 		return HandleHeaderFooter (RTFHdrFtr::hftFooter, footerID);
4908 	}
4909 	case RTF_KW_footerf:
4910 	{
4911 		UT_uint32 footerID = 0;
4912 		return HandleHeaderFooter (RTFHdrFtr::hftFooterFirst, footerID);
4913 	}
4914 	case RTF_KW_footerr:
4915 	{
4916 		UT_uint32 footerID = 0;
4917 		return HandleHeaderFooter (RTFHdrFtr::hftFooterEven, footerID);
4918 	}
4919 	case RTF_KW_footerl:
4920 	{
4921 		UT_uint32 footerID = 0;
4922 		return HandleHeaderFooter (RTFHdrFtr::hftFooter, footerID);
4923 	}
4924 	case RTF_KW_footery:
4925 		// Height ot the header in twips
4926 		m_currentRTFState.m_sectionProps.m_footerYTwips = param;
4927 		break;
4928 	case RTF_KW_gutter:
4929 		// Gap between text and left (or right) margin in twips
4930 		m_currentRTFState.m_sectionProps.m_gutterTwips = param;
4931 		break;
4932 	case RTF_KW_footnote:
4933 		// can be both footnote and endnote ...
4934 // No pasting footnotes/endnotes in HdrFtrs or footnotes/endnotes
4935 		if(bUseInsertNotAppend())
4936 		{
4937 			XAP_Frame * pFrame = XAP_App::getApp()->getLastFocussedFrame();
4938 			if(pFrame == NULL)
4939 			{
4940 				m_currentRTFState.m_destinationState = RTFStateStore::rdsSkip;
4941 				return true;
4942 			}
4943 			FV_View * pView = static_cast<FV_View*>(pFrame->getCurrentView());
4944 			if(pView == NULL)
4945 			{
4946 				m_currentRTFState.m_destinationState = RTFStateStore::rdsSkip;
4947 				return true;
4948 			}
4949 			if(pView->isHdrFtrEdit())
4950 			{
4951 				m_currentRTFState.m_destinationState = RTFStateStore::rdsSkip;
4952 				return true;
4953 			}
4954 			if(pView->isInFootnote(m_dposPaste) || pView->isInEndnote(m_dposPaste) )
4955 		    {
4956 				m_currentRTFState.m_destinationState = RTFStateStore::rdsSkip;
4957 				return true;
4958 			}
4959 		}
4960 
4961 		m_bFootnotePending = true;
4962 		return true;
4963 	case RTF_KW_ftnalt:
4964 		// should not be here, since this keyword is supposed to
4965 		// follow \footnote and is handled separately
4966 		UT_DEBUGMSG(("RTF Keyword \'ftnalt\' where it should not have been\n"));
4967 		return true;
4968 	case RTF_KW_ftnstart:
4969 		if(!getLoadStylesOnly())
4970 		{
4971 			const gchar * props[] = {"document-footnote-initial", NULL,
4972 										NULL};
4973 			std::string i = UT_std_string_sprintf("%d",param);
4974 			props[1] = i.c_str();
4975 			getDoc()->setProperties(&props[0]);
4976 		}
4977 		break;
4978 	case RTF_KW_ftnrstpg:
4979 		if(!getLoadStylesOnly())
4980 		{
4981 			const gchar * props[] = {"document-footnote-restart-page", "1",
4982 										NULL};
4983 			getDoc()->setProperties(&props[0]);
4984 		}
4985 		break;
4986 	case RTF_KW_ftnrestart:
4987 		if(!getLoadStylesOnly())
4988 		{
4989 			const gchar * props[] = {"document-footnote-restart-section", "1",
4990 										NULL};
4991 			getDoc()->setProperties(&props[0]);
4992 		}
4993 		break;
4994 	case RTF_KW_ftnnar:
4995 		if(!getLoadStylesOnly())
4996 		{
4997 			const gchar * props[] = {"document-footnote-type", "numeric",
4998 										NULL};
4999 			getDoc()->setProperties(&props[0]);
5000 		}
5001 		break;
5002 	case RTF_KW_ftnnalc:
5003 		if(!getLoadStylesOnly())
5004 		{
5005 			const gchar * props[] = {"document-footnote-type", "lower",
5006 										NULL};
5007 			getDoc()->setProperties(&props[0]);
5008 		}
5009 		break;
5010 	case RTF_KW_ftnnauc:
5011 		if(!getLoadStylesOnly())
5012 		{
5013 			const gchar * props[] = {"document-footnote-type", "upper",
5014 										NULL};
5015 			getDoc()->setProperties(&props[0]);
5016 		}
5017 		break;
5018 	case RTF_KW_ftnnrlc:
5019 		if(!getLoadStylesOnly())
5020 		{
5021 			const gchar * props[] = {"document-footnote-type", "lower-roman",
5022 										NULL};
5023 			getDoc()->setProperties(&props[0]);
5024 		}
5025 		break;
5026 	case RTF_KW_ftnnruc:
5027 		if(!getLoadStylesOnly())
5028 		{
5029 			const gchar * props[] = {"document-footnote-type", "upper-roman",
5030 										NULL};
5031 			getDoc()->setProperties(&props[0]);
5032 		}
5033 		break;
5034 	case RTF_KW_headery:
5035 		// Height ot the header in twips
5036 		m_currentRTFState.m_sectionProps.m_headerYTwips = param;
5037 		break;
5038 	case RTF_KW_header:
5039 	{
5040 		UT_uint32 headerID = 0;
5041 		return HandleHeaderFooter (RTFHdrFtr::hftHeader, headerID);
5042 	}
5043 	case RTF_KW_headerf:
5044 	{
5045 		UT_uint32 headerID = 0;
5046 		return HandleHeaderFooter (RTFHdrFtr::hftHeaderFirst, headerID);
5047 	}
5048 	case RTF_KW_headerr:
5049 	{
5050 		UT_uint32 headerID = 0;
5051 		return HandleHeaderFooter (RTFHdrFtr::hftHeaderEven, headerID);
5052 	}
5053 	case RTF_KW_headerl:
5054 	{
5055 		UT_uint32 headerID = 0;
5056 		return HandleHeaderFooter (RTFHdrFtr::hftHeader, headerID);
5057 	}
5058 	case RTF_KW_highlight:
5059 		return HandleBackgroundColour(param);
5060 	case RTF_KW_i:
5061 		// italic - either on or off depending on the parameter
5062 		return HandleItalic(fParam ? false : true);
5063 	case RTF_KW_info:
5064 		// TODO Ignore document info for the moment
5065 		return HandleInfoMetaData();
5066 	case RTF_KW_ilvl:
5067 		m_currentRTFState.m_paraProps.m_iOverrideLevel = static_cast<UT_uint32>(_sanitizeListLevel(param));
5068 		return true;
5069 	case RTF_KW_intbl:
5070 		UT_DEBUGMSG(("done intbl \n"));
5071 		m_currentRTFState.m_paraProps.m_bInTable = true;
5072 		return true;
5073 	case RTF_KW_itap:
5074 		if(bUseInsertNotAppend())
5075 		{
5076 			return true;
5077 		}
5078 		if(m_bInFootnote)
5079 		{
5080 			return true;
5081 		}
5082 		m_currentRTFState.m_paraProps.m_tableLevel = param;
5083 //
5084 // Look to see if the nesting level of our tables has changed.
5085 //
5086 		xxx_UT_DEBUGMSG(("SEVIOR!!! itap m_tableLevel %d nestDepth %d \n",m_currentRTFState.m_paraProps.m_tableLevel,m_TableControl.getNestDepth()));
5087 		if(m_currentRTFState.m_paraProps.m_tableLevel > m_TableControl.getNestDepth())
5088 		{
5089 			while(m_currentRTFState.m_paraProps.m_tableLevel > m_TableControl.getNestDepth())
5090 			{
5091 				xxx_UT_DEBUGMSG(("SEVIOR: Doing itap OpenTable \n"));
5092 				OpenTable();
5093 			}
5094 		}
5095 		else if((m_currentRTFState.m_paraProps.m_tableLevel >= 0) && m_currentRTFState.m_paraProps.m_tableLevel < m_TableControl.getNestDepth())
5096 		{
5097 			while(m_currentRTFState.m_paraProps.m_tableLevel < m_TableControl.getNestDepth())
5098 			{
5099 				CloseTable();
5100 			}
5101 
5102 			if(param == 0)
5103 			{
5104 				// we closed the highest level table; in rtf table is equivalent to a block,
5105 				// while our table is contained in a block
5106 				// so we have to insert a block to get the same effect
5107 				StartNewPara();
5108 			}
5109 
5110 		}
5111 		xxx_UT_DEBUGMSG(("SEVIOR!!! After itap m_tableLevel %d nestDepth %d \n",m_currentRTFState.m_paraProps.m_tableLevel,m_TableControl.getNestDepth()));
5112 
5113 		return true;
5114 	case RTF_KW_lquote:
5115 		return ParseChar(UCS_LQUOTE);
5116 	case RTF_KW_ldblquote:
5117 		return ParseChar(UCS_LDBLQUOTE);
5118 	case RTF_KW_li:
5119 		m_currentRTFState.m_paraProps.m_indentLeft = param;
5120 		return true;
5121 	case RTF_KW_line:
5122 		return ParseChar(UCS_LF);
5123 	case RTF_KW_linebetcol:
5124 		m_currentRTFState.m_sectionProps.m_bColumnLine = true;
5125 		return true;
5126 	case RTF_KW_lang:
5127 		xxx_UT_DEBUGMSG(("DOM: lang code (0x%p, %s)\n", param, wvLIDToLangConverter(static_cast<unsigned short>(param))));
5128 		// mark language for spell checking
5129 		m_currentRTFState.m_charProps.m_szLang = wvLIDToLangConverter(static_cast<unsigned short>(param));
5130 		return true;
5131 	case RTF_KW_listoverridetable:
5132 		return ReadListOverrideTable();
5133 	case RTF_KW_listtext:
5134 		// This paragraph is a member of a list.
5135 		SkipCurrentGroup( false);
5136 		return true;
5137 	case RTF_KW_ls:
5138 		// This paragraph is a member of a list.
5139 		m_currentRTFState.m_paraProps.m_iOverride = static_cast<UT_uint32>(param);
5140 		m_currentRTFState.m_paraProps.m_isList = true;
5141 		return true;
5142 	case RTF_KW_landscape:
5143         // TODO
5144         // Just set landscape mode.
5145         //
5146 		break;
5147 	case RTF_KW_ltrpar:
5148 		xxx_UT_DEBUGMSG(("rtf imp.: ltrpar\n"));
5149 		m_currentRTFState.m_paraProps.m_dir = UT_BIDI_LTR;
5150 		//reset doc bidi attribute
5151 		m_bBidiMode = false;
5152 		return true;
5153 	case RTF_KW_ltrsect:
5154 		xxx_UT_DEBUGMSG(("rtf imp.: ltrsect\n"));
5155 		m_currentRTFState.m_sectionProps.m_dir = UT_BIDI_LTR;
5156 		return true;
5157 	case RTF_KW_ltrmark:
5158 	case RTF_KW_ltrch:
5159 		xxx_UT_DEBUGMSG(("rtf imp.: ltrch\n"));
5160 		m_currentRTFState.m_charProps.m_dir = UT_BIDI_LTR;
5161 
5162 		// we enter bidi mode if we encounter a character
5163 		// formatting inconsistent with the base direction of the
5164 		// paragraph; once in bidi mode, we have to stay there
5165 		// until the end of the current pragraph
5166 		m_bBidiMode = m_bBidiMode ||
5167 			(m_currentRTFState.m_charProps.m_dir ^ m_currentRTFState.m_paraProps.m_dir);
5168 		return true;
5169 	case RTF_KW_mac:
5170 		// TODO some iconv's may have a different name - "MacRoman"
5171 		// TODO EncodingManager should handle encoding names
5172 		m_mbtowc.setInCharset("MACINTOSH");
5173 		if(!getLoadStylesOnly())
5174 			getDoc()->setEncodingName("MacRoman");
5175 		return true;
5176 	case RTF_KW_marglsxn:
5177 		// Left margin of section
5178 		m_currentRTFState.m_sectionProps.m_leftMargTwips = param;
5179 		break;
5180 	case RTF_KW_margl:
5181 		m_sectdProps.m_leftMargTwips = param ;
5182 
5183 		// bug 9432: the \margl is document default, and we have to adjust the current
5184 		// settings accordingly -- this assumes that \margl is not preceeded by \marglsxn,
5185 		// but since \margl is document wide setting this should be true in normal rtf
5186 		// documents (otherwise we would need to add m_b*Changed members to the sect props
5187 		// for everyting).
5188 		m_currentRTFState.m_sectionProps.m_leftMargTwips = param;
5189 		break;
5190 	case RTF_KW_margrsxn:
5191 		// Right margin of section
5192 		m_currentRTFState.m_sectionProps.m_rightMargTwips = param;
5193 		break;
5194 	case RTF_KW_margr:
5195 		m_sectdProps.m_rightMargTwips = param;
5196 
5197 		// bug 9432: the \margl is document default, and we have to adjust the current
5198 		// settings accordingly -- this assumes that \margl is not preceeded by \marglsxn,
5199 		// but since \margl is document wide setting this should be true in normal rtf
5200 		// documents (otherwise we would need to add m_b*Changed members to the sect props
5201 		// for everyting).
5202 		m_currentRTFState.m_sectionProps.m_rightMargTwips = param;
5203 		break;
5204 	case RTF_KW_margtsxn:
5205 		// top margin of section
5206 		m_currentRTFState.m_sectionProps.m_topMargTwips = param;
5207 		break;
5208 	case RTF_KW_margt:
5209 		m_sectdProps.m_topMargTwips = param;
5210 
5211 		// bug 9432: the \margl is document default, and we have to adjust the current
5212 		// settings accordingly -- this assumes that \margl is not preceeded by \marglsxn,
5213 		// but since \margl is document wide setting this should be true in normal rtf
5214 		// documents (otherwise we would need to add m_b*Changed members to the sect props
5215 		// for everyting).
5216 		m_currentRTFState.m_sectionProps.m_topMargTwips = param;
5217 		break;
5218 	case RTF_KW_margbsxn:
5219 		// bottom margin of section
5220 		m_currentRTFState.m_sectionProps.m_bottomMargTwips = param;
5221 		break;
5222 	case RTF_KW_margb:
5223 		m_sectdProps.m_bottomMargTwips = param;
5224 
5225 		// bug 9432: the \margl is document default, and we have to adjust the current
5226 		// settings accordingly -- this assumes that \margl is not preceeded by \marglsxn,
5227 		// but since \margl is document wide setting this should be true in normal rtf
5228 		// documents (otherwise we would need to add m_b*Changed members to the sect props
5229 		// for everyting).
5230 		m_currentRTFState.m_sectionProps.m_bottomMargTwips = param;
5231 		break;
5232 	case RTF_KW_nestrow:
5233 		HandleRow();
5234 		return true;
5235 	case RTF_KW_nestcell:
5236 		UT_DEBUGMSG(("SEVIOR: Processing nestcell \n"));
5237 		HandleCell();
5238 		return true;
5239 	case RTF_KW_nonesttables:
5240 		//
5241 		// skip this!
5242 		//
5243 		UT_DEBUGMSG(("SEVIOR: doing nonesttables \n"));
5244 		SkipCurrentGroup();
5245 		return true;
5246 	case RTF_KW_nonshppict:
5247 		// we ignore this one since we handle shppict.
5248 		UT_DEBUGMSG(("Hub: skipping nonshppict\n"));
5249 		SkipCurrentGroup(false);
5250 		break;
5251 	case RTF_KW_noproof:
5252 		// Set language to none for \noproof
5253 		// TODO actually implement proofing flag separate to language setting
5254 		UT_DEBUGMSG(("HIPI: RTF import keyword \\noproof\n"));
5255 		// mark language for spell checking
5256 		m_currentRTFState.m_charProps.m_szLang = "-none-";
5257 		return true;
5258 	case RTF_KW_ol:
5259 		return HandleOverline(fParam ? (param != 0) : true);
5260 	case RTF_KW_object:
5261 		// get picture
5262 		return HandleObject();
5263 	case RTF_KW_par:
5264 		// start new paragraph, continue current attributes
5265 		xxx_UT_DEBUGMSG(("Done par \n"));
5266 		return HandleParKeyword();
5267 	case RTF_KW_plain:
5268 		// reset character attributes
5269 		return ResetCharacterAttributes();
5270 	case RTF_KW_pard:
5271 	{
5272 		// reset paragraph attributes
5273 		xxx_UT_DEBUGMSG(("Done pard \n"));
5274 		bool bres = ResetParagraphAttributes();
5275 
5276 		return bres;
5277 	}
5278 	case RTF_KW_page:
5279 		return ParseChar(UCS_FF);
5280 	case RTF_KW_pntext:
5281 		//
5282 		// skip this!
5283 		//
5284 		//SkipCurrentGroup( false);
5285 		m_currentRTFState.m_destinationState = RTFStateStore::rdsSkip;
5286 		return true;
5287 	case RTF_KW_pict:
5288 		// get picture
5289 		UT_DEBUGMSG(("FOund a pict!!! \n"));
5290 		return HandlePicture();
5291 	case RTF_KW_pc:
5292 		m_mbtowc.setInCharset(XAP_EncodingManager::get_instance()->charsetFromCodepage(437));
5293 		return true;
5294 	case RTF_KW_pca:
5295 		m_mbtowc.setInCharset(XAP_EncodingManager::get_instance()->charsetFromCodepage(850));
5296 		return true;
5297 	case RTF_KW_paperw:
5298         //
5299         // Just set the page width
5300         //
5301 		if(!getLoadStylesOnly())
5302 		{
5303 			double height = getDoc()->m_docPageSize.Height(DIM_IN);
5304 			double width = (static_cast<double>(param))/1440.0;
5305 			getDoc()->m_docPageSize.Set(width,height,DIM_IN);
5306 			UT_DEBUGMSG(("Page set to width %f height %f \n",width,height));
5307 		}
5308 		break;
5309 	case RTF_KW_paperh:
5310         //
5311 		// Just set the page height
5312 		//
5313 		if(!getLoadStylesOnly())
5314 		{
5315 			double width = getDoc()->m_docPageSize.Width(DIM_IN);
5316 			double height = (static_cast<double>(param))/1440.0;
5317 			getDoc()->m_docPageSize.Set(width,height,DIM_IN);
5318 			UT_DEBUGMSG(("Page set to width %f height %f \n",width,height));
5319 		}
5320 		break;
5321 
5322 	case RTF_KW_ql:
5323 		return SetParaJustification(RTFProps_ParaProps::pjLeft);
5324 	case RTF_KW_qc:
5325 		return SetParaJustification(RTFProps_ParaProps::pjCentre);
5326 	case RTF_KW_qr:
5327 		return SetParaJustification(RTFProps_ParaProps::pjRight);
5328 	case RTF_KW_qj:
5329 		return SetParaJustification(RTFProps_ParaProps::pjFull);
5330 
5331 	case RTF_KW_rquote:
5332 		return ParseChar(UCS_RQUOTE);
5333 	case RTF_KW_rdblquote:
5334 		return ParseChar(UCS_RDBLQUOTE);
5335 
5336 	// various revision keywords
5337 	case RTF_KW_deleted: // skip this -- it is redundant
5338 	case RTF_KW_revised:
5339 		return true;
5340 
5341 	case RTF_KW_revauthdel:
5342 		if(m_currentRTFState.m_revAttr.size())
5343 			return true; // ignore this
5344 		else
5345 			return HandleRevisedText(PP_REVISION_DELETION, param);
5346 	case RTF_KW_revauth:
5347 		if(m_currentRTFState.m_revAttr.size())
5348 			return true; // ignore this
5349 		else
5350 			return HandleRevisedText(PP_REVISION_ADDITION, param);
5351 	case RTF_KW_crauth:
5352 		if(m_currentRTFState.m_revAttr.size())
5353 			return true; // ignore this
5354 		else
5355 			return HandleRevisedText(PP_REVISION_FMT_CHANGE, param);
5356 
5357 	case RTF_KW_crdate:
5358 	case RTF_KW_revdttmdel:
5359 	case RTF_KW_revdttm:
5360 		if(m_currentRTFState.m_revAttr.size())
5361 			return true; // ignore this
5362 		else
5363 			return HandleRevisedTextTimestamp(param);
5364 
5365 
5366 	case RTF_KW_ri:
5367 		m_currentRTFState.m_paraProps.m_indentRight = param;
5368 		return true;
5369 	case RTF_KW_rtf:
5370 		return true;
5371 	case RTF_KW_rtlpar:
5372 		xxx_UT_DEBUGMSG(("rtf imp.: rtlpar\n"));
5373 		m_currentRTFState.m_paraProps.m_dir = UT_BIDI_RTL;
5374 		// reset the doc bidi attribute
5375 		m_bBidiMode = false;
5376 		return true;
5377 	case RTF_KW_rtlsect:
5378 		UT_DEBUGMSG(("rtf imp.: rtlsect\n"));
5379 		m_currentRTFState.m_sectionProps.m_dir = UT_BIDI_RTL;
5380 		return true;
5381 
5382 	case RTF_KW_rtlmark:
5383 	case RTF_KW_rtlch:
5384 		xxx_UT_DEBUGMSG(("rtf imp.: rtlch\n"));
5385 		m_currentRTFState.m_charProps.m_dir = UT_BIDI_RTL;
5386 		// we enter bidi mode if we encounter a character
5387 		// formatting inconsistent with the base direction of the
5388 		// paragraph; once in bidi mode, we have to stay there
5389 		// until the end of the current pragraph
5390 		m_bBidiMode = m_bBidiMode ||
5391 			(m_currentRTFState.m_charProps.m_dir ^ m_currentRTFState.m_paraProps.m_dir);
5392 		return true;
5393 	case RTF_KW_row:
5394 		HandleRow();
5395 		return true;
5396 
5397 	case RTF_KW_s:
5398 		m_currentRTFState.m_paraProps.m_styleNumber = param;
5399 		return true;
5400 	case RTF_KW_stylesheet:
5401 		return HandleStyleDefinition();
5402 	case RTF_KW_strike:
5403 	case RTF_KW_striked:
5404 		return HandleStrikeout(fParam ? (param != 0) : true);
5405 	case RTF_KW_sect:
5406 		return StartNewSection();
5407 	case RTF_KW_sectd:
5408 		return ResetSectionAttributes();
5409 	case RTF_KW_sa:
5410 		m_currentRTFState.m_paraProps.m_spaceAfter = param;
5411 		return true;
5412 	case RTF_KW_sb:
5413 		m_currentRTFState.m_paraProps.m_spaceBefore = param;
5414 		return true;
5415 	case RTF_KW_sbknone:
5416 		m_currentRTFState.m_sectionProps.m_breakType = RTFProps_SectionProps::sbkNone;
5417 		return true;
5418 	case RTF_KW_sbkcol:
5419 		m_currentRTFState.m_sectionProps.m_breakType = RTFProps_SectionProps::sbkColumn;
5420 		return true;
5421 	case RTF_KW_sbkpage:
5422 		m_currentRTFState.m_sectionProps.m_breakType = RTFProps_SectionProps::sbkPage;
5423 		return true;
5424 	case RTF_KW_sbkeven:
5425 		m_currentRTFState.m_sectionProps.m_breakType = RTFProps_SectionProps::sbkEven;
5426 		return true;
5427 	case RTF_KW_sbkodd:
5428 		m_currentRTFState.m_sectionProps.m_breakType = RTFProps_SectionProps::sbkOdd;
5429 		return true;
5430 	case RTF_KW_shp:
5431 // Found a positioned thingy
5432 		HandleShape();
5433 		return true;
5434  	case RTF_KW_sl:
5435 		if (!fParam  ||  param == 0) {
5436 			m_currentRTFState.m_paraProps.m_lineSpaceVal = 360;
5437 		}
5438 		else {
5439 			m_currentRTFState.m_paraProps.m_lineSpaceVal = param;
5440 		}
5441 		return true;
5442 	case RTF_KW_slmult:
5443 		m_currentRTFState.m_paraProps.m_lineSpaceExact = (!fParam  ||  param == 0);
5444 		return true;
5445 	case RTF_KW_super:
5446 		return HandleSuperscript(fParam ? false : true);
5447 	case RTF_KW_sub:
5448 		return HandleSubscript(fParam ? false : true);
5449 
5450 	case RTF_KW_tab:
5451 		return ParseChar('\t');
5452 	case RTF_KW_tx:
5453 	{
5454 		UT_return_val_if_fail(fParam, false);	// tabstops should have parameters
5455 		bool bres = AddTabstop(param,
5456 							   m_currentRTFState.m_paraProps.m_curTabType,
5457 							   m_currentRTFState.m_paraProps.m_curTabLeader);
5458 		m_currentRTFState.m_paraProps.m_curTabType = FL_TAB_LEFT;
5459 //			m_currentRTFState.m_paraProps.m_curTabLeader = FL_LEADER_NONE;
5460 		return bres;
5461 	}
5462 	case RTF_KW_tb:
5463 	{
5464 		UT_return_val_if_fail(fParam, false);	// tabstops should have parameters
5465 
5466 		bool bres = AddTabstop(param,FL_TAB_BAR,
5467 							   m_currentRTFState.m_paraProps.m_curTabLeader);
5468 		m_currentRTFState.m_paraProps.m_curTabType = FL_TAB_BAR;
5469 //			m_currentRTFState.m_paraProps.m_curTabLeader = FL_LEADER_NONE;
5470 		return bres;
5471 	}
5472 	case RTF_KW_tqr:
5473 		m_currentRTFState.m_paraProps.m_curTabType = FL_TAB_RIGHT;
5474 		return true;
5475 	case RTF_KW_tqc:
5476 		m_currentRTFState.m_paraProps.m_curTabType = FL_TAB_CENTER;
5477 		return true;
5478 	case RTF_KW_tqdec:
5479 		m_currentRTFState.m_paraProps.m_curTabType = FL_TAB_DECIMAL;
5480 		return true;
5481 	case RTF_KW_tldot:
5482 		m_currentRTFState.m_paraProps.m_curTabLeader = FL_LEADER_DOT;
5483 		return true;
5484 	case RTF_KW_tlhyph:
5485 		m_currentRTFState.m_paraProps.m_curTabLeader = FL_LEADER_HYPHEN;
5486 		return true;
5487 	case RTF_KW_trautofit:
5488 		if(getTable())
5489 		{
5490 			if(param==1)
5491 			{
5492 				getTable()->setAutoFit(true);
5493 			}
5494 		}
5495 		return true;
5496 	case RTF_KW_trleft:
5497 		if(getTable())
5498 		{
5499 			double dLeftPos = static_cast<double>(param)/1440.0;
5500 			std::string sLeftPos = UT_formatDimensionString(DIM_IN,dLeftPos,NULL);
5501 			getTable()->setProp("table-column-leftpos",sLeftPos);
5502 		}
5503 		return true;
5504 	case RTF_KW_tlul:
5505 		m_currentRTFState.m_paraProps.m_curTabLeader = FL_LEADER_UNDERLINE;
5506 		return true;
5507 	case RTF_KW_tleq:
5508 		m_currentRTFState.m_paraProps.m_curTabLeader = FL_LEADER_EQUALSIGN;
5509 		return true;
5510 	case RTF_KW_trowd:
5511 		{
5512 			m_bRowJustPassed = false;
5513 			m_bDoCloseTable = false;
5514 			UT_DEBUGMSG(("Doing trowd \n"));
5515 			if(getTable() == NULL)
5516 			{
5517 				OpenTable();
5518 				m_currentRTFState.m_paraProps.m_tableLevel = m_TableControl.getNestDepth();
5519 			}
5520 //
5521 // Look to see if the nesting level of our tables has changed.
5522 //
5523 			if(m_currentRTFState.m_paraProps.m_tableLevel > m_TableControl.getNestDepth())
5524 			{
5525 				xxx_UT_DEBUGMSG(("At trowd m_tableLevel %d nestDepth %d \n",m_currentRTFState.m_paraProps.m_tableLevel,m_TableControl.getNestDepth()));
5526 				while(m_currentRTFState.m_paraProps.m_tableLevel > m_TableControl.getNestDepth())
5527 				{
5528 					xxx_UT_DEBUGMSG(("SEVIOR: Doing pard OpenTable \n"));
5529 					OpenTable();
5530 				}
5531 				xxx_UT_DEBUGMSG(("After trowd m_tableLevel %d nestDepth %d \n",m_currentRTFState.m_paraProps.m_tableLevel,m_TableControl.getNestDepth()));
5532 			}
5533 			else if((m_currentRTFState.m_paraProps.m_tableLevel >= 0) && m_currentRTFState.m_paraProps.m_tableLevel < m_TableControl.getNestDepth())
5534 			{
5535 				xxx_UT_DEBUGMSG(("At trowd m_tableLevel %d nestDepth %d \n",m_currentRTFState.m_paraProps.m_tableLevel,m_TableControl.getNestDepth()));
5536 				while(m_currentRTFState.m_paraProps.m_tableLevel < m_TableControl.getNestDepth())
5537 				{
5538 					xxx_UT_DEBUGMSG(("SEVIOR:Close Table trowd1  \n"));
5539 					CloseTable();
5540 					m_bCellBlank = true;
5541 				}
5542 				xxx_UT_DEBUGMSG(("After trowd m_tableLevel %d nestDepth %d \n",m_currentRTFState.m_paraProps.m_tableLevel,m_TableControl.getNestDepth()));
5543 			}
5544 //
5545 // Look to see if m_bNestTableProps is true for nested tables.
5546 //
5547 // To all RTF hackers, getting these 0's and 1's is extremely important.
5548 // Don't change them unless you can verify that a huge range of RTF docs with
5549 // tables (nested and unnested) get imported corectly. Martin 10/5/2003
5550 			else if((m_TableControl.getNestDepth() > 0) && !m_bNestTableProps)
5551 			{
5552 				while(m_TableControl.getNestDepth() > 1)
5553 				{
5554 					xxx_UT_DEBUGMSG(("SEVIOR:Close Table trowd2 \n"));
5555 					CloseTable();
5556 					m_bCellBlank = true;
5557 				}
5558 				m_currentRTFState.m_paraProps.m_tableLevel = 1;
5559 			}
5560 
5561 			//If a trowd appears without  a preceding \cell we close the previous table
5562 
5563 			if(!m_bCellBlank && !m_bNestTableProps)
5564 			{
5565 				xxx_UT_DEBUGMSG(("After trowd closing table coz no cell detected -1\n"));
5566 				CloseTable();
5567 			}
5568 
5569 
5570 // Another way of detecting if a trowd appears without a preceding \cell.
5571 // Close the previous table. This should always work.
5572 
5573 			else if(!m_bCellHandled && m_bContentFlushed)
5574 			{
5575 				UT_DEBUGMSG(("After trowd closing table coz no cell detected - 2\n"));
5576 				CloseTable();
5577 			}
5578 			//   			m_bContentFlushed = false;
5579 			m_bNestTableProps = false;
5580 			ResetCellAttributes();
5581 			ResetTableAttributes();
5582 			break;
5583 		}
5584 
5585 	case RTF_KW_ul:
5586 	case RTF_KW_uld:
5587 	case RTF_KW_uldash:
5588 	case RTF_KW_uldashd:
5589 	case RTF_KW_uldashdd:
5590 	case RTF_KW_uldb:
5591 	case RTF_KW_ulth:
5592 	case RTF_KW_ulw:
5593 	case RTF_KW_ulwave:
5594 		return HandleUnderline(fParam ? (param != 0) : true);
5595 	case RTF_KW_ulnone:
5596 		return HandleUnderline(0);
5597 	case RTF_KW_uc:
5598 		// "\uc<n>" defines the number of chars immediately following
5599 		// any "\u<u>" unicode character that are needed to represent
5600 		// a reasonable approximation for the unicode character.
5601 		// generally, this is done by stripping off accents from latin-n
5602 		// characters so that they fold into latin1.
5603 		//
5604 		// the spec says that we need to allow any arbitrary length
5605 		// of chars for this and that we need to maintain a stack of
5606 		// these lengths (as content is nested within {} groups) so
5607 		// that different 'destinations' can have different approximations
5608 		// or have a local diversion for a hard-to-represent character
5609 		// or something like that.
5610 		//
5611 		// this is bullshit (IMHO) -- jeff
5612 
5613 		m_currentRTFState.m_unicodeAlternateSkipCount = param;
5614 		m_currentRTFState.m_unicodeInAlternate = 0;
5615 		return true;
5616 	case RTF_KW_u:
5617 	{
5618 		/* RTF is limited to +/-32K ints so we need to use negative numbers for large unicode values.
5619 		 * So, check for Unicode chars wrapped to negative values.
5620 		 */
5621 		static UT_UCS4Char buf = 0x10000;
5622 		bool bResult;
5623 		if (param < 0)
5624 		{
5625 			unsigned short tmp = (unsigned short) ((signed short) param);
5626 			param = (UT_sint32) tmp;
5627 		}
5628 		if ((unsigned) param >= 0xD800 && (unsigned) param <= 0xDBFF)
5629 		{
5630 			buf = (UT_UCS4Char) param - 0xD800;
5631 			buf <<= 10;
5632 			buf += 0x10000;
5633 			m_currentRTFState.m_unicodeInAlternate = m_currentRTFState.m_unicodeAlternateSkipCount;
5634 			return true;
5635 		}
5636 		if ((unsigned) param >= 0xDC00 && (unsigned) param <= 0xDFFF)
5637 		{
5638 			buf += (UT_UCS4Char) param;
5639 			buf -= 0xDC00;
5640 			bResult = ParseChar(static_cast<UT_UCSChar>(buf));
5641 			buf = 0x10000;
5642 		}
5643 		else
5644 			bResult = ParseChar(static_cast<UT_UCSChar>(param));
5645 		m_currentRTFState.m_unicodeInAlternate = m_currentRTFState.m_unicodeAlternateSkipCount;
5646 		return bResult;
5647 	}
5648 	case RTF_KW_up:
5649 		// superscript with position. Default is 6.
5650 		// subscript: see dn keyword
5651 		return HandleSuperscriptPosition (fParam ? param : 6);
5652 
5653 	case RTF_KW_v:
5654 		HandleHidden(fParam ? (param != 0) : true);
5655 		break;
5656 
5657 	case RTF_KW_STAR:
5658 		return HandleStarKeyword();
5659 		break;
5660 	case RTF_KW_QUOTE:
5661 		m_currentRTFState.m_internalState = RTFStateStore::risHex;
5662 		return true;
5663 		break;
5664 	case RTF_KW_OPENCBRACE:
5665 		ParseChar('{');
5666 		return true;
5667 		break;
5668 	case RTF_KW_CLOSECBRACE:
5669 		ParseChar('}');
5670 		return true;
5671 		break;
5672 	case RTF_KW_BACKSLASH:
5673 		ParseChar('\\');
5674 		return true;
5675 		break;
5676 	case RTF_KW_TILDE:
5677 		ParseChar(UCS_NBSP);
5678 		return true;
5679 		break;
5680 	case RTF_KW_HYPHEN:
5681 		// TODO handle optional hyphen. Currently simply ignore them.
5682 		xxx_UT_DEBUGMSG (("RTF: TODO handle optionnal hyphen\n"));
5683 		return true;
5684 		break;
5685 	case RTF_KW_UNDERSCORE:
5686 		// currently simply make a standard hyphen
5687 		ParseChar('-');	// TODO - make these optional and nonbreaking
5688 		return true;
5689 		break;
5690 	case RTF_KW_CR:	// see bug 2174 ( Cocoa RTF)
5691 	case RTF_KW_LF:
5692 		return StartNewPara();
5693 		break;
5694 	default:
5695 		xxx_UT_DEBUGMSG(("Unhandled keyword in dispatcher: %d\n", keywordID));
5696 	}
5697 	return true;
5698 }
5699 
5700 
5701 
5702 
HandleStarKeyword()5703 bool IE_Imp_RTF::HandleStarKeyword()
5704 {
5705 	unsigned char keyword_star[MAX_KEYWORD_LEN];
5706 	UT_sint32 parameter_star = 0;
5707 	bool parameterUsed_star = false;
5708 	xxx_UT_DEBUGMSG(("RTF Level in HandlStarKeyword %d \n",m_stateStack.getDepth()));
5709 	m_currentRTFState.m_bInKeywordStar = true;
5710 	if (ReadKeyword(keyword_star, &parameter_star, &parameterUsed_star,
5711 					MAX_KEYWORD_LEN))
5712 	{
5713 		xxx_UT_DEBUGMSG(("keyword_star %s read after * \n",keyword_star));
5714 
5715 		if( strcmp(reinterpret_cast<char*>(keyword_star), "\\")== 0)
5716 		{
5717 			if (ReadKeyword(keyword_star, &parameter_star, &parameterUsed_star,
5718 							MAX_KEYWORD_LEN))
5719 			{
5720 
5721 				xxx_UT_DEBUGMSG(("actual keyword_star %s read after * \n",keyword_star));
5722 				RTF_KEYWORD_ID keywordID = KeywordToID(reinterpret_cast<char *>(keyword_star));
5723 				switch (keywordID) {
5724 				case RTF_KW_ol:
5725 					return HandleOverline(parameterUsed_star ?
5726 										  (parameter_star != 0): true);
5727 					break;
5728 				case RTF_KW_pn:
5729 					return HandleLists( m_currentRTFState.m_paraProps.m_rtfListTable);
5730 					break;
5731 				case RTF_KW_listtable:
5732 					return ReadListTable();
5733 					break;
5734 				case RTF_KW_listoverridetable:
5735 					return ReadListOverrideTable();
5736 					break;
5737 				case RTF_KW_abilist:
5738 					return HandleAbiLists();
5739 					break;
5740 				case RTF_KW_topline:
5741 					return HandleTopline(parameterUsed_star ?
5742 										 (parameter_star != 0): true);
5743 					break;
5744 				case RTF_KW_botline:
5745 					return HandleBotline(parameterUsed_star ?
5746 										 (parameter_star != 0): true);
5747 					break;
5748 				case RTF_KW_listtag:
5749 					return HandleListTag(parameter_star);
5750 					break;
5751 				case RTF_KW_abicellprops:
5752 					if(!bUseInsertNotAppend())
5753 					{
5754 						xxx_UT_DEBUGMSG (("ignoring abicellprops on file import \n"));
5755 						m_currentRTFState.m_destinationState = RTFStateStore::rdsSkip;
5756 						return true;
5757 					}
5758 					if(m_iIsInHeaderFooter == 1)
5759 					{
5760 						m_currentRTFState.m_destinationState = RTFStateStore::rdsSkip;
5761 						return true;
5762 					}
5763 					return HandleAbiCell();
5764 					break;
5765 				case RTF_KW_abirevision:
5766 					{
5767 						// the abirevision keyword is enclosed in {}, having its own
5768 						// stack; we however need to set the m_abiRevision parameter of
5769 						// the parent stack
5770 						bool bSuccess = PopRTFState();
5771 
5772 						UT_return_val_if_fail( bSuccess, false );
5773 
5774 						// OK scan through the text until a closing delimeter is
5775 						// found
5776 						unsigned char ch;
5777 
5778 
5779 						while(ReadCharFromFile(&ch))
5780 						{
5781 							if(ch == '}')
5782 								break;
5783 
5784 							if(ch == '\\')
5785 							{
5786 								if (!ReadCharFromFile(&ch))
5787 									return false;
5788 							}
5789 
5790 
5791 							m_currentRTFState.m_revAttr += ch;
5792 						}
5793 
5794 						return true;
5795 					}
5796 
5797 				case RTF_KW_abitableprops:
5798 					if(!bUseInsertNotAppend())
5799 					{
5800 						UT_DEBUGMSG (("ignoring abictableprops on file import \n"));
5801 						m_currentRTFState.m_destinationState = RTFStateStore::rdsSkip;
5802 						return true;
5803 					}
5804 					if(m_iIsInHeaderFooter == 1)
5805 					{
5806 						m_currentRTFState.m_destinationState = RTFStateStore::rdsSkip;
5807 						return true;
5808 					}
5809 					if(m_iIsInHeaderFooter == 0)
5810 					{
5811 						XAP_Frame * pFrame = XAP_App::getApp()->getLastFocussedFrame();
5812 						if(pFrame == NULL)
5813 						{
5814 							m_iIsInHeaderFooter =1;
5815 							m_currentRTFState.m_destinationState = RTFStateStore::rdsSkip;
5816 							return true;
5817 						}
5818 						// TODO fix this as it appears to be a real hack. We shouldn't have access to
5819 						// this from importers.
5820 						FV_View * pView = static_cast<FV_View*>(pFrame->getCurrentView());
5821 						if(pView == NULL)
5822 						{
5823 							m_iIsInHeaderFooter =1;
5824 							m_currentRTFState.m_destinationState = RTFStateStore::rdsSkip;
5825 							return true;
5826 						}
5827 						if(pView->isInEndnote() || pView->isInFootnote())
5828 						{
5829 							m_iIsInHeaderFooter =1;
5830 							m_currentRTFState.m_destinationState = RTFStateStore::rdsSkip;
5831 							return true;
5832 						}
5833 						if(pView->isHdrFtrEdit() && (pView->isInTable() || m_pasteTableStack.getDepth() == 2) )
5834 						{
5835 //
5836 // No nested Tables in header/footer
5837 //
5838 							m_iIsInHeaderFooter =1;
5839 							m_currentRTFState.m_destinationState = RTFStateStore::rdsSkip;
5840 							return true;
5841 						}
5842 
5843 						m_iIsInHeaderFooter = 2;
5844 					}
5845 					return HandleAbiTable();
5846 					break;
5847 				case RTF_KW_abiendtable:
5848 					if(!bUseInsertNotAppend())
5849 					{
5850 						UT_DEBUGMSG (("ignoring abiendtable on file import \n"));
5851 						m_currentRTFState.m_destinationState = RTFStateStore::rdsSkip;
5852 						return true;
5853 					}
5854 					if(m_iIsInHeaderFooter == 1)
5855 					{
5856 						m_currentRTFState.m_destinationState = RTFStateStore::rdsSkip;
5857 						return true;
5858 					}
5859 					return HandleAbiEndTable();
5860 					break;
5861 				case RTF_KW_abiendcell:
5862 					if(!bUseInsertNotAppend())
5863 					{
5864 						UT_DEBUGMSG (("ignoring abiendcell on file import \n"));
5865 						m_currentRTFState.m_destinationState = RTFStateStore::rdsSkip;
5866 						return true;
5867 					}
5868 					if(m_iIsInHeaderFooter == 1)
5869 					{
5870 						m_currentRTFState.m_destinationState = RTFStateStore::rdsSkip;
5871 						return true;
5872 					}
5873 					return HandleAbiEndCell();
5874 					break;
5875 				case RTF_KW_abimathml:
5876 					return HandleAbiMathml();
5877 					break;
5878 				case RTF_KW_abimathmldata:
5879 					return CreateDataItemfromStream();
5880 					break;
5881 				case RTF_KW_abilatexdata:
5882 					return CreateDataItemfromStream();
5883 					break;
5884 				case RTF_KW_abiembed:
5885 					return HandleAbiEmbed();
5886 					break;
5887 				case RTF_KW_abiembeddata:
5888 					return CreateDataItemfromStream();
5889 					break;
5890 				case RTF_KW_shppict:
5891 					UT_DEBUGMSG (("handling shppict\n"));
5892 					HandleShapePict();
5893 					return true;
5894 					break;
5895 				case RTF_KW_shpinst:
5896 					UT_DEBUGMSG(("Doing shpinst \n"));
5897 					SkipCurrentGroup();
5898 					/*
5899 					m_iStackDepthAtFrame = m_stateStack.getDepth();
5900 					m_bFrameOpen = true;
5901 					*/
5902 					return true;
5903 					break;
5904 				case RTF_KW_nesttableprops:
5905 					UT_DEBUGMSG(("SEVIOR: Doing nestableprops opentable \n"));
5906 					m_bNestTableProps = true;
5907 					// OpenTable();
5908 					return true;
5909 					break;
5910 				case RTF_KW_bkmkstart:
5911 					return HandleBookmark (RBT_START);
5912 					break;
5913 				case RTF_KW_bkmkend:
5914 					return HandleBookmark (RBT_END);
5915 				case RTF_KW_rdfanchorstart:
5916 					return HandleRDFAnchor (RBT_START);
5917 					break;
5918 				case RTF_KW_rdfanchorend:
5919 					return HandleRDFAnchor (RBT_END);
5920 				case RTF_KW_deltamoveid:
5921 					return HandleDeltaMoveID();
5922 				case RTF_KW_cs:
5923 					UT_DEBUGMSG(("Found cs in readword stream just ignore \n"));
5924 					return true;
5925 					break;
5926 #if 1
5927 //
5928 // Fixme I need to be able to handle footnotes inside tables in RTF
5929 //
5930 				case RTF_KW_footnote:
5931 					if(bUseInsertNotAppend())
5932 					{
5933 						XAP_Frame * pFrame = XAP_App::getApp()->getLastFocussedFrame();
5934 						if(pFrame == NULL)
5935 						{
5936 							m_currentRTFState.m_destinationState = RTFStateStore::rdsSkip;
5937 							return true;
5938 						}
5939 						FV_View * pView = static_cast<FV_View*>(pFrame->getCurrentView());
5940 						if(pView == NULL)
5941 						{
5942 							m_currentRTFState.m_destinationState = RTFStateStore::rdsSkip;
5943 							return true;
5944 						}
5945 						if(pView->isHdrFtrEdit())
5946 						{
5947 							m_currentRTFState.m_destinationState = RTFStateStore::rdsSkip;
5948 							return true;
5949 						}
5950 						if(pView->isInFootnote(m_dposPaste) || pView->isInEndnote(m_dposPaste) )
5951 						{
5952 							m_currentRTFState.m_destinationState = RTFStateStore::rdsSkip;
5953 							return true;
5954 						}
5955 					}
5956 					//HandleFootnote();
5957 
5958 					m_bFootnotePending = true;
5959 					return true;
5960 					break;
5961 #endif
5962 //
5963 // Decode our own field extensions
5964 //
5965 				case RTF_KW_abifieldD:
5966 				{
5967 					char * pszField = strstr(reinterpret_cast<char *>(keyword_star),"D");
5968 					pszField++;
5969 					char * pszAbiField = g_strdup(pszField);
5970 					char * pszD = strstr(pszAbiField,"D");
5971 					if(pszD)
5972 					{
5973 						*pszD = '_';
5974 						UT_DEBUGMSG(("Appending Abi field %s \n",pszAbiField));
5975 						return _appendField(pszAbiField);
5976 					}
5977 					FREEP(pszAbiField);
5978 					break;
5979 				}
5980 				case RTF_KW_hlinkbase:
5981 				{
5982 					m_hyperlinkBase.clear();
5983 					unsigned char ch = 0;
5984 
5985 					if(!ReadCharFromFile(&ch))
5986 						return false;
5987 
5988 					while (ch != '}')
5989 					{
5990 						m_hyperlinkBase += ch;
5991 						if(!ReadCharFromFile(&ch))
5992 							return false;
5993 					}
5994 
5995 					PopRTFState();
5996 					return true;
5997 				}
5998 				case RTF_KW_revtbl:
5999 					return ReadRevisionTable();
6000 
6001 				case RTF_KW_atnid:
6002 				{
6003 					if(NULL == m_pAnnotation)
6004 					{
6005 						StartAnnotation();
6006 						UT_DEBUGMSG(("found atnid without annotation\n"));
6007 					}
6008 					UT_UTF8String sContent;
6009 					ReadContentFromFile(sContent);
6010 					UT_DEBUGMSG(("atnid content %s \n", sContent.utf8_str()));
6011 					m_pAnnotation->m_sAuthorId = sContent;
6012 					return true;
6013 				}
6014 				case RTF_KW_rdf:
6015 					return ReadRDFTriples();
6016 
6017 				case RTF_KW_atnauthor:
6018 				{
6019 					//
6020 					// Annotation Author
6021 					UT_DEBUGMSG(("Handling atnauthor keyword \n"));
6022 					if(NULL == m_pAnnotation)
6023 					{
6024 						StartAnnotation();
6025 						UT_DEBUGMSG(("found atnauthor without annotation\n"));
6026 					}
6027 					UT_UTF8String sContent;
6028 					ReadContentFromFile(sContent);
6029 					UT_DEBUGMSG(("atnauthor content %s \n", sContent.utf8_str()));
6030 					m_pAnnotation->m_sAuthor = sContent;
6031 					return true;
6032 				}
6033 				case RTF_KW_atrfend:
6034 					//return EndAnnotation();
6035 					return true;
6036 				case RTF_KW_atndate:
6037 				{
6038 					//
6039 					// date of the annotation
6040 					UT_DEBUGMSG(("Found annotation date %p \n",m_pAnnotation));
6041 					if(NULL == m_pAnnotation)
6042 					{
6043 						UT_DEBUGMSG(("found atndate without annotation"));
6044 						return true;
6045 					}
6046 					UT_UTF8String sContent;
6047 					ReadContentFromFile(sContent);
6048 					UT_DEBUGMSG(("annotation date is %s \n",sContent.utf8_str()));
6049 					m_pAnnotation->m_sDate = sContent;
6050 					return true;
6051 				}
6052 				case RTF_KW_annotation:
6053 				{
6054 					//
6055 					// Annotation content
6056 					UT_DEBUGMSG(("Found annotation content m_pAnnotation %p \n",m_pAnnotation));
6057 					if(m_pAnnotation == NULL)
6058 					{
6059 						UT_DEBUGMSG(("found annotation without annotation"));
6060 						return true;
6061 					}
6062 					//					if(m_pAnnotation->m_iAnnNumber != parameter_star)
6063 					//	{
6064 					//	UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
6065 					//	return false;
6066 					//	}
6067 					m_pAnnotation->m_iRTFLevel = m_stateStack.getDepth();
6068 					xxx_UT_DEBUGMSG(("Found annotation content depth %d \n",m_pAnnotation->m_iRTFLevel));
6069 					return true;
6070 				}
6071 				case RTF_KW_atnref:
6072 				{
6073 					//
6074 					// Annotation reference number
6075 					UT_DEBUGMSG(("Write code to handle atnref \n"));
6076 					xxx_UT_DEBUGMSG(("RTF Level inside atnref %d \n",m_stateStack.getDepth()));
6077 					return true;
6078 				}
6079 				break;
6080 				case RTF_KW_atrfstart:
6081 				{
6082 					//StartAnnotation();
6083 					return true;
6084 				}
6085 				default:
6086 
6087 					UT_DEBUGMSG (("RTF: default case star keyword %s not handled\n", keyword_star));
6088 					break;
6089 				}
6090 			}
6091 		}
6092 		UT_DEBUGMSG (("RTF: star keyword %s not handled\n", keyword_star));
6093 	}
6094 
6095 	// Ignore all other \* tags
6096 	// TODO different destination (all unhandled at the moment, so enter skip mode)
6097 	//m_currentRTFState.m_destinationState = RTFStateStore::rdsSkip; was this
6098 	SkipCurrentGroup();
6099 	return true;
6100 }
6101 
StartAnnotation()6102 void IE_Imp_RTF::StartAnnotation()
6103 {
6104 	//
6105 	// Start of Annotated region
6106 	if(m_pAnnotation == NULL)
6107 		m_pAnnotation = new ABI_RTF_Annotation();
6108 	UT_DEBUGMSG(("created m_pAnnotation %p \n",m_pAnnotation));
6109 	m_pAnnotation->m_iAnnNumber = ABI_RTF_Annotation::newNumber();
6110 	std::string sAnnNum;
6111 	sAnnNum = UT_std_string_sprintf("%d",m_pAnnotation->m_iAnnNumber);
6112 	const gchar * attr[3] = {PT_ANNOTATION_NUMBER,NULL,NULL};
6113 	attr[1] = sAnnNum.c_str();
6114 	UT_DEBUGMSG(("Handling atrfstart number %d \n",m_pAnnotation->m_iAnnNumber));
6115 	if(!bUseInsertNotAppend())
6116 	{
6117 		FlushStoredChars();
6118 		getDoc()->appendObject(PTO_Annotation, attr);
6119 		//
6120 		// Remember the annotation field frag. We'll insert
6121 		// the annotation content after this
6122 		//
6123 		m_pAnnotation->m_pInsertFrag = getDoc()->getLastFrag();
6124 	}
6125 	else
6126 	{
6127 		m_pAnnotation->m_Annpos = m_dposPaste;
6128 
6129 	}
6130 }
6131 
6132 
EndAnnotation()6133 void IE_Imp_RTF::EndAnnotation()
6134 {
6135 	//
6136 	// End of Annotated region
6137 	UT_DEBUGMSG(("found annotation end \n"));
6138 	if(NULL == m_pAnnotation)
6139 	{
6140 		UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
6141 		return;
6142 	}
6143 	//if(m_pAnnotation->m_iAnnNumber != number)
6144 	//{
6145 	//	UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
6146 	//	return false;
6147 	//}
6148 	std::string sAnnNum;
6149 	sAnnNum = UT_std_string_sprintf("%d",m_pAnnotation->m_iAnnNumber);
6150 	const gchar * attr[3] = {PT_ANNOTATION_NUMBER,NULL,NULL};
6151 	attr[1] = sAnnNum.c_str();
6152 	UT_DEBUGMSG(("found annotation end id %d  \n",m_pAnnotation->m_iAnnNumber));
6153 
6154 	if(!bUseInsertNotAppend())
6155 	{
6156 		FlushStoredChars();
6157 		getDoc()->appendObject(PTO_Annotation, NULL);
6158 	}
6159 	else
6160 	{
6161 		UT_DEBUGMSG(("Pasting EndAnnotation at %d  \n",m_dposPaste));
6162 		bool bRet = getDoc()->insertObject(m_dposPaste, PTO_Annotation, NULL,NULL);
6163 
6164 		if(bRet)
6165 		{
6166 			UT_DEBUGMSG(("Pasting End Annotation at %d saved pos %d \n",m_dposPaste,m_posSavedDocPosition));
6167 			if(m_posSavedDocPosition >m_dposPaste )
6168 				m_posSavedDocPosition++;
6169 			m_dposPaste++;
6170 			UT_DEBUGMSG(("Pasting Begin Annotation at %d dposPaste %d saved pos %d \n",m_pAnnotation->m_Annpos,m_dposPaste,m_posSavedDocPosition));
6171 
6172 			bRet = getDoc()->insertObject(m_pAnnotation->m_Annpos, PTO_Annotation, attr, NULL);
6173 			if(m_posSavedDocPosition >m_dposPaste )
6174 				m_posSavedDocPosition++;
6175 			m_dposPaste++;
6176 		}
6177 
6178 	}
6179 }
6180 
_formRevisionAttr(std::string & attr,const std::string & props,const std::string & styleName)6181 void IE_Imp_RTF::_formRevisionAttr(std::string & attr, const std::string & props, const std::string & styleName)
6182 {
6183 	attr.clear();
6184 
6185 	if(m_currentRTFState.m_charProps.m_eRevision == PP_REVISION_NONE)
6186 	{
6187 		return;
6188 	}
6189 
6190 
6191 	switch(m_currentRTFState.m_charProps.m_eRevision)
6192 	{
6193 		case PP_REVISION_DELETION:
6194 			attr += '-';
6195 			break;
6196 		case PP_REVISION_FMT_CHANGE:
6197 			attr += '!';
6198 			break;
6199 
6200 		case PP_REVISION_ADDITION:
6201 		case PP_REVISION_ADDITION_AND_FMT:
6202 		default:
6203 			; // nothing
6204 	}
6205 
6206 	attr += UT_std_string_sprintf("%d", m_currentRTFState.m_charProps.m_iCurrentRevisionId);
6207 
6208 
6209 	if(m_currentRTFState.m_charProps.m_eRevision == PP_REVISION_DELETION)
6210 	{
6211 		// ignore props
6212 		return;
6213 	}
6214 
6215 	attr += '{';
6216 	attr += props;
6217 	attr += '}';
6218 	if(!styleName.empty())
6219 	{
6220 		attr += '{';
6221 		attr += PT_STYLE_ATTRIBUTE_NAME;
6222 		attr += ';';
6223 		attr += styleName;
6224 		attr += '}';
6225 	}
6226 }
6227 
6228 
6229 
buildCharacterProps(std::string & propBuffer)6230 bool IE_Imp_RTF::buildCharacterProps(std::string & propBuffer)
6231 {
6232 	std::string tempBuffer;
6233 	// bold
6234 	propBuffer += "font-weight:";
6235 	propBuffer += m_currentRTFState.m_charProps.m_bold ? "bold" : "normal";
6236 
6237 	// italic
6238 	propBuffer += "; font-style:";
6239 	propBuffer += m_currentRTFState.m_charProps.m_italic ? "italic" : "normal";
6240 
6241 	// hidden
6242 	if(m_currentRTFState.m_charProps.m_Hidden)
6243 	{
6244 		propBuffer += "; display:none";
6245 	}
6246 
6247 	// underline & overline & strike-out
6248 	propBuffer += "; text-decoration:";
6249 	static std::string decors;
6250 	decors.clear();
6251 	if (m_currentRTFState.m_charProps.m_underline)
6252 	{
6253 		decors += "underline ";
6254 	}
6255 	if (m_currentRTFState.m_charProps.m_strikeout)
6256 	{
6257 		decors += "line-through ";
6258 	}
6259 	if(m_currentRTFState.m_charProps.m_overline)
6260 	{
6261 		decors += "overline ";
6262 	}
6263 	if(m_currentRTFState.m_charProps.m_topline)
6264 	{
6265 		decors += "topline ";
6266 	}
6267 	if(m_currentRTFState.m_charProps.m_botline)
6268 	{
6269 		decors += "bottomline";
6270 	}
6271 	if(!m_currentRTFState.m_charProps.m_underline  &&
6272 	   !m_currentRTFState.m_charProps.m_strikeout &&
6273 	   !m_currentRTFState.m_charProps.m_overline &&
6274 	   !m_currentRTFState.m_charProps.m_topline &&
6275 	   !m_currentRTFState.m_charProps.m_botline)
6276 	{
6277 		decors = "none";
6278 	}
6279 	propBuffer += decors.c_str();
6280 
6281 	//superscript and subscript
6282 	propBuffer += "; text-position:";
6283 	if (m_currentRTFState.m_charProps.m_superscript)
6284 	{
6285 		if (m_currentRTFState.m_charProps.m_superscript != 0.0)
6286 		{
6287 			UT_DEBUGMSG (("RTF: TODO: Handle text position in pt.\n"));
6288 		}
6289 		propBuffer += "superscript";
6290 	}
6291 	else if (m_currentRTFState.m_charProps.m_subscript)
6292 	{
6293 		if (m_currentRTFState.m_charProps.m_subscript != 0.0)
6294 		{
6295 			UT_DEBUGMSG (("RTF: TODO: Handle text position in pt.\n"));
6296 		}
6297 		propBuffer += "subscript";
6298 	}
6299 	else
6300 	{
6301 		propBuffer += "normal";
6302 	}
6303 	// font size
6304 	// If Font is too big inside a table can trigger an infinite too during layout
6305 	//
6306 	//	UT_ASSERT(m_currentRTFState.m_charProps.m_fontSize < 120);
6307 	propBuffer += UT_std_string_sprintf("; font-size:%spt", std_size_string(static_cast<float>(m_currentRTFState.m_charProps.m_fontSize)));
6308 	// typeface
6309 	RTFFontTableItem* pFont = GetNthTableFont(m_currentRTFState.m_charProps.m_fontNumber);
6310 	if (pFont != NULL)
6311 	{
6312 		propBuffer += "; font-family:";
6313 
6314 		// see bug 2633 - we get a font entry like this (unika.rtf):
6315 		// {\f83\fnil\fcharset0\fprq0{\*\panose 00000000000000000000} ;}
6316 		// note the empty slot after the panose entry
6317 		// later it gets referenced: {\b\f83\fs24\cf1\cgrid0 Malte Cornils
6318 		// this turns those into "Times New Roman" for now, as a hack to keep from crashing
6319 		if ( pFont->m_pFontName != NULL )
6320 			propBuffer += pFont->m_pFontName;
6321 		else
6322 			propBuffer += "Times New Roman";
6323 	}
6324 	if (m_currentRTFState.m_charProps.m_hasColour)
6325 	{
6326 		// colour, only if one has been set. See bug 1324
6327 		UT_uint32 colour = GetNthTableColour(m_currentRTFState.m_charProps.m_colourNumber);
6328 		propBuffer += UT_std_string_sprintf("; color:%06x", colour);
6329 	}
6330 
6331 	if (m_currentRTFState.m_charProps.m_hasBgColour)
6332 	{
6333 		// colour, only if one has been set. See bug 1324
6334 		UT_sint32 bgColour = GetNthTableBgColour(m_currentRTFState.m_charProps.m_bgcolourNumber);
6335 
6336 		if (bgColour != -1) // invalid and should be white
6337 		{
6338 			propBuffer += UT_std_string_sprintf("; bgcolor:%06x", bgColour);
6339 		}
6340 	}
6341 
6342 	if(m_currentRTFState.m_charProps.m_listTag != 0)
6343 	{
6344 // List Tag to hang lists off
6345 		propBuffer += UT_std_string_sprintf("; list-tag:%d",m_currentRTFState.m_charProps.m_listTag);
6346 	}
6347 
6348 	if(m_currentRTFState.m_charProps.m_szLang != 0)
6349 	{
6350 		propBuffer += "; lang:";
6351 		propBuffer += m_currentRTFState.m_charProps.m_szLang;
6352 	}
6353 
6354 	if(m_currentRTFState.m_charProps.m_dirOverride == UT_BIDI_LTR)
6355 	{
6356 		propBuffer += ";dir-override:ltr";
6357 	}
6358 	else if(m_currentRTFState.m_charProps.m_dirOverride == UT_BIDI_RTL)
6359 	{
6360 		propBuffer += ";dir-override:rtl";
6361 	}
6362 
6363 	return true;
6364 }
6365 
6366 
6367 /*!
6368  * Returns true if we're pasting text rather than parsing a file
6369  */
bUseInsertNotAppend(void)6370 bool IE_Imp_RTF::bUseInsertNotAppend(void)
6371 {
6372 	return ((m_pImportFile == NULL) && !m_parsingHdrFtr );
6373 }
6374 
6375 // in non-bidi doc we just append the current format and text; in bidi
6376 // documents we crawl over the text looking for neutral characters;
6377 // when we find one, we see if the implied override is identical to
6378 // directional properties on either side of the character: if yes, we
6379 // leave the character as it is; if not we issued the override. This
6380 // saves us inserting overrides on most space characters in the document
_appendSpan()6381 bool IE_Imp_RTF::_appendSpan()
6382 {
6383 	const gchar* pProps = "props";
6384 	const gchar* pRevs  = "revision";
6385 	const gchar* pStyle = PT_STYLE_ATTRIBUTE_NAME;
6386 
6387 	const gchar* propsArray[5] = {NULL, NULL, NULL, NULL, NULL};
6388 
6389 	std::string prop_basic;
6390 	std::string revision;
6391 	buildCharacterProps(prop_basic);
6392 
6393 	std::string prop_ltr;
6394 	std::string prop_rtl;
6395 
6396 	UT_uint32 iPropOffset = 0;
6397 
6398 	bool bRevisedABI = (m_currentRTFState.m_revAttr.size() != 0);
6399 	bool bRevisedRTF = !bRevisedABI && (m_currentRTFState.m_charProps.m_eRevision != PP_REVISION_NONE);
6400 
6401 	propsArray[0] = bRevisedABI || bRevisedRTF ? pRevs : pProps;
6402 	propsArray[1] = prop_basic.c_str();
6403 
6404 	if(m_currentRTFState.m_charProps.m_styleNumber >= 0
6405 	   && static_cast<UT_uint32>(m_currentRTFState.m_charProps.m_styleNumber) < m_styleTable.size())
6406 	{
6407 		propsArray[2] = pStyle;
6408 		propsArray[3] = m_styleTable[m_currentRTFState.m_charProps.m_styleNumber].c_str();
6409 	}
6410 
6411 	if(bRevisedRTF)
6412 	{
6413 		_formRevisionAttr(revision, prop_basic, propsArray[3]);
6414 
6415 		// the style attribute is inside the revision, clear it out of the props array
6416 		propsArray[1] = revision.c_str();
6417 		propsArray[2] = NULL;
6418 		propsArray[3] = NULL;
6419 
6420 		iPropOffset = 2;
6421 	}
6422 	else if(bRevisedABI)
6423 	{
6424 		propsArray[1] = m_currentRTFState.m_revAttr.utf8_str();
6425 		propsArray[2] = NULL;
6426 		propsArray[3] = NULL;
6427 
6428 		iPropOffset = 2;
6429 	}
6430 	else
6431 	{
6432 		prop_ltr = prop_basic;
6433 		prop_rtl = prop_basic;
6434 
6435 		prop_ltr += ';';
6436 		prop_rtl += ';';
6437 	}
6438 
6439 	prop_ltr += "dir-override:ltr";
6440 	prop_rtl += "dir-override:rtl";
6441 
6442 
6443 	UT_UCS4Char * p;
6444 	UT_uint32 iLen = m_gbBlock.getLength();
6445 
6446 	if(m_bBidiMode)
6447 	{
6448 		UT_BidiCharType cType;
6449 		UT_uint32 iLast = 0;
6450 		UT_UCS4Char c = *(reinterpret_cast<UT_UCS4Char*>(m_gbBlock.getPointer(0)));
6451 
6452 		cType = UT_bidiGetCharType(c);
6453 
6454 		for(UT_uint32 i = 0; i < iLen; i++)
6455 		{
6456 			if(i < iLen - 1 )
6457 			{
6458 				c = *(reinterpret_cast<UT_UCS4Char*>(m_gbBlock.getPointer(i+1)));
6459 				m_iBidiNextType = UT_bidiGetCharType(c);
6460 			}
6461 			else
6462 			{
6463 				m_iBidiNextType = UT_BIDI_UNSET;
6464 			}
6465 
6466 
6467 			if(UT_BIDI_IS_NEUTRAL(cType))
6468 			{
6469 				if(m_currentRTFState.m_charProps.m_dir == UT_BIDI_LTR
6470 				   && m_iAutoBidiOverride != UT_BIDI_LTR
6471 				   && (m_iBidiLastType != UT_BIDI_LTR || m_iBidiNextType != UT_BIDI_LTR))
6472 				{
6473 					if(i - iLast > 0)
6474 					{
6475 						p = reinterpret_cast<UT_UCS4Char*>(m_gbBlock.getPointer(iLast));
6476 						if(m_pDelayedFrag)
6477 						{
6478 							    if(!getDoc()->insertFmtMarkBeforeFrag(m_pDelayedFrag,propsArray))
6479 									return false;
6480 								UT_DEBUGMSG(("Appending span before %p \n",m_pDelayedFrag));
6481 								if(!getDoc()->insertSpanBeforeFrag(m_pDelayedFrag,p, i- iLast))
6482 									return false;
6483 						}
6484 						else
6485 						{
6486 							if(!getDoc()->appendFmt(propsArray))
6487 								return false;
6488 
6489 							if(!getDoc()->appendSpan(p, i - iLast))
6490 								return false;
6491 						}
6492 					}
6493 					m_iAutoBidiOverride = UT_BIDI_LTR;
6494 					propsArray[iPropOffset] = pProps;
6495 					propsArray[iPropOffset + 1] = prop_ltr.c_str();
6496 					iLast = i;
6497 				}
6498 				else if(m_currentRTFState.m_charProps.m_dir == UT_BIDI_RTL
6499 						&& m_iAutoBidiOverride != UT_BIDI_RTL
6500 						&& (m_iBidiLastType != UT_BIDI_RTL || m_iBidiNextType != UT_BIDI_RTL))
6501 				{
6502 					if(i - iLast > 0)
6503 					{
6504 						p = reinterpret_cast<UT_UCS4Char*>(m_gbBlock.getPointer(iLast));
6505 						if(m_pDelayedFrag)
6506 						{
6507 							    if(!getDoc()->insertFmtMarkBeforeFrag(m_pDelayedFrag,propsArray))
6508 									return false;
6509 								if(!getDoc()->insertSpanBeforeFrag(m_pDelayedFrag,p,i - iLast))
6510 									return false;
6511 						}
6512 						else
6513 						{
6514 								if(!getDoc()->appendFmt(propsArray))
6515 									return false;
6516 
6517 								if(!getDoc()->appendSpan(p, i - iLast))
6518 									return false;
6519 						}
6520 					}
6521 					m_iAutoBidiOverride = UT_BIDI_RTL;
6522 					propsArray[iPropOffset] = pProps;
6523 					propsArray[iPropOffset + 1] = prop_rtl.c_str();
6524 					iLast = i;
6525 				}
6526 			}
6527 			else
6528 			{
6529 				// strong character; if we previously issued an override,
6530 				// we need to cancel it
6531 				if(m_iAutoBidiOverride != static_cast<UT_uint32>(UT_BIDI_UNSET))
6532 				{
6533 					if(i - iLast > 0)
6534 					{
6535 						p = reinterpret_cast<UT_UCS4Char*>(m_gbBlock.getPointer(iLast));
6536 						if(m_pDelayedFrag)
6537 						{
6538 							    if(!getDoc()->insertFmtMarkBeforeFrag(m_pDelayedFrag,propsArray))
6539 									return false;
6540 								if(!getDoc()->insertSpanBeforeFrag(m_pDelayedFrag,p,i - iLast))
6541 									return false;
6542 						}
6543 						else
6544 						{
6545 							    if(!getDoc()->appendFmt(propsArray))
6546 									return false;
6547 
6548 								if(!getDoc()->appendSpan(p, i - iLast))
6549 									return false;
6550 						}
6551 					}
6552 					m_iAutoBidiOverride = UT_BIDI_UNSET;
6553 
6554 					if(bRevisedABI || bRevisedRTF)
6555 					{
6556 						propsArray[iPropOffset] = NULL;
6557 						propsArray[iPropOffset + 1] = NULL;
6558 					}
6559 					else
6560 					{
6561 						propsArray[1] = prop_basic.c_str();
6562 					}
6563 
6564 					iLast = i;
6565 				}
6566 			}
6567 
6568 			m_iBidiLastType = cType;
6569 			cType = m_iBidiNextType;
6570 		}
6571 
6572 		// insert what is left over
6573 		if(iLen - iLast > 0)
6574 		{
6575 			p = reinterpret_cast<UT_UCS4Char*>(m_gbBlock.getPointer(iLast));
6576 			if(m_pDelayedFrag)
6577 			{
6578 				if(!getDoc()->insertFmtMarkBeforeFrag(m_pDelayedFrag,propsArray))
6579 					return false;
6580 				if(!getDoc()->insertSpanBeforeFrag(m_pDelayedFrag,p,iLen - iLast))
6581 				   return false;
6582 			}
6583 			else
6584 			{
6585 				if(!getDoc()->appendFmt(propsArray))
6586 					return false;
6587 
6588 				if(!getDoc()->appendSpan(p, iLen - iLast))
6589 					return false;
6590 			}
6591 		}
6592 	}
6593 	else
6594 	{
6595 		// not a bidi doc, just do it the simple way
6596 		p = reinterpret_cast<UT_UCS4Char*>(m_gbBlock.getPointer(0));
6597 		if(m_pDelayedFrag)
6598 		{
6599 			if(!getDoc()->insertFmtMarkBeforeFrag(m_pDelayedFrag,propsArray))
6600 				return false;
6601 			if(!getDoc()->insertSpanBeforeFrag(m_pDelayedFrag,p,iLen))
6602 			   return false;
6603 		}
6604 		else
6605 		{
6606 			if(!getDoc()->appendFmt(propsArray))
6607 				return false;
6608 			if(!getDoc()->appendSpan(p, iLen))
6609 				return false;
6610 		}
6611 	}
6612 
6613 	return true;
6614 }
6615 
_insertSpan()6616 bool IE_Imp_RTF::_insertSpan()
6617 {
6618 	const gchar* pProps = "props";
6619 	const gchar* pRevs  = "revision";
6620 	const gchar* pStyle = PT_STYLE_ATTRIBUTE_NAME;
6621 
6622 	const gchar* propsArray[5] = {NULL, NULL, NULL, NULL, NULL};
6623 
6624 	std::string prop_basic;
6625 	std::string revision;
6626 	buildCharacterProps(prop_basic);
6627 
6628 	std::string prop_ltr;
6629 	std::string prop_rtl;
6630 
6631 	UT_uint32 iPropOffset = 0;
6632 
6633 	bool bRevised = m_currentRTFState.m_charProps.m_eRevision != PP_REVISION_NONE;
6634 
6635 	propsArray[0] = bRevised ? pRevs : pProps;
6636 	propsArray[1] = prop_basic.c_str();
6637 
6638 	UT_UCS4Char * p;
6639 	UT_uint32 iLen = m_gbBlock.getLength();
6640 
6641 	if(m_currentRTFState.m_charProps.m_styleNumber >= 0
6642 	   && static_cast<UT_uint32>(m_currentRTFState.m_charProps.m_styleNumber) < m_styleTable.size())
6643 	{
6644 		propsArray[2] = pStyle;
6645 		propsArray[3] = m_styleTable[m_currentRTFState.m_charProps.m_styleNumber].c_str();
6646 	}
6647 
6648 
6649 	if(bRevised)
6650 	{
6651 		_formRevisionAttr(revision, prop_basic, propsArray[3]);
6652 
6653 		// the style attribute is inside the revision, clear it out of the props array
6654 		propsArray[1] = revision.c_str();
6655 		propsArray[2] = NULL;
6656 		propsArray[3] = NULL;
6657 
6658 		iPropOffset = 2;
6659 	}
6660 	else
6661 	{
6662 		prop_ltr = prop_basic;
6663 		prop_rtl = prop_basic;
6664 
6665 		prop_ltr += ';';
6666 		prop_rtl += ';';
6667 	}
6668 
6669 	prop_ltr += "dir-override:ltr";
6670 	prop_rtl += "dir-override:rtl";
6671 
6672 
6673 
6674 	if(m_bBidiMode)
6675 	{
6676 		UT_BidiCharType cType;
6677 		UT_uint32 iLast = 0;
6678 		UT_UCS4Char c = *(reinterpret_cast<UT_UCS4Char*>(m_gbBlock.getPointer(0)));
6679 
6680 		cType = UT_bidiGetCharType(c);
6681 
6682 		for(UT_uint32 i = 0; i < iLen; i++)
6683 		{
6684 			if(i < iLen - 1 )
6685 			{
6686 				c = *(reinterpret_cast<UT_UCS4Char*>(m_gbBlock.getPointer(i+1)));
6687 				m_iBidiNextType = UT_bidiGetCharType(c);
6688 			}
6689 			else
6690 			{
6691 				m_iBidiNextType = UT_BIDI_UNSET;
6692 			}
6693 
6694 
6695 			if(UT_BIDI_IS_NEUTRAL(cType))
6696 			{
6697 				if(m_currentRTFState.m_charProps.m_dir == UT_BIDI_LTR
6698 				   && m_iAutoBidiOverride != UT_BIDI_LTR
6699 				   && (m_iBidiLastType != UT_BIDI_LTR || m_iBidiNextType != UT_BIDI_LTR))
6700 				{
6701 					if(i - iLast > 0)
6702 					{
6703 						p = reinterpret_cast<UT_UCS4Char*>(m_gbBlock.getPointer(iLast));
6704 						if(getDoc()->isFrameAtPos(m_dposPaste-1) || getDoc()->isTableAtPos(m_dposPaste-1) || getDoc()->isCellAtPos(m_dposPaste-1))
6705 						{
6706 							getDoc()->insertStrux(m_dposPaste,PTX_Block);
6707 							m_dposPaste++;
6708 						}
6709 						if(!getDoc()->insertSpan(m_dposPaste, p ,i - iLast))
6710 							return false;
6711 
6712 						if(!getDoc()->changeSpanFmt(PTC_SetFmt, m_dposPaste,m_dposPaste+ i - iLast,
6713 													propsArray,NULL))
6714 							return false;
6715 
6716 						m_dposPaste += i - iLast;
6717 						if(m_posSavedDocPosition > 0)
6718 							m_posSavedDocPosition += i - iLast;
6719 					}
6720 					m_iAutoBidiOverride = UT_BIDI_LTR;
6721 					propsArray[iPropOffset] = pProps;
6722 					propsArray[iPropOffset + 1] = prop_ltr.c_str();
6723 					iLast = i;
6724 				}
6725 				else if(m_currentRTFState.m_charProps.m_dir == UT_BIDI_RTL
6726 						&& m_iAutoBidiOverride != UT_BIDI_RTL
6727 						&& (m_iBidiLastType != UT_BIDI_RTL || m_iBidiNextType != UT_BIDI_RTL))
6728 				{
6729 					if(i - iLast > 0)
6730 					{
6731 						p = reinterpret_cast<UT_UCS4Char*>(m_gbBlock.getPointer(iLast));
6732 						if(!getDoc()->insertSpan(m_dposPaste, p ,i - iLast))
6733 							return false;
6734 
6735 						if(!getDoc()->changeSpanFmt(PTC_SetFmt, m_dposPaste,m_dposPaste+ i - iLast,
6736 													propsArray,NULL))
6737 							return false;
6738 						m_dposPaste += i - iLast;
6739 						if(m_posSavedDocPosition > 0)
6740 							m_posSavedDocPosition  += i - iLast;
6741 					}
6742 					m_iAutoBidiOverride = UT_BIDI_RTL;
6743 					propsArray[iPropOffset] = pProps;
6744 					propsArray[iPropOffset + 1] = prop_rtl.c_str();
6745 					iLast = i;
6746 				}
6747 			}
6748 			else
6749 			{
6750 				// strong character; if we previously issued an override,
6751 				// we need to cancel it
6752 				if(m_iAutoBidiOverride != static_cast<UT_uint32>(UT_BIDI_UNSET))
6753 				{
6754 					if(i - iLast > 0)
6755 					{
6756 						p = reinterpret_cast<UT_UCS4Char*>(m_gbBlock.getPointer(iLast));
6757 						if(!getDoc()->insertSpan(m_dposPaste, p ,i - iLast))
6758 							return false;
6759 
6760 						if(!getDoc()->changeSpanFmt(PTC_SetFmt, m_dposPaste, m_dposPaste + i - iLast,
6761 													propsArray,NULL))
6762 							return false;
6763 
6764 						m_dposPaste += i - iLast;
6765 						if(m_posSavedDocPosition > 0)
6766 							m_posSavedDocPosition  += i - iLast;
6767 					}
6768 					m_iAutoBidiOverride = UT_BIDI_UNSET;
6769 					if(bRevised)
6770 					{
6771 						propsArray[iPropOffset] = NULL;
6772 						propsArray[iPropOffset + 1] = NULL;
6773 					}
6774 					else
6775 					{
6776 						propsArray[1] = prop_basic.c_str();
6777 					}
6778 
6779 					iLast = i;
6780 				}
6781 			}
6782 
6783 			m_iBidiLastType = cType;
6784 			cType = m_iBidiNextType;
6785 		}
6786 
6787 		// insert what is left over
6788 		if(iLen - iLast > 0)
6789 		{
6790 			p = reinterpret_cast<UT_UCS4Char*>(m_gbBlock.getPointer(iLast));
6791 			if(!getDoc()->insertSpan(m_dposPaste, p ,iLen - iLast))
6792 				return false;
6793 
6794 			if(!getDoc()->changeSpanFmt(PTC_SetFmt, m_dposPaste, m_dposPaste + iLen - iLast,
6795 										propsArray,NULL))
6796 				return false;
6797 
6798 			m_dposPaste += iLen - iLast;
6799 			if(m_posSavedDocPosition > 0)
6800 				m_posSavedDocPosition  += iLen - iLast;
6801 		}
6802 	}
6803 	else
6804 	{
6805 		// not a bidi doc, just do it the simple way
6806 		p = reinterpret_cast<UT_UCS4Char*>(m_gbBlock.getPointer(0));
6807 		if(getDoc()->isFrameAtPos(m_dposPaste-1) || getDoc()->isTableAtPos(m_dposPaste-1) || getDoc()->isCellAtPos(m_dposPaste-1))
6808 		{
6809 			getDoc()->insertStrux(m_dposPaste,PTX_Block);
6810 			m_dposPaste++;
6811 			if(m_posSavedDocPosition > 0)
6812 				m_posSavedDocPosition++;
6813 		}
6814 		if(!getDoc()->insertSpan(m_dposPaste, p ,iLen))
6815 			return false;
6816 
6817 		if(!getDoc()->changeSpanFmt(PTC_SetFmt, m_dposPaste, m_dposPaste + iLen,
6818 									propsArray,NULL))
6819 			return false;
6820 
6821 		m_dposPaste += iLen;
6822 		if(m_posSavedDocPosition > 0)
6823 			m_posSavedDocPosition  += iLen;
6824 	}
6825 
6826 	return true;
6827 }
6828 
ApplyCharacterAttributes()6829 bool IE_Imp_RTF::ApplyCharacterAttributes()
6830 {
6831 	bool ok = false;
6832 	if(isBlockNeededForPasteTable())
6833 	{
6834 		ApplyParagraphAttributes();
6835 	}
6836 	if(m_gbBlock.getLength() > 0)
6837 	{
6838 		if (!bUseInsertNotAppend())	// if we are reading from a file or parsing headers and footers
6839 		{
6840 			ok = _appendSpan();
6841 		}
6842 		else								// else we are pasting from a buffer
6843 		{
6844 			if( m_currentRTFState.m_paraProps.m_isList && (m_dposPaste == m_dOrigPos))
6845 			{
6846 				ApplyParagraphAttributes(true);
6847 			}
6848 			ok = _insertSpan();
6849 		}
6850 		m_gbBlock.truncate(0);
6851 		m_bContentFlushed = true;
6852 		return ok;
6853 	}
6854 	else
6855 	{
6856 		const gchar* pProps = "props";
6857 		const gchar* pStyle = PT_STYLE_ATTRIBUTE_NAME;
6858 		std::string propBuffer;
6859 		buildCharacterProps(propBuffer);
6860 
6861 		const gchar* propsArray[7];
6862 		propsArray[0] = pProps;
6863 		propsArray[1] = propBuffer.c_str();
6864 		propsArray[2] = NULL;
6865 		propsArray[3] = NULL;
6866 		propsArray[4] = NULL;
6867 		propsArray[5] = NULL;
6868 		propsArray[6] = NULL;
6869 		UT_uint32 iPos = 2;
6870 
6871 		if(m_currentRTFState.m_charProps.m_styleNumber >= 0
6872 		   && static_cast<UT_uint32>(m_currentRTFState.m_charProps.m_styleNumber) < m_styleTable.size())
6873 		{
6874 			propsArray[iPos++] = pStyle;
6875 			propsArray[iPos++] = m_styleTable[m_currentRTFState.m_charProps.m_styleNumber].c_str();
6876 		}
6877 
6878 		if(m_currentRTFState.m_revAttr.size())
6879 		{
6880 			propsArray[iPos++] = "revision";
6881 			propsArray[iPos++] = m_currentRTFState.m_revAttr.utf8_str();
6882 		}
6883 
6884 		if (!bUseInsertNotAppend())	// if we are reading from a file or parsing headers and footers
6885 		{
6886 			if(m_pDelayedFrag)
6887 			{
6888 				if(!getDoc()->insertFmtMarkBeforeFrag(m_pDelayedFrag,propsArray))
6889 					ok = getDoc()->insertFmtMarkBeforeFrag(m_pDelayedFrag,propsArray);
6890 				ok = ok && getDoc()->insertFmtMarkBeforeFrag(m_pDelayedFrag);
6891 			}
6892 			else
6893 			{
6894 				if(!getDoc()->appendFmt(propsArray))
6895 					ok = getDoc()->appendFmt(propsArray);
6896 				ok = ok && getDoc()->appendFmtMark();
6897 			}
6898 		}
6899 		else								// else we are pasting from a buffer
6900 		{
6901 			ok = getDoc()->changeSpanFmt(PTC_SetFmt,
6902 												m_dposPaste,m_dposPaste,
6903 												propsArray,NULL);
6904 		}
6905 		return ok;
6906 	}
6907 }
6908 
6909 
ResetCharacterAttributes()6910 bool IE_Imp_RTF::ResetCharacterAttributes()
6911 {
6912 //	bool ok = FlushStoredChars();
6913 	bool ok = true;
6914 	m_currentRTFState.m_charProps = RTFProps_CharProps();
6915 
6916 	return ok;
6917 }
6918 
6919 /*!
6920  *    OK if we are pasting into the text we have to decide if the list we paste
6921  *    should be a new list or an old list. The user might want to swap paragraphs
6922  *    in a list for example.
6923 
6924  *    Use the following algorithim to decide. If the docpos of the paste is
6925  *    within a list of the same ID as our list or if the docpos is immediately
6926  *    before or after a list of the same ID reuse the ID. Otherwise change it.
6927 */
mapID(UT_uint32 id)6928 UT_uint32 IE_Imp_RTF::mapID(UT_uint32 id)
6929 {
6930 	UT_uint32 mappedID = id;
6931 	if(id == 0)
6932 	{
6933 		UT_ASSERT_NOT_REACHED();
6934 		return id;
6935 	}
6936 	if (!bUseInsertNotAppend())  // if we are reading a file - dont remap the ID
6937 	{
6938 	        return id;
6939 	}
6940 //
6941 // Handle case of no id in any lists. If this is the case no need to remap
6942 //
6943 	fl_AutoNum * pAuto1 = getDoc()->getListByID(id);
6944 	if(pAuto1 == NULL)
6945 	{
6946 	        return id;
6947 	}
6948 	///
6949 	/// Now look to see if the ID has been remapped.
6950 	///
6951 	UT_uint32 i,j;
6952 	for(i=0; i<m_numLists; i++)
6953 	{
6954 		if(getAbiList(i)->orig_id == id)
6955 		{
6956 			if(getAbiList(i)->hasBeenMapped == true )
6957 			{
6958 				mappedID =  getAbiList(i)->mapped_id;
6959 			}
6960 			else if(!m_bStruxInserted)
6961 			    ///
6962 			    /// Do the remapping!
6963 			    ///
6964 			{
6965 				fl_AutoNum * pMapAuto = NULL;
6966 				UT_uint32 nLists = getDoc()->getListsCount();
6967 				UT_uint32 highestLevel = 0;
6968 				pf_Frag_Strux* sdh;
6969 //
6970 // Get the List Type
6971 //
6972 				FL_ListType myType = NOT_A_LIST;
6973 				fl_AutoLists al;
6974 				UT_uint32 size_xml_lists = al.getXmlListsSize();
6975 				for(j=0; j < size_xml_lists; j++)
6976 				{
6977 					if( strcmp(m_currentRTFState.m_paraProps.m_pszStyle,al.getXmlList(j))==0)
6978 						break;
6979 				}
6980 				if(j < size_xml_lists)
6981 					myType = static_cast<FL_ListType>(j);
6982 
6983 				getDoc()->getStruxOfTypeFromPosition(m_dposPaste, PTX_Block,&sdh);
6984 				for(j=0; j< nLists; j++)
6985 				{
6986 					fl_AutoNum * pAuto = getDoc()->getNthList(j);
6987 					if(pAuto->isContainedByList(sdh) == true)
6988 					{
6989 						if(highestLevel < pAuto->getLevel())
6990 						{
6991 							highestLevel = pAuto->getLevel();
6992 							FL_ListType thisType = pAuto->getType();
6993 							if(thisType == myType)
6994 							{
6995 								pMapAuto = pAuto;
6996 							}
6997 						}
6998 					}
6999 				}
7000 				if(pMapAuto == NULL )
7001 				{
7002 					mappedID = getDoc()->getUID(UT_UniqueId::List);
7003 				}
7004 				else if( getAbiList(i)->level <= pMapAuto->getLevel() && pMapAuto->getID() != 0)
7005 				{
7006 					mappedID = pMapAuto->getID();
7007 				}
7008 				else
7009 				{
7010 					mappedID = getDoc()->getUID(UT_UniqueId::List);
7011 				}
7012 				getAbiList(i)->hasBeenMapped = true;
7013 				getAbiList(i)->mapped_id = mappedID;
7014 				if(highestLevel > 0)
7015 				{
7016 					getAbiList(i)->mapped_parentid =  getAbiList(i)->orig_parentid;
7017 				}
7018 				else
7019 				{
7020 					getAbiList(i)->mapped_parentid = 0;
7021 					getAbiList(i)->orig_parentid = 0;
7022 					getAbiList(i)->level = 1;
7023 				}
7024 			}
7025 
7026 			///
7027 			/// Now look to see if the parent ID has been remapped, if so update mapped_parentid
7028 			///
7029 			for(j = 0;  j<m_numLists; j++)
7030 			{
7031 				if(getAbiList(j)->orig_id == getAbiList(i)->orig_parentid)
7032 				{
7033 					getAbiList(i)->mapped_parentid = getAbiList(j)->mapped_id;
7034 				}
7035 			}
7036 
7037 		}
7038 	}
7039 	return mappedID;
7040 
7041 }
7042 
7043 /*!
7044  *   OK if we are pasting into the text we have to decide if the list we paste
7045  *   should be a new list or an old list. The user might want to swap paragraphs
7046  *   for example.
7047  */
mapParentID(UT_uint32 id)7048 UT_uint32 IE_Imp_RTF::mapParentID(UT_uint32 id)
7049 {
7050   //
7051   // For the parent ID we have to look to see if the parent ID has been
7052   // remapped or if the id
7053   //
7054 	UT_uint32 mappedID;
7055 	mappedID = id;
7056 	if (!bUseInsertNotAppend())  // if we are reading a file
7057 	{
7058 		return id;
7059 	}
7060 	UT_uint32 i;
7061 	for(i=0; i<m_numLists ; i++)
7062 	{
7063 		if(getAbiList(i)->orig_id == id)
7064 			break;
7065 	}
7066 	if( i < m_numLists && getAbiList(i)->orig_id == id)
7067 	{
7068 	    mappedID =  getAbiList(i)->mapped_id;
7069 	}
7070 	return mappedID;
7071 }
7072 
ApplyParagraphAttributes(bool bDontInsert)7073 bool IE_Imp_RTF::ApplyParagraphAttributes(bool bDontInsert)
7074 {
7075 	const gchar* attribs1[PT_MAX_ATTRIBUTES*2 + 1];
7076 	UT_uint32 attribsCount=0;
7077 
7078 //
7079 // Look to see if the nesting level of our tables has changed.
7080 //
7081 	if(!bUseInsertNotAppend())
7082 	{
7083 		if(m_currentRTFState.m_paraProps.m_tableLevel > m_TableControl.getNestDepth())
7084 		{
7085 			if(m_bParaWrittenForSection)
7086 			{
7087 				xxx_UT_DEBUGMSG(("At Apply Paragraph m_tableLevel %d nestDepth %d \n",m_currentRTFState.m_paraProps.m_tableLevel,m_TableControl.getNestDepth()));
7088 				while((m_currentRTFState.m_paraProps.m_tableLevel > m_TableControl.getNestDepth()) && (m_currentRTFState.m_paraProps.m_tableLevel > 1))
7089 				{
7090 					xxx_UT_DEBUGMSG(("SEVIOR: Doing pard OpenTable \n"));
7091 					m_bCellBlank = false;
7092 					m_bEndTableOpen = false;
7093 					OpenTable();
7094 				}
7095 				xxx_UT_DEBUGMSG(("After Apply Paragraph m_tableLevel %d nestDepth %d \n",m_currentRTFState.m_paraProps.m_tableLevel,m_TableControl.getNestDepth()));
7096 			}
7097 		}
7098 		else if((m_currentRTFState.m_paraProps.m_tableLevel >= 0) && m_currentRTFState.m_paraProps.m_tableLevel < m_TableControl.getNestDepth())
7099 		{
7100 			xxx_UT_DEBUGMSG(("At Apply Paragraph m_tableLevel %d nestDepth %d \n",m_currentRTFState.m_paraProps.m_tableLevel,m_TableControl.getNestDepth()));
7101 			while(m_currentRTFState.m_paraProps.m_tableLevel < m_TableControl.getNestDepth())
7102 			{
7103 				CloseTable();
7104 				if(m_bCellBlank)
7105 				{
7106 					m_bEndTableOpen = true;
7107 				}
7108 			}
7109 			xxx_UT_DEBUGMSG(("After Apply Paragraph m_tableLevel %d nestDepth %d \n",m_currentRTFState.m_paraProps.m_tableLevel,m_TableControl.getNestDepth()));
7110 		}
7111 	}
7112 	m_bParaWrittenForSection = true;
7113 //
7114 // Determine if we've dropped out of a table
7115 //
7116 	if(getTable() != NULL)
7117 	{
7118 		if(!m_currentRTFState.m_paraProps.m_bInTable)
7119 		{
7120 			m_bDoCloseTable = true;
7121 		}
7122 	}
7123 
7124 	std::string propBuffer;
7125 	std::string tempBuffer;
7126 	bool bWord97List = m_currentRTFState.m_paraProps.m_isList && isWord97Lists();
7127 	bool bAbiList = m_currentRTFState.m_paraProps.m_isList && ( 0 != m_currentRTFState.m_paraProps.m_rawID);
7128 	bWord97List = bWord97List && !bAbiList;
7129 	RTF_msword97_listOverride * pOver = NULL;
7130 	UT_uint32 iLevel = 0;
7131 	UT_uint32 iOverride = 0;
7132 //
7133 // Need to get some pointers to add List tabs to the tab definitions.
7134 //
7135 	if(bWord97List)
7136 	{
7137 		iOverride = m_currentRTFState.m_paraProps.m_iOverride;
7138 		iLevel = m_currentRTFState.m_paraProps.m_iOverrideLevel;
7139 		pOver = _getTableListOverride(iOverride);
7140 	}
7141 
7142 	// tabs
7143 	if ((pOver != NULL && pOver->isTab(iLevel)))
7144 	{
7145 //
7146 // The Word 97 RTF list definition has some extra tab stops. Add them here.
7147 //
7148 		if(pOver->isTab(iLevel))
7149 		{
7150 			UT_uint32 i = 0;
7151 			UT_uint32 count = pOver->getTabStopVect(iLevel)->size();
7152 			for(i=0; i< count; i++)
7153 			{
7154 				m_currentRTFState.m_paraProps.m_tabStops.push_back(pOver->getTabStopVect(iLevel)->at(i));
7155 				m_currentRTFState.m_paraProps.m_tabTypes.push_back(pOver->getTabTypeVect(iLevel)->at(i));
7156 				m_currentRTFState.m_paraProps.m_tabLeader.push_back(pOver->getTabLeaderVect(iLevel)->at(i));
7157 			}
7158 		}
7159 	}
7160 	if(!m_currentRTFState.m_paraProps.m_tabStops.empty())
7161 	{
7162 		UT_ASSERT_HARMLESS(m_currentRTFState.m_paraProps.m_tabStops.size() ==
7163 					m_currentRTFState.m_paraProps.m_tabTypes.size() );
7164 		UT_ASSERT_HARMLESS(m_currentRTFState.m_paraProps.m_tabStops.size() ==
7165 					m_currentRTFState.m_paraProps.m_tabLeader.size() );
7166 		propBuffer += "tabstops:";
7167 		for (UT_uint32 i = 0; i < m_currentRTFState.m_paraProps.m_tabStops.size(); i++)
7168 		{
7169 			if (i > 0)
7170 				propBuffer += ",";
7171 
7172 			UT_sint32 tabTwips = m_currentRTFState.m_paraProps.m_tabStops.at(i);
7173 			double tabIn = tabTwips/(20.0*72.);
7174 			eTabType tabType = m_currentRTFState.m_paraProps.m_tabTypes.at(i);
7175 			eTabLeader tabLeader = m_currentRTFState.m_paraProps.m_tabLeader.at(i);
7176 			char  cType = ' ';
7177 			switch(tabType)
7178 			{
7179 			case FL_TAB_LEFT:
7180 				cType ='L';
7181 				break;
7182 			case FL_TAB_RIGHT:
7183 				cType ='R';
7184 				break;
7185 			case FL_TAB_CENTER:
7186 				cType ='C';
7187 				break;
7188 			case FL_TAB_DECIMAL:
7189 				cType ='D';
7190 				break;
7191 			case FL_TAB_BAR:
7192 				cType ='B';
7193 				break;
7194 			default:
7195 				UT_ASSERT_NOT_REACHED();
7196 			}
7197 			char cLeader = '0' + static_cast<char>(tabLeader);
7198 			propBuffer += UT_std_string_sprintf("%s/%c%c", UT_convertInchesToDimensionString(DIM_IN,tabIn,"04"),cType,cLeader);
7199 		}
7200 
7201 		propBuffer += "; ";
7202 	}
7203 
7204 	// justification
7205 	propBuffer += "text-align:";
7206 	switch (m_currentRTFState.m_paraProps.m_justification)
7207 	{
7208 		case RTFProps_ParaProps::pjCentre:
7209 			propBuffer += "center";
7210 			break;
7211 		case RTFProps_ParaProps::pjRight:
7212 			propBuffer += "right";
7213 			break;
7214 		case RTFProps_ParaProps::pjFull:
7215 			propBuffer += "justify";
7216 			break;
7217 		default:
7218 			UT_ASSERT_NOT_REACHED();	// so what is it?
7219 			// fall through
7220 		case RTFProps_ParaProps::pjLeft:
7221 			propBuffer += "left";
7222 			break;
7223 	}
7224 	propBuffer += "; ";
7225 
7226 	// indents - first, left and right, top and bottom
7227 	propBuffer += UT_std_string_sprintf("margin-top:%s; ",		UT_convertInchesToDimensionString(DIM_IN, static_cast<double>(m_currentRTFState.m_paraProps.m_spaceBefore)/1440));
7228 
7229 	propBuffer += UT_std_string_sprintf("margin-bottom:%s; ",	UT_convertInchesToDimensionString(DIM_IN, static_cast<double>(m_currentRTFState.m_paraProps.m_spaceAfter)/1440));
7230 
7231 	propBuffer += "dom-dir:";
7232 	if(m_currentRTFState.m_paraProps.m_dir == UT_BIDI_RTL)
7233 		propBuffer += "rtl; ";
7234 	else
7235 		propBuffer += "ltr; ";
7236 
7237 	//
7238 	// Filled from List deefinition
7239 	//
7240 	if(!bWord97List || bAbiList)
7241 	{
7242 		propBuffer += UT_std_string_sprintf("margin-left:%s; ", UT_convertInchesToDimensionString(DIM_IN, static_cast<double>(m_currentRTFState.m_paraProps.m_indentLeft)/1440));
7243 	}
7244 	propBuffer += UT_std_string_sprintf("margin-right:%s; ", UT_convertInchesToDimensionString(DIM_IN, static_cast<double>(m_currentRTFState.m_paraProps.m_indentRight)/1440));
7245 //
7246 // Filled from List definition
7247 //
7248 	if(!bWord97List || bAbiList)
7249 	{
7250 		propBuffer += UT_std_string_sprintf("text-indent:%s; ", UT_convertInchesToDimensionString(DIM_IN, static_cast<double>(m_currentRTFState.m_paraProps.m_indentFirst)/1440));
7251 	}
7252 // line spacing
7253 	if (m_currentRTFState.m_paraProps.m_lineSpaceExact)
7254 	{
7255         if (m_currentRTFState.m_paraProps.m_lineSpaceVal < 0) {  // exact spacing
7256 			propBuffer += UT_std_string_sprintf("line-height:%spt;",    UT_convertToDimensionlessString(fabs(m_currentRTFState.m_paraProps.m_lineSpaceVal/20.0)));
7257 		}
7258 		else                                                         // "at least" spacing
7259 		{
7260 			propBuffer += UT_std_string_sprintf("line-height:%spt+;",    UT_convertToDimensionlessString(fabs(m_currentRTFState.m_paraProps.m_lineSpaceVal/20.0)));
7261 		}
7262 	}
7263 	else                 // multiple line spacing
7264 	{
7265 		propBuffer += UT_std_string_sprintf("line-height:%s;",	UT_convertToDimensionlessString(fabs(m_currentRTFState.m_paraProps.m_lineSpaceVal/240)));
7266 	}
7267 
7268 	// Lists. If the paragraph has a list element handle it.
7269 	std::string szLevel1;
7270 	std::string szStyle;
7271 	std::string szListID1;
7272 	std::string szParentID1;
7273 	UT_uint32 id = 0,parentID = 0,startValue = 0;
7274 //
7275 // This is for our own extensions to RTF.
7276 //
7277 	if(bUseInsertNotAppend())
7278 	{
7279 		//
7280 		// don't paste lists into hdrftr's
7281 		//
7282 		XAP_Frame * pFrame = XAP_App::getApp()->getLastFocussedFrame();
7283 		FV_View * pView = static_cast<FV_View*>(pFrame->getCurrentView());
7284 		if(pView && pView->isHdrFtrEdit())
7285 		{
7286 			bAbiList = false;
7287 			bWord97List = false;
7288 		}
7289 	}
7290 	if( bAbiList)
7291 	{
7292 	  //
7293 	  // First off assemble the list attributes
7294 	  //
7295 		id = mapID(m_currentRTFState.m_paraProps.m_rawID);
7296 		szListID1 = UT_std_string_sprintf("%d",id);
7297 		parentID = mapParentID(m_currentRTFState.m_paraProps.m_rawParentID);
7298 		szParentID1 = UT_std_string_sprintf("%d",parentID);
7299 		if(parentID == 0)
7300 			m_currentRTFState.m_paraProps.m_level = 1;
7301 		szLevel1 = UT_std_string_sprintf("%d",m_currentRTFState.m_paraProps.m_level);
7302 
7303 		attribs1[attribsCount++] = PT_LISTID_ATTRIBUTE_NAME;
7304 		UT_return_val_if_fail( attribsCount < PT_MAX_ATTRIBUTES * 2,false );
7305 		attribs1[attribsCount++] = szListID1.c_str();
7306 		UT_return_val_if_fail( attribsCount < PT_MAX_ATTRIBUTES * 2,false );
7307 		attribs1[attribsCount++] = PT_PARENTID_ATTRIBUTE_NAME;
7308 		UT_return_val_if_fail( attribsCount < PT_MAX_ATTRIBUTES * 2,false );
7309 		attribs1[attribsCount++] = szParentID1.c_str();
7310 		UT_return_val_if_fail( attribsCount < PT_MAX_ATTRIBUTES * 2,false );
7311 		attribs1[attribsCount++] = PT_LEVEL_ATTRIBUTE_NAME;
7312 		UT_return_val_if_fail( attribsCount < PT_MAX_ATTRIBUTES * 2,false );
7313 		attribs1[attribsCount++] = szLevel1.c_str();
7314 		UT_return_val_if_fail( attribsCount < PT_MAX_ATTRIBUTES * 2,false );
7315 		attribs1[attribsCount] = NULL;
7316 	}
7317 
7318 //
7319 // This is for Word97 Lists
7320 //
7321 	if(bWord97List && pOver)
7322 	{
7323 //
7324 // Now get the properties we've painstakingly put together.
7325 //
7326 		const char * szListID = NULL;
7327 		const char * szParentID = NULL;
7328 		const char * szLevel = NULL;
7329 		const char * szStartat = NULL;
7330 		const char * szFieldFont = NULL;
7331 		const char * szListDelim = NULL;
7332 		const char * szListDecimal = NULL;
7333 		const char * szAlign = NULL;
7334 		const char * szIndent = NULL;
7335 		const char * szListStyle = NULL;
7336 		pOver->buildAbiListProperties( &szListID, &szParentID, &szLevel, &szStartat, &szFieldFont,
7337 									   &szListDelim, &szListDecimal, &szAlign, &szIndent,
7338 									   &szListStyle, iLevel);
7339 
7340 //
7341 // fix up indents.
7342 //
7343 		std::string val;
7344 		double firstLine = UT_convertToInches(szAlign);
7345 		double leftIndent = -firstLine + 0.01;
7346 		if(szIndent && *szIndent)
7347 		{
7348 			leftIndent = UT_convertToInches(szIndent);
7349 		}
7350 		else
7351 		{
7352 			val =  UT_formatDimensionedValue(leftIndent,"in");
7353 			szIndent = val.c_str();
7354 		}
7355 		if((firstLine + leftIndent) < 0.0)
7356 		{
7357 			leftIndent = -firstLine +0.01;
7358 			val =  UT_formatDimensionedValue(leftIndent,"in");
7359 			szIndent = val.c_str();
7360 		}
7361 //
7362 // Got attributes
7363 //
7364 		attribs1[attribsCount++] = PT_LISTID_ATTRIBUTE_NAME;
7365 		attribs1[attribsCount++] = szListID;
7366 		attribs1[attribsCount++] = PT_PARENTID_ATTRIBUTE_NAME;
7367 		attribs1[attribsCount++] = szParentID;
7368 		attribs1[attribsCount++] = PT_LEVEL_ATTRIBUTE_NAME;
7369 		attribs1[attribsCount++] = szLevel;
7370 		attribs1[attribsCount]   = NULL;
7371 
7372 //
7373 // Next do character properties redefined in this list
7374 //
7375 		// bold
7376 		if(pOver->isBoldChanged(iLevel))
7377 		{
7378 			propBuffer += "font-weight:";
7379 			if ( pOver->getBold(iLevel) )
7380 				propBuffer +=  "bold";
7381 			else
7382 				propBuffer += "normal";
7383 			propBuffer += ";";
7384 		}
7385 		// italic
7386 		if(pOver->isItalicChanged(iLevel))
7387 		{
7388 			propBuffer += " font-style:";
7389 			if ( pOver->getItalic(iLevel) )
7390 				propBuffer += "italic";
7391 			else
7392 				propBuffer += "normal";
7393 			propBuffer += ";";
7394 		}
7395 		// underline & overline & strike-out
7396 		if(pOver->isUnderlineChanged(iLevel) || pOver->isStrikeoutChanged(iLevel))
7397 		{
7398 			propBuffer += "; text-decoration:";
7399 			static std::string decors;
7400 			decors.clear();
7401 			if (pOver->getUnderline(iLevel))
7402 			{
7403 				decors += "underline ";
7404 			}
7405 			if (pOver->getStrikeout(iLevel))
7406 			{
7407 				decors += "line-through ";
7408 			}
7409 			if(!pOver->getUnderline(iLevel)  &&
7410 			   !pOver->getStrikeout(iLevel))
7411 			{
7412 				decors = "none";
7413 			}
7414 			propBuffer += decors.c_str();
7415 			propBuffer += ";";
7416 		}
7417 		//superscript and subscript
7418 		if(pOver->isSuperscriptChanged(iLevel) || pOver->isSubscriptChanged(iLevel))
7419 		{
7420 			propBuffer += " text-position:";
7421 			if (pOver->getSuperscript(iLevel))
7422 			{
7423 				if (pOver->getSuperscriptPos(iLevel) != 0.0)
7424 				{
7425 					UT_DEBUGMSG (("RTF: TODO: Handle text position in pt.\n"));
7426 				}
7427 				propBuffer += "superscript;";
7428 			}
7429 			else if (pOver->getSubscript(iLevel))
7430 			{
7431 				if (pOver->getSubscriptPos(iLevel) != 0.0)
7432 				{
7433 					UT_DEBUGMSG (("RTF: TODO: Handle text position in pt.\n"));
7434 				}
7435 				propBuffer += "subscript;";
7436 			}
7437 			else
7438 			{
7439 				propBuffer += "normal;";
7440 			}
7441 		}
7442 
7443 		// font size
7444 		if(pOver->isFontSizeChanged(iLevel))
7445 		{
7446 			propBuffer +=  UT_std_string_sprintf(" font-size:%spt;", std_size_string(static_cast<float>(pOver->getFontSize(iLevel))));
7447 			UT_DEBUGMSG(("RTF: IMPORT!!!!! font sized changed in override %f \n",pOver->getFontSize(iLevel)));
7448 		}
7449 		// typeface
7450 		if(pOver->isFontNumberChanged(iLevel))
7451 		{
7452 			RTFFontTableItem* pFont = GetNthTableFont(pOver->getFontNumber(iLevel));
7453 			if (pFont != NULL)
7454 			{
7455 				propBuffer += " font-family:";
7456 				propBuffer += pFont->m_pFontName;
7457 				propBuffer += ";";
7458 			}
7459 		}
7460 		// Foreground Colour
7461 		if(pOver->isHasColourChanged(iLevel))
7462 		{
7463 			if (pOver->getHasColour(iLevel))
7464 			{
7465 				// colour, only if one has been set. See bug 1324
7466 				UT_uint32 colour = GetNthTableColour(pOver->getColourNumber(iLevel));
7467 				propBuffer += UT_std_string_sprintf(" color:%06x;", colour);
7468 			}
7469 		}
7470 		// BackGround Colour
7471 		if (pOver->isHasBgColourChanged(iLevel))
7472 		{
7473 			if(pOver->getHasBgColour(iLevel))
7474 			{
7475 				// colour, only if one has been set. See bug 1324
7476 				UT_sint32 bgColour = GetNthTableBgColour(pOver->getBgColourNumber(iLevel));
7477 				if (bgColour != -1) // invalid and should be white
7478 				{
7479 					propBuffer += UT_std_string_sprintf(" bgcolor:%06x;", bgColour);
7480 				}
7481 			}
7482 		}
7483 		//
7484 		// Now handle the List properties
7485 		//
7486 
7487 		propBuffer += UT_std_string_sprintf("list-style:%s;",szListStyle);
7488 		propBuffer += UT_std_string_sprintf("list-decimal:%s; ",szListDecimal);
7489 		propBuffer += UT_std_string_sprintf("list-delim:%s; ",szListDelim);
7490 		propBuffer += UT_std_string_sprintf("field-font:%s; ",szFieldFont);
7491 		propBuffer += UT_std_string_sprintf("start-value:%s; ",szStartat);
7492 		propBuffer += UT_std_string_sprintf("margin-left:%s; ",szAlign);
7493 		propBuffer += UT_std_string_sprintf("text-indent:%s;", szIndent); // Note last entry has no ;
7494 	}
7495 
7496 
7497 	if(bAbiList)
7498 	{
7499 		//
7500 		// Now handle the Abi List properties
7501 		//
7502 		szStyle = UT_std_string_sprintf("%s",m_currentRTFState.m_paraProps.m_pszStyle);
7503 		propBuffer += UT_std_string_sprintf("list-style:%s;",m_currentRTFState.m_paraProps.m_pszStyle);
7504 		propBuffer += UT_std_string_sprintf("list-decimal:%s; ",m_currentRTFState.m_paraProps.m_pszListDecimal);
7505 		propBuffer += UT_std_string_sprintf("list-delim:%s; ",m_currentRTFState.m_paraProps.m_pszListDelim);
7506 		propBuffer += UT_std_string_sprintf("field-font:%s; ",m_currentRTFState.m_paraProps.m_pszFieldFont);
7507 		startValue = m_currentRTFState.m_paraProps.m_startValue;
7508 		propBuffer += UT_std_string_sprintf("start-value:%d",startValue);
7509 	}
7510 	// Style name
7511 	if( static_cast<UT_uint32>(m_currentRTFState.m_paraProps.m_styleNumber) < m_styleTable.size() &&
7512 		(m_currentRTFState.m_paraProps.m_styleNumber >= 0) )
7513 	{
7514 		UT_uint32 styleNumber = m_currentRTFState.m_paraProps.m_styleNumber;
7515 		const std::string & styleName = m_styleTable[styleNumber];
7516 		attribs1[attribsCount++] = PT_STYLE_ATTRIBUTE_NAME;
7517 		attribs1[attribsCount++] = styleName.c_str();
7518 		attribs1[attribsCount]   = NULL;
7519 	}
7520 
7521 	// Borders & Shading are exported here
7522 	double w = 0.0;
7523 	UT_sint32 iCol = 0;
7524 	if(m_currentRTFState.m_paraProps.m_bMergeBordersShading)
7525 	{
7526 		propBuffer += "border-merge:1; ";
7527 	}
7528 	if( m_currentRTFState.m_paraProps.m_bBotBorder)
7529 	{
7530 		propBuffer += UT_std_string_sprintf("bot-style:%d; ",m_currentRTFState.m_paraProps.m_iBotBorderStyle);
7531 		w = static_cast<double>(m_currentRTFState.m_paraProps.m_iBotBorderWidth)/1440.;
7532 		UT_LocaleTransactor t(LC_NUMERIC, "C");
7533 		propBuffer += UT_std_string_sprintf("bot-thickness:%fin; ",w);
7534 		w = static_cast<double>(m_currentRTFState.m_paraProps.m_iBotBorderSpacing)/1440.;
7535 		propBuffer += UT_std_string_sprintf("bot-space:%fin; ",w);
7536 		iCol = GetNthTableBgColour(m_currentRTFState.m_paraProps.m_iBotBorderCol);
7537 		propBuffer += UT_std_string_sprintf("bot-color:%06x; ",iCol);
7538 	}
7539 	if( m_currentRTFState.m_paraProps.m_bLeftBorder)
7540 	{
7541 		propBuffer += UT_std_string_sprintf("left-style:%d; ",m_currentRTFState.m_paraProps.m_iLeftBorderStyle);
7542 		UT_LocaleTransactor t(LC_NUMERIC, "C");
7543 		w = static_cast<double>(m_currentRTFState.m_paraProps.m_iLeftBorderWidth)/1440.;
7544 		propBuffer += UT_std_string_sprintf("left-thickness:%fin; ",w);
7545 		w = static_cast<double>(m_currentRTFState.m_paraProps.m_iLeftBorderSpacing)/1440.;
7546 		propBuffer += UT_std_string_sprintf("left-space:%fin; ",w);
7547 		iCol = GetNthTableBgColour(m_currentRTFState.m_paraProps.m_iLeftBorderCol);
7548 		propBuffer += UT_std_string_sprintf("left-color:%06x; ",iCol);
7549 	}
7550 	if( m_currentRTFState.m_paraProps.m_bRightBorder)
7551 	{
7552 		propBuffer += UT_std_string_sprintf("right-style:%d; ",m_currentRTFState.m_paraProps.m_iRightBorderStyle);
7553 		UT_LocaleTransactor t(LC_NUMERIC, "C");
7554 		w = static_cast<double>(m_currentRTFState.m_paraProps.m_iRightBorderWidth)/1440.;
7555 		propBuffer += UT_std_string_sprintf("right-thickness:%fin; ",w);
7556 		w = static_cast<double>(m_currentRTFState.m_paraProps.m_iRightBorderSpacing)/1440.;
7557 		propBuffer += UT_std_string_sprintf("right-space:%fin; ",w);
7558 		iCol = GetNthTableBgColour(m_currentRTFState.m_paraProps.m_iRightBorderCol);
7559 		propBuffer += UT_std_string_sprintf("right-color:%06x; ",iCol);
7560 	}
7561 	if( m_currentRTFState.m_paraProps.m_bTopBorder)
7562 	{
7563 		propBuffer += UT_std_string_sprintf("top-style:%d; ",m_currentRTFState.m_paraProps.m_iTopBorderStyle);
7564 		UT_LocaleTransactor t(LC_NUMERIC, "C");
7565 		w = static_cast<double>(m_currentRTFState.m_paraProps.m_iTopBorderWidth)/1440.;
7566 		propBuffer += UT_std_string_sprintf("top-thickness:%fin; ",w);
7567 		w = static_cast<double>(m_currentRTFState.m_paraProps.m_iTopBorderSpacing)/1440.;
7568 		propBuffer += UT_std_string_sprintf("top-space:%fin; ",w);
7569 		iCol = GetNthTableBgColour(m_currentRTFState.m_paraProps.m_iTopBorderCol);
7570 		propBuffer += UT_std_string_sprintf("top-color:%06x; ",iCol);
7571 	}
7572 	if(m_currentRTFState.m_paraProps.m_iShadingPattern)
7573 	{
7574 		propBuffer += UT_std_string_sprintf("shading-pattern:%d; ",m_currentRTFState.m_paraProps.m_iShadingPattern);
7575 
7576 		if(m_currentRTFState.m_paraProps.m_iShadingForeCol > -1)
7577 		{
7578 			iCol = GetNthTableBgColour(m_currentRTFState.m_paraProps.m_iShadingForeCol);
7579 			propBuffer += UT_std_string_sprintf("shading-foreground-color:%06x; ",iCol);
7580 		}
7581 
7582 		if(m_currentRTFState.m_paraProps.m_iShadingBackCol > -1)
7583 		{
7584 			iCol = GetNthTableBgColour(m_currentRTFState.m_paraProps.m_iShadingBackCol);
7585 			propBuffer += UT_std_string_sprintf("shading-background-color:%06x; ",iCol);
7586 			if(m_currentRTFState.m_paraProps.m_iShadingPattern == 1)
7587 			{
7588 				propBuffer += UT_std_string_sprintf("shading-foreground-color:%06x; ",iCol);
7589 			}
7590 		}
7591 	}
7592 //
7593 // If there are character properties defined now write them into our buffer
7594 //
7595 
7596 //
7597 // Remove the trailing ";" if needed.
7598 //
7599 	UT_sint32 eol = propBuffer.size();
7600 	while(eol >= 0 && (propBuffer[eol] == ' ' || propBuffer[eol] == 0))
7601 	{
7602 		eol--;
7603 	}
7604 	if(propBuffer[eol] == ';')
7605 	{
7606 		propBuffer[eol] = 0;
7607 	}
7608 	attribs1[attribsCount++] = PT_PROPS_ATTRIBUTE_NAME;
7609 //
7610 // if we are reading a file or parsing header and footers
7611 // and we're in a list, append char props to this.
7612 //
7613 	if ( !(bUseInsertNotAppend()) && (bAbiList || bWord97List ))
7614 	{
7615 		buildCharacterProps(propBuffer);
7616 		xxx_UT_DEBUGMSG(("SEVIOR: propBuffer = %s \n",propBuffer.c_str()));
7617 	}
7618 	attribs1[attribsCount++] = propBuffer.c_str();
7619 	attribs1[attribsCount] = NULL;
7620 
7621 	if(m_currentRTFState.m_revAttr.size())
7622 	{
7623 		attribs1[attribsCount++] = "revision";
7624 		attribs1[attribsCount++] = m_currentRTFState.m_revAttr.utf8_str();
7625 		attribs1[attribsCount] = NULL;
7626 	}
7627 
7628 	if (!bUseInsertNotAppend()) // if we are reading a file or parsing header and footers
7629 	{
7630 		if(bAbiList || bWord97List )
7631 		{
7632 			UT_DEBUGMSG(("Append block 1 \n"));
7633 			bool bret = false;
7634 			if(m_pDelayedFrag)
7635 			{
7636 				bret = getDoc()->insertStruxBeforeFrag(m_pDelayedFrag,PTX_Block,attribs1);
7637 			}
7638 			else
7639 			{
7640 				bret = getDoc()->appendStrux(PTX_Block, attribs1);
7641 			}
7642 			m_bEndTableOpen = false;
7643 			m_bCellBlank = false;
7644 			m_newParaFlagged = false;
7645 			m_bSectionHasPara = true;
7646 			getDoc()->appendFmtMark();
7647 			//
7648 			// Insert a list-label field??
7649 			//
7650 			const gchar* fielddef[5];
7651 			fielddef[0] ="type";
7652 			fielddef[1] = "list_label";
7653 			fielddef[2] = NULL;
7654 			fielddef[3] = NULL;
7655 			fielddef[4] = NULL;
7656 			if(bWord97List)
7657 			{
7658 					fielddef[2] = "props";
7659 					fielddef[3] = "text-decoration:none";
7660 			}
7661 			bret =   getDoc()->appendObject(PTO_Field,fielddef);
7662 			UT_UCSChar cTab = UCS_TAB;
7663 //
7664 // Put the tab back in.
7665 //
7666 			if(bWord97List)
7667 			{
7668 					const gchar* attribs[3] = {"props","text-decoration:none",NULL};
7669 					getDoc()->appendFmt(attribs);
7670 			}
7671 			getDoc()->appendSpan(&cTab,1);
7672 			return bret;
7673 		}
7674 		else
7675 		{
7676 			//UT_DEBUGMSG(("SEVIOR: Apply Para's atributes append strux -2 \n"));
7677 			bool ok = false;
7678 			if(m_pDelayedFrag)
7679 			{
7680 				ok = getDoc()->insertStruxBeforeFrag(m_pDelayedFrag,PTX_Block,attribs1);
7681 			}
7682 			else
7683 			{
7684 				ok = getDoc()->appendStrux(PTX_Block, attribs1);
7685 			}
7686 			m_newParaFlagged = false;
7687 			m_bSectionHasPara = true;
7688 			m_bEndTableOpen = false;
7689 			m_bCellBlank = false;
7690 			return ok;
7691 		}
7692 	}
7693 	else
7694 	{
7695 		bool bSuccess = true;
7696 		if(bAbiList || bWord97List )
7697 		{
7698 			if(!bDontInsert)
7699 			{
7700 				UT_DEBUGMSG(("Insert block at 1 \n"));
7701 				markPasteBlock();
7702 				insertStrux(PTX_Block);
7703 			}
7704 			//
7705 			// Put the tab back in.
7706 			//
7707 			UT_UCSChar cTab = UCS_TAB;
7708 			getDoc()->insertSpan(m_dposPaste,&cTab,1);
7709 			m_newParaFlagged = false;
7710 			m_bSectionHasPara = true;
7711 			m_dposPaste++;
7712 			if(m_posSavedDocPosition > 0)
7713 				m_posSavedDocPosition++;
7714 			pf_Frag_Strux* sdh_cur;
7715 			UT_uint32 j;
7716 			fl_AutoNum * pAuto = getDoc()->getListByID(id);
7717 			if(pAuto == NULL)
7718 			/*
7719 			* Got to create a new list here.
7720 			* Old one may have been cut out or ID may have
7721 			* been remapped.
7722 			*/
7723 			{
7724 				FL_ListType lType = NOT_A_LIST;
7725 				fl_AutoLists al;
7726 				UT_uint32 size_xml_lists = al.getXmlListsSize();
7727 				for(j=0; j< size_xml_lists; j++)
7728 				{
7729 					if( strcmp(szStyle.c_str(),al.getXmlList(j)) ==0)
7730 					{
7731 						break;
7732 					}
7733 				}
7734 				if(j < size_xml_lists)
7735 					lType = static_cast<FL_ListType>(j);
7736 				else
7737 					lType = static_cast<FL_ListType>(0);
7738 				pAuto = new fl_AutoNum(id, parentID, lType, startValue,static_cast<gchar *>(m_currentRTFState.m_paraProps.m_pszListDelim),static_cast<gchar *>(m_currentRTFState.m_paraProps.m_pszListDecimal), getDoc(), NULL);
7739 				getDoc()->addList(pAuto);
7740 				pAuto->fixHierarchy();
7741 			}
7742 			bSuccess = getDoc()->getStruxOfTypeFromPosition(m_dposPaste,PTX_Block,&sdh_cur);
7743 			///
7744 			/// Now insert this into the pAuto List
7745 			///
7746 			pAuto->addItem(sdh_cur);
7747 			if(parentID != 0)
7748 			{
7749 				pAuto->findAndSetParentItem();
7750 				pAuto->markAsDirty();
7751 			}
7752 			bSuccess = getDoc()->changeStruxFmt(PTC_SetFmt,m_dposPaste,m_dposPaste,attribs1, NULL,PTX_Block);
7753 		}
7754 		else if(bUseInsertNotAppend())
7755 		{
7756 			ABI_Paste_Table * pPaste = NULL;
7757 			m_pasteTableStack.viewTop((void**)(&pPaste));
7758 			if(pPaste != NULL)
7759 			{
7760 				if(!pPaste->m_bHasPastedCellStrux && pPaste->m_bHasPastedTableStrux)
7761 				{
7762 //
7763 // We have either a bare table strux or a bare endcell strux. No blocks
7764 // allowed here.
7765 //
7766 					return true;
7767 				}
7768 			}
7769 			UT_DEBUGMSG((" Insert block at 2 \n"));
7770 			if(!bDontInsert)
7771 			{
7772 				markPasteBlock();
7773 				insertStrux(PTX_Block);
7774 			}
7775 			m_newParaFlagged = false;
7776 			m_bSectionHasPara = true;
7777 			bSuccess = getDoc()->changeStruxFmt(PTC_SetFmt,m_dposPaste,m_dposPaste, attribs1,NULL,PTX_Block);
7778 			//
7779 			// Now check if this strux has associated list element. If so stop the list!
7780 			//
7781 			pf_Frag_Strux* sdh = NULL;
7782 			getDoc()->getStruxOfTypeFromPosition(m_dposPaste,PTX_Block,&sdh);
7783 			bool bisListItem = false;
7784 			//
7785 			// Have to loop so that multi-level lists get stopped. Each StopList removes
7786 			// the sdh from the next highest level.
7787 			//
7788 			UT_sint32 iLoop = 20;
7789 			do
7790 			{
7791 				fl_AutoNum * pAuto = NULL;
7792 				bisListItem = false;
7793 				for(UT_uint32 i=0; (i< getDoc()->getListsCount() && !bisListItem); i++)
7794 				{
7795 					pAuto = getDoc()->getNthList(i);
7796 					if(pAuto)
7797 						bisListItem = pAuto->isItem(sdh);
7798 				}
7799 				//
7800 				// We've created a list element where we should not. Stop it now!!
7801 				//
7802 				if(bisListItem)
7803 				{
7804 					UT_DEBUGMSG(("SEVIOR: Stopping list at %p \n",sdh));
7805 					getDoc()->StopList(sdh);
7806 				}
7807 				iLoop--;
7808 			}
7809 			while(bisListItem && (iLoop > 0));
7810 		}
7811 		return bSuccess;
7812 	}
7813 	return true;
7814 }
7815 
7816 
ResetCellAttributes(void)7817 bool IE_Imp_RTF::ResetCellAttributes(void)
7818 {
7819 	bool ok = FlushStoredChars();
7820 	m_currentRTFState.m_cellProps = RTFProps_CellProps();
7821 	return ok;
7822 }
7823 
7824 
ResetTableAttributes(void)7825 bool IE_Imp_RTF::ResetTableAttributes(void)
7826 {
7827 	bool ok = FlushStoredChars();
7828 	m_currentRTFState.m_tableProps = RTFProps_TableProps();
7829 	return ok;
7830 }
7831 
ResetParagraphAttributes()7832 bool IE_Imp_RTF::ResetParagraphAttributes()
7833 {
7834 	xxx_UT_DEBUGMSG(("Reset Para Attributes \n"));
7835 	// the \pard keyword always implies we are already in a paragraph
7836 	bool ok = FlushStoredChars();
7837 	m_currentRTFState.m_paraProps = RTFProps_ParaProps();
7838 	m_currentRTFState.m_cellProps = RTFProps_CellProps();
7839 	return ok;
7840 }
7841 
7842 
ResetSectionAttributes()7843 bool IE_Imp_RTF::ResetSectionAttributes()
7844 {
7845 	// the \sectd keyword always implies we are in a section
7846 	bool ok = FlushStoredChars();
7847 
7848 	// not quite correct. a sectd will reset the section defaults
7849 	// to the previously acquired page defaults
7850 
7851 	// margr, margl, margt, margb, paperh, gutter
7852 
7853 	m_currentRTFState.m_sectionProps = m_sectdProps ;
7854 	m_bParaWrittenForSection = false;
7855 	return ok;
7856 }
7857 
7858 
ApplySectionAttributes()7859 bool IE_Imp_RTF::ApplySectionAttributes()
7860 {
7861 	const gchar* pProps = "props";
7862 	std::string propBuffer;
7863 	std::string tempBuffer;
7864 	std::string szHdrID;
7865 	std::string szFtrID;
7866 	std::string szHdrEvenID;
7867 	std::string szFtrEvenID;
7868 	std::string szHdrFirstID;
7869 	std::string szFtrFirstID;
7870 	std::string szHdrLastID;
7871 	std::string szFtrLastID;
7872 	short paramIndex = 0;
7873 
7874 	UT_DEBUGMSG (("Applying SectionAttributes\n"));
7875 
7876 	// columns
7877 	propBuffer += UT_std_string_sprintf("columns:%d", m_currentRTFState.m_sectionProps.m_numCols);
7878 
7879 	if (m_currentRTFState.m_sectionProps.m_bColumnLine)
7880 	{
7881 		propBuffer += "; column-line:on";
7882 	}
7883 	{
7884 		switch (m_currentRTFState.m_sectionProps.m_breakType) {
7885 		case RTFProps_SectionProps::sbkNone:
7886 //			propBuffer += "; ";
7887 			break;
7888 		case RTFProps_SectionProps::sbkColumn:
7889 			break;
7890 		case RTFProps_SectionProps::sbkPage:
7891 			break;
7892 		case RTFProps_SectionProps::sbkEven:
7893 			break;
7894 		case RTFProps_SectionProps::sbkOdd:
7895 			break;
7896 		default:
7897 			UT_ASSERT_HARMLESS (UT_SHOULD_NOT_HAPPEN);
7898 		}
7899 	}
7900 
7901 	UT_LocaleTransactor t(LC_NUMERIC, "C");
7902 	if(true /*m_currentRTFState.m_sectionProps.m_leftMargTwips != 0*/)
7903 	{
7904 		double inch = static_cast<double>(m_currentRTFState.m_sectionProps.m_leftMargTwips)/1440.;
7905 		propBuffer += UT_std_string_sprintf("; page-margin-left:%fin",inch);
7906 	}
7907 	if(true /*m_currentRTFState.m_sectionProps.m_rightMargTwips != 0*/)
7908 	{
7909 		double inch = static_cast<double>(m_currentRTFState.m_sectionProps.m_rightMargTwips)/1440.;
7910 		propBuffer += UT_std_string_sprintf("; page-margin-right:%fin",inch);
7911 	}
7912 	if(true /*m_currentRTFState.m_sectionProps.m_topMargTwips != 0*/)
7913 	{
7914 		double inch = static_cast<double>(m_currentRTFState.m_sectionProps.m_topMargTwips)/1440.;
7915 		propBuffer += UT_std_string_sprintf("; page-margin-top:%fin",inch);
7916 	}
7917 	if(true /*m_currentRTFState.m_sectionProps.m_bottomMargTwips != 0*/)
7918 	{
7919 		double inch = static_cast<double>(m_currentRTFState.m_sectionProps.m_bottomMargTwips)/1440.;
7920 		propBuffer += UT_std_string_sprintf("; page-margin-bottom:%fin",inch);
7921 	}
7922 	if(true /*m_currentRTFState.m_sectionProps.m_colSpaceTwips != 0*/)
7923 	{
7924 		double inch = static_cast<double>(m_currentRTFState.m_sectionProps.m_colSpaceTwips)/1440.;
7925 		propBuffer += UT_std_string_sprintf("; column-gap:%fin",inch);
7926 	}
7927 	if(m_currentRTFState.m_sectionProps.m_headerYTwips != 0)
7928 	{
7929 		UT_sint32 sheader = 0;
7930 //
7931 // The RTF spec is to define a fixed height for the header. We calculate
7932 // the header height as Top margin - header margin.
7933 //
7934 // So the header margin = topmargin - header height.
7935 //
7936 		if(m_currentRTFState.m_sectionProps.m_topMargTwips != 0)
7937 		{
7938 			sheader = m_currentRTFState.m_sectionProps.m_headerYTwips;
7939 			if(sheader < 0)
7940 			{
7941 				sheader = 0;
7942 			}
7943 		}
7944 		double inch = static_cast<double>(sheader)/1440.;
7945 		propBuffer += UT_std_string_sprintf("; page-margin-header:%fin",inch);
7946 	}
7947 #if 0
7948 	if(m_currentRTFState.m_sectionProps.m_gutterTwips != 0)
7949 	{
7950 		double inch = static_cast<double>( m_currentRTFState.m_sectionProps.m_gutterTwips)/1440.;
7951 		propBuffer += UT_std_string_sprintf("; page-margin-footer:%fin",inch);
7952 	}
7953 	UT_DEBUGMSG(("SEVIOR: propBuffer = %s \n",propBuffer.c_str()));
7954 #endif
7955 	if(m_currentRTFState.m_sectionProps.m_footerYTwips != 0)
7956 	{
7957 		double inch = static_cast<double>( m_currentRTFState.m_sectionProps.m_footerYTwips)/1440.;
7958 		propBuffer += UT_std_string_sprintf("; page-margin-footer:%fin",inch);
7959 	}
7960 	UT_DEBUGMSG(("SEVIOR: propBuffer = %s \n",propBuffer.c_str()));
7961 	if(m_currentRTFState.m_sectionProps.m_dir != static_cast<UT_uint32>(UT_BIDI_UNSET))
7962 	{
7963 		const char r[] = "rtl";
7964 		const char l[] = "ltr";
7965 		const char ar[] = "right";
7966 		const char al[] = "left";
7967 		const char * d, * a;
7968 		if(m_currentRTFState.m_sectionProps.m_dir == UT_BIDI_RTL)
7969 		{
7970 			d = r;
7971 			a = ar;
7972 		}
7973 		else
7974 		{
7975 			d = l;
7976 			a = al;
7977 		}
7978 
7979         propBuffer += UT_std_string_sprintf("; dom-dir:%s; text-align:%s",d,a);
7980         xxx_UT_DEBUGMSG(("Apply sect prop: [%s]\n", tempBuffer.c_str()));
7981 	}
7982 
7983 	xxx_UT_DEBUGMSG(("SEVIOR: propBuffer = %s \n",propBuffer.c_str()));
7984 
7985 	const gchar* propsArray[15];
7986 	propsArray[0] = pProps;
7987 	propsArray[1] = propBuffer.c_str();
7988 	paramIndex = 2;
7989 	if (m_currentHdrID != 0)
7990 	{
7991 		UT_DEBUGMSG (("Applying header\n"));
7992 		propsArray [paramIndex] = "header";
7993 		paramIndex++;
7994 		szHdrID = UT_std_string_sprintf ("%u", m_currentHdrID);
7995 		propsArray [paramIndex] = szHdrID.c_str();
7996 		paramIndex++;
7997 	}
7998 	if (m_currentHdrEvenID != 0)
7999 	{
8000 		UT_DEBUGMSG (("Applying header even\n"));
8001 		propsArray [paramIndex] = "header-even";
8002 		paramIndex++;
8003 		szHdrEvenID = UT_std_string_sprintf ("%u", m_currentHdrEvenID);
8004 		propsArray [paramIndex] = szHdrEvenID.c_str();
8005 		paramIndex++;
8006 	}
8007 	if (m_currentHdrFirstID != 0)
8008 	{
8009 		UT_DEBUGMSG (("Applying header first\n"));
8010 		propsArray [paramIndex] = "header-first";
8011 		paramIndex++;
8012 		szHdrFirstID = UT_std_string_sprintf ("%u", m_currentHdrFirstID);
8013 		propsArray [paramIndex] = szHdrFirstID.c_str();
8014 		paramIndex++;
8015 	}
8016 	if (m_currentHdrLastID != 0)
8017 	{
8018 		UT_DEBUGMSG (("Applying header last\n"));
8019 		propsArray [paramIndex] = "header-last";
8020 		paramIndex++;
8021 		szHdrLastID = UT_std_string_sprintf ("%u", m_currentHdrLastID);
8022 		propsArray [paramIndex] = szHdrLastID.c_str();
8023 		paramIndex++;
8024 	}
8025 	if (m_currentFtrID != 0)
8026 	{
8027 		UT_DEBUGMSG (("Applying footer\n"));
8028 		propsArray [paramIndex] = "footer";
8029 		paramIndex++;
8030 		szFtrID = UT_std_string_sprintf("%u", m_currentFtrID);
8031 		propsArray [paramIndex] = szFtrID.c_str();
8032 		paramIndex++;
8033 	}
8034 	if (m_currentFtrEvenID != 0)
8035 	{
8036 		UT_DEBUGMSG (("Applying footer even\n"));
8037 		propsArray [paramIndex] = "footer-even";
8038 		paramIndex++;
8039 		szFtrEvenID = UT_std_string_sprintf("%u", m_currentFtrEvenID);
8040 		propsArray [paramIndex] = szFtrEvenID.c_str();
8041 		paramIndex++;
8042 	}
8043 	if (m_currentFtrFirstID != 0)
8044 	{
8045 		UT_DEBUGMSG (("Applying footer first\n"));
8046 		propsArray [paramIndex] = "footer-first";
8047 		paramIndex++;
8048 		szFtrFirstID = UT_std_string_sprintf ("%u", m_currentFtrFirstID);
8049 		propsArray [paramIndex] = szFtrFirstID.c_str();
8050 		paramIndex++;
8051 	}
8052 	if (m_currentFtrLastID != 0)
8053 	{
8054 		UT_DEBUGMSG (("Applying footer last\n"));
8055 		propsArray [paramIndex] = "footer-last";
8056 		paramIndex++;
8057 		szFtrLastID = UT_std_string_sprintf ("%u", m_currentFtrLastID);
8058 		propsArray [paramIndex] = szFtrLastID.c_str();
8059 		paramIndex++;
8060 	}
8061 	if(m_currentRTFState.m_revAttr.size())
8062 	{
8063 		propsArray[paramIndex++] = "revision";
8064 		propsArray[paramIndex++] = m_currentRTFState.m_revAttr.utf8_str();
8065 	}
8066 
8067 	UT_ASSERT_HARMLESS (paramIndex < 15);
8068 	propsArray [paramIndex] = NULL;
8069 
8070 	if (!bUseInsertNotAppend()) // if we are reading a file or parsing a header and footer
8071 	{
8072 		UT_DEBUGMSG(("Appending Section strux now \n"));
8073 		return getDoc()->appendStrux(PTX_Section, propsArray);
8074 	}
8075 	else
8076 	{
8077 		// Add a block before the section so there's something content
8078 		// can be inserted into.
8079 		UT_DEBUGMSG(("Insert block at 3 \n"));
8080 		markPasteBlock();
8081 		bool bSuccess = insertStrux(PTX_Block);
8082 
8083 		if (bSuccess)
8084 		{
8085 			m_dposPaste--;
8086 			if(m_posSavedDocPosition > 0)
8087 				m_posSavedDocPosition--;
8088 			XAP_Frame * pFrame = XAP_App::getApp()->getLastFocussedFrame();
8089 			if(pFrame == NULL)
8090 			{
8091 				return false;
8092 			}
8093 			FV_View * pView = static_cast<FV_View*>(pFrame->getCurrentView());
8094 			if(pView == NULL)
8095 			{
8096 				return false;
8097 			}
8098 			if(!pView->isInDocSection(m_dposPaste))
8099 			{
8100 				return false;
8101 			}
8102 			bSuccess = insertStrux(PTX_Section);
8103 			if (bSuccess)
8104 			{
8105 				bSuccess = getDoc()->changeStruxFmt(PTC_SetFmt,m_dposPaste,m_dposPaste,
8106 													   propsArray,NULL,PTX_Section);
8107 			}
8108 		}
8109 		return bSuccess;
8110 	}
8111 }
8112 
8113 //////////////////////////////////////////////////////////////////////////////
8114 // List Table reader
8115 /////////////////////////////////////////////////////////////////////////////
8116 
8117 /*!
8118  * This is a general purpose parameter reader. It returns the value of a keyword
8119  * surrounded by a brace. For a construct of the form...
8120  * {\mehere fred}
8121  *         ^
8122  *         Current read point.
8123  * It will return fred and swallow the closing brace.
8124  * For a construct of the form
8125  * {\mehere fred;}
8126  *         ^
8127  *         Current read point.
8128  * It will return fred and swallow the closing brace and semicolon.
8129  * For a construct of the form
8130  * {\mehere {\key1 fred;} {\key2 fred2} {\key3 {\key4 fred}}}
8131  *         ^
8132  *         Current read point.
8133  * It will return {\key1 fred;} {\key2 fred2} {\key3 {\key4 fred}}  and
8134  * swallow the closing brace.
8135  * returns NULL on error.
8136  */
getCharsInsideBrace(void)8137 char * IE_Imp_RTF::getCharsInsideBrace(void)
8138 {
8139 	unsigned static char keyword[MAX_KEYWORD_LEN];
8140 	unsigned char ch;
8141 
8142 	// OK scan through the text until a closing delimeter is
8143 	// found
8144 
8145 	UT_sint32 count = 0;
8146 	UT_uint32 nesting = 1;
8147 	while(nesting > 0 && count < MAX_KEYWORD_LEN - 1)
8148 	{
8149 		if (!ReadCharFromFile(&ch))
8150 			return NULL;
8151 		if( nesting == 1 && (ch == '}'  || ch == ';'))
8152 		{
8153 			nesting--;
8154 		}
8155 		else
8156 		{
8157 			if(ch == '{')
8158 			{
8159 				nesting++;
8160 			}
8161 			if(ch == '}')
8162 			{
8163 				nesting--;
8164 			}
8165 			keyword[count++] = ch;
8166 		}
8167 	}
8168 	if(ch == ';')
8169 	{
8170 //
8171 // Swallow closing brace if ";}" finishes
8172 //
8173 		if (!ReadCharFromFile(&ch))
8174 			return NULL;
8175 //
8176 // if character is not a '}' put it back in the input stream.
8177 //
8178 		if(ch != '}')
8179 		{
8180 			SkipBackChar(ch);
8181 		}
8182 	}
8183 	keyword[count++] = 0;
8184 	return reinterpret_cast<char*>(&keyword[0]);
8185 }
8186 
8187 
ReadListTable()8188 bool IE_Imp_RTF::ReadListTable()
8189 {
8190 //
8191 // Ensure the list tables are empty to start.
8192 //
8193 	UT_std_vector_purgeall(m_vecWord97Lists);
8194 	unsigned char keyword[MAX_KEYWORD_LEN];
8195 	unsigned char ch;
8196 	UT_sint32 parameter = 0;
8197 	bool paramUsed = false;
8198 	UT_uint32 nesting = 1;
8199 	xxx_UT_DEBUGMSG(("Doing Read List Table \n"));
8200 	while (nesting >0) // Outer loop
8201 	{
8202 		xxx_UT_DEBUGMSG(("Nesting %d \n",nesting));
8203 		if (!ReadCharFromFile(&ch))
8204 		{
8205 			return false;
8206 		}
8207 		if(ch == '{')  //new list or listoverride?
8208 		{
8209 			nesting++;
8210 			if (!ReadCharFromFile(&ch))
8211 			{
8212 				return false;
8213 			}
8214 			if(!ReadKeyword(keyword, &parameter, &paramUsed, MAX_KEYWORD_LEN))
8215 			{
8216 				return false;
8217 			}
8218 			if (strcmp(reinterpret_cast<char*>(&keyword[0]), "list") == 0)
8219 			{
8220 				if(!HandleTableList())
8221 					return false;
8222 
8223 // HandleTableList eats the last "}"
8224 
8225 				nesting--;
8226 			}
8227 			else
8228 			{
8229 				UT_DEBUGMSG(("Unexpected keyword in listable %s Here \n",keyword));
8230 			}
8231 		}
8232 		else if(ch == '}')
8233 		{
8234 			nesting--;
8235 		}
8236 	}
8237 	// Reclaim group }
8238 	if (ch=='}') SkipBackChar(ch);
8239 	xxx_UT_DEBUGMSG(("Return from List Table \n"));
8240 	return true;
8241 }
8242 
8243 /*!
8244  * This method parses out the \list item in a list tabledefinition.
8245  */
HandleTableList(void)8246 bool IE_Imp_RTF::HandleTableList(void)
8247 {
8248 	unsigned char keyword[MAX_KEYWORD_LEN];
8249 	unsigned char ch;
8250     UT_sint32 parameter = 0;
8251 	bool paramUsed = false;
8252 	UT_uint32 nesting = 1;
8253 	UT_uint32 levelCount = 0;
8254 //
8255 // Increment list counting vector
8256 //
8257 	RTF_msword97_list * pList = new  RTF_msword97_list(this);
8258 	m_vecWord97Lists.push_back(pList);
8259 //
8260 // OK Parse this \list
8261 //
8262 	while(nesting > 0) // Outer loop
8263 	{
8264 		if (!ReadCharFromFile(&ch))
8265 			return false;
8266 		if(ch == '{')  // listlevel
8267 		{
8268 			if (!ReadCharFromFile(&ch))
8269 			{
8270 				return false;
8271 			}
8272 			if(!ReadKeyword(keyword, &parameter, &paramUsed, MAX_KEYWORD_LEN))
8273 			{
8274 				return false;
8275 			}
8276 			if(strcmp(reinterpret_cast<char*>(&keyword[0]),"listlevel") == 0)
8277 			{
8278 				HandleListLevel(pList,levelCount);
8279 				levelCount++;
8280 			}
8281 			else if(strcmp(reinterpret_cast<char*>(&keyword[0]),"listid") == 0)
8282 			{
8283 				pList->m_RTF_listID = static_cast<UT_uint32>(parameter);
8284 			}
8285 			else
8286 			{
8287 				char * szLevelText = getCharsInsideBrace();
8288 				if(!szLevelText)
8289 					return false;
8290 			}
8291 		}
8292 		else if(ch == '}')
8293 		{
8294 			nesting--;
8295 		}
8296 		else
8297 		{
8298 			if(!ReadKeyword(keyword, &parameter, &paramUsed, MAX_KEYWORD_LEN))
8299 			{
8300 				return false;
8301 			}
8302 			if(strcmp(reinterpret_cast<char*>(&keyword[0]),"listtemplateid") == 0)
8303 			{
8304 				pList->m_RTF_listTemplateID = parameter;
8305 			}
8306 			else if(strcmp(reinterpret_cast<char*>(&keyword[0]),"listid") == 0)
8307 			{
8308 				pList->m_RTF_listID = static_cast<UT_uint32>(parameter);
8309 			}
8310 			else
8311 			{
8312 				UT_DEBUGMSG(("SEVIOR: keyword %s found and ignored in listtable definition \n",keyword));
8313 			}
8314 		}
8315 	}
8316 	return true;
8317 }
8318 
8319 /*!
8320  * This method parses out the list table definition of listlevel's
8321  */
HandleListLevel(RTF_msword97_list * pList,UT_uint32 levelCount)8322 bool IE_Imp_RTF::HandleListLevel(RTF_msword97_list * pList, UT_uint32 levelCount  )
8323 {
8324 	unsigned char keyword[MAX_KEYWORD_LEN];
8325 	unsigned char ch;
8326 	UT_sint32 parameter = 0;
8327 	bool paramUsed = false;
8328 	UT_uint32 nesting = 1;
8329 	std::string szLevelNumbers;
8330 	std::string szLevelText;
8331 //
8332 // OK define this in the data structure.
8333 //
8334 	RTF_msword97_level * pLevel = new RTF_msword97_level(pList, levelCount);
8335     RTFProps_ParaProps * pParas =  new RTFProps_ParaProps();
8336 	RTFProps_CharProps *  pChars = new	RTFProps_CharProps();
8337     RTFProps_bParaProps * pbParas =  new RTFProps_bParaProps();
8338 	RTFProps_bCharProps *  pbChars = new	RTFProps_bCharProps();
8339 	pLevel->m_pParaProps = pParas;
8340 	pLevel->m_pCharProps = pChars;
8341 	pLevel->m_pbParaProps = pbParas;
8342 	pLevel->m_pbCharProps = pbChars;
8343 	delete pList->m_RTF_level[levelCount];
8344 	pList->m_RTF_level[levelCount] = pLevel;
8345 #if 0 // Sevior use this!! The other method can lead to inccorect results upon
8346 	// import. If we export RTF list ID starting at 10000 they might clash
8347     // with these later.
8348 	pLevel->m_AbiLevelID = UT_rand();
8349 	while(pLevel->m_AbiLevelID < 10000)
8350 		pLevel->m_AbiLevelID = UT_rand();
8351 #else
8352 	//pLevel->m_AbiLevelID = pLevel->m_sLastAssignedLevelID++;
8353 	pLevel->m_AbiLevelID = getDoc()->getUID(UT_UniqueId::List);
8354 #endif
8355 	while(nesting > 0)
8356 	{
8357 		if (!ReadCharFromFile(&ch))
8358 			return false;
8359 		if(ch == '{')  // levelnumber and leveltext
8360 		{
8361 			if (!ReadCharFromFile(&ch))
8362 				return false;
8363 			if(!ReadKeyword(keyword, &parameter, &paramUsed, MAX_KEYWORD_LEN))
8364 			{
8365 				return false;
8366 			}
8367 			if(strcmp(reinterpret_cast<char*>(&keyword[0]),"levelnumbers") == 0)
8368 			{
8369 				szLevelNumbers = getCharsInsideBrace();
8370 			}
8371 			else if(strcmp(reinterpret_cast<char*>(&keyword[0]),"leveltext") == 0)
8372 			{
8373 				szLevelText = getCharsInsideBrace();
8374 			}
8375 			else
8376 			{
8377 				getCharsInsideBrace();
8378 			}
8379 		}
8380 		else if(ch == '}')  // Probabally finished here.
8381 		{
8382 			nesting--;
8383 		}
8384 		else
8385 		{
8386 			if(!ReadKeyword(keyword, &parameter, &paramUsed, MAX_KEYWORD_LEN))
8387 			{
8388 				return false;
8389 			}
8390 			if(strcmp(reinterpret_cast<char*>(&keyword[0]),"levelnfc") == 0) // RTF list Type
8391 			{
8392 				pLevel->m_RTFListType = static_cast<UT_uint32>(parameter);
8393 			}
8394 			else if(strcmp(reinterpret_cast<char*>(&keyword[0]),"levelnfcn") == 0)  // Not in my docs
8395 			{
8396 			}
8397 			else if(strcmp(reinterpret_cast<char*>(&keyword[0]),"leveljc") == 0) // Justification
8398 			{
8399 			}
8400 			else if(strcmp(reinterpret_cast<char*>(&keyword[0]),"leveljcn") == 0) // Not in my docs
8401 			{
8402 			}
8403 			else if(strcmp(reinterpret_cast<char*>(&keyword[0]),"levelfollow") == 0) // Tab following
8404 			{
8405 				switch (parameter)
8406 				{
8407 				case 0: // Tab
8408 					pLevel->m_cLevelFollow = '\t';
8409 					break;
8410 				case 1: // Space
8411 					pLevel->m_cLevelFollow = ' ';
8412 					break;
8413 				case 2: // Nothing
8414 					pLevel->m_cLevelFollow = '\0';
8415 					break;
8416 				default:
8417 					UT_ASSERT_NOT_REACHED();
8418 					break;
8419 				}
8420 			}
8421 			else if(strcmp(reinterpret_cast<char*>(&keyword[0]),"levelstartat") == 0)
8422 			{
8423 				pLevel->m_levelStartAt = static_cast<UT_uint32>(parameter);
8424 			}
8425 			else if(strcmp(reinterpret_cast<char*>(&keyword[0]),"levelspace") == 0) // ignore
8426 			{
8427 			}
8428 			else if(strcmp(reinterpret_cast<char*>(&keyword[0]),"levelindent") == 0) // ignore
8429 			{
8430 			}
8431 			else if(strcmp(reinterpret_cast<char*>(&keyword[0]), "levelnorestart") ==0)
8432 			{
8433 				pLevel->m_bRestart = (parameter == 1);
8434 			}
8435 //
8436 // OK parse againgst all the character and allowed paragraph properties.
8437 //
8438 			else
8439 			{
8440 				if(!ParseCharParaProps(static_cast<unsigned char *>(keyword), parameter, paramUsed,pChars,pParas,pbChars,pbParas))
8441 					return false;
8442 			}
8443 		}
8444 	}
8445 	if(pLevel->m_RTFListType != 23)
8446 	{
8447 		pLevel->ParseLevelText(szLevelText,szLevelNumbers, levelCount);
8448 	}
8449 	else
8450 	{
8451 		pLevel->m_listDelim = "%L";
8452 		if(strstr(szLevelText.c_str(),"u-3913") != 0)
8453 		{
8454 			pLevel->m_RTFListType = 23; // Bulleted List
8455 		}
8456 		if(strstr(szLevelText.c_str(),"u-3880") != 0)
8457 		{
8458 			pLevel->m_RTFListType = 23 + IMPLIES_LIST; // IMPLIES List
8459 		}
8460 	}
8461 	return true;
8462 }
8463 
8464 /*!
8465  * OK this method parses the RTF against all the character and
8466  * paragraph properties.
8467  * and fills the pointers to the character and paragraph classes.
8468  * These are used by the list table and stylesheet reader.
8469  */
ParseCharParaProps(unsigned char * pKeyword,UT_sint32 param,bool fParam,RTFProps_CharProps * pChars,RTFProps_ParaProps * pParas,RTFProps_bCharProps * pbChars,RTFProps_bParaProps * pbParas)8470 bool IE_Imp_RTF::ParseCharParaProps( unsigned char * pKeyword,
8471                                      UT_sint32 param, bool fParam,
8472                                      RTFProps_CharProps * pChars,
8473                                      RTFProps_ParaProps * pParas,
8474                                      RTFProps_bCharProps * pbChars,
8475                                      RTFProps_bParaProps * pbParas)
8476 {
8477 	if (strcmp(reinterpret_cast<char*>(pKeyword), "b") == 0) // bold
8478 	{
8479 		pbChars->bm_bold = true;
8480 		pChars->m_bold = fParam ? false : true;
8481 		return true;
8482 	}
8483 	else if (strcmp(reinterpret_cast<char*>(pKeyword), "cf") == 0) // color
8484 	{
8485 		pChars->m_hasColour = true;
8486 		pbChars->bm_hasColour = true;
8487 		pbChars->bm_colourNumber = true;
8488 		pChars->m_colourNumber = static_cast<UT_uint32>(param);
8489 		return true;
8490 	}
8491 	else if (strcmp(reinterpret_cast<char*>(pKeyword), "cb") == 0) // background color
8492 	{
8493 		pbChars->bm_bgcolourNumber = true;
8494 		return HandleU32CharacterProp(static_cast<UT_uint32>(param), &(pChars->m_bgcolourNumber));
8495 	}
8496 	else if (strcmp(reinterpret_cast<char*>(pKeyword), "deleted") == 0) // deleted
8497 	{
8498 		pbChars->bm_deleted = true;
8499 		return HandleBoolCharacterProp(fParam ? false : true, &(pChars->m_deleted));
8500 	}
8501 	else if (strcmp(reinterpret_cast<char *>(pKeyword),"dn") == 0) // subscript with position
8502 	{
8503 		// subscript with position. Default is 6.
8504 		// superscript: see up keyword
8505 		bool ok;
8506 		UT_uint32 pos = (UT_uint32) (fParam ? param : 6);
8507 		ok = HandleBoolCharacterProp((pos != 0) ? true : false, &(pChars->m_superscript));
8508 		if (ok)
8509 		{
8510 			pbChars->bm_superscript_pos = true;
8511 			ok = HandleFloatCharacterProp (pos*0.5, &(pChars->m_superscript_pos));
8512 		}
8513 		return ok;
8514 	}
8515 	else if (strcmp(reinterpret_cast<char*>(pKeyword), "fs") == 0)
8516 	{
8517 		pbChars->bm_fontSize = true;
8518 		return HandleFloatCharacterProp ((fParam ? param : 24)*0.5, &(pChars->m_fontSize));
8519 	}
8520 	else if (strcmp(reinterpret_cast<char*>(pKeyword), "f") == 0)
8521 	{
8522 		UT_uint32 fontNumber = (UT_uint32) (fParam ? param : 0);
8523 		RTFFontTableItem* pFont = GetNthTableFont(fontNumber);
8524 		if (pFont != NULL && pFont->m_szEncoding)
8525 			m_mbtowc.setInCharset(pFont->m_szEncoding);
8526 
8527 		pbChars->bm_fontNumber = true;
8528 		return HandleU32CharacterProp(fontNumber, &(pChars->m_fontNumber));
8529 	}
8530 	else if (strcmp(reinterpret_cast<char*>(pKeyword), "fi") == 0)
8531 	{
8532 		pParas->m_indentFirst = param;
8533 		pbParas->bm_indentFirst = true;
8534 		return true;
8535 	}
8536 	else if (strcmp(reinterpret_cast<char*>(pKeyword), "i") == 0)
8537 	{
8538 		// italic - either on or off depending on the parameter
8539 		pbChars->bm_italic = true;
8540 		return HandleBoolCharacterProp((fParam ? false : true), &(pChars->m_italic));
8541 	}
8542 	else if (strcmp(reinterpret_cast<char*>(pKeyword), "lang") == 0)
8543 	{
8544 		pChars->m_szLang = wvLIDToLangConverter(static_cast<unsigned short>(param));
8545 		return true;
8546 	}
8547 	else if (strcmp(reinterpret_cast<char*>(pKeyword), "li") == 0)
8548 	{
8549 		pbParas->bm_indentLeft = true;
8550 		pParas->m_indentLeft = param;
8551 	}
8552 	else if (strcmp(reinterpret_cast<char*>(pKeyword), "listtag") == 0)
8553 	{
8554 		pbChars->bm_listTag = true;
8555 		pChars->m_listTag = param;
8556 	}
8557 	else if (strcmp(reinterpret_cast<char*>(pKeyword),"ol") == 0)
8558 	{
8559 		pbChars->bm_overline = true;
8560 		return HandleBoolCharacterProp((fParam ? (param != 0) : true), &(pChars->m_overline));
8561 	}
8562 	else if (strcmp(reinterpret_cast<char*>(pKeyword), "ql") == 0)
8563 	{
8564 		pbParas->bm_justification = true;
8565 		pParas->m_justification = RTFProps_ParaProps::pjLeft;
8566 	}
8567 	else if (strcmp(reinterpret_cast<char*>(pKeyword), "qc") == 0)
8568 	{
8569 		pbParas->bm_justification = true;
8570 		pParas->m_justification = RTFProps_ParaProps::pjCentre;
8571 	}
8572 	else if (strcmp(reinterpret_cast<char*>(pKeyword), "qr") == 0)
8573 	{
8574 		pbParas->bm_justification = true;
8575 		pParas->m_justification = RTFProps_ParaProps::pjRight;
8576 	}
8577 	else if (strcmp(reinterpret_cast<char*>(pKeyword), "qj") == 0)
8578 	{
8579 		pbParas->bm_justification = true;
8580 		pParas->m_justification = RTFProps_ParaProps::pjFull;
8581 	}
8582 	else if (strcmp(reinterpret_cast<char*>(pKeyword), "ri") == 0)
8583 	{
8584 		pbParas->bm_indentRight = true;
8585 		pParas->m_indentRight = param;
8586 	}
8587 	else if (strcmp(reinterpret_cast<char*>(pKeyword), "strike") == 0  ||  strcmp(reinterpret_cast<char*>(pKeyword), "striked") == 0)
8588 	{
8589 		pbChars->bm_strikeout = true;
8590 		return HandleBoolCharacterProp((fParam ? (param != 0) : true), &(pChars->m_strikeout));
8591 	}
8592 	else if (strcmp(reinterpret_cast<char*>(pKeyword), "sa") == 0)
8593 	{
8594 		pbParas->bm_spaceAfter = true;
8595 		pParas->m_spaceAfter = param;
8596 	}
8597 	else if (strcmp(reinterpret_cast<char*>(pKeyword), "sb") == 0)
8598 	{
8599 		pbParas->bm_spaceBefore = true;
8600 		pParas->m_spaceBefore = param;
8601 	}
8602 	else if (strcmp(reinterpret_cast<char*>(pKeyword), "sl") == 0)
8603 	{
8604 		pbParas->bm_lineSpaceVal = true;
8605 		if (!fParam  ||  param == 0)
8606 		{
8607 			pParas->m_lineSpaceVal = 360;
8608 		}
8609 		else
8610 		{
8611 			pParas->m_lineSpaceVal = param;
8612 		}
8613 	}
8614 	else if (strcmp(reinterpret_cast<char*>(pKeyword), "slmult") == 0)
8615 	{
8616 		pbParas->bm_lineSpaceExact = true;
8617 		pParas->m_lineSpaceExact = (!fParam  ||  param == 0);   // this means exact or "at least" - which depends on sign of \sl param
8618 	}
8619 	else if (strcmp(reinterpret_cast<char*>(pKeyword), "super") == 0)
8620 	{
8621 		pbChars->bm_superscript = true;
8622 		return HandleBoolCharacterProp((fParam ? false : true), &(pChars->m_superscript));
8623 	}
8624 	else if (strcmp(reinterpret_cast<char*>(pKeyword), "sub") == 0)
8625 	{
8626 		pbChars->bm_subscript = true;
8627 		return HandleBoolCharacterProp((fParam ? false : true), &(pChars->m_subscript));
8628 	}
8629 	else if (strcmp(reinterpret_cast<char*>(pKeyword), "tx") == 0)
8630 	{
8631 		UT_return_val_if_fail(fParam, false);	// tabstops should have parameters
8632 		bool bres = AddTabstop(param,
8633 							   pParas->m_curTabType,
8634 							   pParas->m_curTabLeader,pParas);
8635 		pParas->m_curTabType = FL_TAB_LEFT;
8636 		pParas->m_curTabLeader = FL_LEADER_NONE;
8637 		pbParas->bm_curTabType = true;
8638 		pbParas->bm_curTabLeader = true;
8639 		return bres;
8640 	}
8641 	else if (strcmp(reinterpret_cast<char*>(pKeyword), "tb") == 0)
8642 	{
8643 		UT_return_val_if_fail(fParam, false);	// tabstops should have parameters
8644 
8645 		bool bres = AddTabstop(param,FL_TAB_BAR,
8646 							   pParas->m_curTabLeader,pParas);
8647 		pParas->m_curTabType = FL_TAB_LEFT;
8648 		pParas->m_curTabLeader = FL_LEADER_NONE;
8649 		pbParas->bm_curTabType = true;
8650 		pbParas->bm_curTabLeader = true;
8651 		return bres;
8652 	}
8653 	else if (strcmp(reinterpret_cast<char*>(pKeyword), "jclisttab") == 0)
8654 	{
8655 		UT_DEBUGMSG(("SEVIOR: jclisttab found ignore for now \n"));
8656 	}
8657 	else if (strcmp(reinterpret_cast<char*>(pKeyword), "tqr") == 0)
8658 	{
8659 		pbParas->bm_curTabType = true;
8660 		pParas->m_curTabType = FL_TAB_RIGHT;
8661 		return true;
8662 	}
8663 	else if (strcmp(reinterpret_cast<char*>(pKeyword), "tqc") == 0)
8664 	{
8665 		pbParas->bm_curTabType = true;
8666 		pParas->m_curTabType = FL_TAB_CENTER;
8667 		return true;
8668 	}
8669 	else if (strcmp(reinterpret_cast<char*>(pKeyword), "tqdec") == 0)
8670 	{
8671 		pbParas->bm_curTabType = true;
8672 		pParas->m_curTabType = FL_TAB_DECIMAL;
8673 		return true;
8674 	}
8675 	else if (strcmp(reinterpret_cast<char*>(pKeyword), "tldot") == 0)
8676 	{
8677 		pbParas->bm_curTabLeader = true;
8678 		pParas->m_curTabLeader = FL_LEADER_DOT;
8679 		return true;
8680 	}
8681 	else if (strcmp(reinterpret_cast<char*>(pKeyword), "tlhyph") == 0)
8682 	{
8683 		pbParas->bm_curTabLeader = true;
8684 		pParas->m_curTabLeader = FL_LEADER_HYPHEN;
8685 		return true;
8686 	}
8687 	else if (strcmp(reinterpret_cast<char*>(pKeyword), "tlul") == 0)
8688 	{
8689 		pbParas->bm_curTabLeader = true;
8690 		pParas->m_curTabLeader = FL_LEADER_UNDERLINE;
8691 		return true;
8692 	}
8693 	else if (strcmp(reinterpret_cast<char*>(pKeyword), "tleq") == 0)
8694 	{
8695 		pbParas->bm_curTabLeader = true;
8696 		pParas->m_curTabLeader = FL_LEADER_EQUALSIGN;
8697 		return true;
8698 	}
8699 	else if (strcmp(reinterpret_cast<char*>(pKeyword), "ul") == 0        ||  strcmp(reinterpret_cast<char*>(pKeyword), "uld") == 0  ||
8700 			 strcmp(reinterpret_cast<char*>(pKeyword), "uldash") == 0    ||  strcmp(reinterpret_cast<char*>(pKeyword), "uldashd") == 0  ||
8701 			 strcmp(reinterpret_cast<char*>(pKeyword), "uldashdd") == 0  ||  strcmp(reinterpret_cast<char*>(pKeyword), "uldb") == 0  ||
8702 			 strcmp(reinterpret_cast<char*>(pKeyword), "ulth") == 0      ||  strcmp(reinterpret_cast<char*>(pKeyword), "ulw") == 0  ||
8703 			 strcmp(reinterpret_cast<char*>(pKeyword), "ulwave") == 0)
8704 	{
8705 		pbChars->bm_underline = true;
8706 		return HandleBoolCharacterProp((fParam ? (param != 0) : true), &(pChars->m_underline));
8707 	}
8708 	else if (strcmp(reinterpret_cast<char*>(pKeyword), "ulnone") == 0)
8709 	{
8710 		pbChars->bm_underline = true;
8711 		return HandleBoolCharacterProp(false, &(pChars->m_underline));
8712 	}
8713 	else if (strcmp(reinterpret_cast<char *>(pKeyword),"up") == 0)
8714 	{
8715 		// superscript with position. Default is 6.
8716 		// subscript: see dn keyword
8717 		bool ok;
8718 		UT_uint32 pos = (UT_uint32) (fParam ? param : 6);
8719 		pbChars->bm_superscript = true;
8720 		pChars->m_superscript = (pos != 0) ? true : false ;
8721 		pbChars->bm_superscript_pos = true;
8722 		ok = HandleFloatCharacterProp (pos*0.5, &(pChars->m_superscript_pos));
8723 		return ok;
8724 	}
8725 	return true;
8726 }
8727 
8728 
8729 
8730 
ReadListOverrideTable(void)8731 bool IE_Imp_RTF::ReadListOverrideTable(void)
8732 {
8733 //
8734 // Ensure the list tables are empty to start.
8735 //
8736 	UT_std_vector_purgeall(m_vecWord97ListOverride);
8737 	unsigned char keyword[MAX_KEYWORD_LEN];
8738 	unsigned char ch;
8739 	UT_sint32 parameter = 0;
8740 	bool paramUsed = false;
8741 	UT_uint32 nesting = 1;
8742 	while (nesting >0) // Outer loop
8743 	{
8744 		if (!ReadCharFromFile(&ch))
8745 			return false;
8746 		if(ch == '{')  //new list or listoverride?
8747 		{
8748 			if (!ReadCharFromFile(&ch))
8749 				return false;
8750 
8751 			if(!ReadKeyword(keyword, &parameter, &paramUsed, MAX_KEYWORD_LEN))
8752 			{
8753 				return false;
8754 			}
8755 			if (strcmp(reinterpret_cast<char*>(&keyword[0]), "listoverride") == 0)
8756 			{
8757 				if(!HandleTableListOverride())
8758 				{
8759 					return false;
8760 				}
8761 			}
8762 		}
8763 		else if(ch == '}')
8764 		{
8765 			nesting--;
8766 		}
8767 	}
8768 	if (ch=='}') SkipBackChar(ch);
8769 	return true;
8770 }
8771 
8772 /*!
8773   Get list override of given id
8774   \param id Id of list override
8775   \return List override or NULL if not found
8776 
8777   The old code in ApplyParagraphAttributes would use the given
8778   id as an index to the vector of list overrides. But these
8779   can be given arbitrary ids from 1 to 2000, so the code
8780   would not always have worked. Also, and more relevant,
8781   this function handles an id of 0, as output by
8782   StarWriter/OpenOffice
8783   even though it is not allowed in the spec.
8784 */
8785 RTF_msword97_listOverride*
_getTableListOverride(UT_uint32 id)8786 IE_Imp_RTF::_getTableListOverride(UT_uint32 id)
8787 {
8788 	UT_uint32 i;
8789 	RTF_msword97_listOverride* pLOver;
8790 
8791 	for (i = 0; i < m_vecWord97ListOverride.size(); i++)
8792 	{
8793 		pLOver = m_vecWord97ListOverride.at(i);
8794 		if (id == pLOver->m_RTF_listID)
8795 		{
8796 			return pLOver;
8797 		}
8798 	}
8799 
8800 	// Client requested a list override that was not defined.
8801 	UT_ASSERT_NOT_REACHED();
8802 	return NULL;
8803 }
8804 
HandleTableListOverride(void)8805 bool IE_Imp_RTF::HandleTableListOverride(void)
8806 {
8807 	unsigned char keyword[MAX_KEYWORD_LEN];
8808 	unsigned char ch;
8809 	UT_sint32 parameter = 0;
8810 	bool paramUsed = false;
8811 //
8812 // OK define this in the data structure.
8813 //
8814 	RTF_msword97_listOverride * pLOver = new  RTF_msword97_listOverride(this);
8815 //
8816 // Increment override counting vector
8817 //
8818 	m_vecWord97ListOverride.push_back(pLOver);
8819     RTFProps_ParaProps * pParas =  new RTFProps_ParaProps();
8820 	RTFProps_CharProps *  pChars = new	RTFProps_CharProps();
8821     RTFProps_bParaProps * pbParas =  new RTFProps_bParaProps();
8822 	RTFProps_bCharProps *  pbChars = new	RTFProps_bCharProps();
8823 	pLOver->m_pParaProps = pParas;
8824 	pLOver->m_pCharProps = pChars;
8825 	pLOver->m_pbParaProps = pbParas;
8826 	pLOver->m_pbCharProps = pbChars;
8827 
8828 	UT_uint32 nesting = 1;
8829 	while (nesting >0) // Outer loop
8830 	{
8831 		if (!ReadCharFromFile(&ch))
8832 		{
8833 			return false;
8834 		}
8835 		if(ch == '}')
8836 		{
8837 			nesting--;
8838 		}
8839 		else if(ch == '{')
8840 		{
8841 			nesting++;
8842 		}
8843 		else if(ch == '\\')
8844 		{
8845 			if(!ReadKeyword(keyword, &parameter, &paramUsed, MAX_KEYWORD_LEN))
8846 			{
8847 				return false;
8848 			}
8849 			if(strcmp(reinterpret_cast<char*>(&keyword[0]),"listid") == 0)
8850 			{
8851 				pLOver->m_RTF_listID = static_cast<UT_uint32>(parameter);
8852 				if(!pLOver->setList())
8853 				{
8854 					return false;
8855 				}
8856 			}
8857 			else if(strcmp(reinterpret_cast<char*>(&keyword[0]),"listoverridecount")==0)
8858 			{
8859 				xxx_UT_DEBUGMSG(("SEVIOR: Found list listoverride count. Ignore for now\n"));
8860 			}
8861 			else if(strcmp(reinterpret_cast<char*>(&keyword[0]),"ls")== 0)
8862 			{
8863 				pLOver->m_RTF_listID = static_cast<UT_uint32>(parameter);
8864 			}
8865 		    else
8866 			{
8867 				ParseCharParaProps(reinterpret_cast<unsigned char *>(keyword), parameter,paramUsed,pChars,pParas,pbChars,pbParas);
8868 			}
8869 		}
8870 	}
8871 	return true;
8872 }
8873 
8874 /**
8875  * Reads back data that was written with IE_Exp_RTF::s_escapeXMLString()
8876  */
8877 std::string
s_unEscapeXMLString()8878 IE_Imp_RTF::s_unEscapeXMLString()
8879 {
8880 	std::stringstream ss;
8881 	unsigned char ch = 0;
8882 	// Since the star keyword group is between brackets, a new RTF state was generated. Remove it now.
8883 	// The closing bracket will be ignored.
8884 	PopRTFState();
8885 	while(ReadCharFromFile(&ch) && ch != '}')
8886 	{
8887 		ss << ch;
8888 	}
8889 
8890 	std::string s = ss.str();
8891 
8892 	// We want &7d;&7d; -> &7d;
8893 	// And         &7d; -> }
8894 	// as we know there are no occurances of }} in the string
8895 	// we use that as a temporary state to hold the case of two 7d in a row.
8896 	s = replace_all( s, "&7d;&7d;", "}}" );
8897 	s = replace_all( s, "&7d;", "}" );
8898 	s = replace_all( s, "}}", "&7d;" );
8899 
8900 	return s;
8901 }
8902 
8903 
8904 // rdf triples are an rdf/xml file
8905 // {\*\rdf RDF/XML}
ReadRDFTriples()8906 bool IE_Imp_RTF::ReadRDFTriples()
8907 {
8908 	std::string rdfxml = s_unEscapeXMLString();
8909 	PD_DocumentRDFHandle rdf = getDoc()->getDocumentRDF();
8910 	UT_DEBUGMSG(("rdf triples before read of rdf tag size:%ld\n", (long)rdf->size() ));
8911 
8912 	PD_DocumentRDFMutationHandle m = rdf->createMutation();
8913 	/*UT_Error e = */loadRDFXML( m, rdfxml );
8914 	m->commit();
8915 	UT_DEBUGMSG(("rdf triples after read of rdf tag size:%ld\n", (long)rdf->size() ));
8916 	return true;
8917 }
8918 
8919 
8920 // the revision table looks
8921 // \*\revtb{{Author1;}{Author2;} ... }
ReadRevisionTable()8922 bool IE_Imp_RTF::ReadRevisionTable()
8923 {
8924 	unsigned char ch = 0;
8925 	UT_UCS4String s;
8926 	UT_sint32 i = 1;
8927 
8928 	while(ReadCharFromFile(&ch) && ch != '}')
8929 	{
8930 		while(ch != '{' && ReadCharFromFile(&ch)){;}
8931 
8932 		if(ch != '{')
8933 			return false;
8934 
8935 		s.clear();
8936 
8937 		while(ReadCharFromFile(&ch) && ch != ';')
8938 		{
8939 			s += ch;
8940 		}
8941 		// the semicolon should be followed by a closing brace
8942 		ReadCharFromFile(&ch);
8943 		UT_return_val_if_fail(ch == '}', false);
8944 
8945 		// now add the revision to the document
8946 		// the rtf doc stores the time stamp for each individual rev. operation rather
8947 		// than for the revision set; we will set it when we encounter the first revision
8948 
8949 		// the first entry is typically author Unknown; we will ignore it
8950 		// hack around non stricmp
8951 		UT_UCS4Char u1[] = {'U','n','k','n','o','w','n',0};
8952 		UT_UCS4Char u2[] = {'u','n','k','n','o','w','n',0};
8953 
8954 		if(i == 1 && (!UT_UCS4_strcmp(s.ucs4_str(), u1) || !UT_UCS4_strcmp(s.ucs4_str(), u2)))
8955 			continue;
8956 
8957 		getDoc()->addRevision(i,s.ucs4_str(),s.length(),0,0);
8958 		++i;
8959 	}
8960 
8961 	UT_return_val_if_fail( ch == '}', false );
8962 	return true;
8963 }
8964 
8965 //////////////////////////////////////////////////////////////////////////////
8966 // Font table reader
8967 //////////////////////////////////////////////////////////////////////////////
8968 
8969 /*
8970  * Reads the RTF font table, storing it for future use
8971  *
8972  * This function is very tolerant. It can read entries such as:
8973  *
8974  * Eg:
8975  *     {\f18\fnil\fcharset134\fprq2{\*\panose 02010600030101010101}
8976  *     \'cb\'ce\'cc\'e5{\*\falt SimSun};}
8977  *
8978  * or even:
8979  *	   {\f20\froman Times New {\*\unknowncommand Fibble!}Roman;}
8980  *
8981  * It reads in alternative font names for Asian fonts (as specified
8982  * with the \falt keyword, panose numbers and supports \uXXXXX sequences
8983  * and \'XX hex escaping in the font names.
8984  *
8985  */
8986 
8987 /* The state used while reading the font table.
8988  * iFontNum is the index of the font name that we are currently writing.
8989  * Initially it's set to FontName. We switch it to point to AltFontName when we
8990  * see a \falt command. When the group containing the \falt ends we pop the
8991  * state of the stack and so this index reverts back to FontName.
8992  */
8993 struct SFontTableState {
8994 	enum DataType { MainFontName=0, AltFontName=1, Panose=2};
8995 	enum DataType iCurrentInputData;// Are we reading the main name, the alt name or panose?
8996 	UT_uint32 iUniSkipCount;        // How many characters should we skip after a /uXXXXX sequence?
8997 	UT_uint32 iUniCharsLeftToSkip;  // How many remaining skippable ANSI chars are there?
8998 	bool bSeenStar;                 // Have we seen a "\*" in this group?
8999 };
9000 
ReadFontTable()9001 bool IE_Imp_RTF::ReadFontTable()
9002 {
9003 	/* Declare variables for the information to be read from each entry */
9004 	RTFFontTableItem::FontFamilyEnum fontFamily = RTFFontTableItem::ffNone;
9005 	RTFFontTableItem::FontPitch pitch = RTFFontTableItem::fpDefault;
9006 	UT_uint16 fontIndex = 0;
9007 	int charSet = -1;                    // -1 indicates "none defined".
9008 	int codepage = 0;
9009 	UT_UTF8String sFontNamesAndPanose[3];// The font names and panose data in UTF-8.
9010 	UT_ByteBuf RawDataBuf[3];           // The Font names and panose data in orig. enc.
9011 	/* Variables needed to process the entry. */
9012 	bool bGotFontIndex = false;          // Did the entry specify a font index?
9013 	bool bSeenNonWhiteSpaceData = false; // Have we seen non-ws data in the current entry
9014 	bool bFoundFinalClosingBracket;      // Have we seen the bracket which closes the font table?
9015 	unsigned char keyword[MAX_KEYWORD_LEN];
9016 	RTFTokenType tokenType;
9017 	RTF_KEYWORD_ID keywordID;
9018 	UT_sint32 parameter = 0;
9019 	bool paramUsed = false;
9020 	UT_Byte ch;
9021 	UT_Stack stateStack;
9022 	// RTF state pointers.
9023 	struct SFontTableState *currentState = new SFontTableState;
9024 	UT_DEBUGMSG(("Made new currentState -1 %p \n",currentState));
9025 	struct SFontTableState *oldState = NULL;
9026 	UT_sint32 i;                         // Generic loop index.
9027 
9028 	// Initialise the current state.
9029 	currentState->iCurrentInputData = SFontTableState::MainFontName;
9030 	currentState->iUniSkipCount = m_currentRTFState.m_unicodeAlternateSkipCount;
9031 	currentState->iUniCharsLeftToSkip = 0;
9032 	currentState->bSeenStar = false;
9033 
9034 	bFoundFinalClosingBracket = false;
9035 	while (!bFoundFinalClosingBracket)
9036 	{
9037 		// NB: Ignores whitespace until we've seen non-whitespace data.
9038 		//     This means we pick up the spaces in font names like
9039 		//     "Times New Roman", but it also means that any font names
9040 		//     that genuinely start with spaces will have them discarded.
9041 		//     This is hopefully not a problem.
9042 		tokenType = NextToken(keyword, &parameter,& paramUsed,
9043 	 	                      MAX_KEYWORD_LEN, !bSeenNonWhiteSpaceData);
9044 		switch (tokenType)
9045 		{
9046 		case RTF_TOKEN_OPEN_BRACE:
9047 			// An open brace can prematurely terminate ANSI data after a \uXXXXX
9048 			// sequence. Thus, we reset iUniCharsLeftToSkip here.
9049 			currentState->iUniCharsLeftToSkip = 0;
9050 			// Keep a pointer to the current state.
9051 			oldState = currentState;
9052 			// Push the current state onto the stack...
9053 			stateStack.push(reinterpret_cast<void*>(currentState));
9054 			// ...allocate a new one...
9055 			currentState = new SFontTableState;
9056 			UT_DEBUGMSG(("Made new currentState -2 %p \n",currentState));
9057 			if (!currentState) {
9058 				UT_DEBUGMSG(("RTF: Out of memory.\n"));
9059 				goto IEImpRTF_ReadFontTable_ErrorExit;
9060 			}
9061 			// ...and initialise it as a copy of the old one.
9062 			currentState->iCurrentInputData = oldState->iCurrentInputData;
9063 			currentState->iUniSkipCount = oldState->iUniSkipCount;
9064 			currentState->iUniCharsLeftToSkip = oldState->iUniCharsLeftToSkip;
9065 			currentState->bSeenStar = oldState->bSeenStar;
9066 			break;
9067 		case RTF_TOKEN_CLOSE_BRACE:
9068 			// Throw away the current state.
9069 			UT_DEBUGMSG(("Deleting currentState -4 %p \n",currentState));
9070 			DELETEP(currentState);
9071 			// Pop an old state off the stack .
9072 			if (!stateStack.pop(reinterpret_cast<void**>(&currentState)))
9073 			{
9074 				// If there's no state on the stack then this must be the
9075 				// bracket that ends the font table.
9076 				bFoundFinalClosingBracket = true;
9077 				// Put the closing brace back onto the input stream.
9078 				SkipBackChar('}');
9079 				currentState = NULL;
9080 			}
9081 			break;
9082 		case RTF_TOKEN_DATA:
9083 			// Are we skipping ANSI data after a \uXXXXX?
9084 			if (currentState->iUniCharsLeftToSkip)
9085 			{
9086 				currentState->iUniCharsLeftToSkip--;
9087 				break;
9088 			}
9089 			// We found the font name terminator.
9090 			if (keyword[0] == ';')
9091 			{
9092 				// Check that at the very least we got a font index.
9093 				if (!bGotFontIndex) {
9094 					UT_DEBUGMSG(("RTF: Font table didn't specify a font index.\n"));
9095 					goto IEImpRTF_ReadFontTable_ErrorExit;
9096 				}
9097 				// Flush any data in the buffers to the font name and panose
9098 				// strings, converting to UTF8.
9099 				for (i=SFontTableState::MainFontName; i<=SFontTableState::Panose; i++)
9100 				{
9101 					sFontNamesAndPanose[i].appendBuf(RawDataBuf[i], m_mbtowc);
9102 					RawDataBuf[i].truncate(0);
9103 				}
9104 				// It's possible that the font name will be empty. This might happend
9105 				// because the font table didn't specify a name, or because the \ansicpgN
9106 				// command was invalid, in which case the mbtowc convertion might fail.
9107 				// In these cases, substitute "Times New Roman".
9108 				if (!sFontNamesAndPanose[SFontTableState::MainFontName].length())
9109 				{
9110 					UT_DEBUGMSG(("RTF: Font Index %d: Substituting \"Times New Roman\" for missing font name.\n", fontIndex));
9111 					sFontNamesAndPanose[SFontTableState::MainFontName] = "Times New Roman";
9112 				}
9113 				// Validate and post-process the Panose string.
9114 				if (!PostProcessAndValidatePanose(sFontNamesAndPanose[SFontTableState::Panose]))
9115 				{
9116 					// If the panose string was invalid, then clear it.
9117 					// I don't think it's worth refusing to load the file just because
9118 					// the panose string is wrong.
9119 					UT_DEBUGMSG(("RTF: Panose string for font with index %d invalid, ignoring.\n", fontIndex));
9120 					sFontNamesAndPanose[SFontTableState::Panose] = "";
9121 				}
9122 				// Register the font.
9123 				if (!RegisterFont(fontFamily, pitch, fontIndex, charSet,
9124 				                  codepage, sFontNamesAndPanose)         )
9125 				{
9126 					goto IEImpRTF_ReadFontTable_ErrorExit;
9127 				}
9128 				// Reset both font names/panose.
9129 				for (i=SFontTableState::MainFontName; i<=SFontTableState::Panose; i++)
9130 					sFontNamesAndPanose[i] = "";
9131 				bGotFontIndex = false;
9132 				bSeenNonWhiteSpaceData = false;
9133 			}
9134 			else
9135 			{
9136 				// Other data must be one of the font names, so write it to the
9137 				// current font name pointer.
9138 				RawDataBuf[currentState->iCurrentInputData].append(keyword, 1);
9139 				bSeenNonWhiteSpaceData = true;
9140 			}
9141 			break;
9142 		case RTF_TOKEN_KEYWORD:
9143 			keywordID = KeywordToID(reinterpret_cast<char *>(keyword));
9144 			// Are we skipping ANSI data after a \uXXXXX?
9145 			if (currentState->iUniCharsLeftToSkip)
9146 			{
9147 				currentState->iUniCharsLeftToSkip--;
9148 				break;
9149 			}
9150 
9151 			switch(keywordID)
9152 			{
9153 			// Handle all the face names.
9154 			case RTF_KW_fnil:
9155 				fontFamily = RTFFontTableItem::ffNone;
9156 				break;
9157 			case RTF_KW_froman:
9158 				fontFamily = RTFFontTableItem::ffRoman;
9159 				break;
9160 			case RTF_KW_fswiss:
9161 				fontFamily = RTFFontTableItem::ffSwiss;
9162 				break;
9163 			case RTF_KW_fmodern:
9164 				fontFamily = RTFFontTableItem::ffModern;
9165 				break;
9166 			case RTF_KW_fscript:
9167 				fontFamily = RTFFontTableItem::ffScript;
9168 				break;
9169 			case RTF_KW_fdecor:
9170 				fontFamily = RTFFontTableItem::ffDecorative;
9171 				break;
9172 			case RTF_KW_ftech:
9173 				fontFamily = RTFFontTableItem::ffTechnical;
9174 				break;
9175 			case RTF_KW_fbidi:
9176 				fontFamily = RTFFontTableItem::ffBiDirectional;
9177 				break;
9178 
9179 			// Handle hex escaped data.
9180 			case RTF_KW_QUOTE:
9181 				ch = static_cast<UT_Byte>(ReadHexChar());
9182 				RawDataBuf[currentState->iCurrentInputData].append(&ch, 1);
9183 				break;
9184 			// Handle the "*" keyword.
9185 			case RTF_KW_STAR:
9186 				currentState->bSeenStar = true;
9187 				break;
9188 			// Handle the "\f", font index, keyword.
9189 			case RTF_KW_f:
9190 				// If this is a duplicate font index then it is highly likely
9191 				// that the font table is corrupt. For example, a missing
9192 				// semi-colon causes this.
9193 				if (bGotFontIndex)
9194 				{
9195 					UT_DEBUGMSG(("RTF: Invalid duplicate font index in font table.\n"));
9196 					goto IEImpRTF_ReadFontTable_ErrorExit;
9197 				}
9198 				bGotFontIndex = true;
9199 				fontIndex = parameter;
9200 				break;
9201 			// Handle the "\fcharset", character set, keyword.
9202 			case RTF_KW_fcharset:
9203 				charSet = parameter;
9204 				break;
9205 			// Handle "\falt" keyword.
9206 			case RTF_KW_falt:
9207 				// Change the input data index so that data will be written to
9208 				// the alternative fontname.
9209 				currentState->iCurrentInputData = SFontTableState::AltFontName;
9210 				break;
9211 			// Handle panose numbers.
9212 			case RTF_KW_panose:
9213 				// Change the input data index so that data will be written to
9214 				// the panose string.
9215 				currentState->iCurrentInputData = SFontTableState::Panose;
9216 				break;
9217 			// Handle \uXXXXX escaped data.
9218 			case RTF_KW_u:
9219 			{
9220 				/* RTF is limited to +/-32K ints so we need to use negative
9221 				 * numbers for large unicode values. So, check for Unicode chars
9222 				 * wrapped to negative values.
9223 				 */
9224 				if (parameter < 0)
9225 				{
9226 					unsigned short tmp = (unsigned short) ((signed short) parameter);
9227 					parameter = (UT_sint32) tmp;
9228 				}
9229 				// First flush any data in the buffer to the font name
9230 				// string, converting to UTF8.
9231 				sFontNamesAndPanose[currentState->iCurrentInputData].appendBuf(RawDataBuf[currentState->iCurrentInputData], m_mbtowc);
9232 				RawDataBuf[currentState->iCurrentInputData].truncate(0);
9233 				// Then append the UCS2 char.
9234 				// TODO Since we process one character at a time, this code
9235 				// will not handle surrogate pairs.
9236 				sFontNamesAndPanose[currentState->iCurrentInputData].appendUCS2(reinterpret_cast<UT_UCS2Char *>(&parameter), 1);
9237 
9238 				// Set the reader to skip the appropriate number of ANSI
9239 				// characters after the \uXXXXX command.
9240 				currentState->iUniCharsLeftToSkip = currentState->iUniSkipCount;
9241 				break;  // Break out after handling keyword.
9242 			}
9243 			case RTF_KW_uc:
9244 				currentState->iUniSkipCount = parameter;
9245 				break;
9246 			// Handle unknown keywords.
9247 			default:
9248 				// If this group contained a \* command then we should skip to
9249 				// the end of this group. Otherwise, we just ignore this unknown
9250 				// command.
9251 				if (currentState->bSeenStar)
9252 				{
9253 					if (!SkipCurrentGroup(/*Consume last brace =*/false))
9254 						goto IEImpRTF_ReadFontTable_ErrorExit;
9255 				}
9256 				break;
9257 			} // Keyword switch
9258 			break; // End of tokenType == RTF_TOKEN_KEYWORD case statement.
9259 		case RTF_TOKEN_NONE:
9260 			UT_DEBUGMSG(("RTF: Premature end of file reading font table.\n"));
9261 			goto IEImpRTF_ReadFontTable_ErrorExit;
9262 		case RTF_TOKEN_ERROR:
9263 			UT_DEBUGMSG(("RTF: Error reading token from file.\n"));
9264 			goto IEImpRTF_ReadFontTable_ErrorExit;
9265 		default:
9266 			break;
9267 		} // Token type switch
9268 	}; // while (we've finished reading the font entry).
9269 	UT_DEBUGMSG(("Deleting currentState -2 %p \n",currentState));
9270 	DELETEP(currentState);
9271 	return true;
9272 
9273 /*
9274   Gotos are evil. However, so are memory leaks and code duplication. Exceptions
9275   might be a neater solution, but apparently they're not portable.
9276 */
9277 IEImpRTF_ReadFontTable_ErrorExit:
9278 	UT_DEBUGMSG(("RTF: ReadFontTable: Freeing memory due to error.\n"));
9279 	// Delete the current state and everything on the state stack.
9280 	UT_DEBUGMSG(("Deleting currentState -2 %p \n",currentState));
9281 	DELETEP(currentState);
9282 	while (stateStack.pop(reinterpret_cast<void**>(&currentState)))
9283 	{
9284 		UT_DEBUGMSG(("Deleting currentState -3  %p \n",currentState));
9285 		DELETEP(currentState);
9286 	}
9287 	return false;
9288 }
9289 
9290 
9291 /*
9292  * This function creates a new RTFFontTableItem and adds it to the document
9293  * font table.
9294  */
RegisterFont(RTFFontTableItem::FontFamilyEnum fontFamily,RTFFontTableItem::FontPitch pitch,UT_uint16 fontIndex,int charSet,int codepage,UT_UTF8String sFontNamesAndPanose[])9295 bool IE_Imp_RTF::RegisterFont(RTFFontTableItem::FontFamilyEnum fontFamily,
9296                               RTFFontTableItem::FontPitch pitch,
9297                               UT_uint16 fontIndex,
9298                               int charSet, int codepage,
9299                               UT_UTF8String sFontNamesAndPanose[]) {
9300 #ifndef TOOLKIT_COCOA
9301 	/*work around "helvetica" font name -replace it with "Helvetic"*/
9302 	if (sFontNamesAndPanose[SFontTableState::MainFontName] == "helvetica")
9303 	{
9304 		sFontNamesAndPanose[SFontTableState::MainFontName] = "Helvetic";
9305 	}
9306 #endif /* ! TOOLKIT_COCOA */
9307 
9308 
9309 	// Create the font entry and put it into the font table
9310 	// NB: If the font table didn't specify a font name then we want to pass
9311 	//     NULLs to RTFFontTableItem() rather than zero length strings.
9312 	RTFFontTableItem* pNewFont = new RTFFontTableItem(
9313 							fontFamily, charSet, codepage, pitch,
9314 							sFontNamesAndPanose[SFontTableState::Panose].length() ?
9315 							  sFontNamesAndPanose[SFontTableState::Panose].utf8_str() : NULL,
9316 							sFontNamesAndPanose[SFontTableState::MainFontName].length() ?
9317 							  sFontNamesAndPanose[SFontTableState::MainFontName].utf8_str() : NULL,
9318 							sFontNamesAndPanose[SFontTableState::AltFontName].length() ?
9319 							  sFontNamesAndPanose[SFontTableState::AltFontName].utf8_str() : NULL);
9320 	if (pNewFont == NULL)
9321 	{
9322 		return false;
9323 	}
9324 
9325 	// ensure that the font table is large enough for this index
9326 	while (m_fontTable.size() <= fontIndex)
9327 	{
9328 		m_fontTable.push_back(NULL);
9329 	}
9330 	RTFFontTableItem* pOld = NULL;
9331 	// some RTF files define the fonts several time. This is INVALID according to the
9332 	// specifications. So we ignore it.
9333 
9334 	// Ugly hack for MSVC and GCC comlilant warnings
9335 	#ifdef __GNUC__
9336 		#warning(maybe not the right behaviour)
9337 	#else
9338 		#pragma message("WARNING: maybe not the right behaviour" __FILE__)
9339 	#endif
9340 	if (m_fontTable[fontIndex] == NULL)
9341 	{
9342 		pOld = m_fontTable[fontIndex];
9343 		m_fontTable[fontIndex] = pNewFont;
9344 		UT_return_val_if_fail(pOld == NULL, false);
9345 	}
9346 	else
9347 	{
9348 		UT_DEBUGMSG (("RTF: font %d (named %s) already defined. Ignoring\n",
9349 		                 fontIndex,
9350 		                 sFontNamesAndPanose[SFontTableState::MainFontName].utf8_str()));
9351 		DELETEP (pNewFont);
9352 	}
9353 
9354 	return true;
9355 }
9356 
9357 /*
9358  * This function validates a panose string and does any pose-processing of
9359  * this string that might be necessary. It's called from ReadFontTable().
9360  *
9361  * Note: I don't know anything much about Panose numbers. The implementation
9362  * of ReadFontTable() that this commit replaces (July 2005) read in every other
9363  * byte of the 20 character Panose string to yield a final 10 byte string.
9364  * Therefore, this function does the same. In addition, it checks that all
9365  * characters in the string are digits (0-9) and nothing else.
9366  *
9367  * This function returns false on error.
9368  */
PostProcessAndValidatePanose(UT_UTF8String & Panose)9369 bool IE_Imp_RTF::PostProcessAndValidatePanose(UT_UTF8String &Panose)
9370 {
9371 	UT_UTF8Stringbuf::UTF8Iterator iter = Panose.getIterator ();
9372 	UT_UTF8String sProcessedPanose;
9373 	UT_sint32 i;
9374 
9375 	// If the panose string is not empty.
9376 	iter = iter.start(); // Set the iterator to the first character.
9377 	// There should be 20 characters
9378 	for (i=0; i<20; i++, ++iter)
9379 	{
9380 		const char * pUTF = iter.current ();
9381 		// If we run out of data then the panose string is too short.
9382 		if (!pUTF || !*pUTF)
9383 		{
9384 			// An empty string is valid, so return true if this is the
9385 			// first character.
9386 			if (i==0)
9387 				return true;
9388 			UT_DEBUGMSG(("RTF: Panose string too short.\n"));
9389 			return false;
9390 		}
9391 		// Only hex digits are allowed so we bail if we see anything
9392 		// else.
9393 		if (!isxdigit(*pUTF))
9394 		{
9395 			UT_DEBUGMSG(("RTF: Invalid character in panose string.\n"));
9396 			return false;
9397 		}
9398 		// Store alternate characters in the output string.
9399 		if ((i%2)==1)
9400 		{
9401 			// This wouldn't work for genuine UTF-8, since it's a variable
9402 			// byte encoding. However, we've already check that the string
9403 			// only contains the characters 0-9, so it's effectively ASCII.
9404 			sProcessedPanose += *pUTF;
9405 		}
9406 	}
9407 	// Replace the original panose string with the new one.
9408 	Panose = sProcessedPanose;
9409 	return true;
9410 }
9411 
9412 
9413 //////////////////////////////////////////////////////////////////////////////
9414 // Colour table reader
9415 //////////////////////////////////////////////////////////////////////////////
9416 
ReadColourTable()9417 bool IE_Imp_RTF::ReadColourTable()
9418 {
9419 	// Ensure the table is empty before we start
9420 	UT_return_val_if_fail(m_colourTable.empty(), false);
9421 
9422 	unsigned char keyword[MAX_KEYWORD_LEN];
9423 	unsigned char ch;
9424 	UT_sint32 parameter = 0;
9425 	bool paramUsed = false;
9426 	if (!ReadCharFromFile(&ch))
9427 		return false;
9428 	bool bValidColor = false;
9429 	while (ch != '}')
9430 	{
9431 		UT_uint32 colour = 0;
9432 		bool tableError = false;
9433 		while(ch == ' ')
9434 		{
9435 			if (!ReadCharFromFile(&ch))
9436 				return false;
9437 		}
9438 		bValidColor = false;
9439 		// Create a new entry for the colour table
9440  		if (ch == ';')
9441 		{
9442 			// Default colour required, black it is
9443 			colour = 0;
9444 		}
9445 		else if(ch != '}')
9446 		{
9447 			if (ch == '\\')
9448 			{
9449 				// read colour definition
9450 				long red = 0;
9451 				long green = 0;
9452 				long blue = 0;
9453 				bool hasRed, hasGreen, hasBlue;
9454 				hasRed = false;
9455 				hasGreen = false;
9456 				hasBlue = false;
9457 
9458 				for (int i = 0; i < 3; i++)
9459 				{
9460 					// read Red, Green and Blue values (will be in that order).
9461 					if (!ReadKeyword(keyword, &parameter, &paramUsed, MAX_KEYWORD_LEN))
9462 					{
9463 						UT_DEBUGMSG (("ReadKeyword() failed in ReadColourTable()\n"));
9464 						return false;
9465 					}
9466 					if (strcmp(reinterpret_cast<char*>(&keyword[0]), "red") == 0  &&  paramUsed)
9467 					{
9468 						if (!hasRed) {
9469 							red = parameter;
9470 							hasRed = true;
9471 						}
9472 						else {
9473 							tableError = true;
9474 						}
9475 					}
9476 					else if (strcmp(reinterpret_cast<char*>(&keyword[0]), "green") == 0  &&  paramUsed)
9477 					{
9478 						if (!hasGreen) {
9479 							green = parameter;
9480 							hasGreen = true;
9481 						}
9482 						else {
9483 							tableError = true;
9484 						}
9485 					}
9486 					else if (strcmp(reinterpret_cast<char*>(&keyword[0]), "blue") == 0  &&  paramUsed)
9487 					{
9488 						if (!hasBlue) {
9489 							blue = parameter;
9490 							hasBlue = true;
9491 						}
9492 						else {
9493 							tableError = true;
9494 						}
9495 					}
9496 					else
9497 					{
9498 						tableError = true;
9499 					}
9500 					// Read slash at start of next keyword
9501 					if (!ReadCharFromFile(&ch)
9502 							|| ((ch != '\\') && (ch != ';')))
9503 					{
9504 						tableError = true;
9505 					}
9506 				}
9507 				colour = static_cast<UT_uint32>(red << 16) | static_cast<UT_uint32>(green << 8) | static_cast<UT_uint32>(blue);
9508 				UT_DEBUGMSG(("colour %d red %ld green %ld blue %ld \n",colour,red,green,blue));
9509 				bValidColor = true;
9510 			}
9511 			else {
9512 				tableError = true;
9513 			}
9514 		}
9515 
9516 		if (tableError)
9517 		{
9518 			UT_DEBUGMSG (("RTF color Table error\n"));
9519 			return false;
9520 		}
9521 		else if(ch!= '}' || bValidColor)
9522 		{
9523 			UT_DEBUGMSG(("Add colour %d to table \n",colour));
9524 			m_colourTable.push_back(colour);
9525 
9526 			// Read in the next char
9527 			if (!ReadCharFromFile(&ch))
9528 				return false;
9529 		}
9530 	}
9531 
9532 	// Put the '}' back into the input stream
9533 	return SkipBackChar(ch);
9534 }
9535 
9536 
9537 
9538 
9539 //////////////////////////////////////////////////////////////////////////////
9540 // List properties
9541 //////////////////////////////////////////////////////////////////////////////
9542 
HandleLists(_rtfListTable & rtfTable)9543 bool IE_Imp_RTF::HandleLists(_rtfListTable & rtfTable )
9544 {
9545 	unsigned char keyword[MAX_KEYWORD_LEN];
9546 	unsigned char ch;
9547 	UT_sint32 parameter = 0;
9548 	bool paramUsed = false;
9549 	if (!ReadCharFromFile(&ch))
9550 		return false;
9551 
9552 	while (ch != '}') // Outer loop
9553 	{
9554 	  //SkipBackChar(ch); // Put char back in stream
9555 		if(ch == '{')  // pntxta or pntxtb
9556 		{
9557 			if (!ReadCharFromFile(&ch))
9558 				return false;
9559 			if(!ReadKeyword(keyword, &parameter, &paramUsed, MAX_KEYWORD_LEN))
9560 			{
9561 				return false;
9562 			}
9563 			else
9564 			{
9565 				/*
9566 				   dest indicate the destination
9567 				   0 = none (ignore)
9568 				   1 = after
9569 				   2 = before
9570 				   Any other value has no legal meaning.
9571 				*/
9572 				int dest = 0;
9573 				if (strcmp(reinterpret_cast<char*>(&keyword[0]), "pntxta") == 0) {
9574 					dest = 1;
9575 				}
9576 				else if (strcmp(reinterpret_cast<char*>(&keyword[0]), "pntxtb") == 0) {
9577 					dest = 2;
9578 				}
9579 				else {
9580 					UT_DEBUGMSG(("Unknown keyword %s found in List stream  \n",keyword));
9581 				}
9582 				if (dest != 0) {
9583 					// OK scan through the text until a closing delimeter is
9584 					// found
9585 					int level = 0;
9586 					int count = 0;
9587 					if (!ReadCharFromFile(&ch))
9588 						return false;
9589 					while ((level != 0 || (ch != '}' && ch != ';')) && count < MAX_KEYWORD_LEN - 1)
9590 					{
9591 						if (ch == '{') {
9592 							level++;
9593 						}
9594 						else if (ch == '}') {
9595 							UT_ASSERT_HARMLESS(level);
9596 							level--;
9597 						}
9598 						else {
9599 							keyword[count++] = ch;
9600 						}
9601 						if (!ReadCharFromFile(&ch))
9602 							return false;
9603 					}
9604 					keyword[count++] = 0;
9605 					switch (dest) {
9606 					case 1:
9607 						strncpy(rtfTable.textafter,reinterpret_cast<char*>(&keyword[0]), sizeof(rtfTable.textafter));
9608 						rtfTable.textafter[sizeof(rtfTable.textafter) - 1] = 0;
9609 						UT_DEBUGMSG(("FOUND pntxta in stream, copied %s to input  \n",keyword));
9610 						break;
9611 					case 2:
9612 						strncpy(rtfTable.textbefore,reinterpret_cast<char*>(&keyword[0]), sizeof(rtfTable.textbefore));
9613 						rtfTable.textbefore[sizeof(rtfTable.textbefore) - 1] = 0;
9614 						UT_DEBUGMSG(("FOUND pntxtb in stream,copied %s to input  \n",keyword));
9615 						break;
9616 					default:
9617 						UT_ASSERT_NOT_REACHED();
9618 					}
9619 				}
9620 			}
9621 			goto nextChar;
9622 		}
9623 		if(!ReadKeyword(keyword, &parameter, &paramUsed, MAX_KEYWORD_LEN))
9624 		{
9625 		        return false;
9626 		}
9627 		else
9628 		{
9629 			if (strcmp(reinterpret_cast<char*>(&keyword[0]), "m_levelStartAt") == 0)
9630 			{
9631 				rtfTable.start_value = static_cast<UT_uint32>(parameter);
9632 				UT_DEBUGMSG(("FOUND m_levelStartAt in stream \n"));
9633 			}
9634 			if (strcmp(reinterpret_cast<char*>(&keyword[0]), "pnstart") == 0)
9635 			{
9636 				rtfTable.start_value = static_cast<UT_uint32>(parameter);
9637 				UT_DEBUGMSG(("FOUND pnstart in stream \n"));
9638 			}
9639 			else if (strcmp(reinterpret_cast<char*>(&keyword[0]), "pnlvl") == 0)
9640 			{
9641 				rtfTable.level = static_cast<UT_uint32>(parameter);
9642 				UT_DEBUGMSG(("FOUND pnlvl in stream \n"));
9643 			}
9644 			else if (strcmp(reinterpret_cast<char*>(&keyword[0]), "pnlvlblt") == 0)
9645 			{
9646 				rtfTable.bullet = true;
9647 				UT_DEBUGMSG(("FOUND pnlvlblt in stream \n"));
9648 			}
9649 			else if (strcmp(reinterpret_cast<char*>(&keyword[0]), "pnlvlbody") == 0)
9650 			{
9651 				rtfTable.simple = true;
9652 				UT_DEBUGMSG(("FOUND pnlvlbody in stream \n"));
9653 			}
9654 			else if (strcmp(reinterpret_cast<char*>(&keyword[0]), "pnlvlcont") == 0)
9655 			{
9656 				rtfTable.continueList = true;
9657 				UT_DEBUGMSG(("FOUND pnlvlcont in stream \n"));
9658 			}
9659 			else if (strcmp(reinterpret_cast<char*>(&keyword[0]), "pnnumonce") == 0)
9660 			{
9661 				UT_DEBUGMSG(("FOUND pnnumonce in stream \n"));
9662 			}
9663 			else if (strcmp(reinterpret_cast<char*>(&keyword[0]), "pnacross") == 0)
9664 			{
9665 				UT_DEBUGMSG(("FOUND pnacross in stream \n"));
9666 			}
9667 			else if (strcmp(reinterpret_cast<char*>(&keyword[0]), "pnhang") == 0)
9668 			{
9669 				rtfTable.hangingIndent = true;
9670 				UT_DEBUGMSG(("FOUND pnhang in stream \n"));
9671 			}
9672 			else if (strcmp(reinterpret_cast<char*>(&keyword[0]), "pncard") == 0)
9673 			{
9674 				rtfTable.type = NUMBERED_LIST;
9675 				UT_DEBUGMSG(("FOUND pncard in stream \n"));
9676 			}
9677 			else if (strcmp(reinterpret_cast<char*>(&keyword[0]), "pndec") == 0)
9678 			{
9679 				rtfTable.type = NUMBERED_LIST;
9680 				UT_DEBUGMSG(("FOUND pndec in stream \n"));
9681 			}
9682 			else if (strcmp(reinterpret_cast<char*>(&keyword[0]), "pnucltr") == 0)
9683 			{
9684 				rtfTable.type = UPPERCASE_LIST;
9685 				UT_DEBUGMSG(("FOUND pnucltr in stream \n"));
9686 			}
9687 			else if (strcmp(reinterpret_cast<char*>(&keyword[0]), "pnuclrm") == 0)
9688 			{
9689 				rtfTable.type = UPPERROMAN_LIST;
9690 				UT_DEBUGMSG(("FOUND pnucrm in stream \n"));
9691 			}
9692 			else if (strcmp(reinterpret_cast<char*>(&keyword[0]), "pnlcltr") == 0)
9693 			{
9694 				rtfTable.type = LOWERCASE_LIST;
9695 				UT_DEBUGMSG(("FOUND pnlctr in stream \n"));
9696 			}
9697 			else if (strcmp(reinterpret_cast<char*>(&keyword[0]), "pnlclrm") == 0)
9698 			{
9699 				rtfTable.type = LOWERROMAN_LIST;
9700 				UT_DEBUGMSG(("FOUND pnlcrm in stream \n"));
9701 			}
9702 			else if (strcmp(reinterpret_cast<char*>(&keyword[0]), "pnord") == 0)
9703 			{
9704 				rtfTable.type = NUMBERED_LIST;
9705 				UT_DEBUGMSG(("FOUND pnord in stream \n"));
9706 			}
9707 			else if (strcmp(reinterpret_cast<char*>(&keyword[0]), "pnordt") == 0)
9708 			{
9709 				rtfTable.type = NUMBERED_LIST;
9710 				UT_DEBUGMSG(("FOUND pnordt in stream \n"));
9711 			}
9712 			else if (strcmp(reinterpret_cast<char*>(&keyword[0]), "pnb") == 0)
9713 			{
9714 				rtfTable.bold = true;
9715 				UT_DEBUGMSG(("FOUND pnb in stream \n"));
9716 			}
9717 			else if (strcmp(reinterpret_cast<char*>(&keyword[0]), "pni") == 0)
9718 			{
9719 				rtfTable.italic = true;
9720 				UT_DEBUGMSG(("FOUND pni in stream \n"));
9721 			}
9722 			else if (strcmp(reinterpret_cast<char*>(&keyword[0]), "pncaps") == 0)
9723 			{
9724 				rtfTable.caps = true;
9725 				UT_DEBUGMSG(("FOUND pncaps in stream \n"));
9726 			}
9727 			else if (strcmp(reinterpret_cast<char*>(&keyword[0]), "pnscaps") == 0)
9728 			{
9729 				rtfTable.scaps = true;
9730 				UT_DEBUGMSG(("FOUND pnscaps in stream \n"));
9731 			}
9732 			else if (strcmp(reinterpret_cast<char*>(&keyword[0]), "pnul") == 0)
9733 			{
9734 				rtfTable.underline = true;
9735 				UT_DEBUGMSG(("FOUND pnul in stream \n"));
9736 			}
9737 			else if (strcmp(reinterpret_cast<char*>(&keyword[0]), "pnuld") == 0)
9738 			{
9739 				rtfTable.underline = true;
9740 				UT_DEBUGMSG(("FOUND pnuld in stream \n"));
9741 			}
9742 			else if (strcmp(reinterpret_cast<char*>(&keyword[0]), "pnuldb") == 0)
9743 			{
9744 				rtfTable.underline = true;
9745 				UT_DEBUGMSG(("FOUND pnuldb in stream \n"));
9746 			}
9747 			else if (strcmp(reinterpret_cast<char*>(&keyword[0]), "pnulnone") == 0)
9748 			{
9749 				rtfTable.nounderline = true;
9750 				UT_DEBUGMSG(("FOUND pnulnone in stream \n"));
9751 			}
9752 			else if (strcmp(reinterpret_cast<char*>(&keyword[0]), "pnulw") == 0)
9753 			{
9754 				 UT_DEBUGMSG(("FOUND pnulw in stream - ignore for now \n"));
9755 			}
9756 			else if (strcmp(reinterpret_cast<char*>(&keyword[0]), "pnstrike") == 0)
9757 			{
9758 				rtfTable.strike = true;
9759 				UT_DEBUGMSG(("FOUND pnstrike in stream  \n"));
9760 			}
9761 			else if (strcmp(reinterpret_cast<char*>(&keyword[0]), "pncf") == 0)
9762 			{
9763 				rtfTable.forecolor =  static_cast<UT_uint32>(parameter);
9764 				UT_DEBUGMSG(("FOUND pncf in stream  \n"));
9765 			}
9766 			else if (strcmp(reinterpret_cast<char*>(&keyword[0]), "pnf") == 0)
9767 			{
9768 				rtfTable.font =  static_cast<UT_uint32>(parameter);
9769 				UT_DEBUGMSG(("FOUND pnf in stream  \n"));
9770 			}
9771 			else if (strcmp(reinterpret_cast<char*>(&keyword[0]), "pnfs") == 0)
9772 			{
9773 				rtfTable.fontsize =  static_cast<UT_uint32>(parameter);
9774 				UT_DEBUGMSG(("FOUND pnfs in stream  \n"));
9775 			}
9776 			else if (strcmp(reinterpret_cast<char*>(&keyword[0]), "pnindent") == 0)
9777 			{
9778 				rtfTable.indent =  static_cast<UT_uint32>(parameter);
9779 				UT_DEBUGMSG(("FOUND pnindent in stream  \n"));
9780 			}
9781 			else if (strcmp(reinterpret_cast<char*>(&keyword[0]), "pnsp") == 0)
9782 			{
9783 				UT_DEBUGMSG(("FOUND pnsp in stream  - ignored for now \n"));
9784 			}
9785 			else if (strcmp(reinterpret_cast<char*>(&keyword[0]), "pnprev") == 0)
9786 			{
9787 				rtfTable.prevlist =  true;
9788 				UT_DEBUGMSG(("FOUND pnprev in stream  \n"));
9789 			}
9790 			else if (strcmp(reinterpret_cast<char*>(&keyword[0]), "pnqc") == 0)
9791 			{
9792 				UT_DEBUGMSG(("FOUND pnqc in stream - ignored for now \n"));
9793 				// centered numbering
9794 			}
9795 			else if (strcmp(reinterpret_cast<char*>(&keyword[0]), "pnql") == 0)
9796 			{
9797 				UT_DEBUGMSG(("FOUND pnql in stream - ignored for now \n"));
9798 				// left justified numbering
9799 			}
9800 			else if (strcmp(reinterpret_cast<char*>(&keyword[0]), "pnqr") == 0)
9801 			{
9802 				UT_DEBUGMSG(("FOUND pnqr in stream - ignored for now \n"));
9803 				// right justified numbering
9804 			}
9805 			else if (strcmp(reinterpret_cast<char*>(&keyword[0]), "ls") == 0)
9806 			{
9807 				UT_DEBUGMSG(("FOUND ls in stream - override number %d\n",parameter));
9808 				rtfTable.iWord97Override =  static_cast<UT_uint32>(parameter);
9809 				// Word 97 list table identifier
9810 			}
9811 			else if (strcmp(reinterpret_cast<char*>(&keyword[0]), "ilvl") == 0)
9812 			{
9813 				UT_DEBUGMSG(("FOUND ilvl in stream - levelnumber %d\n",parameter));
9814 				rtfTable.iWord97Level = static_cast<UT_uint32>(_sanitizeListLevel(parameter));
9815 				// Word 97 list level
9816 			}
9817 			else if (strcmp(reinterpret_cast<char*>(&keyword[0]), "pnrnot") == 0)
9818 			{
9819 				UT_DEBUGMSG(("FOUND pnrnot in stream - ignored for now \n"));
9820 				// Don't know this
9821 			}
9822 			else
9823 			{
9824 				UT_DEBUGMSG(("Unknown keyword %s found in List stream  \n",keyword));
9825 			}
9826          nextChar:	if (!ReadCharFromFile(&ch))
9827 			         return false;
9828 		}
9829 	}
9830 	// Put the '}' back into the input stream
9831 	return SkipBackChar(ch);
9832 }
9833 
9834 /////////////////////////////////////////////////////////////////////////
9835 // Handle copy/paste of MathML by extending RTF
9836 /////////////////////////////////////////////////////////////////////////
HandleAbiMathml(void)9837 bool IE_Imp_RTF::HandleAbiMathml(void)
9838 {
9839 	std::string sProps;
9840 	unsigned char ch;
9841 	if (!ReadCharFromFile(&ch))
9842 		return false;
9843 	while(ch == ' ')
9844 	{
9845 		if (!ReadCharFromFile(&ch))
9846 			return false;
9847 	}
9848 	// Since the star keyword group is between brackets, a new RTF state was generated. Remove it now.
9849 	// The closing bracket will be ignored.
9850 	PopRTFState();
9851 	while (ch != '}') // Outer loop
9852 	{
9853 		sProps += ch;
9854 		if (!ReadCharFromFile(&ch))
9855 			return false;
9856 	}
9857 
9858 	std::string sPropName;
9859 	std::string sInputAbiProps;
9860 	const gchar * attrs[7] = {"dataid",NULL,NULL,NULL,NULL,NULL,NULL};
9861 	sPropName = "dataid";
9862 	std::string sDataIDVal = UT_std_string_getPropVal(sProps,sPropName);
9863 	attrs[1] = sDataIDVal.c_str();
9864 	UT_std_string_removeProperty(sProps,sPropName);
9865 	sPropName ="latexid";
9866 	std::string sLatexIDVal = UT_std_string_getPropVal(sProps,sPropName);
9867 	if(sLatexIDVal.size() > 0)
9868 	{
9869 		UT_std_string_removeProperty(sProps,sPropName);
9870 		attrs[2] = "latexid";
9871 		attrs[3] =  sLatexIDVal.c_str();
9872 		attrs[4]= "props";
9873 		attrs[5] = sProps.c_str();
9874 	}
9875 	else
9876 	{
9877 		attrs[2] = "props";
9878 		attrs[3] = sProps.c_str();
9879 	}
9880 	getDoc()->getUID(UT_UniqueId::Image); // Increment the image uid counter
9881 	//
9882 	// OK put in all the complex handling we need. Code taken from insert field
9883 	//
9884 	bool ok = FlushStoredChars(true);
9885 	UT_return_val_if_fail (ok, false);
9886 	if (!bUseInsertNotAppend() || m_bAppendAnyway)
9887 	{
9888 		UT_DEBUGMSG(("SEVIOR: Appending Math Object m_bCellBlank %d m_bEndTableOpen %d \n",m_bCellBlank,m_bEndTableOpen));
9889 		if(m_bCellBlank || m_bEndTableOpen)
9890 		{
9891 			UT_DEBUGMSG(("Append block 5 \n"));
9892 			if(m_pDelayedFrag)
9893 			{
9894 				getDoc()->insertStruxBeforeFrag(m_pDelayedFrag,PTX_Block,NULL);
9895 			}
9896 			else
9897 			{
9898 				getDoc()->appendStrux(PTX_Block,NULL);
9899 			}
9900 			m_bCellBlank = false;
9901 			m_bEndTableOpen = false;
9902 		}
9903 		if(m_pDelayedFrag)
9904 	    {
9905 			getDoc()->insertObjectBeforeFrag(m_pDelayedFrag,PTO_Math, attrs);
9906 		}
9907 		else
9908 		{
9909 			getDoc()->appendObject(PTO_Math, attrs);
9910 		}
9911 	}
9912 	else
9913 	{
9914 		XAP_Frame * pFrame = XAP_App::getApp()->getLastFocussedFrame();
9915 		if(pFrame == NULL)
9916 		{
9917 			 m_currentRTFState.m_destinationState = RTFStateStore::rdsSkip;
9918 			 return true;
9919 		}
9920 		FV_View * pView = static_cast<FV_View*>(pFrame->getCurrentView());
9921 		if(pView == NULL)
9922 		{
9923 			m_currentRTFState.m_destinationState = RTFStateStore::rdsSkip;
9924 			return true;
9925 		}
9926 		getDoc()->insertObject(m_dposPaste, PTO_Math, attrs, NULL);
9927 		m_dposPaste++;
9928 		if(m_posSavedDocPosition > 0)
9929 			m_posSavedDocPosition++;
9930 	}
9931 	return true;
9932 }
9933 
CreateDataItemfromStream(void)9934 bool IE_Imp_RTF::CreateDataItemfromStream(void)
9935 {
9936 	UT_UTF8String sName;
9937 	unsigned char ch;
9938 	if (!ReadCharFromFile(&ch))
9939 		return false;
9940 	//
9941 	// Skip leading spaces
9942 	//
9943 	while(ch == ' ')
9944 	{
9945 		if (!ReadCharFromFile(&ch))
9946 			return false;
9947 	}
9948 	while (ch != ' ') // extract name of name item
9949 	{
9950 		sName += ch;
9951 		if (!ReadCharFromFile(&ch))
9952 			return false;
9953 	}
9954 	//
9955 	// skip trailing spaces
9956 	//
9957 	while(ch == ' ')
9958 	{
9959 		if (!ReadCharFromFile(&ch))
9960 			return false;
9961 	}
9962 	//
9963 	// read the mime type if any
9964 	//
9965 	std::string mime;
9966 	if (ch == 'm')
9967 	{
9968 		while(ch != ' ' && ch != ':')
9969 		{
9970 			mime += ch;
9971 			if (!ReadCharFromFile(&ch))
9972 				return false;
9973 		}
9974 		if (mime != "mime-type")
9975 			return false;
9976 		if (!ReadCharFromFile(&ch))
9977 			return false;
9978 		mime = "";
9979 		while(ch != ' ')
9980 		{
9981 			mime += ch;
9982 			if (!ReadCharFromFile(&ch))
9983 				return false;
9984 		}
9985 		//
9986 		// skip trailing spaces
9987 		//
9988 		while(ch == ' ')
9989 		{
9990 			if (!ReadCharFromFile(&ch))
9991 				return false;
9992 		}
9993 	}
9994 	//
9995 	// We're at the start of the data item.
9996 	//
9997 
9998 	const UT_uint16 chars_per_byte = 2;
9999 	const UT_uint16 BITS_PER_BYTE = 8;
10000 	const UT_uint16 bits_per_char = BITS_PER_BYTE / chars_per_byte;
10001 	bool retval = true;
10002 	bool bFound = true;
10003 
10004 	UT_ByteBuf BinData;
10005 	UT_uint16 chLeft = chars_per_byte;
10006 	UT_Byte bin_byte = 0;
10007 	const UT_ByteBuf * pDum = NULL;
10008 	while (ch != '}')
10009 	{
10010 		int digit;
10011 		if (!hexVal(ch, digit))
10012 		{
10013 			return false;
10014 		}
10015 
10016 		bin_byte = (bin_byte << bits_per_char) + digit;
10017 
10018 		// if we have a complete byte, we put it in the buffer
10019 		if (--chLeft == 0)
10020 		{
10021 			BinData.append(&bin_byte, 1);
10022 			chLeft = chars_per_byte;
10023 			bin_byte = 0;
10024 		}
10025 
10026 		if (!ReadCharFromFile(&ch))
10027 		{
10028 			return false;
10029 		}
10030 	}
10031 	// Put the '}' back into the input stream
10032 	SkipBackChar(ch);
10033 
10034 	bFound = getDoc()->getDataItemDataByName(sName.utf8_str(),&pDum, NULL, NULL);
10035 	if(bFound)
10036 	{
10037 		return true;
10038 	}
10039 	//
10040 	// Now create the data item from the RTF data stream
10041 	//
10042 
10043 	retval = getDoc()->createDataItem(sName.utf8_str(),false,&BinData,mime,NULL);
10044 	return retval;
10045 
10046 }
10047 
10048 /////////////////////////////////////////////////////////////////////////
10049 // Handle copy/paste of Embedded Objects by extending RTF
10050 /////////////////////////////////////////////////////////////////////////
HandleAbiEmbed(void)10051 bool IE_Imp_RTF::HandleAbiEmbed(void)
10052 {
10053 	UT_UTF8String sProps;
10054 	unsigned char ch;
10055 	if (!ReadCharFromFile(&ch))
10056 		return false;
10057 	while(ch == ' ')
10058 	{
10059 		if (!ReadCharFromFile(&ch))
10060 			return false;
10061 	}
10062 	// Since the star keyword group is between brackets, a new RTF state was generated. Remove it now.
10063 	// The closing bracket will be ignored.
10064 	PopRTFState();
10065 	while (ch != '}') // Outer loop
10066 	{
10067 		sProps += ch;
10068 		if (!ReadCharFromFile(&ch))
10069 			return false;
10070 	}
10071 
10072 	UT_UTF8String sPropName;
10073 	UT_UTF8String sInputAbiProps;
10074 	const gchar * attrs[7] = {"dataid",NULL,NULL,NULL,NULL};
10075 	sPropName = "dataid";
10076 	UT_UTF8String sDataIDVal = UT_UTF8String_getPropVal(sProps,sPropName);
10077 	attrs[1] = sDataIDVal.utf8_str();
10078 	UT_UTF8String_removeProperty(sProps,sPropName);
10079 	attrs[2]= "props";
10080 	attrs[3] = sProps.utf8_str();
10081 	bool ok = FlushStoredChars(true);
10082 	UT_return_val_if_fail (ok, false);
10083 	if (!bUseInsertNotAppend() || m_bAppendAnyway)
10084 	{
10085 		UT_DEBUGMSG(("SEVIOR: Appending Embedded Object m_bCellBlank %d m_bEndTableOpen %d \n",m_bCellBlank,m_bEndTableOpen));
10086 		if(m_bCellBlank || m_bEndTableOpen)
10087 		{
10088 			UT_DEBUGMSG(("Append block 5 \n"));
10089 			if(m_pDelayedFrag)
10090 			{
10091 				getDoc()->insertStruxBeforeFrag(m_pDelayedFrag,PTX_Block,NULL);
10092 			}
10093 			else
10094 			{
10095 				getDoc()->appendStrux(PTX_Block,NULL);
10096 			}
10097 			m_bCellBlank = false;
10098 			m_bEndTableOpen = false;
10099 		}
10100 		if(m_pDelayedFrag)
10101 	    {
10102 			getDoc()->insertObjectBeforeFrag(m_pDelayedFrag,PTO_Embed, attrs);
10103 		}
10104 		else
10105 		{
10106 			getDoc()->appendObject(PTO_Embed, attrs);
10107 		}
10108 	}
10109 	else
10110 	{
10111 		XAP_Frame * pFrame = XAP_App::getApp()->getLastFocussedFrame();
10112 		if(pFrame == NULL)
10113 		{
10114 			 m_currentRTFState.m_destinationState = RTFStateStore::rdsSkip;
10115 			 return true;
10116 		}
10117 		FV_View * pView = static_cast<FV_View*>(pFrame->getCurrentView());
10118 		if(pView == NULL)
10119 		{
10120 			m_currentRTFState.m_destinationState = RTFStateStore::rdsSkip;
10121 			return true;
10122 		}
10123 		getDoc()->insertObject(m_dposPaste, PTO_Embed, attrs, NULL);
10124 		m_dposPaste++;
10125 		if(m_posSavedDocPosition > 0)
10126 			m_posSavedDocPosition++;
10127 	}
10128 
10129 	return true;
10130 }
10131 
10132 ///////////////////////////////////////////////////////////////////////////
10133 // Handle copy and paste of tables by extending RTF. These handlers do that
10134 ///////////////////////////////////////////////////////////////////////////
10135 
HandleAbiTable(void)10136 bool IE_Imp_RTF::HandleAbiTable(void)
10137 {
10138 	std::string sProps;
10139 	unsigned char ch;
10140 	if (!ReadCharFromFile(&ch))
10141 		return false;
10142 	while(ch == ' ')
10143 	{
10144 		if (!ReadCharFromFile(&ch))
10145 			return false;
10146 	}
10147 	// Since the star keyword group is between brackets, a new RTF state was generated. Remove it now.
10148 	// The closing bracket will be ignored.
10149 	PopRTFState();
10150 	while (ch != '}') // Outer loop
10151 	{
10152 		sProps += ch;
10153 		if (!ReadCharFromFile(&ch))
10154 			return false;
10155 	}
10156 
10157 	ABI_Paste_Table * pPaste = new ABI_Paste_Table();
10158 	m_pasteTableStack.push(pPaste);
10159 	pPaste->m_bHasPastedTableStrux = false;
10160 	pPaste->m_iRowNumberAtPaste = 0;
10161 
10162 	UT_DEBUGMSG(("RTF_Import: Paste: Tables props are: %s \n",sProps.c_str()));
10163 	bool bIsPasteIntoSame = false;
10164 	pf_Frag_Strux* sdhTable = NULL;
10165 	pf_Frag_Strux* sdhEndTable = NULL;
10166 	bool bFound = getDoc()->getStruxOfTypeFromPosition(m_dposPaste,PTX_SectionTable,&sdhTable);
10167 	PT_DocPosition posTable = 0;
10168 	XAP_Frame * pFrame = XAP_App::getApp()->getLastFocussedFrame();
10169 	if(pFrame == NULL)
10170 	{
10171 		return false;
10172 	}
10173 	FV_View * pView = static_cast<FV_View*>(pFrame->getCurrentView());
10174 	if(pView == NULL)
10175 	{
10176 		return false;
10177 	}
10178 	if(bFound)
10179 	{
10180 		posTable = getDoc()->getStruxPosition(sdhTable);
10181 		sdhEndTable = getDoc()->getEndTableStruxFromTableSDH(sdhTable);
10182 		if(sdhEndTable != NULL)
10183 		{
10184 			PT_DocPosition posEndTable = getDoc()->getStruxPosition(sdhEndTable);
10185 			if(posEndTable > m_dposPaste)
10186 			{
10187 				std::string sPasteTableSDH;
10188 				std::string sProp = "table-sdh";
10189 				sPasteTableSDH = UT_std_string_getPropVal(sProps,sProp);
10190 				std::string sThisTableSDH = UT_std_string_sprintf("%p",sdhTable);
10191 				UT_DEBUGMSG(("sThisTableSDH %s sPasteTableSDH %s \n",sThisTableSDH.c_str(),sPasteTableSDH.c_str()));
10192 				bool isRow = (pView->getSelectionMode() == FV_SelectionMode_TableRow);
10193 				if(!isRow && pView->getSelectionMode() == FV_SelectionMode_NONE)
10194 				{
10195 					isRow = (pView->getPrevSelectionMode() == FV_SelectionMode_TableRow);
10196 				}
10197 				if((sThisTableSDH == sPasteTableSDH) && isRow)
10198 				{
10199 					UT_DEBUGMSG(("Paste Whole Row into same Table!!!!! \n"));
10200 					bIsPasteIntoSame = true;
10201 					pPaste->m_bPasteAfterRow = true;
10202 					pf_Frag_Strux* sdhCell = NULL;
10203 					bool b = getDoc()->getStruxOfTypeFromPosition(m_dposPaste,PTX_SectionCell,&sdhCell);
10204 					UT_return_val_if_fail(b,false);
10205 					const char * szTop = NULL;
10206 					getDoc()->getPropertyFromSDH(sdhCell,
10207 												 true,
10208 												 PD_MAX_REVISION,
10209 												 "top-attach",&szTop);
10210 					UT_return_val_if_fail(szTop,false);
10211 					UT_sint32 iOldTop = atoi(szTop);
10212 					PT_DocPosition posCell = getDoc()->getStruxPosition(sdhCell);
10213 					b = true;
10214 					bool atEnd = false;
10215 					while(b)
10216 					{
10217 						b = getDoc()->getNextStruxOfType(sdhCell,PTX_SectionCell,&sdhCell);
10218 						if(b && sdhCell)
10219 						{
10220 							posCell = getDoc()->getStruxPosition(sdhCell);
10221 						}
10222 						if(!b || (posCell > posEndTable))
10223 						{
10224 							atEnd = true;
10225 							b = false;
10226 						}
10227 						else if(b)
10228 						{
10229 							getDoc()->getPropertyFromSDH(sdhCell,
10230 														 true,
10231 														 PD_MAX_REVISION,
10232 														 "top-attach",&szTop);
10233 							UT_return_val_if_fail(szTop,false);
10234 							UT_sint32 iNewTop = atoi(szTop);
10235 							b = (iNewTop == iOldTop);
10236 						}
10237 					}
10238 					pPaste->m_iRowNumberAtPaste = iOldTop;
10239 					if(atEnd)
10240 					{
10241 //
10242 // At end of Table. Position just after last encCell strux
10243 //
10244 						m_dposPaste = posEndTable;
10245 					}
10246 					else
10247 					{
10248 //
10249 // Position just before the first cell of the next row.
10250 //
10251 						m_dposPaste = getDoc()->getStruxPosition(sdhCell);
10252 					}
10253 //
10254 // Now a change strux on the table to make it rebuild.
10255 //
10256 					const char * sDumProp[3] = {NULL,NULL,NULL};
10257 					sDumProp[0] = "list-tag";
10258 					std::string sVal = UT_std_string_sprintf("%d",getDoc()->getUID(UT_UniqueId::List));
10259 					sDumProp[1] = sVal.c_str();
10260 					sDumProp[2] = NULL;
10261 					getDoc()->changeStruxFmt(PTC_AddFmt,posTable+1,posTable+1,NULL,sDumProp,PTX_SectionTable);
10262 
10263 				}
10264 			}
10265 		}
10266 	}
10267 
10268 //
10269 // Remove the table-sdh property
10270 //
10271 	std::string sProp = "table-sdh";
10272 	UT_std_string_removeProperty(sProps,sProp);
10273 	const gchar * attrs[3] = {"props",NULL,NULL};
10274 	if(! bIsPasteIntoSame)
10275 	{
10276 		attrs[1] = sProps.c_str();
10277 //
10278 // insert a block to terminate the text before this if needed,
10279 //
10280 		if(getDoc()->isBlockAtPos(m_dposPaste) || getDoc()->isTableAtPos(m_dposPaste) || getDoc()->isEndFrameAtPos(m_dposPaste) ||getDoc()->isFrameAtPos(m_dposPaste) || getDoc()->isHdrFtrAtPos(m_dposPaste) || getDoc()->isCellAtPos(m_dposPaste))
10281 		{
10282 			FlushStoredChars(false);
10283 		}
10284 		else
10285 		{
10286 			m_newParaFlagged = true;
10287 			FlushStoredChars(true);
10288 			m_dposPaste--;
10289 			if(m_posSavedDocPosition > 0)
10290 				m_posSavedDocPosition--;
10291 		}
10292 //
10293 // Insert the table strux at the same spot. This will make the table link correctly in the
10294 // middle of the broken text.
10295 		pPaste->m_bHasPastedTableStrux = true;
10296 		insertStrux(PTX_SectionTable,attrs,NULL);
10297 	}
10298 	return true;
10299 }
10300 
HandleAbiEndTable(void)10301 bool IE_Imp_RTF:: HandleAbiEndTable(void)
10302 {
10303 	ABI_Paste_Table * pPaste = NULL;
10304 	m_pasteTableStack.viewTop((void**)(&pPaste));
10305 	if(pPaste == NULL)
10306 	{
10307 		return false;
10308 	}
10309 	if(pPaste->m_bPasteAfterRow)
10310 	{
10311 		UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
10312 		UT_sint32 numRows = pPaste->m_iCurTopCell -pPaste->m_iRowNumberAtPaste;
10313 		pf_Frag_Strux* sdhCell = NULL;
10314 		pf_Frag_Strux* sdhTable = NULL;
10315 		pf_Frag_Strux* sdhEndTable = NULL;
10316 		bool b = getDoc()->getStruxOfTypeFromPosition(m_dposPaste,PTX_SectionTable,&sdhTable);
10317 		UT_return_val_if_fail(b,false);
10318 		sdhEndTable = getDoc()->getEndTableStruxFromTableSDH(sdhTable);
10319 		UT_return_val_if_fail(sdhEndTable,false);
10320 		PT_DocPosition posEndTable = getDoc()->getStruxPosition(sdhEndTable);
10321 		b = getDoc()->getStruxOfTypeFromPosition(m_dposPaste,PTX_SectionCell,&sdhCell);
10322 		b = getDoc()->getNextStruxOfType(sdhCell,PTX_SectionCell,&sdhCell);
10323 		std::string sTop;
10324 		std::string sBot;
10325 		const char * szVal = NULL;
10326 		const gchar * sProps[5] = {NULL,NULL,NULL,NULL};
10327 		PT_DocPosition posCell = getDoc()->getStruxPosition(sdhCell);
10328 		while(b && (posCell < posEndTable))
10329 		{
10330 			getDoc()->getPropertyFromSDH(sdhCell,
10331 										 true,
10332 										 PD_MAX_REVISION,
10333 										 "top-attach", &szVal);
10334 			UT_return_val_if_fail(szVal,false);
10335 			UT_sint32 iTop = atoi(szVal);
10336 			iTop += numRows;
10337 			sTop = UT_std_string_sprintf("%d",iTop);
10338 			getDoc()->getPropertyFromSDH(sdhCell,
10339 										 true,
10340 										 PD_MAX_REVISION,
10341 										 "bot-attach", &szVal);
10342 			UT_return_val_if_fail(szVal,false);
10343 			UT_sint32 iBot = atoi(szVal);
10344 			iBot += numRows;
10345 			sTop = UT_std_string_sprintf("%d",iBot);
10346 			sProps[0] = "top-attach";
10347 			sProps[1] = sTop.c_str();
10348 			sProps[2] = "bot-attach";
10349 			sProps[3] = sBot.c_str();
10350 			getDoc()->changeStruxFmt(PTC_AddFmt,posCell+1,posCell+1,NULL,sProps,PTX_SectionCell);
10351 			b = getDoc()->getNextStruxOfType(sdhCell,PTX_SectionCell,&sdhCell);
10352 			if(b)
10353 			{
10354 				posCell = getDoc()->getStruxPosition(sdhCell);
10355 			}
10356 		}
10357 		return true;
10358 	}
10359 
10360 	insertStrux(PTX_EndTable);
10361 	m_pasteTableStack.pop((void**)(&pPaste));
10362 	delete pPaste;
10363 	return true;
10364 }
10365 
10366 /*!
10367  * If there is an open paste cell mark that the a block has been pasted.
10368  */
markPasteBlock(void)10369 bool IE_Imp_RTF::markPasteBlock(void)
10370 {
10371 	if(!bUseInsertNotAppend())
10372 	{
10373 		return false;
10374 	}
10375 	ABI_Paste_Table * pPaste = NULL;
10376 	m_pasteTableStack.viewTop((void**)(&pPaste));
10377 	if(pPaste == NULL)
10378 	{
10379 		return false;
10380 	}
10381 	if(!pPaste->m_bHasPastedBlockStrux)
10382 	{
10383 		pPaste->m_bHasPastedBlockStrux = true;
10384 		return true;
10385 	}
10386 	return false;
10387 }
10388 
isBlockNeededForPasteTable(void)10389 bool IE_Imp_RTF::isBlockNeededForPasteTable(void)
10390 {
10391 	ABI_Paste_Table * pPaste = NULL;
10392 	if(m_pasteTableStack.getDepth() == 0)
10393 	{
10394 		return false;
10395 	}
10396 	m_pasteTableStack.viewTop((void**)(&pPaste));
10397 	if(pPaste == NULL)
10398 	{
10399 		return false;
10400 	}
10401 	if(!pPaste->m_bHasPastedBlockStrux)
10402 	{
10403 		return true;
10404 	}
10405 	return false;
10406 }
10407 
HandleAbiEndCell(void)10408 bool IE_Imp_RTF::HandleAbiEndCell(void)
10409 {
10410 	ABI_Paste_Table * pPaste = NULL;
10411 	m_pasteTableStack.viewTop((void**)(&pPaste));
10412 	if(pPaste == NULL)
10413 	{
10414 		return false;
10415 	}
10416 	if(!pPaste->m_bHasPastedBlockStrux)
10417 	{
10418 		UT_DEBUGMSG(("Insert Block  -4 \n"));
10419 	    insertStrux(PTX_Block);
10420 	}
10421 	UT_DEBUGMSG(("Insert EndCell -1!!!!!!!!!!!!!! \n"));
10422 	insertStrux(PTX_EndCell);
10423 	pPaste->m_bHasPastedCellStrux = false;
10424 	pPaste->m_bHasPastedBlockStrux = false;
10425 	return true;
10426 }
10427 
HandleAbiCell(void)10428 bool IE_Imp_RTF::HandleAbiCell(void)
10429 {
10430 	std::string sProps;
10431 	unsigned char ch;
10432 	if (!ReadCharFromFile(&ch))
10433 		return false;
10434 	while(ch == ' ')
10435 	{
10436 		if (!ReadCharFromFile(&ch))
10437 			return false;
10438 	}
10439 	// Since the star keyword group is between brackets, a new RTF state was generated. Remove it now.
10440 	// The closing bracket will be ignored.
10441 	PopRTFState();
10442 	while (ch != '}') // Outer loop
10443 	{
10444 		sProps += ch;
10445 		if (!ReadCharFromFile(&ch))
10446 			return false;
10447 	}
10448 
10449 	ABI_Paste_Table * pPaste = NULL;
10450 	m_pasteTableStack.viewTop((void**)(&pPaste));
10451 	if(pPaste == NULL)
10452 	{
10453 		return false;
10454 	}
10455 	std::string sDum = "top-attach";
10456 	std::string sTop = UT_std_string_getPropVal(sProps,sDum);
10457 	pPaste->m_iCurTopCell = atoi(sTop.c_str());
10458 	UT_sint32 iAdditional = 0;
10459 	//
10460 	// Look for the next row of the table
10461 	//
10462 	iAdditional = pPaste->m_iCurTopCell - pPaste->m_iPrevPasteTop;
10463 	pPaste->m_iPrevPasteTop = pPaste->m_iCurTopCell;
10464 	pPaste->m_iRowNumberAtPaste += iAdditional;
10465 	pPaste->m_iNumRows += iAdditional;
10466 	sDum = "right-attach";
10467 	std::string sRight = UT_std_string_getPropVal(sProps,sDum);
10468 	pPaste->m_iCurRightCell = atoi(sRight.c_str());
10469 	if(pPaste->m_iCurRightCell > pPaste->m_iMaxRightCell)
10470 	{
10471 		pPaste->m_iMaxRightCell = pPaste->m_iCurRightCell;
10472 	}
10473 	pPaste->m_bHasPastedCellStrux = true;
10474 	pPaste->m_bHasPastedBlockStrux = false;
10475 	UT_sint32 iMyTop = pPaste->m_iCurTopCell;
10476 	sDum = "bot-attach";
10477 	std::string sBot =  UT_std_string_getPropVal(sProps,sDum);
10478 	UT_sint32 iMyBot = atoi(sBot.c_str());
10479 	if(pPaste->m_bPasteAfterRow)
10480 	{
10481 		UT_sint32 idiff = pPaste->m_iRowNumberAtPaste - iMyTop +1;
10482 		iMyTop += idiff;
10483 		sTop = UT_std_string_sprintf("%d",iMyTop);
10484 		iMyBot += idiff;
10485 		sBot = UT_std_string_sprintf("%d",iMyBot);
10486 		std::string sTopProp = "top-attach";
10487 		std::string sBotProp = "bot-attach";
10488 		UT_std_string_setProperty(sProps,sTopProp,sTop);
10489 		UT_std_string_setProperty(sProps,sBotProp,sBot);
10490 		pPaste->m_iCurTopCell = iMyTop;
10491 	}
10492 	UT_DEBUGMSG(("RTF_Import: Pos %d Paste: Cell props are: %s \n",m_dposPaste,sProps.c_str()));
10493 	const gchar * attrs[3] = {"props",NULL,NULL};
10494 	attrs[1] = sProps.c_str();
10495  	insertStrux(PTX_SectionCell,attrs,NULL);
10496 	m_newParaFlagged = true;
10497 	m_bSectionHasPara = true;
10498 
10499 	return true;
10500 }
10501 
10502 /*!
10503  * Handle context senstive inserts. Like inserting a table into a block
10504  * Requires an extra block insert
10505  * Insert into a hyperlink means the m_dposPate is additionally incremented
10506  * to handle the extra end hyperlink run.
10507  */
insertStrux(PTStruxType pts,const gchar ** attrs,const gchar ** props)10508 bool IE_Imp_RTF::insertStrux(PTStruxType pts , const gchar ** attrs, const gchar ** props)
10509 {
10510 	bool bInHyperlink = false;
10511 	bool bDoExtraBlock = false;
10512 	bool res = false;
10513 	XAP_Frame * pFrame = XAP_App::getApp()->getLastFocussedFrame();
10514 	if(pFrame == NULL)
10515 	{
10516 		m_currentRTFState.m_destinationState = RTFStateStore::rdsSkip;
10517 		return true;
10518 	}
10519 	FV_View * pView = static_cast<FV_View*>(pFrame->getCurrentView());
10520 	PT_DocPosition posEOD = 0;
10521 	pView->getEditableBounds(true,posEOD);
10522 	if(pView == NULL)
10523 	{
10524 		m_currentRTFState.m_destinationState = RTFStateStore::rdsSkip;
10525 		return true;
10526 	}
10527 	if(!m_bStruxInserted)
10528 	{
10529 		fp_Run *pHyperRun = pView->getHyperLinkRun(m_dposPaste);
10530 		if((pHyperRun != NULL) ||(m_iHyperlinkOpen > 0) )
10531 		{
10532 			fp_HyperlinkRun * pRHyper = static_cast<fp_HyperlinkRun *>(pHyperRun);
10533 			if(pRHyper->getHyperlinkType() == HYPERLINK_NORMAL)
10534 				bInHyperlink = true;
10535 		}
10536 		fl_BlockLayout * pBL = pView->getBlockAtPosition(m_dposPaste);
10537 		if(pBL->getPosition() < m_dposPaste)
10538 		{
10539 			bDoExtraBlock = true;
10540 		}
10541 	}
10542 	bool isInHdrFtr = pView->isInHdrFtr(m_dposPaste);
10543 	if(isInHdrFtr)
10544 	{
10545 		if((pts != PTX_Block) &&  (pts != PTX_SectionTable) && (pts != PTX_SectionCell) && (pts != PTX_EndTable) &&(pts != PTX_EndCell))
10546 		{
10547 			m_currentRTFState.m_destinationState = RTFStateStore::rdsSkip;
10548 			return true;
10549 		}
10550 		//
10551 		// No nested tables in header/footers
10552 		//
10553 		if(pView->isInTable(m_dposPaste))
10554 		{
10555 			fl_TableLayout * pTL =pView->getTableAtPos(m_dposPaste);
10556 			if(pTL && pTL->isEndTableIn() && ((pts == PTX_SectionTable)|| (pts == PTX_SectionCell) || (pts == PTX_EndTable) || (pts == PTX_EndCell)))
10557 			{
10558 				m_currentRTFState.m_destinationState = RTFStateStore::rdsSkip;
10559 				return true;
10560 			}
10561 		}
10562 		if((m_pasteTableStack.getDepth() > 2) &&
10563 		   ((pts == PTX_SectionTable) || (pts == PTX_SectionCell) || (pts == PTX_EndTable) || (pts == PTX_EndCell)))
10564 		{
10565 			return true;
10566 		}
10567 	}
10568 //
10569 // Can't insert into a TOC
10570 //
10571 	if(getDoc()->isTOCAtPos(m_dposPaste) &&
10572 	   getDoc()->isTOCAtPos(m_dposPaste-1) &&
10573 		(pts != PTX_EndTOC))
10574 	{
10575 		m_dposPaste--;
10576 		if(m_posSavedDocPosition > 0)
10577 			m_posSavedDocPosition--;
10578 	}
10579 	if(bDoExtraBlock && (pts == PTX_SectionTable))
10580 	{
10581 		//		getDoc()->insertStrux(m_dposPaste,PTX_Block);
10582 		if(bInHyperlink)
10583 		{
10584 			//	m_dposPaste++;
10585 			bInHyperlink = false;
10586 		}
10587 	}
10588 	if(pts == PTX_SectionFrame)
10589 	{
10590 		pf_Frag_Strux * pfs = NULL;
10591 		if(pView->isInFrame(m_dposPaste))
10592 		{
10593 			PT_DocPosition pos = m_dposPaste;
10594 
10595 			while(( getDoc()->isFrameAtPos(pos) || pView->isInFrame(pos)) && pos <= posEOD)
10596 			{
10597 				pos++;
10598 			}
10599 			if(pos > posEOD)
10600 			{
10601 				pos = posEOD;
10602 			}
10603 			m_dposPaste = pos;
10604 		}
10605 		res = getDoc()->insertStrux(m_dposPaste,pts,attrs,props,&pfs);
10606 		m_dposPaste = pfs->getPos()+1;
10607 		return res;
10608 	}
10609 	if((pts == PTX_EndFrame) && (getDoc()->isFrameAtPos(m_dposPaste)))
10610 	{
10611 		res = getDoc()->insertStrux(m_dposPaste,PTX_Block);
10612 		m_dposPaste++;
10613 		res = getDoc()->insertStrux(m_dposPaste,pts,attrs,props);
10614 		m_dposPaste++;
10615 		if(	bInHyperlink)
10616 		{
10617 			m_iHyperlinkOpen =0;
10618 		}
10619 		m_bStruxInserted = true;
10620 		return res;
10621 	}
10622 	//
10623 	// Can't  paste sections in Footnotes/Endnotes
10624 	//
10625 	if(pts == PTX_Section)
10626 	{
10627 		if(pView->getEmbedDepth(m_dposPaste) > 0)
10628 		{
10629 			return false;
10630 		}
10631 		fl_BlockLayout * pBL = pView->getBlockAtPosition(m_dposPaste);
10632 		if(pBL == NULL)
10633 		{
10634 			return false;
10635 		}
10636 		if(pBL->myContainingLayout() == NULL)
10637 		{
10638 			return false;
10639 		}
10640 		if(pBL->myContainingLayout()->getContainerType() !=  FL_CONTAINER_DOCSECTION)
10641 		{
10642 			return false;
10643 		}
10644 		if(pBL->getPosition() > m_dposPaste)
10645 		{
10646 			return false;
10647 		}
10648 		if((pBL->getPosition(true) + pBL->getLength()) < m_dposPaste)
10649 		{
10650 			return false;
10651 		}
10652 		if((pBL->getPrev() == NULL))
10653 		{
10654 			return false;
10655 		}
10656 		if((pBL->getNext() == NULL))
10657 		{
10658 			return false;
10659 		}
10660 		if(pBL->getNext()->getContainerType() != FL_CONTAINER_BLOCK)
10661 		{
10662 			return false;
10663 		}
10664 		if(pBL->getPrev()->getContainerType() != FL_CONTAINER_BLOCK)
10665 		{
10666 			return false;
10667 		}
10668 	}
10669 	res = getDoc()->insertStrux(m_dposPaste,pts,attrs,props);
10670 	m_dposPaste++;
10671 	if(m_posSavedDocPosition > 0)
10672 		m_posSavedDocPosition++;
10673 	if(	bInHyperlink)
10674 	{
10675 		m_dposPaste++;
10676 		m_iHyperlinkOpen =0;
10677 		if(m_posSavedDocPosition > 0)
10678 			m_posSavedDocPosition++;
10679 	}
10680 	m_bStruxInserted = true;
10681 	return res;
10682 }
10683 
10684 
10685 
10686 //////////////////////////////////////////////////////////////////////////////
10687 // AbiList table reader
10688 //////////////////////////////////////////////////////////////////////////////
10689 
HandleAbiLists()10690 bool IE_Imp_RTF::HandleAbiLists()
10691 {
10692 	unsigned char keyword[MAX_KEYWORD_LEN];
10693 	unsigned char ch;
10694 	UT_sint32 parameter = 0;
10695 	bool paramUsed = false;
10696 	if (!ReadCharFromFile(&ch))
10697 		return false;
10698 
10699 	// Since the star keyword group is between brackets, a new RTF state was generated. Remove it now.
10700 	// The closing bracket will be ignored.
10701 	PopRTFState();
10702 	while (ch != '}') // Outer loop
10703 	{
10704 		if(ch == '{')  // abiliststyle, abilistdecimal, abilistdelim
10705 		{
10706 			if (!ReadCharFromFile(&ch))
10707 				return false;
10708 			if(!ReadKeyword(keyword, &parameter, &paramUsed, MAX_KEYWORD_LEN))
10709 			{
10710 				return false;
10711 			}
10712 			else
10713 			{
10714 				if (strcmp(reinterpret_cast<char*>(&keyword[0]), "abiliststyle") == 0)
10715 				 {
10716 			  // OK scan through the text until a closing delimeter is
10717 			  // found
10718 					 int count = 0;
10719 					 if (!ReadCharFromFile(&ch))
10720 						 return false;
10721 					 while ( ch != '}'  && ch != ';' && count < MAX_KEYWORD_LEN - 1)
10722 					 {
10723 						 keyword[count++] = ch;
10724 						 if (!ReadCharFromFile(&ch))
10725 							 return false;
10726 					 }
10727 					 keyword[count++] = 0;
10728 					 strncpy(m_currentRTFState.m_paraProps.m_pszStyle,reinterpret_cast<char*>(&keyword[0]), sizeof(m_currentRTFState.m_paraProps.m_pszStyle));
10729 					 m_currentRTFState.m_paraProps.m_pszStyle[sizeof(m_currentRTFState.m_paraProps.m_pszStyle) - 1] = 0;
10730 				 }
10731 				 else if (strcmp(reinterpret_cast<char*>(&keyword[0]), "abilistdecimal") == 0)
10732 				 {
10733 			  // OK scan through the text until a closing delimeter is
10734 			  // found
10735 					 int count = 0;
10736 					 if (!ReadCharFromFile(&ch))
10737 						 return false;
10738 					 while ( ch != '}'  && ch != ';' && count < MAX_KEYWORD_LEN - 1)
10739 					 {
10740 						 keyword[count++] = ch;
10741 						 if (!ReadCharFromFile(&ch))
10742 							 return false;
10743 					 }
10744 					 keyword[count++] = 0;
10745 					 strncpy(m_currentRTFState.m_paraProps.m_pszListDecimal,reinterpret_cast<char*>(&keyword[0]), sizeof(m_currentRTFState.m_paraProps.m_pszListDecimal));
10746 					 m_currentRTFState.m_paraProps.m_pszListDecimal[sizeof(m_currentRTFState.m_paraProps.m_pszListDecimal) - 1] = 0;
10747 				 }
10748 				 else if (strcmp(reinterpret_cast<char*>(&keyword[0]), "abilistdelim") == 0)
10749 				 {
10750 			  // OK scan through the text until a closing delimeter is
10751 			  // found
10752 					 int count = 0;
10753 					 if (!ReadCharFromFile(&ch))
10754 						 return false;
10755 					 while ( ch != '}'  && ch != ';' && count < MAX_KEYWORD_LEN - 1)
10756 					 {
10757 						 keyword[count++] = ch;
10758 						 if (!ReadCharFromFile(&ch))
10759 							 return false;
10760 					 }
10761 					 keyword[count++] = 0;
10762 					 strncpy(m_currentRTFState.m_paraProps.m_pszListDelim,reinterpret_cast<char*>(&keyword[0]), sizeof(m_currentRTFState.m_paraProps.m_pszListDelim));
10763 					 m_currentRTFState.m_paraProps.m_pszListDelim[sizeof(m_currentRTFState.m_paraProps.m_pszListDelim) - 1] = 0;
10764 				 }
10765 				 else if (strcmp(reinterpret_cast<char*>(&keyword[0]), "abifieldfont") == 0)
10766 				 {
10767 			  // OK scan through the text until a closing delimeter is
10768 			  // found
10769 					 int count = 0;
10770 					 if (!ReadCharFromFile(&ch))
10771 						 return false;
10772 					 while ( ch != '}'  && ch != ';' && count < MAX_KEYWORD_LEN - 1)
10773 					 {
10774 						 keyword[count++] = ch;
10775 						 if (!ReadCharFromFile(&ch))
10776 							 return false;
10777 					 }
10778 					 keyword[count++] = 0;
10779 					 strncpy(m_currentRTFState.m_paraProps.m_pszFieldFont,reinterpret_cast<char*>(&keyword[0]), sizeof(m_currentRTFState.m_paraProps.m_pszFieldFont));
10780 					 m_currentRTFState.m_paraProps.m_pszFieldFont[sizeof(m_currentRTFState.m_paraProps.m_pszFieldFont) - 1] = 0;
10781 				 }
10782 				 else
10783 				 {
10784 					 UT_DEBUGMSG(("Unknown keyword %s found in List stream  \n",keyword));
10785 				 }
10786 			}
10787 			goto nextChar;
10788 		}
10789 		if(!ReadKeyword(keyword, &parameter, &paramUsed, MAX_KEYWORD_LEN))
10790 		{
10791 			return false;
10792 		}
10793 		else
10794 		{
10795 			if (strcmp(reinterpret_cast<char*>(&keyword[0]), "abistartat") == 0)
10796 			{
10797 				m_currentRTFState.m_paraProps.m_startValue= static_cast<UT_uint32>(parameter);
10798 			}
10799 			else if (strcmp(reinterpret_cast<char*>(&keyword[0]), "abilistid") == 0)
10800 			{
10801 				m_currentRTFState.m_paraProps.m_rawID = static_cast<UT_uint32>(parameter);
10802 				m_currentRTFState.m_paraProps.m_isList = true;
10803 
10804 			}
10805 			else if (strcmp(reinterpret_cast<char*>(&keyword[0]), "abilistparentid") == 0)
10806 			{
10807 				m_currentRTFState.m_paraProps.m_rawParentID = static_cast<UT_uint32>(parameter);
10808 			}
10809 			else if (strcmp(reinterpret_cast<char*>(&keyword[0]), "abilistlevel") == 0)
10810 			{
10811 				m_currentRTFState.m_paraProps.m_level = static_cast<UT_uint32>(parameter);
10812 			}
10813 			else
10814 			{
10815 				UT_DEBUGMSG(("Unknown keyword %s found in List stream  \n",keyword));
10816 			}
10817 		}
10818 	nextChar:	if (!ReadCharFromFile(&ch))
10819 		return false;
10820 	}
10821 
10822 	//
10823 	// Increment the list mapping table if necessary
10824 	//
10825 	UT_uint32 i;
10826 	if(m_currentRTFState.m_paraProps.m_rawID != 0)
10827 	{
10828 		for(i=0; i < m_numLists; i++)
10829 		{
10830 			if(m_currentRTFState.m_paraProps.m_rawID == getAbiList(i)->orig_id)
10831 				break;
10832 		}
10833 		if(i >= m_numLists)
10834 		{
10835 			m_vecAbiListTable.push_back(new _rtfAbiListTable);
10836 			getAbiList(m_numLists)->orig_id = m_currentRTFState.m_paraProps.m_rawID ;
10837 			getAbiList(m_numLists)->orig_parentid = m_currentRTFState.m_paraProps.m_rawParentID ;
10838 			getAbiList(m_numLists)->level = m_currentRTFState.m_paraProps.m_level ;
10839 			getAbiList(m_numLists)->hasBeenMapped = false;
10840 			getAbiList(m_numLists)->start_value = 0;
10841 			getAbiList(m_numLists)->mapped_id = 0;
10842 			getAbiList(m_numLists)->mapped_parentid = 0;
10843 			m_numLists++;
10844 		}
10845 	}
10846 
10847 	return true;
10848 }
10849 
10850 
10851 
10852 //////////////////////////////////////////////////////////////////////////////
10853 // Character Properties keyword handlers
10854 //////////////////////////////////////////////////////////////////////////////
HandleRevisedText(PP_RevisionType eType,UT_uint32 iId)10855 bool IE_Imp_RTF::HandleRevisedText(PP_RevisionType eType, UT_uint32 iId)
10856 {
10857 	UT_return_val_if_fail( FlushStoredChars(), false);
10858 
10859 	// remember the id for future reference
10860 	m_currentRTFState.m_charProps.m_iCurrentRevisionId = iId;
10861 	m_currentRTFState.m_charProps.m_eRevision = eType;
10862 
10863 #if 0
10864 	switch(eType)
10865 	{
10866 		case PP_REVISION_ADDITION:
10867 		case PP_REVISION_ADDITION_AND_FMT:
10868 
10869 		case PP_REVISION_DELETION:
10870 
10871 		case PP_REVISION_FMT_CHANGE:
10872 			;
10873 	}
10874 #endif
10875 	return true;
10876 }
10877 
HandleRevisedTextTimestamp(UT_uint32 iDttm)10878 bool IE_Imp_RTF::HandleRevisedTextTimestamp(UT_uint32 iDttm)
10879 {
10880 	// we basically rely on the dttm keyword to follow the auth keyword -- Word outputs
10881 	// them in this sequence, and so do we
10882 	UT_return_val_if_fail( m_currentRTFState.m_charProps.m_iCurrentRevisionId > 0,true); // was false (this enables RTF spec to load)
10883 
10884 	const UT_GenericVector<AD_Revision*> & Rtbl = getDoc()->getRevisions();
10885 	UT_return_val_if_fail(Rtbl.getItemCount(),true); // was false (This enables RTF spec to load)
10886 
10887 	// valid revision id's start at 1, but vector is 0-based
10888 	AD_Revision * pRev = Rtbl.getNthItem(m_currentRTFState.m_charProps.m_iCurrentRevisionId - 1);
10889 
10890 	UT_return_val_if_fail( pRev, false );
10891 
10892 	if(!pRev->getStartTime())
10893 	{
10894 		// set the start time to what ever is represented by dttm
10895 		struct tm TM;
10896 		TM.tm_sec = 0;
10897 		TM.tm_min = (iDttm & 0x3f);
10898 		TM.tm_hour = (iDttm & 0x7c0) >> 6;
10899 		TM.tm_mday = (iDttm & 0xf800) >> 11;
10900 		TM.tm_mon = ((iDttm & 0xf0000) >> 16)- 1;
10901 		TM.tm_year = (iDttm & 0x1ff00000) >> 20;
10902 		TM.tm_isdst = 0;
10903 
10904 		time_t tT = mktime(&TM);
10905 		pRev->setStartTime(tT);
10906 	}
10907 
10908 	return true;
10909 }
10910 
10911 
HandleBoolCharacterProp(bool state,bool * pProp)10912 bool IE_Imp_RTF::HandleBoolCharacterProp(bool state, bool* pProp)
10913 {
10914 	bool ok = FlushStoredChars();
10915 	*pProp = state;
10916 	return ok;
10917 }
10918 
HandleDeleted(bool state)10919 bool IE_Imp_RTF::HandleDeleted(bool state)
10920 {
10921 	return HandleBoolCharacterProp(state, &m_currentRTFState.m_charProps.m_deleted);
10922 }
10923 
HandleBold(bool state)10924 bool IE_Imp_RTF::HandleBold(bool state)
10925 {
10926 	return HandleBoolCharacterProp(state, &m_currentRTFState.m_charProps.m_bold);
10927 }
10928 
HandleItalic(bool state)10929 bool IE_Imp_RTF::HandleItalic(bool state)
10930 {
10931 	return HandleBoolCharacterProp(state, &m_currentRTFState.m_charProps.m_italic);
10932 }
10933 
HandleHidden(bool state)10934 bool IE_Imp_RTF::HandleHidden(bool state)
10935 {
10936 	return HandleBoolCharacterProp(state, &m_currentRTFState.m_charProps.m_Hidden);
10937 }
10938 
HandleUnderline(bool state)10939 bool IE_Imp_RTF::HandleUnderline(bool state)
10940 {
10941 	return HandleBoolCharacterProp(state, &m_currentRTFState.m_charProps.m_underline);
10942 }
10943 
HandleOverline(bool state)10944 bool IE_Imp_RTF::HandleOverline(bool state)
10945 {
10946 	return HandleBoolCharacterProp(state, &m_currentRTFState.m_charProps.m_overline);
10947 }
10948 
10949 
HandleTopline(bool state)10950 bool IE_Imp_RTF::HandleTopline(bool state)
10951 {
10952 	return HandleBoolCharacterProp(state, &m_currentRTFState.m_charProps.m_topline);
10953 }
10954 
10955 
HandleBotline(bool state)10956 bool IE_Imp_RTF::HandleBotline(bool state)
10957 {
10958 	return HandleBoolCharacterProp(state, &m_currentRTFState.m_charProps.m_botline);
10959 }
10960 
HandleStrikeout(bool state)10961 bool IE_Imp_RTF::HandleStrikeout(bool state)
10962 {
10963 	return HandleBoolCharacterProp(state, &m_currentRTFState.m_charProps.m_strikeout);
10964 }
10965 
HandleSuperscript(bool state)10966 bool IE_Imp_RTF::HandleSuperscript(bool state)
10967 {
10968 	return HandleBoolCharacterProp(state, &m_currentRTFState.m_charProps.m_superscript);
10969 }
10970 
10971 // pos is in 1/2pt like in RTF
HandleSuperscriptPosition(UT_uint32 pos)10972 bool IE_Imp_RTF::HandleSuperscriptPosition(UT_uint32 pos)
10973 {
10974 	bool ok;
10975 	ok = HandleBoolCharacterProp((pos != 0) ? true : false, &m_currentRTFState.m_charProps.m_superscript);
10976 	if (ok)
10977 	{
10978 		ok = HandleFloatCharacterProp (pos*0.5, &m_currentRTFState.m_charProps.m_superscript_pos);
10979 	}
10980 	return ok;
10981 }
10982 
HandleSubscript(bool state)10983 bool IE_Imp_RTF::HandleSubscript(bool state)
10984 {
10985 	return HandleBoolCharacterProp(state, &m_currentRTFState.m_charProps.m_subscript);
10986 }
10987 
10988 // pos is in 1/2pt like in RTF
HandleSubscriptPosition(UT_uint32 pos)10989 bool IE_Imp_RTF::HandleSubscriptPosition(UT_uint32 pos)
10990 {
10991 	bool ok;
10992 	ok = HandleBoolCharacterProp((pos != 0) ? true : false, &m_currentRTFState.m_charProps.m_subscript);
10993 	if (ok)
10994 	{
10995 		ok = HandleFloatCharacterProp (pos*0.5, &m_currentRTFState.m_charProps.m_subscript_pos);
10996 	}
10997 	return ok;
10998 }
10999 
HandleFontSize(long sizeInHalfPoints)11000 bool IE_Imp_RTF::HandleFontSize(long sizeInHalfPoints)
11001 {
11002 	return HandleFloatCharacterProp (sizeInHalfPoints*0.5, &m_currentRTFState.m_charProps.m_fontSize);
11003 }
11004 
11005 
HandleFloatCharacterProp(double val,double * pProp)11006 bool IE_Imp_RTF::HandleFloatCharacterProp(double val, double* pProp)
11007 {
11008 	bool ok = FlushStoredChars();
11009 	*pProp = val;
11010 	return ok;
11011 }
11012 
HandleU32CharacterProp(UT_uint32 val,UT_uint32 * pProp)11013 bool IE_Imp_RTF::HandleU32CharacterProp(UT_uint32 val, UT_uint32* pProp)
11014 {
11015 	bool ok = FlushStoredChars();
11016 	*pProp = val;
11017 	return ok;
11018 }
11019 
HandleListTag(long id)11020 bool IE_Imp_RTF::HandleListTag(long id)
11021 {
11022 	UT_uint32 sid = static_cast<UT_uint32>(id);
11023 	return HandleU32CharacterProp(sid, &m_currentRTFState.m_charProps.m_listTag);
11024 }
11025 
11026 
HandleFace(UT_uint32 fontNumber)11027 bool IE_Imp_RTF::HandleFace(UT_uint32 fontNumber)
11028 {
11029 	bool retval;
11030 
11031 	retval = HandleU32CharacterProp(fontNumber, &m_currentRTFState.m_charProps.m_fontNumber);
11032 	setEncoding();  // Activate character encoding
11033 	return retval;
11034 }
11035 
HandleColour(UT_uint32 colourNumber)11036 bool IE_Imp_RTF::HandleColour(UT_uint32 colourNumber)
11037 {
11038 	if (HandleBoolCharacterProp(true, &m_currentRTFState.m_charProps.m_hasColour))
11039 	{
11040 		return HandleU32CharacterProp(colourNumber, &m_currentRTFState.m_charProps.m_colourNumber);
11041 	}
11042 	return false;
11043 }
11044 
HandleBackgroundColour(UT_uint32 colourNumber)11045 bool IE_Imp_RTF::HandleBackgroundColour(UT_uint32 colourNumber)
11046 {
11047 	if (HandleBoolCharacterProp(true, &m_currentRTFState.m_charProps.m_hasBgColour))
11048 	{
11049 		return HandleU32CharacterProp(colourNumber, &m_currentRTFState.m_charProps.m_bgcolourNumber);
11050 	}
11051 	return false;
11052 }
11053 
SetParaJustification(RTFProps_ParaProps::ParaJustification just)11054 bool IE_Imp_RTF::SetParaJustification(RTFProps_ParaProps::ParaJustification just)
11055 {
11056 	m_currentRTFState.m_paraProps.m_justification = just;
11057 
11058 	return true;
11059 }
11060 
AddTabstop(UT_sint32 stopDist,eTabType tabType,eTabLeader tabLeader)11061 bool IE_Imp_RTF::AddTabstop(UT_sint32 stopDist, eTabType tabType, eTabLeader tabLeader)
11062 {
11063 	m_currentRTFState.m_paraProps.m_tabStops.push_back(stopDist);	// convert from twip to inch
11064 	if(tabType >=FL_TAB_LEFT && tabType <= FL_TAB_BAR  )
11065 	{
11066 		m_currentRTFState.m_paraProps.m_tabTypes.push_back(tabType);
11067 	}
11068 	else
11069 	{
11070 		m_currentRTFState.m_paraProps.m_tabTypes.push_back(FL_TAB_LEFT);
11071 	}
11072 	if(tabLeader >= FL_LEADER_NONE  && tabLeader <= FL_LEADER_EQUALSIGN)
11073 	{
11074 		m_currentRTFState.m_paraProps.m_tabLeader.push_back(tabLeader);
11075 	}
11076 	else
11077 	{
11078 		m_currentRTFState.m_paraProps.m_tabLeader.push_back(FL_LEADER_NONE);
11079 	}
11080 
11081 	return true;
11082 }
11083 
11084 
11085 
AddTabstop(UT_sint32 stopDist,eTabType tabType,eTabLeader tabLeader,RTFProps_ParaProps * pParas)11086 bool IE_Imp_RTF::AddTabstop(UT_sint32 stopDist, eTabType tabType, eTabLeader tabLeader,  RTFProps_ParaProps * pParas)
11087 {
11088 	pParas->m_tabStops.push_back(stopDist);	// convert from twip to inch
11089 	if(tabType >=FL_TAB_LEFT && tabType <= FL_TAB_BAR  )
11090 	{
11091 		pParas->m_tabTypes.push_back(tabType);
11092 	}
11093 	else
11094 	{
11095 		pParas->m_tabTypes.push_back(FL_TAB_LEFT);
11096 	}
11097 	if(tabLeader >= FL_LEADER_NONE  && tabLeader <= FL_LEADER_EQUALSIGN)
11098 	{
11099 		pParas->m_tabLeader.push_back(tabLeader);
11100 	}
11101 	else
11102 	{
11103 		pParas->m_tabLeader.push_back(FL_LEADER_NONE);
11104 	}
11105 
11106 	return true;
11107 }
11108 
11109 /*!
11110   Get the next token, put it into buf, if there is an error return RTF_TOKEN_ERROR
11111   otherwise returns the RTFTokenType
11112   If it is RTF_TOKEN_DATA, data is returned byte by byte.
11113   RTF_TOKEN_KEYWORD includes control words and control symbols
11114   (like hex char).
11115   It is up to the caller to distinguish beetween them and parse them.
11116   \retval pKeyword is the data
11117   \retval pParam is the keyword parameter if any, otherwise "". RTF spec says it should be
11118   a signed 16-bits int.
11119   \retval pParamUsed is a flag to tell whether there is a parameter.
11120   \return the type of the next token parsed.
11121   \note Both pParam amd pParamUsed are only used if tokenType is
11122   RTF_TOKEN_KEYWORD
11123   \note this changes the state of the file
11124 */
NextToken(unsigned char * pKeyword,UT_sint32 * pParam,bool * pParamUsed,UT_uint32 len,bool bIgnoreWhiteSpace)11125 IE_Imp_RTF::RTFTokenType IE_Imp_RTF::NextToken (unsigned char *pKeyword, UT_sint32* pParam,
11126 												bool* pParamUsed, UT_uint32 len, bool bIgnoreWhiteSpace /* = false */ )
11127 {
11128 	RTFTokenType tokenType = RTF_TOKEN_NONE;
11129 	bool ok;
11130 
11131 	UT_return_val_if_fail (pKeyword, RTF_TOKEN_NONE);
11132 	UT_return_val_if_fail (len, RTF_TOKEN_NONE);
11133 	UT_return_val_if_fail (pParamUsed, RTF_TOKEN_NONE);
11134 	UT_return_val_if_fail (pParam, RTF_TOKEN_NONE);
11135 	*pParam = 0;
11136 	*pParamUsed = false;
11137 	pKeyword [0] = ' ';
11138 
11139 	if(bIgnoreWhiteSpace)
11140 	{
11141 		// see bug 1211 and bug 1207.rtf - invalid RTF coming in
11142 		// this code instead violates the RTF spec in order to fix that problem,
11143 		// but instead breaks other things like field values:
11144 		// If a space delimits the control word, the space does not appear in the
11145 		// document. Any characters following the delimiter, including spaces, will
11146 		// appear in the document. For this reason, you should use spaces only
11147 		// where necessary; do not use spaces merely to break up RTF code.
11148 
11149 		// OK Sevior put in bool to choose this behaviour for some parts of documents
11150         // where we can work around this broken behaviour and still import the doc.
11151 
11152 		while(pKeyword[0] == ' ')
11153 		{
11154 			if (!ReadCharFromFile(pKeyword))
11155 			{
11156 				tokenType = RTF_TOKEN_ERROR;
11157 				return tokenType;
11158 			}
11159 		}
11160 	}
11161 	else
11162 	{
11163 		if (!ReadCharFromFile(pKeyword))
11164 		{
11165 			tokenType = RTF_TOKEN_ERROR;
11166 			return tokenType;
11167 		}
11168 	}
11169 
11170 	switch (*pKeyword)
11171 	{
11172 	case '\\':
11173 		tokenType = RTF_TOKEN_KEYWORD;
11174 		ok = ReadKeyword (pKeyword, pParam, pParamUsed, len);
11175 		if (!ok)
11176 		{
11177 			tokenType = RTF_TOKEN_ERROR;
11178 		}
11179 		break;
11180 	case '{':
11181 		tokenType = RTF_TOKEN_OPEN_BRACE;
11182 		break;
11183 	case '}':
11184 		tokenType = RTF_TOKEN_CLOSE_BRACE;
11185 		break;
11186 	default:
11187 		tokenType = RTF_TOKEN_DATA;
11188 		break;
11189 	}
11190 
11191 	return tokenType;
11192 }
11193 
11194 
11195 /*!
11196   Handle a bookmark keyword
11197  */
HandleBookmark(RTFBookmarkType type)11198 bool IE_Imp_RTF::HandleBookmark (RTFBookmarkType type)
11199 {
11200 	UT_UTF8String bookmarkName;
11201 
11202 	xxx_UT_DEBUGMSG(("hub: HandleBookmark of type %d\n", type));
11203 
11204 	/* read the bookmark name. It is PCDATA hence we are likely to find non ASCII data.*/
11205 	HandlePCData(bookmarkName);
11206 
11207 	const gchar * props [5];
11208 	props [0] = "type";
11209 	switch (type) {
11210 	case RBT_START:
11211 		props [1] = "start";
11212 		break;
11213 	case RBT_END:
11214 		props [1] = "end";
11215 		break;
11216 	default:
11217 		UT_ASSERT_NOT_REACHED();
11218 		props [1] = NULL;
11219 		break;
11220 	}
11221 	props [2] = "name";
11222 	props [3] = bookmarkName.utf8_str();
11223 	props [4] = NULL;
11224 	UT_DEBUGMSG(("SEVIOR: Appending Object 3 m_bCellBlank %d m_bEndTableOpen %d \n",m_bCellBlank,m_bEndTableOpen));
11225 	if(m_bCellBlank || m_bEndTableOpen || !m_bSectionHasPara)
11226 	{
11227 		UT_DEBUGMSG(("Insert/Append block 3 \n"));
11228 		if (m_newSectionFlagged)
11229 		{
11230 			ApplySectionAttributes();
11231 			m_newSectionFlagged = false;
11232 		}
11233 		if(!bUseInsertNotAppend())
11234 		{
11235 			if(m_pDelayedFrag)
11236 			{
11237 				getDoc()->insertStruxBeforeFrag(m_pDelayedFrag,PTX_Block,NULL);
11238 			}
11239 			else
11240 			{
11241 				getDoc()->appendStrux(PTX_Block,NULL);
11242 			}
11243 		}
11244 		else
11245 		{
11246 			markPasteBlock();
11247 			insertStrux(PTX_Block);
11248 		}
11249 		m_bCellBlank = false;
11250 		m_bEndTableOpen = false;
11251 		m_bSectionHasPara = true;
11252 		m_newParaFlagged = false;
11253 	}
11254 
11255 	if (!bUseInsertNotAppend())
11256 	{
11257 			if(m_pDelayedFrag)
11258 			{
11259 				getDoc()->insertObjectBeforeFrag(m_pDelayedFrag,PTO_Bookmark,props);
11260 			}
11261 			else
11262 			{
11263 				getDoc()->appendObject(PTO_Bookmark, props);
11264 			}
11265 	}
11266 	else
11267 	{
11268 		if(isBlockNeededForPasteTable())
11269 		{
11270 			markPasteBlock();
11271 			insertStrux(PTX_Block);
11272 		}
11273 		getDoc()->insertObject(m_dposPaste, PTO_Bookmark, props, NULL);
11274 		m_dposPaste++;
11275 		if(m_posSavedDocPosition > 0)
11276 			m_posSavedDocPosition++;
11277 	}
11278 	return true;
11279 }
11280 
11281 
HandleRDFAnchor(RTFBookmarkType type)11282 bool IE_Imp_RTF::HandleRDFAnchor (RTFBookmarkType type)
11283 {
11284 	UT_DEBUGMSG(("HandleRDFAnchor() of type %d is-start:%d is-end:%d use-app:%d\n",
11285 				 type,
11286 				 type == RBT_START, type == RBT_END,
11287 				 !bUseInsertNotAppend()  ));
11288 
11289 	std::string xmlid;
11290 	HandlePCData(xmlid);
11291 
11292 	UT_DEBUGMSG(("HandleRDFAnchor() of type %d original xmlid:%s\n", type, xmlid.c_str()));
11293 	if( type == RBT_START )
11294 	{
11295 		PD_XMLIDCreatorHandle xidc = m_XMLIDCreatorHandle;
11296 		std::string updatedxmlid = xidc->createUniqueXMLID( xmlid );
11297 		m_rdfAnchorCloseXMLIDs.insert( make_pair( xmlid, updatedxmlid ) );
11298 		xmlid = updatedxmlid;
11299 	}
11300 	else
11301 	{
11302 		xmlid = m_rdfAnchorCloseXMLIDs[ xmlid ];
11303 		m_rdfAnchorCloseXMLIDs.erase( xmlid );
11304 	}
11305 	UT_DEBUGMSG(("HandleRDFAnchor() of type %d updated  xmlid:%s\n", type, xmlid.c_str()));
11306 
11307 	const gchar* ppAtts[10] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
11308 	int ppIdx = 0;
11309 	ppAtts[ppIdx++] = PT_XMLID;
11310 	ppAtts[ppIdx++] = xmlid.c_str();
11311 	ppAtts[ppIdx++] = "this-is-an-rdf-anchor";
11312 	ppAtts[ppIdx++] = "yes";
11313 	switch (type)
11314 	{
11315 		case RBT_START:
11316 			m_iRDFAnchorOpen--;
11317 			break;
11318 		case RBT_END:
11319 			m_iRDFAnchorOpen++;
11320 			ppAtts[ppIdx++] = PT_RDF_END;
11321 			ppAtts[ppIdx++] = "yes";
11322 			break;
11323 	}
11324 
11325 	if (!bUseInsertNotAppend())
11326 	{
11327 			if(m_pDelayedFrag)
11328 			{
11329 				getDoc()->insertObjectBeforeFrag(m_pDelayedFrag,PTO_RDFAnchor,ppAtts);
11330 			}
11331 			else
11332 			{
11333 				getDoc()->appendObject(PTO_RDFAnchor, ppAtts);
11334 			}
11335 	}
11336 	else
11337 	{
11338 		if(isBlockNeededForPasteTable())
11339 		{
11340 			markPasteBlock();
11341 			insertStrux(PTX_Block);
11342 		}
11343 		getDoc()->insertObject(m_dposPaste, PTO_RDFAnchor, ppAtts, NULL);
11344 		m_dposPaste++;
11345 		if(m_posSavedDocPosition > 0)
11346 			m_posSavedDocPosition++;
11347 	}
11348 
11349 	return true;
11350 }
11351 
HandleDeltaMoveID()11352 bool IE_Imp_RTF::HandleDeltaMoveID()
11353 {
11354 	std::string moveid;
11355 	HandlePCData(moveid);
11356 
11357 	UT_DEBUGMSG(("HandleDeltaMoveID() of t %d\n", 1 ));
11358 	UT_DEBUGMSG(("HandleDeltaMoveID() of dposPaste %d\n", m_dposPaste ));
11359 	UT_DEBUGMSG(("HandleDeltaMoveID() move-id %s\n", moveid.c_str() ));
11360 	if( !moveid.empty() )
11361 	{
11362 //		m_ctMoveID = moveid;
11363 		pf_Frag_Strux* sdh;
11364 		bool bResult = getDoc()->getStruxOfTypeFromPosition( m_dposPaste, PTX_Block, &sdh);
11365 		if( bResult )
11366 		{
11367 			getDoc()->changeStruxAttsNoUpdate( sdh, "delta:move-idref", moveid.c_str() );
11368 		}
11369 	}
11370 	return true;
11371 }
11372 
11373 
_appendHdrFtr()11374 void IE_Imp_RTF::_appendHdrFtr ()
11375 {
11376 	UT_uint32 i;
11377 	UT_uint32 numHdrFtr;
11378 	const RTFHdrFtr * header;
11379 	std::string tempBuffer;
11380 	const gchar* szType = NULL;
11381 
11382 	UT_return_if_fail(m_pImportFile);
11383 
11384 	numHdrFtr = m_hdrFtrTable.size();
11385 
11386 	for (i = 0; i < numHdrFtr; i++)
11387 	{
11388 		header = m_hdrFtrTable[i];
11389 
11390 		m_pPasteBuffer = reinterpret_cast<const unsigned char *>(header->m_buf.getPointer (0));
11391 		m_lenPasteBuffer = header->m_buf.getLength ();
11392 		m_pCurrentCharInPasteBuffer = m_pPasteBuffer;
11393 		m_dposPaste = FV_DOCPOS_EOD;
11394 		const gchar* propsArray[9];
11395 		std::string hdrftrID;
11396 		switch (header->m_type)
11397 		{
11398 		case RTFHdrFtr::hftHeader:
11399 			tempBuffer = UT_std_string_sprintf ("%u", header->m_id);
11400 			szType = "header";
11401 			break;
11402 		case RTFHdrFtr::hftHeaderEven:
11403 			tempBuffer = UT_std_string_sprintf ("%u", header->m_id);
11404 			szType = "header-even";
11405 			break;
11406 		case RTFHdrFtr::hftHeaderFirst:
11407 			tempBuffer = UT_std_string_sprintf ("%u", header->m_id);
11408 			szType = "header-first";
11409 			break;
11410 		case RTFHdrFtr::hftHeaderLast:
11411 			tempBuffer = UT_std_string_sprintf ("%u", header->m_id);
11412 			szType = "header-last";
11413 			break;
11414 		case RTFHdrFtr::hftFooter:
11415 			tempBuffer = UT_std_string_sprintf ("%u", header->m_id);
11416 			szType = "footer";
11417 			break;
11418 		case RTFHdrFtr::hftFooterEven:
11419 			tempBuffer = UT_std_string_sprintf ("%u", header->m_id);
11420 			szType = "footer-even";
11421 			break;
11422 		case RTFHdrFtr::hftFooterFirst:
11423 			tempBuffer = UT_std_string_sprintf ("%u", header->m_id);
11424 			szType = "footer-first";
11425 			break;
11426 		case RTFHdrFtr::hftFooterLast:
11427 			tempBuffer = UT_std_string_sprintf ("%u", header->m_id);
11428 			szType = "footer-last";
11429 			break;
11430 		default:
11431 			UT_ASSERT_NOT_REACHED();
11432 		}
11433 		UT_DEBUGMSG (("id is %s\n", tempBuffer.c_str()));
11434 		hdrftrID = tempBuffer;
11435 		propsArray[0] = "type";
11436 		propsArray[1] = szType;
11437 		propsArray[2] = "id";
11438 		propsArray[3] = tempBuffer.c_str();
11439 		propsArray[4] = "listid";
11440 		propsArray[5] = "0";
11441 		propsArray[6] = "parentid";
11442 		propsArray[7] = "0";
11443 		propsArray[8] = NULL;
11444 
11445 		if(!getDoc()->verifySectionID(hdrftrID.c_str()))
11446 		{
11447 			pf_Frag_Strux* sdh = getDoc()->getLastSectionMutableSDH();
11448 			getDoc()->changeStruxAttsNoUpdate(sdh,szType,hdrftrID.c_str());
11449 		}
11450 		getDoc()->appendStrux (PTX_SectionHdrFtr, propsArray);
11451 		propsArray[0] = NULL;
11452 		// actually it appears that we have to append a block for some cases.
11453 		UT_DEBUGMSG(("Append block 4 with props \n"));
11454 #if 0 //#TF
11455 		getDoc()->appendStrux(PTX_Block, propsArray);
11456 #endif
11457 		// tell that we are parsing headers and footers
11458 		m_parsingHdrFtr = true;
11459 		m_newParaFlagged = true;
11460 		m_bSectionHasPara = false;
11461 		_parseFile (NULL);
11462 		m_parsingHdrFtr = false;
11463 	}
11464 }
11465 
11466 /*!
11467   Appends a field to the document.
11468   \param xmlField the field type value
11469   \return true if OK
11470  */
_appendField(const gchar * xmlField,const gchar ** pszAttribs)11471 bool IE_Imp_RTF::_appendField (const gchar *xmlField, const gchar ** pszAttribs)
11472 {
11473 	bool ok;
11474 	const gchar** propsArray = NULL;
11475 	std::string propBuffer;
11476 	buildCharacterProps(propBuffer);
11477 
11478 	const gchar * pStyle = NULL;
11479 	std::string styleName;
11480 	if(m_currentRTFState.m_charProps.m_styleNumber >= 0
11481 	   && static_cast<UT_uint32>(m_currentRTFState.m_charProps.m_styleNumber) < m_styleTable.size())
11482 	{
11483 		pStyle = PT_STYLE_ATTRIBUTE_NAME;
11484 		styleName = m_styleTable[m_currentRTFState.m_charProps.m_styleNumber];
11485 	}
11486 	bool bNoteRef = false;
11487 	if((strcmp(xmlField,"endnote_ref") == 0) || (strcmp(xmlField,"footnote_ref") == 0))
11488 	{
11489 		bNoteRef = true;
11490 	}
11491 	if(pszAttribs == NULL)
11492 	{
11493 		propsArray = static_cast<const gchar **>(UT_calloc(7, sizeof(gchar *)));
11494 		propsArray [0] = "type";
11495 		propsArray [1] = xmlField;
11496 		propsArray [2] = "props";
11497 		propsArray [3] = propBuffer.c_str();
11498 		propsArray [4] = pStyle;
11499 		propsArray [5] = styleName.c_str();
11500 		propsArray [6] = NULL;
11501 	}
11502 	else
11503 	{
11504 		UT_uint32 isize =0;
11505 		while(pszAttribs[isize] != NULL)
11506 		{
11507 			isize++;
11508 		}
11509 		propsArray = static_cast<const gchar **>(UT_calloc(7+isize, sizeof(gchar *)));
11510 
11511 		UT_uint32 iEmptyAttrib = 4;
11512 		propsArray [0] = "type";
11513 		propsArray [1] = xmlField;
11514 		propsArray [2] = "props";
11515 		propsArray [3] = propBuffer.c_str();
11516 		propsArray [4] = NULL;
11517 		propsArray [5] = NULL;
11518 
11519 		if(pStyle)
11520 		{
11521 			propsArray[iEmptyAttrib++] = pStyle;
11522 			propsArray[iEmptyAttrib++] = styleName.c_str();
11523 		}
11524 
11525 
11526 		UT_uint32 i = 0;
11527 		for(i=0; i< isize;i++)
11528 		{
11529 			propsArray[iEmptyAttrib+i] = pszAttribs[i];
11530 		}
11531 		propsArray[iEmptyAttrib+isize] = NULL;
11532 	}
11533 	// TODO get text props to apply them to the field
11534 	ok = FlushStoredChars (true);
11535 	UT_return_val_if_fail (ok, false);
11536 	if (!bUseInsertNotAppend() || m_bAppendAnyway)
11537 	{
11538 		UT_DEBUGMSG(("SEVIOR: Appending Object m_bCellBlank %d m_bEndTableOpen %d \n",m_bCellBlank,m_bEndTableOpen));
11539 		if(m_bCellBlank || m_bEndTableOpen)
11540 		{
11541 			UT_DEBUGMSG(("Append block 5 \n"));
11542 			if(m_pDelayedFrag)
11543 			{
11544 				getDoc()->insertStruxBeforeFrag(m_pDelayedFrag,PTX_Block,NULL);
11545 			}
11546 			else
11547 			{
11548 				getDoc()->appendStrux(PTX_Block,NULL);
11549 			}
11550 			m_bCellBlank = false;
11551 			m_bEndTableOpen = false;
11552 		}
11553 		if(m_pDelayedFrag)
11554 	    {
11555 			getDoc()->insertObjectBeforeFrag(m_pDelayedFrag,PTO_Field, propsArray);
11556 		}
11557 		else
11558 		{
11559 			getDoc()->appendObject(PTO_Field, propsArray);
11560 		}
11561 	}
11562 	else
11563 	{
11564 		XAP_Frame * pFrame = XAP_App::getApp()->getLastFocussedFrame();
11565 		if(pFrame == NULL)
11566 		 {
11567 			 m_currentRTFState.m_destinationState = RTFStateStore::rdsSkip;
11568 			 return true;
11569 		 }
11570 		FV_View * pView = static_cast<FV_View*>(pFrame->getCurrentView());
11571 		if(pView == NULL)
11572 		{
11573 			m_currentRTFState.m_destinationState = RTFStateStore::rdsSkip;
11574 			return true;
11575 		}
11576 		//
11577 		// No pasting footnotes/endnotes into text boxes, paste just before
11578 		// it.
11579 		//
11580 		if(bNoteRef && pView->isInFrame(m_dposPaste))
11581 		{
11582 			fl_FrameLayout * pFL = pView->getFrameLayout(m_dposPaste);
11583 			if(pFL == NULL)
11584 			{
11585 				m_currentRTFState.m_destinationState = RTFStateStore::rdsSkip;
11586 				return true;
11587 			}
11588 			PT_DocPosition newPos = pFL->getPosition(true);
11589 			while(newPos > 2 && getDoc()->isEndFrameAtPos(newPos-1))
11590 			{
11591 				pFL = pView->getFrameLayout(newPos-2);
11592 				if(pFL)
11593 				{
11594 					newPos = pFL->getPosition(true);
11595 				}
11596 			}
11597 			m_dPosBeforeFootnote = m_dposPaste - newPos;
11598 			m_bMovedPos = true;
11599 			m_dposPaste = newPos;
11600 		}
11601 		getDoc()->insertObject(m_dposPaste, PTO_Field, propsArray, NULL);
11602 		m_dposPaste++;
11603 		if(m_posSavedDocPosition > 0)
11604 			m_posSavedDocPosition++;
11605 	}
11606 	g_free(propsArray);
11607 	m_bFieldRecognized = true;
11608 	return ok;
11609 }
11610 
11611 //////////////////////////////////////////////////////////////////
11612 //////////////////////////////////////////////////////////////////
11613 
pasteFromBuffer(PD_DocumentRange * pDocRange,const unsigned char * pData,UT_uint32 lenData,const char *)11614 bool IE_Imp_RTF::pasteFromBuffer(PD_DocumentRange * pDocRange,
11615 								 const unsigned char * pData, UT_uint32 lenData, const char * /* szEncoding */)
11616 {
11617 	UT_return_val_if_fail(getDoc() == pDocRange->m_pDoc,false);
11618 	UT_return_val_if_fail(pDocRange->m_pos1 == pDocRange->m_pos2,false);
11619 
11620 	m_pPasteBuffer = pData;
11621 	m_lenPasteBuffer = lenData;
11622 	m_pCurrentCharInPasteBuffer = pData;
11623 	m_dposPaste = pDocRange->m_pos1;
11624 	setClipboard(m_dposPaste);
11625 	m_dOrigPos = m_dposPaste;
11626 	// some values to start with -- most often we are somewhere in the middle of doc,
11627 	// i.e., in section and in block
11628 	m_newParaFlagged = false;
11629 	m_bSectionHasPara = true;
11630 	m_newSectionFlagged = false;
11631 
11632 	// we need to work out if we are in section and block
11633 	pf_Frag * pf = getDoc()->getFragFromPosition(m_dposPaste);
11634 
11635 	if(!pf)
11636 	{
11637 		// the doc is entirely empty
11638 		m_newParaFlagged = true;
11639 		m_bSectionHasPara = false;
11640 		m_newSectionFlagged = true;
11641 	}
11642 	else
11643 	{
11644 		// pf is a frag that starts at m_dposPaste -- we want the frag that ends there
11645 		pf = pf->getPrev();
11646 
11647 		// now find the nearest strux to the left
11648 		while(pf && pf->getType() != pf_Frag::PFT_Strux)
11649 			pf = pf->getPrev();
11650 
11651 		if(!pf)
11652 		{
11653 			// this is a malformed doc -- it has content but no stuxes !!!
11654 			UT_ASSERT_HARMLESS( UT_SHOULD_NOT_HAPPEN );
11655 			m_newParaFlagged = true;
11656 			m_bSectionHasPara = false;
11657 			m_newSectionFlagged = true;
11658 		}
11659 		else
11660 		{
11661 			// what kind of strux have we hit ?
11662 			pf_Frag_Strux * pfs = (pf_Frag_Strux*) pf;
11663 			switch(pfs->getStruxType())
11664 			{
11665 				case PTX_Block:
11666 				case PTX_EndFootnote:
11667 				case PTX_EndEndnote:
11668 					// we are ok
11669 					break;
11670 
11671 				default:
11672 					UT_ASSERT_HARMLESS( UT_SHOULD_NOT_HAPPEN );
11673 					// fall through
11674 
11675 				case PTX_Section:
11676 				case PTX_SectionHdrFtr:
11677 				case PTX_SectionEndnote:
11678 				case PTX_SectionTable:
11679 				case PTX_SectionCell:
11680 				case PTX_SectionFootnote:
11681 				case PTX_SectionMarginnote:
11682 				case PTX_SectionFrame:
11683 				case PTX_EndCell:
11684 				case PTX_EndTable:
11685 				case PTX_EndMarginnote:
11686 				case PTX_EndFrame:
11687 				case PTX_SectionTOC:
11688 				case PTX_EndTOC:
11689 				case PTX_StruxDummy:
11690 					// flag block
11691 					m_newParaFlagged = true;
11692 					m_bSectionHasPara = false;
11693 			}
11694 		}
11695 
11696 
11697 	}
11698 
11699 
11700 
11701 	UT_DEBUGMSG(("Pasting %d bytes of RTF\n",lenData));
11702 #if 1 //def DEBUG
11703 	{
11704 		const char * p = (const char*)pData;
11705 		for(UT_uint32 i = 0; i < lenData; i += 50)
11706 		{
11707 			if(lenData - i < 50)
11708 			{
11709 				std::string s(p);
11710 				UT_DEBUGMSG(("%s\n", s.c_str()));
11711 			}
11712 			else
11713 			{
11714 				std::string s(p, 50);
11715 				UT_DEBUGMSG(("%s\n", s.c_str()));
11716 				p += 50;
11717 			}
11718 		}
11719 	}
11720 #endif
11721 
11722 	// to do a paste, we set the fp to null and let the
11723 	// read-a-char routines know about our paste buffer.
11724 
11725 	UT_return_val_if_fail(m_pImportFile==NULL,false);
11726 
11727 	// note, we skip the _writeHeader() call since we don't
11728 	// want to assume that selection starts with a section
11729 	// break.
11730 	_parseFile(NULL);
11731 
11732 	if(m_newParaFlagged)
11733 	{
11734 //
11735 // Finish off any remaining stuff
11736 //
11737 		FlushStoredChars(false);
11738 	}
11739 	//
11740 	// Look if we're at the end of the document
11741 	//
11742 	PT_DocPosition posEnd;
11743 	getDoc()->getBounds(true,posEnd);
11744 	if(getDoc()->isEndTableAtPos(m_dposPaste-1))
11745 	{
11746 		if((posEnd==m_dposPaste) || (getDoc()->isSectionAtPos(m_dposPaste)) ||
11747 		   (getDoc()->isHdrFtrAtPos(m_dposPaste)))
11748 		{
11749 			getDoc()->insertStrux(m_dposPaste,PTX_Block);
11750 			m_dposPaste++;
11751 			if(m_posSavedDocPosition > 0)
11752 				m_posSavedDocPosition++;
11753 		}
11754 	}
11755 	m_pPasteBuffer = NULL;
11756 	m_lenPasteBuffer = 0;
11757 	m_pCurrentCharInPasteBuffer = NULL;
11758 	return true;
11759 }
11760 
11761 
11762 /*!
11763 Define a new style, here is the formal syntax:
11764 <style>	'{' <styledef>?<keycode>? <formatting> <additive>? <based>? <next>?
11765             <stylename>? ';' '}'
11766 <styledef>	\s  |\*\cs  | \ds
11767 <keycode>	'{' \keycode <keys> '}'
11768 <additive>	\additive
11769 <based>	\sbasedon
11770 <next>	\snext
11771 <autoupd>	\sautoupd
11772 <hidden>	\shidden
11773 <formatting>	(<brdrdef> | <parfmt> | <apoctl> | <tabdef> | <shading> | <chrfmt>)+
11774 <stylename>	#PCDATA
11775 <keys>	( \shift? & \ctrl? & \alt?) <key>
11776 <key>	\fn | #PCDATA
11777 
11778 The style definition is located within a {\stylesheet } sequence.
11779 
11780 The minimum (useless) example would be {}
11781 A more typical set of styles would be
11782 {\stylesheet
11783     {\fs20 \sbasedon222\snext0{\*\keycode \shift\ctrl n} Normal;}
11784 	{\s1\qr \fs20 \sbasedon0\snext1 FLUSHRIGHT;}
11785 	{\s2\fi-720\li720\fs20\ri2880\sbasedon0\snext2 IND;}
11786 }
11787 
11788 */
11789 
11790 #define RTF_BASEDON_NONE		222		// the default
11791 
HandleStyleDefinition(void)11792 bool IE_Imp_RTF::HandleStyleDefinition(void)
11793 {
11794 	bool status = true;
11795 	int nesting = 1;
11796 	unsigned char ch;
11797 	const char styleTypeP[] = "P";
11798 	const char styleTypeC[] = "C";
11799 	const char * styleType = styleTypeP;
11800 
11801 	UT_sint32 BasedOn[2000]; // 2000 styles. I know this should be a Vector.
11802 	UT_sint32 FollowedBy[2000]; // 2000 styles. I know this should be a Vector.
11803 	UT_sint32 styleCount = 0;
11804 	UT_GenericVector<UT_GenericVector<const gchar*>*> vecStyles;
11805 	RTFProps_ParaProps * pParas =  new RTFProps_ParaProps();
11806 	RTFProps_CharProps *  pChars = new	RTFProps_CharProps();
11807 	RTFProps_bParaProps * pbParas =  new RTFProps_bParaProps();
11808 	RTFProps_bCharProps *  pbChars = new	RTFProps_bCharProps();
11809 
11810 	static std::string propBuffer;
11811 
11812 	const gchar* attribs[PT_MAX_ATTRIBUTES*2 + 1];
11813 	UT_uint32 attribsCount=0;
11814 	UT_UCS4String styleName;// = "";
11815 	UT_sint32 styleNumber = 0;
11816 	while (nesting>0 && status == true)
11817 	{
11818         unsigned char keyword[MAX_KEYWORD_LEN];
11819         UT_sint32 parameter = 0;
11820 	    bool parameterUsed = false;
11821 
11822 		if (!ReadCharFromFile(&ch))
11823 		    return false;
11824 
11825 		switch(ch)
11826 		{
11827 		case '\\':
11828             status = ReadKeyword(keyword, &parameter, &parameterUsed, MAX_KEYWORD_LEN);
11829 			if (!status)
11830 			{
11831 				return status;
11832 			}
11833 			else if (strcmp(reinterpret_cast<const char *>(&keyword[0]), "'") == 0) {
11834 				/* FIXME really hackish. What if we have this in middle of keywords */
11835 				UT_UCS4Char wc;
11836 				wc = ReadHexChar();
11837 				styleName += wc;
11838 			}
11839 			else if (strcmp(reinterpret_cast<const char *>(&keyword[0]), "sbasedon") == 0)
11840 			{
11841 				if ((parameter != styleNumber) &&
11842 					(parameter != RTF_BASEDON_NONE))
11843 				{
11844 //
11845 // Have to deal with out of sequence styles. ie A style maybe basedon a style that
11846 // has not yet been seen.
11847 //
11848 // So remember it and fill it later..
11849 //
11850 					BasedOn[styleCount] = static_cast<UT_sint32>(parameter);
11851 					attribs[attribsCount++] = PT_BASEDON_ATTRIBUTE_NAME;
11852 					UT_return_val_if_fail( attribsCount < PT_MAX_ATTRIBUTES * 2,false );
11853 					attribs[attribsCount++] = NULL;
11854 					UT_return_val_if_fail( attribsCount < PT_MAX_ATTRIBUTES * 2,false );
11855 					attribs[attribsCount]   = NULL;
11856 				}
11857 				else if(0)
11858 				{
11859 					// TODO: Why is this code here? It left over from before the BasedOn array
11860 					const std::string & val = m_styleTable[parameter];
11861 					if (!val.empty())
11862 					{
11863 						attribs[attribsCount++] = PT_BASEDON_ATTRIBUTE_NAME;
11864 						UT_return_val_if_fail( attribsCount < PT_MAX_ATTRIBUTES * 2,false );
11865 						attribs[attribsCount++] = val.c_str();
11866 						UT_return_val_if_fail( attribsCount < PT_MAX_ATTRIBUTES * 2,false );
11867 						attribs[attribsCount]   = NULL;
11868 					}
11869 				}
11870 			}
11871 			else if (strcmp(reinterpret_cast<char*>(&keyword[0]), "snext") == 0)
11872 			{
11873 				if (parameter != styleNumber)
11874 				{
11875 //
11876 // Have to deal with out of sequence styles. ie A style may have a followed-by style
11877 // that has not yet been seen.
11878 //
11879 // So remember it and fill it later..
11880 //
11881 					FollowedBy[styleCount] = static_cast<UT_sint32>(parameter);
11882 					attribs[attribsCount++] = PT_FOLLOWEDBY_ATTRIBUTE_NAME;
11883 					UT_return_val_if_fail( attribsCount < PT_MAX_ATTRIBUTES * 2,false );
11884 					attribs[attribsCount++] = NULL;
11885 					UT_return_val_if_fail( attribsCount < PT_MAX_ATTRIBUTES * 2,false );
11886 					attribs[attribsCount]   = NULL;
11887 				}
11888 				else if(parameter < styleNumber)
11889 				{
11890 					// TODO: Why is this code here? It left over from before the FollowedBy array
11891 					const std::string & val = m_styleTable[parameter];
11892 					if (!val.empty())
11893 					{
11894 	               		attribs[attribsCount++] = PT_FOLLOWEDBY_ATTRIBUTE_NAME;
11895 						UT_return_val_if_fail( attribsCount < PT_MAX_ATTRIBUTES * 2,false );
11896 						attribs[attribsCount++] = val.c_str();
11897 						UT_return_val_if_fail( attribsCount < PT_MAX_ATTRIBUTES * 2,false );
11898 						attribs[attribsCount]   = NULL;
11899 					}
11900 				}
11901 			}
11902 			else if ((strcmp(reinterpret_cast<char*>(&keyword[0]),  "s") == 0) ||
11903 				     (strcmp(reinterpret_cast<char*>(&keyword[0]), "ds") == 0) ||
11904 					 (strcmp(reinterpret_cast<char*>(&keyword[0]), "ts") == 0))
11905 			{
11906 				styleNumber = parameter;
11907 				styleType = styleTypeP;
11908 				xxx_UT_DEBUGMSG(("Stylesheet RTF Found style number %d Paragraph type \n",styleNumber));
11909 			}
11910 			if (strcmp(reinterpret_cast<char*>(&keyword[0]), "cs") == 0)
11911 			{
11912 				styleNumber = parameter;
11913 				styleType = styleTypeC;
11914 				xxx_UT_DEBUGMSG(("Stylesheet: RTF Found style number %d Character type \n",styleNumber));
11915 			}
11916 			else if (strcmp(reinterpret_cast<char*>(&keyword[0]), "*") == 0)
11917 			{
11918 //
11919 // Get next keyword
11920 //
11921 				xxx_UT_DEBUGMSG(("Found * in StyleSheet reading \n"));
11922 			}
11923 			else
11924 			{
11925 			    status = ParseCharParaProps(static_cast<unsigned char *>(keyword), parameter, parameterUsed,pChars,pParas,pbChars,pbParas);
11926 			}
11927 			break;
11928 		case '{':
11929 			nesting++;
11930 			break;
11931 		case '}':
11932 			nesting--;
11933 			break;
11934 		default:
11935 			// The only thing that should be left is the style name
11936 
11937 			// clear the m_mbtowc buffer
11938 			m_mbtowc.initialize(true);
11939 
11940 			while (ch != '}' && ch != ';')
11941 			{
11942 				/*
11943 				   we have seen cases, including AbiWord, were stylename
11944 				   were generated with non ASCII names encoded as 8bits...
11945 				   We assume it is the document charset.
11946 				*/
11947 				UT_UCS4Char wc;
11948 				if(m_mbtowc.mbtowc(wc,static_cast<UT_Byte>(ch)))
11949 					styleName += wc;
11950 				else
11951 					styleName += ch;
11952 
11953                 if (!ReadCharFromFile(&ch)) {
11954 		            return false;
11955 				}
11956 				if (ch =='}')
11957 				{
11958 					UT_DEBUGMSG(("RTF: Badly formatted style name, no ';'"));
11959 					nesting--;
11960 				}
11961 			}
11962 			if(styleNumber >= 0)
11963 			{
11964 				std::vector<std::string>::size_type newSize = styleNumber + 1;
11965 				if(m_styleTable.size() < newSize) {
11966 					m_styleTable.resize(newSize);
11967 				}
11968 				m_styleTable[styleNumber] = styleName.utf8_str();
11969 			}
11970 			break;
11971 		}
11972 
11973 		// if the stylesheet is malformed there might be nothing in the table ...
11974 		if (nesting == 1 && static_cast<UT_sint32>(m_styleTable.size()) > styleNumber )
11975 		{
11976 			// Reached the end of a single style definition.
11977 			// Use it.
11978 			buildAllProps(propBuffer,pParas,pChars,pbParas,pbChars);
11979 			attribs[attribsCount++] = PT_PROPS_ATTRIBUTE_NAME;
11980 			UT_return_val_if_fail( attribsCount < PT_MAX_ATTRIBUTES * 2,false );
11981 			attribs[attribsCount++] = propBuffer.c_str();
11982 			UT_return_val_if_fail( attribsCount < PT_MAX_ATTRIBUTES * 2,false );
11983 
11984 			attribs[attribsCount++] = PT_NAME_ATTRIBUTE_NAME;
11985 			UT_return_val_if_fail( attribsCount < PT_MAX_ATTRIBUTES * 2,false );
11986 			attribs[attribsCount++] = m_styleTable[styleNumber].c_str();
11987 			UT_return_val_if_fail( attribsCount < PT_MAX_ATTRIBUTES * 2,false );
11988 
11989 			attribs[attribsCount++] = PT_TYPE_ATTRIBUTE_NAME;
11990 			UT_return_val_if_fail( attribsCount < PT_MAX_ATTRIBUTES * 2,false );
11991 			attribs[attribsCount++] = styleType;
11992 			UT_return_val_if_fail( attribsCount < PT_MAX_ATTRIBUTES * 2,false );
11993 //			attribs[attribsCount] = NULL;
11994 //
11995 // OK now we clone this and save it so we can set basedon's and followedby's
11996 //
11997 			UT_sint32 i =0;
11998 			UT_GenericVector<const gchar*>* pVecAttr = new UT_GenericVector<const gchar*>();
11999 			for( i= 0; i< static_cast<UT_sint32>(attribsCount); i++)
12000 			{
12001 				if(attribs[i] != NULL)
12002 				{
12003 					pVecAttr->addItem(g_strdup(attribs[i]));
12004 				}
12005 				else
12006 				{
12007 					pVecAttr->addItem(NULL);
12008 				}
12009 			}
12010 			vecStyles.addItem(pVecAttr);
12011 
12012 			// Reset
12013 			styleCount++;
12014 			attribsCount = 0;
12015 			attribs[attribsCount] = NULL;
12016 			styleNumber = 0;
12017 			styleName = "";
12018 			styleType = "P";
12019 			DELETEP(pParas);
12020 			DELETEP(pChars);
12021 			DELETEP(pbParas);
12022 			DELETEP(pbChars);
12023 			pParas =  new RTFProps_ParaProps();
12024 			pChars = new	RTFProps_CharProps();
12025 			pbParas =  new RTFProps_bParaProps();
12026 			pbChars = new	RTFProps_bCharProps();
12027 			propBuffer.clear();
12028 		}
12029 	}
12030 //
12031 // Finished Style definitions
12032 //
12033 	DELETEP(pParas);
12034 	DELETEP(pChars);
12035 	DELETEP(pbParas);
12036 	DELETEP(pbChars);
12037 //
12038 // Now we loop through them all and write them into our document.
12039 //
12040 	UT_sint32 count = vecStyles.getItemCount();
12041 	UT_sint32 i = 0;
12042 	for(i=0; i< count; i++)
12043 	{
12044 		// Reset
12045 
12046 		attribsCount = 0;
12047 		attribs[attribsCount] = NULL;
12048 		UT_GenericVector<const gchar*> * pCurStyleVec = vecStyles.getNthItem(i);
12049 		UT_sint32 nAtts = pCurStyleVec->getItemCount();
12050 		UT_sint32 j = 0;
12051 		const char * szName = NULL;
12052 
12053 		while(j < nAtts)
12054 		{
12055 			const char * szAtt = pCurStyleVec->getNthItem(j++);
12056 			attribs[attribsCount++] = szAtt;
12057 			if( strcmp(szAtt, PT_NAME_ATTRIBUTE_NAME)== 0)
12058 			{
12059 				szName = pCurStyleVec->getNthItem(j++);
12060 				attribs[attribsCount++] = szName;
12061 			}
12062 			else if( strcmp(szAtt, PT_BASEDON_ATTRIBUTE_NAME)== 0)
12063 			{
12064 				const char * szNext = pCurStyleVec->getNthItem(j++);
12065 				if(NULL == szNext)
12066 				{
12067 					UT_sint32 istyle = BasedOn[i];
12068 					// must not mix static and dynamically allocated strings in the same
12069 					// array, otherwise there is no way we can g_free it !!!
12070 					//attribs[attribsCount++] = g_strdup(static_cast<const char *>(m_styleTable[istyle]));
12071 					if (istyle >= 0 && static_cast<UT_uint32>(istyle) < m_styleTable.size()) {
12072 						attribs[attribsCount++] = m_styleTable[istyle].c_str();
12073 					} else {
12074 						UT_WARNINGMSG(("RTF: basedon by style index out of bounds: %d. max %lu.\n",
12075 									   istyle, m_styleTable.size()));
12076 						attribs[attribsCount++] = NULL;
12077 					}
12078 					UT_return_val_if_fail( attribsCount < PT_MAX_ATTRIBUTES * 2,false );
12079 				}
12080 				else
12081 				{
12082 					attribs[attribsCount++] = szNext;
12083 					UT_return_val_if_fail( attribsCount < PT_MAX_ATTRIBUTES * 2,false );
12084 				}
12085 			}
12086 			else if( strcmp(szAtt, PT_FOLLOWEDBY_ATTRIBUTE_NAME)== 0)
12087 			{
12088 				const char * szNext = pCurStyleVec->getNthItem(j++);
12089 				if(NULL == szNext)
12090 				{
12091 					UT_sint32 istyle = FollowedBy[i];
12092 					// must not mix static and dynamically allocated strings in the same
12093 					// array, otherwise there is no way we can g_free it !!!
12094 					// attribs[attribsCount++] = g_strdup(static_cast<const char *>(m_styleTable[istyle]));
12095 					if (istyle >= 0 && static_cast<UT_uint32>(istyle) < m_styleTable.size()) {
12096 						attribs[attribsCount++] = m_styleTable[istyle].c_str();
12097 					} else {
12098 						UT_WARNINGMSG(("RTF: followed by style index out of bounds: %d. max %lu.\n",
12099 									   istyle, m_styleTable.size()));
12100 						attribs[attribsCount++] = NULL;
12101 					}
12102 					UT_return_val_if_fail( attribsCount < PT_MAX_ATTRIBUTES * 2,false );
12103 				}
12104 				else
12105 				{
12106 					attribs[attribsCount++] = szNext;
12107 					UT_return_val_if_fail( attribsCount < PT_MAX_ATTRIBUTES * 2,false );
12108 				}
12109 			}
12110 			else
12111 			{
12112 				szAtt = pCurStyleVec->getNthItem(j++);
12113 				attribs[attribsCount++] = szAtt;
12114 				UT_return_val_if_fail( attribsCount < PT_MAX_ATTRIBUTES * 2,false );
12115 			}
12116 			attribs[attribsCount] = NULL;
12117 		}
12118 //
12119 // If style exists we have to redefine it like this
12120 //
12121 		// need to test that we have a name, as there are some malformed docs around ...
12122 		if(szName && *szName)
12123 		{
12124 			xxx_UT_DEBUGMSG(("Looking at style %s \n",szName));
12125 			PD_Style * pStyle = NULL;
12126 			if(getDoc()->getStyle(szName, &pStyle))
12127 			{
12128 				if (!isPasting())
12129 				{
12130 					pStyle->addAttributes(attribs);
12131 					pStyle->getBasedOn();
12132 					pStyle->getFollowedBy();
12133 				}
12134 				else
12135 				{
12136 					UT_DEBUGMSG(("DOM: refusing to append props to an already existing style while pasting\n"));
12137 				}
12138 			}
12139 			else
12140 			{
12141 				getDoc()->appendStyle(attribs);
12142 			}
12143 		}
12144 
12145 //
12146 // OK Now delete all this allocated memory...
12147 //
12148 		for(j=0; j< nAtts; j++)
12149 		{
12150 			const gchar * sz = pCurStyleVec->getNthItem(j);
12151 			if(sz != NULL)
12152 			{
12153 				// MUST NOT USED delete[] on strings allocated by g_try_malloc/UT_calloc !!!
12154 				// delete [] sz;
12155 				g_free(const_cast<gchar*>(sz));
12156 				sz = NULL;
12157 			}
12158 		}
12159 		delete pCurStyleVec;
12160 
12161 	}
12162 	status = PopRTFState();
12163 	m_bStyleImportDone = true;
12164 	return status;
12165 
12166 }
12167 
12168 /*!
12169  * This method builds the property list from Paragraph and character classes pParas
12170  * and pChars
12171  */
buildAllProps(std::string & s,RTFProps_ParaProps * pParas,RTFProps_CharProps * pChars,RTFProps_bParaProps * pbParas,RTFProps_bCharProps * pbChars)12172 bool IE_Imp_RTF::buildAllProps(std::string &s,  RTFProps_ParaProps * pParas,
12173 							   RTFProps_CharProps * pChars,
12174 							   RTFProps_bParaProps * pbParas,
12175 							   RTFProps_bCharProps * pbChars)
12176 {
12177 //
12178 // Tab stops.
12179 //
12180 	std::string tempBuffer;
12181 	UT_sint32 count =pParas->m_tabStops.size();
12182 	if(count > 0)
12183 		s += "tabstops:";
12184 	UT_sint32 i=0;
12185 	for (i = 0; i < count; i++)
12186 	{
12187 		if (i > 0)
12188 			s += ",";
12189 
12190 		UT_sint32 tabTwips = pParas->m_tabStops.at(i);
12191 		double tabIn = tabTwips/(20.0*72.);
12192 		eTabType tabType = pParas->m_tabTypes.at(i);
12193 		eTabLeader tabLeader = pParas->m_tabLeader.at(i);
12194 		char  cType = ' ';
12195 		switch(tabType)
12196 		{
12197 		case FL_TAB_LEFT:
12198 			cType ='L';
12199 			break;
12200 		case FL_TAB_RIGHT:
12201 			cType ='R';
12202 			break;
12203 		case FL_TAB_CENTER:
12204 			cType ='C';
12205 			break;
12206 		case FL_TAB_DECIMAL:
12207 			cType ='D';
12208 			break;
12209 		case FL_TAB_BAR:
12210 			cType ='B';
12211 			break;
12212 		default:
12213 			UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
12214 		}
12215 		char cLeader = '0' + static_cast<char>(tabLeader);
12216 		s += UT_std_string_sprintf("%s/%c%c", UT_convertInchesToDimensionString(DIM_IN,tabIn,"04"),cType,cLeader);
12217 	}
12218 	if( count > 0)
12219 		s += "; ";
12220 //
12221 // Top and bottom paragraph margins
12222 //
12223 	if(pbParas->bm_spaceBefore)
12224 	{
12225 		s += UT_std_string_sprintf("margin-top:%s; ",		UT_convertInchesToDimensionString(DIM_IN, static_cast<double>(pParas->m_spaceBefore)/1440));
12226 	}
12227 	if(pbParas->bm_spaceAfter)
12228 	{
12229 		s += UT_std_string_sprintf("margin-bottom:%s; ",	UT_convertInchesToDimensionString(DIM_IN, static_cast<double>(pParas->m_spaceAfter)/1440));
12230 	}
12231 //
12232 // Left and right margins
12233 //
12234 	if(pbParas->bm_indentLeft)
12235 	{
12236 		s += UT_std_string_sprintf("margin-left:%s; ",		UT_convertInchesToDimensionString(DIM_IN, static_cast<double>(pParas->m_indentLeft)/1440));
12237 	}
12238 	if(pbParas->bm_indentRight)
12239 	{
12240 		s += UT_std_string_sprintf("margin-right:%s; ",	UT_convertInchesToDimensionString(DIM_IN, static_cast<double>(pParas->m_indentRight)/1440));
12241 	}
12242 //
12243 // First line indent
12244 //
12245 
12246 	if(pbParas->bm_indentFirst)
12247 	{
12248 		s += UT_std_string_sprintf("text-indent:%s; ",	UT_convertInchesToDimensionString(DIM_IN, static_cast<double>(pParas->m_indentFirst)/1440));
12249 	}
12250 
12251 //
12252 // line spacing
12253 //
12254 	if(pbParas->bm_lineSpaceVal)
12255 	{
12256 		if (pParas->m_lineSpaceExact)
12257 		{
12258 			if (pParas->m_lineSpaceVal < 0) {  // exact spacing
12259 				s += UT_std_string_sprintf("line-height:%spt; ",    UT_convertToDimensionlessString(fabs(pParas->m_lineSpaceVal/20.0)));
12260 			}
12261 			else                                                         // "at least" spacing
12262 			{
12263 				s += UT_std_string_sprintf("line-height:%spt+; ",    UT_convertToDimensionlessString(fabs(pParas->m_lineSpaceVal/20.0)));
12264 			}
12265 		}
12266 		else   // multiple spacing
12267 		{
12268 			s += UT_std_string_sprintf("line-height:%s; ",	UT_convertToDimensionlessString(fabs(pParas->m_lineSpaceVal/240)));
12269 		}
12270 	}
12271 
12272 //
12273 // justification
12274 //
12275 	if (pbParas->bm_justification)
12276 	{
12277 		s += "text-align:";
12278 		switch(pParas->m_justification)
12279 		{
12280 			case RTFProps_ParaProps::pjCentre:
12281 				s += "center; ";
12282 				break;
12283 		    case RTFProps_ParaProps::pjRight:
12284 			    s += "right; ";
12285 			    break;
12286 		    case RTFProps_ParaProps::pjFull:
12287 			    s += "justify; ";
12288 		     	break;
12289 		    default:
12290 			    UT_ASSERT_NOT_REACHED();	// so what is it?
12291 			    // fall through
12292 		    case RTFProps_ParaProps::pjLeft:
12293 			    s += "left; ";
12294 			    break;
12295 		}
12296 	}
12297 
12298 //
12299 // Character Properties.
12300 //
12301 	// bold
12302 	if(pbChars->bm_bold)
12303 	{
12304 		s += "font-weight:";
12305 		s += pChars->m_bold ? "bold" : "normal";
12306 		s += ";";
12307 	}
12308 	// italic
12309 	if(pbChars->bm_italic)
12310 	{
12311 		s += " font-style:";
12312 		s += pChars->m_italic ? "italic" : "normal";
12313 		s += ";";
12314 	}
12315 	// underline & overline & strike-out
12316 	if(pbChars->bm_underline || pbChars->bm_strikeout || pbChars->bm_overline
12317 	   || pbChars->bm_topline || pbChars->bm_botline )
12318 	{
12319 		s += "; text-decoration:";
12320 		static std::string decors;
12321 		decors.clear();
12322 		if (pChars->m_underline)
12323 		{
12324 			decors += "underline ";
12325 		}
12326 		if (pChars->m_strikeout)
12327 		{
12328 			decors += "line-through ";
12329 		}
12330 		if (pChars->m_overline)
12331 		{
12332 			decors += "line-through ";
12333 		}
12334 		if (pChars->m_topline)
12335 		{
12336 			decors += "line-through ";
12337 		}
12338 		if (pChars->m_botline)
12339 		{
12340 			decors += "line-through ";
12341 		}
12342 		if(!pChars->m_underline  &&
12343 		   !pChars->m_strikeout &&
12344 		   !pChars->m_overline &&
12345 		   !pChars->m_topline &&
12346 		   !pChars->m_botline)
12347 		{
12348 			decors = "none";
12349 		}
12350 		s += decors;
12351 		s += ";";
12352 	}
12353 	//superscript and subscript
12354 	if(pbChars->bm_superscript || pbChars->bm_subscript)
12355 	{
12356 		s += " text-position:";
12357 		if (pChars->m_superscript)
12358 		{
12359 			if (pbChars->bm_superscript_pos)
12360 			{
12361 				UT_DEBUGMSG (("RTF: TODO: Handle text position in pt.\n"));
12362 			}
12363 			s += "superscript;";
12364 		}
12365 		else if (pChars->m_subscript)
12366 		{
12367 			if (pbChars->bm_subscript_pos)
12368 			{
12369 				UT_DEBUGMSG (("RTF: TODO: Handle text position in pt.\n"));
12370 			}
12371 			s += "subscript;";
12372 		}
12373 		else
12374 		{
12375 			s += "normal;";
12376 		}
12377 	}
12378 
12379 	// font size
12380 	if(pbChars->bm_fontSize)
12381 	{
12382 		s += UT_std_string_sprintf(" font-size:%spt;", std_size_string(static_cast<float>(pChars->m_fontSize)));
12383 	}
12384 	// typeface
12385 	if(pbChars->bm_fontNumber)
12386 	{
12387 		RTFFontTableItem* pFont = GetNthTableFont(pChars->m_fontNumber);
12388 		if (pFont != NULL)
12389 		{
12390 			s += " font-family:";
12391 			s += pFont->m_pFontName;
12392 			s += ";";
12393 		}
12394 	}
12395 	// Foreground Colour
12396 	if(pbChars->bm_hasColour)
12397 	{
12398 		if (pChars->m_hasColour)
12399 		{
12400 			// colour, only if one has been set. See bug 1324
12401 			UT_uint32 colour = GetNthTableColour(pChars->m_colourNumber);
12402 			s += UT_std_string_sprintf(" color:%06x;", colour);
12403 		}
12404 	}
12405 	// BackGround Colour
12406 	if (pbChars->bm_hasBgColour)
12407 	{
12408 		if(pbChars->bm_hasBgColour)
12409 		{
12410 			// colour, only if one has been set. See bug 1324
12411 			UT_sint32 bgColour = GetNthTableBgColour(pChars->m_bgcolourNumber);
12412 			if (bgColour != -1) // invalid and should be white
12413 			{
12414 				s += UT_std_string_sprintf(" bgcolor:%06x;", bgColour);
12415 			}
12416 		}
12417 	}
12418 // Language
12419 	if (pChars->m_szLang)
12420 	{
12421 		s += " lang:";
12422 		s += pChars->m_szLang;
12423 		s += ";";
12424 	}
12425 // List Tag to hang lists off
12426 	if(pbChars->bm_listTag)
12427 	{
12428 		s += UT_std_string_sprintf(" list-tag:%d; ",pChars->m_listTag);
12429 	}
12430 //
12431 // Now remove any trailing ";"'s
12432 //
12433 	UT_sint32 eol = s.length() - 1;
12434 	while(eol >= 0 && (s[eol] == ' ' || s[eol] == 0))
12435 	{
12436 		eol--;
12437 	}
12438 	if(eol >= 0 && s[eol] == ';')
12439 	{
12440 		s[eol] = 0;
12441 	}
12442 	return true;
12443 }
12444 
12445 
12446 /*!
12447   Handle document meta data
12448  */
HandleInfoMetaData()12449 bool IE_Imp_RTF::HandleInfoMetaData()
12450 {
12451 	RTF_KEYWORD_ID keywordID;
12452 	RTFTokenType tokenType;
12453 	unsigned char keyword[MAX_KEYWORD_LEN];
12454 	UT_sint32 parameter = 0;
12455 	bool paramUsed = false;
12456 	int nested = 0;
12457 	//bool result;
12458 	const char * metaDataKey = NULL;
12459 	std::string metaDataProp;
12460 	enum {
12461 		ACT_NONE,
12462 		ACT_PCDATA,
12463 		ACT_DATETIME
12464 	} action = ACT_NONE;
12465 
12466 	// Since the metadata group is enclosed between brackets, a new RTF state was generated. Remove it now.
12467 	// The closing bracket will be ignored.
12468 	PopRTFState();
12469 	do {
12470 		tokenType = NextToken (keyword, &parameter, &paramUsed, MAX_KEYWORD_LEN,false);
12471 		switch (tokenType) {
12472 		case RTF_TOKEN_ERROR:
12473 			UT_ASSERT_NOT_REACHED();
12474 			return false;
12475 			break;
12476 		case RTF_TOKEN_KEYWORD:
12477 			keywordID = KeywordToID(reinterpret_cast<char *>(keyword));
12478 
12479 			switch(keywordID) {
12480 			case RTF_KW_title:
12481 				metaDataKey = PD_META_KEY_TITLE;
12482 				action = ACT_PCDATA;
12483 				break;
12484 			case RTF_KW_subject:
12485 				metaDataKey = PD_META_KEY_SUBJECT;
12486 				action = ACT_PCDATA;
12487 				break;
12488 			case RTF_KW_author:
12489 				metaDataKey = PD_META_KEY_CREATOR;
12490 				action = ACT_PCDATA;
12491 				break;
12492 			case RTF_KW_manager:
12493 				metaDataKey = PD_META_KEY_PUBLISHER;
12494 				action = ACT_PCDATA;
12495 				break;
12496 			case RTF_KW_company:
12497 				/*result =*/ SkipCurrentGroup();
12498 				action = ACT_NONE;
12499 				break;
12500 			case RTF_KW_operator:
12501 				/*result =*/ SkipCurrentGroup();
12502 				action = ACT_NONE;
12503 				break;
12504 			case RTF_KW_keywords:
12505 				metaDataKey = PD_META_KEY_KEYWORDS;
12506 				action = ACT_PCDATA;
12507 				break;
12508 			case RTF_KW_comment:
12509 				/*result =*/ SkipCurrentGroup();
12510 				action = ACT_NONE;
12511 				break;
12512 			case RTF_KW_doccomm:
12513 				metaDataKey = PD_META_KEY_DESCRIPTION;
12514 				action = ACT_PCDATA;
12515 				break;
12516 			case RTF_KW_hlinkbase:
12517 				/*result =*/ SkipCurrentGroup();
12518 				action = ACT_NONE;
12519 				break;
12520 			case RTF_KW_creatim:
12521 				metaDataKey = PD_META_KEY_DATE;
12522 				action = ACT_NONE;
12523 				break;
12524 			case RTF_KW_revtim:
12525 				metaDataKey = PD_META_KEY_DATE_LAST_CHANGED;
12526 				action = ACT_DATETIME;
12527 				break;
12528 			case RTF_KW_printim:
12529 				/*result =*/ SkipCurrentGroup();
12530 				action = ACT_NONE;
12531 				break;
12532 			case RTF_KW_buptim:
12533 				/*result =*/ SkipCurrentGroup();
12534 				action = ACT_NONE;
12535 				break;
12536 			default:
12537 				/*result =*/ SkipCurrentGroup();
12538 				action = ACT_NONE;
12539 			}
12540 			if (action == ACT_PCDATA) {
12541 				metaDataProp = "";
12542 				/*result =*/ HandlePCData(metaDataProp);
12543 			}
12544 			else if (action == ACT_DATETIME) {
12545 				/*result =*/ SkipCurrentGroup();
12546 				action = ACT_NONE;
12547 				//result = HandlMetaDataTime(&metaTime);
12548 			}
12549 			// if any action needs to be done
12550 			if (action !=  ACT_NONE) {
12551 				getDoc()->setMetaDataProp(metaDataKey, metaDataProp);
12552 			}
12553 			break;
12554 		case RTF_TOKEN_OPEN_BRACE:
12555 			nested++;
12556 			break;
12557 		case RTF_TOKEN_CLOSE_BRACE:
12558 			nested--;
12559 			break;
12560 		case RTF_TOKEN_DATA:
12561 			// Ignore data because we don't know what to do with it
12562 			break;
12563 		default:
12564 			break;
12565 		}
12566 	} while ((tokenType != RTF_TOKEN_CLOSE_BRACE) || (nested >= 0));
12567 	return true;
12568 }
12569 
HandlePCData(std::string & str)12570 bool IE_Imp_RTF::HandlePCData(std::string& str)
12571 {
12572 	UT_UTF8String t;
12573 	bool ret = HandlePCData(t);
12574 	str = t.utf8_str();
12575 	return ret;
12576 }
12577 
12578 /*
12579  * TODO:
12580  * This reads PCData until it reaches a terminating '}'.
12581  * It assumes that a PCData block will not contain sub-groups. This may well be
12582  * fine but we should check the spec. If there is a sub-group then it's closing
12583  * brace will close the PCData block.
12584  *
12585  * Also we assume that the \uc keyword cannot appear.
12586  *
12587  * In general, I think the handling of keywords within this function is
12588  * extremely dangerous. They should be pushed back onto the stream and left for
12589  * the caller to deal with. Otherwise, a "\b" in the header would cause the
12590  * start of the document to be bold as well, for example.
12591  */
HandlePCData(UT_UTF8String & str)12592 bool IE_Imp_RTF::HandlePCData(UT_UTF8String & str)
12593 {
12594 	RTF_KEYWORD_ID keywordID;
12595 	RTFTokenType tokenType;
12596 	unsigned char keyword[MAX_KEYWORD_LEN];
12597 	UT_sint32 parameter = 0;
12598 	bool paramUsed = false;
12599 	bool bStop = false;
12600 	UT_ByteBuf buf;
12601 	UT_sint32 iUniCharsLeftToSkip = 0;
12602 
12603 	do {
12604 		tokenType = NextToken (keyword, &parameter, &paramUsed, MAX_KEYWORD_LEN, false);
12605 		switch (tokenType) {
12606 		case RTF_TOKEN_KEYWORD:
12607 			keywordID = KeywordToID(reinterpret_cast<char *>(keyword));
12608 			switch(keywordID)
12609 			{
12610 			case RTF_KW_QUOTE:
12611 			{
12612 				UT_UCS4Char wc;
12613 				UT_Byte ch;
12614 				wc = ReadHexChar();
12615 				// here we assume that the read char fit on ONE byte. Should be correct.
12616 				ch = static_cast<UT_Byte>(wc);
12617 				buf.append(&ch, 1);
12618 				break;
12619 			}
12620 			case RTF_KW_u:
12621 			{
12622 				UT_UCS2Char ch = 0;
12623 				/* RTF is limited to +/-32K ints so we need to use negative
12624 				 * numbers for large unicode values. So, check for Unicode chars
12625 				 * wrapped to negative values.
12626 		 		 */
12627 				if (parameter < 0)
12628 				{
12629 					unsigned short tmp = (unsigned short) ((signed short) parameter);
12630 					parameter = (UT_sint32) tmp;
12631 				}
12632 				ch = parameter;
12633 
12634 				// First flush any data in the byte buffer to str. Then append
12635 				// the unicode char.
12636 				str.appendBuf(buf, m_mbtowc);
12637 				buf.truncate(0);
12638 				str.appendUCS2(&ch, 1);
12639 
12640 				// Make sure we skip alternative chars.
12641 				iUniCharsLeftToSkip = m_currentRTFState.m_unicodeAlternateSkipCount;
12642 				break;
12643 			}
12644 			case RTF_KW_uc:
12645 				// A little bit evil, but I'd like to know if this happens! - R.Kay
12646 				UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
12647 			default:
12648 				bStop = true; // regular keyword stop reading data and handle it
12649 				break;
12650 			}
12651 			break;
12652 		case RTF_TOKEN_DATA:
12653 			// Don't append data if we're skipping a unicode alternative.
12654 			if (iUniCharsLeftToSkip > 0)
12655 				iUniCharsLeftToSkip--;
12656 			else
12657 				buf.append(keyword, 1);
12658 			break;
12659 		case RTF_TOKEN_ERROR:
12660 			// force close brace to exit loop
12661 			tokenType = RTF_TOKEN_CLOSE_BRACE;
12662 			break;
12663 		case RTF_TOKEN_OPEN_BRACE:
12664 			// A little bit evil, but I'd like to know if this happens! - R.Kay
12665 			UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
12666 			break;
12667 		case RTF_TOKEN_CLOSE_BRACE:
12668 			SkipBackChar('}');
12669 			break;
12670 		default:
12671 			UT_DEBUGMSG(("Unknown token !!!!!!!!!!!\n"));
12672 			break;
12673 		}
12674 	}
12675 	while ((tokenType != RTF_TOKEN_CLOSE_BRACE) && !bStop);
12676 
12677 	/*
12678 	 * TODO: Think about how much sense handling keywords here makes.
12679 	 * What keywords are legal and where should the changes they make appear?
12680 	 * (E.g. in the document, in the header) It probably depends on where this
12681 	 * function is called.
12682 	 */
12683 	str.appendBuf(buf, m_mbtowc);
12684 	if(bStop)
12685 	{
12686 		//
12687 		// Have to insert the data before we process the keyword
12688 		//
12689 		const char * sz = str.utf8_str();
12690 		while(*sz)
12691 		{
12692 			ParseChar(*sz);
12693 			sz++;
12694 		}
12695 		keywordID = KeywordToID(reinterpret_cast<char *>(keyword));
12696 		TranslateKeywordID(keywordID, parameter, paramUsed);
12697 		str.clear();
12698 	}
12699 
12700 	return true;
12701 }
12702 
12703 /*
12704  * Activates the appropriate encoding. This will be the document default, set by
12705  * \ansicpg, unless overridden by the current font.
12706  */
setEncoding()12707 void IE_Imp_RTF::setEncoding() {
12708 	RTFFontTableItem *pFont;
12709 
12710 	// Activate the current encoding.
12711 	pFont = GetNthTableFont(m_currentRTFState.m_charProps.m_fontNumber);
12712 	if (pFont != NULL && pFont->m_szEncoding) {
12713 		m_mbtowc.setInCharset(pFont->m_szEncoding);
12714 	}
12715 	else if (m_szDefaultEncoding != NULL) {
12716 		m_mbtowc.setInCharset(m_szDefaultEncoding);
12717 	}
12718 }
12719 
12720 
12721