/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* libwpd * Version: MPL 2.0 / LGPLv2.1+ * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Major Contributor(s): * Copyright (C) 2002 William Lachance (wrlach@gmail.com) * Copyright (C) 2002 Marc Maurer (uwog@uwog.net) * Copyright (C) 2004 Fridrich Strba (fridrich.strba@bluewin.ch) * * For minor contributions see the git repository. * * Alternatively, the contents of this file may be used under the terms * of the GNU Lesser General Public License Version 2.1 or later * (LGPLv2.1+), in which case the provisions of the LGPLv2.1+ are * applicable instead of those above. * * For further information visit http://libwpd.sourceforge.net */ /* "This product is not manufactured, approved, or supported by * Corel Corporation or Corel Corporation Limited." */ #include "WP6ParagraphGroup.h" #include "libwpd_internal.h" #include "WPXFileStructure.h" #include "WP6FileStructure.h" #include "WP6Listener.h" WP6ParagraphGroup::WP6ParagraphGroup(librevenge::RVNGInputStream *input, WPXEncryption *encryption) : WP6VariableLengthGroup(), m_subGroupData(nullptr) { _read(input, encryption); } WP6ParagraphGroup::~WP6ParagraphGroup() { if (m_subGroupData) delete (m_subGroupData); } void WP6ParagraphGroup::_readContents(librevenge::RVNGInputStream *input, WPXEncryption *encryption) { switch (getSubGroup()) { case WP6_PARAGRAPH_GROUP_LINE_SPACING: m_subGroupData = new WP6ParagraphGroup_LineSpacingSubGroup(input, encryption); break; case WP6_PARAGRAPH_GROUP_TAB_SET: m_subGroupData = new WP6ParagraphGroup_TabSetSubGroup(input, encryption); break; case WP6_PARAGRAPH_GROUP_JUSTIFICATION: m_subGroupData = new WP6ParagraphGroup_JustificationModeSubGroup(input, encryption); break; case WP6_PARAGRAPH_GROUP_SPACING_AFTER_PARAGRAPH: m_subGroupData = new WP6ParagraphGroup_SpacingAfterParagraphSubGroup(input, encryption, getSizeNonDeletable()); break; case WP6_PARAGRAPH_GROUP_INDENT_FIRST_LINE_OF_PARAGRAPH: m_subGroupData = new WP6ParagraphGroup_IndentFirstLineSubGroup(input, encryption); break; case WP6_PARAGRAPH_GROUP_LEFT_MARGIN_ADJUSTMENT: m_subGroupData = new WP6ParagraphGroup_LeftMarginAdjustmentSubGroup(input, encryption); break; case WP6_PARAGRAPH_GROUP_RIGHT_MARGIN_ADJUSTMENT: m_subGroupData = new WP6ParagraphGroup_RightMarginAdjustmentSubGroup(input, encryption); break; case WP6_PARAGRAPH_GROUP_OUTLINE_DEFINE: m_subGroupData = new WP6ParagraphGroup_OutlineDefineSubGroup(input, encryption); break; default: break; } } void WP6ParagraphGroup::parse(WP6Listener *listener) { WPD_DEBUG_MSG(("WordPerfect: handling a Paragraph group\n")); if (m_subGroupData) m_subGroupData->parse(listener, getNumPrefixIDs(), getPrefixIDs()); } WP6ParagraphGroup_LineSpacingSubGroup::WP6ParagraphGroup_LineSpacingSubGroup(librevenge::RVNGInputStream *input, WPXEncryption *encryption) : m_lineSpacing(0) { unsigned lineSpacing = readU32(input, encryption); signed short lineSpacingIntegerPart = (signed short)((lineSpacing & 0xFFFF0000) >> 16); double lineSpacingFractionalPart = (double)(lineSpacing & 0xFFFF)/(double)0xFFFF; WPD_DEBUG_MSG(("WordPerfect: line spacing integer part: %i fractional part: %f (original value: %i)\n", lineSpacingIntegerPart, lineSpacingFractionalPart, lineSpacing)); m_lineSpacing = lineSpacingIntegerPart + lineSpacingFractionalPart; } void WP6ParagraphGroup_LineSpacingSubGroup::parse(WP6Listener *listener, const unsigned char /* numPrefixIDs */, const unsigned short * /* prefixIDs */) const { WPD_DEBUG_MSG(("WordPerfect: parsing a line spacing change of: %f\n", m_lineSpacing)); listener->lineSpacingChange(m_lineSpacing); } WP6ParagraphGroup_TabSetSubGroup::WP6ParagraphGroup_TabSetSubGroup(librevenge::RVNGInputStream *input, WPXEncryption *encryption) : m_isRelative(false), m_tabAdjustValue(0.0), m_usePreWP9LeaderMethods(), m_tabStops() { unsigned char definition = readU8(input, encryption); unsigned short tabAdjustValue = readU16(input, encryption); if (definition == 0) { m_isRelative = false; m_tabAdjustValue = 0.0; } else { m_isRelative = true; m_tabAdjustValue = double(tabAdjustValue)/WPX_NUM_WPUS_PER_INCH; } unsigned char repetitionCount = 0; WPXTabStop tabStop; unsigned char numTabStops = readU8(input, encryption); bool usePreWP9LeaderMethod = false; unsigned char tabType = 0; m_tabStops.reserve(numTabStops); for (int i = 0; i < numTabStops; i++) { tabType = readU8(input, encryption); if ((tabType & 0x80) != 0) { repetitionCount = (tabType & 0x7F); } else { switch (tabType & 0x0F) //alignment bits { case 0x00: tabStop.m_alignment = LEFT; break; case 0x01: tabStop.m_alignment = CENTER; break; case 0x02: tabStop.m_alignment = RIGHT; break; case 0x03: tabStop.m_alignment = DECIMAL; break; case 0x04: tabStop.m_alignment = BAR; break; default: // should not happen, maybe corruption tabStop.m_alignment = LEFT; break; } tabStop.m_leaderNumSpaces = 0; if ((tabType & 0x10) == 0) // no leader character { tabStop.m_leaderCharacter = '\0'; usePreWP9LeaderMethod = false; } else { switch ((tabType & 0x60) >> 5) // leader character type { case 0: // pre-WP9 leader method tabStop.m_leaderCharacter = '.'; tabStop.m_leaderNumSpaces = 0; usePreWP9LeaderMethod = true; break; case 1: // dot leader tabStop.m_leaderCharacter = '.'; tabStop.m_leaderNumSpaces = 0; usePreWP9LeaderMethod = false; break; case 2: // hyphen leader tabStop.m_leaderCharacter = '-'; tabStop.m_leaderNumSpaces = 0; usePreWP9LeaderMethod = false; break; case 3: // underscore leader tabStop.m_leaderCharacter = '_'; tabStop.m_leaderNumSpaces = 0; usePreWP9LeaderMethod = false; break; default: break; } } } unsigned short tabPosition = readU16(input, encryption); if (repetitionCount == 0) { if (tabPosition != 0xFFFF) { tabStop.m_position = double(tabPosition)/WPX_NUM_WPUS_PER_INCH - m_tabAdjustValue; m_tabStops.push_back(tabStop); m_usePreWP9LeaderMethods.push_back(usePreWP9LeaderMethod); } } else { m_tabStops.reserve(m_tabStops.capacity() + repetitionCount); for (int k=0; k::const_iterator i = m_tabStops.begin(); i != m_tabStops.end(); ++i) { WPD_DEBUG_MSG((" %.4f", (*i).m_position)); } WPD_DEBUG_MSG((")\n")); #endif listener->defineTabStops(m_isRelative, m_tabStops, m_usePreWP9LeaderMethods); } WP6ParagraphGroup_IndentFirstLineSubGroup::WP6ParagraphGroup_IndentFirstLineSubGroup(librevenge::RVNGInputStream *input, WPXEncryption *encryption) : m_firstLineOffset(0) { m_firstLineOffset = (signed short)readU16(input, encryption); WPD_DEBUG_MSG(("WordPerfect: indent first line: %i\n", m_firstLineOffset)); } void WP6ParagraphGroup_IndentFirstLineSubGroup::parse(WP6Listener *listener, const unsigned char /* numPrefixIDs */, const unsigned short * /* prefixIDs */) const { WPD_DEBUG_MSG(("WordPerfect: parsing first line indent change of: %i\n", m_firstLineOffset)); listener->indentFirstLineChange(m_firstLineOffset); } WP6ParagraphGroup_LeftMarginAdjustmentSubGroup::WP6ParagraphGroup_LeftMarginAdjustmentSubGroup(librevenge::RVNGInputStream *input, WPXEncryption *encryption) : m_leftMargin(0) { m_leftMargin = (signed short)readU16(input, encryption); WPD_DEBUG_MSG(("WordPerfect: left margin adjustment: %i\n", m_leftMargin)); } void WP6ParagraphGroup_LeftMarginAdjustmentSubGroup::parse(WP6Listener *listener, const unsigned char /* numPrefixIDs */, const unsigned short * /* prefixIDs */) const { WPD_DEBUG_MSG(("WordPerfect: parsing left margin adjustment change of: %i\n", m_leftMargin)); listener->paragraphMarginChange(WPX_LEFT, m_leftMargin); } WP6ParagraphGroup_RightMarginAdjustmentSubGroup::WP6ParagraphGroup_RightMarginAdjustmentSubGroup(librevenge::RVNGInputStream *input, WPXEncryption *encryption) : m_rightMargin(0) { m_rightMargin = (signed short)readU16(input, encryption); WPD_DEBUG_MSG(("WordPerfect: right margin adjustment: %i\n", m_rightMargin)); } void WP6ParagraphGroup_RightMarginAdjustmentSubGroup::parse(WP6Listener *listener, const unsigned char /* numPrefixIDs */, const unsigned short * /* prefixIDs */) const { WPD_DEBUG_MSG(("WordPerfect: parsing right margin adjustment change of: %i\n", m_rightMargin)); listener->paragraphMarginChange(WPX_RIGHT, m_rightMargin); } WP6ParagraphGroup_JustificationModeSubGroup::WP6ParagraphGroup_JustificationModeSubGroup(librevenge::RVNGInputStream *input, WPXEncryption *encryption) : m_justification(0) { m_justification = readU8(input, encryption); } void WP6ParagraphGroup_JustificationModeSubGroup::parse(WP6Listener *listener, const unsigned char /* numPrefixIDs */, const unsigned short * /* prefixIDs */) const { listener->justificationChange(m_justification); } WP6ParagraphGroup_SpacingAfterParagraphSubGroup::WP6ParagraphGroup_SpacingAfterParagraphSubGroup(librevenge::RVNGInputStream *input, WPXEncryption *encryption, const unsigned short sizeNonDeletable) : m_spacingAfterParagraphAbsolute(0.0), m_spacingAfterParagraphRelative(1.0), m_sizeNonDeletable(sizeNonDeletable) { unsigned spacingAfterRelative = readU32(input, encryption); signed short spacingAfterIntegerPart = (signed short)((spacingAfterRelative & 0xFFFF0000) >> 16); double spacingAfterFractionalPart = (double)(spacingAfterRelative & 0xFFFF)/(double)0xFFFF; WPD_DEBUG_MSG(("WordPerfect: spacing after paragraph relative integer part: %i fractional part: %f (original value: %i)\n", spacingAfterIntegerPart, spacingAfterFractionalPart, spacingAfterRelative)); m_spacingAfterParagraphRelative = spacingAfterIntegerPart + spacingAfterFractionalPart; if (m_sizeNonDeletable == (unsigned short)0x06) // Let us use the optional information that is in WPUs { unsigned short spacingAfterAbsolute = readU16(input, encryption); m_spacingAfterParagraphAbsolute = double(spacingAfterAbsolute) / WPX_NUM_WPUS_PER_INCH; WPD_DEBUG_MSG(("WordPerfect: spacing after paragraph absolute: %i\n", spacingAfterAbsolute)); } } void WP6ParagraphGroup_SpacingAfterParagraphSubGroup::parse(WP6Listener *listener, const unsigned char /* numPrefixIDs */, const unsigned short * /* prefixIDs */) const { WPD_DEBUG_MSG(("WordPerfect: parsing a change of spacing after paragraph: relative %f, absolute %f\n", m_spacingAfterParagraphRelative, m_spacingAfterParagraphAbsolute)); listener->spacingAfterParagraphChange(m_spacingAfterParagraphRelative, m_spacingAfterParagraphAbsolute); } WP6ParagraphGroup_OutlineDefineSubGroup::WP6ParagraphGroup_OutlineDefineSubGroup(librevenge::RVNGInputStream *input, WPXEncryption *encryption) : m_outlineHash(0), m_tabBehaviourFlag(0) { // NB: this is identical to WP6OutlineStylePacket::_readContents!! m_outlineHash = readU16(input, encryption); for (unsigned char &numberingMethod : m_numberingMethods) numberingMethod = readU8(input, encryption); m_tabBehaviourFlag = readU8(input, encryption); WPD_DEBUG_MSG(("WordPerfect: Read Outline Style Packet (, outlineHash: %i, tab behaviour flag: %i)\n", (int) m_outlineHash, (int) m_tabBehaviourFlag)); WPD_DEBUG_MSG(("WordPerfect: Read Outline Style Packet (m_numberingMethods: %i %i %i %i %i %i %i %i)\n", m_numberingMethods[0], m_numberingMethods[1], m_numberingMethods[2], m_numberingMethods[3], m_numberingMethods[4], m_numberingMethods[5], m_numberingMethods[6], m_numberingMethods[7])); } void WP6ParagraphGroup_OutlineDefineSubGroup::parse(WP6Listener *listener, const unsigned char /* numPrefixIDs */, const unsigned short * /* prefixIDs */) const { listener->updateOutlineDefinition(m_outlineHash, m_numberingMethods, m_tabBehaviourFlag); } /* vim:set shiftwidth=4 softtabstop=4 noexpandtab: */