Coverage Report

Created: 2026-04-29 07:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libwpd/src/lib/WP6BoxGroup.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) 2007 Fridrich Strba (fridrich.strba@bluewin.ch)
11
 * Copyright (C) 2007 Novell Inc. (http://www.novell.com)
12
 *
13
 * For minor contributions see the git repository.
14
 *
15
 * Alternatively, the contents of this file may be used under the terms
16
 * of the GNU Lesser General Public License Version 2.1 or later
17
 * (LGPLv2.1+), in which case the provisions of the LGPLv2.1+ are
18
 * applicable instead of those above.
19
 *
20
 * For further information visit http://libwpd.sourceforge.net
21
 */
22
23
/* "This product is not manufactured, approved, or supported by
24
 * Corel Corporation or Corel Corporation Limited."
25
 */
26
27
#include "WP6BoxGroup.h"
28
#include "WP6Listener.h"
29
#include "libwpd_internal.h"
30
#include "WP6FileStructure.h"
31
#include "WPXFileStructure.h"
32
#include "WP6GraphicsFilenamePacket.h"
33
#include "WP6GeneralTextPacket.h"
34
#include "WP6GraphicsBoxStylePacket.h"
35
#include "WP6HyperlinkPacket.h"
36
37
WP6BoxGroup::WP6BoxGroup(librevenge::RVNGInputStream *input, WPXEncryption *encryption) :
38
29.1k
  WP6VariableLengthGroup(),
39
29.1k
  m_generalPositioningFlagsMask(0x00),
40
29.1k
  m_generalPositioningFlagsData(0x00),
41
29.1k
  m_hasHorizontalPositioning(false),
42
29.1k
  m_horizontalPositioningFlags(0x00),
43
29.1k
  m_horizontalOffset(0),
44
29.1k
  m_leftColumn(0),
45
29.1k
  m_rightColumn(0),
46
29.1k
  m_hasVerticalPositioning(false),
47
29.1k
  m_verticalPositioningFlags(0x00),
48
29.1k
  m_verticalOffset(0),
49
29.1k
  m_hasWidthInformation(false),
50
29.1k
  m_widthFlags(0x00),
51
29.1k
  m_width(0),
52
29.1k
  m_hasHeightInformation(false),
53
29.1k
  m_heightFlags(0x00),
54
29.1k
  m_height(0),
55
29.1k
  m_hasZOrderInformation(false),
56
29.1k
  m_zOrderFlags(0x00),
57
29.1k
  m_hasBoxContentType(false),
58
29.1k
  m_boxContentType(0x00),
59
29.1k
  m_nativeWidth(0),
60
29.1k
  m_nativeHeight(0)
61
29.1k
{
62
29.1k
  _read(input, encryption);
63
29.1k
}
64
65
void WP6BoxGroup::_readContents(librevenge::RVNGInputStream *input, WPXEncryption *encryption)
66
29.0k
{
67
29.0k
  switch (getSubGroup())
68
29.0k
  {
69
14.3k
  case WP6_BOX_GROUP_CHARACTER_ANCHORED_BOX:
70
14.8k
  case WP6_BOX_GROUP_PARAGRAPH_ANCHORED_BOX:
71
28.4k
  case WP6_BOX_GROUP_PAGE_ANCHORED_BOX:
72
28.4k
  {
73
28.4k
    input->seek(14, librevenge::RVNG_SEEK_CUR); // reserved for future use
74
28.4k
    input->seek(2, librevenge::RVNG_SEEK_CUR); // total size of override and wrap rectangle data for box
75
28.4k
    input->seek(2, librevenge::RVNG_SEEK_CUR); // total size of override data
76
28.4k
    unsigned short tmpOverrideFlags = readU16(input, encryption);
77
28.4k
    if (tmpOverrideFlags & WP6_BOX_GROUP_BOX_COUNTER_DATA_BIT)
78
9.09k
    {
79
9.09k
      long tmpEndOfData = readU16(input, encryption) + input->tell();
80
9.09k
      WPD_DEBUG_MSG(("WP6BoxGroup: parsing Box counter data -- override flags: 0x%x\n", tmpOverrideFlags));
81
#ifdef DEBUG
82
      const unsigned short tmpOverrideFlags2 = readU16(input, encryption);
83
      WPD_DEBUG_MSG(("WP6BoxGroup: parsing Box counter data -- override flags 2: 0x%x\n", tmpOverrideFlags2));
84
#else
85
9.09k
      readU16(input, encryption);
86
9.09k
#endif
87
9.09k
      input->seek(tmpEndOfData, librevenge::RVNG_SEEK_SET);
88
9.09k
    }
89
28.4k
    if (tmpOverrideFlags & WP6_BOX_GROUP_BOX_POSITIONING_DATA_BIT)
90
21.1k
    {
91
21.1k
      long tmpEndOfData = readU16(input, encryption) + input->tell();
92
93
21.1k
      tmpOverrideFlags = readU16(input, encryption);
94
95
21.1k
      if (tmpOverrideFlags & 0x8000)
96
17.5k
        input->seek(2, librevenge::RVNG_SEEK_CUR);
97
21.1k
      if (tmpOverrideFlags & 0x4000)
98
17.9k
      {
99
17.9k
        m_generalPositioningFlagsMask = readU8(input, encryption);
100
17.9k
        m_generalPositioningFlagsData = readU8(input, encryption);
101
17.9k
        WPD_DEBUG_MSG(("Box general positioning flags (mask: 0x%.2x) (data: 0x%.2x)\n",
102
17.9k
                       m_generalPositioningFlagsMask, m_generalPositioningFlagsData));
103
17.9k
      }
104
21.1k
      if (tmpOverrideFlags & 0x2000)
105
20.1k
      {
106
20.1k
        m_hasHorizontalPositioning = true;
107
20.1k
        m_horizontalPositioningFlags = readU8(input, encryption);
108
20.1k
        m_horizontalOffset = (signed short)readU16(input, encryption);
109
20.1k
        m_leftColumn = readU8(input, encryption);
110
20.1k
        m_rightColumn = readU8(input, encryption);
111
20.1k
        WPD_DEBUG_MSG(("Box horizontal positioning flags: 0x%.2x\n", m_horizontalPositioningFlags));
112
20.1k
        WPD_DEBUG_MSG(("Box horizontal offset: %i\n", m_horizontalOffset));
113
20.1k
        WPD_DEBUG_MSG(("Box left column: %i, right column: %i\n", m_leftColumn, m_rightColumn));
114
20.1k
      }
115
21.1k
      if (tmpOverrideFlags & 0x1000)
116
14.4k
      {
117
14.4k
        m_hasVerticalPositioning = true;
118
14.4k
        m_verticalPositioningFlags = readU8(input, encryption);
119
14.4k
        m_verticalOffset = (signed short)readU16(input, encryption);
120
14.4k
        WPD_DEBUG_MSG(("Box vertical positioning flags: 0x%.2x\n", m_verticalPositioningFlags));
121
14.4k
        WPD_DEBUG_MSG(("Box vertical offset: %i\n", m_verticalOffset));
122
14.4k
      }
123
21.1k
      if (tmpOverrideFlags & 0x0800)
124
10.4k
      {
125
10.4k
        m_hasWidthInformation = true;
126
10.4k
        m_widthFlags = readU8(input, encryption);
127
10.4k
        m_width = readU16(input, encryption);
128
10.4k
        WPD_DEBUG_MSG(("Box width flags: 0x%.2x\n", m_widthFlags));
129
10.4k
        WPD_DEBUG_MSG(("Box width value: %i\n", m_width));
130
10.4k
      }
131
21.1k
      if (tmpOverrideFlags & 0x0400)
132
11.7k
      {
133
11.7k
        m_hasHeightInformation = true;
134
11.7k
        m_heightFlags = readU8(input, encryption);
135
11.7k
        m_height = readU16(input, encryption);
136
11.7k
        WPD_DEBUG_MSG(("Box height flags: 0x%.2x\n", m_heightFlags));
137
11.7k
        WPD_DEBUG_MSG(("Box height value: %i\n", m_height));
138
11.7k
      }
139
21.1k
      if (tmpOverrideFlags & 0x0200)
140
9.51k
      {
141
9.51k
        m_hasZOrderInformation = true;
142
9.51k
        m_zOrderFlags = readU8(input, encryption);
143
9.51k
        WPD_DEBUG_MSG(("Box z-order flags: 0x%.2x\n", m_zOrderFlags));
144
9.51k
      }
145
21.1k
      WPD_DEBUG_MSG(("WP6BoxGroup: parsing Box positioning data -- override flags: 0x%x\n", tmpOverrideFlags));
146
21.1k
      input->seek(tmpEndOfData, librevenge::RVNG_SEEK_SET);
147
21.1k
    }
148
28.4k
    if (tmpOverrideFlags & WP6_BOX_GROUP_BOX_CONTENT_DATA_BIT)
149
22.1k
    {
150
22.1k
      long tmpEndOfData = readU16(input, encryption) + input->tell();
151
152
22.1k
      tmpOverrideFlags = readU16(input, encryption);
153
154
22.1k
      if (tmpOverrideFlags & 0x8000)
155
10.3k
        input->seek(2, librevenge::RVNG_SEEK_CUR);
156
157
22.1k
      if (tmpOverrideFlags & 0x4000)
158
21.2k
      {
159
21.2k
        m_hasBoxContentType = true;
160
21.2k
        m_boxContentType = readU8(input, encryption);
161
21.2k
      }
162
163
22.1k
      if (tmpOverrideFlags & 0x2000) // content rendering information
164
10.5k
      {
165
10.5k
        if (m_hasBoxContentType && (m_boxContentType == 0x03)) // Image
166
9.03k
        {
167
9.03k
          unsigned short tmpImageContentOverrideSize = readU16(input, encryption);
168
9.03k
          long tmpImageContentOverrideStart = input->tell();
169
9.03k
          unsigned short tmpImageContentOverrideFlags = readU16(input, encryption);
170
171
9.03k
          if (tmpImageContentOverrideFlags & 0x8000)
172
5.59k
            input->seek(2, librevenge::RVNG_SEEK_CUR);
173
9.03k
          if (tmpImageContentOverrideFlags & 0x4000)
174
6.86k
          {
175
6.86k
            m_nativeWidth = readU16(input, encryption);
176
6.86k
            m_nativeHeight = readU16(input, encryption);
177
6.86k
          }
178
9.03k
          input->seek(tmpImageContentOverrideStart + tmpImageContentOverrideSize, librevenge::RVNG_SEEK_SET);
179
9.03k
        }
180
10.5k
      }
181
#ifdef DEBUG
182
      WPD_DEBUG_MSG(("WP6BoxGroup: parsing Box content data -- override flags: 0x%x\n", tmpOverrideFlags));
183
184
      if (m_hasBoxContentType)
185
        WPD_DEBUG_MSG(("WP6BoxGroup: parsing Box content data -- content type: 0x%.2x\n", m_boxContentType));
186
#endif
187
22.1k
      input->seek(tmpEndOfData, librevenge::RVNG_SEEK_SET);
188
22.1k
    }
189
28.4k
    if (tmpOverrideFlags & WP6_BOX_GROUP_BOX_CAPTION_DATA_BIT)
190
298
    {
191
298
      long tmpEndOfData = readU16(input, encryption) + input->tell();
192
#ifdef DEBUG
193
      tmpOverrideFlags = readU16(input, encryption);
194
#else
195
298
      readU16(input, encryption);
196
298
#endif
197
298
      WPD_DEBUG_MSG(("WP6BoxGroup: parsing Box caption data -- override flags: 0x%x\n", tmpOverrideFlags));
198
298
      input->seek(tmpEndOfData, librevenge::RVNG_SEEK_SET);
199
298
    }
200
28.4k
    if (tmpOverrideFlags & WP6_BOX_GROUP_BOX_BORDER_DATA_BIT)
201
333
    {
202
333
      long tmpEndOfData = readU16(input, encryption) + input->tell();
203
#ifdef DEBUG
204
      tmpOverrideFlags = readU16(input, encryption);
205
#else
206
333
      readU16(input, encryption);
207
333
#endif
208
333
      WPD_DEBUG_MSG(("WP6BoxGroup: parsing Box border data -- override flags: 0x%x\n", tmpOverrideFlags));
209
333
      input->seek(tmpEndOfData, librevenge::RVNG_SEEK_SET);
210
333
    }
211
28.4k
    if (tmpOverrideFlags & WP6_BOX_GROUP_BOX_FILL_DATA_BIT)
212
314
    {
213
314
      long tmpEndOfData = readU16(input, encryption) + input->tell();
214
#ifdef DEBUG
215
      tmpOverrideFlags = readU16(input, encryption);
216
#else
217
314
      readU16(input, encryption);
218
314
#endif
219
314
      WPD_DEBUG_MSG(("WP6BoxGroup: parsing Box fill data -- override flags: 0x%x\n", tmpOverrideFlags));
220
314
      input->seek(tmpEndOfData, librevenge::RVNG_SEEK_SET);
221
314
    }
222
28.4k
    if (tmpOverrideFlags & WP6_BOX_GROUP_BOX_BOX_WRAPPING_DATA_BIT)
223
1.79k
    {
224
1.79k
      long tmpEndOfData = readU16(input, encryption) + input->tell();
225
#ifdef DEBUG
226
      tmpOverrideFlags = readU16(input, encryption);
227
#else
228
1.79k
      readU16(input, encryption);
229
1.79k
#endif
230
1.79k
      WPD_DEBUG_MSG(("WP6BoxGroup: parsing Box wrapping data -- override flags: 0x%x\n", tmpOverrideFlags));
231
1.79k
      input->seek(tmpEndOfData, librevenge::RVNG_SEEK_SET);
232
1.79k
    }
233
28.4k
    if (tmpOverrideFlags & WP6_BOX_GROUP_BOX_BOX_HYPERTEXT_WRAPPING_DATA_BIT)
234
1.21k
    {
235
1.21k
      long tmpEndOfData = readU16(input, encryption) + input->tell();
236
#ifdef DEBUG
237
      tmpOverrideFlags = readU16(input, encryption);
238
#else
239
1.21k
      readU16(input, encryption);
240
1.21k
#endif
241
1.21k
      WPD_DEBUG_MSG(("WP6BoxGroup: parsing Box hypertext wrapping data -- override flags: 0x%x\n", tmpOverrideFlags));
242
1.21k
      input->seek(tmpEndOfData, librevenge::RVNG_SEEK_SET);
243
1.21k
    }
244
28.4k
    if (tmpOverrideFlags & WP6_BOX_GROUP_BOX_HTML_BIT)
245
3.97k
    {
246
3.97k
      WPD_DEBUG_MSG(("WP6BoxGroup: parsing HTML\n"));
247
3.97k
    }
248
28.4k
    if (tmpOverrideFlags & WP6_BOX_GROUP_BOX_GROUPING_DATA_BIT)
249
1.36k
    {
250
1.36k
      long tmpEndOfData = readU16(input, encryption) + input->tell();
251
#ifdef DEBUG
252
      tmpOverrideFlags = readU16(input, encryption);
253
#else
254
1.36k
      readU16(input, encryption);
255
1.36k
#endif
256
1.36k
      WPD_DEBUG_MSG(("WP6BoxGroup: parsing Box grouping data -- override flags: 0x%x\n", tmpOverrideFlags));
257
1.36k
      input->seek(tmpEndOfData, librevenge::RVNG_SEEK_SET);
258
1.36k
    }
259
28.4k
    if (tmpOverrideFlags & WP6_BOX_GROUP_BOX_DRAW_OBJECT_DATA_BIT)
260
756
    {
261
756
      long tmpEndOfData = readU16(input, encryption) + input->tell();
262
#ifdef DEBUG
263
      tmpOverrideFlags = readU16(input, encryption);
264
#else
265
756
      readU16(input, encryption);
266
756
#endif
267
756
      WPD_DEBUG_MSG(("WP6BoxGroup: parsing Box draw object data -- override flags: 0x%x\n", tmpOverrideFlags));
268
756
      input->seek(tmpEndOfData, librevenge::RVNG_SEEK_SET);
269
756
    }
270
28.4k
  }
271
28.4k
  break;
272
6
  case WP6_BOX_GROUP_GRAPHICS_RULE:
273
6
    break;
274
638
  default: /* something else we don't support, since it isn't in the docs */
275
638
    break;
276
29.0k
  }
277
29.0k
}
278
279
void WP6BoxGroup::parse(WP6Listener *listener)
280
28.9k
{
281
28.9k
  WPD_DEBUG_MSG(("WordPerfect: handling a Column group\n"));
282
283
28.9k
  if (getFlags() & 0x40)  // Ignore function flag
284
879
    return;
285
286
28.1k
  if ((getSubGroup() != WP6_BOX_GROUP_CHARACTER_ANCHORED_BOX) && (getSubGroup() != WP6_BOX_GROUP_PARAGRAPH_ANCHORED_BOX) &&
287
13.9k
          (getSubGroup() != WP6_BOX_GROUP_PAGE_ANCHORED_BOX))  // Don't handle Graphics Rule for the while
288
382
    return;
289
290
27.7k
  const WP6GraphicsBoxStylePacket *gbsPacket = nullptr;
291
39.4k
  for (int j=0; j<getNumPrefixIDs(); j++)
292
11.6k
    if ((gbsPacket = dynamic_cast<const WP6GraphicsBoxStylePacket *>(listener->getPrefixDataPacket(getPrefixIDs()[j]))))
293
0
      break;
294
295
27.7k
  unsigned char tmpContentType = 0;
296
27.7k
  if (gbsPacket)
297
0
    tmpContentType = gbsPacket->getContentType();
298
27.7k
  if (m_hasBoxContentType)
299
21.2k
    tmpContentType = m_boxContentType;
300
301
27.7k
  if (tmpContentType != 0x01 && tmpContentType != 0x03)
302
6.95k
    return;
303
304
20.7k
  if (!m_nativeWidth && gbsPacket)
305
0
    m_nativeWidth = gbsPacket->getNativeWidth();
306
20.7k
  if (!m_nativeHeight && gbsPacket)
307
0
    m_nativeHeight = gbsPacket->getNativeHeight();
308
309
20.7k
  std::vector<unsigned> graphicsDataIds;
310
20.7k
  std::vector<unsigned>::iterator gdiIter;
311
20.7k
  std::shared_ptr<WP6SubDocument> subDocument;
312
313
  // Get the box content
314
29.1k
  for (int i=0; i<getNumPrefixIDs(); i++)
315
8.38k
  {
316
8.38k
    if (tmpContentType == 0x03)
317
7.80k
      if (const auto *gfPacket = dynamic_cast<const WP6GraphicsFilenamePacket *>(listener->getPrefixDataPacket(getPrefixIDs()[i])))
318
0
      {
319
0
        graphicsDataIds = gfPacket->getChildIds();
320
0
        break;
321
0
      }
322
8.38k
    if (tmpContentType == 0x01)
323
576
      if (const auto *gtPacket = dynamic_cast<const WP6GeneralTextPacket *>(listener->getPrefixDataPacket(getPrefixIDs()[i])))
324
0
      {
325
0
        subDocument = gtPacket->getSubDocument();
326
0
        break;
327
0
      }
328
8.38k
  }
329
330
  // Get the box hyperlink
331
20.7k
  librevenge::RVNGString linkTarget;
332
29.1k
  for (int i=0; i<getNumPrefixIDs(); i++)
333
8.38k
  {
334
8.38k
    if (tmpContentType == 0x03)
335
7.80k
    {
336
7.80k
      const auto *const hlPacket = dynamic_cast<const WP6HyperlinkPacket *>(listener->getPrefixDataPacket(getPrefixIDs()[i]));
337
7.80k
      if (hlPacket)
338
0
      {
339
0
        linkTarget = hlPacket->getTarget();
340
0
        break;
341
0
      }
342
7.80k
    }
343
8.38k
  }
344
345
  // Get the box anchoring
346
20.7k
  unsigned char tmpAnchoringType = 0;
347
20.7k
  switch (getSubGroup())
348
20.7k
  {
349
9.87k
  case WP6_BOX_GROUP_CHARACTER_ANCHORED_BOX:
350
9.87k
    tmpAnchoringType = WPX_CHARACTER;
351
9.87k
    break;
352
320
  case WP6_BOX_GROUP_PARAGRAPH_ANCHORED_BOX:
353
320
    tmpAnchoringType = WPX_PARAGRAPH;
354
320
    break;
355
10.5k
  case WP6_BOX_GROUP_PAGE_ANCHORED_BOX:
356
10.5k
    tmpAnchoringType = WPX_PAGE;
357
10.5k
    break;
358
0
  case WP6_BOX_GROUP_GRAPHICS_RULE:
359
0
  default: /* something else we don't support, since it isn't in the docs */
360
0
    break;
361
20.7k
  }
362
363
  // Get the box general positioning
364
20.7k
  unsigned char tmpGeneralPositioningFlags = 0;
365
20.7k
  if (gbsPacket)
366
0
    tmpGeneralPositioningFlags = (unsigned char)((gbsPacket->getGeneralPositioningFlags() & (~ m_generalPositioningFlagsMask)) |
367
0
                                                 (m_generalPositioningFlagsData & m_generalPositioningFlagsMask));
368
20.7k
  else  // here we did not manage to get the packet. Let's try to go with the override information
369
20.7k
    tmpGeneralPositioningFlags = (m_generalPositioningFlagsData & m_generalPositioningFlagsMask);
370
371
  // Get the box horizontal position
372
20.7k
  if (gbsPacket && !m_hasHorizontalPositioning)
373
0
  {
374
0
    m_horizontalPositioningFlags = gbsPacket->getHorizontalPositioningFlags();
375
0
    m_horizontalOffset = gbsPacket->getHorizontalOffset();
376
0
    m_leftColumn = gbsPacket->getLeftColumn();
377
0
    m_rightColumn = gbsPacket->getRightColumn();
378
0
  }
379
380
  // Get the box vertical position
381
20.7k
  if (gbsPacket && !m_hasVerticalPositioning)
382
0
  {
383
0
    m_verticalPositioningFlags = gbsPacket->getVerticalPositioningFlags();
384
0
    m_verticalOffset = gbsPacket->getVerticalOffset();
385
0
  }
386
387
  // Get the box width
388
20.7k
  if (gbsPacket && !m_hasWidthInformation)
389
0
  {
390
0
    m_widthFlags = gbsPacket->getWidthFlags();
391
0
    m_width = gbsPacket->getWidth();
392
0
  }
393
394
  // Get the box height
395
20.7k
  if (gbsPacket && !m_hasHeightInformation)
396
0
  {
397
0
    m_heightFlags = gbsPacket->getHeightFlags();
398
0
    m_height = gbsPacket->getHeight();
399
0
  }
400
401
  // Send the box information to the listener and start box
402
20.7k
  listener->boxOn(tmpAnchoringType, tmpGeneralPositioningFlags, m_horizontalPositioningFlags, m_horizontalOffset, m_leftColumn, m_rightColumn,
403
20.7k
                  m_verticalPositioningFlags, m_verticalOffset, m_widthFlags, m_width, m_heightFlags, m_height, tmpContentType, m_nativeWidth, m_nativeHeight,
404
20.7k
                  linkTarget);
405
406
  // Send the content according to its kind
407
20.7k
  if (tmpContentType == 0x03)
408
9.05k
  {
409
9.05k
    for (gdiIter = graphicsDataIds.begin(); gdiIter != graphicsDataIds.end(); ++gdiIter)
410
0
      listener->insertGraphicsData(((unsigned short)*gdiIter));
411
9.05k
  }
412
20.7k
  if ((tmpContentType == 0x01) && (subDocument))
413
0
  {
414
0
    listener->insertTextBox(subDocument.get());
415
0
  }
416
417
  // End the box
418
20.7k
  listener->boxOff();
419
20.7k
}
420
/* vim:set shiftwidth=4 softtabstop=4 noexpandtab: */