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-2003 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 "WP6EOLGroup.h"
29 #include "WP6Listener.h"
30 #include "libwpd_internal.h"
31
32 #include "WP6FillStylePacket.h" // for the fill packet
33
WP6EOLGroup(librevenge::RVNGInputStream * input,WPXEncryption * encryption)34 WP6EOLGroup::WP6EOLGroup(librevenge::RVNGInputStream *input, WPXEncryption *encryption) :
35 WP6VariableLengthGroup(),
36 m_colSpan(1),
37 m_rowSpan(1),
38 m_boundFromAbove(false),
39
40 m_useCellAttributes(false),
41 m_useCellJustification(false),
42 m_ignoreInCalculations(false),
43 m_cellIsLocked(false),
44 m_cellAttributes(0),
45 m_cellJustification(0),
46 m_cellVerticalAlign(TOP),
47
48 m_cellFgColor(),
49 m_cellBgColor(),
50 m_cellBorderColor(new RGBSColor(0x00,0x00,0x00,0x64)),
51
52 m_cellBorders(0x00),
53
54 m_isHeaderRow(false),
55 m_isMinimumHeight(true),
56 m_rowHeight(0),
57 m_isDontEndAParagraphStyleForThisHardReturn(false)
58 {
59 _read(input, encryption);
60 }
61
~WP6EOLGroup()62 WP6EOLGroup::~WP6EOLGroup()
63 {
64 }
65
_readContents(librevenge::RVNGInputStream * input,WPXEncryption * encryption)66 void WP6EOLGroup::_readContents(librevenge::RVNGInputStream *input, WPXEncryption *encryption)
67 {
68 WPD_DEBUG_MSG(("WordPerfect: EOL Group: Reading Embedded Sub-Function Data\n"));
69 long startPosition = input->tell();
70 unsigned short sizeDeletableSubFunctionData = readU16(input, encryption);
71 WPD_DEBUG_MSG(("WordPerfect: EOL Group: Size of Deletable Sub-Function Data: %ld, Size of Deletable and Non-deletable sub-function data: %ld\n", (long) sizeDeletableSubFunctionData, (long) getSizeNonDeletable()));
72 if ((long)sizeDeletableSubFunctionData > (long)getSizeNonDeletable())
73 {
74 WPD_DEBUG_MSG(("WordPerfect: EOL Group: Possible corruption detected, bailing out\n"));
75 throw FileException();
76 }
77
78 input->seek(sizeDeletableSubFunctionData, librevenge::RVNG_SEEK_CUR);
79 while ((long)input->tell() < (long)(startPosition + getSizeNonDeletable()))
80 {
81 unsigned char byte;
82 unsigned short numBytesToSkip = 0;
83 byte = readU8(input, encryption);
84 long startPosition2 = input->tell();
85 switch (byte)
86 {
87 case WP6_EOL_GROUP_ROW_INFORMATION:
88 WPD_DEBUG_MSG(("WordPerfect: EOL Group Embedded Sub-Function: ROW_INFORMATION\n"));
89 numBytesToSkip = WP6_EOL_GROUP_ROW_INFORMATION_SIZE;
90 unsigned char rowFlags;
91 rowFlags = readU8(input, encryption);
92 if ((rowFlags & 0x04) == 0x04)
93 m_isHeaderRow = true;
94 if ((rowFlags & 0x02) == 0x02)
95 {
96 if ((rowFlags & 0x10) == 0x10)
97 m_isMinimumHeight = true;
98 else
99 m_isMinimumHeight = false;
100 m_rowHeight = readU16(input, encryption);
101 }
102 else
103 {
104 m_isMinimumHeight = true;
105 m_rowHeight = 0x0000;
106 }
107 break;
108 case WP6_EOL_GROUP_CELL_FORMULA:
109 unsigned short embeddedSubGroupSize;
110 embeddedSubGroupSize = readU16(input, encryption);
111 WPD_DEBUG_MSG(("WordPerfect: EOL Group Embedded Sub-Function: CELL_FORMULA (length: %ld)\n",
112 (long) embeddedSubGroupSize));
113 numBytesToSkip = embeddedSubGroupSize;
114 break;
115 case WP6_EOL_GROUP_TOP_GUTTER_SPACING:
116 WPD_DEBUG_MSG(("WordPerfect: EOL Group Embedded Sub-Function: TOP_GUTTER_SPACING\n"));
117 numBytesToSkip = WP6_EOL_GROUP_TOP_GUTTER_SPACING_SIZE;
118 break;
119 case WP6_EOL_GROUP_BOTTOM_GUTTER_SPACING:
120 WPD_DEBUG_MSG(("WordPerfect: EOL Group Embedded Sub-Function: BOTTOM_GUTTER_SPACING\n"));
121 numBytesToSkip = WP6_EOL_GROUP_BOTTOM_GUTTER_SPACING_SIZE;
122 break;
123 case WP6_EOL_GROUP_CELL_INFORMATION:
124 WPD_DEBUG_MSG(("WordPerfect: EOL Group Embedded Sub-Function: CELL_INFORMATION\n"));
125 numBytesToSkip = WP6_EOL_GROUP_CELL_INFORMATION_SIZE;
126 unsigned char cellFlag, tmpCellVerticalAlign;
127 unsigned short attributeWord1, attributeWord2;
128 cellFlag = readU8(input, encryption);
129 if ((cellFlag & 0x01) == 0x01)
130 m_useCellAttributes = true;
131 if ((cellFlag & 0x02) == 0x02)
132 m_useCellJustification = true;
133 if ((cellFlag & 0x40) == 0x40)
134 m_ignoreInCalculations = true;
135 if ((cellFlag & 0x80) == 0x80)
136 m_cellIsLocked = true;
137 m_cellJustification = (readU8(input, encryption) & 0x07);
138 tmpCellVerticalAlign = readU8(input, encryption);
139 switch (tmpCellVerticalAlign & 0x03)
140 {
141 case 0x00: // top
142 m_cellVerticalAlign = TOP;
143 break;
144 case 0x01: // center
145 m_cellVerticalAlign = MIDDLE;
146 break;
147 case 0x02: // bottom
148 m_cellVerticalAlign = BOTTOM;
149 break;
150 case 0x03: // full
151 m_cellVerticalAlign = FULL;
152 break;
153 default:
154 break;
155 }
156 attributeWord1 = readU16(input, encryption);
157 attributeWord2 = readU16(input, encryption);
158 m_cellAttributes = (unsigned)(((attributeWord2 & 0x03) << 16) + attributeWord1);
159 break;
160 case WP6_EOL_GROUP_CELL_SPANNING_INFORMATION:
161 WPD_DEBUG_MSG(("WordPerfect: EOL Group Embedded Sub-Function: CELL_SPANNING_INFORMATION\n"));
162 numBytesToSkip = WP6_EOL_GROUP_CELL_SPANNING_INFORMATION_SIZE;
163 m_colSpan = readU8(input, encryption);
164 m_rowSpan = readU8(input, encryption);
165 WPD_DEBUG_MSG(("WordPerfect: num cells spanned (h:%ld, v:%ld)\n",
166 (long) m_colSpan, (long) m_rowSpan));
167 if (m_colSpan >= 128)
168 m_boundFromAbove = true;
169 break;
170 case WP6_EOL_GROUP_CELL_FILL_COLORS:
171 WPD_DEBUG_MSG(("WordPerfect: EOL Group Embedded Sub-Function: CELL_FILL_COLORS\n"));
172 numBytesToSkip = WP6_EOL_GROUP_CELL_FILL_COLORS_SIZE;
173 unsigned char fR, fG, fB, fS;
174 unsigned char bR, bG, bB, bS;
175
176 fR = readU8(input, encryption);
177 fG = readU8(input, encryption);
178 fB = readU8(input, encryption);
179 fS = readU8(input, encryption);
180 bR = readU8(input, encryption);
181 bG = readU8(input, encryption);
182 bB = readU8(input, encryption);
183 bS = readU8(input, encryption);
184
185 m_cellFgColor.reset(new RGBSColor(fR,fG,fB,fS));
186 m_cellBgColor.reset(new RGBSColor(bR,bG,bB,bS));
187 WPD_DEBUG_MSG(("WordPerfect: EOL Group Embedded FG Color (%i, %i, %i, %i) BG Color (%i, %i, %i, %i)\n",
188 m_cellFgColor->m_r, m_cellFgColor->m_g, m_cellFgColor->m_b, m_cellFgColor->m_s,
189 m_cellBgColor->m_r, m_cellBgColor->m_g, m_cellBgColor->m_b, m_cellBgColor->m_s));
190 break;
191 case WP6_EOL_GROUP_CELL_LINE_COLOR:
192 WPD_DEBUG_MSG(("WordPerfect: EOL Group Embedded Sub-Function: CELL_LINE_COLOR\n"));
193 numBytesToSkip = WP6_EOL_GROUP_CELL_LINE_COLOR_SIZE;
194
195 m_cellBorderColor->m_r = readU8(input, encryption);
196 m_cellBorderColor->m_g = readU8(input, encryption);
197 m_cellBorderColor->m_b = readU8(input, encryption);
198 m_cellBorderColor->m_s = readU8(input, encryption);
199
200 WPD_DEBUG_MSG(("WordPerfect: EOL Group Embedded Border Color (%i, %i, %i, %i)\n",
201 m_cellBorderColor->m_r, m_cellBorderColor->m_g, m_cellBorderColor->m_b, m_cellBorderColor->m_s));
202 break;
203 case WP6_EOL_GROUP_CELL_NUMBER_TYPE:
204 WPD_DEBUG_MSG(("WordPerfect: EOL Group Embedded Sub-Function: CELL_NUMBER_TYPE\n"));
205 numBytesToSkip = WP6_EOL_GROUP_CELL_NUMBER_TYPE_SIZE;
206 break;
207 case WP6_EOL_GROUP_CELL_FLOATING_POINT_NUMBER:
208 WPD_DEBUG_MSG(("WordPerfect: EOL Group Embedded Sub-Function: CELL_FLOATING_POINT_NUMBER\n"));
209 numBytesToSkip = WP6_EOL_GROUP_CELL_FLOATING_POINT_NUMBER_SIZE;
210 break;
211 case WP6_EOL_GROUP_CELL_PREFIX_FLAG:
212 WPD_DEBUG_MSG(("WordPerfect: EOL Group Embedded Sub-Function: CELL_PREFIX_FLAG\n"));
213 numBytesToSkip = WP6_EOL_GROUP_CELL_PREFIX_FLAG_SIZE;
214 m_cellBorders = readU8(input, encryption);
215 break;
216 case WP6_EOL_GROUP_CELL_RECALCULATION_ERROR_NUMBER:
217 WPD_DEBUG_MSG(("WordPerfect: EOL Group Embedded Sub-Function: CELL_RECALCULATION_ERROR_NUMBER\n"));
218 numBytesToSkip = WP6_EOL_GROUP_CELL_RECALCULATION_ERROR_NUMBER_SIZE;
219 break;
220 case WP6_EOL_GROUP_DONT_END_A_PARAGRAPH_STYLE_FOR_THIS_HARD_RETURN:
221 WPD_DEBUG_MSG(("WordPerfect: EOL Group Embedded Sub-Function: DONT_END_A_PARAGRAPH_STYLE_FOR_THIS_HARD_RETURN\n"));
222 numBytesToSkip = WP6_EOL_GROUP_DONT_END_A_PARAGRAPH_STYLE_FOR_THIS_HARD_RETURN_SIZE;
223 m_isDontEndAParagraphStyleForThisHardReturn = true;
224 break;
225 case 0x8e:
226 case 0x8f:
227 WPD_DEBUG_MSG(("WordPerfect: EOL Group Embedded Sub-Function: UNKNOWN SUBFUNCTION (%x) (BAD BAD BAD)\n", byte));
228 numBytesToSkip = readU16(input, encryption); // It seems that these two unknow sub-functions have their
229 // length information embedded: <subfunction>[length]...[length]<subfunction>
230 break;
231 default:
232 WPD_DEBUG_MSG(("WordPerfect: EOL Group Embedded Sub-Function: UNKNOWN SUBFUNCTION (%x) (BAD BAD BAD)\n", byte));
233 WPD_DEBUG_MSG(("WordPerfect: Possible corruption detected, bailing out\n"));
234 throw FileException();
235 }
236
237 if (startPosition2 + numBytesToSkip - 1 - input->tell() < 0)
238 throw FileException();
239 input->seek((startPosition2 + numBytesToSkip - 1), librevenge::RVNG_SEEK_SET);
240 }
241 }
242
parse(WP6Listener * listener)243 void WP6EOLGroup::parse(WP6Listener *listener)
244 {
245 WPD_DEBUG_MSG(("WordPerfect: handling an EOL group\n"));
246
247 // first off, grab any prefix information which may be useful
248 const RGBSColor *cellFgColor = m_cellFgColor.get();
249 const RGBSColor *cellBgColor = m_cellBgColor.get();
250 const RGBSColor *cellBorderColor = m_cellBorderColor.get();
251
252 if (!cellFgColor && !cellBgColor)
253 {
254 for (int i=0; i<getNumPrefixIDs(); i++)
255 {
256 if (const auto *fsPacket = dynamic_cast<const WP6FillStylePacket *>(listener->getPrefixDataPacket(getPrefixIDs()[i])))
257 {
258
259 cellFgColor = fsPacket->getFgColor();
260 cellBgColor = fsPacket->getBgColor();
261 }
262 }
263 }
264
265 // main search + dispatch for messages
266 switch (getSubGroup())
267 {
268 case 0: // 0x00 (beginning of file)
269 break; // ignore
270 case WP6_EOL_GROUP_SOFT_EOL:
271 case WP6_EOL_GROUP_SOFT_EOC:
272 case WP6_EOL_GROUP_SOFT_EOC_AT_EOP: // 0x03 (soft EOC at EOP)
273 listener->insertCharacter((unsigned) ' ');
274 break;
275 case WP6_EOL_GROUP_DELETABLE_HARD_EOL: // 0x17 (deletable hard EOL)
276 case WP6_EOL_GROUP_DELETABLE_HARD_EOL_AT_EOC: // 0x18 (deletable hard EOL at EOC)
277 case WP6_EOL_GROUP_DELETABLE_HARD_EOL_AT_EOP: // 0x19 (deletable hard EOL at EOP)
278 case WP6_EOL_GROUP_DELETABLE_HARD_EOP: // deletable hard EOP
279 case WP6_EOL_GROUP_HARD_EOL:
280 case WP6_EOL_GROUP_HARD_EOL_AT_EOC:
281 case WP6_EOL_GROUP_HARD_EOL_AT_EOP:
282 listener->insertEOL();
283 break;
284 case WP6_EOL_GROUP_DELETABLE_SOFT_EOL: // 0x014 (deletable soft EOL)
285 if (m_isDontEndAParagraphStyleForThisHardReturn)
286 listener->handleLineBreak();
287 break;
288 case WP6_EOL_GROUP_HARD_EOC: // 0x07 (hard end of column)
289 case WP6_EOL_GROUP_HARD_EOC_AT_EOP:
290 case WP6_EOL_GROUP_DELETABLE_HARD_EOC:
291 case WP6_EOL_GROUP_DELETABLE_HARD_EOC_AT_EOP:
292 listener->insertBreak(WPX_COLUMN_BREAK);
293 break;
294 case WP6_EOL_GROUP_HARD_EOP: // hard EOP
295 listener->insertBreak(WPX_PAGE_BREAK);
296 break;
297 case WP6_EOL_GROUP_TABLE_CELL: // Table Cell
298 WPD_DEBUG_MSG(("WordPerfect: EOL group: table cell\n"));
299 if (!m_boundFromAbove)
300 {
301 listener->insertCell(m_colSpan, m_rowSpan, m_cellBorders, cellFgColor, cellBgColor,
302 cellBorderColor, m_cellVerticalAlign, m_useCellAttributes, m_cellAttributes);
303 if (m_useCellJustification)
304 listener->justificationChange(m_cellJustification);
305 }
306 break;
307 case WP6_EOL_GROUP_TABLE_ROW_AND_CELL:
308 case WP6_EOL_GROUP_TABLE_ROW_AT_EOC:
309 case WP6_EOL_GROUP_TABLE_ROW_AT_EOP:
310 case WP6_EOL_GROUP_TABLE_ROW_AT_HARD_EOC:
311 case WP6_EOL_GROUP_TABLE_ROW_AT_HARD_EOC_AT_HARD_EOP:
312 case WP6_EOL_GROUP_TABLE_ROW_AT_HARD_EOP:
313 WPD_DEBUG_MSG(("WordPerfect: EOL group: table row and cell\n"));
314
315 listener->insertRow(m_rowHeight, m_isMinimumHeight, m_isHeaderRow);
316 // the cellBorders variable already represent the cell border bits as well
317 if (!m_boundFromAbove)
318 {
319 listener->insertCell(m_colSpan, m_rowSpan, m_cellBorders, cellFgColor, cellBgColor,
320 cellBorderColor, m_cellVerticalAlign, m_useCellAttributes, m_cellAttributes);
321 if (m_useCellJustification)
322 listener->justificationChange(m_cellJustification);
323 }
324 break;
325 case WP6_EOL_GROUP_TABLE_OFF:
326 case WP6_EOL_GROUP_TABLE_OFF_AT_EOC:
327 case WP6_EOL_GROUP_TABLE_OFF_AT_EOC_AT_EOP:
328 listener->endTable();
329 break;
330 // case WP6_EOL_GROUP_DELETABLE_SOFT_EOC: // 0x15 (deletable soft EOC)
331 // case WP6_EOL_GROUP_DELETABLE_SOFT_EOC_AT_EOP: // 0x16 (deleteable soft EOC at EOP)
332 default: // something else we don't support yet
333 break;
334 }
335
336 // search for soft page breaks and dispatch messages to that effect
337 switch (getSubGroup())
338 {
339 case WP6_EOL_GROUP_HARD_EOL_AT_EOP:
340 case WP6_EOL_GROUP_TABLE_ROW_AT_EOP:
341 case WP6_EOL_GROUP_TABLE_ROW_AT_HARD_EOC_AT_HARD_EOP:
342 case WP6_EOL_GROUP_TABLE_ROW_AT_HARD_EOP:
343 case WP6_EOL_GROUP_TABLE_OFF_AT_EOC_AT_EOP:
344 listener->insertBreak(WPX_SOFT_PAGE_BREAK);
345 break;
346 default:
347 break;
348 }
349 }
350 /* vim:set shiftwidth=4 softtabstop=4 noexpandtab: */
351