/* -*- mode: C++; tab-width: 4; c-basic-offset: 4; -*- */ /* AbiWord * Copyright (C) 2001 AbiSource, Inc. * Copyright (C) 2002-2004 Marc Maurer (uwog@uwog.net) * Copyright (C) 2002-2005 William Lachance (william.lachance@sympatico.ca) * Copyright (C) 2006 Fridrich Strba (fridrich.strba@bluewin.ch) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ /* See bug 1764 * "This product is not manufactured, approved, or supported by * Corel Corporation or Corel Corporation Limited." */ #include #include #include #include #include #include #include #include "ut_types.h" #include "ut_string.h" #include "ut_string_class.h" #include "ut_units.h" #include "ut_growbuf.h" #include "ut_assert.h" #include "ut_debugmsg.h" #include "ut_math.h" // for rint (font size) #include "ut_rand.h" #include "ut_locale.h" #include "xap_Frame.h" #include "xap_EncodingManager.h" #include "pd_Document.h" #include "pt_Types.h" #include "fl_AutoLists.h" #include "fl_AutoNum.h" #include "ie_imp_WordPerfect.h" #include "ie_impexp_WordPerfect.h" // Stream class #include #include #include #include #ifdef HAVE_LIBWPS #include #endif class AbiWordperfectInputStream : #ifdef HAVE_LIBWPS public WPSInputStream #else public WPXInputStream #endif { public: AbiWordperfectInputStream(GsfInput *input); ~AbiWordperfectInputStream(); virtual bool isOLEStream(); virtual WPXInputStream * getDocumentOLEStream(); virtual WPXInputStream * getDocumentOLEStream(const char * name); virtual const uint8_t *read(size_t numBytes, size_t &numBytesRead); virtual int seek(long offset, WPX_SEEK_TYPE seekType); virtual long tell(); virtual bool atEOS(); private: GsfInput *m_input; GsfInfile *m_ole; }; AbiWordperfectInputStream::AbiWordperfectInputStream(GsfInput *input) : #ifdef HAVE_LIBWPS WPSInputStream(), #else WPXInputStream(true), #endif m_input(input), m_ole(NULL) { g_object_ref(G_OBJECT(input)); } AbiWordperfectInputStream::~AbiWordperfectInputStream() { if (m_ole) g_object_unref(G_OBJECT(m_ole)); g_object_unref(G_OBJECT(m_input)); } const uint8_t * AbiWordperfectInputStream::read(size_t numBytes, size_t &numBytesRead) { const uint8_t *buf = gsf_input_read(m_input, numBytes, NULL); if (buf == NULL) numBytesRead = 0; else numBytesRead = numBytes; return buf; } int AbiWordperfectInputStream::seek(long offset, WPX_SEEK_TYPE seekType) { GSeekType gsfSeekType = G_SEEK_SET; switch(seekType) { case WPX_SEEK_CUR: gsfSeekType = G_SEEK_CUR; break; case WPX_SEEK_SET: gsfSeekType = G_SEEK_SET; break; } return gsf_input_seek(m_input, offset, gsfSeekType); } bool AbiWordperfectInputStream::isOLEStream() { if (!m_ole) m_ole = GSF_INFILE(gsf_infile_msole_new (m_input, NULL)); if (m_ole != NULL) return true; return false; } WPXInputStream * AbiWordperfectInputStream::getDocumentOLEStream() { return getDocumentOLEStream("PerfectOffice_MAIN"); } WPXInputStream * AbiWordperfectInputStream::getDocumentOLEStream(const char * name) { WPXInputStream *documentStream = NULL; if (!m_ole) m_ole = GSF_INFILE(gsf_infile_msole_new (m_input, NULL)); if (m_ole) { GsfInput *document = gsf_infile_child_by_name(m_ole, name); if (document) { documentStream = new AbiWordperfectInputStream(document); g_object_unref(G_OBJECT (document)); // the only reference should be encapsulated within the new stream } } return documentStream; } long AbiWordperfectInputStream::tell() { return gsf_input_tell(m_input); } bool AbiWordperfectInputStream::atEOS() { return gsf_input_eof(m_input); } // This should probably be defined in pt_Types.h static const UT_uint32 PT_MAX_ATTRIBUTES = 8; ABI_ListDefinition::ABI_ListDefinition(int iOutlineHash) : m_iOutlineHash(iOutlineHash) { for(int i=0; i 0.7.1 reports POOR if the text file is plain text (that _could_ be a WP4x document) // however, we'll let the text importer handle such cases case WPD_CONFIDENCE_POOR: return UT_CONFIDENCE_ZILCH; case WPD_CONFIDENCE_LIKELY: return UT_CONFIDENCE_SOSO; case WPD_CONFIDENCE_GOOD: return UT_CONFIDENCE_GOOD; case WPD_CONFIDENCE_EXCELLENT: return UT_CONFIDENCE_PERFECT; default: return UT_CONFIDENCE_ZILCH; } } UT_Error IE_Imp_WordPerfect_Sniffer::constructImporter (PD_Document * pDocument, IE_Imp ** ppie) { *ppie = new IE_Imp_WordPerfect(pDocument); return UT_OK; } bool IE_Imp_WordPerfect_Sniffer::getDlgLabels (const char ** pszDesc, const char ** pszSuffixList, IEFileType * ft) { *pszDesc = "WordPerfect (.wpd, .wp)"; *pszSuffixList = "*.wpd; *.wp"; *ft = getFileType(); return true; } /****************************************************************************/ /****************************************************************************/ IE_Imp_WordPerfect::IE_Imp_WordPerfect(PD_Document * pDocument) : IE_Imp (pDocument), m_leftPageMargin(1.0f), m_rightPageMargin(1.0f), m_leftSectionMargin(0.0f), m_rightSectionMargin(0.0f), m_sectionColumnsCount(0), m_headerId(-1), m_footerId(-1), m_nextFreeId(0), m_leftMarginOffset(0.0f), m_rightMarginOffset(0.0f), m_pCurrentListDefinition(NULL), m_bParagraphChanged(false), m_bParagraphInSection(false), m_bInSection(false), m_bSectionChanged(false), m_bRequireBlock(false), m_iCurrentListLevel(0), m_bInCell(false), m_bHdrFtrOpenCount(0) { } IE_Imp_WordPerfect::~IE_Imp_WordPerfect() { //UT_HASH_PURGEDATA(ABI_ListDefinition *,&m_listStylesHash,delete); } UT_Error IE_Imp_WordPerfect::_loadFile(GsfInput * input) { AbiWordperfectInputStream gsfInput(input); WPDResult error = WPDocument::parse(&gsfInput, static_cast(this)); if (error != WPD_OK) { UT_DEBUGMSG(("AbiWordPerfect: ERROR: %i!\n", (int)error)); return UT_IE_IMPORTERROR; } return UT_OK; } void IE_Imp_WordPerfect::pasteFromBuffer (PD_DocumentRange *, unsigned char *, unsigned int, const char *) { // nada } void IE_Imp_WordPerfect::setDocumentMetaData(const WPXPropertyList &propList) { if (propList["dc:author"]) getDoc()->setMetaDataProp(PD_META_KEY_CREATOR, propList["dc:author"]->getStr().cstr()); if (propList["dc:subject"]) getDoc()->setMetaDataProp(PD_META_KEY_SUBJECT, propList["dc:subject"]->getStr().cstr()); if (propList["dc:publisher"]) getDoc()->setMetaDataProp(PD_META_KEY_PUBLISHER, propList["dc:publisher"]->getStr().cstr()); if (propList["dc:type"]) getDoc()->setMetaDataProp(PD_META_KEY_TYPE, propList["dc:category"]->getStr().cstr()); if (propList["libwpd:keywords"]) getDoc()->setMetaDataProp(PD_META_KEY_KEYWORDS, propList["libwpd:keywords"]->getStr().cstr()); if (propList["dc:language"]) getDoc()->setMetaDataProp(PD_META_KEY_LANGUAGE, propList["dc:language"]->getStr().cstr()); if (propList["libwpd:abstract"]) getDoc()->setMetaDataProp(PD_META_KEY_DESCRIPTION, propList["libwpd:abstract"]->getStr().cstr()); } void IE_Imp_WordPerfect::startDocument() { UT_DEBUGMSG(("AbiWordPerfect: startDocument\n")); } void IE_Imp_WordPerfect::endDocument() { UT_DEBUGMSG(("AbiWordPerfect: endDocument\n")); } void IE_Imp_WordPerfect::openPageSpan(const WPXPropertyList &propList) { if (m_bHdrFtrOpenCount) return; // HACK UT_DEBUGMSG(("AbiWordPerfect: openPageSpan\n")); float marginLeft = 1.0f, marginRight = 1.0f; if (propList["fo:margin-left"]) marginLeft = propList["fo:margin-left"]->getFloat(); if (propList["fo:margin-right"]) marginRight = propList["fo:margin-right"]->getFloat(); if (marginLeft != m_leftPageMargin || marginRight != m_rightPageMargin /* || */ /* marginTop != m_marginBottom || marginBottom != m_marginBottom */ ) m_bSectionChanged = true; // margin properties are section properties in AbiWord m_leftPageMargin = marginLeft; m_rightPageMargin = marginRight; } void IE_Imp_WordPerfect::openHeader(const WPXPropertyList & /*propList*/) { m_bHdrFtrOpenCount++; /* TODO: THIS CODE IS NOT!!!! USEFULL! - DON'T TOUCH IT - MARCM UT_String propBuffer; switch (headerFooterType) { case HEADER: m_headerId = m_nextFreeId; UT_String_sprintf(propBuffer,"id:%d; listid:0; parentid=0; type=header", m_headerId); break; case FOOTER: m_footerId = m_nextFreeId; UT_String_sprintf(propBuffer,"id:%d; listid:0; parentid=0; type=footer", m_footerId); break; default: UT_ASSERT(SHOULD_NOT_HAPPEN); break; } const gchar* propsArray[3]; propsArray[0] = "props"; propsArray[1] = propBuffer.c_str(); propsArray[2] = NULL; X_CheckDocumentError(appendStrux(PTX_Section, propsArray)); m_bInSection = true; m_bSectionChanged = false;*/ } void IE_Imp_WordPerfect::closeHeader() { m_bHdrFtrOpenCount--; /* TODO: THIS CODE IS NOT!!!! USEFULL! - DON'T TOUCH IT - MARCM m_nextFreeId++; */ } void IE_Imp_WordPerfect::openFooter(const WPXPropertyList & /*propList*/) { m_bHdrFtrOpenCount++; // see above comments re: openHeader } void IE_Imp_WordPerfect::closeFooter() { m_bHdrFtrOpenCount--; // see above comments re: closeHeader } void IE_Imp_WordPerfect::openParagraph(const WPXPropertyList &propList, const WPXPropertyListVector &tabStops) { if (m_bHdrFtrOpenCount) return; // HACK UT_DEBUGMSG(("AbiWordPerfect: openParagraph()\n")); // for now, we always append these options float marginTop = 0.0f, marginBottom = 0.0f; float marginLeft = 0.0f, marginRight = 0.0f, textIndent = 0.0f; if (propList["fo:margin-top"]) marginTop = propList["fo:margin-top"]->getFloat(); if (propList["fo:margin-bottom"]) marginBottom = propList["fo:margin-bottom"]->getFloat(); if (propList["fo:margin-left"]) marginLeft = propList["fo:margin-left"]->getFloat(); if (propList["fo:margin-right"]) marginRight = propList["fo:margin-right"]->getFloat(); if (propList["fo:text-indent"]) textIndent = propList["fo:text-indent"]->getFloat(); m_topMargin = marginTop; m_bottomMargin = marginBottom; m_leftMarginOffset = marginLeft; m_rightMarginOffset = marginRight; m_textIndent = textIndent; UT_String propBuffer; propBuffer += "text-align:"; if (propList["fo:text-align"]) { // AbiWord follows xsl:fo, except here, for some reason.. if (propList["fo:text-align"]->getStr() == "end") propBuffer += "right"; else propBuffer += propList["fo:text-align"]->getStr().cstr(); } else propBuffer += "left"; float lineSpacing = 1.0f; if (propList["fo:line-height"]) lineSpacing = propList["fo:line-height"]->getFloat(); UT_String tmpBuffer; UT_String_sprintf(tmpBuffer, "; margin-top:%.4fin; margin-bottom:%.4fin; margin-left:%.4fin; margin-right:%.4fin; text-indent:%.4fin; line-height:%.4f", m_topMargin, m_bottomMargin, m_leftMarginOffset, m_rightMarginOffset, m_textIndent, lineSpacing); propBuffer += tmpBuffer; if (tabStops.count() > 0) // Append the tabstop information { propBuffer += "; tabstops:"; tmpBuffer = ""; WPXPropertyListVector::Iter i(tabStops); for (i.rewind(); i.next();) { propBuffer += tmpBuffer; if (i()["style:position"]) { UT_String_sprintf(tmpBuffer, "%.4fin", i()["style:position"]->getFloat()); propBuffer += tmpBuffer; } if (i()["style:type"]) if (i()["style:type"]->getStr() == "right") propBuffer += "/R"; else if (i()["style:type"]->getStr() == "center") propBuffer += "/C"; else if (i()["style:type"]->getStr() == "char") propBuffer += "/D"; else propBuffer += "/L"; else // Left aligned is default propBuffer += "/L"; if (i()["style:leader-char"]) if (i()["style:leader-char"]->getStr() == "-") propBuffer += "2"; else if (i()["style:leader-char"]->getStr() == "_") propBuffer += "3"; else // default to dot leader if the given leader is dot or is not supported by AbiWord propBuffer += "1"; else propBuffer += "0"; tmpBuffer = ","; } } UT_DEBUGMSG(("AbiWordPerfect: Appending paragraph properties: %s\n", propBuffer.c_str())); const gchar* propsArray[3]; propsArray[0] = "props"; propsArray[1] = propBuffer.c_str(); propsArray[2] = NULL; X_CheckDocumentError(appendStrux(PTX_Block, propsArray)); m_bRequireBlock = false; if (propList["fo:break-before"]) { if (strcmp(propList["fo:break-before"]->getStr().cstr(), "page") == 0) { UT_UCS4Char ucs = UCS_FF; X_CheckDocumentError(appendSpan(&ucs,1)); } else if (strcmp(propList["fo:break-before"]->getStr().cstr(), "column") == 0) { UT_UCS4Char ucs = UCS_VTAB; X_CheckDocumentError(appendSpan(&ucs,1)); } } } void IE_Imp_WordPerfect::openSpan(const WPXPropertyList &propList) { if (m_bHdrFtrOpenCount) return; // HACK UT_DEBUGMSG(("AbiWordPerfect: Appending current text properties\n")); const gchar* pProps = "props"; UT_String propBuffer; UT_String tempBuffer; // bold propBuffer += "font-weight:"; propBuffer += (propList["fo:font-weight"] ? propList["fo:font-weight"]->getStr().cstr() : "normal"); // italic propBuffer += "; font-style:"; propBuffer += (propList["fo:font-style"] ? propList["fo:font-style"]->getStr().cstr() : "normal"); // superscript or subscript if (propList["style:text-position"]) { propBuffer += "; text-position:"; if (strncmp(propList["style:text-position"]->getStr().cstr(), "super", 5) == 0) propBuffer += "superscript"; else propBuffer += "subscript"; } if (propList["style:text-underline"] || propList["style:text-crossing-out"]) { propBuffer += "; text-decoration:"; if (propList["style:text-underline"]) propBuffer += "underline "; if (propList["style:text-crossing-out"]) propBuffer += "line-through"; } if (propList["style:font-name"]) { propBuffer += "; font-family:"; propBuffer += propList["style:font-name"]->getStr().cstr(); } // font face if (propList["fo:font-size"]) { propBuffer += "; font-size:"; propBuffer += propList["fo:font-size"]->getStr().cstr(); } if (propList["fo:color"]) { propBuffer += "; color:"; propBuffer += propList["fo:color"]->getStr().cstr(); } if (propList["style:text-background-color"]) { propBuffer += "; bgcolor:"; propBuffer += propList["style:text-background-color"]->getStr().cstr(); } UT_DEBUGMSG(("AbiWordPerfect: Appending span format: %s\n", propBuffer.c_str())); const gchar* propsArray[5]; propsArray[0] = pProps; propsArray[1] = propBuffer.c_str(); propsArray[2] = NULL; X_CheckDocumentError(appendFmt(propsArray)); } void IE_Imp_WordPerfect::openSection(const WPXPropertyList &propList, const WPXPropertyListVector &columns) { if (m_bHdrFtrOpenCount) return; // HACK UT_DEBUGMSG(("AbiWordPerfect: openSection\n")); float marginLeft = 0.0f, marginRight = 0.0f; int columnsCount = ((columns.count() == 0) ? 1 : columns.count()); // TODO: support spaceAfter if (propList["fo:margin-left"]) marginLeft = propList["fo:margin-left"]->getFloat(); if (propList["fo:margin-right"]) marginRight = propList["fo:margin-right"]->getFloat(); if (marginLeft != m_leftSectionMargin || marginRight != m_rightSectionMargin || m_sectionColumnsCount != columnsCount) m_bSectionChanged = true; m_leftSectionMargin = marginLeft; m_rightSectionMargin = marginRight; m_sectionColumnsCount = columnsCount; _appendSection(columnsCount, m_leftPageMargin + m_leftSectionMargin, m_rightPageMargin + m_rightSectionMargin); } void IE_Imp_WordPerfect::insertTab() { if (m_bHdrFtrOpenCount) return; // HACK UT_DEBUGMSG(("AbiWordPerfect: insertTab\n")); UT_UCS4Char ucs = UCS_TAB; X_CheckDocumentError(appendSpan(&ucs,1)); } void IE_Imp_WordPerfect::insertText(const WPXString &text) { if (m_bHdrFtrOpenCount) return; // HACK if (text.len()) { UT_DEBUGMSG(("AbiWordPerfect: insertText\n")); UT_UCS4String ucs4(text.cstr()); X_CheckDocumentError(appendSpan(ucs4.ucs4_str(), ucs4.length())); } } void IE_Imp_WordPerfect::insertLineBreak() { if (m_bHdrFtrOpenCount) return; // HACK UT_DEBUGMSG(("AbiWordPerfect: insertLineBreak\n")); UT_UCSChar ucs = UCS_LF; X_CheckDocumentError(appendSpan(&ucs,1)); } void IE_Imp_WordPerfect::defineOrderedListLevel(const WPXPropertyList &propList) { if (m_bHdrFtrOpenCount) return; // HACK UT_DEBUGMSG(("AbiWordPerfect: defineOrderedListLevel\n")); int listID = 0, startingNumber = 0, level = 1; char listType = '1'; UT_UTF8String textBeforeNumber, textAfterNumber; float listLeftOffset = 0.0f; float listMinLabelWidth = 0.0f; if (propList["libwpd:id"]) listID = propList["libwpd:id"]->getInt(); if (propList["text:start-value"]) startingNumber = propList["text:start-value"]->getInt(); if (propList["libwpd:level"]) level = propList["libwpd:level"]->getInt(); if (propList["style:num-prefix"]) textBeforeNumber += propList["style:num-prefix"]->getStr().cstr(); if (propList["style:num-suffix"]) textAfterNumber += propList["style:num-suffix"]->getStr().cstr(); if (propList["style:num-format"]) listType = propList["style:num-format"]->getStr().cstr()[0]; if (propList["text:space-before"]) listLeftOffset = propList["text:space-before"]->getFloat(); if (propList["text:min-label-width"]) listMinLabelWidth = propList["text:min-label-width"]->getFloat(); if (!m_pCurrentListDefinition || m_pCurrentListDefinition->getOutlineHash() != listID || (m_pCurrentListDefinition->getLevelNumber(level) != startingNumber && level == 1)) { if (m_pCurrentListDefinition) delete (m_pCurrentListDefinition); m_pCurrentListDefinition = new ABI_ListDefinition(listID); } if (!m_pCurrentListDefinition->getListID(level)) { m_pCurrentListDefinition->setListType(level, listType); m_pCurrentListDefinition->setListID(level, UT_rand()); m_pCurrentListDefinition->setListLeftOffset(level, listLeftOffset); m_pCurrentListDefinition->setListMinLabelWidth(level, listMinLabelWidth); _updateDocumentOrderedListDefinition(m_pCurrentListDefinition, level, listType, textBeforeNumber, textAfterNumber, startingNumber); } } void IE_Imp_WordPerfect::defineUnorderedListLevel(const WPXPropertyList &propList) { if (m_bHdrFtrOpenCount) return; // HACK UT_DEBUGMSG(("AbiWordPerfect: defineUnorderedListLevel\n")); int listID = 0, level = 1; WPXString textBeforeNumber, textAfterNumber; float listLeftOffset = 0.0f; float listMinLabelWidth = 0.0f; if (propList["libwpd:id"]) listID = propList["libwpd:id"]->getInt(); if (propList["libwpd:level"]) level = propList["libwpd:level"]->getInt(); if (propList["text:space-before"]) listLeftOffset = propList["text:space-before"]->getFloat(); if (propList["text:min-label-width"]) listMinLabelWidth = propList["text:min-label-width"]->getFloat(); if (!m_pCurrentListDefinition || m_pCurrentListDefinition->getOutlineHash() != listID) { if (m_pCurrentListDefinition) delete (m_pCurrentListDefinition); m_pCurrentListDefinition = new ABI_ListDefinition(listID); } if (!m_pCurrentListDefinition->getListID(level)) { m_pCurrentListDefinition->setListID(level, UT_rand()); m_pCurrentListDefinition->setListLeftOffset(level, listLeftOffset); m_pCurrentListDefinition->setListMinLabelWidth(level, listMinLabelWidth); _updateDocumentUnorderedListDefinition(m_pCurrentListDefinition, level); } } //void IE_Imp_WordPerfect::openOrderedListLevel(const int listID) void IE_Imp_WordPerfect::openOrderedListLevel(const WPXPropertyList & /*propList*/) { if (m_bHdrFtrOpenCount) return; // HACK UT_DEBUGMSG(("AbiWordPerfect: openOrderedListLevel\n")); m_iCurrentListLevel++; } void IE_Imp_WordPerfect::closeOrderedListLevel() { if (m_bHdrFtrOpenCount) return; // HACK UT_DEBUGMSG(("AbiWordPerfect: closeOrderedListLevel (level: %i)\n", m_iCurrentListLevel)); UT_ASSERT(m_iCurrentListLevel > 0); // every time we close a list level, the level above it is normally renumbered to start at "1" // again. this code takes care of that. if (m_iCurrentListLevel < (WP6_NUM_LIST_LEVELS-1)) m_pCurrentListDefinition->setLevelNumber(m_iCurrentListLevel + 1, 0); m_iCurrentListLevel--; } void IE_Imp_WordPerfect::openUnorderedListLevel(const WPXPropertyList & /*propList*/) { if (m_bHdrFtrOpenCount) return; // HACK UT_DEBUGMSG(("AbiWordPerfect: openUNorderedListLevel\n")); m_iCurrentListLevel++; } void IE_Imp_WordPerfect::closeUnorderedListLevel() { if (m_bHdrFtrOpenCount) return; // HACK UT_DEBUGMSG(("AbiWordPerfect: closeUnorderedListLevel (level: %i)\n", m_iCurrentListLevel)); UT_ASSERT(m_iCurrentListLevel > 0); m_iCurrentListLevel--; } // ASSUMPTION: We assume that unordered lists will always pass a number of "0". unpredictable behaviour // may result otherwise void IE_Imp_WordPerfect::openListElement(const WPXPropertyList &propList, const WPXPropertyListVector & /*tabStops*/) { if (m_bHdrFtrOpenCount) return; // HACK UT_DEBUGMSG(("AbiWordPerfect: openListElement\n")); UT_ASSERT(m_pCurrentListDefinition); // FIXME: ABI_LISTS_IMPORT throw an exception back to libwpd, if this fails // Paragraph properties for our list element UT_String szListID; UT_String szParentID; UT_String szLevel; UT_String_sprintf(szListID,"%d",m_pCurrentListDefinition->getListID(m_iCurrentListLevel)); if (m_iCurrentListLevel > 1) UT_String_sprintf(szParentID,"%d", m_pCurrentListDefinition->getListID((m_iCurrentListLevel-1))); else UT_String_sprintf(szParentID,"0"); UT_String_sprintf(szLevel,"%d", m_iCurrentListLevel); const gchar* listAttribs[PT_MAX_ATTRIBUTES*2 + 1]; UT_uint32 attribsCount=0; listAttribs[attribsCount++] = PT_LISTID_ATTRIBUTE_NAME; listAttribs[attribsCount++] = szListID.c_str(); listAttribs[attribsCount++] = PT_PARENTID_ATTRIBUTE_NAME; listAttribs[attribsCount++] = szParentID.c_str(); listAttribs[attribsCount++] = PT_LEVEL_ATTRIBUTE_NAME; listAttribs[attribsCount++] = szLevel.c_str(); // Now handle the Abi List properties UT_String propBuffer; UT_String tempBuffer; UT_String_sprintf(tempBuffer,"list-style:%i;", m_pCurrentListDefinition->getListType(m_iCurrentListLevel)); propBuffer += tempBuffer; #if 0 // FIXME: writing the list delimiter is kind of tricky and silly (because wordperfect wants to define // it within the document, while abi wants to (sensibly probably) define it in the list definition) // (we reset it each time but only for numbered lists) if (listDefinition->isLevelNumbered(m_iCurrentListLevel)) { UT_DEBUGMSG(("WordPerfect: Appending this list delim: %s\n", m_rightListDelim.c_str())); listDefinition->setListRightDelimText(m_iCurrentListLevel, m_rightListDelim.c_str()); X_CheckWordPerfectError(_updateDocumentListDefinition(listDefinition, m_iCurrentListLevel)); } #endif if (m_pCurrentListDefinition->getListType(m_iCurrentListLevel) == BULLETED_LIST) UT_String_sprintf(tempBuffer, "field-font:Symbol; "); else UT_String_sprintf(tempBuffer, "field-font:NULL; "); m_pCurrentListDefinition->incrementLevelNumber(m_iCurrentListLevel); propBuffer += tempBuffer; UT_String_sprintf(tempBuffer, "start-value:%i; ", 1); propBuffer += tempBuffer; UT_String_sprintf(tempBuffer, "margin-left:%.4fin; ", m_pCurrentListDefinition->getListLeftOffset(m_iCurrentListLevel) + m_pCurrentListDefinition->getListMinLabelWidth(m_iCurrentListLevel) - (propList["fo:text-indent"] ? propList["fo:text-indent"]->getFloat() : 0.0f)); propBuffer += tempBuffer; UT_String_sprintf(tempBuffer, "text-indent:%.4fin", - m_pCurrentListDefinition->getListMinLabelWidth(m_iCurrentListLevel) + (propList["fo:text-indent"] ? propList["fo:text-indent"]->getFloat() : 0.0f)); propBuffer += tempBuffer; listAttribs[attribsCount++] = PT_PROPS_ATTRIBUTE_NAME; listAttribs[attribsCount++] = propBuffer.c_str(); listAttribs[attribsCount++] = NULL; X_CheckDocumentError(appendStrux(PTX_Block, listAttribs)); m_bRequireBlock = false; // hang text off of a list label getDoc()->appendFmtMark(); UT_DEBUGMSG(("WordPerfect: LISTS - Appended a list tag def'n (character props)\n")); // append a list field label const gchar* fielddef[5]; fielddef[0] ="type"; fielddef[1] = "list_label"; fielddef[2] = NULL; X_CheckDocumentError(appendObject(PTO_Field,fielddef)); UT_DEBUGMSG(("WordPerfect: LISTS - Appended a field def'n\n")); // insert a tab UT_UCS4Char ucs = UCS_TAB; X_CheckDocumentError(appendSpan(&ucs,1)); } void IE_Imp_WordPerfect::openFootnote(const WPXPropertyList & /*propList*/) { if (m_bHdrFtrOpenCount) return; // HACK if (!m_bInSection) { X_CheckDocumentError(appendStrux(PTX_Section, NULL)); X_CheckDocumentError(appendStrux(PTX_Block,NULL)); m_bInSection = true; } const gchar** propsArray = NULL; UT_String footnoteId; UT_String_sprintf(footnoteId,"%i",UT_rand()); propsArray = static_cast(UT_calloc(7, sizeof(gchar *))); propsArray [0] = "type"; propsArray [1] = "footnote_ref"; propsArray [2] = "footnote-id"; propsArray [3] = footnoteId.c_str(); propsArray [4] = NULL; propsArray [5] = NULL; propsArray [6] = NULL; X_CheckDocumentError(appendObject(PTO_Field, propsArray)); const gchar * attribs[3] ={"footnote-id", footnoteId.c_str(), NULL}; X_CheckDocumentError(appendStrux(PTX_SectionFootnote,attribs)); X_CheckDocumentError(appendStrux(PTX_Block,NULL)); m_bRequireBlock = false; propsArray = static_cast(UT_calloc(7, sizeof(gchar *))); propsArray [0] = "type"; propsArray [1] = "footnote_anchor"; propsArray [2] = "footnote-id"; propsArray [3] = footnoteId.c_str(); propsArray [4] = NULL; propsArray [5] = NULL; propsArray [6] = NULL; X_CheckDocumentError(appendObject(PTO_Field, propsArray)); } void IE_Imp_WordPerfect::closeFootnote() { if (m_bHdrFtrOpenCount) return; // HACK X_CheckDocumentError(appendStrux(PTX_EndFootnote,NULL)); } void IE_Imp_WordPerfect::openEndnote(const WPXPropertyList & /*propList*/) { if (m_bHdrFtrOpenCount) return; // HACK const gchar** propsArray = NULL; UT_String endnoteId; UT_String_sprintf(endnoteId,"%i",UT_rand()); propsArray = static_cast(UT_calloc(7, sizeof(gchar *))); propsArray [0] = "type"; propsArray [1] = "endnote_ref"; propsArray [2] = "endnote-id"; propsArray [3] = endnoteId.c_str(); propsArray [4] = NULL; propsArray [5] = NULL; propsArray [6] = NULL; X_CheckDocumentError(appendObject(PTO_Field, propsArray)); const gchar * attribs[3] ={"endnote-id", endnoteId.c_str(), NULL}; X_CheckDocumentError(appendStrux(PTX_SectionEndnote,attribs)); X_CheckDocumentError(appendStrux(PTX_Block,NULL)); m_bRequireBlock = false; propsArray = static_cast(UT_calloc(7, sizeof(gchar *))); propsArray [0] = "type"; propsArray [1] = "endnote_anchor"; propsArray [2] = "endnote-id"; propsArray [3] = endnoteId.c_str(); propsArray [4] = NULL; propsArray [5] = NULL; propsArray [6] = NULL; X_CheckDocumentError(appendObject(PTO_Field, propsArray)); } void IE_Imp_WordPerfect::closeEndnote() { if (m_bHdrFtrOpenCount) return; // HACK X_CheckDocumentError(appendStrux(PTX_EndEndnote,NULL)); } void IE_Imp_WordPerfect::openTable(const WPXPropertyList &propList, const WPXPropertyListVector &columns) { if (m_bHdrFtrOpenCount) return; // HACK // TODO: handle 'marginLeftOffset' and 'marginRightOffset' UT_DEBUGMSG(("AbiWordPerfect: openTable\n")); UT_String propBuffer; if (propList["table:align"]) { // no need to support left: default behaviour //if (strcmp(propList["table:align"]->getStr().cstr(), "right")) // abiword does not support this I think //if (strcmp(propList["table:align"]->getStr().cstr(), "center")) // abiword does not support this I think //if (strcmp(propList["table:align"]->getStr().cstr(), "margins")) // abiword does not support this I think if (strcmp(propList["table:align"]->getStr().cstr(), "margins")) { if (propList["fo:margin-left"]) UT_String_sprintf(propBuffer, "table-column-leftpos:%s; ", propList["fo:margin-left"]->getStr().cstr()); } } propBuffer += "table-column-props:"; WPXPropertyListVector::Iter i(columns); for (i.rewind(); i.next();) { UT_String tmpBuffer; if (i()["style:column-width"]) UT_String_sprintf(tmpBuffer, "%s/", i()["style:column-width"]->getStr().cstr()); propBuffer += tmpBuffer; } const gchar* propsArray[3]; propsArray[0] = "props"; propsArray[1] = propBuffer.c_str(); propsArray[2] = NULL; X_CheckDocumentError(appendStrux(PTX_SectionTable, propsArray)); } void IE_Imp_WordPerfect::openTableRow(const WPXPropertyList & /*propList*/) { if (m_bHdrFtrOpenCount) return; // HACK UT_DEBUGMSG(("AbiWordPerfect: openRow\n")); if (m_bInCell) { X_CheckDocumentError(appendStrux(PTX_EndCell, NULL)); } m_bInCell = false; } void IE_Imp_WordPerfect::openTableCell(const WPXPropertyList &propList) { if (m_bHdrFtrOpenCount) return; // HACK int col =0, row = 0, colSpan = 0, rowSpan = 0; if (propList["libwpd:column"]) col = propList["libwpd:column"]->getInt(); if (propList["libwpd:row"]) row = propList["libwpd:row"]->getInt(); if (propList["table:number-columns-spanned"]) colSpan = propList["table:number-columns-spanned"]->getInt(); if (propList["table:number-rows-spanned"]) rowSpan = propList["table:number-rows-spanned"]->getInt(); UT_DEBUGMSG(("AbiWordPerfect: openCell(col: %d, row: %d, colSpan: %d, rowSpan: %d\n", col, row, colSpan, rowSpan)); if (m_bInCell) { X_CheckDocumentError(appendStrux(PTX_EndCell, NULL)); } UT_String propBuffer; UT_String_sprintf(propBuffer, "left-attach:%d; right-attach:%d; top-attach:%d; bot-attach:%d", col, col+colSpan, row, row+rowSpan); UT_String borderStyle; // we only support bg-style:1 for now bool borderLeftSolid = false; bool borderRightSolid = false; bool borderTopSolid = false; bool borderBottomSolid = false; if (propList["fo:border-left"]) borderLeftSolid = strncmp(propList["fo:border-left"]->getStr().cstr(), "0.0inch", 7); if (propList["fo:border-right"]) borderRightSolid = strncmp(propList["fo:border-right"]->getStr().cstr(), "0.0inch", 7); if (propList["fo:border-top"]) borderTopSolid = strncmp(propList["fo:border-top"]->getStr().cstr(), "0.0inch", 7); if (propList["fo:border-bottom"]) borderBottomSolid = strncmp(propList["fo:border-bottom"]->getStr().cstr(), "0.0inch", 7); UT_String_sprintf(borderStyle, "; left-style:%s; right-style:%s; top-style:%s; bot-style:%s", (borderLeftSolid ? "solid" : "none"), (borderRightSolid ? "solid" : "none"), (borderTopSolid ? "solid" : "none"), (borderBottomSolid ? "solid" : "none")); propBuffer += borderStyle; // we only support bg-style:1 for now if (propList["fo:background-color"]) { UT_String bgCol; UT_String_sprintf(bgCol, "; bg-style:1; background-color:%s", &(propList["fo:background-color"]->getStr().cstr()[1])); propBuffer += bgCol; } UT_DEBUGMSG(("AbiWordPerfect: Inserting a Cell definition: %s\n", propBuffer.c_str())); const gchar* propsArray[3]; propsArray[0] = "props"; propsArray[1] = propBuffer.c_str(); propsArray[2] = NULL; X_CheckDocumentError(appendStrux(PTX_SectionCell, propsArray)); m_bInCell = true; } void IE_Imp_WordPerfect::closeTable() { if (m_bHdrFtrOpenCount) return; // HACK UT_DEBUGMSG(("AbiWordPerfect: Closing table\n")); if (m_bInCell) { X_CheckDocumentError(appendStrux(PTX_EndCell, NULL)); } X_CheckDocumentError(appendStrux(PTX_EndTable, NULL)); m_bInCell = false; // we need to open a new paragraph after a table, since libwpd does NOT do it // FIXME: NEED TO PASS THE CURRENT PROPERTIES INSTEAD OF NULL // NOTE: THIS SUCKS......... X_CheckDocumentError(appendStrux(PTX_Block, NULL)); m_bRequireBlock = false; } UT_Error IE_Imp_WordPerfect::_appendSection(int numColumns, const float marginLeft, const float marginRight) { UT_DEBUGMSG(("AbiWordPerfect: Appending section\n")); UT_String myProps("") ; UT_LocaleTransactor lt(LC_NUMERIC, "C"); myProps += UT_String_sprintf("columns:%d; page-margin-left:%.4fin; page-margin-right:%.4fin", numColumns, marginLeft, marginRight); if(m_bInSection && m_bRequireBlock) // AbiWord will hang on an empty
{ X_CheckDocumentError(appendStrux(PTX_Block,NULL)); } const gchar * propsArray[3]; propsArray[0] = "props"; propsArray[1] = myProps.c_str(); propsArray[2] = NULL ; X_CheckDocumentError(appendStrux(PTX_Section, propsArray)); m_bInSection = true; m_bRequireBlock = true; m_bSectionChanged = false; return UT_OK; } // NB: AbiWord-2.0 doesn't properly support nested lists with different nested styles: only "1" style // really looks proper. We hack around this be only using the style given at level "1" // NB: AbiWord-2.0 doesn't properly support setting list delimeters at levels greater than 1, // we hack around this by using only "plain" (e.g.: NULL) list delimeters on levels greater than 1. UT_Error IE_Imp_WordPerfect::_updateDocumentOrderedListDefinition(ABI_ListDefinition *pListDefinition, int iLevel, const char /*listType*/, const UT_UTF8String &sTextBeforeNumber, const UT_UTF8String &sTextAfterNumber, int iStartingNumber) { UT_DEBUGMSG(("AbiWordPerfect: Updating document list definition (iLevel: %i)\n", iLevel)); if (iLevel > 1) { UT_DEBUGMSG(("WLACH: Parent's list id is.. %i\n", pListDefinition->getListID((iLevel-1)))); } // finally, set the document's list identification info.. fl_AutoNum * pAuto = getDoc()->getListByID(pListDefinition->getListID(iLevel)); // not in document yet, we should create a list for it if (pAuto == NULL) { UT_DEBUGMSG(("AbiWordPerfect: pAuto is NULL: creating a list\n")); if (iLevel > 1) { pAuto = new fl_AutoNum(pListDefinition->getListID(iLevel), pListDefinition->getListID((iLevel-1)), pListDefinition->getListType(1), iStartingNumber, const_cast(reinterpret_cast("%L")), ".", getDoc(), NULL); } else { UT_UTF8String sNumberingString; UT_UTF8String sNumber("%L", (size_t)0); sNumberingString += sTextBeforeNumber; sNumberingString += sNumber; sNumberingString += sTextAfterNumber; pAuto = new fl_AutoNum(pListDefinition->getListID(iLevel), 0, pListDefinition->getListType(iLevel), iStartingNumber, const_cast(reinterpret_cast(sNumberingString.utf8_str())), ".", getDoc(), NULL); } getDoc()->addList(pAuto); } // we should update what we have else { UT_DEBUGMSG(("AbiWordPerfect: pAuto already exists\n")); } pAuto->fixHierarchy(); return UT_OK; } UT_Error IE_Imp_WordPerfect::_updateDocumentUnorderedListDefinition(ABI_ListDefinition *pListDefinition, int iLevel) { UT_DEBUGMSG(("AbiWordPerfect: Updating document list definition (iLevel: %i)\n", iLevel)); // finally, set the document's list identification info.. fl_AutoNum * pAuto = getDoc()->getListByID(pListDefinition->getListID(iLevel)); // not in document yet, we should create a list for it if (pAuto == NULL) { UT_DEBUGMSG(("AbiWordPerfect: pAuto is NULL: creating a list\n")); if (iLevel > 1) { pAuto = new fl_AutoNum(pListDefinition->getListID(iLevel), pListDefinition->getListID((iLevel-1)), pListDefinition->getListType(1), 0, const_cast(reinterpret_cast("%L")), ".", getDoc(), NULL); } else pAuto = new fl_AutoNum(pListDefinition->getListID(iLevel), 0, pListDefinition->getListType(iLevel), 0, const_cast(reinterpret_cast("%L")), ".", getDoc(), NULL); getDoc()->addList(pAuto); } // we should update what we have else { UT_DEBUGMSG(("AbiWordPerfect: pAuto already exists\n")); } pAuto->fixHierarchy(); return UT_OK; } #ifdef HAVE_LIBWPS class IE_Imp_MSWorks : public IE_Imp_WordPerfect { public: IE_Imp_MSWorks(PD_Document * pDocument) : IE_Imp_WordPerfect(pDocument) { } ~IE_Imp_MSWorks() { } protected: virtual UT_Error _loadFile(GsfInput * input) { AbiWordperfectInputStream gsfInput(input); WPSResult error = WPSDocument::parse(&gsfInput, static_cast(this)); if (error != WPS_OK) { UT_DEBUGMSG(("AbiMSWorks: ERROR: %i!\n", (int)error)); return UT_IE_IMPORTERROR; } return UT_OK; } }; /****************************************************************************************/ /****************************************************************************************/ IE_Imp_MSWorks_Sniffer::IE_Imp_MSWorks_Sniffer() : IE_ImpSniffer("application/vnd.ms-works") { } IE_Imp_MSWorks_Sniffer::~IE_Imp_MSWorks_Sniffer() { } // supported suffixes static IE_SuffixConfidence IE_Imp_MSWorks_Sniffer__SuffixConfidence[] = { { "wps", UT_CONFIDENCE_PERFECT }, { "", UT_CONFIDENCE_ZILCH } }; const IE_SuffixConfidence * IE_Imp_MSWorks_Sniffer::getSuffixConfidence () { return IE_Imp_MSWorks_Sniffer__SuffixConfidence; } UT_Confidence_t IE_Imp_MSWorks_Sniffer::recognizeContents (GsfInput * input) { AbiWordperfectInputStream gsfInput(input); WPSConfidence confidence = WPSDocument::isFileFormatSupported(&gsfInput, true); switch (confidence) { case WPS_CONFIDENCE_NONE: return UT_CONFIDENCE_ZILCH; case WPS_CONFIDENCE_POOR: return UT_CONFIDENCE_POOR; case WPS_CONFIDENCE_LIKELY: return UT_CONFIDENCE_SOSO; case WPS_CONFIDENCE_GOOD: return UT_CONFIDENCE_GOOD; case WPS_CONFIDENCE_EXCELLENT: return UT_CONFIDENCE_PERFECT; default: return UT_CONFIDENCE_ZILCH; } } UT_Error IE_Imp_MSWorks_Sniffer::constructImporter (PD_Document * pDocument, IE_Imp ** ppie) { *ppie = new IE_Imp_MSWorks(pDocument); return UT_OK; } bool IE_Imp_MSWorks_Sniffer::getDlgLabels (const char ** pszDesc, const char ** pszSuffixList, IEFileType * ft) { *pszDesc = "Microsoft Works (.wps)"; *pszSuffixList = "*.wps"; *ft = getFileType(); return true; } #endif