/src/libwps/src/lib/WPSTextParser.cpp
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ |
2 | | /* libwps |
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) 2009, 2011 Alonso Laurent (alonso@loria.fr) |
11 | | * Copyright (C) 2006, 2007 Andrew Ziem |
12 | | * Copyright (C) 2004-2006 Fridrich Strba (fridrich.strba@bluewin.ch) |
13 | | * Copyright (C) 2004 Marc Maurer (uwog@uwog.net) |
14 | | * Copyright (C) 2003-2005 William Lachance (william.lachance@sympatico.ca) |
15 | | * |
16 | | * For minor contributions see the git repository. |
17 | | * |
18 | | * Alternatively, the contents of this file may be used under the terms |
19 | | * of the GNU Lesser General Public License Version 2.1 or later |
20 | | * (LGPLv2.1+), in which case the provisions of the LGPLv2.1+ are |
21 | | * applicable instead of those above. |
22 | | * |
23 | | * For further information visit http://libwps.sourceforge.net |
24 | | */ |
25 | | |
26 | | #include <stdlib.h> |
27 | | #include <string.h> |
28 | | |
29 | | #include "libwps_internal.h" |
30 | | |
31 | | #include "WPSParser.h" |
32 | | |
33 | | #include "WPSTextParser.h" |
34 | | |
35 | | //////////////////////////////////////////////////////////// |
36 | | // Constructor |
37 | | //////////////////////////////////////////////////////////// |
38 | | WPSTextParser::WPSTextParser(WPSParser &parser, RVNGInputStreamPtr &input) |
39 | 17.2k | : m_version(0) |
40 | 17.2k | , m_input(input) |
41 | 17.2k | , m_mainParser(parser) |
42 | 17.2k | , m_textPositions(), |
43 | 17.2k | m_FODList() |
44 | 17.2k | , m_asciiFile(parser.ascii()) |
45 | 17.2k | { |
46 | 17.2k | } |
47 | | |
48 | 17.2k | WPSTextParser::~WPSTextParser() {} |
49 | | |
50 | | |
51 | | int WPSTextParser::version() const |
52 | 16.4M | { |
53 | 16.4M | if (m_version <= 0) |
54 | 7.77k | m_version=m_mainParser.version(); |
55 | 16.4M | return m_version; |
56 | 16.4M | } |
57 | | |
58 | | WPSParser::NameMultiMap &WPSTextParser::getNameEntryMap() |
59 | 3.45M | { |
60 | 3.45M | return m_mainParser.getNameEntryMap(); |
61 | 3.45M | } |
62 | | |
63 | | WPSParser::NameMultiMap const &WPSTextParser::getNameEntryMap() const |
64 | 6.02k | { |
65 | 6.02k | return m_mainParser.getNameEntryMap(); |
66 | 6.02k | } |
67 | | |
68 | | //////////////////////////////////////////////////////////// |
69 | | // read data |
70 | | //////////////////////////////////////////////////////////// |
71 | | bool WPSTextParser::readFDP(WPSEntry const &entry, |
72 | | std::vector<DataFOD> &fods, |
73 | | WPSTextParser::FDPParser parser) |
74 | 2.55M | { |
75 | 2.55M | RVNGInputStreamPtr input = getInput(); |
76 | 2.55M | if (entry.length() <= 0 || entry.begin() <= 0) |
77 | 439k | { |
78 | 439k | WPS_DEBUG_MSG(("WPSTextParser::readFDP: warning: FDP entry unintialized\n")); |
79 | 439k | return false; |
80 | 439k | } |
81 | | |
82 | 2.11M | entry.setParsed(); |
83 | 2.11M | long page_offset = entry.begin(); |
84 | 2.11M | long length = entry.length(); |
85 | 2.11M | long endPage = entry.end(); |
86 | | |
87 | 2.11M | bool smallFDP = version() < 5; |
88 | 2.11M | int deplSize = smallFDP ? 1 : 2; |
89 | 2.11M | int headerSize = smallFDP ? 4 : 8; |
90 | | |
91 | 2.11M | if (length < headerSize) |
92 | 13.6k | { |
93 | 13.6k | WPS_DEBUG_MSG(("WPSTextParser::readFDP: warning: FDP offset=0x%lx, length=0x%lx\n", |
94 | 13.6k | static_cast<unsigned long>(page_offset), static_cast<unsigned long>(length))); |
95 | 13.6k | return false; |
96 | 13.6k | } |
97 | | |
98 | 2.10M | libwps::DebugStream f, f2; |
99 | 2.10M | if (smallFDP) |
100 | 48.0k | { |
101 | 48.0k | endPage--; |
102 | 48.0k | input->seek(endPage, librevenge::RVNG_SEEK_SET); |
103 | 48.0k | } |
104 | 2.05M | else |
105 | 2.05M | input->seek(page_offset, librevenge::RVNG_SEEK_SET); |
106 | 2.10M | uint16_t cfod = deplSize == 1 ? uint16_t(libwps::readU8(m_input)) : libwps::readU16(m_input); |
107 | | |
108 | 2.10M | f << "FDP: N="<<int(cfod); |
109 | 2.10M | if (smallFDP) input->seek(page_offset, librevenge::RVNG_SEEK_SET); |
110 | 2.05M | else f << ", unk=" << libwps::read16(m_input); |
111 | | |
112 | 2.10M | if (headerSize+(4+deplSize)*static_cast<long>(cfod) > length) |
113 | 120k | { |
114 | 120k | WPS_DEBUG_MSG(("WPSTextParser::readFDP: error: cfod = %i (0x%X)\n", cfod, unsigned(cfod))); |
115 | 120k | return false; |
116 | 120k | } |
117 | | |
118 | 1.98M | auto firstFod = int(fods.size()); |
119 | 1.98M | long lastLimit = firstFod ? fods.back().m_pos : 0; |
120 | | |
121 | 1.98M | long lastReadPos = 0L; |
122 | | |
123 | 1.98M | DataFOD::Type type = DataFOD::ATTR_UNKN; |
124 | 1.98M | if (entry.hasType("FDPC")) type = DataFOD::ATTR_TEXT; |
125 | 1.16M | else if (entry.hasType("FDPP")) type = DataFOD::ATTR_PARAG; |
126 | 86 | else |
127 | 86 | { |
128 | 86 | WPS_DEBUG_MSG(("WPSTextParser::readFDP: FDP error: unknown type = '%s'\n", entry.type().c_str())); |
129 | 86 | } |
130 | | |
131 | | /* Read array of fcLim of FODs. The fcLim refers to the offset of the |
132 | | last character covered by the formatting. */ |
133 | 6.14M | for (int i = 0; i <= cfod; ++i) |
134 | 4.25M | { |
135 | 4.25M | DataFOD fod; |
136 | 4.25M | fod.m_type = type; |
137 | 4.25M | fod.m_pos = long(libwps::readU32(m_input)); |
138 | 4.25M | if (fod.m_pos == 0) fod.m_pos=m_textPositions.begin(); |
139 | | |
140 | | /* check that fcLim is not too large */ |
141 | 4.25M | if (fod.m_pos > m_textPositions.end()) |
142 | 75.7k | { |
143 | 75.7k | WPS_DEBUG_MSG(("WPSTextParser::readFDP: error: length of 'text selection' %ld > " |
144 | 75.7k | "total text length %ld\n", fod.m_pos, m_textPositions.end())); |
145 | 75.7k | return false; |
146 | 75.7k | } |
147 | | |
148 | | /* check that pos is monotonic */ |
149 | 4.18M | if (lastLimit > fod.m_pos) |
150 | 23.3k | { |
151 | 23.3k | WPS_DEBUG_MSG(("WPSTextParser::readFDP: error: character position list must " |
152 | 23.3k | "be monotonic, but found %ld, %ld\n", lastLimit, fod.m_pos)); |
153 | 23.3k | return false; |
154 | 23.3k | } |
155 | | |
156 | 4.15M | lastLimit = fod.m_pos; |
157 | | |
158 | 4.15M | if (i != cfod) |
159 | 2.27M | fods.push_back(fod); |
160 | 1.88M | else // ignore the last text position |
161 | 1.88M | lastReadPos = fod.m_pos; |
162 | 4.15M | } |
163 | | |
164 | 1.88M | std::vector<DataFOD>::iterator fods_iter; |
165 | | /* Read array of bfprop of FODs. The bfprop is the offset where |
166 | | the FPROP is located. */ |
167 | 1.88M | f << ", Tpos:defP=("; |
168 | 3.90M | for (fods_iter = fods.begin() + firstFod; fods_iter!= fods.end(); ++fods_iter) |
169 | 2.06M | { |
170 | 2.06M | unsigned depl = deplSize == 1 ? libwps::readU8(m_input) : libwps::readU16(m_input); |
171 | | /* check size of bfprop */ |
172 | 2.06M | if ((depl < unsigned(headerSize+(4+deplSize)*cfod) && depl > 0) || |
173 | 2.05M | page_offset+long(depl) > endPage) |
174 | 36.3k | { |
175 | 36.3k | WPS_DEBUG_MSG(("WPSTextParser::readFDP: error: pos of bfprop is bad " |
176 | 36.3k | "%u (0x%X)\n", depl, depl)); |
177 | 36.3k | return false; |
178 | 36.3k | } |
179 | | |
180 | 2.02M | if (depl) |
181 | 1.95M | (*fods_iter).m_defPos = long(depl) + page_offset; |
182 | 2.02M | } |
183 | 1.84M | ascii().addPos(input->tell()); |
184 | | |
185 | 1.84M | std::map<long,int> mapPtr; |
186 | 1.84M | bool smallSzInProp = smallFDP; |
187 | 3.74M | for (fods_iter = fods.begin() + firstFod; fods_iter!= fods.end(); ++fods_iter) |
188 | 1.98M | { |
189 | 1.98M | long pos = (*fods_iter).m_defPos; |
190 | 1.98M | f << std::hex << (*fods_iter).m_pos << std::dec << ":"; |
191 | 1.98M | if (pos == 0) |
192 | 64.0k | { |
193 | 64.0k | f << "_, "; |
194 | 64.0k | continue; |
195 | 64.0k | } |
196 | | |
197 | 1.92M | auto it= mapPtr.find(pos); |
198 | 1.92M | if (it != mapPtr.end()) |
199 | 61.4k | { |
200 | 61.4k | (*fods_iter).m_id = mapPtr[pos]; |
201 | 61.4k | f << entry.type() << (*fods_iter).m_id << ", "; |
202 | 61.4k | continue; |
203 | 61.4k | } |
204 | | |
205 | 1.86M | input->seek(pos, librevenge::RVNG_SEEK_SET); |
206 | 1.86M | int szProp = smallSzInProp ? libwps::readU8(m_input) : libwps::readU16(m_input); |
207 | 1.86M | if (smallSzInProp) szProp++; |
208 | 1.86M | if (szProp == 0) |
209 | 54.5k | { |
210 | 54.5k | WPS_DEBUG_MSG(("WPSTextParser::readFDP: error: 0 == szProp at file offset 0x%lx\n", static_cast<unsigned long>(input->tell()-1))); |
211 | 54.5k | return false; |
212 | 54.5k | } |
213 | 1.80M | long endPos = pos+szProp; |
214 | 1.80M | if (endPos > endPage) |
215 | 33.2k | { |
216 | 33.2k | WPS_DEBUG_MSG(("WPSTextParser::readFDP: error: cch = %d, too large\n", szProp)); |
217 | 33.2k | return false; |
218 | 33.2k | } |
219 | | |
220 | 1.77M | int id=0; |
221 | 1.77M | std::string mess; |
222 | 1.77M | if (parser &&(this->*parser)(endPos, id, mess)) |
223 | 1.72M | { |
224 | 1.72M | (*fods_iter).m_id = mapPtr[pos] = id; |
225 | | |
226 | 1.72M | f2.str(""); |
227 | 1.72M | f2 << entry.type() << id <<":" << mess; |
228 | 1.72M | ascii().addPos(pos); |
229 | 1.72M | ascii().addNote(f2.str().c_str()); |
230 | 1.72M | pos = input->tell(); |
231 | 1.72M | } |
232 | 1.77M | f << entry.type() << (*fods_iter).m_id << ", "; |
233 | 1.77M | if (pos != endPos) |
234 | 83.6k | { |
235 | 83.6k | f2.str(""); |
236 | 83.6k | f2 << entry.type() << "###"; |
237 | 83.6k | ascii().addPos(pos); |
238 | 83.6k | ascii().addNote(f2.str().c_str()); |
239 | 83.6k | } |
240 | 1.77M | } |
241 | 1.75M | f << "), lstPos=" << std::hex << lastReadPos << std::dec << ", "; |
242 | | |
243 | 1.75M | ascii().addPos(page_offset); |
244 | 1.75M | ascii().addNote(f.str().c_str()); |
245 | | |
246 | | /* go to end of page */ |
247 | 1.75M | input->seek(endPage, librevenge::RVNG_SEEK_SET); |
248 | | |
249 | 1.75M | return m_textPositions.end() > lastReadPos; |
250 | 1.84M | } |
251 | | |
252 | | std::vector<WPSTextParser::DataFOD> WPSTextParser::mergeSortedFODLists |
253 | | (std::vector<WPSTextParser::DataFOD> const &lst1, |
254 | | std::vector<WPSTextParser::DataFOD> const &lst2) const |
255 | 1.04M | { |
256 | 1.04M | std::vector<WPSTextParser::DataFOD> res; |
257 | | // we regroup these two lists in one list |
258 | 1.04M | size_t num1 = lst1.size(), i1 = 0; |
259 | 1.04M | size_t num2 = lst2.size(), i2 = 0; |
260 | | |
261 | 646M | while (i1 < num1 || i2 < num2) |
262 | 645M | { |
263 | 645M | DataFOD val; |
264 | 645M | if (i2 == num2) val = lst1[i1++]; |
265 | 644M | else if (i1 == num1 || lst2[i2].m_pos < lst1[i1].m_pos) |
266 | 7.55M | val = lst2[i2++]; |
267 | 637M | else val = lst1[i1++]; |
268 | | |
269 | 645M | if (val.m_pos < m_textPositions.begin() || val.m_pos > m_textPositions.end()) |
270 | 6.60M | continue; |
271 | | |
272 | 638M | res.push_back(val); |
273 | 638M | } |
274 | 1.04M | return res; |
275 | 1.04M | } |
276 | | /* vim:set shiftwidth=4 softtabstop=4 noexpandtab: */ |