/src/libstaroffice/src/lib/StarZone.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 | | /* libstaroffice |
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 <cstring> |
35 | | #include <iomanip> |
36 | | #include <iostream> |
37 | | #include <limits> |
38 | | #include <sstream> |
39 | | |
40 | | #include <librevenge/librevenge.h> |
41 | | |
42 | | #include "StarEncryption.hxx" |
43 | | |
44 | | #include "StarZone.hxx" |
45 | | |
46 | | constexpr size_t MAX_RECORD_NESTING = 1 << 10; |
47 | | |
48 | | //////////////////////////////////////////////////////////// |
49 | | // constructor/destructor, ... |
50 | | //////////////////////////////////////////////////////////// |
51 | | StarZone::StarZone(STOFFInputStreamPtr const &inputStream, std::string const &ascName, std::string const &zoneName, char const *password) |
52 | 206k | : m_input(inputStream) |
53 | 206k | , m_ascii(inputStream) |
54 | 206k | , m_version(0) |
55 | 206k | , m_documentVersion(0) |
56 | 206k | , m_headerVersionStack() |
57 | 206k | , m_encoding(StarEncoding::E_DONTKNOW) |
58 | 206k | , m_guiType(0) |
59 | 206k | , m_encryption() |
60 | 206k | , m_asciiName(ascName) |
61 | 206k | , m_zoneName(zoneName) |
62 | 206k | , m_typeStack() |
63 | 206k | , m_positionStack() |
64 | 206k | , m_beginToEndMap() |
65 | | , m_flagEndZone() |
66 | 206k | , m_poolList() |
67 | 206k | { |
68 | 206k | if (password) |
69 | 0 | m_encryption.reset(new StarEncryption(password)); |
70 | 206k | } |
71 | | |
72 | | StarZone::~StarZone() |
73 | 206k | { |
74 | 206k | m_ascii.reset(); |
75 | 206k | } |
76 | | |
77 | | void StarZone::setInput(STOFFInputStreamPtr ip) |
78 | 56.8k | { |
79 | 56.8k | m_input=ip; |
80 | 56.8k | m_ascii.setStream(ip); |
81 | 56.8k | } |
82 | | |
83 | | bool StarZone::readString(std::vector<uint32_t> &string, std::vector<size_t> &srcPositions, int encoding, bool chckEncryption) const |
84 | 4.35M | { |
85 | 4.35M | auto sSz=int(m_input->readULong(2)); |
86 | 4.35M | string.clear(); |
87 | 4.35M | srcPositions.clear(); |
88 | 4.35M | if (!sSz) return true; |
89 | 2.34M | unsigned long numRead; |
90 | 2.34M | uint8_t const *data=m_input->read(size_t(sSz), numRead); |
91 | 2.34M | if (!data || numRead!=static_cast<unsigned long>(sSz)) { |
92 | 343k | STOFF_DEBUG_MSG(("StarZone::readString: the sSz seems bad\n")); |
93 | 343k | return false; |
94 | 343k | } |
95 | 2.00M | std::vector<uint8_t> buffer; |
96 | 2.00M | buffer.resize(size_t(sSz)); |
97 | 2.00M | std::memcpy(&buffer[0], data, size_t(sSz)); |
98 | 2.00M | if (chckEncryption && m_encryption) |
99 | 0 | m_encryption->decode(buffer); |
100 | 2.00M | auto encod=m_encoding; |
101 | 2.00M | if (encoding>=1) encod=StarEncoding::getEncodingForId(encoding); |
102 | 2.00M | return StarEncoding::convert(buffer, encod, string, srcPositions); |
103 | 2.34M | } |
104 | | |
105 | | bool StarZone::readStringsPool() |
106 | 1.61k | { |
107 | 1.61k | long pos=m_input->tell(); |
108 | 1.61k | unsigned char type; |
109 | 1.61k | if (m_input->peek()!='!' || !openSWRecord(type)) { |
110 | 36 | m_input->seek(pos, librevenge::RVNG_SEEK_SET); |
111 | 36 | return false; |
112 | 36 | } |
113 | 1.58k | libstoff::DebugStream f; |
114 | 1.58k | f << "Entries(SWPoolList)[" << getRecordLevel() << "]:"; |
115 | | // sw_sw3misc.xx: InStringPool sw_sw3imp.cxx: LoadOld and Load |
116 | 1.58k | int encoding=m_encoding; |
117 | 1.58k | m_poolList.clear(); |
118 | 1.58k | long lastPos=getRecordLastPosition(); |
119 | 1.58k | if (!isCompatibleWith(3)) { |
120 | 2 | auto n=int(m_input->readULong(2)); |
121 | 2 | if (n>=256) { |
122 | 2 | m_input->seek(-1, librevenge::RVNG_SEEK_CUR); |
123 | 2 | encoding=int(m_input->readULong(1)); |
124 | 2 | f << "encoding=" << encoding << ","; |
125 | 2 | n=int(m_input->readULong(2)); |
126 | 2 | } |
127 | 2 | f << "n=" << n << ","; |
128 | 2 | m_ascii.addPos(pos); |
129 | 2 | m_ascii.addNote(f.str().c_str()); |
130 | 2 | std::vector<uint32_t> string; |
131 | 2 | for (int i=0; i<n; ++i) { |
132 | 2 | pos=m_input->tell(); |
133 | 2 | f.str(""); |
134 | 2 | f << "SWPoolList-" << i << ":"; |
135 | 2 | if (!readString(string, encoding) || m_input->tell()>lastPos) { |
136 | 2 | STOFF_DEBUG_MSG(("StarZone::readStringsPool: can not read a string\n")); |
137 | 2 | m_input->seek(pos, librevenge::RVNG_SEEK_SET); |
138 | 2 | break; |
139 | 2 | } |
140 | 0 | m_poolList.push_back(libstoff::getString(string)); |
141 | 0 | f << m_poolList.back().cstr() << ","; |
142 | 0 | m_ascii.addPos(pos); |
143 | 0 | m_ascii.addNote(f.str().c_str()); |
144 | 0 | } |
145 | 2 | } |
146 | 1.58k | else { |
147 | 1.58k | encoding=int(m_input->readULong(1)); |
148 | 1.58k | f << "encoding=" << encoding << ","; |
149 | 1.58k | auto n=int(m_input->readULong(2)); |
150 | 1.58k | f << "n=" << n << ","; |
151 | 1.58k | m_ascii.addPos(pos); |
152 | 1.58k | m_ascii.addNote(f.str().c_str()); |
153 | | |
154 | 1.58k | std::vector<uint32_t> string; |
155 | 18.2k | for (int i=0; i<n; ++i) { // checkme |
156 | 16.8k | pos=m_input->tell(); |
157 | 16.8k | f.str(""); |
158 | 16.8k | f << "SWPoolList-" << i << ":"; |
159 | 16.8k | auto nId=int(m_input->readULong(2)); |
160 | 16.8k | f << "nId=" << nId << ","; |
161 | 16.8k | if (!readString(string, encoding) || m_input->tell()>lastPos) { |
162 | 163 | STOFF_DEBUG_MSG(("StarZone::readStringsPool: can not read a string\n")); |
163 | 163 | m_input->seek(pos, librevenge::RVNG_SEEK_SET); |
164 | 163 | break; |
165 | 163 | } |
166 | 16.6k | m_poolList.push_back(libstoff::getString(string)); |
167 | 16.6k | f << m_poolList.back().cstr() << ","; |
168 | 16.6k | m_ascii.addPos(pos); |
169 | 16.6k | m_ascii.addNote(f.str().c_str()); |
170 | 16.6k | } |
171 | 1.58k | } |
172 | 1.58k | closeSWRecord(type, "SWPoolList"); |
173 | 1.58k | return true; |
174 | 1.61k | } |
175 | | |
176 | | bool StarZone::checkEncryption(uint32_t date, uint32_t time, std::vector<uint8_t> const &passwd) |
177 | 0 | { |
178 | 0 | if ((!date && !time) || passwd.empty()) |
179 | 0 | return true; |
180 | 0 | if (m_encryption && m_encryption->checkPassword(date,time,passwd)) |
181 | 0 | return true; |
182 | 0 | if (!m_encryption) m_encryption.reset(new StarEncryption); |
183 | |
|
184 | 0 | if (!m_encryption->guessPassword(date,time,passwd) || !m_encryption->checkPassword(date,time,passwd)) { |
185 | 0 | STOFF_DEBUG_MSG(("StarZone::readZoneHeader: can not find the password\n")); |
186 | 0 | throw libstoff::WrongPasswordException(); |
187 | 0 | } |
188 | 0 | STOFF_DEBUG_MSG(("StarZone::readZoneHeader: find a potential password, let continue\n")); |
189 | 0 | return true; |
190 | 0 | } |
191 | | |
192 | | bool StarZone::readSWHeader() |
193 | 1.67k | { |
194 | 1.67k | m_ascii.open(m_asciiName); |
195 | | |
196 | 1.67k | libstoff::DebugStream f; |
197 | 1.67k | f << "Entries(" << m_zoneName << "):"; |
198 | | |
199 | | // sw_sw3doc.cxx: Sw3IoImp::InHeader |
200 | 1.67k | if (m_input->size()<0x36) { |
201 | 0 | STOFF_DEBUG_MSG(("StarZone::readSWHeader: the zone is too short\n")); |
202 | 0 | f << "###"; |
203 | 0 | m_ascii.addPos(0); |
204 | 0 | m_ascii.addNote(f.str().c_str()); |
205 | |
|
206 | 0 | return false; |
207 | 0 | } |
208 | 1.67k | m_input->seek(0, librevenge::RVNG_SEEK_SET); |
209 | | |
210 | 1.67k | auto val=int(m_input->readULong(2)); |
211 | 1.67k | if (val==0x5357) |
212 | 0 | m_input->setReadInverted(!m_input->readInverted()); |
213 | 1.67k | else if (val!=0x5753) { |
214 | 45 | STOFF_DEBUG_MSG(("StarZone::readSWHeader: can not set the endian\n")); |
215 | 45 | f << "###"; |
216 | 45 | m_ascii.addPos(0); |
217 | 45 | m_ascii.addNote(f.str().c_str()); |
218 | | |
219 | 45 | return false; |
220 | 45 | } |
221 | | |
222 | 1.62k | m_input->seek(0, librevenge::RVNG_SEEK_SET); |
223 | 13.0k | for (int i=0; i<7; ++i) { |
224 | 11.4k | auto c=char(m_input->readULong(1)); |
225 | 11.4k | static char const expected[]= {'S','W',char(0),'H', 'D', 'R', char(0)}; |
226 | 11.4k | if (c==expected[i]) continue; |
227 | 1.63k | if (i!=2) { |
228 | 1 | STOFF_DEBUG_MSG(("StarZone::readSWHeader: can not read the header\n")); |
229 | 1 | f << "###"; |
230 | 1 | m_ascii.addPos(0); |
231 | 1 | m_ascii.addNote(f.str().c_str()); |
232 | | |
233 | 1 | return false; |
234 | 1 | } |
235 | 1.62k | if (c<'3' || c>'5') { |
236 | 4 | STOFF_DEBUG_MSG(("StarZone::readZoneHeader: find unexpected version number\n")); |
237 | 4 | f << "##version=" << int(c) << ","; |
238 | 4 | } |
239 | 1.62k | else { |
240 | 1.62k | m_version=int(c-'0'); |
241 | 1.62k | f << "version=" << m_version << ","; |
242 | 1.62k | } |
243 | 1.62k | } |
244 | 1.62k | auto hSz=int(m_input->readULong(1)); |
245 | 1.62k | if (hSz<0x2e || !m_input->checkPosition(8+hSz)) { |
246 | 0 | STOFF_DEBUG_MSG(("StarZone::readSWHeader: the header seems bad\n")); |
247 | 0 | f << "###hSz"; |
248 | 0 | m_ascii.addPos(0); |
249 | 0 | m_ascii.addNote(f.str().c_str()); |
250 | |
|
251 | 0 | return false; |
252 | 0 | } |
253 | 1.62k | m_documentVersion=int(m_input->readULong(2)); |
254 | 1.62k | f << "docVersion=" << std::hex << m_documentVersion << std::dec << ","; |
255 | 1.62k | auto fFlags=int(m_input->readULong(2)); |
256 | 1.62k | bool hasPasswd=false; |
257 | 1.62k | if (fFlags&2) f << "hasBlockName,"; |
258 | 1.62k | if (fFlags&8) { |
259 | 2 | hasPasswd=true; |
260 | 2 | f << "hasPasswd,"; |
261 | 2 | } |
262 | 1.62k | if (fFlags&0x100) f << "hasPGNums,"; |
263 | 1.62k | if (fFlags&0x8000) { |
264 | 2 | f << "#badFile,"; |
265 | 2 | STOFF_DEBUG_MSG(("StarZone::readSWHeader: bad file is set\n")); |
266 | | |
267 | 2 | m_ascii.addPos(0); |
268 | 2 | m_ascii.addNote(f.str().c_str()); |
269 | | |
270 | 2 | return false; |
271 | 2 | } |
272 | 1.62k | fFlags&=0x7EF5; |
273 | 1.62k | if (fFlags) f << "flags=" << std::hex << fFlags << std::dec << ","; |
274 | 1.62k | auto dFlags=long(m_input->readULong(4)); |
275 | 1.62k | if (dFlags&1) f << "browse[mode],"; |
276 | 1.62k | if (dFlags&2) f << "browse[mode2],"; |
277 | 1.62k | if (dFlags&4) f << "html[mode],"; |
278 | 1.62k | if (dFlags&8) f << "show[header],"; |
279 | 1.62k | if (dFlags&0x10) f << "show[footer],"; |
280 | 1.62k | if (dFlags&0x20) f << "global[doc],"; |
281 | 1.62k | if (dFlags&0x40) f << "hasSections,"; |
282 | 1.62k | if (dFlags&0x80) f << "isLabel,"; |
283 | 1.62k | dFlags&=0xffffff00; |
284 | 1.62k | if (dFlags) f << "dFlags=" << std::hex << dFlags << std::dec << ","; |
285 | 1.62k | long recPos=int(m_input->readULong(4)); |
286 | 1.62k | if (recPos) f << "recPos=" << std::hex << val << std::dec << ","; |
287 | 1.62k | m_input->seek(6, librevenge::RVNG_SEEK_CUR); // dummy |
288 | 1.62k | val=int(m_input->readULong(1)); |
289 | 1.62k | if (val&1) |
290 | 0 | f << "redline[on],"; |
291 | 1.62k | if (val&2) |
292 | 0 | f << "redline[ignore],"; |
293 | 1.62k | if (val&0x10) |
294 | 1.61k | f << "redline[showInsert],"; |
295 | 1.62k | if (val&0x20) |
296 | 1.61k | f << "redline[showDelete],"; |
297 | 1.62k | val&=0xCC; |
298 | 1.62k | if (val) f << "redline=" << std::hex << val << std::dec << ","; |
299 | 1.62k | val=int(m_input->readULong(1)); |
300 | 1.62k | if (val) f << "compVers=" << val << ","; |
301 | 1.62k | std::vector<uint8_t> passwd; |
302 | 27.6k | for (int i=0; i<16; ++i) passwd.push_back(static_cast<uint8_t>(m_input->readULong(1))); |
303 | 1.62k | val=int(m_input->readULong(1)); |
304 | 1.62k | if (val) f << "charSet[encoding]=" << val << ","; |
305 | 1.62k | m_encoding=StarEncoding::getEncodingForId(val); |
306 | 1.62k | val=int(m_input->readULong(1)); |
307 | 1.62k | if (val) f << "f0=" << val << ","; |
308 | 1.62k | uint32_t date, time; |
309 | 1.62k | *m_input >> date >> time; |
310 | 1.62k | f << "date=" << date << ","; |
311 | 1.62k | f << "time=" << time << ","; |
312 | 1.62k | if (hasPasswd) |
313 | 0 | checkEncryption(date,time,passwd); |
314 | 1.62k | else |
315 | 1.62k | m_encryption.reset(); |
316 | 1.62k | if (hSz==0x2e +64 && (fFlags&2)) { |
317 | 0 | std::string string(""); |
318 | 0 | for (int i=0; i<64; ++i) { |
319 | 0 | auto c=char(m_input->readULong(1)); |
320 | 0 | if (!c) break; |
321 | 0 | string+=c; |
322 | 0 | } |
323 | 0 | f << string; |
324 | 0 | m_input->seek(8+0x2e +64, librevenge::RVNG_SEEK_SET); |
325 | 0 | } |
326 | 1.62k | if (m_input->tell()!=8+hSz) { |
327 | 0 | m_ascii.addDelimiter(m_input->tell(),'|'); |
328 | 0 | STOFF_DEBUG_MSG(("StarZone::readSWHeader: find extra data\n")); |
329 | 0 | f << "###extra"; |
330 | 0 | } |
331 | 1.62k | m_ascii.addPos(0); |
332 | 1.62k | m_ascii.addNote(f.str().c_str()); |
333 | 1.62k | m_input->seek(8+hSz, librevenge::RVNG_SEEK_SET); |
334 | 1.62k | if (recPos && isCompatibleWith(int('%'))) |
335 | 0 | return readRecordSizes(recPos); |
336 | | |
337 | 1.62k | return true; |
338 | 1.62k | } |
339 | | |
340 | | //////////////////////////////////////////////////////////// |
341 | | // sdrheader: open/close |
342 | | //////////////////////////////////////////////////////////// |
343 | | bool StarZone::openSCHHeader() |
344 | 25.2k | { |
345 | 25.2k | long pos=m_input->tell(); |
346 | 25.2k | if (!m_input->checkPosition(pos+6)) return false; |
347 | | // schiocmp.cxx: SchIOHeader::SchIOHeader |
348 | 25.1k | auto len=long(m_input->readULong(4)); |
349 | 25.1k | m_headerVersionStack.push(int(m_input->readULong(2))); |
350 | 25.1k | long endPos=pos+len; |
351 | 25.1k | if (len<6 || !m_input->checkPosition(endPos)) { |
352 | 9.64k | m_headerVersionStack.pop(); |
353 | 9.64k | m_input->seek(pos, librevenge::RVNG_SEEK_SET); |
354 | 9.64k | return false; |
355 | 9.64k | } |
356 | | // check the position ends in the current group (if a group is open) |
357 | 15.5k | if (!m_positionStack.empty() && endPos>m_positionStack.top() && m_positionStack.top()) { |
358 | 250 | STOFF_DEBUG_MSG(("StarZone::openSCHHeader: argh endPosition is not in the current group\n")); |
359 | 250 | m_headerVersionStack.pop(); |
360 | 250 | m_input->seek(pos, librevenge::RVNG_SEEK_SET); |
361 | 250 | return false; |
362 | 250 | } |
363 | 15.2k | m_typeStack.push('@'); |
364 | 15.2k | m_positionStack.push(endPos); |
365 | 15.2k | return true; |
366 | 15.5k | } |
367 | | |
368 | | bool StarZone::closeSCHHeader(std::string const &debugName) |
369 | 15.3k | { |
370 | 15.3k | if (!m_headerVersionStack.empty()) m_headerVersionStack.pop(); |
371 | 15.3k | return closeRecord('@', debugName); |
372 | 15.3k | } |
373 | | |
374 | | bool StarZone::openVersionCompatHeader() |
375 | 39.3k | { |
376 | 39.3k | long pos=m_input->tell(); |
377 | 39.3k | if (!m_input->checkPosition(pos+6)) return false; |
378 | | // vcompat.cxx: VersionCompat::VersionCompat |
379 | 39.2k | m_headerVersionStack.push(int(m_input->readULong(2))); |
380 | 39.2k | auto len=long(m_input->readULong(4)); |
381 | 39.2k | long endPos=pos+6+len; |
382 | 39.2k | if (len<0 || !m_input->checkPosition(endPos)) { |
383 | 2.27k | m_headerVersionStack.pop(); |
384 | 2.27k | m_input->seek(pos, librevenge::RVNG_SEEK_SET); |
385 | 2.27k | return false; |
386 | 2.27k | } |
387 | | // check the position ends in the current group (if a group is open) |
388 | 37.0k | if (!m_positionStack.empty() && endPos>m_positionStack.top() && m_positionStack.top()) { |
389 | 198 | STOFF_DEBUG_MSG(("StarZone::openVersionCompatHeader: argh endPosition is not in the current group\n")); |
390 | 198 | m_headerVersionStack.pop(); |
391 | 198 | m_input->seek(pos, librevenge::RVNG_SEEK_SET); |
392 | 198 | return false; |
393 | 198 | } |
394 | 36.8k | m_typeStack.push('*'); |
395 | 36.8k | m_positionStack.push(endPos); |
396 | 36.8k | return true; |
397 | 37.0k | } |
398 | | |
399 | | bool StarZone::closeVersionCompatHeader(std::string const &debugName) |
400 | 36.8k | { |
401 | 36.8k | if (!m_headerVersionStack.empty()) m_headerVersionStack.pop(); |
402 | 36.8k | return closeRecord('*', debugName); |
403 | 36.8k | } |
404 | | |
405 | | bool StarZone::openSDRHeader(std::string &magic) |
406 | 479k | { |
407 | 479k | long pos=m_input->tell(); |
408 | 479k | if (!m_input->checkPosition(pos+4)) return false; |
409 | 479k | if (m_positionStack.size()>=MAX_RECORD_NESTING) { |
410 | 0 | STOFF_DEBUG_MSG(("StarZone::openSDRHeader: the record is nested too deeply\n")); |
411 | 0 | return false; |
412 | 0 | } |
413 | | // svdio.cxx: SdrIOHeader::Read |
414 | 479k | magic=""; |
415 | 2.39M | for (int i=0; i<4; ++i) magic+=char(m_input->readULong(1)); |
416 | | // special case: ok to have only magic if ... |
417 | 479k | if (magic=="DrXX") { |
418 | 43.2k | m_typeStack.push('_'); |
419 | 43.2k | m_positionStack.push(m_input->tell()); |
420 | 43.2k | return true; |
421 | 43.2k | } |
422 | 436k | m_headerVersionStack.push(int(m_input->readULong(2))); |
423 | 436k | auto len=long(m_input->readULong(4)); |
424 | 436k | long endPos=pos+len; |
425 | 436k | if (len<10 || magic.compare(0,2,"Dr")!=0 || !m_input->checkPosition(endPos)) { |
426 | 14.7k | m_headerVersionStack.pop(); |
427 | 14.7k | m_input->seek(pos, librevenge::RVNG_SEEK_SET); |
428 | 14.7k | return false; |
429 | 14.7k | } |
430 | | // check the position ends in the current group (if a group is open) |
431 | 421k | if (!m_positionStack.empty() && endPos>m_positionStack.top() && m_positionStack.top()) { |
432 | 5.31k | STOFF_DEBUG_MSG(("StarZone::openSDRHeader: argh endPosition is not in the current group\n")); |
433 | 5.31k | m_headerVersionStack.pop(); |
434 | 5.31k | m_input->seek(pos, librevenge::RVNG_SEEK_SET); |
435 | 5.31k | return false; |
436 | 5.31k | } |
437 | 416k | m_typeStack.push('_'); |
438 | 416k | m_positionStack.push(endPos); |
439 | 416k | return true; |
440 | 421k | } |
441 | | |
442 | | bool StarZone::closeSDRHeader(std::string const &debugName) |
443 | 459k | { |
444 | 459k | if (!m_headerVersionStack.empty()) m_headerVersionStack.pop(); |
445 | 459k | return closeRecord('_', debugName); |
446 | 459k | } |
447 | | |
448 | | //////////////////////////////////////////////////////////// |
449 | | // record: open/close, read size |
450 | | //////////////////////////////////////////////////////////// |
451 | | bool StarZone::openDummyRecord() |
452 | 3.53M | { |
453 | 3.53M | m_typeStack.push('@'); |
454 | 3.53M | if (!m_positionStack.empty()) |
455 | 3.36M | m_positionStack.push(m_positionStack.top()); |
456 | 162k | else |
457 | 162k | m_positionStack.push(m_input->size()); |
458 | 3.53M | return true; |
459 | 3.53M | } |
460 | | |
461 | | bool StarZone::openRecord() |
462 | 1.23M | { |
463 | 1.23M | long pos=m_input->tell(); |
464 | 1.23M | if (!m_input->checkPosition(pos+4)) return false; |
465 | 1.23M | unsigned long sz=m_input->readULong(4); |
466 | 1.23M | long endPos=0; |
467 | | |
468 | 1.23M | m_flagEndZone=0; |
469 | 1.23M | if (sz<4) { |
470 | 12.3k | STOFF_DEBUG_MSG(("StarZone::openRecord: size can be less than 4\n")); |
471 | 12.3k | return false; |
472 | 12.3k | } |
473 | 1.22M | endPos=pos+long(sz); |
474 | | // check the position is in the file |
475 | 1.22M | if (endPos && !m_input->checkPosition(endPos)) { |
476 | 47.5k | STOFF_DEBUG_MSG(("StarZone::openRecord: endPosition is bad\n")); |
477 | 47.5k | return false; |
478 | 47.5k | } |
479 | | // check the position ends in the current group (if a group is open) |
480 | 1.17M | if (!m_positionStack.empty() && endPos>m_positionStack.top() && m_positionStack.top()) { |
481 | 9.65k | STOFF_DEBUG_MSG(("StarZone::openRecord: argh endPosition is not in the current group\n")); |
482 | 9.65k | return false; |
483 | 9.65k | } |
484 | 1.16M | m_typeStack.push(' '); |
485 | 1.16M | m_positionStack.push(endPos); |
486 | 1.16M | return true; |
487 | 1.17M | } |
488 | | |
489 | | bool StarZone::openSCRecord() |
490 | 593k | { |
491 | 593k | long pos=m_input->tell(); |
492 | 593k | if (!m_input->checkPosition(pos+4)) return false; |
493 | 593k | unsigned long sz=m_input->readULong(4); |
494 | 593k | long endPos=0; |
495 | | |
496 | 593k | m_flagEndZone=0; |
497 | 593k | endPos=pos+4+long(sz); |
498 | | // check the position is in the file |
499 | 593k | if (endPos && !m_input->checkPosition(endPos)) { |
500 | 111k | STOFF_DEBUG_MSG(("StarZone::openSCRecord: endPosition is bad\n")); |
501 | 111k | return false; |
502 | 111k | } |
503 | | // check the position ends in the current group (if a group is open) |
504 | 482k | if (!m_positionStack.empty() && endPos>m_positionStack.top() && m_positionStack.top()) { |
505 | 6.27k | STOFF_DEBUG_MSG(("StarZone::openSCRecord: argh endPosition is not in the current group\n")); |
506 | 6.27k | return false; |
507 | 6.27k | } |
508 | 475k | m_typeStack.push('_'); |
509 | 475k | m_positionStack.push(endPos); |
510 | 475k | return true; |
511 | 482k | } |
512 | | |
513 | | bool StarZone::openSWRecord(unsigned char &type) |
514 | 58.7k | { |
515 | 58.7k | long pos=m_input->tell(); |
516 | 58.7k | if (!m_input->checkPosition(pos+4)) return false; |
517 | 58.7k | if (m_positionStack.size()>=MAX_RECORD_NESTING) { |
518 | 0 | STOFF_DEBUG_MSG(("StarZone::openSWRecord: the record is nested too deeply\n")); |
519 | 0 | return false; |
520 | 0 | } |
521 | 58.7k | unsigned long val=m_input->readULong(4); |
522 | 58.7k | type=static_cast<unsigned char>(val&0xff); |
523 | 58.7k | if (!type) { |
524 | 1.17k | STOFF_DEBUG_MSG(("StarZone::openSWRecord: type can not be null\n")); |
525 | 1.17k | return false; |
526 | 1.17k | } |
527 | 57.5k | unsigned long sz=(val>>8); |
528 | 57.5k | long endPos=0; |
529 | | |
530 | 57.5k | m_flagEndZone=0; |
531 | 57.5k | if (sz==0xffffff && isCompatibleWith(0x0209)) { |
532 | 356 | if (m_beginToEndMap.find(pos)!=m_beginToEndMap.end()) |
533 | 0 | endPos=m_beginToEndMap.find(pos)->second; |
534 | 356 | else { |
535 | 356 | STOFF_DEBUG_MSG(("StarZone::openSWRecord: can not find size for a zone, we may have some problem\n")); |
536 | 356 | } |
537 | 356 | } |
538 | 57.2k | else { |
539 | 57.2k | if (sz<4) { |
540 | 534 | STOFF_DEBUG_MSG(("StarZone::openSWRecord: size can be less than 4\n")); |
541 | 534 | return false; |
542 | 534 | } |
543 | 56.6k | endPos=pos+long(sz); |
544 | 56.6k | } |
545 | | // check the position is in the file |
546 | 57.0k | if (endPos && !m_input->checkPosition(endPos)) { |
547 | 4.66k | STOFF_DEBUG_MSG(("StarZone::openSWRecord: endPosition is bad\n")); |
548 | 4.66k | return false; |
549 | 4.66k | } |
550 | | // check the position ends in the current group (if a group is open) |
551 | 52.3k | if (!m_positionStack.empty() && endPos>m_positionStack.top() && m_positionStack.top()) { |
552 | 1.95k | STOFF_DEBUG_MSG(("StarZone::openSWRecord: argh endPosition is not in the current group\n")); |
553 | 1.95k | return false; |
554 | 1.95k | } |
555 | 50.4k | m_typeStack.push(type); |
556 | 50.4k | m_positionStack.push(endPos); |
557 | 50.4k | return true; |
558 | 52.3k | } |
559 | | |
560 | | bool StarZone::openSfxRecord(unsigned char &type) |
561 | 2.02M | { |
562 | 2.02M | long pos=m_input->tell(); |
563 | 2.02M | if (!m_input->checkPosition(pos+4)) return false; |
564 | | // filerec.cxx SfxMiniRecordReader::SfxMiniRecordReader |
565 | 2.02M | unsigned long val=m_input->readULong(4); |
566 | 2.02M | type=static_cast<unsigned char>(val&0xff); |
567 | | // checkme: can type be null |
568 | 2.02M | unsigned long sz=(val>>8); |
569 | 2.02M | long endPos=0; |
570 | | |
571 | 2.02M | m_flagEndZone=0; |
572 | 2.02M | endPos=pos+4+long(sz); |
573 | | // check the position is in the file |
574 | 2.02M | if (endPos && !m_input->checkPosition(endPos)) { |
575 | 118k | STOFF_DEBUG_MSG(("StarZone::openSfxRecord: endPosition is bad\n")); |
576 | 118k | return false; |
577 | 118k | } |
578 | | // check the position ends in the current group (if a group is open) |
579 | 1.90M | if (!m_positionStack.empty() && endPos>m_positionStack.top() && m_positionStack.top()) { |
580 | 156k | STOFF_DEBUG_MSG(("StarZone::openSfxRecord: argh endPosition is not in the current group\n")); |
581 | 156k | return false; |
582 | 156k | } |
583 | 1.74M | m_typeStack.push(type); |
584 | 1.74M | m_positionStack.push(endPos); |
585 | 1.74M | return true; |
586 | 1.90M | } |
587 | | |
588 | | bool StarZone::closeRecord(unsigned char type, std::string const &debugName) |
589 | 6.76M | { |
590 | 6.76M | m_flagEndZone=0; |
591 | 7.48M | while (!m_typeStack.empty()) { |
592 | 7.48M | unsigned char typ=m_typeStack.top(); |
593 | 7.48M | long pos=m_positionStack.top(); |
594 | | |
595 | 7.48M | m_typeStack.pop(); |
596 | 7.48M | m_positionStack.pop(); |
597 | 7.48M | if (typ!=type) continue; |
598 | 6.76M | if (!pos || type=='@') |
599 | 3.54M | return true; |
600 | 3.21M | long actPos=m_input->tell(); |
601 | 3.21M | if (actPos!=pos) { |
602 | 305k | if (actPos>pos) { |
603 | 44.0k | STOFF_DEBUG_MSG(("StarZone::closeRecord: oops, we read to much data\n")); |
604 | 44.0k | } |
605 | 261k | else if (actPos<pos) { |
606 | 261k | STOFF_DEBUG_MSG(("StarZone::closeRecord: oops, some data have been ignored\n")); |
607 | 261k | } |
608 | 305k | libstoff::DebugStream f; |
609 | 305k | f << debugName << ":###extra"; |
610 | 305k | m_ascii.addPos(actPos); |
611 | 305k | m_ascii.addNote(f.str().c_str()); |
612 | 305k | } |
613 | | |
614 | 3.21M | m_input->seek(pos, librevenge::RVNG_SEEK_SET); |
615 | 3.21M | return true; |
616 | 6.76M | } |
617 | 1.81k | STOFF_DEBUG_MSG(("StarZone::closeRecord: oops, can not find type %d\n", int(type))); |
618 | 1.81k | return false; |
619 | 6.76M | } |
620 | | |
621 | | unsigned char StarZone::openFlagZone() |
622 | 26.3k | { |
623 | 26.3k | auto cFlags=static_cast<unsigned char>(m_input->readULong(1)); |
624 | 26.3k | m_flagEndZone=m_input->tell()+long(cFlags&0xf); |
625 | 26.3k | return cFlags; |
626 | 26.3k | } |
627 | | |
628 | | void StarZone::closeFlagZone() |
629 | 26.3k | { |
630 | 26.3k | if (!m_flagEndZone) { |
631 | 0 | STOFF_DEBUG_MSG(("StarZone::closeFlagZone: oops, can not find end position\n")); |
632 | 0 | return; |
633 | 0 | } |
634 | 26.3k | if (m_flagEndZone<m_input->tell()) { |
635 | 4.61k | STOFF_DEBUG_MSG(("StarZone::closeFlagZone: oops, we have read too much data\n")); |
636 | 4.61k | m_ascii.addPos(m_input->tell()); |
637 | 4.61k | m_ascii.addNote("Entries(BadFlagZone):###"); |
638 | 4.61k | } |
639 | 21.7k | else if (m_flagEndZone>m_input->tell()) { |
640 | 1.45k | STOFF_DEBUG_MSG(("StarZone::closeFlagZone: oops, we do not have read all data\n")); |
641 | 1.45k | m_ascii.addPos(m_input->tell()); |
642 | 1.45k | m_ascii.addNote("Entries(BadFlagZone):#"); |
643 | 1.45k | } |
644 | 26.3k | m_input->seek(m_flagEndZone, librevenge::RVNG_SEEK_SET); |
645 | 26.3k | } |
646 | | |
647 | | bool StarZone::readRecordSizes(long pos) |
648 | 0 | { |
649 | 0 | if (!pos || !isCompatibleWith('%')) |
650 | 0 | return true; |
651 | | // read the position: sw_sw3imp.cxx: Sw3IoImp::InRecSizes |
652 | 0 | long oldPos=m_input->tell(); |
653 | 0 | if (oldPos!=pos) |
654 | 0 | m_input->seek(pos, librevenge::RVNG_SEEK_SET); |
655 | 0 | libstoff::DebugStream f; |
656 | 0 | f << m_zoneName << "[RecSize]:"; |
657 | 0 | unsigned char type; |
658 | 0 | bool ok=openSWRecord(type); |
659 | 0 | if (!ok || type!='%') { |
660 | 0 | STOFF_DEBUG_MSG(("StarZone::readRecordSizes: can not open the record(recsize)\n")); |
661 | 0 | f << "###extra"; |
662 | 0 | m_ascii.addPos(pos); |
663 | 0 | m_ascii.addNote(f.str().c_str()); |
664 | |
|
665 | 0 | m_input->seek(oldPos, librevenge::RVNG_SEEK_SET); |
666 | 0 | return ok || (oldPos!=pos); |
667 | 0 | } |
668 | | |
669 | 0 | openFlagZone(); |
670 | 0 | auto nCount=int(m_input->readULong(4)); |
671 | 0 | f << "N=" << nCount << ","; |
672 | 0 | closeFlagZone(); |
673 | |
|
674 | 0 | if (nCount<0 || (getRecordLastPosition()-m_input->tell())/8<nCount || !m_input->checkPosition(m_input->tell()+8*nCount)) { |
675 | 0 | STOFF_DEBUG_MSG(("StarZone::readRecordSizes: endCPos seems bad\n")); |
676 | 0 | f << "###badN,"; |
677 | |
|
678 | 0 | m_ascii.addPos(pos); |
679 | 0 | m_ascii.addNote(f.str().c_str()); |
680 | 0 | closeSWRecord('%',m_zoneName); |
681 | 0 | if (oldPos!=pos) |
682 | 0 | m_input->seek(oldPos, librevenge::RVNG_SEEK_SET); |
683 | 0 | return true; |
684 | 0 | } |
685 | 0 | f << "pos:size=["; |
686 | 0 | for (int i=0; i<nCount; ++i) { |
687 | 0 | auto cPos=long(m_input->readULong(4)); |
688 | 0 | auto sz=long(m_input->readULong(4)); |
689 | 0 | m_beginToEndMap[cPos]=cPos+sz; |
690 | 0 | f << std::hex << cPos << "<->" << cPos+sz << std::dec << ","; |
691 | 0 | } |
692 | 0 | f << "],"; |
693 | |
|
694 | 0 | closeSWRecord('%',m_zoneName); |
695 | 0 | if (oldPos!=pos) |
696 | 0 | m_input->seek(oldPos, librevenge::RVNG_SEEK_SET); |
697 | |
|
698 | 0 | m_ascii.addPos(pos); |
699 | 0 | m_ascii.addNote(f.str().c_str()); |
700 | 0 | return true; |
701 | 0 | } |
702 | | |
703 | | // vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: |