filters

mswriteimport.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2001-2003 Clarence Dang <dang@kde.org>
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License Version 2 as published by the Free Software Foundation.
7
8 This library is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 Library General Public License Version 2 for more details.
12
13 You should have received a copy of the GNU Library General Public License
14 Version 2 along with this library; see the file COPYING.LIB. If not,
15 write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
16 * Boston, MA 02110-1301, USA.
17*/
18
19#ifndef NDEBUG
20 //#define DEBUG_XML_OUTPUT
21#endif
22
23#include <stdio.h>
24#include <string.h>
25#include <stdarg.h>
26
27#include <tqfile.h>
28#include <tqobject.h>
29#include <tqstring.h>
30#include <tqtextcodec.h>
31#include <tqtextstream.h>
32
33#include <kdebug.h>
34#include <kgenericfactory.h>
35
36#include <KoFilterChain.h>
37#include <KoStore.h>
38
39#include "list.h"
40#include "libmswrite.h"
41
42#include "ImportDialog.h"
43#include "mswriteimport.h"
44
45
46class MSWriteImportFactory : KGenericFactory <MSWriteImport, KoFilter>
47{
48public:
49 MSWriteImportFactory () : KGenericFactory <MSWriteImport, KoFilter> ("kwordmswriteimport")
50 {
51 }
52
53protected:
54 virtual void setupTranslations (void)
55 {
56 TDEGlobal::locale()->insertCatalogue ("kofficefilters");
57 }
58};
59
60K_EXPORT_COMPONENT_FACTORY (libmswriteimport, MSWriteImportFactory ())
61
62
63//
64// Device that reads from .WRI file
65//
66
67class WRIDevice : public MSWrite::Device
68{
69private:
70 FILE *m_infp;
71
72public:
73 WRIDevice () : m_infp (NULL)
74 {
75 }
76
77 virtual ~WRIDevice ()
78 {
79 closeFile ();
80 }
81
82 bool openFile (const char *fileName)
83 {
84 m_infp = fopen (fileName, "rb");
85 if (!m_infp)
86 {
87 error (MSWrite::Error::FileError, "could not open file for reading\n");
88 return false;
89 }
90
91 return true;
92 }
93
94 bool closeFile (void)
95 {
96 if (m_infp)
97 {
98 if (fclose (m_infp))
99 {
100 error (MSWrite::Error::FileError, "could not close input file\n");
101 return false;
102 }
103
104 m_infp = NULL;
105 }
106
107 return true;
108 }
109
110 bool read (MSWrite::Byte *buf, const MSWrite::DWord numBytes)
111 {
112 if (fread (buf, 1, (size_t) numBytes, m_infp) != (size_t) numBytes)
113 {
114 error (MSWrite::Error::FileError, "could not read from input file\n");
115 return false;
116 }
117
118 return true;
119 }
120
121 bool write (const MSWrite::Byte *, const MSWrite::DWord)
122 {
123 error (MSWrite::Error::InternalError, "writing to an input file?\n");
124 return false;
125 }
126
127 bool seek (const long offset, const int whence)
128 {
129 if (fseek (m_infp, offset, whence))
130 {
131 error (MSWrite::Error::InternalError, "could not seek input file\n");
132 return false;
133 }
134
135 return true;
136 }
137
138 long tell (void)
139 {
140 return ftell (m_infp);
141 }
142
143 void debug (const char *s)
144 {
145 kdDebug (30509) << s;
146 }
147
148 void debug (const int i)
149 {
150 kdDebug (30509) << i;
151 }
152
153 void error (const int errorCode, const char *message,
154 const char * /*file*/ = "", const int /*lineno*/ = 0,
155 MSWrite::DWord /*tokenValue*/ = NoToken)
156 {
157 if (errorCode == MSWrite::Error::Warn)
158 kdWarning (30509) << message;
159 else
160 {
161 m_error = errorCode;
162 kdError (30509) << message;
163 }
164 }
165};
166
167
168//
169// Generator that creates the KWord file
170//
171
172class KWordGenerator : public MSWrite::Generator, public MSWrite::NeedsDevice
173{
174private:
175 // KoStore can only have 1 file open at a time
176 // so we store objects in this structure temporarily
177 class WRIObject
178 {
179 private:
180 WRIObject (const WRIObject &rhs);
181
182 public:
183 MSWrite::Byte *m_data;
184 MSWrite::DWord m_dataLength;
185 MSWrite::DWord m_dataUpto;
186 TQString m_nameInStore;
187
188 WRIObject () : m_data (NULL), m_dataLength (0), m_dataUpto (0)
189 {
190 }
191
192 ~WRIObject ()
193 {
194 delete [] m_data;
195 }
196
197 WRIObject operator= (const WRIObject &rhs)
198 {
199 delete [] m_data;
200
201 m_dataLength = rhs.m_dataLength;
202 m_dataUpto = rhs.m_dataUpto;
203 m_nameInStore = rhs.m_nameInStore;
204
205 if (rhs.m_data)
206 {
207 m_data = new MSWrite::Byte [m_dataLength];
208 if (m_data)
209 memcpy (m_data, rhs.m_data, m_dataLength);
210 // remember to check m_data before use
211 }
212 else
213 m_data = NULL;
214
215 return *this;
216 }
217 };
218
219 // page/margin dimensions
220 int m_pageWidth, m_pageHeight;
221 int m_left, m_right, m_top, m_bottom; // describing border of Text Frameset (position, not magnitude)
222 int m_leftMargin, m_rightMargin, m_topMargin, m_bottomMargin;
223 int m_headerFromTop, m_footerFromTop;
224 bool m_hasHeader, m_isHeaderOnFirstPage;
225 bool m_hasFooter, m_isFooterOnFirstPage;
226 bool m_writeHeaderFirstTime, m_writeFooterFirstTime;
227
228 int inWhat;
229
230 enum inWhatPossiblities
231 {
232 Nothing,
233 Header,
234 Footer,
235 Body
236 };
237
238 int m_startingPageNumber;
239
240 KoFilterChain *m_chain;
241 KoStoreDevice *m_outfile;
242
243 // for charset conversion
244 TQTextCodec *m_codec;
245 TQTextDecoder *m_decoder;
246
247 // import options (compensate for differences between KWord and MS Write)
248 bool m_simulateLineSpacing;
249 bool m_simulateImageOffset;
250
251 // formatting
252 TQString m_formatOutput;
253 int m_charInfoCountStart, m_charInfoCountLen;
254 bool m_pageBreak, m_needAnotherParagraph;
255 int m_pageBreakOffset;
256 int m_lineSpacingFromAbove;
257
258 // picture counters
259 int m_numPictures;
260 TQString m_pictures;
261
262 TQString m_objectFrameset;
263
264 MSWrite::List <WRIObject> m_objectList;
265
266 double m_objectHorizOffset;
267 bool m_paraIsImage;
268
269 MSWriteImport *m_koLink;
270
271 // XML output that is held back until after "Text Frameset 1" is output
272 // (i.e. header & footer must come after the Body in KWord)
273 bool m_delayOutput;
274 TQString m_heldOutput;
275
276 void delayOutput (const bool yes)
277 {
278 m_delayOutput = yes;
279 }
280
281 bool delayOutputFlush (void)
282 {
283 TQCString strUtf8 = m_heldOutput.utf8 ();
284 int strLength = strUtf8.length ();
285
286 if (m_outfile->writeBlock (strUtf8, strLength) != strLength)
287 ErrorAndQuit (MSWrite::Error::FileError, "could not write delayed output\n");
288
289 m_heldOutput = "";
290 return true;
291 }
292
293public:
294 KWordGenerator () : m_hasHeader (false), m_isHeaderOnFirstPage (false),
295 m_hasFooter (false), m_isFooterOnFirstPage (false),
296 m_writeHeaderFirstTime (true), m_writeFooterFirstTime (true),
297 inWhat (Nothing),
298 m_decoder (NULL),
299 m_simulateLineSpacing (false),
300 m_simulateImageOffset (true),
301 m_pageBreak (false), m_needAnotherParagraph (false),
302 m_lineSpacingFromAbove (0),
303 m_numPictures (0)
304 {
305 delayOutput (false);
306
307 // just select windows-1252 until the "Select Encoding" dialog works
308 m_codec = TQTextCodec::codecForName ("CP 1252");
309
310 if (m_codec)
311 m_decoder = m_codec->makeDecoder();
312 else
313 kdWarning (30509) << "Cannot convert from Win Charset!" << endl;
314 }
315
316 virtual ~KWordGenerator ()
317 {
318 delete m_decoder;
319 }
320
321 void setFilterChain (KoFilterChain *chain)
322 {
323 m_chain = chain;
324 }
325
326 bool writeDocumentBegin (const MSWrite::Word,
327 const MSWrite::PageLayout *pageLayout)
328 {
329 kdDebug (30509) << "writeDocumentBegin()" << endl;
330
331 // open maindoc.xml
332 m_outfile = m_chain->storageFile ("root", KoStore::Write);
333 if (!m_outfile)
334 ErrorAndQuit (MSWrite::Error::FileError, "could not open root in store\n");
335
336
337 //
338 // store page dimensions for now
339 //
340
341 // page width & height
342 m_pageWidth = Twip2Point (pageLayout->getPageWidth ());
343 m_pageHeight = Twip2Point (pageLayout->getPageHeight ());
344
345 // offset of margins
346 m_left = Twip2Point (pageLayout->getLeftMargin ());
347 m_right = m_left + Twip2Point (pageLayout->getTextWidth ()) - 1;
348 m_top = Twip2Point (pageLayout->getTopMargin ());
349 m_bottom = m_top + Twip2Point (pageLayout->getTextHeight ()) - 1;
350
351 // size of margins
352 m_leftMargin = m_left;
353 m_rightMargin = Twip2Point (pageLayout->getRightMargin ());
354 m_topMargin = m_top;
355 m_bottomMargin = Twip2Point (pageLayout->getBottomMargin ());
356
357 kdDebug (30509) << "leftMargin: " << m_leftMargin << endl;
358 kdDebug (30509) << "rightMargin: " << m_rightMargin << endl;
359 kdDebug (30509) << "topMargin: " << m_topMargin << endl;
360 kdDebug (30509) << "bottomMargin: " << m_bottomMargin << endl;
361
362 // offset of header & footer
363 m_headerFromTop = Twip2Point (pageLayout->getHeaderFromTop ());
364 m_footerFromTop = Twip2Point (pageLayout->getFooterFromTop ());
365
366 kdDebug (30509) << "headerFromTop: " << m_headerFromTop
367 << " footerFromTop: " << m_footerFromTop << endl;
368
369 m_startingPageNumber = pageLayout->getPageNumberStart ();
370
371 return true;
372 }
373
374 bool writeDocumentBeginForReal (void)
375 {
376 kdDebug (30509) << "writeDocumentBeginForReal()" << endl;
377
378 // adjust margins/PAPERBORDERS to ensure that the header & footer are
379 // within them
380 // TODO: stop header & footer from changing body's location
381 // TODO: recompute offset of margins after recomputing margins
382 if (m_hasHeader)
383 if (m_headerFromTop < m_topMargin)
384 m_topMargin = m_headerFromTop;
385
386 if (m_hasFooter)
387 if (m_pageHeight - m_footerFromTop < m_bottomMargin)
388 m_bottomMargin = m_pageHeight - m_footerFromTop;
389
390 kdDebug (30509) << "adjusted::: leftMargin: " << m_leftMargin
391 << " rightMargin: " << m_rightMargin
392 << " topMargin: " << m_topMargin
393 << " bottomMargin: " << m_bottomMargin
394 << endl;
395
396 // start document
397 // TODO: error checking
398 writeTextInternal ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
399 writeTextInternal ("<!DOCTYPE DOC PUBLIC \"-//KDE//DTD kword 1.3//EN\" "
400 "\"http://www.koffice.org/DTD/kword-1.3.dtd\">");
401 writeTextInternal ("<DOC xmlns=\"http://www.koffice.org/DTD/kword\" "
402 "mime=\"application/x-kword\" "
403 "syntaxVersion=\"3\" editor=\"KWord\">");
404
405 writeTextInternal ("<PAPER format=\"1\" "
406 "width=\"%i\" height=\"%i\" "
407 "orientation=\"0\" columns=\"1\" "
408 "hType=\"%i\" fType=\"%i\">",
409 m_pageWidth, m_pageHeight,
410 m_isHeaderOnFirstPage ? 0 : 2,
411 m_isFooterOnFirstPage ? 0 : 2);
412
413 writeTextInternal ("<PAPERBORDERS left=\"%i\" right=\"%i\" "
414 "top=\"%i\" bottom=\"%i\"/>",
415 m_leftMargin, m_rightMargin,
416 m_topMargin, m_bottomMargin);
417
418 writeTextInternal ("</PAPER>");
419
420 writeTextInternal ("<ATTRIBUTES processing=\"0\" "
421 "tabStopValue=\"%lf\" "
422 "hasHeader=\"%i\" hasFooter=\"%i\"/>",
423 Inch2Point (0.5),
424 m_hasHeader ? 1 : 0, m_hasFooter ? 1 : 0);
425
426 // handle page numbering not starting from 1
427 if (m_startingPageNumber != 1)
428 writeTextInternal ("<VARIABLESETTINGS startingPageNumber=\"%i\"/>",
429 m_startingPageNumber);
430
431 writeTextInternal ("<FRAMESETS>");
432
433 return true;
434 }
435
436 bool writeDocumentEnd (const MSWrite::Word, const MSWrite::PageLayout *)
437 {
438 kdDebug (30509) << "writeDocumentEnd()" << endl;
439
440 // write framesets for the objects
441 writeTextInternal (m_objectFrameset);
442
443 writeTextInternal ("</FRAMESETS>");
444 writeTextInternal ("<STYLES>");
445 writeTextInternal ("<STYLE>");
446 writeTextInternal ("<NAME value=\"Standard\"/>");
447 writeTextInternal ("<FLOW align=\"left\"/>");
448 writeTextInternal ("<INDENTS first=\"0\" left=\"0\" right=\"0\"/>");
449 writeTextInternal ("<OFFSETS before=\"0\" after=\"0\"/>");
450
451 writeTextInternal ("<FORMAT id=\"1\">");
452 writeTextInternal ("<COLOR blue=\"0\" red=\"0\" green=\"0\"/>");
453 writeTextInternal ("<FONT name=\"helvetica\"/>");
454 writeTextInternal ("<SIZE value=\"12\"/>");
455 writeTextInternal ("<WEIGHT value=\"50\"/>");
456 writeTextInternal ("<ITALIC value=\"0\"/>");
457 writeTextInternal ("<UNDERLINE value=\"0\"/>");
458 writeTextInternal ("<STRIKEOUT value=\"0\"/>");
459 writeTextInternal ("<VERTALIGN value=\"0\"/>");
460 writeTextInternal ("</FORMAT>");
461
462 writeTextInternal ("<FOLLOWING name=\"Standard\"/>");
463 writeTextInternal ("</STYLE>");
464 writeTextInternal ("</STYLES>");
465
466 // write out image keys
467 writeTextInternal ("<PICTURES>");
468 writeTextInternal (m_pictures);
469 writeTextInternal ("</PICTURES>");
470
471 // end document
472 writeTextInternal ("</DOC>");
473
474 // close maindoc.xml
475 m_outfile->close ();
476 m_outfile = (KoStoreDevice *) NULL;
477
478 //
479 // output object data
480
481 /*if (m_objectUpto != getNumObjects ())
482 warning ("m_objectUpto (%i) != getNumObjects() (%i) -- this is probably because OLE is unimplemented\n",
483 m_objectUpto, getNumObjects ());*/
484
485 MSWrite::List <WRIObject>::Iterator it;
486 MSWrite::List <WRIObject>::Iterator end(m_objectList.end ());
487 for (it = m_objectList.begin (); it != end; ++it)
488 {
489 kdDebug (30509) << "outputting object \'" << (*it).m_nameInStore
490 << "\' (length: " << (*it).m_dataLength << ")"
491 << endl;
492
493 if (!(*it).m_data)
494 ErrorAndQuit (MSWrite::Error::InternalError, "image data not initialised\n");
495
496 // open file for object in store
497 m_outfile = m_chain->storageFile ((*it).m_nameInStore, KoStore::Write);
498 if (!m_outfile)
499 ErrorAndQuit (MSWrite::Error::FileError, "could not open image in store\n");
500
501 if (m_outfile->writeBlock ((const char *) (*it).m_data, (*it).m_dataLength)
502 != (TQ_LONG) (*it).m_dataLength)
503 ErrorAndQuit (MSWrite::Error::FileError, "could not write image to store\n");
504
505 // close object in store
506 m_outfile->close ();
507 m_outfile = NULL;
508 }
509
510 return true;
511 }
512
513
514 bool writeFooterBegin (void)
515 {
516 kdDebug (30509) << "writeFooterBegin()" << endl;
517
518 inWhat = Footer;
519 m_hasFooter = true;
520
521 // footers must go after body in KWord
522 delayOutput (true);
523
524 // footer frameset will be written in writeParaInfoBegin()
525
526 return true;
527 }
528
529 bool writeFooterEnd (void)
530 {
531 kdDebug (30509) << "writeFooterEnd()" << endl;
532
533 inWhat = Nothing;
534
535 if (!m_writeFooterFirstTime)
536 writeTextInternal ("</FRAMESET>");
537 delayOutput (false);
538
539 return true;
540 }
541
542 bool writeHeaderBegin (void)
543 {
544 kdDebug (30509) << "writeHeaderBegin()" << endl;
545
546 inWhat = Header;
547 m_hasHeader = true;
548
549 // headers must go after body in KWord
550 delayOutput (true);
551
552 // header frameset will be written in writeParaInfoBegin()
553
554 return true;
555 }
556
557 bool writeHeaderEnd (void)
558 {
559 kdDebug (30509) << "writeHeaderEnd()" << endl;
560
561 inWhat = Nothing;
562
563 if (!m_writeHeaderFirstTime)
564 writeTextInternal ("</FRAMESET>");
565 delayOutput (false);
566
567 return true;
568 }
569
570 bool writeBodyBegin (void)
571 {
572 kdDebug (30509) << "writeBodyBegin()" << endl;
573
574 inWhat = Body;
575
576 // writeFooterBegin() and writeHeaderBegin() have been called by now
577 // so we have enough information to actually write about them
578 writeDocumentBeginForReal ();
579
580 writeTextInternal ("<FRAMESET frameType=\"1\" frameInfo=\"0\" name=\"Text Frameset 1\" visible=\"1\">");
581 // TODO: runaround?
582 writeTextInternal ("<FRAME runaround=\"1\" autoCreateNewFrame=\"1\" newFrameBehavior=\"0\" copy=\"0\""
583 " top=\"%i\" bottom=\"%i\" left=\"%i\" right=\"%i\"/>",
584 m_top, m_bottom, m_left, m_right);
585
586 return true;
587 }
588
589 bool writeBodyEnd (void)
590 {
591 kdDebug (30509) << "writeBodyEnd()" << endl;
592
593 inWhat = Nothing;
594
595 // <PAGEBREAKING hardFrameBreakAfter=\"true\"/>" may have been in the last paragraph
596 // and for "hardFrameBreakAfter" to do its work, we need one more final paragraph!
597 if (m_needAnotherParagraph)
598 {
599 kdDebug (30509) << "needAnotherParagraph in bodyEndWrite()" << endl;
600 writeTextInternal ("<PARAGRAPH><TEXT></TEXT><LAYOUT></LAYOUT></PARAGRAPH>");
601 m_needAnotherParagraph = false;
602 }
603
604 writeTextInternal ("</FRAMESET>");
605
606 // since "Text Frameset 1" has ended, we can output the header & footer, now
607 delayOutputFlush ();
608
609 return true;
610 }
611
612 bool writeParaInfoBegin (const MSWrite::FormatParaProperty *paraProperty,
613 const MSWrite::OLE *ole,
614 const MSWrite::Image *image)
615 {
616 //kdDebug (30509) << "writeParaInfoBegin()" << endl;
617
618 // reset charInfo counters
619 m_charInfoCountStart = 0;
620 m_charInfoCountLen = 0;
621
622 if (inWhat == Header)
623 {
624 m_isHeaderOnFirstPage = paraProperty->getIsOnFirstPage ();
625
626 if (m_writeHeaderFirstTime)
627 {
628 // dummy header frames
629 //
630
631 // except, if the header is NOT on the first page, then make an empty "First Page Header"
632 // by setting "visible=1"
633 writeTextInternal ("<FRAMESET frameType=\"1\" frameInfo=\"1\" name=\"First Page Header\" visible=\"%i\">",
634 m_isHeaderOnFirstPage ? 1 : 0);
635 writeTextInternal ("<FRAME runaround=\"1\" copy=\"0\" newFrameBehavior=\"2\" autoCreateNewFrame=\"0\""
636 " top=\"%i\" bottom=\"%i\" left=\"%i\" right=\"%i\"/>",
637 m_headerFromTop, m_headerFromTop, m_left, m_right);
638 writeTextInternal ("</FRAMESET>");
639
640 writeTextInternal ("<FRAMESET frameType=\"1\" frameInfo=\"2\" name=\"Even Pages Header\" visible=\"0\">");
641 writeTextInternal ("<FRAME runaround=\"1\" copy=\"0\" newFrameBehavior=\"2\" autoCreateNewFrame=\"0\""
642 " top=\"%i\" bottom=\"%i\" left=\"%i\" right=\"%i\"/>",
643 m_headerFromTop, m_headerFromTop, m_left, m_right);
644 writeTextInternal ("</FRAMESET>");
645
646 // real header frame
647 writeTextInternal ("<FRAMESET frameType=\"1\" frameInfo=\"3\" name=\"Odd Pages Header\" visible=\"1\">");
648 writeTextInternal ("<FRAME runaround=\"1\" copy=\"1\" newFrameBehavior=\"2\" autoCreateNewFrame=\"0\""
649 " top=\"%i\" bottom=\"%i\" left=\"%i\" right=\"%i\"/>",
650 m_headerFromTop, m_headerFromTop, m_left, m_right);
651
652 m_writeHeaderFirstTime = false;
653 }
654 }
655 else if (inWhat == Footer)
656 {
657 m_isFooterOnFirstPage = paraProperty->getIsOnFirstPage ();
658
659 if (m_writeFooterFirstTime)
660 {
661 // dummy footer frames
662 //
663
664 // except, if the footer is NOT on the first page, then make an empty "First Page Footer"
665 // by setting "visible=1"
666 writeTextInternal ("<FRAMESET frameType=\"1\" frameInfo=\"4\" name=\"First Page Footer\" visible=\"%i\">",
667 m_isFooterOnFirstPage ? 1 : 0);
668 writeTextInternal ("<FRAME runaround=\"1\" copy=\"0\" newFrameBehavior=\"2\" autoCreateNewFrame=\"0\""
669 " top=\"%i\" bottom=\"%i\" left=\"%i\" right=\"%i\"/>",
670 m_footerFromTop, m_footerFromTop, m_left, m_right);
671 writeTextInternal ("</FRAMESET>");
672
673 writeTextInternal ("<FRAMESET frameType=\"1\" frameInfo=\"5\" name=\"Even Pages Footer\" visible=\"0\">");
674 writeTextInternal ("<FRAME runaround=\"1\" copy=\"0\" newFrameBehavior=\"2\" autoCreateNewFrame=\"0\""
675 " top=\"%i\" bottom=\"%i\" left=\"%i\" right=\"%i\"/>",
676 m_footerFromTop, m_footerFromTop, m_left, m_right);
677 writeTextInternal ("</FRAMESET>");
678
679 // real footer frame
680 writeTextInternal ("<FRAMESET frameType=\"1\" frameInfo=\"6\" name=\"Odd Pages Footer\" visible=\"1\">");
681 writeTextInternal ("<FRAME runaround=\"1\" copy=\"1\" newFrameBehavior=\"2\" autoCreateNewFrame=\"0\""
682 " top=\"%i\" bottom=\"%i\" left=\"%i\" right=\"%i\"/>",
683 m_footerFromTop, m_footerFromTop, m_left, m_right);
684
685 m_writeFooterFirstTime = false;
686 }
687 }
688
689 if (!writeTextInternal ("<PARAGRAPH><TEXT>")) return false;
690
691 if (image)
692 {
693 kdDebug (30509) << "Paragraph is an image!" << endl;
694
695 TQString imageName;
696 TQString fileInStore;
697
698
699 // give picture a name
700 //
701
702 imageName = "Picture ";
703 imageName += TQString::number (m_numPictures + 1); // image numbers start at 1...
704
705
706 // give picture a filename
707 //
708
709 fileInStore = "pictures/picture" + TQString::number (m_numPictures + 1);
710
711 kdDebug (30509) << "\tGetting type..." << endl;
712
713 // append extension
714 if (image->getIsBMP ())
715 fileInStore += ".bmp";
716 else if (image->getIsWMF () )
717 fileInStore += ".wmf";
718 else
719 ErrorAndQuit (MSWrite::Error::InternalError, "unsupported picture type\n");
720
721
722 // indicate anchored image in formatting
723 //
724 kdDebug (30509) << "\tIndicating anchored image in formatting" << endl;
725 if (!writeTextInternal ("#")) return false;
726
727 m_formatOutput += "<FORMAT id=\"6\" pos=\"0\" len=\"1\">";
728 m_formatOutput += "<ANCHOR type=\"frameset\" instance=\"";
729 m_formatOutput += imageName;
730 m_formatOutput += "\"/>";
731 m_formatOutput += "</FORMAT>";
732
733
734 // write framesets (truly written in documentEndWrite())
735 //
736 kdDebug (30509) << "\tWriting framesets!" << endl;
737
738 m_objectFrameset += "<FRAMESET frameType=\"2\" frameInfo=\"0\" name=\"";
739 m_objectFrameset += imageName;
740 m_objectFrameset += "\" visible=\"1\">";
741
742 m_objectFrameset += "<FRAME runaround=\"1\" copy=\"0\" newFrameBehavior=\"1\"";
743
744 const double imageLeft = double (m_left) + Twip2Point (double (image->getIndent ()));
745 m_objectFrameset += " left=\"";
746 m_objectFrameset += TQString::number (imageLeft);
747 m_objectFrameset += "\"";
748
749 const double imageWidth = Twip2Point (double (image->getDisplayedWidth ()));
750 m_objectFrameset += " right=\"";
751 m_objectFrameset += TQString::number (imageLeft + imageWidth - 1);
752 m_objectFrameset += "\"";
753
754 m_objectFrameset += " top=\"";
755 m_objectFrameset += TQString::number (m_top);
756 m_objectFrameset += "\"";
757
758 const double imageHeight = Twip2Point (double (image->getDisplayedHeight ()));
759 m_objectFrameset += " bottom=\"";
760 m_objectFrameset += TQString::number (double (m_top) + imageHeight - 1);
761 m_objectFrameset += "\"/>";
762
763 m_objectFrameset += "<PICTURE keepAspectRatio=\"false\">";
764 m_objectFrameset += "<KEY msec=\"0\" hour=\"0\" second=\"0\" minute=\"0\" day=\"1\" month=\"1\" year=\"1970\"";
765 m_objectFrameset += " filename=\"";
766 m_objectFrameset += fileInStore;
767 m_objectFrameset += "\"/>";
768 m_objectFrameset += "</PICTURE>";
769
770 m_objectFrameset += "</FRAMESET>";
771 #ifdef DEBUG_XML_OUTPUT
772 m_objectFrameset += "\n";
773 #endif
774
775 m_pictures += "<KEY msec=\"0\" hour=\"0\" second=\"0\" minute=\"0\" day=\"1\" month=\"1\" year=\"1970\"";
776 m_pictures += " name=\"";
777 m_pictures += fileInStore;
778 m_pictures += "\"";
779 m_pictures += " filename=\"";
780 m_pictures += fileInStore;
781 m_pictures += "\"/>";
782
783 m_numPictures++;
784
785
786 // store object properties
787 //
788 kdDebug (30509) << "\tStoring object" << endl;
789
790 if (!m_objectList.addToBack ())
791 ErrorAndQuit (MSWrite::Error::OutOfMemory, "could not allocate memory for object\n");
792
793 WRIObject &obj = *m_objectList.begin (false);
794 obj.m_nameInStore = fileInStore;
795 obj.m_dataLength = image->getExternalImageSize ();
796 obj.m_data = new MSWrite::Byte [obj.m_dataLength];
797 if (!obj.m_data)
798 ErrorAndQuit (MSWrite::Error::OutOfMemory, "could not allocate memory for object data\n");
799
800 // if anchored images could be positioned properly, this wouldn't be needed
801 m_objectHorizOffset = double (Twip2Point (image->getIndent ()));
802 m_paraIsImage = true;
803 }
804 else
805 {
806 if (ole)
807 {
808 if (!writeTextInternal ("[OLE unsupported]")) return false;
809 }
810
811 m_paraIsImage = false;
812 }
813
814
815 return true;
816 }
817
818 bool writeParaInfoEnd (const MSWrite::FormatParaProperty *paraProperty,
819 const MSWrite::OLE * /*ole*/,
820 const MSWrite::Image *image)
821
822 {
823 //kdDebug (30509) << "writeParaInfoEnd()" << endl;
824
825 if (image)
826 {
827 WRIObject &obj = *m_objectList.begin (false);
828
829 // consistency check: wrote exactly the right amount of data?
830 if (obj.m_dataUpto != obj.m_dataLength)
831 kdWarning (30509) << "obj.dataUpto (" << obj.m_dataUpto
832 << ") != obj.dataLength (" << obj.m_dataLength
833 << ")" << endl;
834 }
835
836 TQString output;
837 output += "</TEXT>";
838
839 output += "<LAYOUT>";
840 output += "<NAME value=\"Standard\"/>";
841
842 int align = paraProperty->getAlignment ();
843
844 if (align != MSWrite::Alignment::Left)
845 {
846 output += "<FLOW align=\"";
847 switch (align)
848 {
849 /*case MSWrite::Alignment::Left:
850 output += "left";
851 break;*/
852 case MSWrite::Alignment::Centre:
853 output += "center";
854 break;
855 case MSWrite::Alignment::Right:
856 output += "right";
857 break;
858 case MSWrite::Alignment::Justify:
859 output += "justify";
860 break;
861 }
862 output += "\"/>";
863 }
864
865 double indentFirst = Twip2Point (double (paraProperty->getLeftIndentFirstLine ()));
866 double indentLeft = Twip2Point (double (paraProperty->getLeftIndent ()));
867 double indentRight = Twip2Point (double (paraProperty->getRightIndent ()));
868
869 #if 0
870 debug ("raw indent: first: %i left: %i right: %i\n",
871 indentFirst, indentLeft, indentRight);
872 #endif
873
874 if (m_paraIsImage /*paraProperty->isObject ()*/ && m_objectHorizOffset)
875 {
876 if (align == MSWrite::Align::Center)
877 {
878 // TODO: I don't know what m_objectHorizOffset is relative to!
879 kdDebug (30509) << "ignoring image offset with centred image" << endl;
880 m_objectHorizOffset = 0;
881 }
882 else
883 {
884 // MSWrite does not add the horizontal offset of the image from the left margin to the Left Indent
885 // -- instead, it selects the bigger one
886 // TODO: proper image positioning (see doc IMPERFECT)
887 if (m_simulateImageOffset && m_objectHorizOffset > indentLeft)
888 {
889 kdDebug (30509) << "image is further away from left margin by itself, rather than using indentLeft ("
890 << m_objectHorizOffset << " > " << indentLeft << ")" << endl;
891 indentLeft = m_objectHorizOffset;
892 }
893 }
894 }
895
896 // hopefully these test operations will be cheaper than the XML ones :)
897 if (indentFirst || indentLeft || indentRight)
898 {
899 output += "<INDENTS";
900 if (indentFirst) output += " first=\"" + TQString::number (indentFirst) + "\"";
901 if (indentLeft) output += " left=\"" + TQString::number (indentLeft) + "\"";
902 if (indentRight) output += " right=\"" + TQString::number (indentRight) + "\"";
903 output += "/>";
904 }
905
906 MSWrite::Word lineSpacing = paraProperty->getLineSpacing ();
907
908 if (lineSpacing != MSWrite::LineSpacing::Single)
909 {
910 #if 1
911 output += "<LINESPACING type=\"atleast\" spacingvalue=\"" + TQString::number (Twip2Point (lineSpacing)) + "\"/>";
912 #else // old way
913 output += "<LINESPACING type=\"";
914 switch (lineSpacing)
915 {
916 //case MSWrite:;LineSpacing::Single:
917 // break;
918 case MSWrite::LineSpacing::OneAndAHalf:
919 output += "oneandhalf";
920 break;
921 case MSWrite::LineSpacing::Double:
922 output += "double";
923 break;
924 default:
925 kdWarning (30509) << "non-\"standard\" linespacing value: " << lineSpacing << endl;
926 output += "atleast\" ";
927 output += "spacingvalue=\"";
928 output += TQString::number (Twip2Point (lineSpacing));
929 break;
930 }
931 output += "\"/>";
932 #endif
933 }
934
935 // Do we want the linespacing to _look_ like it does in Write?
936 // (this adds extra space before each paragraph)
937 if (m_simulateLineSpacing)
938 {
939 // emulate Write's linespacing (aligned to bottom)
940 // by using varying amounts of space before the paragraph
941 // TODO: test if it works nicely enough (what if you have several different sized fonts in paragraph?)
942 if (lineSpacing != MSWrite::LineSpacing::Single) // if not normal linespacing...
943 {
944 output += "<OFFSETS before=\"";
945
946 int amount = 0;
947 switch (lineSpacing)
948 {
949 /*case MSWrite::LineSpacing::Single:
950 break;*/
951 case MSWrite::LineSpacing::OneAndAHalf:
952 amount = 7;
953 break;
954 case MSWrite::LineSpacing::Double:
955 amount = 14;
956 break;
957 default:
958 kdWarning (30509) << "unknown linespacing value: " << lineSpacing << endl;
959 break;
960 }
961
962 // subtract the amount of trailing linespace from last paragraph
963 amount -= m_lineSpacingFromAbove;
964 if (amount <= 0) amount = 0; // no emulation can be perfect...
965
966 output += TQString::number (amount);
967 output += "\" />";
968 }
969
970 // GUESS (TODO: fix) the amount of trailing linespace
971 switch (lineSpacing)
972 {
973 case MSWrite::LineSpacing::Single:
974 m_lineSpacingFromAbove = 0;
975 break;
976 case MSWrite::LineSpacing::OneAndAHalf:
977 m_lineSpacingFromAbove = 7;
978 break;
979 case MSWrite::LineSpacing::Double:
980 m_lineSpacingFromAbove = 14;
981 break;
982 default: // unknown
983 m_lineSpacingFromAbove = 0;
984 break;
985 }
986 } // if (m_simulateLineSpacing) {
987
988 if (m_pageBreak)
989 {
990 #if 0
991 debug ("\tpagebrk: output: offset: %i chars in paragraph: %i\n",
992 m_pageBreakOffset, m_charInfoCountStart + m_charInfoCountLen);
993 #endif
994
995 // page break before all the text
996 if (m_pageBreakOffset == 0 && m_charInfoCountStart + m_charInfoCountLen > 0)
997 {
998 output += "<PAGEBREAKING hardFrameBreak=\"true\"/>";
999 m_needAnotherParagraph = false; // this paragraph is on first page so we don't need another one
1000 }
1001 // we assume that the pageBreak was after all the text (TODO: don't assume this)
1002 else
1003 {
1004 output += "<PAGEBREAKING hardFrameBreakAfter=\"true\"/>";
1005 m_needAnotherParagraph = true; // need another paragraph for hardFrameBreakAfter to work
1006 }
1007
1008 m_pageBreak = false; // reset flag
1009 }
1010 else
1011 m_needAnotherParagraph = false;
1012
1013 // Tabulators
1014 for (int i = 0; i < paraProperty->getNumTabulator (); i++)
1015 {
1016 const MSWrite::FormatParaPropertyTabulator *tab = paraProperty->getTabulator (i);
1017 if (tab->getIsDummy ()) break;
1018
1019 output += "<TABULATOR";
1020
1021 if (tab->getIsDecimal ())
1022 output += " type=\"3\" alignchar=\".\"";
1023 else
1024 output += " type=\"0\"";
1025
1026 output += " ptpos=\"" + TQString::number (Twip2Point (double (tab->getIndent ()))) + "\"/>";
1027
1028 //debug ("Tab: isNormal: %i ptPos: %i\n",
1029 // paraProperty->tbd [i].isTabNormal (), paraProperty->tbd [i].getTabNumPoints ());
1030 }
1031
1032 output += "</LAYOUT>";
1033 #ifdef DEBUG_XML_OUTPUT
1034 output += "\n";
1035 #endif
1036
1037 output += "<FORMATS>";
1038 #ifdef DEBUG_XML_OUTPUT
1039 output += "\n";
1040 #endif
1041 // output all the charInfo for this paragraph
1042 output += m_formatOutput; m_formatOutput = "";
1043 output += "</FORMATS>";
1044 #ifdef DEBUG_XML_OUTPUT
1045 output += "\n";
1046 #endif
1047
1048 output += "</PARAGRAPH>";
1049 #ifdef DEBUG_XML_OUTPUT
1050 output += "\n";
1051 #endif
1052
1053 if (!writeTextInternal (output)) return false;
1054
1055 return true;
1056 }
1057
1058 bool writeCharInfoBegin (const MSWrite::FormatCharProperty * /*charProperty*/)
1059 {
1060 //kdDebug (30509) << "writeCharInfoBegin()" << endl;
1061
1062 return true;
1063 }
1064
1065 // outputs character formatting tags
1066 bool writeCharInfoEnd (const MSWrite::FormatCharProperty *charProperty,
1067 const bool = false)
1068 {
1069 //kdDebug (30509) << "writeCharInfoEnd()" << endl;
1070
1071 // output type of format information (page number or normal text)
1072 m_formatOutput += "<FORMAT id=\"";
1073 if (charProperty->getIsPageNumber ())
1074 m_formatOutput += "4";
1075 else
1076 m_formatOutput += "1";
1077 m_formatOutput += "\" ";
1078
1079 m_formatOutput += "pos=\""; m_formatOutput += TQString::number (m_charInfoCountStart); m_formatOutput += "\" ";
1080 m_formatOutput += "len=\""; m_formatOutput += TQString::number (m_charInfoCountLen); m_formatOutput += "\">";
1081
1082 m_charInfoCountStart += m_charInfoCountLen;
1083 m_charInfoCountLen = 0;
1084
1085 if (charProperty->getIsPageNumber ())
1086 {
1087 m_formatOutput += "<VARIABLE>";
1088 m_formatOutput += "<TYPE key=\"NUMBER\" type=\"4\"/>";
1089 m_formatOutput += "<PGNUM subtype=\"0\" value=\"1\"/>";
1090 m_formatOutput += "</VARIABLE>";
1091 }
1092
1093 m_formatOutput += "<FONT name=\"";
1094 m_formatOutput += (const char *) (charProperty->getFont ()->getName ());
1095 m_formatOutput += "\"/>";
1096 m_formatOutput += "<SIZE value=\"";
1097 m_formatOutput += TQString::number (charProperty->getFontSize ());
1098 m_formatOutput += "\"/>";
1099
1100 if (charProperty->getIsBold ())
1101 m_formatOutput += "<WEIGHT value=\"75\"/>";
1102 //else
1103 // m_formatOutput += "<WEIGHT value=\"50\" />";
1104
1105 if (charProperty->getIsItalic ())
1106 m_formatOutput += "<ITALIC value=\"1\"/>";
1107 // else
1108 // m_formatOutput += "<ITALIC value=\"0\" />";
1109
1110 if (charProperty->getIsUnderlined ())
1111 m_formatOutput += "<UNDERLINE value=\"1\"/>";
1112 // else
1113 // m_formatOutput += "<UNDERLINE value=\"0\" />";
1114
1115 /*if (charProperty->isNormalPosition ())
1116 m_formatOutput += "<VERTALIGN value=\"0\" />";
1117 else*/ if (charProperty->getIsSubscript ())
1118 m_formatOutput += "<VERTALIGN value=\"1\"/>";
1119 else if (charProperty->getIsSuperscript ())
1120 m_formatOutput += "<VERTALIGN value=\"2\"/>";
1121 /*else
1122 error ("unknown valign\n");*/
1123
1124 m_formatOutput += "</FORMAT>";
1125
1126 return true;
1127 }
1128
1129 bool writeBinary (const MSWrite::Byte *buffer, const MSWrite::DWord length)
1130 {
1131 kdDebug (30509) << "writeBinary()" << endl;
1132
1133 // must be OLE, TODO: implement OLE properly
1134 if (!m_paraIsImage)
1135 return true;
1136
1137 WRIObject &obj = *m_objectList.begin (false);
1138
1139 if (!obj.m_data)
1140 ErrorAndQuit (MSWrite::Error::InternalError, "object data not initialised\n");
1141
1142 // consistency check: aren't going to write past end of array?
1143 if (obj.m_dataUpto + length > obj.m_dataLength)
1144 {
1145 kdDebug (30509) << "object image overrun: "
1146 << obj.m_dataUpto << " + " << length
1147 << " > " << obj.m_dataLength << endl;
1148 ErrorAndQuit (MSWrite::Error::InternalError, "object image overrun\n");
1149 }
1150
1151 memcpy (obj.m_data + obj.m_dataUpto, buffer, length);
1152 obj.m_dataUpto += length;
1153
1154 return true;
1155 }
1156
1157
1158
1159 //
1160 // text output functions
1161 //
1162
1163 bool writeText (const MSWrite::Byte *string)
1164 {
1165 // from Win Character Set...
1166 TQString strUnicode;
1167
1168 // there is a codec, therefore there is a decoder...
1169 if (m_codec)
1170 {
1171 // output Unicode (UTF8)
1172 strUnicode = m_decoder->toUnicode ((const char *) string, strlen ((const char *) string));
1173 }
1174 else
1175 {
1176 // output a plain string still in wrong Character Set
1177 // (hopefully the user won't notice)
1178 strUnicode = (const char *) string;
1179 }
1180
1181 // update character information counter (after charset conversion)
1182 m_charInfoCountLen += strUnicode.length ();
1183
1184 // make string XML-friendly (TODO: speed up)
1185 strUnicode.replace ('&', "&amp;");
1186 strUnicode.replace ('<', "&lt;");
1187 strUnicode.replace ('>', "&gt;");
1188 strUnicode.replace ('\"', "&quot;");
1189 strUnicode.replace ('\'', "&apos;");
1190
1191 return writeTextInternal (strUnicode);
1192 }
1193
1194 bool writeTextInternal (const MSWrite::Byte *str)
1195 {
1196 #if 0
1197 return textWrite_lowLevel (TQString (str));
1198 #else // while this is code duplication (of below func), this ensures that no
1199 // characters are mysteriously converted (this makes writeOptionalHyphen () work)
1200 if (m_delayOutput)
1201 {
1202 // header/footer must be written after main body
1203 m_heldOutput += (const char *) str;
1204 return true;
1205 }
1206 else
1207 {
1208 int strLength = strlen ((const char *) str);
1209
1210 if (m_outfile->writeBlock ((const char *) str, strLength) != strLength)
1211 {
1212 ErrorAndQuit (MSWrite::Error::FileError, "could not write to maindoc.xml\n");
1213 }
1214 else
1215 return true;
1216 }
1217 #endif
1218 }
1219
1220 bool writeTextInternal (const TQString &str)
1221 {
1222 if (m_delayOutput)
1223 {
1224 // header/footer must be written after main body
1225 m_heldOutput += str;
1226 return true;
1227 }
1228 else
1229 {
1230 TQCString strUtf8 = str.utf8 ();
1231 int strLength = strUtf8.length ();
1232
1233 if (m_outfile->writeBlock (strUtf8, strLength) != strLength)
1234 {
1235 ErrorAndQuit (MSWrite::Error::FileError, "could not write to maindoc.xml (2)\n");
1236 }
1237 else
1238 return true;
1239 }
1240 }
1241
1242 bool writeTextInternal (const int num)
1243 {
1244 return writeTextInternal (TQString::number (num));
1245 }
1246
1247 bool writeTextInternal (const char *format, ...)
1248 {
1249 va_list list;
1250 va_start (list, format);
1251
1252 bool ret;
1253 // This function is mainly for outputting tags (where XML characters are
1254 // already escaped and the text is in the right character set...ASCII
1255 // = UTF-8 for alphanumeric chars I hope). So _don't_ pass user text
1256 // to this function (that's what writeText() is for); otherwise you might
1257 // exceed this 1024 limit.
1258 char string [1024];
1259
1260 vsnprintf (string, sizeof (string) - 1, format, list);
1261 string [sizeof (string) - 1] = '\0';
1262
1263 ret = writeTextInternal ((const MSWrite::Byte *) string);
1264
1265 va_end (list);
1266 return ret;
1267 }
1268
1269
1270 // writePageNew() is called for the pageTable
1271 // -- however, pageTable can be very inaccurate, so we ignore it
1272 bool writePageNew (const int)
1273 {
1274 return true;
1275 }
1276
1277 // handles explicit page breaks
1278 bool writePageBreak (void)
1279 {
1280 // later used in paraEndWrite
1281 m_pageBreak = true;
1282 m_pageBreakOffset = m_charInfoCountStart + m_charInfoCountLen;
1283
1284 return true;
1285 }
1286
1287 // handle "(page)" number
1288 bool writePageNumber (void)
1289 {
1290 m_charInfoCountLen++; // not incremented by writeTextInternal()
1291 return writeTextInternal ("#");
1292 }
1293
1294 bool writeCarriageReturn (void)
1295 {
1296 return true; // ignore CR
1297 }
1298
1299 // write newline unless end-of-paragraph
1300 // (this is the support for paragraphs with multiple newlines)
1301 bool writeNewLine (const bool endOfParagraph)
1302 {
1303 if (!endOfParagraph)
1304 {
1305 m_charInfoCountLen++; // not incremented by writeTextInternal()
1306 return writeTextInternal ("\n");
1307 }
1308 else
1309 return true;
1310 }
1311
1312 // aka "soft hyphen"
1313 bool writeOptionalHyphen (void)
1314 {
1315 m_charInfoCountLen++; // not incremented by writeTextInternal()
1316 return writeTextInternal ("\xC2\xAD");
1317 }
1318
1319 void setKOfficeLink (MSWriteImport *kofficeLink)
1320 {
1321 m_koLink = kofficeLink;
1322 }
1323
1324 void sigProgress (const int value)
1325 {
1326 m_koLink->sigProgress (value);
1327 }
1328};
1329
1330
1331
1332//
1333// KoFilter
1334//
1335
1336MSWriteImport::MSWriteImport (KoFilter *, const char *, const TQStringList &)
1337 : m_device (NULL), m_parser (NULL), m_generator (NULL)
1338{
1339}
1340
1341MSWriteImport::~MSWriteImport ()
1342{
1343 delete m_generator;
1344 delete m_parser;
1345 delete m_device;
1346}
1347
1348KoFilter::ConversionStatus MSWriteImport::convert (const TQCString &from, const TQCString &to)
1349{
1350 kdDebug (30509) << "MSWriteImport $Date: 2006-02-12 19:28:12 +0100 (Sun, 12 Feb 2006) $ using LibMSWrite "
1351 << MSWrite::Version << endl;
1352
1353 if (to != "application/x-kword" || from != "application/x-mswrite")
1354 {
1355 kdError (30509) << "Internal error! Filter not implemented?" << endl;
1356 return KoFilter::NotImplemented;
1357 }
1358
1359#if 0
1360 //MSWriteImportDialog *dialog = new MSWriteImportDialog ();
1361 MSWriteImportDialog dialog;
1362
1363 /*debug ("DIALOG check alloc\n");
1364 if (!dialog)
1365 {
1366 error ("Could not allocate memory for dialog\n");
1367 return KoFilter::StupidError;
1368 }*/
1369
1370 debug ("DIALOG EXEC!!!\n");
1371 if (!dialog.exec ())
1372 {
1373 error ("Dialog was aborted! Aborting filter!\n");
1374 return KoFilter::UserCancelled;
1375 }
1376
1377 debug ("DIALOG GET!!!\n");
1378
1379 // read settings from dialog
1380 m_codec = dialog.getCodec ();
1381 m_simulateLinespacing = dialog.getSimulateLinespacing ();
1382 m_simulateImageOffset = dialog.getSimulateImageOffset ();
1383 debug ("Import options: simulateLinespacing: %i\tsimulateImageOffset: %i\n",
1384 m_simulateLinespacing, m_simulateImageOffset);
1385
1386 debug ("DIALOG DELETE\n");
1387 //delete dialog;
1388#endif
1389
1390 // create the Device that will read from the .WRI file
1391 m_device = new WRIDevice;
1392 if (!m_device)
1393 {
1394 kdError (30509) << "Could not allocate memory for device" << endl;
1395 return KoFilter::OutOfMemory;
1396 }
1397
1398 // open the .WRI file
1399 if (!m_device->openFile (TQFile::encodeName (m_chain->inputFile ())))
1400 {
1401 kdError (30509) << "Could not open \'" << m_chain->inputFile () << "\'" << endl;
1402 return KoFilter::FileNotFound;
1403 }
1404
1405
1406 // create Parser that will interpret the .WRI file and call the Generator
1407 m_parser = new MSWrite::InternalParser;
1408 if (!m_parser)
1409 {
1410 kdError (30509) << "Could not allocate memory for parser" << endl;
1411 return KoFilter::OutOfMemory;
1412 }
1413
1414 // tell the Parser to use the Device to read from the .WRI file
1415 m_parser->setDevice (m_device);
1416
1417
1418 // create Generator that will produce the .KWD file
1419 m_generator = new KWordGenerator;
1420 if (!m_generator)
1421 {
1422 kdError (30509) << "Could not allocate memory for generator" << endl;
1423 return KoFilter::OutOfMemory;
1424 }
1425
1426 // give the Generator the Device for error-handling purposes
1427 m_generator->setDevice (m_device);
1428
1429 // give the Generator the chain
1430 m_generator->setFilterChain (m_chain);
1431
1432 // hand over sigProgess to give some feedback to the user
1433 m_generator->setKOfficeLink (this);
1434
1435
1436 // hook up Generator to Parser
1437 m_parser->setGenerator (m_generator);
1438
1439
1440 // filter!
1441 if (!m_parser->parse ())
1442 {
1443 // try to return somewhat more meaningful errors than StupidError
1444 // for the day that KOffice actually reports them to the user properly
1445 int errorCode = m_device->bad ();
1446 switch (errorCode)
1447 {
1448 case MSWrite::Error::Ok:
1449 kdDebug (30509) << "Error::Ok but aborted???" << endl;
1450 return KoFilter::InternalError;
1451
1452 case MSWrite::Error::Warn:
1453 kdDebug (30509) << "Error::Warn" << endl;
1454 return KoFilter::InternalError; // warnings should _never_ set m_error
1455
1456 case MSWrite::Error::InvalidFormat:
1457 kdDebug (30509) << "Error::InvalidFormat" << endl;
1458 return KoFilter::WrongFormat;
1459
1460 case MSWrite::Error::OutOfMemory:
1461 kdDebug (30509) << "Error::OutOfMemory" << endl;
1462 return KoFilter::OutOfMemory;
1463
1464 case MSWrite::Error::InternalError:
1465 kdDebug (30509) << "Error::InternalError" << endl;
1466 return KoFilter::InternalError;
1467
1468 case MSWrite::Error::Unsupported:
1469 kdDebug (30509) << "Error::Unsupported" << endl;
1470 return KoFilter::InternalError;
1471
1472 case MSWrite::Error::FileError:
1473 kdDebug (30509) << "Error::FileError" << endl;
1474 return KoFilter::StupidError; // got a better return value?
1475 }
1476
1477 kdWarning (30509) << "Unknown error: " << errorCode << endl;
1478 return KoFilter::StupidError;
1479 }
1480
1481 return KoFilter::OK;
1482}
1483
1484#include <mswriteimport.moc>