/src/libmwaw/src/lib/MsWrdStruct.cxx
Line | Count | Source |
1 | | /* -*- Mode: C++; c-default-style: "k&r"; indent-tabs-mode: nil; tab-width: 2; c-basic-offset: 2 -*- */ |
2 | | |
3 | | /* libmwaw |
4 | | * Version: MPL 2.0 / LGPLv2+ |
5 | | * |
6 | | * The contents of this file are subject to the Mozilla Public License Version |
7 | | * 2.0 (the "License"); you may not use this file except in compliance with |
8 | | * the License or as specified alternatively below. You may obtain a copy of |
9 | | * the License at http://www.mozilla.org/MPL/ |
10 | | * |
11 | | * Software distributed under the License is distributed on an "AS IS" basis, |
12 | | * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License |
13 | | * for the specific language governing rights and limitations under the |
14 | | * License. |
15 | | * |
16 | | * Major Contributor(s): |
17 | | * Copyright (C) 2002 William Lachance (wrlach@gmail.com) |
18 | | * Copyright (C) 2002,2004 Marc Maurer (uwog@uwog.net) |
19 | | * Copyright (C) 2004-2006 Fridrich Strba (fridrich.strba@bluewin.ch) |
20 | | * Copyright (C) 2006, 2007 Andrew Ziem |
21 | | * Copyright (C) 2011, 2012 Alonso Laurent (alonso@loria.fr) |
22 | | * |
23 | | * |
24 | | * All Rights Reserved. |
25 | | * |
26 | | * For minor contributions see the git repository. |
27 | | * |
28 | | * Alternatively, the contents of this file may be used under the terms of |
29 | | * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"), |
30 | | * in which case the provisions of the LGPLv2+ are applicable |
31 | | * instead of those above. |
32 | | */ |
33 | | |
34 | | #include "MWAWDebug.hxx" |
35 | | #include "MWAWFontConverter.hxx" |
36 | | #include "MWAWInputStream.hxx" |
37 | | #include "MWAWSection.hxx" |
38 | | |
39 | | #include "MsWrdStruct.hxx" |
40 | | |
41 | | namespace MsWrdStruct |
42 | | { |
43 | | // ------ font ------------- |
44 | | std::ostream &operator<<(std::ostream &o, Font const &font) |
45 | 0 | { |
46 | 0 | char const *what[Font::NumFlags]= { |
47 | 0 | "b", "it", "strikeout", "outline", "shadow", "smallCaps", "allCaps", |
48 | 0 | "hidden", "underline" |
49 | 0 | }; |
50 | 0 | for (int i=0; i < Font::NumFlags; i++) { |
51 | 0 | if (!font.m_flags[i].isSet()) continue; |
52 | 0 | o << what[i]; |
53 | 0 | switch (font.m_flags[i].get()) { |
54 | 0 | case 0x80: |
55 | 0 | o << "=noStyle"; |
56 | 0 | break; |
57 | 0 | case 0: |
58 | 0 | o << "=no"; |
59 | 0 | break; |
60 | 0 | case 0x81: |
61 | 0 | o << "=style"; |
62 | 0 | break; |
63 | 0 | case 1: |
64 | 0 | break; |
65 | 0 | default: |
66 | 0 | o << "=" << std::hex << font.m_flags[i].get() << std::dec << ","; |
67 | 0 | } |
68 | 0 | o << ","; |
69 | 0 | } |
70 | 0 | if (font.m_picturePos.get()) |
71 | 0 | o << "pict=" << std::hex << font.m_picturePos.get() << std::dec << ","; |
72 | 0 | if (font.m_unknown.get()) |
73 | 0 | o << "ft=" << std::hex << font.m_unknown.get() << std::dec << ","; |
74 | 0 | if (font.m_size.isSet() && (font.m_size.get() < font.m_font->size() || |
75 | 0 | font.m_size.get() > font.m_font->size())) |
76 | 0 | o << "#size2=" << font.m_size.get() << ","; |
77 | 0 | if (font.m_value.isSet()) o << "id?=" << font.m_value.get() << ","; |
78 | 0 | if (font.m_extra.length()) |
79 | 0 | o << font.m_extra << ","; |
80 | 0 | return o; |
81 | 0 | } |
82 | | |
83 | | void Font::insert(Font const &font, Font const *styleFont) |
84 | 2.35M | { |
85 | 2.35M | updateFontToFinalState(styleFont); |
86 | 2.35M | if (!m_font.isSet()) |
87 | 1.35M | m_font=font.m_font; |
88 | 992k | else if (font.m_font.isSet()) |
89 | 133k | m_font->insert(font.m_font.get()); |
90 | 2.35M | m_size.insert(font.m_size); |
91 | 2.35M | m_value.insert(font.m_value); |
92 | 2.35M | m_picturePos.insert(font.m_picturePos); |
93 | 2.35M | m_unknown.insert(font.m_unknown); |
94 | 23.5M | for (int i = 0; i < NumFlags; i++) |
95 | 21.1M | m_flags[i] = font.m_flags[i]; |
96 | 2.35M | m_extra+=font.m_extra; |
97 | 2.35M | } |
98 | | |
99 | | void Font::updateFontToFinalState(Font const *styleFont) |
100 | 3.06M | { |
101 | 3.06M | uint32_t res=0; |
102 | 3.06M | uint32_t const fl[NumFlags] = { |
103 | 3.06M | MWAWFont::boldBit, MWAWFont::italicBit, 0, MWAWFont::outlineBit, |
104 | 3.06M | MWAWFont::shadowBit, MWAWFont::smallCapsBit, MWAWFont::uppercaseBit, MWAWFont::hiddenBit, 0 |
105 | 3.06M | }; |
106 | 3.06M | if (m_font.isSet()) res = m_font->flags(); |
107 | 3.06M | bool flagsMod = false; |
108 | 30.6M | for (int i=0; i < NumFlags; i++) { |
109 | 27.5M | if (!m_flags[i].isSet()) continue; |
110 | 78.7k | int action = m_flags[i].get(); |
111 | 78.7k | if (action&0xFF7E) continue; |
112 | 54.0k | bool on = (action&1); |
113 | 54.0k | if ((action&0x80) && styleFont) { |
114 | 17.5k | bool prev=false; |
115 | 17.5k | if (i==2) |
116 | 1.12k | prev = styleFont->m_font->getStrikeOut().isSet(); |
117 | 16.3k | else if (i==8) |
118 | 3.53k | prev = styleFont->m_font->getUnderline().isSet(); |
119 | 12.8k | else |
120 | 12.8k | prev = styleFont->m_font->flags()&fl[i]; |
121 | 17.5k | if (action==0x81) |
122 | 13.3k | on = prev; |
123 | 4.13k | else |
124 | 4.13k | on = !prev; |
125 | 17.5k | } |
126 | 54.0k | switch (i) { |
127 | 15.4k | case 2: |
128 | 15.4k | if (on) |
129 | 1.16k | m_font->setStrikeOutStyle(MWAWFont::Line::Simple); |
130 | 14.2k | else |
131 | 14.2k | m_font->setStrikeOutStyle(MWAWFont::Line::None); |
132 | 15.4k | break; |
133 | 12.2k | case 8: |
134 | 12.2k | if (on) |
135 | 5.20k | m_font->setUnderlineStyle(MWAWFont::Line::Simple); |
136 | 7.05k | else |
137 | 7.05k | m_font->setUnderlineStyle(MWAWFont::Line::None); |
138 | 12.2k | break; |
139 | 26.3k | default: |
140 | 26.3k | if (on) res|=fl[i]; |
141 | 15.3k | else res &= ~(fl[i]); |
142 | 26.3k | flagsMod=true; |
143 | 26.3k | break; |
144 | 54.0k | } |
145 | 54.0k | } |
146 | 3.06M | if (flagsMod) |
147 | 26.3k | m_font->setFlags(res); |
148 | 3.06M | } |
149 | | |
150 | | // ------ section ------------- |
151 | | MWAWSection Section::getSection(double pageWidth) const |
152 | 54.6k | { |
153 | 54.6k | MWAWSection sec; |
154 | 54.6k | int numCols = *m_col; |
155 | 54.6k | if (numCols <= 1) |
156 | 54.2k | return sec; |
157 | 405 | MWAWSection::Column col; |
158 | 405 | col.m_width=pageWidth/double(numCols); |
159 | 405 | col.m_widthUnit=librevenge::RVNG_INCH; |
160 | 405 | col.m_margins[libmwaw::Left] = col.m_margins[libmwaw::Right] = double(*m_colSep)/2.; |
161 | 405 | sec.m_columns.resize(size_t(numCols), col); |
162 | 405 | sec.m_columns[0].m_margins[libmwaw::Left] = 0; |
163 | 405 | sec.m_columns[size_t(numCols-1)].m_margins[libmwaw::Right] = 0; |
164 | 405 | sec.m_balanceText = true; |
165 | 405 | return sec; |
166 | 54.6k | } |
167 | | |
168 | | bool Section::read(MWAWInputStreamPtr &input, long endPos) |
169 | 9.28M | { |
170 | 9.28M | long pos = input->tell(); |
171 | 9.28M | long dSz = endPos-pos; |
172 | 9.28M | if (dSz < 1) return false; |
173 | 9.28M | libmwaw::DebugStream f; |
174 | 9.28M | int c = static_cast<int>(input->readULong(1)), val; |
175 | 9.28M | switch (c) { |
176 | 126k | case 0x75: // column break |
177 | 126k | if (dSz < 2) return false; |
178 | 125k | val = static_cast<int>(input->readLong(1)); |
179 | 125k | switch (val) { |
180 | 3.65k | case 0: |
181 | 3.65k | m_colBreak = false; |
182 | 3.65k | return true; |
183 | 661 | case 1: |
184 | 661 | m_colBreak = true; |
185 | 661 | return true; |
186 | 120k | default: |
187 | 120k | f << "#f75=" << val << ","; |
188 | 120k | break; |
189 | 125k | } |
190 | 120k | break; |
191 | 120k | case 0x77: // num column |
192 | 47.6k | if (dSz<3) return false; |
193 | 45.1k | m_col = static_cast<int>(input->readLong(2))+1; |
194 | 45.1k | return true; |
195 | 58.0k | case 0x78: |
196 | 58.0k | if (dSz<3) return false; |
197 | 56.4k | m_colSep = float(input->readULong(2))/1440.f; |
198 | 56.4k | return true; |
199 | | // FIXME: UNKNOWN |
200 | 18.7k | case 0x80: // a small number: 0, 8, 10 |
201 | 61.6k | case 0x76: // always 1 ? |
202 | 88.6k | case 0x79: |
203 | 101k | case 0x7d: // always 1 |
204 | 115k | case 0x7e: // always 0 |
205 | 115k | if (dSz<2) return false; |
206 | 112k | f << "f" << std::hex << c << std::dec << "=" << input->readLong(1) << ","; |
207 | 112k | break; |
208 | 20.0k | case 0x7b: // 2e1 3d08 |
209 | 189k | case 0x7c: // 4da, 6a5, 15ff |
210 | 189k | if (dSz<3) return false; |
211 | 184k | f << "f" << std::hex << c << std::dec << "="; |
212 | 184k | f << std::hex << input->readULong(1) << std::dec << ":"; |
213 | 184k | f << std::hex << input->readULong(1) << std::dec << ","; |
214 | 184k | break; |
215 | 127k | case 0x82: // find one time with 168 (related to 7e ?) |
216 | 127k | if (dSz<3) return false; |
217 | 119k | f << "f" << std::hex << c << std::dec << "=" << input->readLong(2) << ","; |
218 | 119k | break; |
219 | 102k | case 0x83: |
220 | 110k | case 0x84: |
221 | 110k | if (dSz < 3) return false; |
222 | 108k | val = static_cast<int>(input->readLong(2)); |
223 | 108k | if (c == 0x83) f << "header[top]=" << val/1440. << ","; |
224 | 8.23k | else f << "header[bottom]=" << val/1440. << ","; |
225 | 108k | break; |
226 | 8.51M | default: |
227 | 8.51M | return false; |
228 | 9.28M | } |
229 | 647k | m_extra += f.str(); |
230 | 647k | return true; |
231 | 9.28M | } |
232 | | |
233 | | // data seems very different in v3, so a new function.... |
234 | | bool Section::readV3(MWAWInputStreamPtr &input, long endPos) |
235 | 3.02M | { |
236 | 3.02M | long pos = input->tell(); |
237 | 3.02M | long dSz = endPos-pos; |
238 | 3.02M | if (dSz < 1) return false; |
239 | 3.02M | libmwaw::DebugStream f; |
240 | 3.02M | int wh = static_cast<int>(input->readULong(1)), val; |
241 | 3.02M | switch (wh) { |
242 | 80.4k | case 0x36: |
243 | 80.4k | if (dSz < 2) return false; |
244 | 77.4k | val = static_cast<int>(input->readLong(1)); |
245 | 77.4k | switch (val) { |
246 | 327 | case 0: |
247 | 327 | f << "division=no,"; |
248 | 327 | break; |
249 | 66 | case 1: |
250 | 66 | f << "division=columns,"; |
251 | 66 | break; |
252 | 27 | case 2: |
253 | 27 | f << "division=page,"; |
254 | 27 | break; // default |
255 | 119 | case 3: |
256 | 119 | f << "division=evenpage,"; |
257 | 119 | break; |
258 | 0 | case 4: |
259 | 0 | f << "division=oddpage,"; |
260 | 0 | break; |
261 | 76.9k | default: |
262 | 76.9k | f << "#division=" << val << ","; |
263 | 76.9k | break; |
264 | 77.4k | } |
265 | 77.4k | break; |
266 | 77.4k | case 0x37: |
267 | 25.1k | if (dSz < 2) return false; |
268 | 21.8k | val = static_cast<int>(input->readLong(1)); |
269 | 21.8k | switch (val) { |
270 | 146 | case 0: |
271 | 146 | break; // no front page |
272 | 95 | case 1: |
273 | 95 | f << "frontPage,"; |
274 | 95 | break; |
275 | 21.6k | default: |
276 | 21.6k | f << "#frontPage=" << val << ","; |
277 | 21.6k | break; |
278 | 21.8k | } |
279 | 21.8k | break; |
280 | 48.5k | case 0x3a: |
281 | 48.5k | if (dSz < 2) return false; |
282 | 46.9k | val = static_cast<int>(input->readLong(1)); |
283 | 46.9k | switch (val) { |
284 | 148 | case 1: |
285 | 148 | f << "addNumbering,"; |
286 | 148 | break; |
287 | 46.8k | default: |
288 | 46.8k | f << "#addNumbering=" << val << ","; |
289 | 46.8k | break; |
290 | 46.9k | } |
291 | 46.9k | break; |
292 | 46.9k | case 0x3b: |
293 | 36.0k | if (dSz < 2) return false; |
294 | 34.3k | val = static_cast<int>(input->readLong(1)); |
295 | 34.3k | switch (val) { |
296 | 1.62k | case 1: |
297 | 1.62k | f << "numbering=arabic,"; |
298 | 1.62k | break; // normal |
299 | 242 | case 2: |
300 | 242 | f << "numbering=roman[upper],"; |
301 | 242 | break; |
302 | 37 | case 3: |
303 | 37 | f << "numbering=alpha[upper],"; |
304 | 37 | break; |
305 | 21 | case 4: |
306 | 21 | f << "numbering=alpha[lower],"; |
307 | 21 | break; |
308 | 93 | case 5: |
309 | 93 | f << "numbering=roman[lower],"; |
310 | 93 | break; |
311 | 32.3k | default: |
312 | 32.3k | f << "#numbering[type]=" << val << ","; |
313 | 32.3k | break; |
314 | 34.3k | } |
315 | 34.3k | break; |
316 | 34.3k | case 0x3e: |
317 | 22.2k | if (dSz < 2) return false; |
318 | 20.4k | val = static_cast<int>(input->readLong(1)); |
319 | 20.4k | switch (val) { |
320 | 33 | case 1: |
321 | 33 | f << "newNumber=byPage,"; |
322 | 33 | break; |
323 | 20.3k | default: |
324 | 20.3k | f << "#newNumber=" << val << ","; |
325 | 20.3k | break; |
326 | 20.4k | } |
327 | 20.4k | break; |
328 | 31.0k | case 0x3f: |
329 | 31.0k | if (dSz < 2) return false; |
330 | 29.3k | val = static_cast<int>(input->readLong(1)); |
331 | 29.3k | switch (val) { |
332 | 134 | case 0: |
333 | 134 | f << "footnote,"; |
334 | 134 | break; |
335 | 204 | case 1: |
336 | 204 | f << "endnote,"; |
337 | 204 | break; // default |
338 | 29.0k | default: |
339 | 29.0k | f << "#endnote=" << val << ","; |
340 | 29.0k | break; |
341 | 29.3k | } |
342 | 29.3k | break; |
343 | 97.9k | case 0x40: |
344 | 97.9k | if (dSz < 2) return false; |
345 | 96.1k | val = static_cast<int>(input->readLong(1)); |
346 | 96.1k | switch (val) { |
347 | 1.11k | case 1: |
348 | 1.11k | f << "numberline=byDivision,"; |
349 | 1.11k | break; |
350 | 172 | case 2: |
351 | 172 | f << "numberline=consecutive,"; |
352 | 172 | break; |
353 | 94.8k | default: |
354 | 94.8k | f << "#numberline=" << val << ","; |
355 | 94.8k | break; |
356 | 96.1k | } |
357 | 96.1k | break; |
358 | 96.1k | case 0x41: // 8 or a |
359 | 51.0k | if (dSz < 2) return false; |
360 | 49.3k | val = static_cast<int>(input->readLong(1)); |
361 | 49.3k | f << "f41=" << std::hex << val << std::dec << ","; |
362 | 49.3k | break; |
363 | 30.6k | case 0x38: |
364 | 43.5k | case 0x39: |
365 | 52.4k | case 0x3c: |
366 | 71.4k | case 0x3d: |
367 | 101k | case 0x42: |
368 | 127k | case 0x43: // find 0x168 |
369 | 143k | case 0x44: |
370 | 166k | case 0x45: |
371 | 166k | if (dSz < 3) return false; |
372 | 148k | val = static_cast<int>(input->readLong(2)); |
373 | 148k | switch (wh) { |
374 | 27.5k | case 0x38: |
375 | 27.5k | m_col = static_cast<int>(val)+1; |
376 | 27.5k | break; |
377 | 28.1k | case 0x42: |
378 | 28.1k | f << "numberline[lines]=" << val << ","; |
379 | 28.1k | break; |
380 | 11.4k | case 0x39: |
381 | 11.4k | m_colSep = float(val)/1440.f; |
382 | 11.4k | break; |
383 | 7.98k | case 0x3c: |
384 | 7.98k | f << "numberingPos[T]=" << val/1440.0 << ","; |
385 | 7.98k | break; |
386 | 17.6k | case 0x3d: |
387 | 17.6k | f << "numberingPos[R]=" << val/1440.0 << ","; |
388 | 17.6k | break; |
389 | 12.3k | case 0x44: |
390 | 12.3k | f << "headerSize=" << val/1440.0 << ","; |
391 | 12.3k | break; |
392 | 19.6k | case 0x45: |
393 | 19.6k | f << "footerSize=" << val/1440.0 << ","; |
394 | 19.6k | break; |
395 | 24.0k | default: |
396 | 24.0k | f << "f" << std::hex << wh << std::dec << "=" << val << ","; |
397 | 24.0k | break; |
398 | 148k | } |
399 | 148k | break; |
400 | 2.46M | default: |
401 | 2.46M | return false; |
402 | 3.02M | } |
403 | 524k | m_extra += f.str(); |
404 | 524k | return true; |
405 | 3.02M | } |
406 | | |
407 | | std::ostream &operator<<(std::ostream &o, Section const §ion) |
408 | 0 | { |
409 | 0 | if (section.m_type.get()) // 0|0x40|0x80|0xc0 |
410 | 0 | o << "type=" << std::hex << section.m_type.get() << std::dec << ","; |
411 | 0 | if (section.m_paragraphId.isSet() && section.m_paragraphId.get() > -9999) |
412 | 0 | o << "sP=" << section.m_paragraphId.get() << ","; |
413 | 0 | if (section.m_col.isSet() && section.m_col.get() != 1) |
414 | 0 | o << "cols=" << section.m_col.get() << ","; |
415 | 0 | if (section.m_colSep.isSet()) |
416 | 0 | o << "colSep=" << section.m_colSep.get() << "in,"; |
417 | 0 | if (section.m_colBreak.get()) o << "colBreak,"; |
418 | 0 | if (section.m_flag.get()) |
419 | 0 | o << "fl=" << std::hex << section.m_flag.get() << std::dec << ","; |
420 | 0 | if (section.m_extra.length()) o << section.m_extra << ","; |
421 | 0 | return o; |
422 | 0 | } |
423 | | |
424 | | // table |
425 | | MWAWVariable<Table::Cell> &Table::getCell(int id) |
426 | 700k | { |
427 | 700k | if (id < 0) { |
428 | 0 | MWAW_DEBUG_MSG(("MsWrdStruct::Table::getCell: can not return a negative cell id\n")); |
429 | 0 | return m_badCell; |
430 | 0 | } |
431 | 700k | if (m_cells.size() <= size_t(id)) m_cells.resize(size_t(id)+1); |
432 | 700k | return m_cells[size_t(id)]; |
433 | 700k | } |
434 | | |
435 | | bool Table::read(MWAWInputStreamPtr &input, long endPos) |
436 | 10.1M | { |
437 | 10.1M | long pos = input->tell(); |
438 | 10.1M | long dSz = endPos-pos; |
439 | 10.1M | if (dSz < 1) return false; |
440 | 10.1M | libmwaw::DebugStream f, f2; |
441 | 10.1M | int c = static_cast<int>(input->readULong(1)), val; |
442 | 10.1M | switch (c) { |
443 | 30.6k | case 0x98: { // tabs columns |
444 | 30.6k | auto sz = static_cast<int>(input->readULong(2)); |
445 | 30.6k | if (!sz || dSz < 2+sz) return false; |
446 | 17.9k | auto N = static_cast<int>(input->readULong(1)); |
447 | 17.9k | if (1+(N+1)*2 > sz) { |
448 | 902 | MWAW_DEBUG_MSG(("MsWrdStruct::Table::read: table definition seems odd\n")); |
449 | 902 | f << "#colDef"; |
450 | 902 | input->seek(pos+2+sz, librevenge::RVNG_SEEK_SET); |
451 | 902 | break; |
452 | 902 | } |
453 | 84.8k | for (int i=0; i <= N; i++) |
454 | 67.8k | m_columns->push_back(float(input->readLong(2))/20.0f); |
455 | 17.0k | int N1 = (sz-(N+1)*2-2); |
456 | 43.0k | for (int i=0; i < (N1+8)/10; i++) { |
457 | 26.0k | Cell cell; |
458 | 26.0k | int numElt= (N1-10*i)/2; |
459 | 26.0k | if (numElt>5) numElt=5; |
460 | 26.0k | f2.str(""); |
461 | 26.0k | val = static_cast<int>(input->readULong(2)); |
462 | 26.0k | switch (val) { |
463 | 14.0k | case 0: |
464 | 14.0k | break; |
465 | 48 | case 0x4000: |
466 | 48 | f2 << "empty,"; |
467 | 48 | break; |
468 | 81 | case 0x8000: |
469 | 81 | f2 << "merge,"; |
470 | 81 | break; |
471 | 11.8k | default: |
472 | 11.8k | f2 << "#type=" << std::hex << val << std::dec << ","; |
473 | 26.0k | } |
474 | 26.0k | if (numElt > 0) { |
475 | 26.0k | cell.m_borders.resize(size_t(numElt)-1); |
476 | 108k | for (int b = 0; b < numElt-1; b++) { |
477 | 82.2k | std::string bExtra; |
478 | 82.2k | cell.m_borders[size_t(b)] = getBorder(static_cast<int>(input->readULong(2)), bExtra); |
479 | 82.2k | if (bExtra.length()) |
480 | 0 | f2 << "#bord" << b << "=" << bExtra << ","; |
481 | 82.2k | } |
482 | 26.0k | } |
483 | 26.0k | cell.m_extra = f2.str(); |
484 | 26.0k | m_cells.push_back(MWAWVariable<Cell>(cell)); |
485 | 26.0k | m_cells.back().setSet(true); |
486 | 26.0k | } |
487 | 17.0k | input->seek(pos+2+sz, librevenge::RVNG_SEEK_SET); |
488 | 17.0k | return true; |
489 | 17.0k | } |
490 | 67.7k | case 0x92: // table alignment |
491 | 67.7k | if (dSz < 3) return false; |
492 | 66.2k | val = static_cast<int>(input->readULong(2)); |
493 | 66.2k | switch (val&3) { |
494 | 7.42k | case 0: |
495 | 7.42k | m_justify = MWAWParagraph::JustificationLeft; |
496 | 7.42k | break; |
497 | 2.23k | case 1: |
498 | 2.23k | m_justify = MWAWParagraph::JustificationCenter; |
499 | 2.23k | break; |
500 | 55.2k | case 2: |
501 | 55.2k | m_justify = MWAWParagraph::JustificationRight; |
502 | 55.2k | break; |
503 | 1.28k | case 3: |
504 | 1.28k | m_justify = MWAWParagraph::JustificationFull; |
505 | 1.28k | break; |
506 | 0 | default: |
507 | 0 | break; |
508 | 66.2k | } |
509 | 66.2k | if (val&0xFFFC) f << "#align=" << std::hex << (val&0xFFFC) << std::dec << ","; |
510 | 66.2k | break; |
511 | 16.3k | case 0x93: // table alignment indent |
512 | 16.3k | if (dSz < 3) return false; |
513 | 15.8k | m_indent = float(input->readLong(2))/1440.f; |
514 | 15.8k | return true; |
515 | 21.8k | case 0x99: // table height DWIPP |
516 | 21.8k | if (dSz < 3) return false; |
517 | 15.0k | m_height = float(input->readLong(2))/1440.f; |
518 | 15.0k | return true; |
519 | 29.3k | case 0x9a: { // the table shading |
520 | 29.3k | if (dSz < 2) return false; |
521 | 27.4k | auto sz = static_cast<int>(input->readULong(1)); |
522 | 27.4k | if (2+sz > dSz || (sz%2)) return false; |
523 | 116k | for (int i = 0; i < sz/2; i++) { |
524 | 108k | float backColor=1.f-float(input->readULong(2))/10000.f; |
525 | 108k | getCell(i)->m_backColor = backColor; |
526 | 108k | } |
527 | 8.16k | break; |
528 | 27.4k | } |
529 | 770k | case 0x9d: { // table cell shading |
530 | 770k | if (dSz < 6) return false; |
531 | 756k | val = static_cast<int>(input->readLong(1)); // a small number often 4 |
532 | 756k | if (val!=4) f << "backColor[unkn?]=" << val << ","; |
533 | 756k | auto firstCol = static_cast<int>(input->readLong(1)); |
534 | 756k | auto lastCol = static_cast<int>(input->readLong(1)); |
535 | 756k | if (firstCol < 0 || lastCol < 0 || firstCol+1 > lastCol) { |
536 | 746k | input->seek(2, librevenge::RVNG_SEEK_CUR); |
537 | 746k | MWAW_DEBUG_MSG(("MsWrdStruct::Table::read: pb for background range\n")); |
538 | 746k | f << "###backRange=" << firstCol << "<->" << lastCol-1 << ","; |
539 | 746k | break; |
540 | 746k | } |
541 | 9.83k | float backColor = 1.f-float(input->readULong(2))/10000.f; |
542 | 186k | for (int i = firstCol; i < lastCol; i++) |
543 | 177k | getCell(i)->m_backColor = backColor; |
544 | 9.83k | break; |
545 | 756k | } |
546 | 41.4k | case 0xa0: { // table dimension modifier |
547 | 41.4k | if (dSz < 5) return false; |
548 | 33.4k | auto firstCol = static_cast<int>(input->readULong(1)); |
549 | 33.4k | auto lastCol = static_cast<int>(input->readULong(1)); |
550 | 33.4k | float dim=float(input->readLong(2))/20.0f; |
551 | 33.4k | f << "col[widthMod" << firstCol << "<->" << lastCol-1 << "]=" << dim<< ","; |
552 | 33.4k | if (m_columnsWidthMod->size()<=size_t(firstCol)) |
553 | 23.7k | m_columnsWidthMod->resize(size_t(firstCol)+1, -1); |
554 | 33.4k | (*m_columnsWidthMod)[size_t(firstCol)]=dim; |
555 | 33.4k | break; |
556 | 41.4k | } |
557 | 45.2k | case 0xa3: { |
558 | 45.2k | if (dSz < 6) return false; |
559 | | // range 0: means A1 |
560 | 39.7k | auto firstCol = static_cast<int>(input->readLong(1)); |
561 | 39.7k | auto lastCol = static_cast<int>(input->readLong(1)); |
562 | 39.7k | if (firstCol < 0 || lastCol < 0 || firstCol+1 > lastCol) { |
563 | 19.4k | input->seek(3, librevenge::RVNG_SEEK_CUR); |
564 | 19.4k | MWAW_DEBUG_MSG(("MsWrdStruct::Table::read: pb for mod color\n")); |
565 | 19.4k | f << "###backRange=" << firstCol << "<->" << lastCol-1 << ","; |
566 | 19.4k | break; |
567 | 19.4k | } |
568 | 20.3k | val = int(input->readULong(1)); |
569 | 20.3k | size_t maxVal = 0; |
570 | 20.3k | if (val & 1) maxVal = 1; |
571 | 20.3k | if (val & 2) maxVal = 2; |
572 | 20.3k | if (val & 4) maxVal = 3; |
573 | 20.3k | if (val & 8) maxVal = 4; |
574 | 20.3k | if (val&0xF0) f << "borderMod[wh=#" << std::hex << int(val&0xF0) << std::dec << "],"; |
575 | 20.3k | std::string bExtra; |
576 | 20.3k | MWAWBorder border = getBorder(static_cast<int>(input->readULong(2)), bExtra); |
577 | 435k | for (int i = firstCol; i < lastCol; i++) { |
578 | 415k | MWAWVariable<Cell> &cell = getCell(i); |
579 | 415k | if (cell->m_borders.size() < maxVal) |
580 | 357k | cell->m_borders.resize(maxVal); |
581 | 415k | if (val&1) cell->m_borders[0] = border; |
582 | 415k | if (val&2) cell->m_borders[1] = border; |
583 | 415k | if (val&4) cell->m_borders[2] = border; |
584 | 415k | if (val&8) cell->m_borders[3] = border; |
585 | 415k | } |
586 | 20.3k | if (bExtra.length()) f << "borderMod=" << bExtra << ","; |
587 | 20.3k | break; |
588 | 39.7k | } |
589 | 9.10M | default: |
590 | 9.10M | return false; |
591 | 10.1M | } |
592 | 904k | m_extra += f.str(); |
593 | 904k | return true; |
594 | 10.1M | } |
595 | | |
596 | | void Table::insert(Table const &table) |
597 | 8.59k | { |
598 | 8.59k | m_height.insert(table.m_height); |
599 | 8.59k | m_justify.insert(table.m_justify); |
600 | 8.59k | m_indent.insert(table.m_indent); |
601 | 8.59k | m_columns.insert(table.m_columns); |
602 | 8.59k | if (table.m_columnsWidthMod.isSet() && !m_columns->empty() |
603 | 0 | && !table.m_columnsWidthMod->empty()) { |
604 | 0 | size_t numCols=m_columns->size(); |
605 | 0 | std::vector<float> colWidth(numCols-1,0); |
606 | 0 | for (size_t c=0; c+1<numCols; ++c) |
607 | 0 | colWidth[c]=(*m_columns)[c+1]-(*m_columns)[c]; |
608 | 0 | for (size_t c=0; c<table.m_columnsWidthMod->size(); ++c) { |
609 | 0 | if (c+1 >= numCols) break; |
610 | 0 | if (table.m_columnsWidthMod.get()[c]<0) continue; |
611 | 0 | colWidth[c]=table.m_columnsWidthMod.get()[c]; |
612 | 0 | } |
613 | 0 | for (size_t c=0; c+1<numCols; ++c) |
614 | 0 | (*m_columns)[c+1]=colWidth[c]+(*m_columns)[c]; |
615 | 0 | } |
616 | 8.59k | size_t tNumCells = table.m_cells.size(); |
617 | 8.59k | if (tNumCells > m_cells.size()) |
618 | 1 | m_cells.resize(tNumCells, MWAWVariable<Cell>()); |
619 | 27.3k | for (size_t i=0; i < tNumCells; i++) { |
620 | 18.7k | if (!m_cells[i].isSet()) |
621 | 4 | m_cells[i] = table.m_cells[i]; |
622 | 18.7k | else if (table.m_cells[i].isSet()) |
623 | 18.7k | m_cells[i]->insert(*table.m_cells[i]); |
624 | 18.7k | } |
625 | 8.59k | m_extra+=table.m_extra; |
626 | 8.59k | } |
627 | | |
628 | | std::ostream &operator<<(std::ostream &o, Table::Cell const &cell) |
629 | 0 | { |
630 | 0 | if (cell.hasBorders()) { |
631 | 0 | o << "borders=["; |
632 | 0 | char const *wh[] = { "T", "L", "B", "R" }; |
633 | 0 | for (size_t i = 0; i < cell.m_borders.size() ; i++) { |
634 | 0 | if (!cell.m_borders[i].isSet()) continue; |
635 | 0 | if (i < 4) o << wh[i]; |
636 | 0 | else o << "#" << i; |
637 | 0 | o << "=" << cell.m_borders[i].get() << ","; |
638 | 0 | } |
639 | 0 | o << "],"; |
640 | 0 | } |
641 | 0 | if (cell.m_backColor.isSet()) o << "backColor=" << cell.m_backColor.get() << ","; |
642 | 0 | if (cell.m_extra.length()) o << cell.m_extra; |
643 | 0 | return o; |
644 | 0 | } |
645 | | |
646 | | std::ostream &operator<<(std::ostream &o, Table const &table) |
647 | 0 | { |
648 | 0 | if (table.m_height.isSet()) { // 0 means automatic |
649 | 0 | if (table.m_height.get() > 0) |
650 | 0 | o << "height[row]=" << table.m_height.get() << "[atLeast],"; |
651 | 0 | else if (table.m_height.get() < 0) |
652 | 0 | o << "height[row]=" << table.m_height.get() << ","; |
653 | 0 | } |
654 | 0 | if (table.m_justify.isSet()) { |
655 | 0 | switch (table.m_justify.get()) { |
656 | 0 | case MWAWParagraph::JustificationLeft: |
657 | 0 | o << "just=left,"; |
658 | 0 | break; |
659 | 0 | case MWAWParagraph::JustificationCenter: |
660 | 0 | o << "just=centered, "; |
661 | 0 | break; |
662 | 0 | case MWAWParagraph::JustificationRight: |
663 | 0 | o << "just=right, "; |
664 | 0 | break; |
665 | 0 | case MWAWParagraph::JustificationFull: |
666 | 0 | o << "just=full, "; |
667 | 0 | break; |
668 | 0 | case MWAWParagraph::JustificationFullAllLines: |
669 | 0 | o << "just=fullAllLines, "; |
670 | 0 | break; |
671 | | #if !defined(__clang__) |
672 | | default: |
673 | | o << "just=" << table.m_justify.get() << ", "; |
674 | | break; |
675 | | #endif |
676 | 0 | } |
677 | 0 | } |
678 | 0 | if (table.m_indent.isSet()) o << "indent=" << table.m_indent.get() << ","; |
679 | 0 | if (table.m_columns.isSet() && table.m_columns->size()) { |
680 | 0 | o << "cols=["; |
681 | 0 | for (auto const &col : table.m_columns.get()) |
682 | 0 | o << col << ","; |
683 | 0 | o << "],"; |
684 | 0 | } |
685 | 0 | if (table.m_columnsWidthMod.isSet() && table.m_columnsWidthMod->size()) { |
686 | 0 | for (size_t i = 0; i < table.m_columnsWidthMod->size(); i++) { |
687 | 0 | if (table.m_columnsWidthMod.get()[i] >= 0) |
688 | 0 | o << "col" << i << "[width]=" << (*table.m_columnsWidthMod)[i] << ","; |
689 | 0 | } |
690 | 0 | } |
691 | 0 | if (table.m_cells.size()) { |
692 | 0 | o << "cells=["; |
693 | 0 | for (auto const &cell : table.m_cells) |
694 | 0 | o << "[" << cell.get() << "],"; |
695 | 0 | o << "],"; |
696 | 0 | } |
697 | 0 | if (table.m_extra.length()) o << table.m_extra; |
698 | 0 | return o; |
699 | 0 | } |
700 | | |
701 | | // paragraph info |
702 | | bool ParagraphInfo::read(MWAWInputStreamPtr &input, long endPos, int vers) |
703 | 1.99M | { |
704 | 1.99M | long pos = input->tell(); |
705 | 1.99M | if ((vers <= 3 && endPos < pos+2) || (vers > 3 && endPos < pos+6)) { |
706 | 0 | MWAW_DEBUG_MSG(("ParagraphInfo::read: zone is too short\n")); |
707 | 0 | return false; |
708 | 0 | } |
709 | 1.99M | m_type = static_cast<int>(input->readULong(1)); // 0, 20(then ff), 40, 60(then ff) |
710 | 1.99M | m_numLines = static_cast<int>(input->readLong(1)); |
711 | 1.99M | if (vers <= 3) |
712 | 0 | return true; |
713 | 1.99M | m_dim->setX(float(input->readULong(2))/1440.f); |
714 | 1.99M | m_dim->setY(float(input->readLong(2))/72.f); |
715 | 1.99M | return true; |
716 | 1.99M | } |
717 | | void ParagraphInfo::insert(ParagraphInfo const &pInfo) |
718 | 0 | { |
719 | 0 | m_type.insert(pInfo.m_type); |
720 | 0 | m_dim.insert(pInfo.m_dim); |
721 | 0 | m_numLines.insert(pInfo.m_numLines); |
722 | 0 | m_error += pInfo.m_error; |
723 | 0 | } |
724 | | |
725 | | // paragraph |
726 | | Paragraph::~Paragraph() |
727 | 129M | { |
728 | 129M | } |
729 | | |
730 | | bool Paragraph::read(MWAWInputStreamPtr &input, long endPos) |
731 | 10.7M | { |
732 | 10.7M | long pos = input->tell(); |
733 | 10.7M | bool sectionSet = m_section.isSet(); |
734 | 10.7M | if (m_version > 3 && m_section->read(input,endPos)) |
735 | 396k | return true; |
736 | 10.3M | if (m_version == 3 && m_section->readV3(input,endPos)) |
737 | 273k | return true; |
738 | 10.1M | if (!sectionSet) m_section.setSet(false); |
739 | | |
740 | 10.1M | input->seek(pos, librevenge::RVNG_SEEK_SET); |
741 | 10.1M | bool tableSet = m_table.isSet(); |
742 | 10.1M | if (m_table->read(input,endPos)) |
743 | 952k | return true; |
744 | 9.17M | if (!tableSet) m_table.setSet(false); |
745 | | |
746 | 9.17M | input->seek(pos, librevenge::RVNG_SEEK_SET); |
747 | 9.17M | long dSz = endPos-pos; |
748 | 9.17M | if (dSz < 1) return false; |
749 | 9.17M | libmwaw::DebugStream f; |
750 | 9.17M | int c = static_cast<int>(input->readULong(1)), val; |
751 | 9.17M | switch (c) { |
752 | 72.2k | case 0x2: // sprmPIstd |
753 | 72.2k | if (dSz < 2) return false; |
754 | 69.1k | m_styleId = static_cast<int>(input->readLong(1)); |
755 | 69.1k | break; |
756 | 36.6k | case 0x3: { // sprmPIstdPermute: checkme: alway find with 3,3,2,3 |
757 | 36.6k | if (dSz < 2) return false; |
758 | 34.3k | auto num= static_cast<int>(input->readULong(1)); |
759 | 34.3k | if (num<=0 || dSz < 2+num) return false; |
760 | 9.54k | MWAW_DEBUG_MSG(("Paragraph::read: find istd permute list, unimplemented\n")); |
761 | 9.54k | f << "istPerm=["; |
762 | 332k | for (int i = 0; i < num; i++) |
763 | 323k | f << input->readLong(1) << ","; |
764 | 9.54k | f << "],"; |
765 | 9.54k | break; |
766 | 34.3k | } |
767 | 62.4k | case 0x5: |
768 | 62.4k | if (dSz < 2) return false; |
769 | 56.8k | val = static_cast<int>(input->readLong(1)); |
770 | 56.8k | switch (val) { |
771 | 6.06k | case 0: |
772 | 6.06k | m_justify = MWAWParagraph::JustificationLeft; |
773 | 6.06k | return true; |
774 | 7.57k | case 1: |
775 | 7.57k | m_justify = MWAWParagraph::JustificationCenter; |
776 | 7.57k | return true; |
777 | 2.14k | case 2: |
778 | 2.14k | m_justify = MWAWParagraph::JustificationRight; |
779 | 2.14k | return true; |
780 | 1.61k | case 3: |
781 | 1.61k | m_justify = MWAWParagraph::JustificationFull; |
782 | 1.61k | return true; |
783 | 39.4k | default: |
784 | 39.4k | MWAW_DEBUG_MSG(("MsWrdStruct::Paragraph::read: can not read align\n")); |
785 | 39.4k | f << "#align=" << val << ","; |
786 | 39.4k | break; |
787 | 56.8k | } |
788 | 39.4k | break; |
789 | 48.7k | case 0x6: // a small number : always 1 ? |
790 | 120k | case 0x7: |
791 | 175k | case 0x8: |
792 | 207k | case 0x9: |
793 | 239k | case 0xe: // a small number always 0 ? |
794 | 239k | if (dSz < 2) return false; |
795 | 219k | val = static_cast<int>(input->readLong(1)); |
796 | 219k | switch (c) { |
797 | 66.6k | case 7: |
798 | 66.6k | if (val==0) |
799 | 7.17k | m_breakStatus = m_breakStatus.get()&(~MWAWParagraph::NoBreakBit); |
800 | 59.5k | else |
801 | 59.5k | m_breakStatus = m_breakStatus.get()|MWAWParagraph::NoBreakBit; |
802 | 66.6k | f << "noBreak"; |
803 | 66.6k | break; |
804 | 46.7k | case 8: |
805 | 46.7k | if (val==0) |
806 | 4.17k | m_breakStatus = m_breakStatus.get()&(~MWAWParagraph::NoBreakWithNextBit); |
807 | 42.6k | else |
808 | 42.6k | m_breakStatus = m_breakStatus.get()|MWAWParagraph::NoBreakWithNextBit; |
809 | 46.7k | f << "noBreakWithNext"; |
810 | 46.7k | break; |
811 | 30.4k | case 9: // normally ok, ... |
812 | 30.4k | f << "pagebreakbefore"; |
813 | 30.4k | break; |
814 | 75.1k | default: |
815 | 75.1k | f << "f" << std::hex << c << std::dec; |
816 | 75.1k | break; |
817 | 219k | } |
818 | 219k | if (val==0) f << "*"; |
819 | 201k | else if (val != 1) f << "=" << val; |
820 | 219k | f << ","; |
821 | 219k | break; |
822 | 504k | case 0xa: { |
823 | 504k | if (dSz < 2) return false; |
824 | 428k | val = static_cast<int>(input->readLong(1)); |
825 | 428k | MWAWBorder border; |
826 | 428k | switch (val) { |
827 | 6.54k | case 0: |
828 | 6.54k | break; // normal, checkme |
829 | 3.29k | case 1: |
830 | 3.29k | border.m_width = 2; |
831 | 3.29k | break; |
832 | 2.31k | case 2: |
833 | 2.31k | border.m_type = MWAWBorder::Double; |
834 | 2.31k | break; |
835 | 2.88k | case 3: |
836 | 2.88k | border.m_width = 2; |
837 | 2.88k | f << "border[shadow],"; |
838 | 2.88k | break; |
839 | 413k | default: |
840 | 413k | f << "#borders=" << val << ","; |
841 | 413k | break; |
842 | 428k | } |
843 | 428k | m_bordersStyle = border; |
844 | 428k | break; |
845 | 428k | } |
846 | 228k | case 0xb: |
847 | 228k | if (dSz < 2) return false; |
848 | 213k | val = static_cast<int>(input->readULong(1)); |
849 | 213k | if (val && val <= 0x10) { |
850 | 186k | if (m_borders.size() < 4) |
851 | 56.7k | resizeBorders(4); |
852 | 186k | if (val & 0x1) |
853 | 181k | m_borders[libmwaw::Top] = m_bordersStyle.get(); |
854 | 186k | if (val & 0x2) |
855 | 179k | m_borders[libmwaw::Bottom] = m_bordersStyle.get(); |
856 | | // val & 0x4 |
857 | 186k | if ((val & 0x4) || val==0x10) |
858 | 3.38k | m_borders[libmwaw::Left] = m_bordersStyle.get(); |
859 | 186k | if (val & 0x8) |
860 | 181k | m_borders[libmwaw::Right] = m_bordersStyle.get(); |
861 | 186k | return true; |
862 | 186k | } |
863 | 27.2k | else if (val) |
864 | 19.4k | f << "#borders=" << val << ","; |
865 | 27.2k | break; |
866 | 30.3k | case 0xf: // tabs |
867 | 54.1k | case 0x17: { // tabs |
868 | 54.1k | auto sz = static_cast<int>(input->readULong(1)); |
869 | 54.1k | if (sz<2 || 2+sz > dSz) { |
870 | 27.9k | MWAW_DEBUG_MSG(("MsWrdStruct::Paragraph::read: can not read tab\n")); |
871 | 27.9k | return false; |
872 | 27.9k | } |
873 | 26.2k | int deletedSz=(c==0x17) ? 4 : 2; |
874 | 26.2k | auto N0 = static_cast<int>(input->readULong(1)); |
875 | 26.2k | if (deletedSz*N0 > sz) { |
876 | 11.1k | MWAW_DEBUG_MSG(("MsWrdStruct::Paragraph::read: num of deleted tabs seems odd\n")); |
877 | 11.1k | return false; |
878 | 11.1k | } |
879 | 15.0k | if (N0) { |
880 | 87.0k | for (int i = 0; i < N0; i++) |
881 | 78.8k | m_deletedTabs.push_back(float(input->readLong(2))/1440.f); |
882 | 8.16k | } |
883 | 15.0k | if (c==0x17 && N0) { |
884 | 783 | f << "del17=["; |
885 | 5.27k | for (int i = 0; i < N0; i++) { // always with 0x19 ? |
886 | 4.49k | val=static_cast<int>(input->readULong(2)); |
887 | 4.49k | if (val==0x19) |
888 | 24 | f << "_"; |
889 | 4.46k | else |
890 | 4.46k | f << std::hex << val << std::dec << ","; |
891 | 4.49k | } |
892 | 783 | f << "],"; |
893 | 783 | } |
894 | 15.0k | auto N = static_cast<int>(input->readULong(1)); |
895 | 15.0k | if (N*3+deletedSz*N0+2 != sz) { |
896 | 7.80k | MWAW_DEBUG_MSG(("MsWrdStruct::Paragraph::read: num tab seems odd\n")); |
897 | 7.80k | f << "#"; |
898 | 7.80k | m_extra += f.str(); |
899 | 7.80k | return false; |
900 | 7.80k | } |
901 | 7.23k | std::vector<float> tabs; |
902 | 7.23k | tabs.resize(size_t(N)); |
903 | 18.6k | for (auto &t : tabs) t = float(input->readLong(2))/1440.f; |
904 | 18.6k | for (auto const &tabPos : tabs) { |
905 | 18.6k | MWAWTabStop tab; |
906 | 18.6k | tab.m_position = double(tabPos); |
907 | 18.6k | val = static_cast<int>(input->readULong(1)); |
908 | 18.6k | switch (val>>5) { |
909 | 11.8k | case 0: |
910 | 11.8k | break; |
911 | 759 | case 1: |
912 | 759 | tab.m_alignment = MWAWTabStop::CENTER; |
913 | 759 | break; |
914 | 407 | case 2: |
915 | 407 | tab.m_alignment = MWAWTabStop::RIGHT; |
916 | 407 | break; |
917 | 615 | case 3: |
918 | 615 | tab.m_alignment = MWAWTabStop::DECIMAL; |
919 | 615 | break; |
920 | 205 | case 4: |
921 | 205 | tab.m_alignment = MWAWTabStop::BAR; |
922 | 205 | break; |
923 | 4.85k | default: |
924 | 4.85k | f << "#tabAlign=" << int(val>>5) << ","; |
925 | 4.85k | break; |
926 | 18.6k | } |
927 | 18.6k | switch ((val>>2)&3) { |
928 | 2.32k | case 1: |
929 | 2.32k | tab.m_leaderCharacter = '.'; |
930 | 2.32k | break; |
931 | 1.67k | case 2: |
932 | 1.67k | tab.m_leaderCharacter = '-'; |
933 | 1.67k | break; |
934 | 3.96k | case 3: |
935 | 3.96k | tab.m_leaderCharacter = '_'; |
936 | 3.96k | break; |
937 | 10.7k | case 0: |
938 | 10.7k | default: |
939 | 10.7k | break; |
940 | 18.6k | } |
941 | 18.6k | if (val & 0x13) |
942 | 8.48k | f << "#tabsFlags=" << std::hex << (val & 0x13) << ","; |
943 | 18.6k | m_tabs->push_back(tab); |
944 | 18.6k | } |
945 | 7.23k | break; |
946 | 7.23k | } |
947 | 1.40M | case 0x10: // right |
948 | 1.46M | case 0x11: // left |
949 | 1.51M | case 0x13: // first left |
950 | 1.51M | if (dSz < 3) return false; |
951 | 1.48M | val = static_cast<int>(input->readLong(2)); |
952 | 1.48M | if (c == 0x13) m_margins[0] = val/1440.; |
953 | 1.43M | else if (c == 0x11) m_margins[1] = val/1440.; |
954 | 1.37M | else m_margins[2] = val/1440.; |
955 | 1.48M | return true; |
956 | 83.0k | case 0x14: // alignment : 240 normal, 480 : double, .. |
957 | 83.0k | if (dSz < 3) return false; |
958 | 75.9k | val = static_cast<int>(input->readLong(2)); |
959 | 75.9k | m_interline=double(val)/1440.; |
960 | 75.9k | return true; |
961 | 44.0k | case 0x15: // spacing before DWIPP |
962 | 103k | case 0x16: // spacing after DWIPP |
963 | 103k | if (dSz < 3) return false; |
964 | 93.4k | val = static_cast<int>(input->readLong(2)); |
965 | 93.4k | m_spacings[c-0x14] = double(val)/1440.; |
966 | 93.4k | return true; |
967 | 232k | case 0x18: |
968 | 309k | case 0x19: |
969 | 309k | if (dSz < 2) return false; |
970 | 303k | val = static_cast<int>(input->readULong(1)); |
971 | 303k | if (c==0x18) m_inCell = (val!=0); |
972 | 75.5k | else m_tableDef = (val != 0); |
973 | 303k | if (val != 0 && val!=1) { |
974 | 193k | f << "#f" << std::hex << c << std::dec << "=" << val << ","; |
975 | 193k | break; |
976 | 193k | } |
977 | 110k | return true; |
978 | 15.6k | case 0x1a: // frame x,y,w |
979 | 32.5k | case 0x1b: |
980 | 70.9k | case 0x1c: { |
981 | 70.9k | if (dSz < 3) return false; |
982 | 62.3k | val = static_cast<int>(input->readLong(2)); |
983 | 62.3k | char const *what[] = {"frameX", "frameY", "frameWidth" }; |
984 | 62.3k | f << what[c-0x1a] << "="; |
985 | 62.3k | if (val < 0) { |
986 | 10.8k | val = -val; |
987 | 10.8k | int type=(val&0x1C)>>2; |
988 | 10.8k | if (c==0x1a) { |
989 | 2.97k | switch (type) { |
990 | 33 | case 1: |
991 | 33 | f << "center"; |
992 | 33 | break; |
993 | 1.00k | case 2: |
994 | 1.00k | f << "right"; |
995 | 1.00k | break; |
996 | 932 | case 3: |
997 | 932 | f << "inside"; |
998 | 932 | break; |
999 | 711 | case 4: |
1000 | 711 | f << "outside"; |
1001 | 711 | break; |
1002 | 298 | default: |
1003 | 298 | f << "#" << type; |
1004 | 298 | break; |
1005 | 2.97k | } |
1006 | 2.97k | val &= 0xFFE3; |
1007 | 2.97k | } |
1008 | 7.86k | else if (c==0x1b) { |
1009 | 3.65k | switch (type) { |
1010 | 1.30k | case 1: |
1011 | 1.30k | f << "top,"; |
1012 | 1.30k | break; |
1013 | 21 | case 2: |
1014 | 21 | f << "center,"; |
1015 | 21 | break; |
1016 | 127 | case 3: |
1017 | 127 | f << "bottom,"; |
1018 | 127 | break; |
1019 | 2.20k | default: |
1020 | 2.20k | f << "#" << type; |
1021 | 2.20k | break; |
1022 | 3.65k | } |
1023 | 3.65k | val &= 0xFFE3; |
1024 | 3.65k | } |
1025 | 10.8k | if (val) |
1026 | 10.2k | f << "[" << val << "]"; |
1027 | 10.8k | f << ","; |
1028 | 10.8k | } |
1029 | 51.5k | else f << val/1440. << ","; |
1030 | 62.3k | break; |
1031 | 62.3k | } |
1032 | 96.3k | case 0x1d: |
1033 | 96.3k | if (dSz < 2) return false; |
1034 | 93.7k | val = static_cast<int>(input->readULong(1)); |
1035 | 93.7k | switch (val&3) { |
1036 | 3.21k | case 0: |
1037 | 3.21k | break; // column |
1038 | 81.9k | case 1: |
1039 | 81.9k | f << "Xrel=margin,"; |
1040 | 81.9k | break; |
1041 | 4.84k | case 2: |
1042 | 4.84k | f << "Xrel=page,"; |
1043 | 4.84k | break; |
1044 | 3.76k | default: |
1045 | 3.76k | f << "#Xrel=3,"; |
1046 | 3.76k | break; |
1047 | 93.7k | } |
1048 | 93.7k | if (val&4) f << "Yrel=page,"; // def margin |
1049 | 93.7k | if (val&0xF8) f << "#rel=" << (val>>3) << ","; |
1050 | 93.7k | break; |
1051 | 70.6k | case 0x1e: // checkme: find one time in v3 (text struct file) with data 0x80 |
1052 | 106k | case 0x1f: |
1053 | 186k | case 0x20: |
1054 | 831k | case 0x21: |
1055 | 994k | case 0x22: { |
1056 | 994k | if (dSz < 3) return false; |
1057 | 955k | std::string bExtra; |
1058 | 955k | MWAWBorder border = getBorder(static_cast<int>(input->readULong(2)), bExtra); |
1059 | 955k | if (bExtra.length()) |
1060 | 0 | f << "bord" << (c-0x1e) << "[" << bExtra << "],"; |
1061 | 955k | if (c < 0x22) { |
1062 | 798k | size_t const wh[] = { libmwaw::Top, libmwaw::Left, |
1063 | 798k | libmwaw::Bottom, libmwaw::Right |
1064 | 798k | }; |
1065 | 798k | size_t p = wh[c-0x1e]; |
1066 | 798k | if (m_borders.size() <= p) |
1067 | 340k | resizeBorders(p+1); |
1068 | 798k | m_borders[p] = border; |
1069 | 798k | } |
1070 | 157k | else { |
1071 | 157k | if (m_borders.size() < 6) |
1072 | 70.9k | resizeBorders(6); |
1073 | 157k | m_borders[libmwaw::HMiddle] = border; |
1074 | 157k | m_borders[libmwaw::VMiddle] = border; |
1075 | 157k | } |
1076 | 955k | break; |
1077 | 994k | } |
1078 | 74.2k | case 0x24: { // distance to text (related to frame ?) |
1079 | 74.2k | if (dSz < 3) return false; |
1080 | 67.5k | val = static_cast<int>(input->readULong(2)); |
1081 | 67.5k | if (val) f << "distToText=" << val/1440. << ","; |
1082 | 67.5k | break; |
1083 | 74.2k | } |
1084 | 4.72M | default: |
1085 | 4.72M | return false; |
1086 | 9.17M | } |
1087 | 2.17M | m_extra += f.str(); |
1088 | 2.17M | return true; |
1089 | 9.17M | } |
1090 | | |
1091 | | // paragraph |
1092 | | std::ostream &operator<<(std::ostream &o, Paragraph const &ind) |
1093 | 0 | { |
1094 | 0 | if (ind.m_styleId.isSet()) |
1095 | 0 | o << "styleId[orig]=" << ind.m_styleId.get() << ","; |
1096 | 0 | if (!ind.m_deletedTabs.empty()) { |
1097 | 0 | o << "deletedTab=["; |
1098 | 0 | for (auto const &val : ind.m_deletedTabs) |
1099 | 0 | o << val << ","; |
1100 | 0 | o << "],"; |
1101 | 0 | } |
1102 | 0 | if (ind.m_interline.isSet()) |
1103 | 0 | o << "interline=" << *ind.m_interline << ","; |
1104 | 0 | if (ind.m_info.isSet()) |
1105 | 0 | o << "dim=[" << *ind.m_info << "],"; |
1106 | 0 | o << static_cast<MWAWParagraph const &>(ind); |
1107 | 0 | if (ind.m_bordersStyle.isSet()) |
1108 | 0 | o << "borders[style]=" << ind.m_bordersStyle.get() << ","; |
1109 | 0 | if (ind.m_section.isSet()) o << ind.m_section.get() << ","; |
1110 | 0 | if (ind.m_inCell.get()) o << "cell,"; |
1111 | 0 | if (ind.m_tableDef.get()) o << "table[def],"; |
1112 | 0 | if (ind.m_table.isSet()) o << "table=[" << ind.m_table.get() << "],"; |
1113 | 0 | return o; |
1114 | 0 | } |
1115 | | |
1116 | | bool Paragraph::getFont(Font &font, Font const *styleFont) const |
1117 | 653k | { |
1118 | 653k | bool res = true; |
1119 | 653k | if (m_font.isSet()) |
1120 | 94.7k | font = m_font.get(); |
1121 | 558k | else |
1122 | 558k | res = false; |
1123 | 653k | if (m_modFont.isSet()) { |
1124 | 132k | font.insert(*m_modFont, styleFont); |
1125 | 132k | res = true; |
1126 | 132k | } |
1127 | 653k | return res; |
1128 | 653k | } |
1129 | | |
1130 | | void Paragraph::updateParagraphToFinalState(Paragraph const *style) |
1131 | 597k | { |
1132 | 597k | if (!m_interline.isSet()) return; |
1133 | 111k | double interline=*m_interline; |
1134 | 111k | if (interline<-1 || interline>1) { |
1135 | 1.21k | MWAW_DEBUG_MSG(("MsWrdStruct::Paragraph::updateParagraphToFinalState: interline spacing seems odd\n")); |
1136 | 1.21k | setInterline(1.0, librevenge::RVNG_PERCENT); |
1137 | 1.21k | return; |
1138 | 1.21k | } |
1139 | 110k | if (interline>0) { |
1140 | 28.1k | setInterline(interline, librevenge::RVNG_INCH, MWAWParagraph::AtLeast); |
1141 | 28.1k | return; |
1142 | 28.1k | } |
1143 | 81.9k | if (interline<0) { |
1144 | 228 | setInterline(-interline, librevenge::RVNG_INCH); |
1145 | 228 | return; |
1146 | 228 | } |
1147 | | // checkme: what to do when m_interline=0, use the style interline or the para info? |
1148 | 81.7k | if (!style || !style->m_interline.isSet()) |
1149 | 9.81k | return; |
1150 | 71.9k | interline=*style->m_interline; |
1151 | 71.9k | if (interline>0 && interline <=1) |
1152 | 27.7k | setInterline(interline, librevenge::RVNG_INCH, MWAWParagraph::AtLeast); |
1153 | 44.2k | else if (interline<0 && interline >=-1) |
1154 | 10 | setInterline(-interline, librevenge::RVNG_INCH, MWAWParagraph::AtLeast); |
1155 | 71.9k | } |
1156 | | |
1157 | | void Paragraph::insert(Paragraph const ¶, bool insertModif) |
1158 | 351k | { |
1159 | 351k | if (m_tabs.isSet()) { |
1160 | 412k | for (int st=0; st<2; ++st) { |
1161 | 274k | std::vector<float> const &deletedTabs=st==0?para.m_deletedTabs:m_deletedTabs; |
1162 | 274k | for (auto const val : deletedTabs) { |
1163 | 191k | for (auto it=m_tabs->begin(); it!=m_tabs->end(); ++it) { |
1164 | 158k | if (it->m_position < double(val)-1e-3 || it->m_position > double(val)+1e-3) |
1165 | 50.1k | continue; |
1166 | 108k | m_tabs->erase(it); |
1167 | 108k | break; |
1168 | 158k | } |
1169 | 141k | } |
1170 | 274k | } |
1171 | 137k | } |
1172 | 351k | MWAWParagraph::insert(para); |
1173 | 351k | m_styleId.insert(para.m_styleId); |
1174 | 351k | m_interline.insert(para.m_interline); |
1175 | 351k | if (para.m_info.isSet() && para.m_info->isLineSet()) |
1176 | 154k | m_info.insert(para.m_info); |
1177 | 351k | if (!m_font.isSet()) |
1178 | 214k | m_font=para.m_font; |
1179 | 137k | else if (para.m_font.isSet()) |
1180 | 623 | m_font->insert(*para.m_font); |
1181 | 351k | if (insertModif) |
1182 | 351k | m_modFont->insert(*para.m_modFont); |
1183 | 351k | if (!m_section.isSet()) |
1184 | 339k | m_section = para.m_section; |
1185 | 12.9k | else if (para.m_section.isSet()) |
1186 | 5.49k | m_section->insert(*para.m_section); |
1187 | 351k | if (!m_bordersStyle.isSet() || para.m_bordersStyle.isSet()) |
1188 | 343k | m_bordersStyle = para.m_bordersStyle; |
1189 | 351k | m_inCell.insert(para.m_inCell); |
1190 | 351k | if (!m_table.isSet()) |
1191 | 285k | m_table = para.m_table; |
1192 | 66.1k | else if (para.m_table.isSet()) |
1193 | 8.59k | m_table->insert(*para.m_table); |
1194 | 351k | m_tableDef.insert(para.m_tableDef); |
1195 | 351k | } |
1196 | | |
1197 | | void Paragraph::print(std::ostream &o, MWAWFontConverterPtr converter) const |
1198 | 0 | { |
1199 | 0 | if (m_font.isSet()) |
1200 | 0 | o << "font=[" << m_font->m_font->getDebugString(converter) << m_font.get() << "],"; |
1201 | 0 | if (m_modFont.isSet()) |
1202 | 0 | o << "modifFont=[" << m_modFont->m_font->getDebugString(converter) << m_modFont.get() << "],"; |
1203 | 0 | o << *this; |
1204 | 0 | } |
1205 | | |
1206 | | // generic |
1207 | | MWAWBorder getBorder(int val, std::string &extra) |
1208 | 1.05M | { |
1209 | 1.05M | MWAWBorder border; |
1210 | 1.05M | libmwaw::DebugStream f; |
1211 | | |
1212 | 1.05M | if (val & 0x3E00) f << "textSep=" << int((val& 0x3E00)>>9) << "pt"; |
1213 | 1.05M | if (val & 0x4000) f << "shad,"; |
1214 | 1.05M | if (val & 0x8000) f << "*"; |
1215 | 1.05M | switch (val &0x1FF) { |
1216 | 33.1k | case 0: |
1217 | 33.1k | border.m_style = MWAWBorder::None; |
1218 | 33.1k | break; |
1219 | 24.1k | case 0x40: |
1220 | 24.1k | break; // normal |
1221 | 8.52k | case 0x49: |
1222 | 8.52k | border.m_type = MWAWBorder::Double; |
1223 | 8.52k | break; |
1224 | 7.67k | case 0x80: |
1225 | 7.67k | border.m_width = 2; |
1226 | 7.67k | break; |
1227 | 2.96k | case 0x180: |
1228 | 2.96k | border.m_style = MWAWBorder::Dot; |
1229 | 2.96k | break; |
1230 | 1.20k | case 0x1c0: |
1231 | 1.20k | border.m_width = 0.5; |
1232 | 1.20k | break; |
1233 | 980k | default: |
1234 | 980k | f << "#bType=" << std::hex << (val & 0x1FF) << std::dec; |
1235 | 980k | break; |
1236 | 1.05M | } |
1237 | | |
1238 | 1.05M | extra=f.str(); |
1239 | 1.05M | return border; |
1240 | 1.05M | } |
1241 | | |
1242 | | } |
1243 | | // vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: |