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, ¶meter, ¶meterUsed, 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, ¶meter, ¶meterUsed, 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*>(¶meter[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, ¶meter, ¶mUsed, 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, ¶meter, ¶mUsed, 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, ¶meter, ¶mUsed, 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, ¶meter, ¶mUsed, 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, ¶meter, ¶mUsed, 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, ¶meter_star, ¶meterUsed_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, ¶meter_star, ¶meterUsed_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, ¶meter, ¶mUsed, 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, ¶meter, ¶mUsed, 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, ¶meter, ¶mUsed, 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, ¶meter, ¶mUsed, 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, ¶meter, ¶mUsed, 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, ¶meter, ¶mUsed, 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, ¶meter, ¶mUsed, 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, ¶meter,& 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**>(¤tState)))
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 *>(¶meter), 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**>(¤tState)))
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, ¶meter, ¶mUsed, 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, ¶meter, ¶mUsed, 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, ¶meter, ¶mUsed, 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, ¶meter, ¶mUsed, 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, ¶meter, ¶mUsed, 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, ¶meter, ¶meterUsed, 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, ¶meter, ¶mUsed, 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, ¶meter, ¶mUsed, 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