filters

mswriteimport.cc

00001 /* This file is part of the KDE project
00002    Copyright (C) 2001-2003 Clarence Dang <dang@kde.org>
00003 
00004    This library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License Version 2 as published by the Free Software Foundation.
00007 
00008    This library is distributed in the hope that it will be useful,
00009    but WITHOUT ANY WARRANTY; without even the implied warranty of
00010    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00011    Library General Public License Version 2 for more details.
00012 
00013    You should have received a copy of the GNU Library General Public License
00014    Version 2 along with this library; see the file COPYING.LIB.  If not,
00015    write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00016  * Boston, MA 02110-1301, USA.
00017 */
00018 
00019 #ifndef NDEBUG
00020     //#define DEBUG_XML_OUTPUT
00021 #endif
00022 
00023 #include <stdio.h>
00024 #include <string.h>
00025 #include <stdarg.h>
00026 
00027 #include <qfile.h>
00028 #include <qobject.h>
00029 #include <qstring.h>
00030 #include <qtextcodec.h>
00031 #include <qtextstream.h>
00032 
00033 #include <kdebug.h>
00034 #include <kgenericfactory.h>
00035 
00036 #include <KoFilterChain.h>
00037 #include <KoStore.h>
00038 
00039 #include "list.h"
00040 #include "libmswrite.h"
00041 
00042 #include "ImportDialog.h"
00043 #include "mswriteimport.h"
00044 
00045 
00046 class MSWriteImportFactory : KGenericFactory <MSWriteImport, KoFilter>
00047 {
00048 public:
00049     MSWriteImportFactory () : KGenericFactory <MSWriteImport, KoFilter> ("kwordmswriteimport")
00050     {
00051     }
00052 
00053 protected:
00054     virtual void setupTranslations (void)
00055     {
00056         KGlobal::locale()->insertCatalogue ("kofficefilters");
00057     }
00058 };
00059 
00060 K_EXPORT_COMPONENT_FACTORY (libmswriteimport, MSWriteImportFactory ())
00061 
00062 
00063 //
00064 // Device that reads from .WRI file
00065 //
00066 
00067 class WRIDevice : public MSWrite::Device
00068 {
00069 private:
00070     FILE *m_infp;
00071 
00072 public:
00073     WRIDevice () : m_infp (NULL)
00074     {
00075     }
00076 
00077     virtual ~WRIDevice ()
00078     {
00079         closeFile ();
00080     }
00081 
00082     bool openFile (const char *fileName)
00083     {
00084         m_infp = fopen (fileName, "rb");
00085         if (!m_infp)
00086         {
00087             error (MSWrite::Error::FileError, "could not open file for reading\n");
00088             return false;
00089         }
00090 
00091         return true;
00092     }
00093 
00094     bool closeFile (void)
00095     {
00096         if (m_infp)
00097         {
00098             if (fclose (m_infp))
00099             {
00100                 error (MSWrite::Error::FileError, "could not close input file\n");
00101                 return false;
00102             }
00103 
00104             m_infp = NULL;
00105         }
00106 
00107         return true;
00108     }
00109 
00110     bool read (MSWrite::Byte *buf, const MSWrite::DWord numBytes)
00111     {
00112         if (fread (buf, 1, (size_t) numBytes, m_infp) != (size_t) numBytes)
00113         {
00114             error (MSWrite::Error::FileError, "could not read from input file\n");
00115             return false;
00116         }
00117 
00118         return true;
00119     }
00120 
00121     bool write (const MSWrite::Byte *, const MSWrite::DWord)
00122     {
00123         error (MSWrite::Error::InternalError, "writing to an input file?\n");
00124         return false;
00125     }
00126 
00127     bool seek (const long offset, const int whence)
00128     {
00129         if (fseek (m_infp, offset, whence))
00130         {
00131             error (MSWrite::Error::InternalError, "could not seek input file\n");
00132             return false;
00133         }
00134 
00135         return true;
00136     }
00137 
00138     long tell (void)
00139     {
00140         return ftell (m_infp);
00141     }
00142 
00143     void debug (const char *s)
00144     {
00145         kdDebug (30509) << s;
00146     }
00147 
00148     void debug (const int i)
00149     {
00150         kdDebug (30509) << i;
00151     }
00152 
00153     void error (const int errorCode, const char *message,
00154                     const char * /*file*/ = "", const int /*lineno*/ = 0,
00155                     MSWrite::DWord /*tokenValue*/ = NoToken)
00156     {
00157         if (errorCode == MSWrite::Error::Warn)
00158             kdWarning (30509) << message;
00159         else
00160         {
00161             m_error = errorCode;
00162             kdError (30509) << message;
00163         }
00164     }
00165 };
00166 
00167 
00168 //
00169 // Generator that creates the KWord file
00170 //
00171 
00172 class KWordGenerator : public MSWrite::Generator, public MSWrite::NeedsDevice
00173 {
00174 private:
00175     // KoStore can only have 1 file open at a time
00176     // so we store objects in this structure temporarily
00177     class WRIObject
00178     {
00179     private:
00180         WRIObject (const WRIObject &rhs);
00181 
00182     public:
00183         MSWrite::Byte *m_data;
00184         MSWrite::DWord m_dataLength;
00185         MSWrite::DWord m_dataUpto;
00186         QString m_nameInStore;
00187 
00188         WRIObject () : m_data (NULL), m_dataLength (0), m_dataUpto (0)
00189         {
00190         }
00191 
00192         ~WRIObject ()
00193         {
00194             delete [] m_data;
00195         }
00196 
00197         WRIObject operator= (const WRIObject &rhs)
00198         {
00199             delete [] m_data;
00200 
00201             m_dataLength = rhs.m_dataLength;
00202             m_dataUpto = rhs.m_dataUpto;
00203             m_nameInStore = rhs.m_nameInStore;
00204 
00205             if (rhs.m_data)
00206             {
00207                 m_data = new MSWrite::Byte [m_dataLength];
00208                 if (m_data)
00209                     memcpy (m_data, rhs.m_data, m_dataLength);
00210                 // remember to check m_data before use
00211             }
00212             else
00213                 m_data = NULL;
00214 
00215             return *this;
00216         }
00217     };
00218 
00219     // page/margin dimensions
00220     int m_pageWidth, m_pageHeight;
00221     int m_left, m_right, m_top, m_bottom;       // describing border of Text Frameset (position, not magnitude)
00222     int m_leftMargin, m_rightMargin, m_topMargin, m_bottomMargin;
00223     int m_headerFromTop, m_footerFromTop;
00224     bool m_hasHeader, m_isHeaderOnFirstPage;
00225     bool m_hasFooter, m_isFooterOnFirstPage;
00226     bool m_writeHeaderFirstTime, m_writeFooterFirstTime;
00227 
00228     int inWhat;
00229 
00230     enum inWhatPossiblities
00231     {
00232         Nothing,
00233         Header,
00234         Footer,
00235         Body
00236     };
00237 
00238     int m_startingPageNumber;
00239 
00240     KoFilterChain *m_chain;
00241     KoStoreDevice *m_outfile;
00242 
00243     // for charset conversion
00244     QTextCodec *m_codec;
00245     QTextDecoder *m_decoder;
00246 
00247     // import options (compensate for differences between KWord and MS Write)
00248     bool m_simulateLineSpacing;
00249     bool m_simulateImageOffset;
00250 
00251     // formatting
00252     QString m_formatOutput;
00253     int m_charInfoCountStart, m_charInfoCountLen;
00254     bool m_pageBreak, m_needAnotherParagraph;
00255     int m_pageBreakOffset;
00256     int m_lineSpacingFromAbove;
00257 
00258     // picture counters
00259     int m_numPictures;
00260     QString m_pictures;
00261 
00262     QString m_objectFrameset;
00263 
00264     MSWrite::List <WRIObject> m_objectList;
00265 
00266     double m_objectHorizOffset;
00267     bool m_paraIsImage;
00268 
00269     MSWriteImport *m_koLink;
00270 
00271     // XML output that is held back until after "Text Frameset 1" is output
00272     // (i.e. header & footer must come after the Body in KWord)
00273     bool m_delayOutput;
00274     QString m_heldOutput;
00275 
00276     void delayOutput (const bool yes)
00277     {
00278         m_delayOutput = yes;
00279     }
00280 
00281     bool delayOutputFlush (void)
00282     {
00283         QCString strUtf8 = m_heldOutput.utf8 ();
00284         int strLength = strUtf8.length ();
00285 
00286         if (m_outfile->writeBlock (strUtf8, strLength) != strLength)
00287             ErrorAndQuit (MSWrite::Error::FileError, "could not write delayed output\n");
00288 
00289         m_heldOutput = "";
00290         return true;
00291     }
00292 
00293 public:
00294     KWordGenerator () : m_hasHeader (false), m_isHeaderOnFirstPage (false),
00295                                 m_hasFooter (false), m_isFooterOnFirstPage (false),
00296                                 m_writeHeaderFirstTime (true), m_writeFooterFirstTime (true),
00297                                 inWhat (Nothing),
00298                                 m_decoder (NULL),
00299                                 m_simulateLineSpacing (false),
00300                                 m_simulateImageOffset (true),
00301                                 m_pageBreak (false), m_needAnotherParagraph (false),
00302                                 m_lineSpacingFromAbove (0),
00303                                 m_numPictures (0)
00304     {
00305         delayOutput (false);
00306 
00307         // just select windows-1252 until the "Select Encoding" dialog works
00308         m_codec = QTextCodec::codecForName ("CP 1252");
00309 
00310         if (m_codec)
00311             m_decoder = m_codec->makeDecoder();
00312         else
00313             kdWarning (30509) << "Cannot convert from Win Charset!" << endl;
00314     }
00315 
00316     virtual ~KWordGenerator ()
00317     {
00318         delete m_decoder;
00319     }
00320 
00321     void setFilterChain (KoFilterChain *chain)
00322     {
00323         m_chain = chain;
00324     }
00325 
00326     bool writeDocumentBegin (const MSWrite::Word,
00327                                         const MSWrite::PageLayout *pageLayout)
00328     {
00329         kdDebug (30509) << "writeDocumentBegin()" << endl;
00330 
00331         // open maindoc.xml
00332         m_outfile = m_chain->storageFile ("root", KoStore::Write);
00333         if (!m_outfile)
00334             ErrorAndQuit (MSWrite::Error::FileError, "could not open root in store\n");
00335 
00336 
00337         //
00338         // store page dimensions for now
00339         //
00340 
00341         // page width & height
00342         m_pageWidth = Twip2Point (pageLayout->getPageWidth ());
00343         m_pageHeight = Twip2Point (pageLayout->getPageHeight ());
00344 
00345         // offset of margins
00346         m_left = Twip2Point (pageLayout->getLeftMargin ());
00347         m_right = m_left + Twip2Point (pageLayout->getTextWidth ()) - 1;
00348         m_top = Twip2Point (pageLayout->getTopMargin ());
00349         m_bottom = m_top + Twip2Point (pageLayout->getTextHeight ()) - 1;
00350 
00351         // size of margins
00352         m_leftMargin = m_left;
00353         m_rightMargin = Twip2Point (pageLayout->getRightMargin ());
00354         m_topMargin = m_top;
00355         m_bottomMargin = Twip2Point (pageLayout->getBottomMargin ());
00356 
00357         kdDebug (30509) << "leftMargin: " << m_leftMargin << endl;
00358         kdDebug (30509) << "rightMargin: " << m_rightMargin << endl;
00359         kdDebug (30509) << "topMargin: " << m_topMargin << endl;
00360         kdDebug (30509) << "bottomMargin: " << m_bottomMargin << endl;
00361 
00362         // offset of header & footer
00363         m_headerFromTop = Twip2Point (pageLayout->getHeaderFromTop ());
00364         m_footerFromTop = Twip2Point (pageLayout->getFooterFromTop ());
00365 
00366         kdDebug (30509) << "headerFromTop: " << m_headerFromTop
00367                                 << " footerFromTop: " << m_footerFromTop << endl;
00368 
00369         m_startingPageNumber = pageLayout->getPageNumberStart ();
00370 
00371         return true;
00372     }
00373 
00374     bool writeDocumentBeginForReal (void)
00375     {
00376         kdDebug (30509) << "writeDocumentBeginForReal()" << endl;
00377 
00378         // adjust margins/PAPERBORDERS to ensure that the header & footer are
00379         // within them
00380         // TODO: stop header & footer from changing body's location
00381         // TODO: recompute offset of margins after recomputing margins
00382         if (m_hasHeader)
00383             if (m_headerFromTop < m_topMargin)
00384                 m_topMargin = m_headerFromTop;
00385 
00386         if (m_hasFooter)
00387             if (m_pageHeight - m_footerFromTop < m_bottomMargin)
00388                 m_bottomMargin = m_pageHeight - m_footerFromTop;
00389 
00390         kdDebug (30509) << "adjusted::: leftMargin: " << m_leftMargin
00391                                 << "  rightMargin: " << m_rightMargin
00392                                 << "  topMargin: " << m_topMargin
00393                                 << "  bottomMargin: " << m_bottomMargin
00394                                 << endl;
00395 
00396         // start document
00397         // TODO: error checking
00398         writeTextInternal ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
00399         writeTextInternal ("<!DOCTYPE DOC PUBLIC \"-//KDE//DTD kword 1.3//EN\" "
00400                                     "\"http://www.koffice.org/DTD/kword-1.3.dtd\">");
00401         writeTextInternal ("<DOC xmlns=\"http://www.koffice.org/DTD/kword\" "
00402                                     "mime=\"application/x-kword\" "
00403                                     "syntaxVersion=\"3\" editor=\"KWord\">");
00404 
00405         writeTextInternal ("<PAPER format=\"1\" "
00406                                     "width=\"%i\" height=\"%i\" "
00407                                     "orientation=\"0\" columns=\"1\" "
00408                                     "hType=\"%i\" fType=\"%i\">",
00409                                     m_pageWidth, m_pageHeight,
00410                                     m_isHeaderOnFirstPage ? 0 : 2,
00411                                     m_isFooterOnFirstPage ? 0 : 2);
00412 
00413         writeTextInternal ("<PAPERBORDERS left=\"%i\" right=\"%i\" "
00414                                     "top=\"%i\" bottom=\"%i\"/>",
00415                                     m_leftMargin, m_rightMargin,
00416                                     m_topMargin, m_bottomMargin);
00417 
00418         writeTextInternal ("</PAPER>");
00419 
00420         writeTextInternal ("<ATTRIBUTES processing=\"0\" "
00421                                     "tabStopValue=\"%lf\" "
00422                                     "hasHeader=\"%i\" hasFooter=\"%i\"/>",
00423                                     Inch2Point (0.5),
00424                                     m_hasHeader ? 1 : 0, m_hasFooter ? 1 : 0);
00425 
00426         // handle page numbering not starting from 1
00427         if (m_startingPageNumber != 1)
00428             writeTextInternal ("<VARIABLESETTINGS startingPageNumber=\"%i\"/>",
00429                                         m_startingPageNumber);
00430 
00431         writeTextInternal ("<FRAMESETS>");
00432 
00433         return true;
00434     }
00435 
00436     bool writeDocumentEnd (const MSWrite::Word, const MSWrite::PageLayout *)
00437     {
00438         kdDebug (30509) << "writeDocumentEnd()" << endl;
00439 
00440         // write framesets for the objects
00441         writeTextInternal (m_objectFrameset);
00442 
00443         writeTextInternal ("</FRAMESETS>");
00444         writeTextInternal ("<STYLES>");
00445         writeTextInternal ("<STYLE>");
00446             writeTextInternal ("<NAME value=\"Standard\"/>");
00447             writeTextInternal ("<FLOW align=\"left\"/>");
00448             writeTextInternal ("<INDENTS first=\"0\" left=\"0\" right=\"0\"/>");
00449             writeTextInternal ("<OFFSETS before=\"0\" after=\"0\"/>");
00450 
00451             writeTextInternal ("<FORMAT id=\"1\">");
00452                 writeTextInternal ("<COLOR blue=\"0\" red=\"0\" green=\"0\"/>");
00453                 writeTextInternal ("<FONT name=\"helvetica\"/>");
00454                 writeTextInternal ("<SIZE value=\"12\"/>");
00455                 writeTextInternal ("<WEIGHT value=\"50\"/>");
00456                 writeTextInternal ("<ITALIC value=\"0\"/>");
00457                 writeTextInternal ("<UNDERLINE value=\"0\"/>");
00458                 writeTextInternal ("<STRIKEOUT value=\"0\"/>");
00459                 writeTextInternal ("<VERTALIGN value=\"0\"/>");
00460             writeTextInternal ("</FORMAT>");
00461 
00462             writeTextInternal ("<FOLLOWING name=\"Standard\"/>");
00463         writeTextInternal ("</STYLE>");
00464         writeTextInternal ("</STYLES>");
00465 
00466         // write out image keys
00467         writeTextInternal ("<PICTURES>");
00468             writeTextInternal (m_pictures);
00469         writeTextInternal ("</PICTURES>");
00470 
00471         // end document
00472         writeTextInternal ("</DOC>");
00473 
00474         // close maindoc.xml
00475         m_outfile->close ();
00476         m_outfile = (KoStoreDevice *) NULL;
00477 
00478         //
00479         // output object data
00480 
00481         /*if (m_objectUpto != getNumObjects ())
00482             warning ("m_objectUpto (%i) != getNumObjects() (%i) -- this is probably because OLE is unimplemented\n",
00483                         m_objectUpto, getNumObjects ());*/
00484 
00485         MSWrite::List <WRIObject>::Iterator it;
00486         MSWrite::List <WRIObject>::Iterator end(m_objectList.end ());
00487         for (it = m_objectList.begin (); it != end; ++it)
00488         {
00489             kdDebug (30509) << "outputting object \'" << (*it).m_nameInStore
00490                                     << "\'   (length: " << (*it).m_dataLength << ")"
00491                                     << endl;
00492 
00493             if (!(*it).m_data)
00494                 ErrorAndQuit (MSWrite::Error::InternalError, "image data not initialised\n");
00495 
00496             // open file for object in store
00497             m_outfile = m_chain->storageFile ((*it).m_nameInStore, KoStore::Write);
00498             if (!m_outfile)
00499                 ErrorAndQuit (MSWrite::Error::FileError, "could not open image in store\n");
00500 
00501             if (m_outfile->writeBlock ((const char *) (*it).m_data, (*it).m_dataLength)
00502                 != (Q_LONG) (*it).m_dataLength)
00503                 ErrorAndQuit (MSWrite::Error::FileError, "could not write image to store\n");
00504 
00505             // close object in store
00506             m_outfile->close ();
00507             m_outfile = NULL;
00508         }
00509 
00510         return true;
00511     }
00512 
00513 
00514     bool writeFooterBegin (void)
00515     {
00516         kdDebug (30509) << "writeFooterBegin()" << endl;
00517 
00518         inWhat = Footer;
00519         m_hasFooter = true;
00520 
00521         // footers must go after body in KWord
00522         delayOutput (true);
00523 
00524         // footer frameset will be written in writeParaInfoBegin()
00525 
00526         return true;
00527     }
00528 
00529     bool writeFooterEnd (void)
00530     {
00531         kdDebug (30509) << "writeFooterEnd()" << endl;
00532 
00533         inWhat = Nothing;
00534 
00535         if (!m_writeFooterFirstTime)
00536             writeTextInternal ("</FRAMESET>");
00537         delayOutput (false);
00538 
00539         return true;
00540     }
00541 
00542     bool writeHeaderBegin (void)
00543     {
00544         kdDebug (30509) << "writeHeaderBegin()" << endl;
00545 
00546         inWhat = Header;
00547         m_hasHeader = true;
00548 
00549         // headers must go after body in KWord
00550         delayOutput (true);
00551 
00552         // header frameset will be written in writeParaInfoBegin()
00553 
00554         return true;
00555     }
00556 
00557     bool writeHeaderEnd (void)
00558     {
00559         kdDebug (30509) << "writeHeaderEnd()" << endl;
00560 
00561         inWhat = Nothing;
00562 
00563         if (!m_writeHeaderFirstTime)
00564             writeTextInternal ("</FRAMESET>");
00565         delayOutput (false);
00566 
00567         return true;
00568     }
00569 
00570     bool writeBodyBegin (void)
00571     {
00572         kdDebug (30509) << "writeBodyBegin()" << endl;
00573 
00574         inWhat = Body;
00575 
00576         // writeFooterBegin() and writeHeaderBegin() have been called by now
00577         // so we have enough information to actually write about them
00578         writeDocumentBeginForReal ();
00579 
00580         writeTextInternal ("<FRAMESET frameType=\"1\" frameInfo=\"0\" name=\"Text Frameset 1\" visible=\"1\">");
00581         // TODO: runaround?
00582         writeTextInternal ("<FRAME runaround=\"1\" autoCreateNewFrame=\"1\" newFrameBehavior=\"0\" copy=\"0\""
00583                                     " top=\"%i\" bottom=\"%i\" left=\"%i\" right=\"%i\"/>",
00584                                     m_top, m_bottom, m_left, m_right);
00585 
00586         return true;
00587     }
00588 
00589     bool writeBodyEnd (void)
00590     {
00591         kdDebug (30509) << "writeBodyEnd()" << endl;
00592 
00593         inWhat = Nothing;
00594 
00595         // <PAGEBREAKING hardFrameBreakAfter=\"true\"/>" may have been in the last paragraph
00596         // and for "hardFrameBreakAfter" to do its work, we need one more final paragraph!
00597         if (m_needAnotherParagraph)
00598         {
00599             kdDebug (30509) << "needAnotherParagraph in bodyEndWrite()" << endl;
00600             writeTextInternal ("<PARAGRAPH><TEXT></TEXT><LAYOUT></LAYOUT></PARAGRAPH>");
00601             m_needAnotherParagraph = false;
00602         }
00603 
00604         writeTextInternal ("</FRAMESET>");
00605 
00606         // since "Text Frameset 1" has ended, we can output the header & footer, now
00607         delayOutputFlush ();
00608 
00609         return true;
00610     }
00611 
00612     bool writeParaInfoBegin (const MSWrite::FormatParaProperty *paraProperty,
00613                                         const MSWrite::OLE *ole,
00614                                         const MSWrite::Image *image)
00615     {
00616         //kdDebug (30509) << "writeParaInfoBegin()" << endl;
00617 
00618         // reset charInfo counters
00619         m_charInfoCountStart = 0;
00620         m_charInfoCountLen = 0;
00621 
00622         if (inWhat == Header)
00623         {
00624             m_isHeaderOnFirstPage = paraProperty->getIsOnFirstPage ();
00625 
00626             if (m_writeHeaderFirstTime)
00627             {
00628                 // dummy header frames
00629                 //
00630 
00631                 // except, if the header is NOT on the first page, then make an empty "First Page Header"
00632                 // by setting "visible=1"
00633                 writeTextInternal ("<FRAMESET frameType=\"1\" frameInfo=\"1\" name=\"First Page Header\" visible=\"%i\">",
00634                                             m_isHeaderOnFirstPage ? 1 : 0);
00635                 writeTextInternal ("<FRAME runaround=\"1\" copy=\"0\" newFrameBehavior=\"2\" autoCreateNewFrame=\"0\""
00636                                             " top=\"%i\" bottom=\"%i\" left=\"%i\" right=\"%i\"/>",
00637                                             m_headerFromTop, m_headerFromTop, m_left, m_right);
00638                 writeTextInternal ("</FRAMESET>");
00639 
00640                 writeTextInternal ("<FRAMESET frameType=\"1\" frameInfo=\"2\" name=\"Even Pages Header\" visible=\"0\">");
00641                 writeTextInternal ("<FRAME runaround=\"1\" copy=\"0\" newFrameBehavior=\"2\" autoCreateNewFrame=\"0\""
00642                                             " top=\"%i\" bottom=\"%i\" left=\"%i\" right=\"%i\"/>",
00643                                             m_headerFromTop, m_headerFromTop, m_left, m_right);
00644                 writeTextInternal ("</FRAMESET>");
00645 
00646                 // real header frame
00647                 writeTextInternal ("<FRAMESET frameType=\"1\" frameInfo=\"3\" name=\"Odd Pages Header\" visible=\"1\">");
00648                 writeTextInternal ("<FRAME runaround=\"1\" copy=\"1\" newFrameBehavior=\"2\" autoCreateNewFrame=\"0\""
00649                                             " top=\"%i\" bottom=\"%i\" left=\"%i\" right=\"%i\"/>",
00650                                             m_headerFromTop, m_headerFromTop, m_left, m_right);
00651 
00652                 m_writeHeaderFirstTime = false;
00653             }
00654         }
00655         else if (inWhat == Footer)
00656         {
00657             m_isFooterOnFirstPage = paraProperty->getIsOnFirstPage ();
00658 
00659             if (m_writeFooterFirstTime)
00660             {
00661                 // dummy footer frames
00662                 //
00663 
00664                 // except, if the footer is NOT on the first page, then make an empty "First Page Footer"
00665                 // by setting "visible=1"
00666                 writeTextInternal ("<FRAMESET frameType=\"1\" frameInfo=\"4\" name=\"First Page Footer\" visible=\"%i\">",
00667                                             m_isFooterOnFirstPage ? 1 : 0);
00668                 writeTextInternal ("<FRAME runaround=\"1\" copy=\"0\" newFrameBehavior=\"2\" autoCreateNewFrame=\"0\""
00669                                             " top=\"%i\" bottom=\"%i\" left=\"%i\" right=\"%i\"/>",
00670                                             m_footerFromTop, m_footerFromTop, m_left, m_right);
00671                 writeTextInternal ("</FRAMESET>");
00672 
00673                 writeTextInternal ("<FRAMESET frameType=\"1\" frameInfo=\"5\" name=\"Even Pages Footer\" visible=\"0\">");
00674                 writeTextInternal ("<FRAME runaround=\"1\" copy=\"0\" newFrameBehavior=\"2\" autoCreateNewFrame=\"0\""
00675                                             " top=\"%i\" bottom=\"%i\" left=\"%i\" right=\"%i\"/>",
00676                                             m_footerFromTop, m_footerFromTop, m_left, m_right);
00677                 writeTextInternal ("</FRAMESET>");
00678 
00679                 // real footer frame
00680                 writeTextInternal ("<FRAMESET frameType=\"1\" frameInfo=\"6\" name=\"Odd Pages Footer\" visible=\"1\">");
00681                 writeTextInternal ("<FRAME runaround=\"1\" copy=\"1\" newFrameBehavior=\"2\" autoCreateNewFrame=\"0\""
00682                                             " top=\"%i\" bottom=\"%i\" left=\"%i\" right=\"%i\"/>",
00683                                             m_footerFromTop, m_footerFromTop, m_left, m_right);
00684 
00685                 m_writeFooterFirstTime = false;
00686             }
00687         }
00688 
00689         if (!writeTextInternal ("<PARAGRAPH><TEXT>")) return false;
00690 
00691         if (image)
00692         {
00693             kdDebug (30509) << "Paragraph is an image!" << endl;
00694 
00695             QString imageName;
00696             QString fileInStore;
00697 
00698 
00699             // give picture a name
00700             //
00701 
00702             imageName = "Picture ";
00703             imageName += QString::number (m_numPictures + 1);   // image numbers start at 1...
00704 
00705 
00706             // give picture a filename
00707             //
00708 
00709             fileInStore = "pictures/picture" + QString::number (m_numPictures + 1);
00710 
00711             kdDebug (30509) << "\tGetting type..." << endl;
00712 
00713             // append extension
00714             if (image->getIsBMP ())
00715                 fileInStore += ".bmp";
00716             else if (image->getIsWMF () )
00717                 fileInStore += ".wmf";
00718             else
00719                 ErrorAndQuit (MSWrite::Error::InternalError, "unsupported picture type\n");
00720 
00721 
00722             // indicate anchored image in formatting
00723             //
00724             kdDebug (30509) << "\tIndicating anchored image in formatting" << endl;
00725             if (!writeTextInternal ("#")) return false;
00726 
00727             m_formatOutput += "<FORMAT id=\"6\" pos=\"0\" len=\"1\">";
00728                 m_formatOutput += "<ANCHOR type=\"frameset\" instance=\"";
00729                     m_formatOutput += imageName;
00730                 m_formatOutput += "\"/>";
00731             m_formatOutput += "</FORMAT>";
00732 
00733 
00734             // write framesets (truly written in documentEndWrite())
00735             //
00736             kdDebug (30509) << "\tWriting framesets!" << endl;
00737 
00738             m_objectFrameset += "<FRAMESET frameType=\"2\" frameInfo=\"0\" name=\"";
00739             m_objectFrameset += imageName;
00740             m_objectFrameset += "\" visible=\"1\">";
00741 
00742                 m_objectFrameset += "<FRAME runaround=\"1\" copy=\"0\" newFrameBehavior=\"1\"";
00743 
00744                 const double imageLeft = double (m_left) + Twip2Point (double (image->getIndent ()));
00745                 m_objectFrameset += " left=\"";
00746                     m_objectFrameset += QString::number (imageLeft);
00747                     m_objectFrameset += "\"";
00748 
00749                 const double imageWidth = Twip2Point (double (image->getDisplayedWidth ()));
00750                 m_objectFrameset += " right=\"";
00751                     m_objectFrameset += QString::number (imageLeft + imageWidth - 1);
00752                     m_objectFrameset += "\"";
00753 
00754                 m_objectFrameset += " top=\"";
00755                     m_objectFrameset += QString::number (m_top);
00756                     m_objectFrameset += "\"";
00757 
00758                 const double imageHeight = Twip2Point (double (image->getDisplayedHeight ()));
00759                 m_objectFrameset += " bottom=\"";
00760                     m_objectFrameset += QString::number (double (m_top) + imageHeight - 1);
00761                     m_objectFrameset += "\"/>";
00762 
00763                 m_objectFrameset += "<PICTURE keepAspectRatio=\"false\">";
00764                 m_objectFrameset += "<KEY msec=\"0\" hour=\"0\" second=\"0\" minute=\"0\" day=\"1\" month=\"1\" year=\"1970\"";
00765                 m_objectFrameset += " filename=\"";
00766                 m_objectFrameset += fileInStore;
00767                 m_objectFrameset += "\"/>";
00768                 m_objectFrameset += "</PICTURE>";
00769 
00770             m_objectFrameset += "</FRAMESET>";
00771         #ifdef DEBUG_XML_OUTPUT
00772             m_objectFrameset += "\n";
00773         #endif
00774 
00775             m_pictures += "<KEY msec=\"0\" hour=\"0\" second=\"0\" minute=\"0\" day=\"1\" month=\"1\" year=\"1970\"";
00776             m_pictures += " name=\"";
00777             m_pictures += fileInStore;
00778             m_pictures += "\"";
00779             m_pictures += " filename=\"";
00780             m_pictures += fileInStore;
00781             m_pictures += "\"/>";
00782 
00783             m_numPictures++;
00784 
00785 
00786             // store object properties
00787             //
00788             kdDebug (30509) << "\tStoring object" << endl;
00789 
00790             if (!m_objectList.addToBack ())
00791                 ErrorAndQuit (MSWrite::Error::OutOfMemory, "could not allocate memory for object\n");
00792 
00793             WRIObject &obj = *m_objectList.begin (false);
00794             obj.m_nameInStore = fileInStore;
00795             obj.m_dataLength = image->getExternalImageSize ();
00796             obj.m_data = new MSWrite::Byte [obj.m_dataLength];
00797             if (!obj.m_data)
00798                 ErrorAndQuit (MSWrite::Error::OutOfMemory, "could not allocate memory for object data\n");
00799 
00800             // if anchored images could be positioned properly, this wouldn't be needed
00801             m_objectHorizOffset = double (Twip2Point (image->getIndent ()));
00802             m_paraIsImage = true;
00803         }
00804         else
00805         {
00806             if (ole)
00807             {
00808                 if (!writeTextInternal ("[OLE unsupported]")) return false;
00809             }
00810 
00811             m_paraIsImage = false;
00812         }
00813 
00814 
00815         return true;
00816     }
00817 
00818     bool writeParaInfoEnd (const MSWrite::FormatParaProperty *paraProperty,
00819                                     const MSWrite::OLE * /*ole*/,
00820                                     const MSWrite::Image *image)
00821 
00822     {
00823         //kdDebug (30509) << "writeParaInfoEnd()" << endl;
00824 
00825         if (image)
00826         {
00827             WRIObject &obj = *m_objectList.begin (false);
00828 
00829             // consistency check: wrote exactly the right amount of data?
00830             if (obj.m_dataUpto != obj.m_dataLength)
00831                 kdWarning (30509) << "obj.dataUpto (" << obj.m_dataUpto
00832                                         << ") != obj.dataLength (" << obj.m_dataLength
00833                                         << ")" << endl;
00834         }
00835 
00836         QString output;
00837         output += "</TEXT>";
00838 
00839         output += "<LAYOUT>";
00840             output += "<NAME value=\"Standard\"/>";
00841 
00842             int align = paraProperty->getAlignment ();
00843 
00844             if (align != MSWrite::Alignment::Left)
00845             {
00846                 output += "<FLOW align=\"";
00847                 switch (align)
00848                 {
00849                     /*case MSWrite::Alignment::Left:
00850                         output += "left";
00851                         break;*/
00852                     case MSWrite::Alignment::Centre:
00853                         output += "center";
00854                         break;
00855                     case MSWrite::Alignment::Right:
00856                         output += "right";
00857                         break;
00858                     case MSWrite::Alignment::Justify:
00859                         output += "justify";
00860                         break;
00861                 }
00862                 output += "\"/>";
00863             }
00864 
00865             double indentFirst = Twip2Point (double (paraProperty->getLeftIndentFirstLine ()));
00866             double indentLeft = Twip2Point (double (paraProperty->getLeftIndent ()));
00867             double indentRight = Twip2Point (double (paraProperty->getRightIndent ()));
00868 
00869     #if 0
00870             debug ("raw indent:  first: %i  left: %i  right: %i\n",
00871                         indentFirst, indentLeft, indentRight);
00872     #endif
00873 
00874             if (m_paraIsImage /*paraProperty->isObject ()*/ && m_objectHorizOffset)
00875             {
00876                 if (align == MSWrite::Align::Center)
00877                 {
00878                     // TODO: I don't know what m_objectHorizOffset is relative to!
00879                     kdDebug (30509) <<  "ignoring image offset with centred image" << endl;
00880                     m_objectHorizOffset = 0;
00881                 }
00882                 else
00883                 {
00884                     // MSWrite does not add the horizontal offset of the image from the left margin to the Left Indent
00885                     // -- instead, it selects the bigger one
00886                     // TODO: proper image positioning (see doc IMPERFECT)
00887                     if (m_simulateImageOffset && m_objectHorizOffset > indentLeft)
00888                     {
00889                         kdDebug (30509) << "image is further away from left margin by itself, rather than using indentLeft ("
00890                                                 << m_objectHorizOffset << " > " << indentLeft << ")" << endl;
00891                         indentLeft = m_objectHorizOffset;
00892                     }
00893                 }
00894             }
00895 
00896             // hopefully these test operations will be cheaper than the XML ones :)
00897             if (indentFirst || indentLeft || indentRight)
00898             {
00899                 output += "<INDENTS";
00900                 if (indentFirst) output += " first=\"" + QString::number (indentFirst) + "\"";
00901                 if (indentLeft) output += " left=\"" + QString::number (indentLeft) + "\"";
00902                 if (indentRight) output += " right=\"" + QString::number (indentRight) + "\"";
00903                 output += "/>";
00904             }
00905 
00906             MSWrite::Word lineSpacing = paraProperty->getLineSpacing ();
00907 
00908             if (lineSpacing != MSWrite::LineSpacing::Single)
00909             {
00910             #if 1
00911                 output += "<LINESPACING type=\"atleast\" spacingvalue=\"" + QString::number (Twip2Point (lineSpacing)) + "\"/>";
00912             #else   // old way
00913                 output += "<LINESPACING type=\"";
00914                 switch (lineSpacing)
00915                 {
00916                     //case MSWrite:;LineSpacing::Single:
00917                     //  break;
00918                     case MSWrite::LineSpacing::OneAndAHalf:
00919                         output += "oneandhalf";
00920                         break;
00921                     case MSWrite::LineSpacing::Double:
00922                         output += "double";
00923                         break;
00924                     default:
00925                         kdWarning (30509) << "non-\"standard\" linespacing value: " <<  lineSpacing << endl;
00926                         output += "atleast\" ";
00927                         output += "spacingvalue=\"";
00928                             output += QString::number (Twip2Point (lineSpacing));
00929                         break;
00930                 }
00931                 output += "\"/>";
00932             #endif
00933             }
00934 
00935             // Do we want the linespacing to _look_ like it does in Write?
00936             // (this adds extra space before each paragraph)
00937             if (m_simulateLineSpacing)
00938             {
00939                 // emulate Write's linespacing (aligned to bottom)
00940                 // by using varying amounts of space before the paragraph
00941                 // TODO: test if it works nicely enough (what if you have several different sized fonts in paragraph?)
00942                 if (lineSpacing != MSWrite::LineSpacing::Single)        // if not normal linespacing...
00943                 {
00944                     output += "<OFFSETS before=\"";
00945 
00946                     int amount = 0;
00947                     switch (lineSpacing)
00948                     {
00949                     /*case MSWrite::LineSpacing::Single:
00950                         break;*/
00951                     case MSWrite::LineSpacing::OneAndAHalf:
00952                         amount = 7;
00953                         break;
00954                     case MSWrite::LineSpacing::Double:
00955                         amount = 14;
00956                         break;
00957                     default:
00958                         kdWarning (30509) << "unknown linespacing value: " << lineSpacing << endl;
00959                         break;
00960                     }
00961 
00962                     // subtract the amount of trailing linespace from last paragraph
00963                     amount -= m_lineSpacingFromAbove;
00964                     if (amount <= 0) amount = 0;        // no emulation can be perfect...
00965 
00966                     output += QString::number (amount);
00967                     output += "\" />";
00968                 }
00969 
00970                 // GUESS (TODO: fix) the amount of trailing linespace
00971                 switch (lineSpacing)
00972                 {
00973                 case MSWrite::LineSpacing::Single:
00974                     m_lineSpacingFromAbove = 0;
00975                     break;
00976                 case MSWrite::LineSpacing::OneAndAHalf:
00977                     m_lineSpacingFromAbove = 7;
00978                     break;
00979                 case MSWrite::LineSpacing::Double:
00980                     m_lineSpacingFromAbove = 14;
00981                     break;
00982                 default:        // unknown
00983                     m_lineSpacingFromAbove = 0;
00984                     break;
00985                 }
00986             }   // if (m_simulateLineSpacing)   {
00987 
00988             if (m_pageBreak)
00989             {
00990     #if 0
00991                 debug ("\tpagebrk: output: offset: %i chars in paragraph: %i\n",
00992                     m_pageBreakOffset, m_charInfoCountStart + m_charInfoCountLen);
00993     #endif
00994 
00995                 // page break before all the text
00996                 if (m_pageBreakOffset == 0 && m_charInfoCountStart + m_charInfoCountLen > 0)
00997                 {
00998                     output += "<PAGEBREAKING hardFrameBreak=\"true\"/>";
00999                     m_needAnotherParagraph = false; // this paragraph is on first page so we don't need another one
01000                 }
01001                 // we assume that the pageBreak was after all the text (TODO: don't assume this)
01002                 else
01003                 {
01004                     output += "<PAGEBREAKING hardFrameBreakAfter=\"true\"/>";
01005                     m_needAnotherParagraph = true;  // need another paragraph for hardFrameBreakAfter to work
01006                 }
01007 
01008                 m_pageBreak = false;        // reset flag
01009             }
01010             else
01011                 m_needAnotherParagraph = false;
01012 
01013             // Tabulators
01014             for (int i = 0; i < paraProperty->getNumTabulator (); i++)
01015             {
01016                 const MSWrite::FormatParaPropertyTabulator *tab = paraProperty->getTabulator (i);
01017                 if (tab->getIsDummy ()) break;
01018 
01019                 output += "<TABULATOR";
01020 
01021                 if (tab->getIsDecimal ())
01022                     output += " type=\"3\" alignchar=\".\"";
01023                 else
01024                     output += " type=\"0\"";
01025 
01026                 output += " ptpos=\"" + QString::number (Twip2Point (double (tab->getIndent ()))) + "\"/>";
01027 
01028                 //debug ("Tab: isNormal: %i  ptPos: %i\n",
01029                 //          paraProperty->tbd [i].isTabNormal (), paraProperty->tbd [i].getTabNumPoints ());
01030             }
01031 
01032         output += "</LAYOUT>";
01033     #ifdef DEBUG_XML_OUTPUT
01034         output += "\n";
01035     #endif
01036 
01037         output += "<FORMATS>";
01038     #ifdef DEBUG_XML_OUTPUT
01039         output += "\n";
01040     #endif
01041             // output all the charInfo for this paragraph
01042             output += m_formatOutput; m_formatOutput = "";
01043         output += "</FORMATS>";
01044     #ifdef DEBUG_XML_OUTPUT
01045         output += "\n";
01046     #endif
01047 
01048         output += "</PARAGRAPH>";
01049     #ifdef DEBUG_XML_OUTPUT
01050         output += "\n";
01051     #endif
01052 
01053         if (!writeTextInternal (output)) return false;
01054 
01055         return true;
01056     }
01057 
01058     bool writeCharInfoBegin (const MSWrite::FormatCharProperty * /*charProperty*/)
01059     {
01060         //kdDebug (30509) << "writeCharInfoBegin()" << endl;
01061 
01062         return true;
01063     }
01064 
01065     // outputs character formatting tags
01066     bool writeCharInfoEnd (const MSWrite::FormatCharProperty *charProperty,
01067                                     const bool = false)
01068     {
01069         //kdDebug (30509) << "writeCharInfoEnd()" << endl;
01070 
01071         // output type of format information (page number or normal text)
01072         m_formatOutput += "<FORMAT id=\"";
01073         if (charProperty->getIsPageNumber ())
01074             m_formatOutput += "4";
01075         else
01076             m_formatOutput += "1";
01077         m_formatOutput += "\" ";
01078 
01079         m_formatOutput += "pos=\""; m_formatOutput += QString::number (m_charInfoCountStart); m_formatOutput += "\" ";
01080         m_formatOutput += "len=\""; m_formatOutput += QString::number (m_charInfoCountLen); m_formatOutput += "\">";
01081 
01082         m_charInfoCountStart += m_charInfoCountLen;
01083         m_charInfoCountLen = 0;
01084 
01085         if (charProperty->getIsPageNumber ())
01086         {
01087             m_formatOutput += "<VARIABLE>";
01088                 m_formatOutput += "<TYPE key=\"NUMBER\" type=\"4\"/>";
01089                 m_formatOutput += "<PGNUM subtype=\"0\" value=\"1\"/>";
01090             m_formatOutput += "</VARIABLE>";
01091         }
01092 
01093         m_formatOutput += "<FONT name=\"";
01094             m_formatOutput += (const char *) (charProperty->getFont ()->getName ());
01095             m_formatOutput += "\"/>";
01096             m_formatOutput += "<SIZE value=\"";
01097             m_formatOutput += QString::number (charProperty->getFontSize ());
01098             m_formatOutput += "\"/>";
01099 
01100         if (charProperty->getIsBold ())
01101             m_formatOutput += "<WEIGHT value=\"75\"/>";
01102     //else
01103     //          m_formatOutput += "<WEIGHT value=\"50\" />";
01104 
01105         if (charProperty->getIsItalic ())
01106             m_formatOutput += "<ITALIC value=\"1\"/>";
01107     //  else
01108     //      m_formatOutput += "<ITALIC value=\"0\" />";
01109 
01110         if (charProperty->getIsUnderlined ())
01111             m_formatOutput += "<UNDERLINE value=\"1\"/>";
01112     //  else
01113     //      m_formatOutput += "<UNDERLINE value=\"0\" />";
01114 
01115         /*if (charProperty->isNormalPosition ())
01116             m_formatOutput += "<VERTALIGN value=\"0\" />";
01117         else*/ if (charProperty->getIsSubscript ())
01118             m_formatOutput += "<VERTALIGN value=\"1\"/>";
01119         else if (charProperty->getIsSuperscript ())
01120             m_formatOutput += "<VERTALIGN value=\"2\"/>";
01121         /*else
01122             error ("unknown valign\n");*/
01123 
01124         m_formatOutput += "</FORMAT>";
01125 
01126         return true;
01127     }
01128 
01129     bool writeBinary (const MSWrite::Byte *buffer, const MSWrite::DWord length)
01130     {
01131         kdDebug (30509) << "writeBinary()" << endl;
01132 
01133         // must be OLE, TODO: implement OLE properly
01134         if (!m_paraIsImage)
01135             return true;
01136 
01137         WRIObject &obj = *m_objectList.begin (false);
01138 
01139         if (!obj.m_data)
01140             ErrorAndQuit (MSWrite::Error::InternalError, "object data not initialised\n");
01141 
01142         // consistency check: aren't going to write past end of array?
01143         if (obj.m_dataUpto + length > obj.m_dataLength)
01144         {
01145             kdDebug (30509) << "object image overrun: "
01146                                     << obj.m_dataUpto << " + " << length
01147                                     << " > " << obj.m_dataLength  << endl;
01148             ErrorAndQuit (MSWrite::Error::InternalError, "object image overrun\n");
01149         }
01150 
01151         memcpy (obj.m_data + obj.m_dataUpto, buffer, length);
01152         obj.m_dataUpto += length;
01153 
01154         return true;
01155     }
01156 
01157 
01158 
01159     //
01160     // text output functions
01161     //
01162 
01163     bool writeText (const MSWrite::Byte *string)
01164     {
01165         // from Win Character Set...
01166         QString strUnicode;
01167 
01168         // there is a codec, therefore there is a decoder...
01169         if (m_codec)
01170         {
01171             // output Unicode (UTF8)
01172             strUnicode = m_decoder->toUnicode ((const char *) string, strlen ((const char *) string));
01173         }
01174         else
01175         {
01176             // output a plain string still in wrong Character Set
01177             // (hopefully the user won't notice)
01178             strUnicode = (const char *) string;
01179         }
01180 
01181         // update character information counter (after charset conversion)
01182         m_charInfoCountLen += strUnicode.length ();
01183 
01184         // make string XML-friendly (TODO: speed up)
01185         strUnicode.replace ('&', "&amp;");
01186         strUnicode.replace ('<', "&lt;");
01187         strUnicode.replace ('>', "&gt;");
01188         strUnicode.replace ('\"', "&quot;");
01189         strUnicode.replace ('\'', "&apos;");
01190 
01191         return writeTextInternal (strUnicode);
01192     }
01193 
01194     bool writeTextInternal (const MSWrite::Byte *str)
01195     {
01196     #if 0
01197         return textWrite_lowLevel (QString (str));
01198     #else   // while this is code duplication (of below func), this ensures that no
01199             // characters are mysteriously converted (this makes writeOptionalHyphen () work)
01200         if (m_delayOutput)
01201         {
01202             // header/footer must be written after main body
01203             m_heldOutput += (const char *) str;
01204             return true;
01205         }
01206         else
01207         {
01208             int strLength = strlen ((const char *) str);
01209 
01210             if (m_outfile->writeBlock ((const char *) str, strLength) != strLength)
01211             {
01212                 ErrorAndQuit (MSWrite::Error::FileError, "could not write to maindoc.xml\n");
01213             }
01214             else
01215                 return true;
01216         }
01217     #endif
01218     }
01219 
01220     bool writeTextInternal (const QString &str)
01221     {
01222         if (m_delayOutput)
01223         {
01224             // header/footer must be written after main body
01225             m_heldOutput += str;
01226             return true;
01227         }
01228         else
01229         {
01230             QCString strUtf8 = str.utf8 ();
01231             int strLength = strUtf8.length ();
01232 
01233             if (m_outfile->writeBlock (strUtf8, strLength) != strLength)
01234             {
01235                 ErrorAndQuit (MSWrite::Error::FileError, "could not write to maindoc.xml (2)\n");
01236             }
01237             else
01238                 return true;
01239         }
01240     }
01241 
01242     bool writeTextInternal (const int num)
01243     {
01244         return writeTextInternal (QString::number (num));
01245     }
01246 
01247     bool writeTextInternal (const char *format, ...)
01248     {
01249         va_list list;
01250         va_start (list, format);
01251 
01252         bool ret;
01253         // This function is mainly for outputting tags (where XML characters are
01254         // already escaped and the text is in the right character set...ASCII
01255         // = UTF-8 for alphanumeric chars I hope).  So _don't_ pass user text
01256         // to this function (that's what writeText() is for); otherwise you might
01257         // exceed this 1024 limit.
01258         char string [1024];
01259 
01260         vsnprintf (string, sizeof (string) - 1, format, list);
01261         string [sizeof (string) - 1] = '\0';
01262 
01263         ret = writeTextInternal ((const MSWrite::Byte *) string);
01264 
01265         va_end (list);
01266         return ret;
01267     }
01268 
01269 
01270     // writePageNew() is called for the pageTable
01271     // -- however, pageTable can be very inaccurate, so we ignore it
01272     bool writePageNew (const int)
01273     {
01274         return true;
01275     }
01276 
01277     // handles explicit page breaks
01278     bool writePageBreak (void)
01279     {
01280         // later used in paraEndWrite
01281         m_pageBreak = true;
01282         m_pageBreakOffset = m_charInfoCountStart + m_charInfoCountLen;
01283 
01284         return true;
01285     }
01286 
01287     // handle "(page)" number
01288     bool writePageNumber (void)
01289     {
01290         m_charInfoCountLen++;   // not incremented by writeTextInternal()
01291         return writeTextInternal ("#");
01292     }
01293 
01294     bool writeCarriageReturn (void)
01295     {
01296         return true;    // ignore CR
01297     }
01298 
01299     // write newline unless end-of-paragraph
01300     // (this is the support for paragraphs with multiple newlines)
01301     bool writeNewLine (const bool endOfParagraph)
01302     {
01303         if (!endOfParagraph)
01304         {
01305             m_charInfoCountLen++;   // not incremented by writeTextInternal()
01306             return writeTextInternal ("\n");
01307         }
01308         else
01309             return true;
01310     }
01311 
01312     // aka "soft hyphen"
01313     bool writeOptionalHyphen (void)
01314     {
01315         m_charInfoCountLen++;   // not incremented by writeTextInternal()
01316         return writeTextInternal ("\xC2\xAD");
01317     }
01318 
01319     void setKOfficeLink (MSWriteImport *kofficeLink)
01320     {
01321         m_koLink = kofficeLink;
01322     }
01323 
01324     void sigProgress (const int value)
01325     {
01326         m_koLink->sigProgress (value);
01327     }
01328 };
01329 
01330 
01331 
01332 //
01333 // KoFilter
01334 //
01335 
01336 MSWriteImport::MSWriteImport (KoFilter *, const char *, const QStringList &)
01337                     : m_device (NULL), m_parser (NULL), m_generator (NULL)
01338 {
01339 }
01340 
01341 MSWriteImport::~MSWriteImport ()
01342 {
01343     delete m_generator;
01344     delete m_parser;
01345     delete m_device;
01346 }
01347 
01348 KoFilter::ConversionStatus MSWriteImport::convert (const QCString &from, const QCString &to)
01349 {
01350     kdDebug (30509) << "MSWriteImport $Date: 2006-02-12 19:28:12 +0100 (dim, 12 fév 2006) $ using LibMSWrite "
01351                             << MSWrite::Version << endl;
01352 
01353     if (to != "application/x-kword" || from != "application/x-mswrite")
01354     {
01355         kdError (30509) << "Internal error!  Filter not implemented?" << endl;
01356         return KoFilter::NotImplemented;
01357     }
01358 
01359 #if 0
01360     //MSWriteImportDialog *dialog = new MSWriteImportDialog ();
01361     MSWriteImportDialog dialog;
01362 
01363     /*debug ("DIALOG check alloc\n");
01364     if (!dialog)
01365     {
01366         error ("Could not allocate memory for dialog\n");
01367         return KoFilter::StupidError;
01368     }*/
01369 
01370     debug ("DIALOG EXEC!!!\n");
01371     if (!dialog.exec ())
01372     {
01373         error ("Dialog was aborted! Aborting filter!\n");
01374         return KoFilter::UserCancelled;
01375     }
01376 
01377     debug ("DIALOG GET!!!\n");
01378 
01379     // read settings from dialog
01380     m_codec = dialog.getCodec ();
01381     m_simulateLinespacing = dialog.getSimulateLinespacing ();
01382     m_simulateImageOffset = dialog.getSimulateImageOffset ();
01383     debug ("Import options: simulateLinespacing: %i\tsimulateImageOffset: %i\n",
01384                 m_simulateLinespacing, m_simulateImageOffset);
01385 
01386     debug ("DIALOG DELETE\n");
01387     //delete dialog;
01388 #endif
01389 
01390     // create the Device that will read from the .WRI file
01391     m_device = new WRIDevice;
01392     if (!m_device)
01393     {
01394         kdError (30509) << "Could not allocate memory for device" << endl;
01395         return KoFilter::OutOfMemory;
01396     }
01397 
01398     // open the .WRI file
01399     if (!m_device->openFile (QFile::encodeName (m_chain->inputFile ())))
01400     {
01401         kdError (30509) << "Could not open \'" << m_chain->inputFile () << "\'" << endl;
01402         return KoFilter::FileNotFound;
01403     }
01404 
01405 
01406     // create Parser that will interpret the .WRI file and call the Generator
01407     m_parser = new MSWrite::InternalParser;
01408     if (!m_parser)
01409     {
01410         kdError (30509) << "Could not allocate memory for parser" << endl;
01411         return KoFilter::OutOfMemory;
01412     }
01413 
01414     // tell the Parser to use the Device to read from the .WRI file
01415     m_parser->setDevice (m_device);
01416 
01417 
01418     // create Generator that will produce the .KWD file
01419     m_generator = new KWordGenerator;
01420     if (!m_generator)
01421     {
01422         kdError (30509) << "Could not allocate memory for generator" << endl;
01423         return KoFilter::OutOfMemory;
01424     }
01425 
01426     // give the Generator the Device for error-handling purposes
01427     m_generator->setDevice (m_device);
01428 
01429     // give the Generator the chain
01430     m_generator->setFilterChain (m_chain);
01431 
01432     // hand over sigProgess to give some feedback to the user
01433     m_generator->setKOfficeLink (this);
01434 
01435 
01436     // hook up Generator to Parser
01437     m_parser->setGenerator (m_generator);
01438 
01439 
01440     // filter!
01441     if (!m_parser->parse ())
01442     {
01443         // try to return somewhat more meaningful errors than StupidError
01444         // for the day that KOffice actually reports them to the user properly
01445         int errorCode = m_device->bad ();
01446         switch (errorCode)
01447         {
01448         case MSWrite::Error::Ok:
01449             kdDebug (30509) << "Error::Ok but aborted???" << endl;
01450             return KoFilter::InternalError;
01451 
01452         case MSWrite::Error::Warn:
01453             kdDebug (30509) << "Error::Warn" << endl;
01454             return KoFilter::InternalError; // warnings should _never_ set m_error
01455 
01456         case MSWrite::Error::InvalidFormat:
01457             kdDebug (30509) << "Error::InvalidFormat" << endl;
01458             return KoFilter::WrongFormat;
01459 
01460         case MSWrite::Error::OutOfMemory:
01461             kdDebug (30509) << "Error::OutOfMemory" << endl;
01462             return KoFilter::OutOfMemory;
01463 
01464         case MSWrite::Error::InternalError:
01465             kdDebug (30509) << "Error::InternalError" << endl;
01466             return KoFilter::InternalError;
01467 
01468         case MSWrite::Error::Unsupported:
01469             kdDebug (30509) << "Error::Unsupported" << endl;
01470             return KoFilter::InternalError;
01471 
01472         case MSWrite::Error::FileError:
01473             kdDebug (30509) << "Error::FileError" << endl;
01474             return KoFilter::StupidError;   // got a better return value?
01475         }
01476 
01477         kdWarning (30509) << "Unknown error: " << errorCode << endl;
01478         return KoFilter::StupidError;
01479     }
01480 
01481     return KoFilter::OK;
01482 }
01483 
01484 #include <mswriteimport.moc>
KDE Home | KDE Accessibility Home | Description of Access Keys