/src/libmwaw/src/lib/MWAWRSRCParser.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 <librevenge/librevenge.h> |
35 | | |
36 | | #include "MWAWCell.hxx" |
37 | | #include "MWAWInputStream.hxx" |
38 | | #include "MWAWEntry.hxx" |
39 | | |
40 | | #include "MWAWRSRCParser.hxx" |
41 | | |
42 | | MWAWRSRCParser::MWAWRSRCParser(MWAWInputStreamPtr const &input) |
43 | 59.8k | : m_input(input) |
44 | 59.8k | , m_entryMap() |
45 | 59.8k | , m_asciiName("") |
46 | 59.8k | , m_asciiFile(MWAWInputStreamPtr()) |
47 | 59.8k | , m_parsed(false) |
48 | 59.8k | { |
49 | 59.8k | } |
50 | | |
51 | | MWAWRSRCParser::~MWAWRSRCParser() |
52 | 59.8k | { |
53 | | #ifdef DEBUG |
54 | | try { |
55 | | libmwaw::DebugStream f; |
56 | | for (auto const &it : m_entryMap) { |
57 | | MWAWEntry const &tEntry = it.second; |
58 | | if (tEntry.isParsed()) continue; |
59 | | |
60 | | if (tEntry.type()=="CODE") { // skip the code... |
61 | | ascii().skipZone(tEntry.begin()-4, tEntry.end()-1); |
62 | | continue; |
63 | | } |
64 | | f.str(""); |
65 | | f << "Entries(RSRC" << tEntry.type() << "):" << tEntry.id(); |
66 | | ascii().addPos(tEntry.begin()-4); |
67 | | ascii().addNote(f.str().c_str()); |
68 | | ascii().addPos(tEntry.end()); |
69 | | ascii().addNote("_"); |
70 | | } |
71 | | } |
72 | | catch (...) { |
73 | | } |
74 | | #endif |
75 | | |
76 | 59.8k | ascii().reset(); |
77 | 59.8k | } |
78 | | |
79 | | MWAWEntry MWAWRSRCParser::getEntry(std::string type, int id) const |
80 | 82.8k | { |
81 | 82.8k | if (!m_parsed) |
82 | 758 | const_cast<MWAWRSRCParser *>(this)->parse(); |
83 | 82.8k | auto it = m_entryMap.lower_bound(type); |
84 | 192k | while (it != m_entryMap.end()) { |
85 | 170k | if (it->first != type) |
86 | 5.32k | break; |
87 | 165k | MWAWEntry const &tEntry = (it++)->second; |
88 | 165k | if (tEntry.id()==id) |
89 | 55.7k | return tEntry; |
90 | 165k | } |
91 | | |
92 | 27.1k | return MWAWEntry(); |
93 | 82.8k | } |
94 | | |
95 | | bool MWAWRSRCParser::parse() |
96 | 55.0k | { |
97 | 55.0k | if (m_parsed) |
98 | 0 | return !m_entryMap.empty(); |
99 | 55.0k | m_parsed = true; |
100 | 55.0k | if (!m_input) return false; |
101 | | |
102 | 55.0k | if (m_asciiName.length()) { |
103 | 53.9k | ascii().setStream(m_input); |
104 | 53.9k | ascii().open("RSRC"); |
105 | 53.9k | } |
106 | 55.0k | try { |
107 | 55.0k | libmwaw::DebugStream f; |
108 | 55.0k | m_input->seek(0, librevenge::RVNG_SEEK_SET); |
109 | 55.0k | long pos = m_input->tell(); |
110 | 55.0k | MWAWEntry data, map; |
111 | 55.0k | data.setBegin(m_input->readLong(4)); |
112 | 55.0k | map.setBegin(m_input->readLong(4)); |
113 | 55.0k | data.setLength(m_input->readLong(4)); |
114 | 55.0k | map.setLength(m_input->readLong(4)); |
115 | | // data.length()==0 can be ok, if no data |
116 | 55.0k | if (!map.valid() || (!data.valid()&&data.length()!=0)) { |
117 | 17.9k | MWAW_DEBUG_MSG(("MWAWRSRCParser::parse: can not read the header\n")); |
118 | 17.9k | return false; |
119 | 17.9k | } |
120 | 37.1k | long endPos = data.end() > map.end() ? data.end() : map.end(); |
121 | 37.1k | m_input->seek(endPos, librevenge::RVNG_SEEK_SET); |
122 | 37.1k | if (m_input->tell() != endPos) { |
123 | 9.31k | MWAW_DEBUG_MSG(("MWAWRSRCParser::parse: stream seems too small\n")); |
124 | 9.31k | return false; |
125 | 9.31k | } |
126 | 27.8k | f << "Header:"; |
127 | 27.8k | ascii().addPos(pos); |
128 | 27.8k | ascii().addNote(f.str().c_str()); |
129 | 27.8k | ascii().addPos(16); |
130 | 27.8k | ascii().addNote("_"); |
131 | | |
132 | 27.8k | if (!parseMap(map, data.begin())) return false; |
133 | | |
134 | | #ifdef DEBUG_WITH_FILES |
135 | | // try to parse the system reserved zone |
136 | | m_input->seek(48, librevenge::RVNG_SEEK_SET); |
137 | | int strSz=int(m_input->readULong(1)); |
138 | | if (data.begin()>=0x100 && map.begin()>=0x100 && (strSz>0 && strSz<32)) { |
139 | | f.str(""); |
140 | | f << "Entries(RSRCPriv):name="; |
141 | | pos=48; |
142 | | std::string name; |
143 | | for (int i=0; i<strSz; ++i) name+=char(m_input->readULong(1)); |
144 | | f << name << ","; |
145 | | ascii().addDelimiter(m_input->tell(),'|'); |
146 | | ascii().addPos(pos); |
147 | | ascii().addNote(f.str().c_str()); |
148 | | m_input->seek(pos+32, librevenge::RVNG_SEEK_SET); |
149 | | |
150 | | f.str(""); |
151 | | f << "RSRCPriv-2:"; |
152 | | pos=m_input->tell(); |
153 | | int val=int(m_input->readLong(2)); |
154 | | if (val) f << "f0=" << val << ","; |
155 | | for (int w=0; w<2; ++w) { |
156 | | long aPos=m_input->tell(); |
157 | | std::string type; |
158 | | for (int j=0; j<4; ++j) { |
159 | | char c=char(m_input->readULong(1)); |
160 | | if (!c) break; |
161 | | type+=c; |
162 | | } |
163 | | f << (w==0 ? "type" : "creator") << "=" << type << ","; |
164 | | m_input->seek(aPos+4, librevenge::RVNG_SEEK_SET); |
165 | | } |
166 | | for (int i=0; i<12; ++i) { // f1=256, f2-3: small number |
167 | | val=int(m_input->readLong(2)); |
168 | | if (val) |
169 | | f << "f" << i+1 << "=" << val << ","; |
170 | | } |
171 | | auto date=m_input->readULong(4); |
172 | | if (date) { |
173 | | int Y, M, D, HH, MM, SS; |
174 | | MWAWCellContent::double2Date(double(date/3600/24)+1460., Y, M, D); // change the reference date from 1/1/1904 to 1/1/1900 |
175 | | double time=double(date%(3600*24))/3600/24; |
176 | | MWAWCellContent::double2Time(time, HH, MM, SS); |
177 | | f << "date=" << D << "/" << M << "/" << Y << " " << HH << ":" << MM << ","; |
178 | | } |
179 | | f << "sz=["; |
180 | | for (int i=0; i<2; ++i) { |
181 | | val=int(m_input->readULong(4)); |
182 | | if (val) |
183 | | f << val << ","; |
184 | | else |
185 | | f << "_,"; |
186 | | } |
187 | | f << "],"; |
188 | | ascii().addPos(pos); |
189 | | ascii().addNote(f.str().c_str()); |
190 | | |
191 | | ascii().addPos(m_input->tell()); |
192 | | ascii().addNote("_"); |
193 | | } |
194 | | #endif |
195 | 655k | for (auto &it : m_entryMap) { |
196 | 655k | MWAWEntry &tEntry = it.second; |
197 | 655k | if (tEntry.begin()+4 >= data.end()) { |
198 | 265k | MWAW_DEBUG_MSG(("MWAWRSRCParser::parseMap: can not read entry %s[%d]\n", tEntry.type().c_str(), tEntry.id())); |
199 | 265k | continue; |
200 | 265k | } |
201 | 390k | m_input->seek(tEntry.begin(), librevenge::RVNG_SEEK_SET); |
202 | 390k | tEntry.setBegin(tEntry.begin()+4); |
203 | 390k | const auto length = long(m_input->readULong(4)); |
204 | 390k | if (tEntry.begin() + length > data.end()) { |
205 | 50.4k | MWAW_DEBUG_MSG(("MWAWRSRCParser::parse: entry %s[%d] has got invalid length %ld\n", tEntry.type().c_str(), tEntry.id(), length)); |
206 | 50.4k | continue; |
207 | 50.4k | } |
208 | 340k | tEntry.setLength(length); |
209 | 340k | } |
210 | | |
211 | 26.7k | auto it = m_entryMap.lower_bound("vers"); |
212 | 59.8k | while (it != m_entryMap.end()) { |
213 | 37.4k | if (it->first != "vers") |
214 | 4.43k | break; |
215 | 33.0k | MWAWEntry const &tEntry = (it++)->second; |
216 | 33.0k | Version vers; |
217 | 33.0k | parseVers(tEntry, vers); |
218 | 33.0k | } |
219 | 26.7k | it = m_entryMap.lower_bound("STR "); |
220 | 47.6k | while (it != m_entryMap.end()) { |
221 | 44.4k | if (it->first != "STR ") |
222 | 23.6k | break; |
223 | 20.8k | std::string str; |
224 | 20.8k | MWAWEntry const &tEntry = (it++)->second; |
225 | 20.8k | parseSTR(tEntry, str); |
226 | 20.8k | } |
227 | 26.7k | it = m_entryMap.lower_bound("STR#"); |
228 | 45.8k | while (it != m_entryMap.end()) { |
229 | 42.4k | if (it->first != "STR#") |
230 | 23.4k | break; |
231 | 19.0k | std::vector<std::string> list; |
232 | 19.0k | MWAWEntry const &tEntry = (it++)->second; |
233 | 19.0k | parseSTRList(tEntry, list); |
234 | 19.0k | } |
235 | 26.7k | } |
236 | 55.0k | catch (...) { |
237 | 0 | MWAW_DEBUG_MSG(("MWAWRSRCParser::parse: can not parse the input\n")); |
238 | 0 | return false; |
239 | 0 | } |
240 | 26.7k | return true; |
241 | 55.0k | } |
242 | | |
243 | | bool MWAWRSRCParser::parseMap(MWAWEntry const &entry, long dataBegin) |
244 | 27.8k | { |
245 | 27.8k | if (!m_input) return false; |
246 | | |
247 | 27.8k | if (entry.length() < 28) { |
248 | 120 | MWAW_DEBUG_MSG(("MWAWRSRCParser::parseMap: entry map is two short\n")); |
249 | 120 | return false; |
250 | 120 | } |
251 | | |
252 | 27.7k | libmwaw::DebugStream f, f2; |
253 | 27.7k | m_input->seek(entry.begin()+24, librevenge::RVNG_SEEK_SET); |
254 | 27.7k | f << "Entries(RSRCMap):"; |
255 | 27.7k | auto offsetTypes=long(m_input->readULong(2)); |
256 | 27.7k | auto offsetNameLists=long(m_input->readULong(2)); |
257 | 27.7k | auto numTypes = static_cast<int>(m_input->readULong(2)); |
258 | 27.7k | if (offsetTypes+2 > entry.length() || offsetNameLists > entry.length()) { |
259 | 779 | MWAW_DEBUG_MSG(("MWAWRSRCParser::parseMap: the offsets seems bad\n")); |
260 | 779 | return false; |
261 | 779 | } |
262 | | // this case can appear if no data |
263 | 26.9k | if (numTypes == 0xFFFF) |
264 | 104 | numTypes = -1; |
265 | 26.9k | f << "N=" << numTypes+1; |
266 | 26.9k | ascii().addPos(entry.begin()); |
267 | 26.9k | ascii().addNote(f.str().c_str()); |
268 | 26.9k | if (m_input->tell() != entry.begin()+offsetTypes+2) { |
269 | 2.27k | ascii().addPos(m_input->tell()); |
270 | 2.27k | ascii().addNote("_"); |
271 | 2.27k | } |
272 | | |
273 | 26.9k | long pos = entry.begin()+offsetTypes+2; |
274 | 26.9k | m_input->seek(pos, librevenge::RVNG_SEEK_SET); |
275 | 26.9k | if (pos+8*(numTypes+1) > entry.end()) { |
276 | 150 | MWAW_DEBUG_MSG(("MWAWRSRCParser::parseMap: the type zones seems too short\n")); |
277 | 150 | return false; |
278 | 150 | } |
279 | 26.7k | std::vector<MWAWEntry> typesList; |
280 | 448k | for (int i = 0; i <= numTypes; i++) { |
281 | 421k | pos = m_input->tell(); |
282 | 421k | f.str(""); |
283 | 421k | f << "RSRCMap[Type" << i << "]:"; |
284 | 421k | std::string type(""); |
285 | 2.10M | for (int c = 0; c < 4; c++) |
286 | 1.68M | type+=char(m_input->readULong(1)); |
287 | 421k | MWAWEntry tEntry; |
288 | 421k | tEntry.setType(type); |
289 | 421k | tEntry.setId(static_cast<int>(m_input->readULong(2))+1); // the number of entry |
290 | 421k | tEntry.setBegin(entry.begin()+offsetTypes+long(m_input->readULong(2))); |
291 | 421k | typesList.push_back(tEntry); |
292 | 421k | f << tEntry << ":" << std::hex << tEntry.begin() << std::dec << ","; |
293 | 421k | ascii().addPos(pos); |
294 | 421k | ascii().addNote(f.str().c_str()); |
295 | 421k | m_input->seek(pos+8, librevenge::RVNG_SEEK_SET); |
296 | 421k | } |
297 | 26.7k | ascii().addPos(m_input->tell()); |
298 | 26.7k | ascii().addNote("_"); |
299 | 421k | for (auto const &tEntry : typesList) { |
300 | 421k | if (tEntry.begin()+12*tEntry.id() > entry.end()) { |
301 | 57.2k | MWAW_DEBUG_MSG(("MWAWRSRCParser::parseMap: can not read entry %s[%d]\n", tEntry.type().c_str(), tEntry.id())); |
302 | 57.2k | continue; |
303 | 57.2k | } |
304 | 363k | m_input->seek(tEntry.begin(), librevenge::RVNG_SEEK_SET); |
305 | 1.01M | for (int n = 0; n < tEntry.id(); n++) { |
306 | 655k | pos = m_input->tell(); |
307 | 655k | f.str(""); |
308 | 655k | f << "RSRCMap[Rsrc" << n << "]:"; |
309 | 655k | MWAWEntry rsrc(tEntry); |
310 | 655k | rsrc.setId(static_cast<int>(m_input->readLong(2))); |
311 | 655k | auto offset = long(m_input->readULong(2)); |
312 | 655k | if (offset != 0xFFFF) { |
313 | 402k | std::string name(""); |
314 | 402k | if (offset+offsetNameLists+1 <= entry.length()) { |
315 | 127k | long actPos = m_input->tell(); |
316 | 127k | m_input->seek(entry.begin()+offset+offsetNameLists, librevenge::RVNG_SEEK_SET); |
317 | 127k | auto nSz = static_cast<int>(m_input->readULong(1)); |
318 | 127k | if (offset+offsetNameLists+1+nSz <= entry.length()) { |
319 | 2.98M | for (int j = 0; j < nSz; j++) |
320 | 2.86M | name+=char(m_input->readULong(1)); |
321 | 119k | f2.str(""); |
322 | 119k | f2 << "nameList:" << name; |
323 | 119k | ascii().addPos(entry.begin()+offset+offsetNameLists); |
324 | 119k | ascii().addNote(f2.str().c_str()); |
325 | 119k | } |
326 | 127k | m_input->seek(actPos, librevenge::RVNG_SEEK_SET); |
327 | 127k | } |
328 | 402k | if (!name.length()) { |
329 | 347k | MWAW_DEBUG_MSG(("MWAWRSRCParser::parseMap: can not read name of entry %s[%d]\n", tEntry.type().c_str(), tEntry.id())); |
330 | 347k | f << "#listNamesOffset=" << std::hex << offset << std::dec << ","; |
331 | 347k | } |
332 | 54.8k | else { |
333 | 54.8k | rsrc.setName(name); |
334 | 54.8k | f << "name=" << name << ","; |
335 | 54.8k | } |
336 | 402k | } |
337 | 655k | unsigned long dOffset = m_input->readULong(4); |
338 | 655k | if (dOffset & 0xFF000000) { |
339 | 181k | f << "attributes=" << (dOffset>>12) << ","; |
340 | 181k | dOffset &= 0xFFFFFF; |
341 | 181k | } |
342 | 655k | rsrc.setBegin(dataBegin+long(dOffset)); |
343 | 655k | m_entryMap.insert(std::multimap<std::string, MWAWEntry>::value_type(rsrc.type(), rsrc)); |
344 | 655k | f << rsrc.type() << ":" << rsrc.id() << ","; |
345 | 655k | f << "pos=" << std::hex << rsrc.begin() << std::dec << ","; |
346 | | |
347 | 655k | ascii().addPos(pos); |
348 | 655k | ascii().addNote(f.str().c_str()); |
349 | 655k | m_input->seek(pos+12, librevenge::RVNG_SEEK_SET); |
350 | 655k | } |
351 | 363k | } |
352 | 26.7k | if (offsetNameLists != entry.length()) { |
353 | 6.67k | ascii().addPos(entry.begin()+offsetNameLists); |
354 | 6.67k | ascii().addNote("RSRCMap[nameList]"); |
355 | 6.67k | } |
356 | 26.7k | return true; |
357 | 26.9k | } |
358 | | |
359 | | //////////////////////////////////////////////////////////// |
360 | | // read a string resource |
361 | | // -16396: application-missing name string resource |
362 | | // -16397: application-missing string resource |
363 | | //////////////////////////////////////////////////////////// |
364 | | bool MWAWRSRCParser::parseSTR(MWAWEntry const &entry, std::string &str) |
365 | 22.5k | { |
366 | 22.5k | str=""; |
367 | 22.5k | if (!m_input || !entry.valid()) { |
368 | 6.18k | MWAW_DEBUG_MSG(("MWAWRSRCParser::parseSTR: entry is invalid\n")); |
369 | 6.18k | return false; |
370 | 6.18k | } |
371 | 16.3k | entry.setParsed(true); |
372 | 16.3k | libmwaw::DebugStream f; |
373 | 16.3k | m_input->seek(entry.begin(), librevenge::RVNG_SEEK_SET); |
374 | 16.3k | auto sz = long(m_input->readULong(1)); |
375 | 16.3k | if (sz+1 > entry.length()) { |
376 | 453 | MWAW_DEBUG_MSG(("MWAWRSRCParser::parseSTR: string length is too small\n")); |
377 | 453 | return false; |
378 | 453 | } |
379 | 1.29M | for (long i = 0; i < sz; i++) { |
380 | 1.28M | if (m_input->isEnd()) { |
381 | 0 | MWAW_DEBUG_MSG(("MWAWRSRCParser::parseSTR: file is too short\n")); |
382 | 0 | return false; |
383 | 0 | } |
384 | 1.28M | str += char(m_input->readULong(1)); |
385 | 1.28M | } |
386 | 15.8k | f << "Entries(RSRCSTR)[" << entry.type() << ":" << entry.id() << "]:" << str; |
387 | 15.8k | if (sz+1 != entry.length()) { |
388 | | // can this happens ? |
389 | 6.15k | MWAW_DEBUG_MSG(("MWAWRSRCParser::parseSTR: ARGGS multiple strings\n")); |
390 | 6.15k | ascii().addDelimiter(m_input->tell(),'|'); |
391 | 6.15k | f << "###"; |
392 | 6.15k | } |
393 | 15.8k | ascii().addPos(entry.begin()-4); |
394 | 15.8k | ascii().addNote(f.str().c_str()); |
395 | 15.8k | return true; |
396 | 15.8k | } |
397 | | |
398 | | bool MWAWRSRCParser::parseSTRList(MWAWEntry const &entry, std::vector<std::string> &list) |
399 | 19.0k | { |
400 | 19.0k | list.resize(0); |
401 | 19.0k | if (!m_input || !entry.valid() || entry.length()<2) { |
402 | 9.30k | MWAW_DEBUG_MSG(("MWAWRSRCParser::parseSTRList: the entry is bad\n")); |
403 | 9.30k | return false; |
404 | 9.30k | } |
405 | 9.71k | entry.setParsed(true); |
406 | 9.71k | long pos = entry.begin(); |
407 | 9.71k | long endPos = entry.end(); |
408 | 9.71k | m_input->seek(pos, librevenge::RVNG_SEEK_SET); |
409 | | |
410 | 9.71k | libmwaw::DebugStream f; |
411 | 9.71k | f << "Entries(RSRCListStr)[" << entry.type() << ":" << entry.id() << "]:"; |
412 | 9.71k | auto N=static_cast<int>(m_input->readULong(2)); |
413 | 9.71k | ascii().addPos(pos-4); |
414 | 9.71k | ascii().addNote(f.str().c_str()); |
415 | | |
416 | 93.3k | for (int i = 0; i < N; i++) { |
417 | 87.6k | f.str(""); |
418 | 87.6k | f << "RSRCListStr-" << i << ":"; |
419 | 87.6k | pos = m_input->tell(); |
420 | 87.6k | if (pos+1 > endPos) { |
421 | 1.56k | f << "###"; |
422 | 1.56k | ascii().addPos(pos); |
423 | 1.56k | ascii().addNote(f.str().c_str()); |
424 | | |
425 | 1.56k | MWAW_DEBUG_MSG(("MWAWRSRCParser::parseSTRList: can not read string %d\n", i)); |
426 | 1.56k | return false; |
427 | 1.56k | } |
428 | 86.0k | auto sz = static_cast<int>(m_input->readULong(1)); |
429 | 86.0k | if (pos+1+sz > endPos) { |
430 | 2.40k | f.str(""); |
431 | 2.40k | f << "###"; |
432 | 2.40k | ascii().addPos(pos); |
433 | 2.40k | ascii().addNote(f.str().c_str()); |
434 | | |
435 | 2.40k | MWAW_DEBUG_MSG(("MWAWRSRCParser::parseSTRList: string size %d is bad\n", i)); |
436 | 2.40k | return false; |
437 | 2.40k | } |
438 | | |
439 | 83.6k | std::string str(""); |
440 | 885k | for (int c=0; c < sz; c++) |
441 | 802k | str += char(m_input->readULong(1)); |
442 | 83.6k | list.push_back(str); |
443 | 83.6k | f << str << ","; |
444 | | |
445 | 83.6k | ascii().addPos(pos); |
446 | 83.6k | ascii().addNote(f.str().c_str()); |
447 | 83.6k | } |
448 | 5.74k | return true; |
449 | 9.71k | } |
450 | | |
451 | | bool MWAWRSRCParser::parseClut(MWAWEntry const &entry, std::vector<MWAWColor> &list) |
452 | 0 | { |
453 | 0 | list.resize(0); |
454 | 0 | if (!m_input || !entry.valid() || entry.length()<8) { |
455 | 0 | MWAW_DEBUG_MSG(("MWAWRSRCParser::parseClut: the entry is bad\n")); |
456 | 0 | return false; |
457 | 0 | } |
458 | 0 | entry.setParsed(true); |
459 | 0 | long pos = entry.begin(); |
460 | | // skip seed |
461 | 0 | m_input->seek(pos+4, librevenge::RVNG_SEEK_SET); |
462 | |
|
463 | 0 | libmwaw::DebugStream f; |
464 | 0 | f << "Entries(RSRCClut)[" << entry.type() << ":" << entry.id() << "]:"; |
465 | 0 | auto flags = static_cast<int>(m_input->readULong(2)); |
466 | 0 | if (flags==0x8000) f << "indexed,"; |
467 | 0 | else if (flags) f << "#flags=" << std::hex << flags << ","; |
468 | 0 | auto N= static_cast<int>(m_input->readULong(2)); |
469 | 0 | if (entry.length()==8+8*(N+1)) // N can be num or maxId |
470 | 0 | N++; |
471 | 0 | f << "N=" << N << ","; |
472 | 0 | if (entry.length()!=8+8*N) { |
473 | 0 | f << "###"; |
474 | 0 | MWAW_DEBUG_MSG(("MWAWRSRCParser::parseClut: find unexpected size/format\n")); |
475 | 0 | ascii().addPos(pos-4); |
476 | 0 | ascii().addNote(f.str().c_str()); |
477 | 0 | return false; |
478 | 0 | } |
479 | 0 | ascii().addPos(pos-4); |
480 | 0 | ascii().addNote(f.str().c_str()); |
481 | |
|
482 | 0 | for (int i = 0; i < N; i++) { |
483 | 0 | pos = m_input->tell(); |
484 | 0 | f.str(""); |
485 | 0 | f << "RSRCClut-" << i << ":"; |
486 | 0 | auto index = static_cast<int>(m_input->readULong(2)); |
487 | 0 | if (index != i) { |
488 | 0 | static bool first=true; |
489 | 0 | if (first) { |
490 | 0 | MWAW_DEBUG_MSG(("MWAWRSRCParser::parseClut: find some odd index value\n")); |
491 | 0 | first = false; |
492 | 0 | } |
493 | 0 | f << "#index=" << index << ","; |
494 | 0 | } |
495 | 0 | unsigned char col[3]; |
496 | 0 | for (auto &c : col) c = static_cast<unsigned char>(m_input->readULong(2)>>8); |
497 | 0 | MWAWColor color(col[0],col[1],col[2]); |
498 | 0 | list.push_back(color); |
499 | 0 | f << color << ","; |
500 | |
|
501 | 0 | ascii().addPos(pos); |
502 | 0 | ascii().addNote(f.str().c_str()); |
503 | 0 | } |
504 | 0 | return true; |
505 | 0 | } |
506 | | |
507 | | //////////////////////////////////////////////////////////// |
508 | | // read the version: |
509 | | // id=1 version of the appliction |
510 | | // id=2 version of the file |
511 | | //////////////////////////////////////////////////////////// |
512 | | std::ostream &operator<< (std::ostream &o, MWAWRSRCParser::Version const &vers) |
513 | 0 | { |
514 | 0 | o << vers.m_string; |
515 | 0 | if (vers.m_versionString.length()) |
516 | 0 | o << "(" << vers.m_versionString << ")"; |
517 | 0 | o << ","; |
518 | 0 | o << "vers=" << vers.m_majorVersion; |
519 | 0 | if (vers.m_minorVersion) |
520 | 0 | o << "(" << vers.m_minorVersion << ")"; |
521 | 0 | o << ","; |
522 | 0 | if (vers.m_countryCode) |
523 | 0 | o << "country=" << std::hex << vers.m_countryCode << std::dec << ","; |
524 | 0 | o << vers.m_extra; |
525 | 0 | return o; |
526 | 0 | } |
527 | | |
528 | | bool MWAWRSRCParser::parseVers(MWAWEntry const &entry, Version &vers) |
529 | 73.8k | { |
530 | 73.8k | vers = Version(); |
531 | 73.8k | if (!m_input || !entry.valid() || entry.length()<8 || !m_input->checkPosition(entry.end())) { |
532 | 7.81k | MWAW_DEBUG_MSG(("MWAWRSRCParser::parseVers: entry is invalid\n")); |
533 | 7.81k | return false; |
534 | 7.81k | } |
535 | 66.0k | entry.setParsed(true); |
536 | 66.0k | libmwaw::DebugStream f; |
537 | 66.0k | m_input->seek(entry.begin(), librevenge::RVNG_SEEK_SET); |
538 | 66.0k | vers.m_majorVersion = static_cast<int>(m_input->readULong(1)); |
539 | 66.0k | vers.m_minorVersion = static_cast<int>(m_input->readULong(1)); |
540 | 66.0k | auto val = long(m_input->readULong(1)); |
541 | 66.0k | if (val) f << "devStage=" << val << ","; |
542 | 66.0k | val = long(m_input->readULong(1)); |
543 | 66.0k | if (val) f << "preReleaseLevel=" << std::hex << val << std::dec << ","; |
544 | 66.0k | vers.m_countryCode = static_cast<int>(m_input->readULong(2)); |
545 | 193k | for (int i = 0; i < 2; i++) { |
546 | 131k | auto sz = static_cast<int>(m_input->readULong(1)); |
547 | 131k | long pos = m_input->tell(); |
548 | 131k | if (pos+sz > entry.end()) { |
549 | 4.65k | MWAW_DEBUG_MSG(("MWAWRSRCParser::parseVers: can not read strings %d\n",i)); |
550 | 4.65k | return false; |
551 | 4.65k | } |
552 | 127k | std::string str(""); |
553 | 3.29M | for (int c = 0; c < sz; c++) |
554 | 3.16M | str+=char(m_input->readULong(1)); |
555 | 127k | if (i==0) |
556 | 65.7k | vers.m_versionString = str; |
557 | 61.3k | else |
558 | 61.3k | vers.m_string = str; |
559 | 127k | } |
560 | 61.3k | vers.m_extra = f.str(); |
561 | 61.3k | f << "Entries(RSRCvers)[" << entry.id() << "]:" << vers; |
562 | 61.3k | ascii().addPos(entry.begin()-4); |
563 | 61.3k | ascii().addNote(f.str().c_str()); |
564 | 61.3k | return true; |
565 | 66.0k | } |
566 | | |
567 | | //////////////////////////////////////////////////////////// |
568 | | // read a pict resource |
569 | | //////////////////////////////////////////////////////////// |
570 | | bool MWAWRSRCParser::parsePICT(MWAWEntry const &entry, librevenge::RVNGBinaryData &pict) |
571 | 6.67k | { |
572 | 6.67k | pict.clear(); |
573 | 6.67k | if (!m_input || !entry.valid() || entry.length()<0xd) { |
574 | 958 | MWAW_DEBUG_MSG(("MWAWRSRCParser::parsePICT: entry is invalid\n")); |
575 | 958 | return false; |
576 | 958 | } |
577 | | |
578 | 5.71k | libmwaw::DebugStream f; |
579 | 5.71k | f << "Entries(RSRC" << entry.type() << ")[" << entry.id() << "]:"; |
580 | 5.71k | m_input->seek(entry.begin(), librevenge::RVNG_SEEK_SET); |
581 | 5.71k | m_input->readDataBlock(entry.length(), pict); |
582 | | |
583 | | #ifdef DEBUG_WITH_FILES |
584 | | if (!entry.isParsed()) { |
585 | | ascii().skipZone(entry.begin(), entry.end()-1); |
586 | | libmwaw::DebugStream f2; |
587 | | f2 << "RSRC-" << entry.type() << "_" << entry.id() << ".pct"; |
588 | | libmwaw::Debug::dumpFile(pict, f2.str().c_str()); |
589 | | } |
590 | | #endif |
591 | | |
592 | 5.71k | ascii().addPos(entry.begin()-4); |
593 | 5.71k | ascii().addNote(f.str().c_str()); |
594 | | |
595 | 5.71k | entry.setParsed(true); |
596 | 5.71k | return true; |
597 | 6.67k | } |
598 | | // vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: |