/src/libwps/src/lib/WPS8Struct.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 "WPS8Struct.h" |
27 | | |
28 | | #include "WPSDebug.h" |
29 | | |
30 | | namespace WPS8Struct |
31 | | { |
32 | | // try to read a block, which can be or not a list of data |
33 | | bool FileData::readArrayBlock() const |
34 | 20.3k | { |
35 | 20.3k | if (isRead()) return isArray(); |
36 | 20.3k | long actPos = m_input->tell(); |
37 | 20.3k | m_input->seek(m_beginOffset, librevenge::RVNG_SEEK_SET); |
38 | 20.3k | std::string error; |
39 | 20.3k | bool ok = readBlockData(m_input, m_endOffset, const_cast<FileData &>(*this), error); |
40 | 20.3k | m_input->seek(actPos, librevenge::RVNG_SEEK_SET); |
41 | 20.3k | return ok; |
42 | 20.3k | } |
43 | | |
44 | | // create a message to store unparsed data |
45 | | std::string FileData::createErrorString(RVNGInputStreamPtr input, long endPos) |
46 | 184k | { |
47 | 184k | libwps::DebugStream f; |
48 | 184k | f << ",###unread=(" << std::hex; |
49 | 184k | while (input->tell() < endPos-1) f << libwps::readU16(input) << ", "; |
50 | 184k | if (input->tell() < endPos) f << libwps::readU8(input) << ", "; |
51 | 184k | f << ")"; |
52 | | |
53 | 184k | return f.str(); |
54 | 184k | } |
55 | | |
56 | | bool FileData::getBorderStyles(WPSBorder::Style &style, WPSBorder::Type &borderType, std::string &mess) const |
57 | 186k | { |
58 | 186k | style = WPSBorder::Simple; |
59 | 186k | borderType = WPSBorder::Single; |
60 | 186k | libwps::DebugStream f; |
61 | 186k | switch (m_value) |
62 | 186k | { |
63 | 8.05k | case 0: |
64 | 8.05k | style = WPSBorder::None; |
65 | 8.05k | break; |
66 | 4.25k | case 1: // normal |
67 | 4.25k | break; |
68 | 10.4k | case 2: // double normal |
69 | 10.4k | borderType = WPSBorder::Double; |
70 | 10.4k | break; |
71 | 22.6k | case 3: |
72 | 22.6k | f << "ext=2,int=1,"; |
73 | 22.6k | borderType = WPSBorder::Double; |
74 | 22.6k | break; |
75 | 16.2k | case 4: |
76 | 16.2k | f << "ext=1,int=2,"; |
77 | 16.2k | borderType = WPSBorder::Double; |
78 | 16.2k | break; |
79 | 27.2k | case 5: |
80 | 27.2k | style = WPSBorder::Dash; |
81 | 27.2k | break; |
82 | 14.9k | case 6: |
83 | 14.9k | style = WPSBorder::LargeDot; |
84 | 14.9k | break; |
85 | 25.7k | case 7: |
86 | 25.7k | style = WPSBorder::Dot; |
87 | 25.7k | break; |
88 | 21.5k | case 8: |
89 | 21.5k | f << "dash+rot-5,"; |
90 | 21.5k | style = WPSBorder::Dash; |
91 | 21.5k | break; |
92 | 9.91k | case 9: |
93 | 9.91k | f << "dash+rot5,"; |
94 | 9.91k | style = WPSBorder::Dash; |
95 | 9.91k | break; |
96 | 10.3k | case 0xa: |
97 | 10.3k | f << "triple,"; |
98 | 10.3k | borderType = WPSBorder::Triple; |
99 | 10.3k | break; |
100 | 15.5k | default: |
101 | 15.5k | f << "#style=" << std::hex << m_value << std::dec << ","; |
102 | 15.5k | break; |
103 | 186k | } |
104 | | |
105 | 186k | mess = f.str(); |
106 | 186k | return true; |
107 | 186k | } |
108 | | |
109 | | // operator << |
110 | | std::ostream &operator<< (std::ostream &o, FileData const &dt) |
111 | 0 | { |
112 | 0 | if (dt.id() != -1) |
113 | 0 | o << "unkn" << std::hex << dt.id() << "[typ=" << dt.m_type << "]:" << std::dec; |
114 | 0 | auto &DT = const_cast<FileData &>(dt); |
115 | | // If the data are unread, try to read them as a block list |
116 | 0 | if (!dt.isRead() && !dt.readArrayBlock()) |
117 | 0 | { |
118 | | // if this fails... |
119 | 0 | long size = dt.m_endOffset-dt.m_beginOffset-2; |
120 | 0 | int sz = (size%4) == 0 ? 4 : (size%2) == 0 ? 2 : 1; |
121 | 0 | auto numElt = int(size/sz); |
122 | |
|
123 | 0 | long actPos = DT.m_input->tell(); |
124 | 0 | DT.m_input->seek(dt.m_beginOffset, librevenge::RVNG_SEEK_SET); |
125 | 0 | o << "###FAILS[sz="<< sz << "]=(" << std::hex; |
126 | 0 | auto val = long(libwps::read16(DT.m_input)); |
127 | 0 | if (val) o << "unkn=" << val <<","; |
128 | 0 | for (int i = 0; i < numElt; i++) |
129 | 0 | { |
130 | 0 | switch (sz) |
131 | 0 | { |
132 | 0 | case 1: |
133 | 0 | o << libwps::readU8(DT.m_input) << ","; |
134 | 0 | break; |
135 | 0 | case 2: |
136 | 0 | o << libwps::readU16(DT.m_input) << ","; |
137 | 0 | break; |
138 | 0 | case 4: |
139 | 0 | o << libwps::readU32(DT.m_input) << ","; |
140 | 0 | break; |
141 | 0 | default: |
142 | 0 | break; |
143 | 0 | } |
144 | 0 | } |
145 | 0 | o << ")" << std::dec; |
146 | |
|
147 | 0 | DT.m_input->seek(actPos, librevenge::RVNG_SEEK_SET); |
148 | |
|
149 | 0 | return o; |
150 | 0 | } |
151 | 0 | if (dt.hasStr()) o << "('" << dt.m_text << "')"; |
152 | 0 | if (dt.isFalse()) o << "=false,"; |
153 | 0 | if ((dt.m_type & 0x30) || dt.m_value) |
154 | 0 | o << "=" << dt.m_value << ":" << std::hex << dt.m_value << std::dec; |
155 | 0 | if (dt.m_recursData.empty()) return o; |
156 | | |
157 | 0 | o << ",ch=("; |
158 | 0 | for (auto const &data : dt.m_recursData) |
159 | 0 | { |
160 | 0 | if (data.isBad()) continue; |
161 | 0 | o << data << ","; |
162 | 0 | } |
163 | 0 | o << ")"; |
164 | 0 | return o; |
165 | 0 | } |
166 | | |
167 | | // try to read a data : which can be an item, a list or unknown zone |
168 | | bool readBlockData(RVNGInputStreamPtr input, long endPos, FileData &dt, std::string &error) |
169 | 6.02M | { |
170 | 6.02M | std::string saveError = error; |
171 | 6.02M | long actPos = input->tell(); |
172 | 6.02M | dt.m_recursData.resize(0); |
173 | | |
174 | 6.02M | if (actPos+2 > endPos) // to short |
175 | 184k | { |
176 | 184k | error += FileData::createErrorString(input, endPos); |
177 | 184k | return false; |
178 | 184k | } |
179 | | |
180 | 5.84M | dt.m_value = libwps::readU16(input); // normally 0, but who know ... |
181 | 5.84M | dt.m_beginOffset = dt.m_endOffset = -1; |
182 | | |
183 | 5.84M | int prevId = -1; |
184 | 5.84M | bool ok = true; |
185 | 17.2M | while (input->tell() != endPos) |
186 | 16.1M | { |
187 | 16.1M | FileData child; |
188 | 16.1M | if (!readData(input, endPos, child, error)) |
189 | 2.86M | { |
190 | 2.86M | ok = false; |
191 | 2.86M | break; |
192 | 2.86M | } |
193 | 13.2M | if (child.isBad()) continue; |
194 | 13.2M | if (prevId > child.id()) |
195 | 1.87M | { |
196 | 1.87M | ok = false; |
197 | 1.87M | break; |
198 | 1.87M | } |
199 | 11.4M | prevId = child.id(); |
200 | 11.4M | dt.m_recursData.push_back(child); |
201 | 11.4M | } |
202 | 5.84M | if (ok) return true; |
203 | | |
204 | 4.74M | if (dt.m_type == -1) dt.m_type = 0x80; |
205 | 4.74M | dt.m_beginOffset = actPos; |
206 | 4.74M | dt.m_endOffset = endPos; |
207 | 4.74M | dt.m_input = input; |
208 | | |
209 | 4.74M | error = saveError; |
210 | 4.74M | input->seek(endPos, librevenge::RVNG_SEEK_SET); |
211 | | |
212 | 4.74M | return false; |
213 | 5.84M | } |
214 | | |
215 | | // try to read an item |
216 | | bool readData(RVNGInputStreamPtr input, long endPos, |
217 | | FileData &dt, std::string &/*error*/) |
218 | 16.1M | { |
219 | 16.1M | long actPos = input->tell(); |
220 | 16.1M | dt = FileData(); |
221 | | |
222 | 16.1M | if (actPos >= endPos) return false; |
223 | | |
224 | 16.0M | auto val = long(libwps::readU16(input)); |
225 | 16.0M | dt.m_type = int((val & 0xFF00)>>8); |
226 | 16.0M | dt.m_id = (val & 0xFF); |
227 | | |
228 | 16.0M | if (dt.m_type & 5) |
229 | 1.69M | { |
230 | 1.69M | dt.m_type = -1; |
231 | 1.69M | return false; |
232 | 1.69M | } |
233 | | |
234 | 14.3M | dt.m_value = 0; |
235 | | // what is the meaning of dt.m_type & 0xF |
236 | | // maybe : |
237 | | // 0x1/0x4 -> never seem |
238 | | // 0x2 -> set for the main child ? |
239 | | // 0x8 -> signed/unsigned ? set/unset for bool ? |
240 | 14.3M | switch (dt.m_type>>4) |
241 | 14.3M | { |
242 | 7.69M | case 0: |
243 | 7.69M | return true; |
244 | 1.85M | case 1: |
245 | 1.85M | if (actPos+4 > endPos) break; |
246 | 1.77M | if (dt.m_type == 0x12) |
247 | 1.14M | { |
248 | 1.14M | dt.m_value = libwps::readU8(input); |
249 | 1.14M | input->seek(1, librevenge::RVNG_SEEK_CUR); |
250 | 1.14M | } |
251 | 628k | else |
252 | 628k | dt.m_value = libwps::readU16(input); |
253 | 1.77M | return true; |
254 | 3.53M | case 2: |
255 | 3.53M | { |
256 | 3.53M | if (dt.m_type == 0x2a) // special case : STR4 + long |
257 | 338k | { |
258 | 338k | if (actPos+10 > endPos) break; |
259 | 1.22M | for (int i = 0; i < 4; i++) dt.m_text += char(libwps::readU8(input)); |
260 | 245k | dt.m_value = libwps::read32(input); |
261 | 245k | return true; |
262 | 338k | } |
263 | 3.19M | if (actPos+6 > endPos) break; |
264 | 3.06M | dt.m_value = libwps::read32(input); |
265 | 3.06M | return true; |
266 | 3.19M | } |
267 | 867k | case 8: |
268 | 867k | { |
269 | 867k | if (actPos+4 > endPos) break; |
270 | | |
271 | 806k | auto extraSize = long(libwps::readU16(input)); |
272 | 806k | long newEndPos = actPos+2+extraSize; |
273 | | |
274 | 806k | if ((extraSize%2) || newEndPos > endPos) break; |
275 | | |
276 | | // can either be a list of data or a structured list, so we stored the information |
277 | 499k | dt.m_beginOffset = actPos+4; |
278 | 499k | dt.m_endOffset = newEndPos; |
279 | 499k | dt.m_input = input; |
280 | 499k | input->seek(newEndPos, librevenge::RVNG_SEEK_SET); |
281 | 499k | return true; |
282 | 806k | } |
283 | 437k | default: |
284 | 437k | break; |
285 | 14.3M | } |
286 | | |
287 | 1.10M | dt.m_type = -1; |
288 | 1.10M | return false; |
289 | 14.3M | } |
290 | | |
291 | | } |
292 | | |
293 | | /* vim:set shiftwidth=4 softtabstop=4 noexpandtab: */ |