1 /* -*- mode: C++; tab-width: 4; c-basic-offset: 4; -*- */
2 
3 /* AbiWord
4  * Copyright (C) 2001 AbiSource, Inc.
5  * Copyright (C) 2002-2004 Marc Maurer (uwog@uwog.net)
6  * Copyright (C) 2002-2005 William Lachance (william.lachance@sympatico.ca)
7  * Copyright (C) 2006 Fridrich Strba (fridrich.strba@bluewin.ch)
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 /* See bug 1764
26  * "This product is not manufactured, approved, or supported by
27  * Corel Corporation or Corel Corporation Limited."
28  */
29 
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <math.h>
34 #include <map>
35 #include <string>
36 #include <gsf/gsf-utils.h>
37 #include <gsf/gsf-input-memory.h>
38 #include <gsf/gsf-input-stdio.h>
39 
40 #include "ut_types.h"
41 #include "ut_string.h"
42 #include "ut_string_class.h"
43 #include "ut_units.h"
44 #include "ut_growbuf.h"
45 #include "ut_assert.h"
46 #include "ut_debugmsg.h"
47 #include "ut_math.h" // for rint (font size)
48 #include "ut_rand.h"
49 #include "ut_locale.h"
50 
51 #include "xap_Frame.h"
52 #include "xap_EncodingManager.h"
53 
54 #include "pd_Document.h"
55 #include "pt_Types.h"
56 
57 #include "fl_AutoLists.h"
58 #include "fl_AutoNum.h"
59 
60 #include "ie_imp_WordPerfect.h"
61 #include "ie_impexp_WordPerfect.h"
62 
63 // Stream class
64 
65 #include <librevenge-stream/librevenge-stream.h>
66 #include <libwpd/libwpd.h>
67 
68 #include <gsf/gsf-input.h>
69 #include <gsf/gsf-infile.h>
70 #include <gsf/gsf-infile-msole.h>
71 #include <gsf/gsf-infile-zip.h>
72 
73 #ifdef HAVE_LIBWPS
74 #include <libwps/libwps.h>
75 #endif
76 
77 class AbiWordperfectInputStream : public librevenge::RVNGInputStream
78 {
79 public:
80 	AbiWordperfectInputStream(GsfInput *input);
81 	~AbiWordperfectInputStream();
82 
83 	virtual bool isStructured();
84 	virtual unsigned subStreamCount();
85 	virtual const char* subStreamName(unsigned);
86 	bool existsSubStream(const char*);
87 	virtual librevenge::RVNGInputStream* getSubStreamByName(const char*);
88 	virtual librevenge::RVNGInputStream* getSubStreamById(unsigned);
89 	virtual const unsigned char *read(unsigned long numBytes, unsigned long &numBytesRead);
90 	virtual int seek(long offset, librevenge::RVNG_SEEK_TYPE seekType);
91 	virtual long tell();
92 	virtual bool isEnd();
93 
94 private:
95 
96 	GsfInput *m_input;
97 	GsfInfile *m_ole;
98 	std::map<unsigned, std::string> m_substreams;
99 };
100 
AbiWordperfectInputStream(GsfInput * input)101 AbiWordperfectInputStream::AbiWordperfectInputStream(GsfInput *input) :
102 	librevenge::RVNGInputStream(),
103 	m_input(input),
104 	m_ole(NULL),
105 	m_substreams()
106 {
107 	g_object_ref(G_OBJECT(input));
108 }
109 
~AbiWordperfectInputStream()110 AbiWordperfectInputStream::~AbiWordperfectInputStream()
111 {
112 	if (m_ole)
113 		g_object_unref(G_OBJECT(m_ole));
114 
115 	g_object_unref(G_OBJECT(m_input));
116 }
117 
read(unsigned long numBytes,unsigned long & numBytesRead)118 const unsigned char * AbiWordperfectInputStream::read(unsigned long numBytes, unsigned long &numBytesRead)
119 {
120 	const unsigned char *buf = gsf_input_read(m_input, numBytes, NULL);
121 
122 	if (buf == NULL)
123 		numBytesRead = 0;
124 	else
125 		numBytesRead = numBytes;
126 
127 	return buf;
128 }
129 
seek(long offset,librevenge::RVNG_SEEK_TYPE seekType)130 int AbiWordperfectInputStream::seek(long offset, librevenge::RVNG_SEEK_TYPE seekType)
131 {
132 	GSeekType gsfSeekType = G_SEEK_SET;
133 	switch(seekType)
134 	{
135 	case librevenge::RVNG_SEEK_CUR:
136 		gsfSeekType = G_SEEK_CUR;
137 		break;
138 	case librevenge::RVNG_SEEK_SET:
139 		gsfSeekType = G_SEEK_SET;
140 		break;
141 	case librevenge::RVNG_SEEK_END:
142 		gsfSeekType = G_SEEK_END;
143 		break;
144 	}
145 
146 	return gsf_input_seek(m_input, offset, gsfSeekType);
147 }
148 
isStructured()149 bool AbiWordperfectInputStream::isStructured()
150 {
151 	if (!m_ole)
152 		m_ole = GSF_INFILE(gsf_infile_msole_new (m_input, NULL));
153 
154 	if (!m_ole)
155 		m_ole = GSF_INFILE(gsf_infile_zip_new (m_input, NULL));
156 
157 	if (m_ole)
158 		return true;
159 
160 	return false;
161 }
162 
subStreamCount()163 unsigned AbiWordperfectInputStream::subStreamCount()
164 {
165 	if (!m_ole)
166 		m_ole = GSF_INFILE(gsf_infile_msole_new (m_input, NULL));
167 
168 	if (!m_ole)
169 		m_ole = GSF_INFILE(gsf_infile_zip_new (m_input, NULL));
170 
171 	if (m_ole)
172 		{
173 			int numChildren = gsf_infile_num_children(m_ole);
174 			if (numChildren > 0)
175 				return numChildren;
176 			return 0;
177 		}
178 
179 	return 0;
180 }
181 
subStreamName(unsigned id)182 const char * AbiWordperfectInputStream::subStreamName(unsigned id)
183 {
184 	if (!m_ole)
185 		m_ole = GSF_INFILE(gsf_infile_msole_new (m_input, NULL));
186 
187 	if (!m_ole)
188 		m_ole = GSF_INFILE(gsf_infile_zip_new (m_input, NULL));
189 
190 	if (m_ole)
191 		{
192 			if ((int)id >= gsf_infile_num_children(m_ole))
193 			{
194 				return 0;
195 			}
196 			std::map<unsigned, std::string>::iterator i = m_substreams.lower_bound(id);
197 			if (i == m_substreams.end() || m_substreams.key_comp()(id, i->first))
198 				{
199 					std::string name = gsf_infile_name_by_index(m_ole, (int)id);
200 					i = m_substreams.insert(i, std::map<unsigned, std::string>::value_type(id, name));
201 				}
202 			return i->second.c_str();
203 		}
204 
205 	return 0;
206 }
207 
existsSubStream(const char * name)208 bool AbiWordperfectInputStream::existsSubStream(const char * name)
209 {
210 	if (!m_ole)
211 		m_ole = GSF_INFILE(gsf_infile_msole_new (m_input, NULL));
212 
213 	if (!m_ole)
214 		m_ole = GSF_INFILE(gsf_infile_zip_new (m_input, NULL));
215 
216 	if (m_ole)
217 		{
218 			GsfInput *document = gsf_infile_child_by_name(m_ole, name);
219 			if (document)
220 				{
221 					g_object_unref(G_OBJECT (document));
222 					return true;
223 				}
224 		}
225 
226 	return false;
227 }
228 
getSubStreamByName(const char * name)229 librevenge::RVNGInputStream * AbiWordperfectInputStream::getSubStreamByName(const char * name)
230 {
231 	librevenge::RVNGInputStream *documentStream = NULL;
232 
233 	if (!m_ole)
234 		m_ole = GSF_INFILE(gsf_infile_msole_new (m_input, NULL));
235 
236 	if (!m_ole)
237 		m_ole = GSF_INFILE(gsf_infile_zip_new (m_input, NULL));
238 
239 	if (m_ole)
240 		{
241 			GsfInput *document = gsf_infile_child_by_name(m_ole, name);
242 			if (document)
243 				{
244 					documentStream = new AbiWordperfectInputStream(document);
245 					g_object_unref(G_OBJECT (document)); // the only reference should be encapsulated within the new stream
246 				}
247 		}
248 
249 	return documentStream;
250 }
251 
getSubStreamById(unsigned id)252 librevenge::RVNGInputStream * AbiWordperfectInputStream::getSubStreamById(unsigned id)
253 {
254 	librevenge::RVNGInputStream *documentStream = NULL;
255 
256 	if (!m_ole)
257 		m_ole = GSF_INFILE(gsf_infile_msole_new (m_input, NULL));
258 
259 	if (!m_ole)
260 		m_ole = GSF_INFILE(gsf_infile_zip_new (m_input, NULL));
261 
262 	if (m_ole)
263 		{
264 			GsfInput *document = gsf_infile_child_by_index(m_ole, (int)id);
265 			if (document)
266 				{
267 					documentStream = new AbiWordperfectInputStream(document);
268 					g_object_unref(G_OBJECT (document)); // the only reference should be encapsulated within the new stream
269 				}
270 		}
271 
272 	return documentStream;
273 }
274 
tell()275 long AbiWordperfectInputStream::tell()
276 {
277 	return gsf_input_tell(m_input);
278 }
279 
isEnd()280 bool AbiWordperfectInputStream::isEnd()
281 {
282 	return gsf_input_eof(m_input);
283 }
284 
285 // This should probably be defined in pt_Types.h
286 static const UT_uint32 PT_MAX_ATTRIBUTES = 8;
287 
ABI_ListDefinition(int iOutlineHash)288 ABI_ListDefinition::ABI_ListDefinition(int iOutlineHash) :
289 	m_iOutlineHash(iOutlineHash)
290 {
291 	for(int i=0; i<WP6_NUM_LIST_LEVELS; i++)
292 	{
293 		m_iListIDs[i] = 0;
294 		m_listTypes[i] = BULLETED_LIST;
295 		m_iListNumbers[i] = 0;
296 		m_listLeftOffset[i] = 0.0f;
297 		m_listMinLabelWidth[i] = 0.0f;
298 	}
299 }
300 
setListType(const int level,const char type)301 void ABI_ListDefinition::setListType(const int level, const char type)
302 {
303 	switch (type)
304 	{
305 	case '1':
306 		m_listTypes[level-1] = NUMBERED_LIST;
307 		break;
308 	case 'a':
309 		m_listTypes[level-1] = LOWERCASE_LIST;
310 		break;
311 	case 'A':
312 		m_listTypes[level-1] = UPPERCASE_LIST;
313 		break;
314 	case 'i':
315 		m_listTypes[level-1] = LOWERROMAN_LIST;
316 		break;
317 	case 'I':
318 		m_listTypes[level-1] = UPPERROMAN_LIST;
319 		break;
320 	}
321 }
322 
323 #define X_CheckDocumentError(v) if (!v) { UT_DEBUGMSG(("X_CheckDocumentError: %d\n", __LINE__)); }
324 
IE_Imp_WordPerfect_Sniffer()325 IE_Imp_WordPerfect_Sniffer::IE_Imp_WordPerfect_Sniffer()
326 	: IE_ImpSniffer(IE_MIMETYPE_WP_6)
327 {
328 }
329 
~IE_Imp_WordPerfect_Sniffer()330 IE_Imp_WordPerfect_Sniffer::~IE_Imp_WordPerfect_Sniffer()
331 {
332 }
333 
334 // supported suffixes
335 static IE_SuffixConfidence IE_Imp_WordPerfect_Sniffer__SuffixConfidence[] = {
336 	{ "wpd", 	UT_CONFIDENCE_PERFECT 	},
337 	{ "wp", 	UT_CONFIDENCE_PERFECT 	},
338 	{ "", 	UT_CONFIDENCE_ZILCH 	}
339 };
340 
getSuffixConfidence()341 const IE_SuffixConfidence * IE_Imp_WordPerfect_Sniffer::getSuffixConfidence ()
342 {
343 	return IE_Imp_WordPerfect_Sniffer__SuffixConfidence;
344 }
345 
recognizeContents(GsfInput * input)346 UT_Confidence_t IE_Imp_WordPerfect_Sniffer::recognizeContents (GsfInput * input)
347 {
348 	AbiWordperfectInputStream gsfInput(input);
349 
350 	libwpd::WPDConfidence confidence = libwpd::WPDocument::isFileFormatSupported(&gsfInput);
351 
352 	switch (confidence)
353 	{
354 		case libwpd::WPD_CONFIDENCE_NONE:
355 			return UT_CONFIDENCE_ZILCH;
356 		case libwpd::WPD_CONFIDENCE_EXCELLENT:
357 			return UT_CONFIDENCE_PERFECT;
358 		default:
359 			return UT_CONFIDENCE_ZILCH;
360 	}
361 }
362 
constructImporter(PD_Document * pDocument,IE_Imp ** ppie)363 UT_Error IE_Imp_WordPerfect_Sniffer::constructImporter (PD_Document * pDocument,
364 							IE_Imp ** ppie)
365 {
366 	*ppie = new IE_Imp_WordPerfect(pDocument);
367 	return UT_OK;
368 }
369 
getDlgLabels(const char ** pszDesc,const char ** pszSuffixList,IEFileType * ft)370 bool IE_Imp_WordPerfect_Sniffer::getDlgLabels  (const char ** pszDesc,
371 						const char ** pszSuffixList,
372 						IEFileType * ft)
373 {
374 	*pszDesc = "WordPerfect (.wpd, .wp)";
375 	*pszSuffixList = "*.wpd; *.wp";
376 	*ft = getFileType();
377 	return true;
378 }
379 
380 /****************************************************************************/
381 /****************************************************************************/
382 
IE_Imp_WordPerfect(PD_Document * pDocument)383 IE_Imp_WordPerfect::IE_Imp_WordPerfect(PD_Document * pDocument)
384   : IE_Imp (pDocument),
385 	m_leftPageMargin(1.0f),
386 	m_rightPageMargin(1.0f),
387 	m_leftSectionMargin(0.0f),
388 	m_rightSectionMargin(0.0f),
389 	m_sectionColumnsCount(0),
390 	m_headerId(-1),
391 	m_footerId(-1),
392 	m_nextFreeId(0),
393 	m_leftMarginOffset(0.0f),
394 	m_rightMarginOffset(0.0f),
395 	m_pCurrentListDefinition(NULL),
396 	m_bParagraphChanged(false),
397 	m_bParagraphInSection(false),
398 	m_bInSection(false),
399 	m_bSectionChanged(false),
400 	m_bRequireBlock(false),
401 	m_iCurrentListLevel(0),
402 	m_bInCell(false),
403 	m_bHdrFtrOpenCount(0)
404 {
405 }
406 
~IE_Imp_WordPerfect()407 IE_Imp_WordPerfect::~IE_Imp_WordPerfect()
408 {
409 	//UT_HASH_PURGEDATA(ABI_ListDefinition *,&m_listStylesHash,delete);
410 }
411 
_loadFile(GsfInput * input)412 UT_Error IE_Imp_WordPerfect::_loadFile(GsfInput * input)
413 {
414 	AbiWordperfectInputStream gsfInput(input);
415 	libwpd::WPDResult error = libwpd::WPDocument::parse(&gsfInput, static_cast<librevenge::RVNGTextInterface *>(this), NULL);
416 
417 	if (error != libwpd::WPD_OK)
418 	{
419 		UT_DEBUGMSG(("AbiWordPerfect: ERROR: %i!\n", (int)error));
420 		return UT_IE_IMPORTERROR;
421 	}
422 
423 	return UT_OK;
424 }
425 
pasteFromBuffer(PD_DocumentRange *,unsigned char *,unsigned int,const char *)426 void IE_Imp_WordPerfect::pasteFromBuffer (PD_DocumentRange *,
427 					  unsigned char *, unsigned int, const char *)
428 {
429 	// nada
430 }
431 
setDocumentMetaData(const librevenge::RVNGPropertyList & propList)432 void IE_Imp_WordPerfect::setDocumentMetaData(const librevenge::RVNGPropertyList &propList)
433 {
434 	if (propList["dc:author"])
435 		getDoc()->setMetaDataProp(PD_META_KEY_CREATOR, propList["dc:author"]->getStr().cstr());
436 	if (propList["dc:subject"])
437 		getDoc()->setMetaDataProp(PD_META_KEY_SUBJECT, propList["dc:subject"]->getStr().cstr());
438 	if (propList["dc:publisher"])
439 		getDoc()->setMetaDataProp(PD_META_KEY_PUBLISHER, propList["dc:publisher"]->getStr().cstr());
440 	if (propList["dc:type"])
441 		getDoc()->setMetaDataProp(PD_META_KEY_TYPE, propList["dc:category"]->getStr().cstr());
442 	if (propList["librevenge:keywords"])
443 		getDoc()->setMetaDataProp(PD_META_KEY_KEYWORDS, propList["librevenge:keywords"]->getStr().cstr());
444 	if (propList["dc:language"])
445 		getDoc()->setMetaDataProp(PD_META_KEY_LANGUAGE, propList["dc:language"]->getStr().cstr());
446 	if (propList["librevenge:abstract"])
447 		getDoc()->setMetaDataProp(PD_META_KEY_DESCRIPTION, propList["librevenge:abstract"]->getStr().cstr());
448 }
449 
startDocument(const librevenge::RVNGPropertyList &)450 void IE_Imp_WordPerfect::startDocument(const librevenge::RVNGPropertyList & /* propList */)
451 {
452 	UT_DEBUGMSG(("AbiWordPerfect: startDocument\n"));
453 }
454 
endDocument()455 void IE_Imp_WordPerfect::endDocument()
456 {
457 	UT_DEBUGMSG(("AbiWordPerfect: endDocument\n"));
458 }
459 
openPageSpan(const librevenge::RVNGPropertyList & propList)460 void IE_Imp_WordPerfect::openPageSpan(const librevenge::RVNGPropertyList &propList)
461 {
462 	if (m_bHdrFtrOpenCount) return; // HACK
463 	UT_DEBUGMSG(("AbiWordPerfect: openPageSpan\n"));
464 
465 	float marginLeft = 1.0f, marginRight = 1.0f;
466 
467 	if (propList["fo:margin-left"])
468 		marginLeft = propList["fo:margin-left"]->getDouble();
469 	if (propList["fo:margin-right"])
470 		marginRight = propList["fo:margin-right"]->getDouble();
471 
472 	if (marginLeft != m_leftPageMargin || marginRight != m_rightPageMargin /* || */
473 		/* marginTop != m_marginBottom || marginBottom != m_marginBottom */ )
474 		m_bSectionChanged = true; // margin properties are section properties in AbiWord
475 
476 	m_leftPageMargin = marginLeft;
477 	m_rightPageMargin = marginRight;
478 
479 }
480 
openHeader(const librevenge::RVNGPropertyList &)481 void IE_Imp_WordPerfect::openHeader(const librevenge::RVNGPropertyList & /*propList*/)
482 {
483 	m_bHdrFtrOpenCount++;
484 
485 	/*
486 	TODO: THIS CODE IS NOT!!!! USEFULL! - DON'T TOUCH IT - MARCM
487 	UT_String propBuffer;
488 
489 	switch (headerFooterType)
490 	{
491 		case HEADER:
492 			m_headerId = m_nextFreeId;
493 			UT_String_sprintf(propBuffer,"id:%d; listid:0; parentid=0; type=header", m_headerId);
494 			break;
495 		case FOOTER:
496 			m_footerId = m_nextFreeId;
497 			UT_String_sprintf(propBuffer,"id:%d; listid:0; parentid=0; type=footer", m_footerId);
498 			break;
499 		default:
500 			UT_ASSERT(SHOULD_NOT_HAPPEN);
501 			break;
502 	}
503 
504 	const gchar* propsArray[3];
505 	propsArray[0] = "props";
506 	propsArray[1] = propBuffer.c_str();
507 	propsArray[2] = NULL;
508 
509     X_CheckDocumentError(appendStrux(PTX_Section, propsArray));
510 	m_bInSection = true;
511 	m_bSectionChanged = false;*/
512 }
513 
closeHeader()514 void IE_Imp_WordPerfect::closeHeader()
515 {
516 	m_bHdrFtrOpenCount--;
517 	/*
518 	TODO: THIS CODE IS NOT!!!! USEFULL! - DON'T TOUCH IT - MARCM
519 	m_nextFreeId++;
520 	*/
521 }
522 
openFooter(const librevenge::RVNGPropertyList &)523 void IE_Imp_WordPerfect::openFooter(const librevenge::RVNGPropertyList & /*propList*/)
524 {
525 	m_bHdrFtrOpenCount++;
526 	// see above comments re: openHeader
527 }
528 
closeFooter()529 void IE_Imp_WordPerfect::closeFooter()
530 {
531 	m_bHdrFtrOpenCount--;
532 	// see above comments re: closeHeader
533 }
534 
openParagraph(const librevenge::RVNGPropertyList & propList)535 void IE_Imp_WordPerfect::openParagraph(const librevenge::RVNGPropertyList &propList)
536 {
537 	if (m_bHdrFtrOpenCount) return; // HACK
538 	UT_DEBUGMSG(("AbiWordPerfect: openParagraph()\n"));
539 	// for now, we always append these options
540 	float marginTop = 0.0f, marginBottom = 0.0f;
541 	float marginLeft = 0.0f, marginRight = 0.0f, textIndent = 0.0f;
542 	if (propList["fo:margin-top"])
543 	    marginTop = propList["fo:margin-top"]->getDouble();
544 	if (propList["fo:margin-bottom"])
545 	    marginBottom = propList["fo:margin-bottom"]->getDouble();
546 	if (propList["fo:margin-left"])
547 	    marginLeft = propList["fo:margin-left"]->getDouble();
548 	if (propList["fo:margin-right"])
549 	    marginRight = propList["fo:margin-right"]->getDouble();
550 	if (propList["fo:text-indent"])
551 	    textIndent = propList["fo:text-indent"]->getDouble();
552 
553 	m_topMargin = marginTop;
554 	m_bottomMargin = marginBottom;
555 	m_leftMarginOffset = marginLeft;
556 	m_rightMarginOffset = marginRight;
557 	m_textIndent = textIndent;
558 
559 	UT_String propBuffer;
560 	propBuffer += "text-align:";
561 	if (propList["fo:text-align"])
562 	{
563 		// AbiWord follows xsl:fo, except here, for some reason..
564 		if (propList["fo:text-align"]->getStr() == "end")
565 			propBuffer += "right";
566 		else
567 			propBuffer += propList["fo:text-align"]->getStr().cstr();
568 	}
569 	else
570 		propBuffer += "left";
571 
572 	float lineSpacing = 1.0f;
573 	if (propList["fo:line-height"])
574 		lineSpacing = propList["fo:line-height"]->getDouble();
575 
576 	UT_String tmpBuffer;
577 	UT_String_sprintf(tmpBuffer, "; margin-top:%dpt; margin-bottom:%dpt; margin-left:%.4fin; margin-right:%.4fin; text-indent:%.4fin; line-height:%.4f",
578 		(int)(m_topMargin*72), (int)(m_bottomMargin*72), m_leftMarginOffset, m_rightMarginOffset, m_textIndent, lineSpacing);
579 	propBuffer += tmpBuffer;
580 
581 	const librevenge::RVNGPropertyListVector *tabStops = propList.child("style:tab-stops");
582 
583 	if (tabStops && tabStops->count()) // Append the tabstop information
584 	{
585 		propBuffer += "; tabstops:";
586 		tmpBuffer = "";
587 		librevenge::RVNGPropertyListVector::Iter i(*tabStops);
588 		for (i.rewind(); i.next();)
589 		{
590 			propBuffer += tmpBuffer;
591 			if (i()["style:position"])
592 			{
593 				UT_String_sprintf(tmpBuffer, "%.4fin", i()["style:position"]->getDouble());
594 				propBuffer += tmpBuffer;
595 			}
596 
597 			if (i()["style:type"])
598 				if (i()["style:type"]->getStr() == "right")
599 					propBuffer += "/R";
600 				else if (i()["style:type"]->getStr() == "center")
601 					propBuffer += "/C";
602 				else if (i()["style:type"]->getStr() == "char")
603 					propBuffer += "/D";
604 				else
605 					propBuffer += "/L";
606 			else // Left aligned is default
607 				propBuffer += "/L";
608 
609 			if (i()["style:leader-text"])
610 				if (i()["style:leader-text"]->getStr() == "-")
611 					propBuffer += "2";
612 				else if (i()["style:leader-text"]->getStr() == "_")
613 					propBuffer += "3";
614 				else // default to dot leader if the given leader is dot or is not supported by AbiWord
615 					propBuffer += "1";
616 			else
617 				propBuffer += "0";
618 
619 			tmpBuffer = ",";
620 		}
621 	}
622 
623 
624 
625 	UT_DEBUGMSG(("AbiWordPerfect: Appending paragraph properties: %s\n", propBuffer.c_str()));
626 	const gchar* propsArray[3];
627 	propsArray[0] = "props";
628 	propsArray[1] = propBuffer.c_str();
629 	propsArray[2] = NULL;
630 	X_CheckDocumentError(appendStrux(PTX_Block, propsArray));
631 	m_bRequireBlock = false;
632 
633 	if (propList["fo:break-before"])
634 	{
635 		if (strcmp(propList["fo:break-before"]->getStr().cstr(), "page") == 0)
636 		{
637 			UT_UCS4Char ucs = UCS_FF;
638 			X_CheckDocumentError(appendSpan(&ucs,1));
639 		}
640 		else if (strcmp(propList["fo:break-before"]->getStr().cstr(), "column") == 0)
641 		{
642 			UT_UCS4Char ucs = UCS_VTAB;
643 			X_CheckDocumentError(appendSpan(&ucs,1));
644 		}
645 	}
646 }
647 
openSpan(const librevenge::RVNGPropertyList & propList)648 void IE_Imp_WordPerfect::openSpan(const librevenge::RVNGPropertyList &propList)
649 {
650 	if (m_bHdrFtrOpenCount) return; // HACK
651 	UT_DEBUGMSG(("AbiWordPerfect: Appending current text properties\n"));
652 
653 	const gchar* pProps = "props";
654 	UT_String propBuffer;
655 	UT_String tempBuffer;
656 
657 	// bold
658 	propBuffer += "font-weight:";
659 	propBuffer += (propList["fo:font-weight"] ? propList["fo:font-weight"]->getStr().cstr() : "normal");
660 
661 	// italic
662 	propBuffer += "; font-style:";
663 	propBuffer += (propList["fo:font-style"] ? propList["fo:font-style"]->getStr().cstr() : "normal");
664 
665 	// superscript or subscript
666 	if (propList["style:text-position"])
667 	{
668 		propBuffer += "; text-position:";
669 		if (strncmp(propList["style:text-position"]->getStr().cstr(), "super", 5) == 0)
670 			propBuffer += "superscript";
671 		else
672 			propBuffer += "subscript";
673 	}
674 
675 	if (propList["style:text-underline-type"] || propList["style:text-line-through-type"])
676 	{
677 		propBuffer += "; text-decoration:";
678 		if (propList["style:text-underline-type"])
679 			propBuffer += "underline ";
680 		if (propList["style:text-line-through-type"])
681 			propBuffer += "line-through";
682 
683 	}
684 
685 	if (propList["style:font-name"])
686 	{
687 		propBuffer += "; font-family:";
688 		propBuffer += propList["style:font-name"]->getStr().cstr();
689 	}
690 
691 	// font face
692 	if (propList["fo:font-size"])
693 	{
694 		propBuffer += "; font-size:";
695 		propBuffer += propList["fo:font-size"]->getStr().cstr();
696 	}
697 
698 	if (propList["fo:color"])
699 	{
700 		propBuffer += "; color:";
701 		propBuffer += propList["fo:color"]->getStr().cstr();
702 	}
703 
704 	if (propList["fo:background-color"])
705 	{
706 		propBuffer += "; bgcolor:";
707 		propBuffer += propList["fo:background-color"]->getStr().cstr();
708 	}
709 
710 	UT_DEBUGMSG(("AbiWordPerfect: Appending span format: %s\n", propBuffer.c_str()));
711 	const gchar* propsArray[5];
712 
713 	propsArray[0] = pProps;
714 	propsArray[1] = propBuffer.c_str();
715 	propsArray[2] = NULL;
716 	X_CheckDocumentError(appendFmt(propsArray));
717 }
718 
openSection(const librevenge::RVNGPropertyList & propList)719 void IE_Imp_WordPerfect::openSection(const librevenge::RVNGPropertyList &propList)
720 {
721 	if (m_bHdrFtrOpenCount) return; // HACK
722 	UT_DEBUGMSG(("AbiWordPerfect: openSection\n"));
723 
724 	float marginLeft = 0.0f, marginRight = 0.0f;
725 	const librevenge::RVNGPropertyListVector *columns = propList.child("style:columns");
726 	int columnsCount = ((!columns || !columns->count()) ? 1 : columns->count());
727 
728 	// TODO: support spaceAfter
729 	if (propList["fo:start-indent"])
730 		marginLeft = propList["fo:start-indent"]->getDouble();
731 	if (propList["fo:end-indent"])
732 		marginRight = propList["fo:end-indent"]->getDouble();
733 
734 	if (marginLeft != m_leftSectionMargin || marginRight != m_rightSectionMargin || m_sectionColumnsCount != columnsCount)
735 		m_bSectionChanged = true;
736 
737 	m_leftSectionMargin = marginLeft;
738 	m_rightSectionMargin = marginRight;
739 	m_sectionColumnsCount = columnsCount;
740 
741 	_appendSection(columnsCount, m_leftPageMargin + m_leftSectionMargin, m_rightPageMargin + m_rightSectionMargin);
742 }
743 
insertTab()744 void IE_Imp_WordPerfect::insertTab()
745 {
746 	if (m_bHdrFtrOpenCount) return; // HACK
747 	UT_DEBUGMSG(("AbiWordPerfect: insertTab\n"));
748 
749 	UT_UCS4Char ucs = UCS_TAB;
750 	X_CheckDocumentError(appendSpan(&ucs,1));
751 }
752 
insertText(const librevenge::RVNGString & text)753 void IE_Imp_WordPerfect::insertText(const librevenge::RVNGString &text)
754 {
755 	if (m_bHdrFtrOpenCount) return; // HACK
756 	if (text.len())
757 	{
758 		UT_DEBUGMSG(("AbiWordPerfect: insertText\n"));
759 		UT_UCS4String ucs4(text.cstr());
760 		X_CheckDocumentError(appendSpan(ucs4.ucs4_str(), ucs4.length()));
761 	}
762 }
763 
insertSpace()764 void IE_Imp_WordPerfect::insertSpace()
765 {
766 	if (m_bHdrFtrOpenCount) return; // HACK
767 	UT_DEBUGMSG(("AbiWordPerfect: insertSpace\n"));
768 
769 	UT_UCS4Char ucs = UCS_SPACE;
770 	X_CheckDocumentError(appendSpan(&ucs,1));
771 }
772 
insertLineBreak()773 void IE_Imp_WordPerfect::insertLineBreak()
774 {
775 	if (m_bHdrFtrOpenCount) return; // HACK
776 	UT_DEBUGMSG(("AbiWordPerfect: insertLineBreak\n"));
777 
778 	UT_UCSChar ucs = UCS_LF;
779 	X_CheckDocumentError(appendSpan(&ucs,1));
780 }
781 
782 
openOrderedListLevel(const librevenge::RVNGPropertyList & propList)783 void IE_Imp_WordPerfect::openOrderedListLevel(const librevenge::RVNGPropertyList &propList)
784 {
785 	if (m_bHdrFtrOpenCount) return; // HACK
786 	UT_DEBUGMSG(("AbiWordPerfect: openOrderedListLevel\n"));
787 
788 	int listID = 0, startingNumber = 0, level = 1;
789 	char listType = '1';
790 	UT_UTF8String textBeforeNumber, textAfterNumber;
791 	float listLeftOffset = 0.0f;
792 	float listMinLabelWidth = 0.0f;
793 
794 	if (propList["librevenge:id"])
795 		listID = propList["librevenge:id"]->getInt();
796 	if (propList["text:start-value"])
797 		startingNumber = propList["text:start-value"]->getInt();
798 	if (propList["librevenge:level"])
799 		level = propList["librevenge:level"]->getInt();
800 	if (propList["style:num-prefix"])
801 		textBeforeNumber += propList["style:num-prefix"]->getStr().cstr();
802 	if (propList["style:num-suffix"])
803 		textAfterNumber += propList["style:num-suffix"]->getStr().cstr();
804 	if (propList["style:num-format"])
805 		listType = propList["style:num-format"]->getStr().cstr()[0];
806 	if (propList["text:space-before"])
807 		listLeftOffset = propList["text:space-before"]->getDouble();
808 	if (propList["text:min-label-width"])
809 		listMinLabelWidth = propList["text:min-label-width"]->getDouble();
810 
811 	if (!m_pCurrentListDefinition ||
812 		m_pCurrentListDefinition->getOutlineHash() != listID ||
813 		(m_pCurrentListDefinition->getLevelNumber(level) != startingNumber &&
814 		 level == 1))
815 	{
816 		if (m_pCurrentListDefinition)
817 			delete (m_pCurrentListDefinition);
818 
819 		m_pCurrentListDefinition = new ABI_ListDefinition(listID);
820 	}
821 
822 	if (!m_pCurrentListDefinition->getListID(level))
823 	{
824 		m_pCurrentListDefinition->setListType(level, listType);
825 		m_pCurrentListDefinition->setListID(level, UT_rand());
826 		m_pCurrentListDefinition->setListLeftOffset(level, listLeftOffset);
827 		m_pCurrentListDefinition->setListMinLabelWidth(level, listMinLabelWidth);
828 		_updateDocumentOrderedListDefinition(m_pCurrentListDefinition, level, listType, textBeforeNumber, textAfterNumber, startingNumber);
829 	}
830 
831 	m_iCurrentListLevel++;
832 }
833 
closeOrderedListLevel()834 void IE_Imp_WordPerfect::closeOrderedListLevel()
835 {
836 	if (m_bHdrFtrOpenCount) return; // HACK
837 	UT_DEBUGMSG(("AbiWordPerfect: closeOrderedListLevel (level: %i)\n", m_iCurrentListLevel));
838 	UT_ASSERT(m_iCurrentListLevel > 0);
839 
840 	// every time we close a list level, the level above it is normally renumbered to start at "1"
841 	// again. this code takes care of that.
842 	if (m_iCurrentListLevel < (WP6_NUM_LIST_LEVELS-1))
843 		m_pCurrentListDefinition->setLevelNumber(m_iCurrentListLevel + 1, 0);
844 
845 	m_iCurrentListLevel--;
846 }
847 
openUnorderedListLevel(const librevenge::RVNGPropertyList & propList)848 void IE_Imp_WordPerfect::openUnorderedListLevel(const librevenge::RVNGPropertyList &propList)
849 {
850 	if (m_bHdrFtrOpenCount) return; // HACK
851 	UT_DEBUGMSG(("AbiWordPerfect: openUNorderedListLevel\n"));
852 
853 	int listID = 0, level = 1;
854 	librevenge::RVNGString textBeforeNumber, textAfterNumber;
855 	float listLeftOffset = 0.0f;
856 	float listMinLabelWidth = 0.0f;
857 
858 	if (propList["librevenge:id"])
859 		listID = propList["librevenge:id"]->getInt();
860 	if (propList["librevenge:level"])
861 		level = propList["librevenge:level"]->getInt();
862 	if (propList["text:space-before"])
863 		listLeftOffset = propList["text:space-before"]->getDouble();
864 	if (propList["text:min-label-width"])
865 		listMinLabelWidth = propList["text:min-label-width"]->getDouble();
866 
867 	if (!m_pCurrentListDefinition || m_pCurrentListDefinition->getOutlineHash() != listID)
868 	{
869 		if (m_pCurrentListDefinition)
870 			delete (m_pCurrentListDefinition);
871 
872 		m_pCurrentListDefinition = new ABI_ListDefinition(listID);
873 	}
874 
875 	if (!m_pCurrentListDefinition->getListID(level))
876 	{
877 		m_pCurrentListDefinition->setListID(level, UT_rand());
878 		m_pCurrentListDefinition->setListLeftOffset(level, listLeftOffset);
879 		m_pCurrentListDefinition->setListMinLabelWidth(level, listMinLabelWidth);
880 		_updateDocumentUnorderedListDefinition(m_pCurrentListDefinition, level);
881 	}
882 
883 	m_iCurrentListLevel++;
884 }
885 
closeUnorderedListLevel()886 void IE_Imp_WordPerfect::closeUnorderedListLevel()
887 {
888 	if (m_bHdrFtrOpenCount) return; // HACK
889 	UT_DEBUGMSG(("AbiWordPerfect: closeUnorderedListLevel (level: %i)\n", m_iCurrentListLevel));
890 	UT_ASSERT(m_iCurrentListLevel > 0);
891 
892 	m_iCurrentListLevel--;
893 }
894 
895 // ASSUMPTION: We assume that unordered lists will always pass a number of "0". unpredictable behaviour
896 // may result otherwise
openListElement(const librevenge::RVNGPropertyList & propList)897 void IE_Imp_WordPerfect::openListElement(const librevenge::RVNGPropertyList &propList)
898 {
899 	if (m_bHdrFtrOpenCount) return; // HACK
900 	UT_DEBUGMSG(("AbiWordPerfect: openListElement\n"));
901 
902 	UT_ASSERT(m_pCurrentListDefinition); // FIXME: ABI_LISTS_IMPORT throw an exception back to libwpd, if this fails
903 
904 	// Paragraph properties for our list element
905 	UT_String szListID;
906 	UT_String szParentID;
907 	UT_String szLevel;
908 	UT_String_sprintf(szListID,"%d",m_pCurrentListDefinition->getListID(m_iCurrentListLevel));
909 	if (m_iCurrentListLevel > 1)
910 		UT_String_sprintf(szParentID,"%d", m_pCurrentListDefinition->getListID((m_iCurrentListLevel-1)));
911 	else
912 		UT_String_sprintf(szParentID,"0");
913 	UT_String_sprintf(szLevel,"%d", m_iCurrentListLevel);
914 
915 	const gchar* listAttribs[PT_MAX_ATTRIBUTES*2 + 1];
916 	UT_uint32 attribsCount=0;
917 
918 	listAttribs[attribsCount++] = PT_LISTID_ATTRIBUTE_NAME;
919 	listAttribs[attribsCount++] = szListID.c_str();
920 	listAttribs[attribsCount++] = PT_PARENTID_ATTRIBUTE_NAME;
921 	listAttribs[attribsCount++] = szParentID.c_str();
922 	listAttribs[attribsCount++] = PT_LEVEL_ATTRIBUTE_NAME;
923 	listAttribs[attribsCount++] = szLevel.c_str();
924 
925 	// Now handle the Abi List properties
926 	UT_String propBuffer;
927 	UT_String tempBuffer;
928 	UT_String_sprintf(tempBuffer,"list-style:%i;", m_pCurrentListDefinition->getListType(m_iCurrentListLevel));
929 	propBuffer += tempBuffer;
930 
931 #if 0
932 	// FIXME: writing the list delimiter is kind of tricky and silly (because wordperfect wants to define
933 	// it within the document, while abi wants to (sensibly probably) define it in the list definition)
934 	// (we reset it each time but only for numbered lists)
935 	if (listDefinition->isLevelNumbered(m_iCurrentListLevel))
936 	{
937 		UT_DEBUGMSG(("WordPerfect: Appending this list delim: %s\n", m_rightListDelim.c_str()));
938 		listDefinition->setListRightDelimText(m_iCurrentListLevel, m_rightListDelim.c_str());
939 		X_CheckWordPerfectError(_updateDocumentListDefinition(listDefinition, m_iCurrentListLevel));
940 	}
941 #endif
942 
943 	if (m_pCurrentListDefinition->getListType(m_iCurrentListLevel) == BULLETED_LIST)
944 		UT_String_sprintf(tempBuffer, "field-font:Symbol; ");
945 	else
946 		UT_String_sprintf(tempBuffer, "field-font:NULL; ");
947 
948 	m_pCurrentListDefinition->incrementLevelNumber(m_iCurrentListLevel);
949 
950 	propBuffer += tempBuffer;
951 	UT_String_sprintf(tempBuffer, "start-value:%i; ", 1);
952 	propBuffer += tempBuffer;
953 
954 	UT_String_sprintf(tempBuffer, "margin-left:%.4fin; ", m_pCurrentListDefinition->getListLeftOffset(m_iCurrentListLevel)
955 					+ m_pCurrentListDefinition->getListMinLabelWidth(m_iCurrentListLevel)
956 					- (propList["fo:text-indent"] ? propList["fo:text-indent"]->getDouble() : 0.0f));
957 	propBuffer += tempBuffer;
958 	UT_String_sprintf(tempBuffer, "text-indent:%.4fin", - m_pCurrentListDefinition->getListMinLabelWidth(m_iCurrentListLevel)
959 					+ (propList["fo:text-indent"] ? propList["fo:text-indent"]->getDouble() : 0.0f));
960 	propBuffer += tempBuffer;
961 
962 	listAttribs[attribsCount++] = PT_PROPS_ATTRIBUTE_NAME;
963 	listAttribs[attribsCount++] = propBuffer.c_str();
964 	listAttribs[attribsCount++] = NULL;
965 
966 	X_CheckDocumentError(appendStrux(PTX_Block, listAttribs));
967 	m_bRequireBlock = false;
968 
969 	// hang text off of a list label
970 	getDoc()->appendFmtMark();
971 	UT_DEBUGMSG(("WordPerfect: LISTS - Appended a list tag def'n (character props)\n"));
972 
973 	// append a list field label
974 	const gchar* fielddef[5];
975 	fielddef[0] ="type";
976 	fielddef[1] = "list_label";
977 	fielddef[2] = NULL;
978 	X_CheckDocumentError(appendObject(PTO_Field,fielddef));
979 	UT_DEBUGMSG(("WordPerfect: LISTS - Appended a field def'n\n"));
980 
981 	// insert a tab
982 	UT_UCS4Char ucs = UCS_TAB;
983 	X_CheckDocumentError(appendSpan(&ucs,1));
984 }
985 
openFootnote(const librevenge::RVNGPropertyList &)986 void IE_Imp_WordPerfect::openFootnote(const librevenge::RVNGPropertyList & /*propList*/)
987 {
988 	if (m_bHdrFtrOpenCount) return; // HACK
989 
990 	if (!m_bInSection)
991 	{
992 		X_CheckDocumentError(appendStrux(PTX_Section, NULL));
993 		X_CheckDocumentError(appendStrux(PTX_Block,NULL));
994 		m_bInSection = true;
995 	}
996 
997 	const gchar** propsArray = NULL;
998 
999 	UT_String footnoteId;
1000 	UT_String_sprintf(footnoteId,"%i",UT_rand());
1001 
1002 	propsArray = static_cast<const gchar **>(UT_calloc(7, sizeof(gchar *)));
1003 	propsArray [0] = "type";
1004 	propsArray [1] = "footnote_ref";
1005 	propsArray [2] = "footnote-id";
1006 	propsArray [3] = footnoteId.c_str();
1007 	propsArray [4] = NULL;
1008 	propsArray [5] = NULL;
1009 	propsArray [6] = NULL;
1010 	X_CheckDocumentError(appendObject(PTO_Field, propsArray));
1011 
1012 	const gchar * attribs[3] ={"footnote-id", footnoteId.c_str(), NULL};
1013 	X_CheckDocumentError(appendStrux(PTX_SectionFootnote,attribs));
1014 
1015 	X_CheckDocumentError(appendStrux(PTX_Block,NULL));
1016 	m_bRequireBlock = false;
1017 
1018 	propsArray = static_cast<const gchar **>(UT_calloc(7, sizeof(gchar *)));
1019 	propsArray [0] = "type";
1020 	propsArray [1] = "footnote_anchor";
1021 	propsArray [2] = "footnote-id";
1022 	propsArray [3] = footnoteId.c_str();
1023 	propsArray [4] = NULL;
1024 	propsArray [5] = NULL;
1025 	propsArray [6] = NULL;
1026 	X_CheckDocumentError(appendObject(PTO_Field, propsArray));
1027 }
1028 
closeFootnote()1029 void IE_Imp_WordPerfect::closeFootnote()
1030 {
1031 	if (m_bHdrFtrOpenCount) return; // HACK
1032 	X_CheckDocumentError(appendStrux(PTX_EndFootnote,NULL));
1033 }
1034 
openEndnote(const librevenge::RVNGPropertyList &)1035 void IE_Imp_WordPerfect::openEndnote(const librevenge::RVNGPropertyList & /*propList*/)
1036 {
1037 	if (m_bHdrFtrOpenCount) return; // HACK
1038 	const gchar** propsArray = NULL;
1039 
1040 	UT_String endnoteId;
1041 	UT_String_sprintf(endnoteId,"%i",UT_rand());
1042 
1043 	propsArray = static_cast<const gchar **>(UT_calloc(7, sizeof(gchar *)));
1044 	propsArray [0] = "type";
1045 	propsArray [1] = "endnote_ref";
1046 	propsArray [2] = "endnote-id";
1047 	propsArray [3] = endnoteId.c_str();
1048 	propsArray [4] = NULL;
1049 	propsArray [5] = NULL;
1050 	propsArray [6] = NULL;
1051 	X_CheckDocumentError(appendObject(PTO_Field, propsArray));
1052 
1053 	const gchar * attribs[3] ={"endnote-id", endnoteId.c_str(), NULL};
1054 	X_CheckDocumentError(appendStrux(PTX_SectionEndnote,attribs));
1055 
1056 	X_CheckDocumentError(appendStrux(PTX_Block,NULL));
1057 	m_bRequireBlock = false;
1058 
1059 	propsArray = static_cast<const gchar **>(UT_calloc(7, sizeof(gchar *)));
1060 	propsArray [0] = "type";
1061 	propsArray [1] = "endnote_anchor";
1062 	propsArray [2] = "endnote-id";
1063 	propsArray [3] = endnoteId.c_str();
1064 	propsArray [4] = NULL;
1065 	propsArray [5] = NULL;
1066 	propsArray [6] = NULL;
1067 	X_CheckDocumentError(appendObject(PTO_Field, propsArray));
1068 }
1069 
closeEndnote()1070 void IE_Imp_WordPerfect::closeEndnote()
1071 {
1072 	if (m_bHdrFtrOpenCount) return; // HACK
1073 	X_CheckDocumentError(appendStrux(PTX_EndEndnote,NULL));
1074 }
1075 
openTable(const librevenge::RVNGPropertyList & propList)1076 void IE_Imp_WordPerfect::openTable(const librevenge::RVNGPropertyList &propList)
1077 {
1078 	if (m_bHdrFtrOpenCount) return; // HACK
1079 	// TODO: handle 'marginLeftOffset' and 'marginRightOffset'
1080 	UT_DEBUGMSG(("AbiWordPerfect: openTable\n"));
1081 
1082 	UT_String propBuffer;
1083 
1084 	if (propList["table:align"])
1085 	{
1086 		// no need to support left: default behaviour
1087 
1088 		//if (strcmp(propList["table:align"]->getStr().cstr(), "right"))
1089 		// abiword does not support this I think
1090 		//if (strcmp(propList["table:align"]->getStr().cstr(), "center"))
1091 		// abiword does not support this I think
1092 		//if (strcmp(propList["table:align"]->getStr().cstr(), "margins"))
1093 		// abiword does not support this I think
1094 		if (strcmp(propList["table:align"]->getStr().cstr(), "margins"))
1095 		{
1096 			if (propList["fo:margin-left"])
1097 				UT_String_sprintf(propBuffer, "table-column-leftpos:%s; ", propList["fo:margin-left"]->getStr().cstr());
1098 		}
1099 	}
1100 
1101 	const librevenge::RVNGPropertyListVector *columns = propList.child("librevenge:table-columns");
1102 	if (columns)
1103 	{
1104 		propBuffer += "table-column-props:";
1105 		librevenge::RVNGPropertyListVector::Iter i(*columns);
1106 		for (i.rewind(); i.next();)
1107 		{
1108 			UT_String tmpBuffer;
1109 			if (i()["style:column-width"])
1110 				UT_String_sprintf(tmpBuffer, "%s/", i()["style:column-width"]->getStr().cstr());
1111 			propBuffer += tmpBuffer;
1112 		}
1113 	}
1114 
1115 	const gchar* propsArray[3];
1116 	propsArray[0] = "props";
1117 	propsArray[1] = propBuffer.c_str();
1118 	propsArray[2] = NULL;
1119 
1120 	X_CheckDocumentError(appendStrux(PTX_SectionTable, propsArray));
1121 }
1122 
openTableRow(const librevenge::RVNGPropertyList &)1123 void IE_Imp_WordPerfect::openTableRow(const librevenge::RVNGPropertyList & /*propList*/)
1124 {
1125 	if (m_bHdrFtrOpenCount) return; // HACK
1126 	UT_DEBUGMSG(("AbiWordPerfect: openRow\n"));
1127 	if (m_bInCell)
1128 	{
1129 		X_CheckDocumentError(appendStrux(PTX_EndCell, NULL));
1130 	}
1131 
1132 	m_bInCell = false;
1133 }
1134 
openTableCell(const librevenge::RVNGPropertyList & propList)1135 void IE_Imp_WordPerfect::openTableCell(const librevenge::RVNGPropertyList &propList)
1136 {
1137 	if (m_bHdrFtrOpenCount) return; // HACK
1138 	int col =0,  row = 0, colSpan = 0, rowSpan = 0;
1139 	if (propList["librevenge:column"])
1140 		col = propList["librevenge:column"]->getInt();
1141 	if (propList["librevenge:row"])
1142 		row = propList["librevenge:row"]->getInt();
1143 	if (propList["table:number-columns-spanned"])
1144 		colSpan = propList["table:number-columns-spanned"]->getInt();
1145 	if (propList["table:number-rows-spanned"])
1146 		rowSpan = propList["table:number-rows-spanned"]->getInt();
1147 
1148 	UT_DEBUGMSG(("AbiWordPerfect: openCell(col: %d, row: %d, colSpan: %d, rowSpan: %d\n", col, row, colSpan, rowSpan));
1149 	if (m_bInCell)
1150 	{
1151 		X_CheckDocumentError(appendStrux(PTX_EndCell, NULL));
1152 	}
1153 
1154 	UT_String propBuffer;
1155 	UT_String_sprintf(propBuffer, "left-attach:%d; right-attach:%d; top-attach:%d; bot-attach:%d",
1156 					col, col+colSpan, row, row+rowSpan);
1157 
1158 	UT_String borderStyle;
1159 	// we only support bg-style:1 for now
1160 	bool borderLeftSolid = false;
1161 	bool borderRightSolid = false;
1162 	bool borderTopSolid = false;
1163 	bool borderBottomSolid = false;
1164 	if (propList["fo:border-left"])
1165 		borderLeftSolid = strncmp(propList["fo:border-left"]->getStr().cstr(), "0.0inch", 7);
1166 	if (propList["fo:border-right"])
1167 		borderRightSolid = strncmp(propList["fo:border-right"]->getStr().cstr(), "0.0inch", 7);
1168 	if (propList["fo:border-top"])
1169 		borderTopSolid = strncmp(propList["fo:border-top"]->getStr().cstr(), "0.0inch", 7);
1170 	if (propList["fo:border-bottom"])
1171 		borderBottomSolid = strncmp(propList["fo:border-bottom"]->getStr().cstr(), "0.0inch", 7);
1172 
1173 	UT_String_sprintf(borderStyle, "; left-style:%s; right-style:%s; top-style:%s; bot-style:%s",
1174 					  (borderLeftSolid ? "solid" : "none"),
1175 					  (borderRightSolid ? "solid" : "none"),
1176 					  (borderTopSolid ? "solid" : "none"),
1177 					  (borderBottomSolid ? "solid" : "none"));
1178 	propBuffer += borderStyle;
1179 
1180 	// we only support bg-style:1 for now
1181 	if (propList["fo:background-color"])
1182 	{
1183 		UT_String bgCol;
1184 		UT_String_sprintf(bgCol, "; bg-style:1; background-color:%s", &(propList["fo:background-color"]->getStr().cstr()[1]));
1185 		propBuffer += bgCol;
1186 	}
1187 
1188 	UT_DEBUGMSG(("AbiWordPerfect: Inserting a Cell definition: %s\n", propBuffer.c_str()));
1189 
1190 	const gchar* propsArray[3];
1191 	propsArray[0] = "props";
1192 	propsArray[1] = propBuffer.c_str();
1193 	propsArray[2] = NULL;
1194 
1195 	X_CheckDocumentError(appendStrux(PTX_SectionCell, propsArray));
1196 	m_bInCell = true;
1197 }
1198 
closeTable()1199 void IE_Imp_WordPerfect::closeTable()
1200 {
1201 	if (m_bHdrFtrOpenCount) return; // HACK
1202 	UT_DEBUGMSG(("AbiWordPerfect: Closing table\n"));
1203 
1204 	if (m_bInCell)
1205 	{
1206 		X_CheckDocumentError(appendStrux(PTX_EndCell, NULL));
1207 	}
1208 	X_CheckDocumentError(appendStrux(PTX_EndTable, NULL));
1209 	m_bInCell = false;
1210 
1211 	// we need to open a new paragraph after a table, since libwpd does NOT do it
1212 	// FIXME: NEED TO PASS THE CURRENT PROPERTIES INSTEAD OF NULL
1213 	// NOTE: THIS SUCKS.........
1214 	X_CheckDocumentError(appendStrux(PTX_Block, NULL));
1215 	m_bRequireBlock = false;
1216 }
1217 
_appendSection(int numColumns,const float marginLeft,const float marginRight)1218 UT_Error IE_Imp_WordPerfect::_appendSection(int numColumns, const float marginLeft, const float marginRight)
1219 {
1220 	UT_DEBUGMSG(("AbiWordPerfect: Appending section\n"));
1221 
1222 	UT_String myProps("") ;
1223 	UT_LocaleTransactor lt(LC_NUMERIC, "C");
1224 	myProps += UT_String_sprintf("columns:%d; page-margin-left:%.4fin; page-margin-right:%.4fin", numColumns, marginLeft, marginRight);
1225 
1226 	if(m_bInSection && m_bRequireBlock) // AbiWord will hang on an empty <section>
1227 	{
1228 		X_CheckDocumentError(appendStrux(PTX_Block,NULL));
1229 	}
1230 
1231 	const gchar * propsArray[3];
1232 	propsArray[0] = "props";
1233 	propsArray[1] = myProps.c_str();
1234 	propsArray[2] = NULL ;
1235 	X_CheckDocumentError(appendStrux(PTX_Section, propsArray));
1236 
1237 	m_bInSection = true;
1238 	m_bRequireBlock = true;
1239 
1240 	m_bSectionChanged = false;
1241 
1242 	return UT_OK;
1243 }
1244 
1245 // NB: AbiWord-2.0 doesn't properly support nested lists with different nested styles: only "1" style
1246 // really looks proper. We hack around this be only using the style given at level "1"
1247 // NB: AbiWord-2.0 doesn't properly support setting list delimeters at levels greater than 1,
1248 // we hack around this by using only "plain" (e.g.: NULL) list delimeters on levels greater than 1.
_updateDocumentOrderedListDefinition(ABI_ListDefinition * pListDefinition,int iLevel,const char,const UT_UTF8String & sTextBeforeNumber,const UT_UTF8String & sTextAfterNumber,int iStartingNumber)1249 UT_Error IE_Imp_WordPerfect::_updateDocumentOrderedListDefinition(ABI_ListDefinition *pListDefinition, int iLevel,
1250 																  const char /*listType*/, const UT_UTF8String &sTextBeforeNumber,
1251 																  const UT_UTF8String &sTextAfterNumber, int iStartingNumber)
1252 {
1253 	UT_DEBUGMSG(("AbiWordPerfect: Updating document list definition (iLevel: %i)\n", iLevel));
1254 
1255 	if (iLevel > 1) {
1256         UT_DEBUGMSG(("WLACH: Parent's list id is.. %i\n", pListDefinition->getListID((iLevel-1))));
1257     }
1258 
1259 	// finally, set the document's list identification info..
1260 	fl_AutoNum * pAuto = getDoc()->getListByID(pListDefinition->getListID(iLevel));
1261 	// not in document yet, we should create a list for it
1262 	if (pAuto == NULL)
1263 	{
1264 		UT_DEBUGMSG(("AbiWordPerfect: pAuto is NULL: creating a list\n"));
1265 		if (iLevel > 1)
1266 		{
1267 			pAuto = new fl_AutoNum(pListDefinition->getListID(iLevel),
1268 								   pListDefinition->getListID((iLevel-1)),
1269 								   pListDefinition->getListType(1),
1270 								   iStartingNumber,
1271 								   const_cast<gchar*>(reinterpret_cast<const gchar*>("%L")),
1272 								   ".",
1273 								   getDoc(),
1274 								   NULL);
1275 		}
1276 		else
1277 		{
1278 			UT_UTF8String sNumberingString;
1279 			UT_UTF8String sNumber("%L", (size_t)0);
1280 
1281 			sNumberingString += sTextBeforeNumber;
1282 			sNumberingString += sNumber;
1283 			sNumberingString += sTextAfterNumber;
1284 
1285 			pAuto = new fl_AutoNum(pListDefinition->getListID(iLevel), 0, pListDefinition->getListType(iLevel), iStartingNumber,
1286 								   const_cast<gchar*>(reinterpret_cast<const gchar*>(sNumberingString.utf8_str())), ".", getDoc(), NULL);
1287 		}
1288 		getDoc()->addList(pAuto);
1289 	}
1290 	// we should update what we have
1291 	else
1292 	{
1293 		UT_DEBUGMSG(("AbiWordPerfect: pAuto already exists\n"));
1294 	}
1295 
1296 	pAuto->fixHierarchy();
1297 
1298 	return UT_OK;
1299 }
1300 
_updateDocumentUnorderedListDefinition(ABI_ListDefinition * pListDefinition,int iLevel)1301 UT_Error IE_Imp_WordPerfect::_updateDocumentUnorderedListDefinition(ABI_ListDefinition *pListDefinition, int iLevel)
1302 {
1303 	UT_DEBUGMSG(("AbiWordPerfect: Updating document list definition (iLevel: %i)\n", iLevel));
1304 
1305 	// finally, set the document's list identification info..
1306 	fl_AutoNum * pAuto = getDoc()->getListByID(pListDefinition->getListID(iLevel));
1307 	// not in document yet, we should create a list for it
1308 	if (pAuto == NULL)
1309 	{
1310 		UT_DEBUGMSG(("AbiWordPerfect: pAuto is NULL: creating a list\n"));
1311 		if (iLevel > 1)
1312 		{
1313 			pAuto = new fl_AutoNum(pListDefinition->getListID(iLevel), pListDefinition->getListID((iLevel-1)),
1314 								   pListDefinition->getListType(1), 0, const_cast<gchar*>(reinterpret_cast<const gchar*>("%L")), ".", getDoc(), NULL);
1315 		}
1316 		else
1317 			pAuto = new fl_AutoNum(pListDefinition->getListID(iLevel), 0, pListDefinition->getListType(iLevel), 0,
1318 								   const_cast<gchar*>(reinterpret_cast<const gchar*>("%L")), ".", getDoc(), NULL);
1319 
1320 		getDoc()->addList(pAuto);
1321 	}
1322 	// we should update what we have
1323 	else
1324 	{
1325 		UT_DEBUGMSG(("AbiWordPerfect: pAuto already exists\n"));
1326 	}
1327 
1328 	pAuto->fixHierarchy();
1329 
1330 	return UT_OK;
1331 }
1332 
1333 #ifdef HAVE_LIBWPS
1334 
1335 class IE_Imp_MSWorks : public IE_Imp_WordPerfect
1336 {
1337 public:
1338 
IE_Imp_MSWorks(PD_Document * pDocument)1339     IE_Imp_MSWorks(PD_Document * pDocument)
1340 		: IE_Imp_WordPerfect(pDocument)
1341 	{
1342 	}
1343 
~IE_Imp_MSWorks()1344     ~IE_Imp_MSWorks()
1345 	{
1346 	}
1347 
1348 protected:
_loadFile(GsfInput * input)1349     virtual UT_Error _loadFile(GsfInput * input)
1350 	{
1351 		AbiWordperfectInputStream gsfInput(input);
1352 		libwps::WPSResult error = libwps::WPSDocument::parse(&gsfInput, static_cast<librevenge::RVNGTextInterface *>(this), NULL, NULL);
1353 
1354 		if (error != libwps::WPS_OK)
1355 			{
1356 				UT_DEBUGMSG(("AbiMSWorks: ERROR: %i!\n", (int)error));
1357 				return UT_IE_IMPORTERROR;
1358 			}
1359 
1360 		return UT_OK;
1361 	}
1362 };
1363 
1364 /****************************************************************************************/
1365 /****************************************************************************************/
1366 
IE_Imp_MSWorks_Sniffer()1367 IE_Imp_MSWorks_Sniffer::IE_Imp_MSWorks_Sniffer()
1368 	: IE_ImpSniffer("application/vnd.ms-works")
1369 {
1370 }
1371 
~IE_Imp_MSWorks_Sniffer()1372 IE_Imp_MSWorks_Sniffer::~IE_Imp_MSWorks_Sniffer()
1373 {
1374 }
1375 
1376 // supported suffixes
1377 static IE_SuffixConfidence IE_Imp_MSWorks_Sniffer__SuffixConfidence[] = {
1378 	{ "wps", 	UT_CONFIDENCE_PERFECT 	},
1379 	{ "", 	UT_CONFIDENCE_ZILCH 	}
1380 };
1381 
getSuffixConfidence()1382 const IE_SuffixConfidence * IE_Imp_MSWorks_Sniffer::getSuffixConfidence ()
1383 {
1384 	return IE_Imp_MSWorks_Sniffer__SuffixConfidence;
1385 }
1386 
recognizeContents(GsfInput * input)1387 UT_Confidence_t IE_Imp_MSWorks_Sniffer::recognizeContents (GsfInput * input)
1388 {
1389 	AbiWordperfectInputStream gsfInput(input);
1390 
1391 	libwps::WPSCreator creator;
1392 	libwps::WPSKind kind;
1393 	bool needEncoding;
1394 	libwps::WPSConfidence confidence = libwps::WPSDocument::isFileFormatSupported(&gsfInput, kind, creator, needEncoding);
1395 
1396 	if (kind != libwps::WPS_TEXT)
1397 		confidence = libwps::WPS_CONFIDENCE_NONE;
1398 
1399 	switch (confidence)
1400 	{
1401 		case libwps::WPS_CONFIDENCE_NONE:
1402 			return UT_CONFIDENCE_ZILCH;
1403 		case libwps::WPS_CONFIDENCE_EXCELLENT:
1404 			return UT_CONFIDENCE_PERFECT;
1405 		default:
1406 			return UT_CONFIDENCE_ZILCH;
1407 	}
1408 }
1409 
constructImporter(PD_Document * pDocument,IE_Imp ** ppie)1410 UT_Error IE_Imp_MSWorks_Sniffer::constructImporter (PD_Document * pDocument,
1411 							IE_Imp ** ppie)
1412 {
1413 	*ppie = new IE_Imp_MSWorks(pDocument);
1414 	return UT_OK;
1415 }
1416 
getDlgLabels(const char ** pszDesc,const char ** pszSuffixList,IEFileType * ft)1417 bool IE_Imp_MSWorks_Sniffer::getDlgLabels  (const char ** pszDesc,
1418 						const char ** pszSuffixList,
1419 						IEFileType * ft)
1420 {
1421 	*pszDesc = "Microsoft Works (.wps)";
1422 	*pszSuffixList = "*.wps";
1423 	*ft = getFileType();
1424 	return true;
1425 }
1426 
1427 #endif
1428