Coverage Report

Created: 2026-09-14 06:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libwpd/src/lib/WP6ParagraphGroup.cpp
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2
/* libwpd
3
 * Version: MPL 2.0 / LGPLv2.1+
4
 *
5
 * This Source Code Form is subject to the terms of the Mozilla Public
6
 * License, v. 2.0. If a copy of the MPL was not distributed with this
7
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8
 *
9
 * Major Contributor(s):
10
 * Copyright (C) 2002 William Lachance (wrlach@gmail.com)
11
 * Copyright (C) 2002 Marc Maurer (uwog@uwog.net)
12
 * Copyright (C) 2004 Fridrich Strba (fridrich.strba@bluewin.ch)
13
 *
14
 * For minor contributions see the git repository.
15
 *
16
 * Alternatively, the contents of this file may be used under the terms
17
 * of the GNU Lesser General Public License Version 2.1 or later
18
 * (LGPLv2.1+), in which case the provisions of the LGPLv2.1+ are
19
 * applicable instead of those above.
20
 *
21
 * For further information visit http://libwpd.sourceforge.net
22
 */
23
24
/* "This product is not manufactured, approved, or supported by
25
 * Corel Corporation or Corel Corporation Limited."
26
 */
27
28
#include "WP6ParagraphGroup.h"
29
#include "libwpd_internal.h"
30
#include "WPXFileStructure.h"
31
#include "WP6FileStructure.h"
32
#include "WP6Listener.h"
33
34
WP6ParagraphGroup::WP6ParagraphGroup(librevenge::RVNGInputStream *input, WPXEncryption *encryption) :
35
0
  WP6VariableLengthGroup(),
36
0
  m_subGroupData()
37
0
{
38
0
  _read(input, encryption);
39
0
}
40
41
WP6ParagraphGroup::~WP6ParagraphGroup()
42
0
{
43
0
}
44
45
void WP6ParagraphGroup::_readContents(librevenge::RVNGInputStream *input, WPXEncryption *encryption)
46
0
{
47
0
  switch (getSubGroup())
48
0
  {
49
0
  case WP6_PARAGRAPH_GROUP_LINE_SPACING:
50
0
    m_subGroupData.reset(new WP6ParagraphGroup_LineSpacingSubGroup(input, encryption));
51
0
    break;
52
0
  case WP6_PARAGRAPH_GROUP_TAB_SET:
53
0
    m_subGroupData.reset(new WP6ParagraphGroup_TabSetSubGroup(input, encryption));
54
0
    break;
55
0
  case WP6_PARAGRAPH_GROUP_JUSTIFICATION:
56
0
    m_subGroupData.reset(new WP6ParagraphGroup_JustificationModeSubGroup(input, encryption));
57
0
    break;
58
0
  case WP6_PARAGRAPH_GROUP_SPACING_AFTER_PARAGRAPH:
59
0
    m_subGroupData.reset(new WP6ParagraphGroup_SpacingAfterParagraphSubGroup(input, encryption, getSizeNonDeletable()));
60
0
    break;
61
0
  case WP6_PARAGRAPH_GROUP_INDENT_FIRST_LINE_OF_PARAGRAPH:
62
0
    m_subGroupData.reset(new WP6ParagraphGroup_IndentFirstLineSubGroup(input, encryption));
63
0
    break;
64
0
  case WP6_PARAGRAPH_GROUP_LEFT_MARGIN_ADJUSTMENT:
65
0
    m_subGroupData.reset(new WP6ParagraphGroup_LeftMarginAdjustmentSubGroup(input, encryption));
66
0
    break;
67
0
  case WP6_PARAGRAPH_GROUP_RIGHT_MARGIN_ADJUSTMENT:
68
0
    m_subGroupData.reset(new WP6ParagraphGroup_RightMarginAdjustmentSubGroup(input, encryption));
69
0
    break;
70
0
  case WP6_PARAGRAPH_GROUP_OUTLINE_DEFINE:
71
0
    m_subGroupData.reset(new WP6ParagraphGroup_OutlineDefineSubGroup(input, encryption));
72
0
    break;
73
0
  default:
74
0
    break;
75
0
  }
76
0
}
77
78
void WP6ParagraphGroup::parse(WP6Listener *listener)
79
0
{
80
0
  WPD_DEBUG_MSG(("WordPerfect: handling a Paragraph group\n"));
81
82
0
  if (m_subGroupData)
83
0
    m_subGroupData->parse(listener, getNumPrefixIDs(), getPrefixIDs());
84
0
}
85
86
WP6ParagraphGroup_LineSpacingSubGroup::WP6ParagraphGroup_LineSpacingSubGroup(librevenge::RVNGInputStream *input, WPXEncryption *encryption) :
87
0
  m_lineSpacing(0)
88
0
{
89
0
  unsigned lineSpacing = readU32(input, encryption);
90
0
  auto lineSpacingIntegerPart = (signed short)((lineSpacing & 0xFFFF0000) >> 16);
91
0
  double lineSpacingFractionalPart = (double)(lineSpacing & 0xFFFF)/(double)0xFFFF;
92
0
  WPD_DEBUG_MSG(("WordPerfect: line spacing integer part: %i fractional part: %f (original value: %i)\n",
93
0
                 lineSpacingIntegerPart, lineSpacingFractionalPart, lineSpacing));
94
0
  m_lineSpacing = lineSpacingIntegerPart + lineSpacingFractionalPart;
95
0
}
96
97
void WP6ParagraphGroup_LineSpacingSubGroup::parse(WP6Listener *listener, const unsigned char /* numPrefixIDs */,
98
                                                  const unsigned short * /* prefixIDs */) const
99
0
{
100
0
  WPD_DEBUG_MSG(("WordPerfect: parsing a line spacing change of: %f\n", m_lineSpacing));
101
0
  listener->lineSpacingChange(m_lineSpacing);
102
0
}
103
104
WP6ParagraphGroup_TabSetSubGroup::WP6ParagraphGroup_TabSetSubGroup(librevenge::RVNGInputStream *input, WPXEncryption *encryption) :
105
0
  m_isRelative(false),
106
0
  m_tabAdjustValue(0.0),
107
0
  m_usePreWP9LeaderMethods(),
108
0
  m_tabStops()
109
0
{
110
0
  unsigned char definition = readU8(input, encryption);
111
0
  unsigned short tabAdjustValue = readU16(input, encryption);
112
0
  if (definition == 0)
113
0
  {
114
0
    m_isRelative = false;
115
0
    m_tabAdjustValue = 0.0;
116
0
  }
117
0
  else
118
0
  {
119
0
    m_isRelative = true;
120
0
    m_tabAdjustValue = double(tabAdjustValue)/WPX_NUM_WPUS_PER_INCH;
121
0
  }
122
0
  unsigned char repetitionCount = 0;
123
0
  WPXTabStop tabStop;
124
0
  unsigned char numTabStops = readU8(input, encryption);
125
0
  bool usePreWP9LeaderMethod = false;
126
0
  unsigned char tabType = 0;
127
0
  m_tabStops.reserve(numTabStops);
128
0
  for (int i = 0; i < numTabStops; i++)
129
0
  {
130
0
    tabType = readU8(input, encryption);
131
0
    if ((tabType & 0x80) != 0)
132
0
    {
133
0
      repetitionCount = (tabType & 0x7F);
134
0
    }
135
0
    else
136
0
    {
137
0
      switch (tabType & 0x0F) //alignment bits
138
0
      {
139
0
      case 0x00:
140
0
        tabStop.m_alignment = LEFT;
141
0
        break;
142
0
      case 0x01:
143
0
        tabStop.m_alignment = CENTER;
144
0
        break;
145
0
      case 0x02:
146
0
        tabStop.m_alignment = RIGHT;
147
0
        break;
148
0
      case 0x03:
149
0
        tabStop.m_alignment = DECIMAL;
150
0
        break;
151
0
      case 0x04:
152
0
        tabStop.m_alignment = BAR;
153
0
        break;
154
0
      default: // should not happen, maybe corruption
155
0
        tabStop.m_alignment = LEFT;
156
0
        break;
157
0
      }
158
0
      tabStop.m_leaderNumSpaces = 0;
159
0
      if ((tabType & 0x10) == 0) // no leader character
160
0
      {
161
0
        tabStop.m_leaderCharacter = '\0';
162
0
        usePreWP9LeaderMethod = false;
163
0
      }
164
0
      else
165
0
      {
166
0
        switch ((tabType & 0x60) >> 5) // leader character type
167
0
        {
168
0
        case 0: // pre-WP9 leader method
169
0
          tabStop.m_leaderCharacter = '.';
170
0
          tabStop.m_leaderNumSpaces = 0;
171
0
          usePreWP9LeaderMethod = true;
172
0
          break;
173
0
        case 1: // dot leader
174
0
          tabStop.m_leaderCharacter = '.';
175
0
          tabStop.m_leaderNumSpaces = 0;
176
0
          usePreWP9LeaderMethod = false;
177
0
          break;
178
0
        case 2: // hyphen leader
179
0
          tabStop.m_leaderCharacter = '-';
180
0
          tabStop.m_leaderNumSpaces = 0;
181
0
          usePreWP9LeaderMethod = false;
182
0
          break;
183
0
        case 3: // underscore leader
184
0
          tabStop.m_leaderCharacter = '_';
185
0
          tabStop.m_leaderNumSpaces = 0;
186
0
          usePreWP9LeaderMethod = false;
187
0
          break;
188
0
        default:
189
0
          break;
190
0
        }
191
0
      }
192
0
    }
193
0
    unsigned short tabPosition = readU16(input, encryption);
194
0
    if (repetitionCount == 0)
195
0
    {
196
0
      if (tabPosition != 0xFFFF)
197
0
      {
198
0
        tabStop.m_position = double(tabPosition)/WPX_NUM_WPUS_PER_INCH - m_tabAdjustValue;
199
0
        m_tabStops.push_back(tabStop);
200
0
        m_usePreWP9LeaderMethods.push_back(usePreWP9LeaderMethod);
201
0
      }
202
0
    }
203
0
    else
204
0
    {
205
0
      m_tabStops.reserve(m_tabStops.capacity() + repetitionCount);
206
0
      for (int k=0; k<repetitionCount; k++)
207
0
      {
208
0
        tabStop.m_position += double(tabPosition)/WPX_NUM_WPUS_PER_INCH;
209
0
        m_tabStops.push_back(tabStop);
210
0
        m_usePreWP9LeaderMethods.push_back(usePreWP9LeaderMethod);
211
0
      }
212
0
      repetitionCount = 0;
213
0
    }
214
0
  }
215
0
  m_tabStops.shrink_to_fit();
216
0
}
217
218
WP6ParagraphGroup_TabSetSubGroup::~WP6ParagraphGroup_TabSetSubGroup()
219
0
{
220
0
}
221
222
void WP6ParagraphGroup_TabSetSubGroup::parse(WP6Listener *listener, const unsigned char /* numPrefixIDs */,
223
                                             const unsigned short * /* prefixIDs */) const
224
0
{
225
#ifdef DEBUG
226
  WPD_DEBUG_MSG(("Parsing Tab Set (isRelative: %s, positions: ", (m_isRelative?"true":"false")));
227
  for (std::vector<WPXTabStop>::const_iterator i = m_tabStops.begin(); i != m_tabStops.end(); ++i)
228
  {
229
    WPD_DEBUG_MSG((" %.4f", (*i).m_position));
230
  }
231
  WPD_DEBUG_MSG((")\n"));
232
#endif
233
0
  listener->defineTabStops(m_isRelative, m_tabStops, m_usePreWP9LeaderMethods);
234
0
}
235
236
WP6ParagraphGroup_IndentFirstLineSubGroup::WP6ParagraphGroup_IndentFirstLineSubGroup(librevenge::RVNGInputStream *input, WPXEncryption *encryption) :
237
0
  m_firstLineOffset(0)
238
0
{
239
0
  m_firstLineOffset = (signed short)readU16(input, encryption);
240
0
  WPD_DEBUG_MSG(("WordPerfect: indent first line: %i\n", m_firstLineOffset));
241
0
}
242
243
void WP6ParagraphGroup_IndentFirstLineSubGroup::parse(WP6Listener *listener, const unsigned char /* numPrefixIDs */,
244
                                                      const unsigned short * /* prefixIDs */) const
245
0
{
246
0
  WPD_DEBUG_MSG(("WordPerfect: parsing first line indent change of: %i\n", m_firstLineOffset));
247
0
  listener->indentFirstLineChange(m_firstLineOffset);
248
0
}
249
250
WP6ParagraphGroup_LeftMarginAdjustmentSubGroup::WP6ParagraphGroup_LeftMarginAdjustmentSubGroup(librevenge::RVNGInputStream *input, WPXEncryption *encryption) :
251
0
  m_leftMargin(0)
252
0
{
253
0
  m_leftMargin = (signed short)readU16(input, encryption);
254
0
  WPD_DEBUG_MSG(("WordPerfect: left margin adjustment: %i\n", m_leftMargin));
255
0
}
256
257
void WP6ParagraphGroup_LeftMarginAdjustmentSubGroup::parse(WP6Listener *listener, const unsigned char /* numPrefixIDs */,
258
                                                           const unsigned short * /* prefixIDs */) const
259
0
{
260
0
  WPD_DEBUG_MSG(("WordPerfect: parsing left margin adjustment change of: %i\n", m_leftMargin));
261
0
  listener->paragraphMarginChange(WPX_LEFT, m_leftMargin);
262
0
}
263
264
WP6ParagraphGroup_RightMarginAdjustmentSubGroup::WP6ParagraphGroup_RightMarginAdjustmentSubGroup(librevenge::RVNGInputStream *input, WPXEncryption *encryption) :
265
0
  m_rightMargin(0)
266
0
{
267
0
  m_rightMargin = (signed short)readU16(input, encryption);
268
0
  WPD_DEBUG_MSG(("WordPerfect: right margin adjustment: %i\n", m_rightMargin));
269
0
}
270
271
void WP6ParagraphGroup_RightMarginAdjustmentSubGroup::parse(WP6Listener *listener, const unsigned char /* numPrefixIDs */,
272
                                                            const unsigned short * /* prefixIDs */) const
273
0
{
274
0
  WPD_DEBUG_MSG(("WordPerfect: parsing right margin adjustment change of: %i\n", m_rightMargin));
275
0
  listener->paragraphMarginChange(WPX_RIGHT, m_rightMargin);
276
0
}
277
278
WP6ParagraphGroup_JustificationModeSubGroup::WP6ParagraphGroup_JustificationModeSubGroup(librevenge::RVNGInputStream *input, WPXEncryption *encryption) :
279
0
  m_justification(0)
280
0
{
281
0
  m_justification = readU8(input, encryption);
282
0
}
283
284
void WP6ParagraphGroup_JustificationModeSubGroup::parse(WP6Listener *listener, const unsigned char /* numPrefixIDs */,
285
                                                        const unsigned short * /* prefixIDs */) const
286
0
{
287
0
  listener->justificationChange(m_justification);
288
0
}
289
290
WP6ParagraphGroup_SpacingAfterParagraphSubGroup::WP6ParagraphGroup_SpacingAfterParagraphSubGroup(librevenge::RVNGInputStream *input,
291
                                                                                                 WPXEncryption *encryption, const unsigned short sizeNonDeletable) :
292
0
  m_spacingAfterParagraphAbsolute(0.0),
293
0
  m_spacingAfterParagraphRelative(1.0),
294
0
  m_sizeNonDeletable(sizeNonDeletable)
295
0
{
296
0
  unsigned spacingAfterRelative = readU32(input, encryption);
297
0
  auto spacingAfterIntegerPart = (signed short)((spacingAfterRelative & 0xFFFF0000) >> 16);
298
0
  double spacingAfterFractionalPart = (double)(spacingAfterRelative & 0xFFFF)/(double)0xFFFF;
299
0
  WPD_DEBUG_MSG(("WordPerfect: spacing after paragraph relative integer part: %i fractional part: %f (original value: %i)\n",
300
0
                 spacingAfterIntegerPart, spacingAfterFractionalPart, spacingAfterRelative));
301
0
  m_spacingAfterParagraphRelative = spacingAfterIntegerPart + spacingAfterFractionalPart;
302
0
  if (m_sizeNonDeletable == (unsigned short)0x06) // Let us use the optional information that is in WPUs
303
0
  {
304
0
    unsigned short spacingAfterAbsolute = readU16(input, encryption);
305
0
    m_spacingAfterParagraphAbsolute = double(spacingAfterAbsolute) / WPX_NUM_WPUS_PER_INCH;
306
0
    WPD_DEBUG_MSG(("WordPerfect: spacing after paragraph absolute: %i\n", spacingAfterAbsolute));
307
0
  }
308
0
}
309
310
void WP6ParagraphGroup_SpacingAfterParagraphSubGroup::parse(WP6Listener *listener, const unsigned char /* numPrefixIDs */,
311
                                                            const unsigned short * /* prefixIDs */) const
312
0
{
313
0
  WPD_DEBUG_MSG(("WordPerfect: parsing a change of spacing after paragraph: relative %f, absolute %f\n",
314
0
                 m_spacingAfterParagraphRelative, m_spacingAfterParagraphAbsolute));
315
0
  listener->spacingAfterParagraphChange(m_spacingAfterParagraphRelative, m_spacingAfterParagraphAbsolute);
316
0
}
317
318
WP6ParagraphGroup_OutlineDefineSubGroup::WP6ParagraphGroup_OutlineDefineSubGroup(librevenge::RVNGInputStream *input, WPXEncryption *encryption) :
319
0
  m_outlineHash(0),
320
0
  m_tabBehaviourFlag(0)
321
0
{
322
  // NB: this is identical to WP6OutlineStylePacket::_readContents!!
323
0
  m_outlineHash = readU16(input, encryption);
324
0
  for (unsigned char &numberingMethod : m_numberingMethods)
325
0
    numberingMethod = readU8(input, encryption);
326
0
  m_tabBehaviourFlag = readU8(input, encryption);
327
328
0
  WPD_DEBUG_MSG(("WordPerfect: Read Outline Style Packet (, outlineHash: %i, tab behaviour flag: %i)\n", (int) m_outlineHash, (int) m_tabBehaviourFlag));
329
0
  WPD_DEBUG_MSG(("WordPerfect: Read Outline Style Packet (m_numberingMethods: %i %i %i %i %i %i %i %i)\n",
330
0
                 m_numberingMethods[0], m_numberingMethods[1], m_numberingMethods[2], m_numberingMethods[3],
331
0
                 m_numberingMethods[4], m_numberingMethods[5], m_numberingMethods[6], m_numberingMethods[7]));
332
0
}
333
334
void WP6ParagraphGroup_OutlineDefineSubGroup::parse(WP6Listener *listener, const unsigned char /* numPrefixIDs */,
335
                                                    const unsigned short * /* prefixIDs */) const
336
0
{
337
0
  listener->updateOutlineDefinition(m_outlineHash, m_numberingMethods, m_tabBehaviourFlag);
338
0
}
339
/* vim:set shiftwidth=4 softtabstop=4 noexpandtab: */