/src/libmwaw/src/lib/MsWks3Text.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 <iomanip> |
35 | | #include <iostream> |
36 | | #include <limits> |
37 | | #include <map> |
38 | | #include <sstream> |
39 | | |
40 | | #include <librevenge/librevenge.h> |
41 | | |
42 | | #include "MWAWDebug.hxx" |
43 | | #include "MWAWFont.hxx" |
44 | | #include "MWAWFontConverter.hxx" |
45 | | #include "MWAWListener.hxx" |
46 | | #include "MWAWParagraph.hxx" |
47 | | #include "MWAWParser.hxx" |
48 | | #include "MWAWSubDocument.hxx" |
49 | | |
50 | | #include "MsWksDocument.hxx" |
51 | | |
52 | | #include "MsWks3Text.hxx" |
53 | | |
54 | | /** Internal: the structures of a MsWks3Text */ |
55 | | namespace MsWks3TextInternal |
56 | | { |
57 | | //////////////////////////////////////// |
58 | | //! Internal: header zone |
59 | | struct LineZone { |
60 | | //! the constructor |
61 | | LineZone() |
62 | 130M | : m_type(-1) |
63 | 130M | , m_pos() |
64 | 130M | , m_id(0) |
65 | | , m_flags() |
66 | 130M | , m_height(0) |
67 | 130M | { |
68 | 130M | } |
69 | | //! operator<< |
70 | | friend std::ostream &operator<<(std::ostream &o, LineZone const &z) |
71 | 0 | { |
72 | 0 | switch (z.m_type>>5) { |
73 | 0 | case 0: |
74 | 0 | case 1: |
75 | 0 | case 2: |
76 | 0 | case 3: |
77 | 0 | o << "Text,"; |
78 | 0 | break; |
79 | 0 | case 4: |
80 | 0 | o << "Tabs,"; |
81 | 0 | break; |
82 | 0 | default: |
83 | 0 | o << "##type=" << std::hex << (z.m_type >> 5) << std::dec << ","; |
84 | 0 | } |
85 | 0 | if (z.m_type&0x8) o << "note,"; |
86 | 0 | if (z.m_type&0x7) o << "#type=" << std::hex << (z.m_type&0x7) << std::dec << ","; |
87 | 0 | if (z.m_id) o << "id=" << z.m_id << ","; |
88 | 0 | if (z.m_flags&1) o << "softBreak,"; |
89 | 0 | if (z.m_flags&2) o << "hardBreak,"; |
90 | 0 | if (!(z.m_flags&4)) o << "beginDoc,"; |
91 | 0 | if (z.m_flags&8) o << "graphics,"; |
92 | 0 | if (z.m_flags&0x20) o << "noteFl,"; |
93 | 0 | if (z.m_flags&0x40) o << "fields,"; |
94 | 0 | if (z.m_flags&0x90) o << "#flags=" << std::hex << (z.m_flags&0x90) << std::dec << ","; |
95 | 0 | if (z.m_height) o << "h=" << z.m_height << ","; |
96 | 0 | return o; |
97 | 0 | } |
98 | | //! return true if this is a note |
99 | | bool isNote() const |
100 | 4.60M | { |
101 | 4.60M | return (m_type&0x8)==0x8; |
102 | 4.60M | } |
103 | | //! return true if this is a tabs |
104 | | bool isRuler() const |
105 | 38.4k | { |
106 | 38.4k | return (m_type&0xE0)==0x80; |
107 | 38.4k | } |
108 | | //! the type |
109 | | int m_type; |
110 | | //! the file position |
111 | | MWAWEntry m_pos; |
112 | | //! the id |
113 | | int m_id; |
114 | | //! the zone flags |
115 | | int m_flags; |
116 | | //! the height |
117 | | int m_height; |
118 | | }; |
119 | | |
120 | | //////////////////////////////////////// |
121 | | //! Internal: the fonts |
122 | | struct Font { |
123 | | //! the constructor |
124 | 13.4M | Font(): m_font(), m_extra("") |
125 | 13.4M | { |
126 | 40.2M | for (int &flag : m_flags) flag = 0; |
127 | 13.4M | } |
128 | | |
129 | | //! operator<< |
130 | | friend std::ostream &operator<<(std::ostream &o, Font const &font) |
131 | 0 | { |
132 | 0 | for (int i = 0; i < 3; i++) { |
133 | 0 | if (!font.m_flags[i]) continue; |
134 | 0 | o << "ft" << i << "="; |
135 | 0 | if (i == 0) o << std::hex; |
136 | 0 | o << font.m_flags[i] << std::dec << ","; |
137 | 0 | } |
138 | 0 | if (font.m_extra.length()) |
139 | 0 | o << font.m_extra << ","; |
140 | 0 | return o; |
141 | 0 | } |
142 | | |
143 | | //! the font |
144 | | MWAWFont m_font; |
145 | | //! some unknown flag |
146 | | int m_flags[3]; |
147 | | //! extra data |
148 | | std::string m_extra; |
149 | | }; |
150 | | |
151 | | //////////////////////////////////////// |
152 | | //! Internal: the text zone |
153 | | struct TextZone { |
154 | | enum Type { Header, Footer, Main, Unknown }; |
155 | | //! constructor |
156 | | TextZone() |
157 | 65.2M | : m_type(Unknown) |
158 | 65.2M | , m_id(0) |
159 | 65.2M | , m_zonesList() |
160 | 65.2M | , m_linesHeight() |
161 | 65.2M | , m_pagesHeight() |
162 | 65.2M | , m_pagesPosition() |
163 | 65.2M | , m_footnoteMap() |
164 | 65.2M | , m_text("") |
165 | 65.2M | , m_isSent(false) |
166 | 65.2M | { |
167 | 65.2M | } |
168 | | |
169 | | //! return true if this is the main zone |
170 | | bool isMain() const |
171 | 1.33M | { |
172 | 1.33M | return m_type == Main; |
173 | 1.33M | } |
174 | | //! the zone type; |
175 | | int m_type; |
176 | | //! the zone id |
177 | | int m_id; |
178 | | //! the list of zones |
179 | | std::vector<LineZone> m_zonesList; |
180 | | //! the line height |
181 | | std::vector<int> m_linesHeight; |
182 | | //! the pages height |
183 | | std::vector<int> m_pagesHeight; |
184 | | //! the zone id -> hard break |
185 | | std::map<int, bool> m_pagesPosition; |
186 | | //! the note id -> zone limit |
187 | | std::map<int, MWAWVec2i> m_footnoteMap; |
188 | | //! a string used to store v1-2 files header/footer |
189 | | std::string m_text; |
190 | | //! flag to know if the zone is send or not |
191 | | bool m_isSent; |
192 | | }; |
193 | | |
194 | | //////////////////////////////////////// |
195 | | //! Internal: the state of a MsWks3Text |
196 | | struct State { |
197 | | //! constructor |
198 | | State() |
199 | 77.1k | : m_version(-1) |
200 | 77.1k | , m_zones() |
201 | 77.1k | , m_numPages(1) |
202 | 77.1k | , m_actualPage(1) |
203 | 77.1k | { |
204 | 77.1k | } |
205 | | //! the file version |
206 | | mutable int m_version; |
207 | | //! the main zone |
208 | | std::vector<TextZone> m_zones; |
209 | | |
210 | | int m_numPages /* the number of pages */, m_actualPage /* the actual page */; |
211 | | }; |
212 | | |
213 | | //////////////////////////////////////// |
214 | | //! Internal: the subdocument of a MsWks3Text |
215 | | class SubDocument final : public MWAWSubDocument |
216 | | { |
217 | | public: |
218 | | enum Type { Zone, Text }; |
219 | | SubDocument(MsWks3Text &pars, MWAWInputStreamPtr const &input, int zoneId, int noteId) |
220 | 472k | : MWAWSubDocument(pars.m_mainParser, input, MWAWEntry()) |
221 | 472k | , m_textParser(&pars) |
222 | 472k | , m_id(zoneId) |
223 | 472k | , m_noteId(noteId) |
224 | 472k | { |
225 | 472k | } |
226 | | |
227 | | //! destructor |
228 | 0 | ~SubDocument() final {} |
229 | | |
230 | | //! operator!= |
231 | | bool operator!=(MWAWSubDocument const &doc) const final; |
232 | | |
233 | | //! the parser function |
234 | | void parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType type) final; |
235 | | |
236 | | protected: |
237 | | /** the text parser */ |
238 | | MsWks3Text *m_textParser; |
239 | | /** the subdocument id*/ |
240 | | int m_id; |
241 | | /** the note id */ |
242 | | int m_noteId; |
243 | | private: |
244 | | SubDocument(SubDocument const &orig) = delete; |
245 | | SubDocument operator=(SubDocument const &orig) = delete; |
246 | | }; |
247 | | |
248 | | void SubDocument::parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType /*type*/) |
249 | 472k | { |
250 | 472k | if (!listener.get()) { |
251 | 0 | MWAW_DEBUG_MSG(("MsWks3TextInternal::SubDocument::parse: no listener\n")); |
252 | 0 | return; |
253 | 0 | } |
254 | 472k | if (!m_textParser) { |
255 | 0 | MWAW_DEBUG_MSG(("MsWks3TextInternal::SubDocument::parse: no parser\n")); |
256 | 0 | return; |
257 | 0 | } |
258 | | |
259 | 472k | long pos = m_input->tell(); |
260 | 472k | m_textParser->sendNote(m_id, m_noteId); |
261 | 472k | m_input->seek(pos, librevenge::RVNG_SEEK_SET); |
262 | 472k | } |
263 | | |
264 | | bool SubDocument::operator!=(MWAWSubDocument const &doc) const |
265 | 400k | { |
266 | 400k | if (MWAWSubDocument::operator!=(doc)) return true; |
267 | 400k | auto const *sDoc = dynamic_cast<SubDocument const *>(&doc); |
268 | 400k | if (!sDoc) return true; |
269 | 0 | if (m_textParser != sDoc->m_textParser) return true; |
270 | 0 | if (m_id != sDoc->m_id) return true; |
271 | 0 | if (m_noteId != sDoc->m_noteId) return true; |
272 | 0 | return false; |
273 | 0 | } |
274 | | |
275 | | } |
276 | | |
277 | | //////////////////////////////////////////////////////////// |
278 | | // constructor/destructor, ... |
279 | | //////////////////////////////////////////////////////////// |
280 | | MsWks3Text::MsWks3Text(MsWksDocument &document) |
281 | 77.1k | : m_parserState() |
282 | 77.1k | , m_state(new MsWks3TextInternal::State) |
283 | 77.1k | , m_mainParser(&document.getMainParser()) |
284 | 77.1k | , m_document(document) |
285 | 77.1k | { |
286 | 77.1k | m_parserState=m_mainParser->getParserState(); |
287 | 77.1k | } |
288 | | |
289 | | MsWks3Text::~MsWks3Text() |
290 | 77.1k | { |
291 | 77.1k | } |
292 | | |
293 | | int MsWks3Text::version() const |
294 | 13.3M | { |
295 | 13.3M | if (m_state->m_version < 0) |
296 | 28.6k | m_state->m_version = m_parserState->m_version; |
297 | 13.3M | return m_state->m_version; |
298 | 13.3M | } |
299 | | |
300 | | int MsWks3Text::numPages(int zoneId) const |
301 | 29.7k | { |
302 | 29.7k | if (zoneId < 0 || zoneId >= int(m_state->m_zones.size())) { |
303 | 0 | MWAW_DEBUG_MSG(("MsWks3Text::numPages: unknown zone %d\n", zoneId)); |
304 | 0 | return 0; |
305 | 0 | } |
306 | 29.7k | auto const &zone = m_state->m_zones[size_t(zoneId)]; |
307 | 29.7k | int nPages = 1 + int(zone.m_pagesPosition.size()); |
308 | 29.7k | if (zone.isMain()) { |
309 | 29.7k | m_state->m_actualPage = 1; |
310 | 29.7k | m_state->m_numPages = nPages; |
311 | 29.7k | } |
312 | 0 | else { |
313 | 0 | MWAW_DEBUG_MSG(("MsWks3Text::numPages: called on no main zone: %d\n", zoneId)); |
314 | 0 | } |
315 | 29.7k | return nPages; |
316 | 29.7k | } |
317 | | |
318 | | bool MsWks3Text::getLinesPagesHeight |
319 | | (int zoneId, std::vector<int> &lines, std::vector<int> &pages) |
320 | 54.9k | { |
321 | 54.9k | lines.resize(0); |
322 | 54.9k | pages.resize(0); |
323 | 54.9k | if (zoneId < 0 || zoneId >= int(m_state->m_zones.size())) { |
324 | 32.8k | MWAW_DEBUG_MSG(("MsWks3Text::getLinesPagesHeight: unknown zone %d\n", zoneId)); |
325 | 32.8k | return false; |
326 | 32.8k | } |
327 | 22.0k | lines = m_state->m_zones[size_t(zoneId)].m_linesHeight; |
328 | 22.0k | pages = m_state->m_zones[size_t(zoneId)].m_pagesHeight; |
329 | 22.0k | return true; |
330 | 54.9k | } |
331 | | |
332 | | //////////////////////////////////////////////////////////// |
333 | | // Intermediate level |
334 | | //////////////////////////////////////////////////////////// |
335 | | int MsWks3Text::getHeader() const |
336 | 60.4k | { |
337 | 91.3k | for (size_t i = 0; i < m_state->m_zones.size(); i++) |
338 | 33.3k | if (m_state->m_zones[i].m_type == MsWks3TextInternal::TextZone::Header) |
339 | 2.45k | return int(i); |
340 | 58.0k | return -1; |
341 | 60.4k | } |
342 | | |
343 | | int MsWks3Text::getFooter() const |
344 | 60.4k | { |
345 | 93.9k | for (size_t i = 0; i < m_state->m_zones.size(); i++) |
346 | 35.3k | if (m_state->m_zones[i].m_type == MsWks3TextInternal::TextZone::Footer) |
347 | 1.85k | return int(i); |
348 | 58.6k | return -1; |
349 | 60.4k | } |
350 | | |
351 | | //////////////////////////////////////////////////////////// |
352 | | // try to find the different zone |
353 | | //////////////////////////////////////////////////////////// |
354 | | int MsWks3Text::createZones(int numLines, bool mainZone) |
355 | 65.2M | { |
356 | 65.2M | MsWks3TextInternal::LineZone zone; |
357 | 65.2M | auto zoneId = int(m_state->m_zones.size()); |
358 | 65.2M | m_state->m_zones.push_back(MsWks3TextInternal::TextZone()); |
359 | 65.2M | auto &actualZone = m_state->m_zones.back(); |
360 | 65.2M | actualZone.m_id = zoneId; |
361 | 65.2M | if (mainZone) |
362 | 54.9k | actualZone.m_type = MsWks3TextInternal::TextZone::Main; |
363 | 65.2M | bool hasNote=false; |
364 | 65.2M | int firstNote=0; |
365 | 65.2M | MWAWInputStreamPtr input=m_document.getInput(); |
366 | 67.2M | while (!input->isEnd()) { |
367 | 65.2M | if (numLines==0) break; |
368 | 65.2M | if (numLines>0) numLines--; |
369 | 65.2M | long pos = input->tell(); |
370 | 65.2M | if (!readZoneHeader(zone)) { |
371 | 63.2M | input->seek(pos, librevenge::RVNG_SEEK_SET); |
372 | 63.2M | break; |
373 | 63.2M | } |
374 | 1.95M | if (!hasNote && zone.isNote()) { |
375 | 10.7k | firstNote = int(actualZone.m_zonesList.size()); |
376 | 10.7k | hasNote = true; |
377 | 10.7k | } |
378 | 1.95M | actualZone.m_zonesList.push_back(zone); |
379 | 1.95M | input->seek(zone.m_pos.end(), librevenge::RVNG_SEEK_SET); |
380 | 1.95M | } |
381 | 65.2M | auto numLineZones = int(actualZone.m_zonesList.size()); |
382 | 65.2M | if (numLineZones == 0) { |
383 | 65.2M | m_state->m_zones.pop_back(); |
384 | 65.2M | return -1; |
385 | 65.2M | } |
386 | | |
387 | 34.5k | update(actualZone); |
388 | 34.5k | if (hasNote) |
389 | 10.7k | updateNotes(actualZone, firstNote); |
390 | 34.5k | return zoneId; |
391 | 65.2M | } |
392 | | |
393 | | void MsWks3Text::update(MsWks3TextInternal::TextZone &zone) |
394 | 34.5k | { |
395 | 34.5k | size_t numLineZones = zone.m_zonesList.size(); |
396 | 34.5k | if (numLineZones == 0) return; |
397 | | |
398 | 34.5k | auto textHeight = int(72.0*m_mainParser->getPageSpan().getPageLength()); |
399 | | |
400 | 34.5k | int actH = 0, actualPH = 0; |
401 | 34.5k | zone.m_linesHeight.push_back(0); |
402 | 1.98M | for (size_t i = 0; i < numLineZones; i++) { |
403 | 1.95M | auto const &z = zone.m_zonesList[i]; |
404 | 1.95M | if (z.isNote()) continue; // a note |
405 | 1.90M | actH += z.m_height; |
406 | 1.90M | zone.m_linesHeight.push_back(actH); |
407 | 1.90M | bool newPage = ((z.m_flags&1) && actualPH) || (z.m_flags&2); |
408 | 1.90M | actualPH += z.m_height; |
409 | 1.90M | if (newPage || (actualPH > textHeight && textHeight > 0)) { |
410 | 34.8k | zone.m_pagesPosition[int(i)]=(z.m_flags&2); |
411 | 34.8k | zone.m_pagesHeight.push_back(actualPH-z.m_height); |
412 | 34.8k | actualPH=z.m_height; |
413 | 34.8k | } |
414 | 1.90M | } |
415 | 34.5k | } |
416 | | |
417 | | void MsWks3Text::updateNotes(MsWks3TextInternal::TextZone &zone, int firstNote) |
418 | 10.7k | { |
419 | 10.7k | auto numLineZones = int(zone.m_zonesList.size()); |
420 | 10.7k | if (firstNote < 0 || firstNote >= numLineZones) { |
421 | 0 | MWAW_DEBUG_MSG(("MsWks3Text::updateNotes: can not find first note position\n")); |
422 | 0 | return; |
423 | 0 | } |
424 | | |
425 | 10.7k | MWAWInputStreamPtr input=m_document.getInput(); |
426 | 10.7k | MsWks3TextInternal::Font font; |
427 | 10.7k | int noteId = -1; |
428 | 10.7k | long lastIndentPos = -1; |
429 | 10.7k | MWAWVec2i notePos; |
430 | | |
431 | 49.1k | for (int n = firstNote; n < numLineZones; n++) { |
432 | 43.8k | auto const &z = zone.m_zonesList[size_t(n)]; |
433 | 43.8k | if (!z.isNote()) { |
434 | 5.42k | noteId=-1; |
435 | 5.42k | MWAW_DEBUG_MSG(("MsWks3Text::updateNotes: find extra data in notes, stop recording note\n")); |
436 | 5.42k | break; |
437 | 5.42k | } |
438 | 38.4k | if (z.isRuler()) { |
439 | 3.40k | lastIndentPos = n; |
440 | 3.40k | continue; |
441 | 3.40k | } |
442 | 35.0k | if (z.m_pos.length() < 8) continue; |
443 | 30.0k | long actPos = z.m_pos.begin(); |
444 | 30.0k | input->seek(actPos+6,librevenge::RVNG_SEEK_SET); |
445 | | |
446 | 30.0k | auto c = static_cast<int>(input->readULong(1)); |
447 | 30.0k | if ((c == 1 || c == 2) && readFont(font, z.m_pos.end())) { |
448 | 7.77k | if (long(input->tell())+2 > z.m_pos.end()) |
449 | 338 | continue; |
450 | 7.43k | c = static_cast<int>(input->readULong(1)); |
451 | 7.43k | if (c <= 4) { |
452 | 4.22k | if (long(input->tell())+2 > z.m_pos.end()) |
453 | 285 | continue; |
454 | 3.94k | c = static_cast<int>(input->readULong(1)); |
455 | 3.94k | } |
456 | 7.43k | } |
457 | 29.4k | if (c != 0x14) continue; |
458 | 17.3k | if (noteId >= 0) { |
459 | 14.2k | notePos[1] = (lastIndentPos != -1) ? int(lastIndentPos) : n; |
460 | 14.2k | if (zone.m_footnoteMap.find(noteId)==zone.m_footnoteMap.end()) |
461 | 9.82k | zone.m_footnoteMap[noteId] = notePos; |
462 | 4.39k | else { |
463 | 4.39k | MWAW_DEBUG_MSG(("MsWks3Text::updateNotes: note %d is already defined, ignored\n", noteId)); |
464 | 4.39k | } |
465 | 14.2k | } |
466 | 17.3k | noteId = static_cast<int>(input->readULong(2)); |
467 | 17.3k | notePos[0] = (lastIndentPos != -1) ? int(lastIndentPos) : n; |
468 | 17.3k | lastIndentPos = -1; |
469 | 17.3k | } |
470 | 10.7k | if (noteId >= 0) { |
471 | 1.94k | notePos[1] = numLineZones; |
472 | 1.94k | if (zone.m_footnoteMap.find(noteId)==zone.m_footnoteMap.end()) |
473 | 1.67k | zone.m_footnoteMap[noteId] = notePos; |
474 | 272 | else { |
475 | 272 | MWAW_DEBUG_MSG(("MsWks3Text::updateNotes: note %d is already defined, ignored\n", noteId)); |
476 | 272 | } |
477 | 1.94k | } |
478 | 10.7k | } |
479 | | |
480 | | bool MsWks3Text::readZoneHeader(MsWks3TextInternal::LineZone &zone) const |
481 | 65.2M | { |
482 | 65.2M | zone = MsWks3TextInternal::LineZone(); |
483 | 65.2M | MWAWInputStreamPtr input=m_document.getInput(); |
484 | 65.2M | long pos = input->tell(); |
485 | 65.2M | if (!input->checkPosition(pos+6)) return false; |
486 | 59.6M | zone.m_pos.setBegin(pos); |
487 | 59.6M | zone.m_type = static_cast<int>(input->readULong(1)); |
488 | 59.6M | if (zone.m_type & 0x17) return false; |
489 | 38.6M | zone.m_id = static_cast<int>(input->readULong(1)); |
490 | 38.6M | zone.m_flags = static_cast<int>(input->readULong(1)); |
491 | 38.6M | zone.m_height = static_cast<int>(input->readULong(1)); |
492 | 38.6M | zone.m_pos.setLength(6+long(input->readULong(2))); |
493 | 38.6M | if (!input->checkPosition(zone.m_pos.end())) return false; |
494 | 1.95M | return true; |
495 | 38.6M | } |
496 | | |
497 | | //////////////////////////////////////////////////////////// |
498 | | // the text: |
499 | | //////////////////////////////////////////////////////////// |
500 | | bool MsWks3Text::sendText(MsWks3TextInternal::LineZone &zone, int zoneId) |
501 | 4.62M | { |
502 | 4.62M | MWAWListenerPtr listener=m_parserState->getMainListener(); |
503 | 4.62M | if (!listener) { |
504 | 0 | MWAW_DEBUG_MSG(("MsWks3Text::sendText: can not find the listener\n")); |
505 | 0 | return true; |
506 | 0 | } |
507 | 4.62M | MWAWInputStreamPtr input=m_document.getInput(); |
508 | 4.62M | input->seek(zone.m_pos.begin()+6, librevenge::RVNG_SEEK_SET); |
509 | 4.62M | int vers = version(); |
510 | 4.62M | libmwaw::DebugFile &ascFile = m_document.ascii(); |
511 | 4.62M | libmwaw::DebugStream f; |
512 | 4.62M | f << "Entries(TextZone):" << zone << ","; |
513 | 4.62M | MsWks3TextInternal::Font font; |
514 | 4.62M | if (zone.m_height > 0) { |
515 | 968k | MWAWParagraph para=listener->getParagraph(); |
516 | 968k | para.setInterline(zone.m_height, librevenge::RVNG_POINT); |
517 | 968k | listener->setParagraph(para); |
518 | 968k | } |
519 | 132M | while (!input->isEnd()) { |
520 | 132M | long pos = input->tell(); |
521 | 132M | if (pos >= zone.m_pos.end()) break; |
522 | 128M | auto c = static_cast<int>(input->readULong(1)); |
523 | 128M | if ((c == 1 || c == 2) && readFont(font, zone.m_pos.end())) { |
524 | 8.02M | listener->setFont(font.m_font); |
525 | 8.02M | f << "[" << font.m_font.getDebugString(m_parserState->m_fontConverter) << font << "]"; |
526 | 8.02M | continue; |
527 | 8.02M | } |
528 | 120M | if (c == 0) { |
529 | 56.0M | f << "#"; |
530 | 56.0M | continue; |
531 | 56.0M | } |
532 | 64.0M | f << char(c); |
533 | 64.0M | switch (c) { |
534 | 1.19M | case 0x9: |
535 | 1.19M | listener->insertTab(); |
536 | 1.19M | break; |
537 | 360k | case 0x10: // cursor pos |
538 | 812k | case 0x11: |
539 | 812k | break; |
540 | 62.0M | default: |
541 | 62.0M | if (c >= 0x14 && c <= 0x19 && vers >= 3) { |
542 | 2.43M | int sz = (c==0x19) ? 0 : (c == 0x18) ? 1 : 2; |
543 | 2.43M | int id = (sz && pos+1+sz <= zone.m_pos.end()) ? int(input->readLong(sz)) : 0; |
544 | 2.43M | if (id) f << "[" << id << "]"; |
545 | 2.43M | switch (c) { |
546 | 125k | case 0x19: |
547 | 125k | listener->insertField(MWAWField(MWAWField::Title)); |
548 | 125k | break; |
549 | 394k | case 0x18: |
550 | 394k | listener->insertField(MWAWField(MWAWField::PageNumber)); |
551 | 394k | break; |
552 | 200k | case 0x16: |
553 | 200k | listener->insertField(MWAWField(MWAWField::Time)); |
554 | 200k | break; |
555 | 228k | case 0x17: // id = 0 : short date ; id=9 : long date |
556 | 228k | listener->insertField(MWAWField(MWAWField::Date)); |
557 | 228k | break; |
558 | 124k | case 0x15: |
559 | 124k | MWAW_DEBUG_MSG(("MsWks3Text::sendText: find unknown field type 0x15\n")); |
560 | 124k | break; |
561 | 1.36M | case 0x14: |
562 | 1.36M | if (!zone.isNote()) { |
563 | 472k | MWAWSubDocumentPtr subdoc |
564 | 472k | (new MsWks3TextInternal::SubDocument(*this, m_document.getInput(), zoneId, id)); |
565 | 472k | listener->insertNote(MWAWNote(MWAWNote::FootNote), subdoc); |
566 | 472k | } |
567 | 1.36M | break; |
568 | 0 | default: |
569 | 0 | break; |
570 | 2.43M | } |
571 | 2.43M | } |
572 | 59.6M | else if (c <= 0x1f) { |
573 | 15.3M | f << "#" << std::hex << c << std::dec << "]"; |
574 | 15.3M | ascFile.addDelimiter(pos,'#'); |
575 | 15.3M | MWAW_DEBUG_MSG(("MsWks3Text::sendText: find char=%x\n", static_cast<unsigned int>(c))); |
576 | 15.3M | } |
577 | 44.3M | else |
578 | 44.3M | listener->insertCharacter(static_cast<unsigned char>(c), input, zone.m_pos.end()); |
579 | 62.0M | break; |
580 | 64.0M | } |
581 | 64.0M | } |
582 | 4.62M | if (listener) |
583 | 4.62M | listener->insertEOL(); |
584 | 4.62M | ascFile.addPos(zone.m_pos.begin()); |
585 | 4.62M | ascFile.addNote(f.str().c_str()); |
586 | 4.62M | return true; |
587 | 4.62M | } |
588 | | |
589 | | bool MsWks3Text::sendString(std::string &str) |
590 | 10.3k | { |
591 | 10.3k | MWAWListenerPtr listener=m_parserState->getMainListener(); |
592 | 10.3k | if (!listener) |
593 | 0 | return true; |
594 | 10.3k | MsWks3TextInternal::Font defFont; |
595 | 10.3k | defFont.m_font = MWAWFont(20,12); |
596 | 10.3k | listener->setFont(defFont.m_font); |
597 | | |
598 | 403k | for (auto c : str) { |
599 | 403k | switch (c) { |
600 | 12.2k | case 0x9: |
601 | 12.2k | listener->insertTab(); |
602 | 12.2k | break; |
603 | 6.29k | case 0x10: // cursor pos |
604 | 15.8k | case 0x11: |
605 | 15.8k | break; |
606 | 4.59k | case 0x19: |
607 | 4.59k | listener->insertField(MWAWField(MWAWField::Title)); |
608 | 4.59k | break; |
609 | 11.9k | case 0x18: |
610 | 11.9k | listener->insertField(MWAWField(MWAWField::PageNumber)); |
611 | 11.9k | break; |
612 | 6.35k | case 0x16: |
613 | 6.35k | listener->insertField(MWAWField(MWAWField::Time)); |
614 | 6.35k | break; |
615 | 17.8k | case 0x17: // id = 0 : short date ; id=9 : long date |
616 | 17.8k | listener->insertField(MWAWField(MWAWField::Date)); |
617 | 17.8k | break; |
618 | 5.40k | case 0x15: |
619 | 5.40k | MWAW_DEBUG_MSG(("MsWks3Text::sendString: find unknown field type 0x15\n")); |
620 | 5.40k | break; |
621 | 10.8k | case 0x14: // fixme |
622 | 10.8k | MWAW_DEBUG_MSG(("MsWks3Text::sendString: footnote are not implemented\n")); |
623 | 10.8k | break; |
624 | 318k | default: |
625 | 318k | listener->insertCharacter(static_cast<unsigned char>(c)); |
626 | 318k | break; |
627 | 403k | } |
628 | 403k | } |
629 | 10.3k | return true; |
630 | 10.3k | } |
631 | | |
632 | | //////////////////////////////////////////////////////////// |
633 | | // the font: |
634 | | //////////////////////////////////////////////////////////// |
635 | | bool MsWks3Text::readFont(MsWks3TextInternal::Font &font, long endPos) |
636 | 8.75M | { |
637 | 8.75M | int vers = version(); |
638 | 8.75M | font = MsWks3TextInternal::Font(); |
639 | 8.75M | MWAWInputStreamPtr input=m_document.getInput(); |
640 | 8.75M | long pos = input->tell(); |
641 | 8.75M | input->seek(-1, librevenge::RVNG_SEEK_CUR); |
642 | 8.75M | auto type = static_cast<int>(input->readLong(1)); |
643 | 8.75M | if ((type != 1 && type != 2) || pos+type+3 > endPos) { |
644 | 719k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
645 | 719k | return false; |
646 | 719k | } |
647 | 8.03M | libmwaw::DebugStream f; |
648 | 8.03M | auto flag = static_cast<int>(input->readULong(1)); // check or font ? |
649 | 8.03M | if (flag) f << "#f0=" << flag << ","; |
650 | 8.03M | font.m_font.setId(static_cast<int>(input->readULong(1))); |
651 | 8.03M | font.m_font.setSize(float(input->readULong(1))); |
652 | 8.03M | flag = static_cast<int>(input->readULong(1)); |
653 | 8.03M | uint32_t flags = 0; |
654 | 8.03M | if (flag & 0x1) flags |= MWAWFont::boldBit; |
655 | 8.03M | if (flag & 0x2) flags |= MWAWFont::italicBit; |
656 | 8.03M | if (flag & 0x4) font.m_font.setUnderlineStyle(MWAWFont::Line::Simple); |
657 | 8.03M | if (flag & 0x8) flags |= MWAWFont::embossBit; |
658 | 8.03M | if (flag & 0x10) flags |= MWAWFont::shadowBit; |
659 | 8.03M | if (flag & 0x20) { |
660 | 1.35M | if (vers==1) |
661 | 19.7k | font.m_font.set(MWAWFont::Script(20,librevenge::RVNG_PERCENT,80)); |
662 | 1.33M | else |
663 | 1.33M | font.m_font.set(MWAWFont::Script::super100()); |
664 | 1.35M | } |
665 | 8.03M | if (flag & 0x40) { |
666 | 1.90M | if (vers==1) |
667 | 20.0k | font.m_font.set(MWAWFont::Script(-20,librevenge::RVNG_PERCENT,80)); |
668 | 1.88M | else |
669 | 1.88M | font.m_font.set(MWAWFont::Script::sub100()); |
670 | 1.90M | } |
671 | 8.03M | if ((flag & 0x80) && !(flag & 0x60)) f << "fFl80#,"; |
672 | 8.03M | font.m_font.setFlags(flags); |
673 | 8.03M | int color = 1; |
674 | 8.03M | if (type == 2) { |
675 | 3.35M | color=static_cast<int>(input->readULong(1)); |
676 | 3.35M | } |
677 | 4.68M | else if (pos+type+5 <= endPos) { |
678 | 4.61M | auto val = static_cast<int>(input->readULong(1)); |
679 | 4.61M | if (val == 0) |
680 | 1.72M | f << "end0#,"; |
681 | 2.88M | else |
682 | 2.88M | input->seek(-1, librevenge::RVNG_SEEK_CUR); |
683 | 4.61M | } |
684 | 8.03M | if (color != 1) { |
685 | 3.25M | MWAWColor col; |
686 | 3.25M | if (m_document.getColor(color,col,vers)) |
687 | 3.16M | font.m_font.setColor(col); |
688 | 93.4k | else |
689 | 93.4k | f << "#fColor=" << color << ","; |
690 | 3.25M | } |
691 | 8.03M | font.m_extra = f.str(); |
692 | 8.03M | return true; |
693 | 8.75M | } |
694 | | |
695 | | //////////////////////////////////////////////////////////// |
696 | | // the tabulations: |
697 | | //////////////////////////////////////////////////////////// |
698 | | bool MsWks3Text::readParagraph(MsWks3TextInternal::LineZone &zone, MWAWParagraph ¶g) |
699 | 780k | { |
700 | 780k | int dataSize = int(zone.m_pos.length())-6; |
701 | 780k | if (dataSize < 15) return false; |
702 | 733k | MWAWInputStreamPtr input=m_document.getInput(); |
703 | 733k | input->seek(zone.m_pos.begin()+6, librevenge::RVNG_SEEK_SET); |
704 | | |
705 | 733k | parag = MWAWParagraph(); |
706 | 733k | libmwaw::DebugFile &ascFile = m_document.ascii(); |
707 | 733k | libmwaw::DebugStream f; |
708 | | |
709 | 733k | int fl[2]; |
710 | 733k | bool firstFlag = (dataSize & 1) == 0; |
711 | 733k | fl[0] = firstFlag ? static_cast<int>(input->readULong(1)) : 0x4c; |
712 | 733k | switch (fl[0]) { |
713 | 149k | case 0x4c: |
714 | 149k | break; |
715 | 15.0k | case 0x43: |
716 | 15.0k | parag.m_justify = MWAWParagraph::JustificationCenter; |
717 | 15.0k | break; |
718 | 14.3k | case 0x52: |
719 | 14.3k | parag.m_justify = MWAWParagraph::JustificationRight; |
720 | 14.3k | break; |
721 | 18.9k | case 0x46: |
722 | 18.9k | parag.m_justify = MWAWParagraph::JustificationFull; |
723 | 18.9k | break; |
724 | 535k | default: |
725 | 535k | f << "#align=" << std::hex << fl[0] << ","; |
726 | 535k | MWAW_DEBUG_MSG(("MsWks3Text::readParagraph: unknown alignment %x\n", static_cast<unsigned int>(fl[0]))); |
727 | 535k | break; |
728 | 733k | } |
729 | 733k | fl[1] = static_cast<int>(input->readULong(1)); |
730 | 733k | if (fl[1]) |
731 | 618k | f << "fl0=" <<fl[1] << std::dec << ","; |
732 | 733k | int dim[3]; |
733 | 733k | bool ok = true; |
734 | 2.93M | for (int i = 0; i < 3; i++) { |
735 | 2.19M | dim[i] = static_cast<int>(input->readULong(2)); |
736 | 2.19M | if (i==0&&(dim[0]&0x8000)) { |
737 | 63.1k | dim[0] &= 0x7FFF; |
738 | 63.1k | f << "6linesByInches,"; |
739 | 63.1k | } |
740 | 2.19M | if (dim[i] > 3000) ok = false; |
741 | 2.19M | } |
742 | 733k | if (!ok) { |
743 | 570k | MWAW_DEBUG_MSG(("MsWks3Text::readParagraph: size is very odd\n")); |
744 | 570k | f << "##"; |
745 | 570k | } |
746 | 733k | if (dim[0] || dim[1] || dim[2]) { |
747 | 702k | f << "size=" << dim[1] << "x" << dim[0]; |
748 | 702k | if (dim[2]) f << "[" << dim[2] << "]"; |
749 | 702k | f << ","; |
750 | 702k | } |
751 | | |
752 | 733k | int fl2[2]; |
753 | 733k | for (auto &flag : fl2) // between -16 and 16 |
754 | 1.46M | flag = static_cast<int>(input->readULong(1)); |
755 | 733k | if (fl2[0] || fl2[1]) |
756 | 300k | f << "fl2=(" << std::hex << fl2[0] << ", " <<fl2[1] << ")" << std::dec << ","; |
757 | | |
758 | 2.93M | for (int i = 0; i < 3; i++) { |
759 | 2.19M | auto val = static_cast<int>(input->readULong(2)); |
760 | 2.19M | int flag = (val & 0xc000) >> 14; |
761 | 2.19M | val = (val & 0x3fff); |
762 | 2.19M | if (val > 8000 || flag) { |
763 | 968k | MWAW_DEBUG_MSG(("MsWks3Text::readParagraph: find odd margin %d\n", i)); |
764 | 968k | f << "#margin" << i << "=" << val << "(" << flag << "),"; |
765 | 968k | } |
766 | 2.19M | if (val > 8000) continue; |
767 | | // i = 0 (last), i = 1 (firstL), i=2 (nextL) |
768 | 1.71M | parag.m_margins[2-i] = val/72.0; |
769 | 1.71M | } |
770 | 733k | *(parag.m_margins[0]) -= *(parag.m_margins[1]); |
771 | 733k | if (parag.m_margins[2].get() > 0.0) |
772 | 504k | parag.m_margins[2] = m_mainParser->getPageWidth()-*(parag.m_margins[2]); |
773 | 733k | if (parag.m_margins[2].get() > 56./72.) *(parag.m_margins[2]) -= 28./72.; |
774 | 340k | else if (parag.m_margins[2].get() >=0.0) *(parag.m_margins[2]) *= 0.5; |
775 | 111k | else parag.m_margins[2] = 0.0; |
776 | 733k | int numVal = (dataSize-9)/2-3; |
777 | 733k | parag.m_tabs->resize(size_t(numVal)); |
778 | 733k | size_t numTabs = 0; |
779 | | |
780 | | // checkme: in order to avoid x_tabs > textWidth (appears sometimes when i=0) |
781 | 733k | auto maxWidth = long(m_mainParser->getPageWidth()*72-36); |
782 | 733k | if (dim[1] > maxWidth) maxWidth = dim[1]; |
783 | | |
784 | 65.6M | for (int i = 0; i < numVal; i++) { |
785 | 64.9M | auto val = static_cast<int>(input->readULong(2)); |
786 | 64.9M | MWAWTabStop::Alignment align = MWAWTabStop::LEFT; |
787 | 64.9M | switch (val >> 14) { |
788 | 2.93M | case 1: |
789 | 2.93M | align = MWAWTabStop::DECIMAL; |
790 | 2.93M | break; |
791 | 3.67M | case 2: |
792 | 3.67M | align = MWAWTabStop::RIGHT; |
793 | 3.67M | break; |
794 | 3.65M | case 3: |
795 | 3.65M | align = MWAWTabStop::CENTER; |
796 | 3.65M | break; |
797 | 54.7M | default: |
798 | 54.7M | break; |
799 | 64.9M | } |
800 | 64.9M | val = (val & 0x3fff); |
801 | 64.9M | if (val > maxWidth) { |
802 | 7.47M | static bool first = true; |
803 | 7.47M | if (first) { |
804 | 34 | MWAW_DEBUG_MSG(("MsWks3Text::readParagraph: finds some odd tabs (ignored)\n")); |
805 | 34 | first = false; |
806 | 34 | } |
807 | 7.47M | f << "#tabs" << i << "=" << val << ","; |
808 | 7.47M | continue; |
809 | 7.47M | } |
810 | 57.4M | (*parag.m_tabs)[numTabs].m_alignment = align; |
811 | 57.4M | (*parag.m_tabs)[numTabs++].m_position = val/72.0; |
812 | 57.4M | } |
813 | 733k | if (int(numTabs)!=numVal) parag.m_tabs->resize(numTabs); |
814 | 733k | parag.m_extra = f.str(); |
815 | | |
816 | 733k | f.str(""); |
817 | 733k | f << "Entries(Paragraph):" << zone << "," << parag << ","; |
818 | 733k | ascFile.addPos(zone.m_pos.begin()); |
819 | 733k | ascFile.addNote(f.str().c_str()); |
820 | | |
821 | 733k | return true; |
822 | 733k | } |
823 | | |
824 | | //////////////////////////////////////////////////////////// |
825 | | // read v1-v2 header/footer string |
826 | | //////////////////////////////////////////////////////////// |
827 | | std::string MsWks3Text::readHeaderFooterString(bool header) |
828 | 13.8k | { |
829 | 13.8k | std::string res(""); |
830 | 13.8k | MWAWInputStreamPtr input=m_document.getInput(); |
831 | 13.8k | auto numChar = static_cast<int>(input->readULong(1)); |
832 | 13.8k | if (!numChar) return res; |
833 | 10.3k | if (!input->checkPosition(input->tell()+numChar)) { |
834 | 947 | MWAW_DEBUG_MSG(("MsWks3Text::readHeaderFooterString: the number of char seems bad\n")); |
835 | 947 | return res; |
836 | 947 | } |
837 | 340k | for (int i = 0; i < numChar; i++) { |
838 | 337k | auto c = static_cast<unsigned char>(input->readULong(1)); |
839 | 337k | if (c == 0) { |
840 | 6.75k | input->seek(-1, librevenge::RVNG_SEEK_CUR); |
841 | 6.75k | break; |
842 | 6.75k | } |
843 | 331k | if (c == '&') { |
844 | 18.0k | auto nextC = static_cast<unsigned char>(input->readULong(1)); |
845 | 18.0k | bool field = true; |
846 | 18.0k | switch (nextC) { |
847 | 132 | case 'F': |
848 | 132 | res += char(0x19); |
849 | 132 | break; // file name |
850 | 2.39k | case 'D': |
851 | 2.39k | res += char(0x17); |
852 | 2.39k | break; // date |
853 | 1.27k | case 'P': |
854 | 1.27k | res += char(0x18); |
855 | 1.27k | break; // page |
856 | 4.37k | case 'T': |
857 | 4.37k | res += char(0x16); |
858 | 4.37k | break; // time |
859 | 9.90k | default: |
860 | 9.90k | field = false; |
861 | 18.0k | } |
862 | 18.0k | if (field) continue; |
863 | 9.90k | input->seek(-1, librevenge::RVNG_SEEK_CUR); |
864 | 9.90k | } |
865 | 322k | res += char(c); |
866 | 322k | } |
867 | 9.44k | if (res.length()) { |
868 | 9.01k | m_state->m_zones.push_back(MsWks3TextInternal::TextZone()); |
869 | 9.01k | auto &zone = m_state->m_zones.back(); |
870 | 9.01k | zone.m_id = int(m_state->m_zones.size())-1; |
871 | 9.01k | zone.m_type = header ? MsWks3TextInternal::TextZone::Header : |
872 | 9.01k | MsWks3TextInternal::TextZone::Footer; |
873 | 9.01k | zone.m_text = res; |
874 | 9.01k | } |
875 | 9.44k | return res; |
876 | 9.44k | } |
877 | | |
878 | | //////////////////////////////////////////////////////////// |
879 | | // |
880 | | // Low level |
881 | | // |
882 | | //////////////////////////////////////////////////////////// |
883 | | void MsWks3Text::send(MsWks3TextInternal::TextZone &zone, MWAWVec2i limit) |
884 | 1.44M | { |
885 | 1.44M | auto numZones = int(zone.m_zonesList.size()); |
886 | | // set the default font |
887 | 1.44M | if (m_parserState->getMainListener()) |
888 | 1.44M | m_parserState->getMainListener()->setFont(MWAWFont(20,12)); |
889 | 1.44M | if (numZones == 0 && zone.m_text.length()) { |
890 | 10.3k | sendString(zone.m_text); |
891 | 10.3k | zone.m_isSent = true; |
892 | 10.3k | return; |
893 | 10.3k | } |
894 | 1.43M | bool isMain = false; |
895 | 1.43M | MWAWVec2i notePos(-1, -1); |
896 | 1.43M | if (limit[0] < 0) { |
897 | 1.30M | limit = MWAWVec2i(0,numZones); |
898 | 1.30M | isMain = zone.isMain(); |
899 | | // find the notes in the text zones |
900 | 1.30M | for (auto const ¬eIt : zone.m_footnoteMap) { |
901 | 644k | if (notePos[0]==-1) { |
902 | 174k | notePos = noteIt.second; |
903 | 174k | continue; |
904 | 174k | } |
905 | 470k | if (notePos[0] > noteIt.second[0]) |
906 | 170k | notePos[0] = noteIt.second[0]; |
907 | 470k | if (notePos[1] < noteIt.second[1]) |
908 | 114k | notePos[1] = noteIt.second[1]; |
909 | 470k | } |
910 | 1.30M | } |
911 | | |
912 | 7.01M | for (int i = limit[0]; i < limit[1]; i++) { |
913 | 5.58M | if (i == notePos[0]) { |
914 | 174k | i = notePos[1]-1; |
915 | 174k | continue; |
916 | 174k | } |
917 | 5.40M | if (isMain && zone.m_pagesPosition.find(i) != zone.m_pagesPosition.end()) { |
918 | 28.6k | ++m_state->m_actualPage; |
919 | 28.6k | m_document.newPage(m_state->m_actualPage, zone.m_pagesPosition[i]); |
920 | 28.6k | } |
921 | 5.40M | auto &z = zone.m_zonesList[size_t(i)]; |
922 | 5.40M | if (z.m_type & 0x80) { |
923 | 780k | MWAWParagraph parag; |
924 | 780k | if (readParagraph(z, parag) && m_parserState->getMainListener()) |
925 | 733k | m_parserState->getMainListener()->setParagraph(parag); |
926 | 780k | } |
927 | 4.62M | else |
928 | 4.62M | sendText(z, zone.m_id); |
929 | 5.40M | } |
930 | 1.43M | zone.m_isSent = true; |
931 | 1.43M | } |
932 | | |
933 | | void MsWks3Text::sendNote(int zoneId, int noteId) |
934 | 472k | { |
935 | 472k | MWAWListenerPtr listener=m_parserState->getMainListener(); |
936 | 472k | if (zoneId < 0 || zoneId >= int(m_state->m_zones.size())) { |
937 | 0 | if (listener) listener->insertChar(' '); |
938 | 0 | MWAW_DEBUG_MSG(("MsWks3Text::sendNote: unknown zone %d\n", zoneId)); |
939 | 0 | return; |
940 | 0 | } |
941 | 472k | auto &zone=m_state->m_zones[size_t(zoneId)]; |
942 | 472k | auto noteIt = zone.m_footnoteMap.find(noteId); |
943 | 472k | if (noteIt==zone.m_footnoteMap.end()) { |
944 | 335k | MWAW_DEBUG_MSG(("MsWks3Text::sendNote: unknown note %d-%d\n", zoneId, noteId)); |
945 | 335k | if (listener) listener->insertChar(' '); |
946 | 335k | } |
947 | 136k | else |
948 | 136k | send(zone, noteIt->second); |
949 | 472k | } |
950 | | |
951 | | void MsWks3Text::sendZone(int zoneId) |
952 | 1.30M | { |
953 | 1.30M | if (zoneId < 0 || zoneId >= int(m_state->m_zones.size())) { |
954 | 0 | MWAW_DEBUG_MSG(("MsWks3Text::sendZone: unknown zone %d\n", zoneId)); |
955 | 0 | return; |
956 | 0 | } |
957 | 1.30M | send(m_state->m_zones[size_t(zoneId)]); |
958 | 1.30M | } |
959 | | |
960 | | |
961 | | void MsWks3Text::flushExtra() |
962 | 54.9k | { |
963 | 54.9k | for (auto &zone : m_state->m_zones) { |
964 | 34.1k | if (zone.m_isSent) |
965 | 24.9k | continue; |
966 | 9.19k | send(zone); |
967 | 9.19k | } |
968 | 54.9k | } |
969 | | |
970 | | // vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: |