/src/libvisio/src/lib/VSDParser.cpp
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* |
3 | | * This file is part of the libvisio project. |
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 | | |
10 | | #include "VSDParser.h" |
11 | | |
12 | | #include <librevenge-stream/librevenge-stream.h> |
13 | | #include <locale.h> |
14 | | #include <sstream> |
15 | | #include <string> |
16 | | #include <cmath> |
17 | | #include <set> |
18 | | #include "libvisio_utils.h" |
19 | | #include "VSDInternalStream.h" |
20 | | #include "VSDDocumentStructure.h" |
21 | | #include "VSDContentCollector.h" |
22 | | #include "VSDStylesCollector.h" |
23 | | #include "VSDMetaData.h" |
24 | | |
25 | | libvisio::VSDParser::VSDParser(librevenge::RVNGInputStream *input, librevenge::RVNGDrawingInterface *painter, librevenge::RVNGInputStream *container) |
26 | 31.8k | : m_input(input), m_painter(painter), m_container(container), m_header(), m_collector(nullptr), m_shapeList(), m_currentLevel(0), |
27 | 31.8k | m_stencils(), m_currentStencil(nullptr), m_shape(), m_isStencilStarted(false), m_isInStyles(false), |
28 | 31.8k | m_currentShapeLevel(0), m_currentShapeID(MINUS_ONE), m_currentLayerListLevel(0), m_extractStencils(false), m_colours(), |
29 | 31.8k | m_isBackgroundPage(false), m_isShapeStarted(false), m_shadowOffsetX(0.0), m_shadowOffsetY(0.0), |
30 | 31.8k | m_currentGeometryList(nullptr), m_currentGeomListCount(0), m_fonts(), m_names(), m_namesMapMap(), |
31 | 31.8k | m_currentPageName(), m_currentTabSet() |
32 | 31.8k | {} |
33 | | |
34 | | libvisio::VSDParser::~VSDParser() |
35 | 31.8k | { |
36 | 31.8k | } |
37 | | |
38 | | void libvisio::VSDParser::_nameFromId(VSDName &name, unsigned id, unsigned level) |
39 | 162k | { |
40 | 162k | name = VSDName(); |
41 | 162k | std::map<unsigned, std::map<unsigned, VSDName> >::const_iterator iter1 = m_namesMapMap.find(level); |
42 | 162k | if (iter1 != m_namesMapMap.end()) |
43 | 48.7k | { |
44 | 48.7k | auto iter = iter1->second.find(id); |
45 | 48.7k | if (iter != iter1->second.end()) |
46 | 1.19k | name = iter->second; |
47 | 48.7k | } |
48 | 162k | } |
49 | | |
50 | | bool libvisio::VSDParser::getChunkHeader(librevenge::RVNGInputStream *input) |
51 | 910k | { |
52 | 910k | unsigned char tmpChar = 0; |
53 | 13.9M | while (!input->isEnd() && !tmpChar) |
54 | 13.0M | tmpChar = readU8(input); |
55 | | |
56 | 910k | if (input->isEnd()) |
57 | 5.70k | return false; |
58 | 905k | else |
59 | 905k | input->seek(-1, librevenge::RVNG_SEEK_CUR); |
60 | | |
61 | 905k | m_header.chunkType = readU32(input); |
62 | 905k | m_header.id = readU32(input); |
63 | 905k | m_header.list = readU32(input); |
64 | | |
65 | | // Certain chunk types seem to always have a trailer |
66 | 905k | m_header.trailer = 0; |
67 | 905k | if (m_header.list != 0 || m_header.chunkType == 0x71 || m_header.chunkType == 0x70 || |
68 | 674k | m_header.chunkType == 0x6b || m_header.chunkType == 0x6a || m_header.chunkType == 0x69 || |
69 | 660k | m_header.chunkType == 0x66 || m_header.chunkType == 0x65 || m_header.chunkType == 0x2c) |
70 | 256k | m_header.trailer += 8; // 8 byte trailer |
71 | | |
72 | 905k | m_header.dataLength = readU32(input); |
73 | 905k | m_header.level = readU16(input); |
74 | 905k | m_header.unknown = readU8(input); |
75 | | |
76 | 905k | unsigned trailerChunks [14] = {0x64, 0x65, 0x66, 0x69, 0x6a, 0x6b, 0x6f, 0x71, |
77 | 905k | 0x92, 0xa9, 0xb4, 0xb6, 0xb9, 0xc7 |
78 | 905k | }; |
79 | | // Add word separator under certain circumstances for v11 |
80 | | // Below are known conditions, may be more or a simpler pattern |
81 | 905k | if (m_header.list != 0 || (m_header.level == 2 && m_header.unknown == 0x55) || |
82 | 651k | (m_header.level == 2 && m_header.unknown == 0x54 && m_header.chunkType == 0xaa) |
83 | 650k | || (m_header.level == 3 && m_header.unknown != 0x50 && m_header.unknown != 0x54)) |
84 | 338k | { |
85 | 338k | m_header.trailer += 4; |
86 | 338k | } |
87 | | |
88 | 905k | for (unsigned int trailerChunk : trailerChunks) |
89 | 12.3M | { |
90 | 12.3M | if (m_header.chunkType == trailerChunk && m_header.trailer != 12 && m_header.trailer != 4) |
91 | 38.1k | { |
92 | 38.1k | m_header.trailer += 4; |
93 | 38.1k | break; |
94 | 38.1k | } |
95 | 12.3M | } |
96 | | |
97 | | // Some chunks never have a trailer |
98 | 905k | if (m_header.chunkType == 0x1f || m_header.chunkType == 0xc9 || |
99 | 881k | m_header.chunkType == 0x2d || m_header.chunkType == 0xd1) |
100 | 27.8k | { |
101 | 27.8k | m_header.trailer = 0; |
102 | 27.8k | } |
103 | 905k | return true; |
104 | 910k | } |
105 | | |
106 | | bool libvisio::VSDParser::parseMain() |
107 | 31.8k | { |
108 | 31.8k | if (!m_input) |
109 | 0 | { |
110 | 0 | return false; |
111 | 0 | } |
112 | | // Seek to trailer stream pointer |
113 | 31.8k | m_input->seek(0x24, librevenge::RVNG_SEEK_SET); |
114 | | |
115 | 31.8k | Pointer trailerPointer; |
116 | 31.8k | readPointer(m_input, trailerPointer); |
117 | 31.8k | bool compressed = ((trailerPointer.Format & 2) == 2); |
118 | 31.8k | unsigned shift = 0; |
119 | 31.8k | if (compressed) |
120 | 25.0k | shift = 4; |
121 | | |
122 | 31.8k | m_input->seek(trailerPointer.Offset, librevenge::RVNG_SEEK_SET); |
123 | 31.8k | VSDInternalStream trailerStream(m_input, trailerPointer.Length, compressed); |
124 | | |
125 | 31.8k | std::vector<std::map<unsigned, XForm> > groupXFormsSequence; |
126 | 31.8k | std::vector<std::map<unsigned, unsigned> > groupMembershipsSequence; |
127 | 31.8k | std::vector<std::list<unsigned> > documentPageShapeOrders; |
128 | | |
129 | 31.8k | VSDStylesCollector stylesCollector(groupXFormsSequence, groupMembershipsSequence, documentPageShapeOrders); |
130 | 31.8k | m_collector = &stylesCollector; |
131 | 31.8k | VSD_DEBUG_MSG(("VSDParser::parseMain 1st pass\n")); |
132 | 31.8k | if (!parseDocument(&trailerStream, shift)) |
133 | 4.64k | return false; |
134 | | |
135 | 27.2k | _handleLevelChange(0); |
136 | | |
137 | 27.2k | VSDStyles styles = stylesCollector.getStyleSheets(); |
138 | 27.2k | const std::optional<unsigned> varColInd = stylesCollector.getvariationColorIndex(); |
139 | 27.2k | const std::optional<unsigned> varStyInd = stylesCollector.getvariationStyleIndex(); |
140 | | |
141 | 27.2k | VSDContentCollector contentCollector(m_painter, groupXFormsSequence, groupMembershipsSequence, documentPageShapeOrders, styles, m_stencils, varColInd, varStyInd); |
142 | 27.2k | m_collector = &contentCollector; |
143 | 27.2k | if (m_container) |
144 | 5.60k | parseMetaData(); |
145 | | |
146 | 27.2k | VSD_DEBUG_MSG(("VSDParser::parseMain 2nd pass\n")); |
147 | 27.2k | if (!parseDocument(&trailerStream, shift)) |
148 | 19 | return false; |
149 | | |
150 | 27.2k | return true; |
151 | 27.2k | } |
152 | | |
153 | 6.18k | void libvisio::VSDParser::parseMetaData() try |
154 | 6.18k | { |
155 | 6.18k | if (!m_container) |
156 | 0 | return; |
157 | 6.18k | m_container->seek(0, librevenge::RVNG_SEEK_SET); |
158 | 6.18k | if (!m_container->isStructured()) |
159 | 5.01k | return; |
160 | 1.17k | VSDMetaData metaData; |
161 | | |
162 | 1.17k | const RVNGInputStreamPtr_t sumaryInfo(m_container->getSubStreamByName("\x05SummaryInformation")); |
163 | 1.17k | if (bool(sumaryInfo)) |
164 | 496 | metaData.parse(sumaryInfo.get()); |
165 | | |
166 | 1.17k | const RVNGInputStreamPtr_t docSumaryInfo(m_container->getSubStreamByName("\005DocumentSummaryInformation")); |
167 | 1.17k | if (bool(docSumaryInfo)) |
168 | 479 | metaData.parse(docSumaryInfo.get()); |
169 | | |
170 | 1.17k | m_container->seek(0, librevenge::RVNG_SEEK_SET); |
171 | 1.17k | metaData.parseTimes(m_container); |
172 | 1.17k | m_collector->collectMetaData(metaData.getMetaData()); |
173 | 1.17k | } |
174 | 6.18k | catch (...) |
175 | 6.18k | { |
176 | | // Ignore any exceptions in metadata. They are not important enough to stop parsing. |
177 | 176 | } |
178 | | |
179 | | bool libvisio::VSDParser::parseDocument(librevenge::RVNGInputStream *input, unsigned shift) |
180 | 59.0k | { |
181 | 59.0k | std::set<unsigned> visited; |
182 | 59.0k | try |
183 | 59.0k | { |
184 | 59.0k | handleStreams(input, VSD_TRAILER_STREAM, shift, 0, visited); |
185 | 59.0k | return true; |
186 | 59.0k | } |
187 | 59.0k | catch (...) |
188 | 59.0k | { |
189 | 4.66k | return false; |
190 | 4.66k | } |
191 | 59.0k | } |
192 | | |
193 | | bool libvisio::VSDParser::extractStencils() |
194 | 0 | { |
195 | 0 | m_extractStencils = true; |
196 | 0 | return parseMain(); |
197 | 0 | } |
198 | | |
199 | | void libvisio::VSDParser::readPointer(librevenge::RVNGInputStream *input, Pointer &ptr) |
200 | 1.92M | { |
201 | 1.92M | ptr.Type = readU32(input); |
202 | 1.92M | input->seek(4, librevenge::RVNG_SEEK_CUR); // Skip dword |
203 | 1.92M | ptr.Offset = readU32(input); |
204 | 1.92M | ptr.Length = readU32(input); |
205 | 1.92M | ptr.Format = readU16(input); |
206 | 1.92M | } |
207 | | |
208 | | void libvisio::VSDParser::readPointerInfo(librevenge::RVNGInputStream *input, unsigned /* ptrType */, unsigned shift, unsigned &listSize, int &pointerCount) |
209 | 43.7k | { |
210 | 43.7k | VSD_DEBUG_MSG(("VSDParser::readPointerInfo\n")); |
211 | 43.7k | input->seek(shift, librevenge::RVNG_SEEK_SET); |
212 | 43.7k | unsigned offset = readU32(input); |
213 | 43.7k | input->seek(offset+shift-4, librevenge::RVNG_SEEK_SET); |
214 | 43.7k | listSize = readU32(input); |
215 | 43.7k | pointerCount = readS32(input); |
216 | 43.7k | input->seek(4, librevenge::RVNG_SEEK_CUR); |
217 | 43.7k | } |
218 | | |
219 | | void libvisio::VSDParser::handleStreams(librevenge::RVNGInputStream *input, unsigned ptrType, unsigned shift, unsigned level, std::set<unsigned> &visited) |
220 | 197k | { |
221 | 197k | VSD_DEBUG_MSG(("VSDParser::HandleStreams\n")); |
222 | 197k | std::vector<unsigned> pointerOrder; |
223 | 197k | std::map<unsigned, libvisio::Pointer> PtrList; |
224 | 197k | std::map<unsigned, libvisio::Pointer> FontFaces; |
225 | 197k | std::map<unsigned, libvisio::Pointer> NameList; |
226 | 197k | std::map<unsigned, libvisio::Pointer> NameIDX; |
227 | | |
228 | 197k | try |
229 | 197k | { |
230 | | // Parse out pointers to streams |
231 | 197k | unsigned listSize = 0; |
232 | 197k | int pointerCount = 0; |
233 | 197k | readPointerInfo(input, ptrType, shift, listSize, pointerCount); |
234 | 20.3M | for (int i = 0; i < pointerCount; i++) |
235 | 20.1M | { |
236 | 20.1M | Pointer ptr; |
237 | 20.1M | readPointer(input, ptr); |
238 | 20.1M | if (ptr.Type == 0) |
239 | 5.88M | continue; |
240 | | |
241 | 14.2M | if (ptr.Type == VSD_FONTFACES) |
242 | 36.3k | FontFaces[i] = ptr; |
243 | 14.2M | else if (ptr.Type == VSD_NAME_LIST2) |
244 | 86.7k | NameList[i] = ptr; |
245 | 14.1M | else if (ptr.Type == VSD_NAMEIDX || ptr.Type == VSD_NAMEIDX123) |
246 | 1.04M | NameIDX[i] = ptr; |
247 | 13.0M | else if (ptr.Type) |
248 | 13.0M | PtrList[i] = ptr; |
249 | 14.2M | } |
250 | 197k | if (listSize <= 1) |
251 | 62.2k | listSize = 0; |
252 | 1.72M | while (listSize--) |
253 | 1.52M | pointerOrder.push_back(readU32(input)); |
254 | 197k | } |
255 | 197k | catch (const EndOfStreamException &) |
256 | 197k | { |
257 | 127k | pointerOrder.clear(); |
258 | 127k | PtrList.clear(); |
259 | 127k | FontFaces.clear(); |
260 | 127k | NameList.clear(); |
261 | 127k | } |
262 | | |
263 | 197k | std::map<unsigned, libvisio::Pointer>::iterator iter; |
264 | 217k | for (iter = NameList.begin(); iter != NameList.end(); ++iter) |
265 | 20.0k | handleStream(iter->second, iter->first, level+1, visited); |
266 | | |
267 | 1.23M | for (iter = NameIDX.begin(); iter != NameIDX.end(); ++iter) |
268 | 1.04M | handleStream(iter->second, iter->first, level+1, visited); |
269 | | |
270 | 208k | for (iter = FontFaces.begin(); iter != FontFaces.end(); ++iter) |
271 | 11.2k | handleStream(iter->second, iter->first, level+1, visited); |
272 | | |
273 | 197k | if (!pointerOrder.empty()) |
274 | 7.65k | { |
275 | 7.65k | for (unsigned int j : pointerOrder) |
276 | 448k | { |
277 | 448k | iter = PtrList.find(j); |
278 | 448k | if (iter != PtrList.end()) |
279 | 42.6k | { |
280 | 42.6k | handleStream(iter->second, iter->first, level+1, visited); |
281 | 42.6k | PtrList.erase(iter); |
282 | 42.6k | } |
283 | 448k | } |
284 | 7.65k | } |
285 | 4.33M | for (iter = PtrList.begin(); iter != PtrList.end(); ++iter) |
286 | 4.13M | handleStream(iter->second, iter->first, level+1, visited); |
287 | | |
288 | 197k | } |
289 | | |
290 | | void libvisio::VSDParser::handleStream(const Pointer &ptr, unsigned idx, unsigned level, std::set<unsigned> &visited) |
291 | 5.25M | { |
292 | 5.25M | VSD_DEBUG_MSG(("VSDParser::HandleStream %u type 0x%x\n", idx, ptr.Type)); |
293 | 5.25M | m_header.level = level; |
294 | 5.25M | m_header.id = idx; |
295 | 5.25M | m_header.chunkType = ptr.Type; |
296 | 5.25M | _handleLevelChange(level); |
297 | 5.25M | VSDStencil tmpStencil; |
298 | 5.25M | bool compressed = ((ptr.Format & 2) == 2); |
299 | 5.25M | m_input->seek(ptr.Offset, librevenge::RVNG_SEEK_SET); |
300 | 5.25M | VSDInternalStream tmpInput(m_input, ptr.Length, compressed); |
301 | 5.25M | m_header.dataLength = tmpInput.getSize(); |
302 | 5.25M | unsigned shift = compressed ? 4 : 0; |
303 | 5.25M | switch (ptr.Type) |
304 | 5.25M | { |
305 | 18.8k | case VSD_STYLES: |
306 | 18.8k | m_isInStyles = true; |
307 | 18.8k | break; |
308 | 46.3k | case VSD_PAGES: |
309 | 46.3k | if (m_extractStencils) |
310 | 0 | return; |
311 | 46.3k | break; |
312 | 162k | case VSD_PAGE: |
313 | 162k | if (m_extractStencils) |
314 | 0 | return; |
315 | 162k | if (!(ptr.Format&0x1)) |
316 | 66.9k | m_isBackgroundPage = true; |
317 | 95.4k | else |
318 | 95.4k | m_isBackgroundPage = false; |
319 | 162k | _nameFromId(m_currentPageName, idx, level+1); |
320 | 162k | m_collector->startPage(idx); |
321 | 162k | break; |
322 | 29.9k | case VSD_STENCILS: |
323 | 29.9k | if (m_extractStencils) |
324 | 0 | break; |
325 | 29.9k | if (m_stencils.count()) |
326 | 11.2k | return; |
327 | 18.7k | m_isStencilStarted = true; |
328 | 18.7k | break; |
329 | 71.2k | case VSD_STENCIL_PAGE: |
330 | 71.2k | if (m_extractStencils) |
331 | 0 | { |
332 | 0 | m_isBackgroundPage = false; |
333 | 0 | _nameFromId(m_currentPageName, idx, level+1); |
334 | 0 | m_collector->startPage(idx); |
335 | 0 | } |
336 | 71.2k | else |
337 | 71.2k | m_currentStencil = &tmpStencil; |
338 | 71.2k | break; |
339 | 15.6k | case VSD_SHAPE_GROUP: |
340 | 44.3k | case VSD_SHAPE_SHAPE: |
341 | 114k | case VSD_SHAPE_FOREIGN: |
342 | 114k | m_currentShapeID = idx; |
343 | 114k | break; |
344 | 28.3k | case VSD_OLE_LIST: |
345 | 28.3k | if (!m_shape.m_foreign) |
346 | 15.8k | m_shape.m_foreign = std::make_unique<ForeignData>(); |
347 | 28.3k | m_shape.m_foreign->dataId = idx; |
348 | 28.3k | break; |
349 | 4.78M | default: |
350 | 4.78M | break; |
351 | 5.25M | } |
352 | | |
353 | 5.24M | if ((ptr.Format >> 4) == 0x4 || (ptr.Format >> 4) == 0x5 || (ptr.Format >> 4) == 0x0) |
354 | 2.22M | { |
355 | 2.22M | handleBlob(&tmpInput, shift, level+1); |
356 | 2.22M | if ((ptr.Format >> 4) == 0x5 && ptr.Type != VSD_COLORS) |
357 | 326k | { |
358 | | // Each stream offset is handled once, however many pointers reach it. |
359 | 326k | if (visited.insert(ptr.Offset).second) |
360 | 138k | handleStreams(&tmpInput, ptr.Type, shift, level+1, visited); |
361 | 326k | } |
362 | 2.22M | } |
363 | 3.01M | else if ((ptr.Format >> 4) == 0xd || (ptr.Format >> 4) == 0xc || (ptr.Format >> 4) == 0x8) |
364 | 888k | handleChunks(&tmpInput, level+1); |
365 | | |
366 | 5.24M | switch (ptr.Type) |
367 | 5.24M | { |
368 | 18.5k | case VSD_STYLES: |
369 | 18.5k | _handleLevelChange(0); |
370 | 18.5k | m_isInStyles = false; |
371 | 18.5k | break; |
372 | 161k | case VSD_PAGE: |
373 | 161k | _handleLevelChange(0); |
374 | 161k | m_collector->endPage(); |
375 | 161k | break; |
376 | 46.2k | case VSD_PAGES: |
377 | 46.2k | _handleLevelChange(0); |
378 | 46.2k | m_collector->endPages(); |
379 | 46.2k | break; |
380 | 18.5k | case VSD_STENCILS: |
381 | 18.5k | _handleLevelChange(0); |
382 | 18.5k | if (m_extractStencils) |
383 | 0 | m_collector->endPages(); |
384 | 18.5k | else |
385 | 18.5k | m_isStencilStarted = false; |
386 | 18.5k | break; |
387 | 71.1k | case VSD_STENCIL_PAGE: |
388 | 71.1k | _handleLevelChange(0); |
389 | 71.1k | if (m_extractStencils) |
390 | 0 | m_collector->endPage(); |
391 | 71.1k | else if (m_currentStencil) |
392 | 71.0k | { |
393 | 71.0k | m_stencils.addStencil(idx, *m_currentStencil); |
394 | 71.0k | m_currentStencil = nullptr; |
395 | 71.0k | } |
396 | 71.1k | break; |
397 | 15.6k | case VSD_SHAPE_GROUP: |
398 | 44.2k | case VSD_SHAPE_SHAPE: |
399 | 114k | case VSD_SHAPE_FOREIGN: |
400 | 114k | if (m_isStencilStarted) |
401 | 4.91k | { |
402 | 4.91k | _handleLevelChange(0); |
403 | 4.91k | if (m_currentStencil) |
404 | 3.82k | m_currentStencil->addStencilShape(m_shape.m_shapeId, m_shape); |
405 | 4.91k | } |
406 | 114k | break; |
407 | 4.80M | default: |
408 | 4.80M | break; |
409 | 5.24M | } |
410 | | |
411 | 5.24M | } |
412 | | |
413 | | void libvisio::VSDParser::handleBlob(librevenge::RVNGInputStream *input, unsigned shift, unsigned level) |
414 | 2.22M | { |
415 | 2.22M | try |
416 | 2.22M | { |
417 | 2.22M | m_header.level = level; |
418 | 2.22M | input->seek(shift, librevenge::RVNG_SEEK_SET); |
419 | 2.22M | m_header.dataLength -= shift; |
420 | 2.22M | _handleLevelChange(m_header.level); |
421 | 2.22M | handleChunk(input); |
422 | 2.22M | } |
423 | 2.22M | catch (EndOfStreamException &) |
424 | 2.22M | { |
425 | 376k | VSD_DEBUG_MSG(("VSDParser::handleBlob - catching EndOfStreamException\n")); |
426 | 376k | } |
427 | 2.22M | } |
428 | | |
429 | | void libvisio::VSDParser::handleChunks(librevenge::RVNGInputStream *input, unsigned level) |
430 | 888k | { |
431 | 888k | long endPos = 0; |
432 | | |
433 | 9.69M | while (!input->isEnd()) |
434 | 8.83M | { |
435 | 8.83M | if (!getChunkHeader(input)) |
436 | 20.3k | return; |
437 | 8.81M | m_header.level += level; |
438 | 8.81M | endPos = m_header.dataLength+m_header.trailer+input->tell(); |
439 | | |
440 | 8.81M | _handleLevelChange(m_header.level); |
441 | 8.81M | VSD_DEBUG_MSG(("VSDParser::handleChunks - parsing chunk type 0x%x\n", m_header.chunkType)); |
442 | 8.81M | handleChunk(input); |
443 | 8.81M | input->seek(endPos, librevenge::RVNG_SEEK_SET); |
444 | 8.81M | } |
445 | 888k | } |
446 | | |
447 | | void libvisio::VSDParser::handleChunk(librevenge::RVNGInputStream *input) |
448 | 11.0M | { |
449 | 11.0M | switch (m_header.chunkType) |
450 | 11.0M | { |
451 | 101k | case VSD_SHAPE_GROUP: |
452 | 316k | case VSD_SHAPE_SHAPE: |
453 | 725k | case VSD_SHAPE_FOREIGN: |
454 | 725k | readShape(input); |
455 | 725k | break; |
456 | 20.1k | case VSD_XFORM_DATA: |
457 | 20.1k | readXFormData(input); |
458 | 20.1k | break; |
459 | 13.0k | case VSD_XFORM_1D: |
460 | 13.0k | readXForm1D(input); |
461 | 13.0k | break; |
462 | 29.3k | case VSD_TEXT_XFORM: |
463 | 29.3k | readTxtXForm(input); |
464 | 29.3k | break; |
465 | 47.8k | case VSD_SHAPE_LIST: |
466 | 47.8k | readShapeList(input); |
467 | 47.8k | break; |
468 | 282k | case VSD_SHAPE_ID: |
469 | 282k | readShapeId(input); |
470 | 282k | break; |
471 | 131k | case VSD_LINE: |
472 | 131k | readLine(input); |
473 | 131k | break; |
474 | 41.8k | case VSD_PROP_LIST: |
475 | 41.8k | readPropList(input); |
476 | 41.8k | break; |
477 | 139k | case VSD_FILL_AND_SHADOW: |
478 | 139k | readFillAndShadow(input); |
479 | 139k | break; |
480 | 305k | case VSD_GEOM_LIST: |
481 | 305k | readGeomList(input); |
482 | 305k | break; |
483 | 45.8k | case VSD_GEOMETRY: |
484 | 45.8k | readGeometry(input); |
485 | 45.8k | break; |
486 | 202k | case VSD_MOVE_TO: |
487 | 202k | readMoveTo(input); |
488 | 202k | break; |
489 | 183k | case VSD_LINE_TO: |
490 | 183k | readLineTo(input); |
491 | 183k | break; |
492 | 83.7k | case VSD_ARC_TO: |
493 | 83.7k | readArcTo(input); |
494 | 83.7k | break; |
495 | 66.6k | case VSD_ELLIPSE: |
496 | 66.6k | readEllipse(input); |
497 | 66.6k | break; |
498 | 62.7k | case VSD_ELLIPTICAL_ARC_TO: |
499 | 62.7k | readEllipticalArcTo(input); |
500 | 62.7k | break; |
501 | 68.6k | case VSD_NURBS_TO: |
502 | 68.6k | readNURBSTo(input); |
503 | 68.6k | break; |
504 | 59.7k | case VSD_POLYLINE_TO: |
505 | 59.7k | readPolylineTo(input); |
506 | 59.7k | break; |
507 | 100k | case VSD_INFINITE_LINE: |
508 | 100k | readInfiniteLine(input); |
509 | 100k | break; |
510 | 242k | case VSD_SHAPE_DATA: |
511 | 242k | readShapeData(input); |
512 | 242k | break; |
513 | 102k | case VSD_FOREIGN_DATA_TYPE: |
514 | 102k | readForeignDataType(input); |
515 | 102k | break; |
516 | 64.6k | case VSD_FOREIGN_DATA: |
517 | 64.6k | readForeignData(input); |
518 | 64.6k | break; |
519 | 52.3k | case VSD_OLE_LIST: |
520 | 52.3k | readOLEList(input); |
521 | 52.3k | break; |
522 | 23.0k | case VSD_OLE_DATA: |
523 | 23.0k | readOLEData(input); |
524 | 23.0k | break; |
525 | 77.0k | case VSD_NAMEIDX: |
526 | 77.0k | readNameIDX(input); |
527 | 77.0k | break; |
528 | 289k | case VSD_NAMEIDX123: |
529 | 289k | readNameIDX123(input); |
530 | 289k | break; |
531 | 26.0k | case VSD_PAGE_PROPS: |
532 | 26.0k | readPageProps(input); |
533 | 26.0k | break; |
534 | 56.8k | case VSD_CHAR_LIST: |
535 | 56.8k | readCharList(input); |
536 | 56.8k | break; |
537 | 19.9k | case VSD_PARA_LIST: |
538 | 19.9k | readParaList(input); |
539 | 19.9k | break; |
540 | 138k | case VSD_TEXT: |
541 | 138k | readText(input); |
542 | 138k | break; |
543 | 159k | case VSD_CHAR_IX: |
544 | 159k | readCharIX(input); |
545 | 159k | break; |
546 | 133k | case VSD_PARA_IX: |
547 | 133k | readParaIX(input); |
548 | 133k | break; |
549 | 41.2k | case VSD_TEXT_BLOCK: |
550 | 41.2k | readTextBlock(input); |
551 | 41.2k | break; |
552 | 63.7k | case VSD_FONT_IX: // ver 6 only |
553 | 63.7k | readFontIX(input); |
554 | 63.7k | break; |
555 | 101k | case VSD_PAGE: |
556 | 101k | readPage(input); |
557 | 101k | break; |
558 | 35.1k | case VSD_STENCIL_PAGE: |
559 | 35.1k | if (m_extractStencils) |
560 | 0 | readPage(input); |
561 | 35.1k | break; |
562 | 41.6k | case VSD_SPLINE_START: |
563 | 41.6k | readSplineStart(input); |
564 | 41.6k | break; |
565 | 56.4k | case VSD_SPLINE_KNOT: |
566 | 56.4k | readSplineKnot(input); |
567 | 56.4k | break; |
568 | 29.4k | case VSD_NAME_LIST: |
569 | 29.4k | readNameList(input); |
570 | 29.4k | break; |
571 | 53.3k | case VSD_NAME_LIST2: |
572 | 53.3k | readNameList2(input); |
573 | 53.3k | break; |
574 | 33.6k | case VSD_NAME: |
575 | 33.6k | readName(input); |
576 | 33.6k | break; |
577 | 110k | case VSD_NAME2: |
578 | 110k | readName2(input); |
579 | 110k | break; |
580 | 24.7k | case VSD_FIELD_LIST: |
581 | 24.7k | readFieldList(input); |
582 | 24.7k | break; |
583 | 65.2k | case VSD_TEXT_FIELD: |
584 | 65.2k | readTextField(input); |
585 | 65.2k | break; |
586 | 565k | case VSD_STYLE_SHEET: |
587 | 565k | readStyleSheet(input); |
588 | 565k | break; |
589 | 20.6k | case VSD_PAGE_SHEET: |
590 | 20.6k | readPageSheet(input); |
591 | 20.6k | break; |
592 | 9.12k | case VSD_COLORS: |
593 | 9.12k | readColours(input); |
594 | 9.12k | break; |
595 | 51.1k | case VSD_FONTFACE: // substreams of FONTAFACES stream, ver 11 only |
596 | 51.1k | readFont(input); |
597 | 51.1k | break; |
598 | 26.4k | case VSD_MISC: |
599 | 26.4k | readMisc(input); |
600 | 26.4k | break; |
601 | 25.4k | case VSD_LAYER_LIST: |
602 | 25.4k | readLayerList(input); |
603 | 25.4k | break; |
604 | 56.9k | case VSD_LAYER: |
605 | 56.9k | readLayer(input); |
606 | 56.9k | break; |
607 | 59.6k | case VSD_LAYER_MEMBERSHIP: |
608 | 59.6k | readLayerMem(input); |
609 | 59.6k | break; |
610 | 16.3k | case VSD_TABS_DATA_LIST: |
611 | 16.3k | readTabsDataList(input); |
612 | 16.3k | break; |
613 | 11.9k | case VSD_TABS_DATA_1: |
614 | 53.7k | case VSD_TABS_DATA_2: |
615 | 64.0k | case VSD_TABS_DATA_3: |
616 | 64.0k | readTabsData(input); |
617 | 64.0k | break; |
618 | 5.54M | default: |
619 | 5.54M | m_collector->collectUnhandledChunk(m_header.id, m_header.level); |
620 | 11.0M | } |
621 | 11.0M | } |
622 | | |
623 | | void libvisio::VSDParser::_flushShape() |
624 | 808k | { |
625 | 808k | if (!m_isShapeStarted) |
626 | 304k | return; |
627 | | |
628 | 503k | m_collector->collectShape(m_shape.m_shapeId, m_currentShapeLevel, m_shape.m_parent, m_shape.m_masterPage, m_shape.m_masterShape, m_shape.m_lineStyleId, m_shape.m_fillStyleId, m_shape.m_textStyleId, m_shape.m_aName); |
629 | | |
630 | 503k | m_collector->collectShapesOrder(0, m_currentShapeLevel+2, m_shape.m_shapeList.getShapesOrder()); |
631 | | |
632 | 503k | m_collector->collectXFormData(m_currentShapeLevel+2, m_shape.m_xform); |
633 | | |
634 | 503k | m_collector->collectLayerMem(m_currentShapeLevel+2, m_shape.m_layerMem); |
635 | | |
636 | 503k | m_collector->collectMisc(m_currentShapeLevel+2, m_shape.m_misc); |
637 | | |
638 | 503k | if (m_shape.m_txtxform) |
639 | 14.9k | m_collector->collectTxtXForm(m_currentShapeLevel+2, *(m_shape.m_txtxform)); |
640 | | |
641 | 503k | m_collector->collectLine(m_currentShapeLevel+2, m_shape.m_lineStyle.width, m_shape.m_lineStyle.colour, m_shape.m_lineStyle.pattern, |
642 | 503k | m_shape.m_lineStyle.startMarker, m_shape.m_lineStyle.endMarker, m_shape.m_lineStyle.cap, m_shape.m_lineStyle.rounding, |
643 | 503k | m_shape.m_lineStyle.qsLineColour, m_shape.m_lineStyle.qsLineMatrix); |
644 | | |
645 | 503k | m_collector->collectFillAndShadow(m_currentShapeLevel+2, m_shape.m_fillStyle.fgColour, m_shape.m_fillStyle.bgColour, m_shape.m_fillStyle.pattern, |
646 | 503k | m_shape.m_fillStyle.fgTransparency, m_shape.m_fillStyle.bgTransparency, m_shape.m_fillStyle.shadowPattern, |
647 | 503k | m_shape.m_fillStyle.shadowFgColour, m_shape.m_fillStyle.shadowOffsetX, m_shape.m_fillStyle.shadowOffsetY, |
648 | 503k | m_shape.m_fillStyle.qsFillColour, m_shape.m_fillStyle.qsShadowColour, m_shape.m_fillStyle.qsFillMatrix); |
649 | | |
650 | 503k | m_collector->collectTextBlock(m_currentShapeLevel+2, m_shape.m_textBlockStyle.leftMargin, m_shape.m_textBlockStyle.rightMargin, |
651 | 503k | m_shape.m_textBlockStyle.topMargin, m_shape.m_textBlockStyle.bottomMargin, m_shape.m_textBlockStyle.verticalAlign, |
652 | 503k | m_shape.m_textBlockStyle.isTextBkgndFilled, m_shape.m_textBlockStyle.textBkgndColour, |
653 | 503k | m_shape.m_textBlockStyle.defaultTabStop, m_shape.m_textBlockStyle.textDirection); |
654 | | |
655 | 503k | if (m_shape.m_foreign) |
656 | 30.6k | m_collector->collectForeignDataType(m_currentShapeLevel+2, m_shape.m_foreign->type, m_shape.m_foreign->format, |
657 | 30.6k | m_shape.m_foreign->offsetX, m_shape.m_foreign->offsetY, m_shape.m_foreign->width, m_shape.m_foreign->height); |
658 | | |
659 | 515k | for (std::map<unsigned, NURBSData>::const_iterator iterNurbs = m_shape.m_nurbsData.begin(); iterNurbs != m_shape.m_nurbsData.end(); ++iterNurbs) |
660 | 11.4k | m_collector->collectShapeData(iterNurbs->first, m_currentShapeLevel+2, iterNurbs->second.xType, iterNurbs->second.yType, |
661 | 11.4k | iterNurbs->second.degree, iterNurbs->second.lastKnot, iterNurbs->second.points, |
662 | 11.4k | iterNurbs->second.knots, iterNurbs->second.weights); |
663 | | |
664 | 508k | for (std::map<unsigned, PolylineData>::const_iterator iterPoly = m_shape.m_polylineData.begin(); iterPoly != m_shape.m_polylineData.end(); ++iterPoly) |
665 | 4.94k | m_collector->collectShapeData(iterPoly->first, m_currentShapeLevel+2, iterPoly->second.xType, iterPoly->second.yType, iterPoly->second.points); |
666 | | |
667 | 508k | for (std::map<unsigned, VSDName>::const_iterator iterName = m_shape.m_names.begin(); iterName != m_shape.m_names.end(); ++iterName) |
668 | 4.95k | m_collector->collectName(iterName->first, m_currentShapeLevel+2, iterName->second.m_data, iterName->second.m_format); |
669 | | |
670 | 503k | if (m_shape.m_foreign && m_shape.m_foreign->data.size()) |
671 | 16.5k | m_collector->collectForeignData(m_currentShapeLevel+1, m_shape.m_foreign->data); |
672 | | |
673 | 503k | m_collector->collectTabsDataList(m_currentShapeLevel+1, m_shape.m_tabSets); |
674 | | |
675 | 503k | if (!m_shape.m_fields.empty()) |
676 | 15.3k | m_shape.m_fields.handle(m_collector); |
677 | | |
678 | 503k | if (m_shape.m_text.size()) |
679 | 97.2k | m_collector->collectText(m_currentShapeLevel+1, m_shape.m_text, m_shape.m_textFormat); |
680 | | |
681 | | |
682 | 634k | for (std::map<unsigned, VSDGeometryList>::const_iterator iterGeom = m_shape.m_geometries.begin(); iterGeom != m_shape.m_geometries.end(); ++iterGeom) |
683 | 131k | iterGeom->second.handle(m_collector); |
684 | | |
685 | 503k | m_collector->collectDefaultCharStyle(m_shape.m_charStyle.charCount, m_shape.m_charStyle.font, m_shape.m_charStyle.colour, |
686 | 503k | m_shape.m_charStyle.size, m_shape.m_charStyle.bold, m_shape.m_charStyle.italic, m_shape.m_charStyle.underline, |
687 | 503k | m_shape.m_charStyle.doubleunderline, m_shape.m_charStyle.strikeout, m_shape.m_charStyle.doublestrikeout, |
688 | 503k | m_shape.m_charStyle.allcaps, m_shape.m_charStyle.initcaps, m_shape.m_charStyle.smallcaps, |
689 | 503k | m_shape.m_charStyle.superscript, m_shape.m_charStyle.subscript, m_shape.m_charStyle.scaleWidth); |
690 | | |
691 | 503k | m_shape.m_charList.handle(m_collector); |
692 | | |
693 | 503k | m_collector->collectDefaultParaStyle(m_shape.m_paraStyle.charCount, m_shape.m_paraStyle.indFirst, m_shape.m_paraStyle.indLeft, |
694 | 503k | m_shape.m_paraStyle.indRight, m_shape.m_paraStyle.spLine, m_shape.m_paraStyle.spBefore, |
695 | 503k | m_shape.m_paraStyle.spAfter, m_shape.m_paraStyle.align, m_shape.m_paraStyle.bullet, |
696 | 503k | m_shape.m_paraStyle.bulletStr, m_shape.m_paraStyle.bulletFont, m_shape.m_paraStyle.bulletFontSize, |
697 | 503k | m_shape.m_paraStyle.textPosAfterBullet, m_shape.m_paraStyle.flags); |
698 | | |
699 | 503k | m_shape.m_paraList.handle(m_collector); |
700 | 503k | } |
701 | | |
702 | | void libvisio::VSDParser::_handleLevelChange(unsigned level) |
703 | 16.6M | { |
704 | 16.6M | if (level == m_currentLevel) |
705 | 9.51M | return; |
706 | 7.11M | if (level <= m_currentShapeLevel+1) |
707 | 2.70M | { |
708 | 2.70M | if (!m_shape.m_geometries.empty() && m_currentGeometryList && m_currentGeometryList->empty()) |
709 | 43.2k | { |
710 | 43.2k | m_shape.m_geometries.erase(--m_currentGeomListCount); |
711 | 43.2k | m_currentGeometryList = nullptr; |
712 | 43.2k | } |
713 | 2.70M | m_collector->collectShapesOrder(0, m_currentShapeLevel+2, m_shapeList.getShapesOrder()); |
714 | 2.70M | m_shapeList.clear(); |
715 | | |
716 | 2.70M | } |
717 | 7.11M | if (level <= m_currentShapeLevel) |
718 | 836k | { |
719 | 836k | if (!m_isStencilStarted) |
720 | 808k | { |
721 | 808k | _flushShape(); |
722 | 808k | m_shape.clear(); |
723 | 808k | m_currentGeometryList = nullptr; |
724 | 808k | } |
725 | 836k | m_isShapeStarted = false; |
726 | 836k | m_currentShapeLevel = 0; |
727 | 836k | } |
728 | 7.11M | m_currentLevel = level; |
729 | 7.11M | } |
730 | | |
731 | | // --- READERS --- |
732 | | |
733 | | void libvisio::VSDParser::readEllipticalArcTo(librevenge::RVNGInputStream *input) |
734 | 62.7k | { |
735 | 62.7k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
736 | 62.7k | double x3 = readDouble(input); // End x |
737 | 62.7k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
738 | 62.7k | double y3 = readDouble(input); // End y |
739 | 62.7k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
740 | 62.7k | double x2 = readDouble(input); // Mid x |
741 | 62.7k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
742 | 62.7k | double y2 = readDouble(input); // Mid y |
743 | 62.7k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
744 | 62.7k | double angle = readDouble(input); // Angle |
745 | 62.7k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
746 | 62.7k | double ecc = readDouble(input); // Eccentricity |
747 | | |
748 | 62.7k | if (m_currentGeometryList) |
749 | 44.3k | m_currentGeometryList->addEllipticalArcTo(m_header.id, m_header.level, x3, y3, x2, y2, angle, ecc); |
750 | 62.7k | } |
751 | | |
752 | | |
753 | | void libvisio::VSDParser::readForeignData(librevenge::RVNGInputStream *input) |
754 | 64.6k | { |
755 | 64.6k | unsigned long tmpBytesRead = 0; |
756 | 64.6k | const unsigned char *buffer = input->read(m_header.dataLength, tmpBytesRead); |
757 | 64.6k | if (m_header.dataLength != tmpBytesRead) |
758 | 2.88k | return; |
759 | 61.7k | librevenge::RVNGBinaryData binaryData(buffer, tmpBytesRead); |
760 | | |
761 | 61.7k | if (!m_shape.m_foreign) |
762 | 15.3k | m_shape.m_foreign = std::make_unique<ForeignData>(); |
763 | 61.7k | m_shape.m_foreign->dataId = m_header.id; |
764 | 61.7k | m_shape.m_foreign->data = binaryData; |
765 | 61.7k | } |
766 | | |
767 | | void libvisio::VSDParser::readOLEList(librevenge::RVNGInputStream * /* input */) |
768 | 52.3k | { |
769 | 52.3k | } |
770 | | |
771 | | void libvisio::VSDParser::readOLEData(librevenge::RVNGInputStream *input) |
772 | 23.0k | { |
773 | 23.0k | unsigned long tmpBytesRead = 0; |
774 | 23.0k | const unsigned char *buffer = input->read(m_header.dataLength, tmpBytesRead); |
775 | 23.0k | if (m_header.dataLength != tmpBytesRead) |
776 | 1.95k | return; |
777 | 21.0k | librevenge::RVNGBinaryData oleData(buffer, tmpBytesRead); |
778 | | |
779 | 21.0k | if (!m_shape.m_foreign) |
780 | 6.97k | m_shape.m_foreign = std::make_unique<ForeignData>(); |
781 | | // Append data instead of setting it - allows multi-stream OLE objects |
782 | 21.0k | m_shape.m_foreign->data.append(oleData); |
783 | | |
784 | 21.0k | } |
785 | | |
786 | | void libvisio::VSDParser::readTabsData(librevenge::RVNGInputStream *input) |
787 | 64.0k | { |
788 | 64.0k | m_shape.m_tabSets[m_header.id].m_numChars = getUInt(input); |
789 | 64.0k | unsigned char numStops = readU8(input); |
790 | 64.0k | m_shape.m_tabSets[m_header.id].m_tabStops.clear(); |
791 | 761k | for (unsigned char i = 0; i < numStops; ++i) |
792 | 697k | { |
793 | 697k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
794 | 697k | m_shape.m_tabSets[m_header.id].m_tabStops[i].m_position = readDouble(input); |
795 | 697k | m_shape.m_tabSets[m_header.id].m_tabStops[i].m_alignment = readU8(input); |
796 | 697k | m_shape.m_tabSets[m_header.id].m_tabStops[i].m_leader = readU8(input); |
797 | 697k | } |
798 | 64.0k | } |
799 | | |
800 | | void libvisio::VSDParser::readNameIDX(librevenge::RVNGInputStream *input) |
801 | 25.8k | { |
802 | 25.8k | std::map<unsigned, VSDName> names; |
803 | 25.8k | unsigned recordCount = readU32(input); |
804 | 25.8k | if (recordCount > getRemainingLength(input) / 13) |
805 | 6.21k | recordCount = getRemainingLength(input) / 13; |
806 | 826k | for (unsigned i = 0; i < recordCount; ++i) |
807 | 800k | { |
808 | 800k | unsigned nameId = readU32(input); |
809 | 800k | if (nameId != readU32(input)) |
810 | 407k | { |
811 | 407k | VSD_DEBUG_MSG(("VSDParser::readNameIDX --> mismatch of first two dwords\n")); |
812 | 407k | } |
813 | 800k | unsigned elementId = readU32(input); |
814 | 800k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
815 | 800k | std::map<unsigned, VSDName>::const_iterator iter = m_names.find(nameId); |
816 | 800k | if (iter != m_names.end()) |
817 | 263k | names[elementId] = iter->second; |
818 | 800k | } |
819 | 25.8k | m_namesMapMap[m_header.level] = names; |
820 | 25.8k | } |
821 | | |
822 | | void libvisio::VSDParser::readNameIDX123(librevenge::RVNGInputStream *input) |
823 | 289k | { |
824 | 289k | std::map<unsigned, VSDName> names; |
825 | 289k | long endPosition = input->tell() + m_header.dataLength; |
826 | 423M | while (!input->isEnd() && input->tell() < endPosition) |
827 | 423M | { |
828 | 423M | unsigned nameId = getUInt(input); |
829 | 423M | unsigned elementId = getUInt(input); |
830 | 423M | std::map<unsigned, VSDName>::const_iterator iter = m_names.find(nameId); |
831 | 423M | if (iter != m_names.end()) |
832 | 25.5M | names[elementId] = iter->second; |
833 | 423M | } |
834 | 289k | m_namesMapMap[m_header.level] = names; |
835 | | |
836 | 289k | } |
837 | | |
838 | | void libvisio::VSDParser::readEllipse(librevenge::RVNGInputStream *input) |
839 | 66.6k | { |
840 | 66.6k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
841 | 66.6k | double cx = readDouble(input); |
842 | 66.6k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
843 | 66.6k | double cy = readDouble(input); |
844 | 66.6k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
845 | 66.6k | double xleft = readDouble(input); |
846 | 66.6k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
847 | 66.6k | double yleft = readDouble(input); |
848 | 66.6k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
849 | 66.6k | double xtop = readDouble(input); |
850 | 66.6k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
851 | 66.6k | double ytop = readDouble(input); |
852 | | |
853 | 66.6k | if (m_currentGeometryList) |
854 | 53.7k | m_currentGeometryList->addEllipse(m_header.id, m_header.level, cx, cy, xleft, yleft, xtop, ytop); |
855 | 66.6k | } |
856 | | |
857 | | void libvisio::VSDParser::readLine(librevenge::RVNGInputStream *input) |
858 | 16.9k | { |
859 | 16.9k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
860 | 16.9k | double strokeWidth = readDouble(input); |
861 | 16.9k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
862 | 16.9k | Colour c; |
863 | 16.9k | c.r = readU8(input); |
864 | 16.9k | c.g = readU8(input); |
865 | 16.9k | c.b = readU8(input); |
866 | 16.9k | c.a = readU8(input); |
867 | 16.9k | unsigned char linePattern = readU8(input); |
868 | 16.9k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
869 | 16.9k | double rounding = readDouble(input); |
870 | 16.9k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
871 | 16.9k | unsigned char startMarker = readU8(input); |
872 | 16.9k | unsigned char endMarker = readU8(input); |
873 | 16.9k | unsigned char lineCap = readU8(input); |
874 | | |
875 | 16.9k | if (m_isInStyles) |
876 | 6.00k | m_collector->collectLineStyle(m_header.level, strokeWidth, c, linePattern, startMarker, endMarker, lineCap, rounding, -1, -1); |
877 | 10.9k | else |
878 | 10.9k | m_shape.m_lineStyle.override(VSDOptionalLineStyle(strokeWidth, c, linePattern, startMarker, endMarker, lineCap, rounding, -1, -1)); |
879 | 16.9k | } |
880 | | |
881 | | void libvisio::VSDParser::readTextBlock(librevenge::RVNGInputStream *input) |
882 | 14.8k | { |
883 | 14.8k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
884 | 14.8k | double leftMargin = readDouble(input); |
885 | 14.8k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
886 | 14.8k | double rightMargin = readDouble(input); |
887 | 14.8k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
888 | 14.8k | double topMargin = readDouble(input); |
889 | 14.8k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
890 | 14.8k | double bottomMargin = readDouble(input); |
891 | 14.8k | unsigned char verticalAlign = readU8(input); |
892 | 14.8k | const unsigned char bgColourIdx = readU8(input); |
893 | | // The TextBkgnd cell can have any value from 0 through 24, or 255. |
894 | | // The values 0 and 255 (visTxtBlklOpaque) both indicate a transparent text background. |
895 | 14.8k | const bool isBgFilled = bgColourIdx != 0 && bgColourIdx != 0xff; |
896 | 14.8k | Colour c; |
897 | 14.8k | c.r = readU8(input); |
898 | 14.8k | c.g = readU8(input); |
899 | 14.8k | c.b = readU8(input); |
900 | 14.8k | c.a = readU8(input); |
901 | 14.8k | if (isBgFilled) |
902 | 5.47k | c = _colourFromIndex(bgColourIdx - 1); |
903 | 14.8k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
904 | 14.8k | double defaultTabStop = readDouble(input); |
905 | 14.8k | input->seek(12, librevenge::RVNG_SEEK_CUR); |
906 | 14.8k | unsigned char textDirection = readU8(input); |
907 | | |
908 | 14.8k | if (m_isInStyles) |
909 | 4.58k | m_collector->collectTextBlockStyle(m_header.level, leftMargin, rightMargin, topMargin, bottomMargin, |
910 | 4.58k | verticalAlign, isBgFilled, c, defaultTabStop, textDirection); |
911 | 10.2k | else |
912 | 10.2k | m_shape.m_textBlockStyle.override(VSDOptionalTextBlockStyle(leftMargin, rightMargin, topMargin, bottomMargin, |
913 | 10.2k | verticalAlign, isBgFilled, c, defaultTabStop, textDirection)); |
914 | 14.8k | } |
915 | | |
916 | | void libvisio::VSDParser::readGeomList(librevenge::RVNGInputStream *input) |
917 | 29.1k | { |
918 | 29.1k | if (!m_shape.m_geometries.empty() && m_currentGeometryList && m_currentGeometryList->empty()) |
919 | 6.40k | m_shape.m_geometries.erase(--m_currentGeomListCount); |
920 | | // Since this is a map, this will default construct an element and then |
921 | | // the m_currentGeometryList pointer takes its address and we will work |
922 | | // on it over that pointer. |
923 | 29.1k | m_currentGeometryList = &m_shape.m_geometries[m_currentGeomListCount++]; |
924 | | |
925 | 29.1k | if (m_header.trailer) |
926 | 22.9k | { |
927 | 22.9k | uint32_t subHeaderLength = readU32(input); |
928 | 22.9k | uint32_t childrenListLength = readU32(input); |
929 | 22.9k | input->seek(subHeaderLength, librevenge::RVNG_SEEK_CUR); |
930 | 22.9k | std::vector<unsigned> geometryOrder; |
931 | 22.9k | if (childrenListLength > getRemainingLength(input)) |
932 | 5.08k | childrenListLength = getRemainingLength(input); |
933 | 22.9k | geometryOrder.reserve(childrenListLength / sizeof(uint32_t)); |
934 | 2.36M | for (size_t i = 0; i < (childrenListLength / sizeof(uint32_t)); i++) |
935 | 2.34M | geometryOrder.push_back(readU32(input)); |
936 | | |
937 | 22.9k | if (m_currentGeometryList) |
938 | 22.6k | m_currentGeometryList->setElementsOrder(geometryOrder); |
939 | 22.9k | } |
940 | | |
941 | | // We want the collectors to still get the level information |
942 | 29.1k | if (!m_isStencilStarted) |
943 | 24.8k | m_collector->collectUnhandledChunk(m_header.id, m_header.level); |
944 | 29.1k | } |
945 | | |
946 | | void libvisio::VSDParser::readCharList(librevenge::RVNGInputStream *input) |
947 | 24.6k | { |
948 | | // We want the collectors to still get the level information |
949 | 24.6k | if (!m_isStencilStarted) |
950 | 23.3k | m_collector->collectUnhandledChunk(m_header.id, m_header.level); |
951 | | |
952 | 24.6k | if (m_header.trailer) |
953 | 23.3k | { |
954 | 23.3k | uint32_t subHeaderLength = readU32(input); |
955 | 23.3k | uint32_t childrenListLength = readU32(input); |
956 | 23.3k | input->seek(subHeaderLength, librevenge::RVNG_SEEK_CUR); |
957 | 23.3k | if (childrenListLength > getRemainingLength(input)) |
958 | 8.47k | childrenListLength = getRemainingLength(input); |
959 | 23.3k | std::vector<unsigned> characterOrder; |
960 | 23.3k | characterOrder.reserve(childrenListLength / sizeof(uint32_t)); |
961 | 6.04M | for (size_t i = 0; i < (childrenListLength / sizeof(uint32_t)); i++) |
962 | 6.01M | characterOrder.push_back(readU32(input)); |
963 | | |
964 | 23.3k | m_shape.m_charList.setElementsOrder(characterOrder); |
965 | 23.3k | } |
966 | 24.6k | } |
967 | | |
968 | | void libvisio::VSDParser::readParaList(librevenge::RVNGInputStream *input) |
969 | 12.9k | { |
970 | | // We want the collectors to still get the level information |
971 | 12.9k | if (!m_isStencilStarted) |
972 | 11.9k | m_collector->collectUnhandledChunk(m_header.id, m_header.level); |
973 | | |
974 | 12.9k | if (m_header.trailer) |
975 | 12.0k | { |
976 | 12.0k | uint32_t subHeaderLength = readU32(input); |
977 | 12.0k | uint32_t childrenListLength = readU32(input); |
978 | 12.0k | input->seek(subHeaderLength, librevenge::RVNG_SEEK_CUR); |
979 | 12.0k | if (childrenListLength > getRemainingLength(input)) |
980 | 4.36k | childrenListLength = getRemainingLength(input); |
981 | 12.0k | std::vector<unsigned> paragraphOrder; |
982 | 12.0k | paragraphOrder.reserve(childrenListLength / sizeof(uint32_t)); |
983 | 4.44M | for (size_t i = 0; i < (childrenListLength / sizeof(uint32_t)); i++) |
984 | 4.43M | paragraphOrder.push_back(readU32(input)); |
985 | | |
986 | 12.0k | m_shape.m_paraList.setElementsOrder(paragraphOrder); |
987 | 12.0k | } |
988 | 12.9k | } |
989 | | |
990 | | void libvisio::VSDParser::readPropList(librevenge::RVNGInputStream * /* input */) |
991 | 26.7k | { |
992 | 26.7k | } |
993 | | |
994 | | void libvisio::VSDParser::readTabsDataList(librevenge::RVNGInputStream *input) |
995 | 7.78k | { |
996 | | // We want the collectors to still get the level information |
997 | 7.78k | if (!m_isStencilStarted) |
998 | 6.55k | m_collector->collectUnhandledChunk(m_header.id, m_header.level); |
999 | | |
1000 | 7.78k | if (m_header.trailer) |
1001 | 7.10k | { |
1002 | 7.10k | uint32_t subHeaderLength = readU32(input); |
1003 | 7.10k | uint32_t childrenListLength = readU32(input); |
1004 | 7.10k | input->seek(subHeaderLength, librevenge::RVNG_SEEK_CUR); |
1005 | 7.10k | if (childrenListLength > getRemainingLength(input)) |
1006 | 2.08k | childrenListLength = getRemainingLength(input); |
1007 | 7.10k | std::vector<unsigned> tabsOrder; |
1008 | 7.10k | tabsOrder.reserve(childrenListLength / sizeof(uint32_t)); |
1009 | 525k | for (size_t i = 0; i < (childrenListLength / sizeof(uint32_t)); i++) |
1010 | 518k | tabsOrder.push_back(readU32(input)); |
1011 | 7.10k | } |
1012 | 7.78k | } |
1013 | | |
1014 | | void libvisio::VSDParser::readLayerList(librevenge::RVNGInputStream *input) |
1015 | 25.4k | { |
1016 | | // We want the collectors to still get the level information |
1017 | 25.4k | if (!m_isStencilStarted) |
1018 | 23.2k | m_collector->collectUnhandledChunk(m_header.id, m_header.level); |
1019 | | |
1020 | 25.4k | if (m_header.trailer) |
1021 | 8.37k | { |
1022 | 8.37k | uint32_t subHeaderLength = readU32(input); |
1023 | 8.37k | uint32_t childrenListLength = readU32(input); |
1024 | 8.37k | input->seek(subHeaderLength, librevenge::RVNG_SEEK_CUR); |
1025 | 8.37k | if (childrenListLength > getRemainingLength(input)) |
1026 | 2.31k | childrenListLength = getRemainingLength(input); |
1027 | 8.37k | std::vector<unsigned> layerOrder; |
1028 | 8.37k | layerOrder.reserve(childrenListLength / sizeof(uint32_t)); |
1029 | 695k | for (size_t i = 0; i < (childrenListLength / sizeof(uint32_t)); i++) |
1030 | 687k | layerOrder.push_back(readU32(input)); |
1031 | 8.37k | } |
1032 | 25.4k | } |
1033 | | |
1034 | | void libvisio::VSDParser::readLayer(librevenge::RVNGInputStream *input) |
1035 | 56.9k | { |
1036 | 56.9k | libvisio::VSDLayer layer; |
1037 | 56.9k | input->seek(8, librevenge::RVNG_SEEK_CUR); |
1038 | 56.9k | unsigned char colourId = readU8(input); |
1039 | 56.9k | if (colourId == 0xff) |
1040 | 2.53k | input->seek(4, librevenge::RVNG_SEEK_CUR); |
1041 | 54.4k | else |
1042 | 54.4k | { |
1043 | 54.4k | libvisio::Colour colour; |
1044 | 54.4k | colour.r = readU8(input); |
1045 | 54.4k | colour.g = readU8(input); |
1046 | 54.4k | colour.b = readU8(input); |
1047 | 54.4k | colour.a = readU8(input); |
1048 | 54.4k | layer.m_colour = colour; |
1049 | 54.4k | } |
1050 | 56.9k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1051 | 56.9k | layer.m_visible = !!readU8(input); |
1052 | 56.9k | layer.m_printable = !!readU8(input); |
1053 | | |
1054 | 56.9k | m_collector->collectLayer(m_header.id, m_header.level, layer); |
1055 | 56.9k | } |
1056 | | |
1057 | | void libvisio::VSDParser::readLayerMem(librevenge::RVNGInputStream *input) |
1058 | 5.04k | { |
1059 | 5.04k | input->seek(13, librevenge::RVNG_SEEK_CUR); |
1060 | 5.04k | unsigned textLength = readU8(input); |
1061 | | |
1062 | 5.04k | librevenge::RVNGBinaryData textStream; |
1063 | 5.04k | unsigned long numBytesRead = 0; |
1064 | 5.04k | const unsigned char *tmpBuffer = input->read(textLength*2, numBytesRead); |
1065 | 5.04k | if (numBytesRead) |
1066 | 3.39k | { |
1067 | 3.39k | textStream.append(tmpBuffer, numBytesRead); |
1068 | 3.39k | m_shape.m_layerMem.m_data = textStream; |
1069 | 3.39k | m_shape.m_layerMem.m_format = libvisio::VSD_TEXT_UTF16; |
1070 | 3.39k | } |
1071 | | |
1072 | 5.04k | } |
1073 | | |
1074 | | void libvisio::VSDParser::readPage(librevenge::RVNGInputStream *input) |
1075 | 14.7k | { |
1076 | 14.7k | input->seek(8, librevenge::RVNG_SEEK_CUR); //sub header length and children list length |
1077 | 14.7k | unsigned backgroundPageID = readU32(input); |
1078 | 14.7k | m_collector->collectPage(m_header.id, m_header.level, backgroundPageID, m_isBackgroundPage, m_currentPageName); |
1079 | 14.7k | } |
1080 | | |
1081 | | void libvisio::VSDParser::readGeometry(librevenge::RVNGInputStream *input) |
1082 | 45.8k | { |
1083 | 45.8k | unsigned char geomFlags = readU8(input); |
1084 | 45.8k | bool noFill = (!!(geomFlags & 1)); |
1085 | 45.8k | bool noLine = (!!(geomFlags & 2)); |
1086 | 45.8k | bool noShow = (!!(geomFlags & 4)); |
1087 | | |
1088 | 45.8k | if (m_currentGeometryList) |
1089 | 35.1k | m_currentGeometryList->addGeometry(m_header.id, m_header.level, noFill, noLine, noShow); |
1090 | 45.8k | } |
1091 | | |
1092 | | void libvisio::VSDParser::readMoveTo(librevenge::RVNGInputStream *input) |
1093 | 202k | { |
1094 | 202k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1095 | 202k | double x = readDouble(input); |
1096 | 202k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1097 | 202k | double y = readDouble(input); |
1098 | | |
1099 | 202k | if (m_currentGeometryList) |
1100 | 129k | m_currentGeometryList->addMoveTo(m_header.id, m_header.level, x, y); |
1101 | 202k | } |
1102 | | |
1103 | | void libvisio::VSDParser::readLineTo(librevenge::RVNGInputStream *input) |
1104 | 183k | { |
1105 | 183k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1106 | 183k | double x = readDouble(input); |
1107 | 183k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1108 | 183k | double y = readDouble(input); |
1109 | | |
1110 | 183k | if (m_currentGeometryList) |
1111 | 116k | m_currentGeometryList->addLineTo(m_header.id, m_header.level, x, y); |
1112 | 183k | } |
1113 | | |
1114 | | void libvisio::VSDParser::readArcTo(librevenge::RVNGInputStream *input) |
1115 | 83.7k | { |
1116 | 83.7k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1117 | 83.7k | double x2 = readDouble(input); |
1118 | 83.7k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1119 | 83.7k | double y2 = readDouble(input); |
1120 | 83.7k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1121 | 83.7k | double bow = readDouble(input); |
1122 | | |
1123 | 83.7k | if (m_currentGeometryList) |
1124 | 63.4k | m_currentGeometryList->addArcTo(m_header.id, m_header.level, x2, y2, bow); |
1125 | 83.7k | } |
1126 | | |
1127 | | void libvisio::VSDParser::readXFormData(librevenge::RVNGInputStream *input) |
1128 | 20.1k | { |
1129 | 20.1k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1130 | 20.1k | m_shape.m_xform.pinX = readDouble(input); |
1131 | 20.1k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1132 | 20.1k | m_shape.m_xform.pinY = readDouble(input); |
1133 | 20.1k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1134 | 20.1k | m_shape.m_xform.width = readDouble(input); |
1135 | 20.1k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1136 | 20.1k | m_shape.m_xform.height = readDouble(input); |
1137 | 20.1k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1138 | 20.1k | m_shape.m_xform.pinLocX = readDouble(input); |
1139 | 20.1k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1140 | 20.1k | m_shape.m_xform.pinLocY = readDouble(input); |
1141 | 20.1k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1142 | 20.1k | m_shape.m_xform.angle = readDouble(input); |
1143 | 20.1k | m_shape.m_xform.flipX = !!readU8(input); |
1144 | 20.1k | m_shape.m_xform.flipY = !!readU8(input); |
1145 | 20.1k | } |
1146 | | |
1147 | | void libvisio::VSDParser::readXForm1D(librevenge::RVNGInputStream *input) |
1148 | 5.41k | { |
1149 | 5.41k | if (!m_shape.m_xform1d) |
1150 | 4.43k | m_shape.m_xform1d = std::make_unique<XForm1D>(); |
1151 | 5.41k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1152 | 5.41k | m_shape.m_xform1d->beginX = readDouble(input); |
1153 | 5.41k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1154 | 5.41k | m_shape.m_xform1d->beginY = readDouble(input); |
1155 | 5.41k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1156 | 5.41k | m_shape.m_xform1d->endX = readDouble(input); |
1157 | 5.41k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1158 | 5.41k | m_shape.m_xform1d->endY = readDouble(input); |
1159 | 5.41k | } |
1160 | | |
1161 | | void libvisio::VSDParser::readTxtXForm(librevenge::RVNGInputStream *input) |
1162 | 29.3k | { |
1163 | 29.3k | m_shape.m_txtxform = std::make_unique<XForm>(); |
1164 | 29.3k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1165 | 29.3k | m_shape.m_txtxform->pinX = readDouble(input); |
1166 | 29.3k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1167 | 29.3k | m_shape.m_txtxform->pinY = readDouble(input); |
1168 | 29.3k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1169 | 29.3k | m_shape.m_txtxform->width = readDouble(input); |
1170 | 29.3k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1171 | 29.3k | m_shape.m_txtxform->height = readDouble(input); |
1172 | 29.3k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1173 | 29.3k | m_shape.m_txtxform->pinLocX = readDouble(input); |
1174 | 29.3k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1175 | 29.3k | m_shape.m_txtxform->pinLocY = readDouble(input); |
1176 | 29.3k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1177 | 29.3k | m_shape.m_txtxform->angle = readDouble(input); |
1178 | 29.3k | } |
1179 | | |
1180 | | void libvisio::VSDParser::readShapeId(librevenge::RVNGInputStream *input) |
1181 | 282k | { |
1182 | 282k | if (!m_isShapeStarted) |
1183 | 191k | m_shapeList.addShapeId(m_header.id, getUInt(input)); |
1184 | 90.7k | else |
1185 | 90.7k | m_shape.m_shapeList.addShapeId(m_header.id, getUInt(input)); |
1186 | 282k | } |
1187 | | |
1188 | | void libvisio::VSDParser::readShapeList(librevenge::RVNGInputStream *input) |
1189 | 21.7k | { |
1190 | | // We want the collectors to still get the level information |
1191 | 21.7k | m_collector->collectUnhandledChunk(m_header.id, m_header.level); |
1192 | | |
1193 | 21.7k | if (m_header.trailer) |
1194 | 20.6k | { |
1195 | 20.6k | uint32_t subHeaderLength = readU32(input); |
1196 | 20.6k | uint32_t childrenListLength = readU32(input); |
1197 | 20.6k | input->seek(subHeaderLength, librevenge::RVNG_SEEK_CUR); |
1198 | 20.6k | if (childrenListLength > getRemainingLength(input)) |
1199 | 7.17k | childrenListLength = getRemainingLength(input); |
1200 | 20.6k | std::vector<unsigned> shapeOrder; |
1201 | 20.6k | shapeOrder.reserve(childrenListLength / sizeof(uint32_t)); |
1202 | 4.23M | for (size_t i = 0; i < (childrenListLength / sizeof(uint32_t)); i++) |
1203 | 4.21M | shapeOrder.push_back(readU32(input)); |
1204 | | |
1205 | 20.6k | if (!m_isShapeStarted) |
1206 | 15.1k | m_shapeList.setElementsOrder(shapeOrder); |
1207 | 5.55k | else |
1208 | 5.55k | m_shape.m_shapeList.setElementsOrder(shapeOrder); |
1209 | 20.6k | } |
1210 | 21.7k | } |
1211 | | |
1212 | | void libvisio::VSDParser::readForeignDataType(librevenge::RVNGInputStream *input) |
1213 | 102k | { |
1214 | 102k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1215 | 102k | double imgOffsetX = readDouble(input); |
1216 | 102k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1217 | 102k | double imgOffsetY = readDouble(input); |
1218 | 102k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1219 | 102k | double imgWidth = readDouble(input); |
1220 | 102k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1221 | 102k | double imgHeight = readDouble(input); |
1222 | 102k | unsigned foreignType = readU16(input); |
1223 | 102k | unsigned foreignMapMode = readU16(input); |
1224 | 102k | if (foreignMapMode == 0x8) |
1225 | 902 | foreignType = 0x4; |
1226 | 102k | input->seek(0x9, librevenge::RVNG_SEEK_CUR); |
1227 | 102k | unsigned foreignFormat = readU32(input); |
1228 | | |
1229 | 102k | if (!m_shape.m_foreign) |
1230 | 49.0k | m_shape.m_foreign = std::make_unique<ForeignData>(); |
1231 | 102k | m_shape.m_foreign->typeId = m_header.id; |
1232 | 102k | m_shape.m_foreign->type = foreignType; |
1233 | 102k | m_shape.m_foreign->format = foreignFormat; |
1234 | 102k | m_shape.m_foreign->offsetX = imgOffsetX; |
1235 | 102k | m_shape.m_foreign->offsetY = imgOffsetY; |
1236 | 102k | m_shape.m_foreign->width = imgWidth; |
1237 | 102k | m_shape.m_foreign->height = imgHeight; |
1238 | 102k | } |
1239 | | |
1240 | | void libvisio::VSDParser::readPageProps(librevenge::RVNGInputStream *input) |
1241 | 26.0k | { |
1242 | | // Skip bytes representing unit to *display* (value is always inches) |
1243 | 26.0k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1244 | 26.0k | const double pageWidth = std::max<double>(readDouble(input), 0); |
1245 | 26.0k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1246 | 26.0k | const double pageHeight = std::max<double>(readDouble(input), 0); |
1247 | 26.0k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1248 | 26.0k | m_shadowOffsetX = readDouble(input); |
1249 | 26.0k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1250 | 26.0k | m_shadowOffsetY = readDouble(input); |
1251 | 26.0k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1252 | 26.0k | const double pageScale = readDouble(input); |
1253 | | |
1254 | 26.0k | const unsigned char drawingScaleUnit = readU8(input); |
1255 | 26.0k | double drawingScale = readDouble(input); |
1256 | 26.0k | if (VSD_ALMOST_ZERO(drawingScale)) |
1257 | 20.0k | drawingScale = 1; |
1258 | | |
1259 | 26.0k | const double scale = std::abs(pageScale / drawingScale); |
1260 | | |
1261 | 26.0k | if (m_isStencilStarted && m_currentStencil) |
1262 | 1.40k | { |
1263 | 1.40k | m_currentStencil->m_shadowOffsetX = m_shadowOffsetX; |
1264 | 1.40k | m_currentStencil->m_shadowOffsetY = m_shadowOffsetY; |
1265 | 1.40k | } |
1266 | 26.0k | m_collector->collectPageProps(m_header.id, m_header.level, pageWidth, pageHeight, m_shadowOffsetX, m_shadowOffsetY, scale, drawingScaleUnit, 0, 0); |
1267 | 26.0k | } |
1268 | | |
1269 | | void libvisio::VSDParser::readShape(librevenge::RVNGInputStream *input) |
1270 | 74.9k | { |
1271 | 74.9k | m_currentGeomListCount = 0; |
1272 | 74.9k | m_isShapeStarted = true; |
1273 | 74.9k | m_shapeList.clear(); |
1274 | 74.9k | if (m_header.id != MINUS_ONE) |
1275 | 72.8k | m_currentShapeID = m_header.id; |
1276 | 74.9k | m_currentShapeLevel = m_header.level; |
1277 | 74.9k | unsigned parent = 0; |
1278 | 74.9k | auto masterPage = MINUS_ONE; |
1279 | 74.9k | auto masterShape = MINUS_ONE; |
1280 | 74.9k | auto lineStyle = MINUS_ONE; |
1281 | 74.9k | auto fillStyle = MINUS_ONE; |
1282 | 74.9k | auto textStyle = MINUS_ONE; |
1283 | | |
1284 | 74.9k | try |
1285 | 74.9k | { |
1286 | 74.9k | input->seek(10, librevenge::RVNG_SEEK_CUR); |
1287 | 74.9k | parent = readU32(input); |
1288 | 74.9k | input->seek(4, librevenge::RVNG_SEEK_CUR); |
1289 | 74.9k | masterPage = readU32(input); |
1290 | 74.9k | input->seek(4, librevenge::RVNG_SEEK_CUR); |
1291 | 74.9k | masterShape = readU32(input); |
1292 | 74.9k | input->seek(0x4, librevenge::RVNG_SEEK_CUR); |
1293 | 74.9k | fillStyle = readU32(input); |
1294 | 74.9k | input->seek(4, librevenge::RVNG_SEEK_CUR); |
1295 | 74.9k | lineStyle = readU32(input); |
1296 | 74.9k | input->seek(4, librevenge::RVNG_SEEK_CUR); |
1297 | 74.9k | textStyle = readU32(input); |
1298 | 74.9k | } |
1299 | 74.9k | catch (const EndOfStreamException &) |
1300 | 74.9k | { |
1301 | 2.39k | } |
1302 | | |
1303 | 74.9k | m_shape.clear(); |
1304 | 74.9k | m_currentGeometryList = nullptr; |
1305 | 74.9k | const VSDShape *tmpShape = m_stencils.getStencilShape(masterPage, masterShape); |
1306 | 74.9k | if (tmpShape) |
1307 | 2.63k | { |
1308 | 2.63k | if (tmpShape->m_foreign) |
1309 | 238 | m_shape.m_foreign = std::make_unique<ForeignData>(*(tmpShape->m_foreign)); |
1310 | 2.63k | m_shape.m_xform = tmpShape->m_xform; |
1311 | 2.63k | if (tmpShape->m_txtxform) |
1312 | 1.53k | m_shape.m_txtxform = std::make_unique<XForm>(*(tmpShape->m_txtxform)); |
1313 | 2.63k | m_shape.m_tabSets = tmpShape->m_tabSets; |
1314 | 2.63k | m_shape.m_text = tmpShape->m_text; |
1315 | 2.63k | m_shape.m_textFormat = tmpShape->m_textFormat; |
1316 | 2.63k | m_shape.m_misc = tmpShape->m_misc; |
1317 | 2.63k | } |
1318 | | |
1319 | 74.9k | m_shape.m_lineStyleId = lineStyle; |
1320 | 74.9k | m_shape.m_fillStyleId = fillStyle; |
1321 | 74.9k | m_shape.m_textStyleId = textStyle; |
1322 | 74.9k | m_shape.m_parent = parent; |
1323 | 74.9k | m_shape.m_masterPage = masterPage; |
1324 | 74.9k | m_shape.m_masterShape = masterShape; |
1325 | 74.9k | m_shape.m_shapeId = m_currentShapeID; |
1326 | 74.9k | m_currentShapeID = MINUS_ONE; |
1327 | 74.9k | } |
1328 | | |
1329 | | void libvisio::VSDParser::readNURBSTo(librevenge::RVNGInputStream *input) |
1330 | 68.6k | { |
1331 | 68.6k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1332 | 68.6k | double x = readDouble(input); |
1333 | 68.6k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1334 | 68.6k | double y = readDouble(input); |
1335 | 68.6k | double knot = readDouble(input); // Second last knot |
1336 | 68.6k | double weight = readDouble(input); // Last weight |
1337 | 68.6k | double knotPrev = readDouble(input); // First knot |
1338 | 68.6k | double weightPrev = readDouble(input); // First weight |
1339 | | |
1340 | | // Detect whether to use Shape Data block |
1341 | 68.6k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1342 | 68.6k | unsigned char useData = readU8(input); |
1343 | 68.6k | if (useData == 0x8a) |
1344 | 3.81k | { |
1345 | 3.81k | input->seek(3, librevenge::RVNG_SEEK_CUR); |
1346 | 3.81k | unsigned dataId = readU32(input); |
1347 | | |
1348 | 3.81k | if (m_currentGeometryList) |
1349 | 3.16k | m_currentGeometryList->addNURBSTo(m_header.id, m_header.level, x, y, knot, knotPrev, weight, weightPrev, dataId); |
1350 | 3.81k | return; |
1351 | 3.81k | } |
1352 | | |
1353 | 64.8k | std::vector<double> knotVector; |
1354 | 64.8k | knotVector.push_back(knotPrev); |
1355 | 64.8k | std::vector<std::pair<double, double> > controlPoints; |
1356 | 64.8k | std::vector<double> weights; |
1357 | 64.8k | weights.push_back(weightPrev); |
1358 | | |
1359 | 64.8k | input->seek(9, librevenge::RVNG_SEEK_CUR); // Seek to blocks at offset 0x50 (80) |
1360 | 64.8k | unsigned long chunkBytesRead = 0x50; |
1361 | | |
1362 | | // Find formula block referring to cell E (cell 6) |
1363 | 64.8k | unsigned cellRef = 0; |
1364 | 64.8k | unsigned length = 0; |
1365 | 64.8k | unsigned long inputPos = input->tell(); |
1366 | 1.51M | while (cellRef != 6 && !input->isEnd() && |
1367 | 1.44M | m_header.dataLength - chunkBytesRead > 4) |
1368 | 1.44M | { |
1369 | 1.44M | length = readU32(input); |
1370 | 1.44M | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1371 | 1.44M | cellRef = readU8(input); |
1372 | 1.44M | if (cellRef < 6) |
1373 | 44.7k | input->seek(length - 6, librevenge::RVNG_SEEK_CUR); |
1374 | 1.44M | chunkBytesRead += input->tell() - inputPos; |
1375 | 1.44M | inputPos = input->tell(); |
1376 | 1.44M | } |
1377 | | |
1378 | 64.8k | if (input->isEnd()) |
1379 | 39.1k | return; |
1380 | | |
1381 | | // Only read formula if block is found |
1382 | 25.6k | if (cellRef == 6) |
1383 | 17.6k | { |
1384 | 17.6k | unsigned char xType = 1; |
1385 | 17.6k | unsigned char yType = 1; |
1386 | 17.6k | unsigned degree = 3; |
1387 | | // Indicates whether it's a "simple" NURBS block with a static format |
1388 | | // or a complex block where parameters each have a type |
1389 | 17.6k | unsigned char paramType = readU8(input); |
1390 | 17.6k | unsigned char valueType = 0; |
1391 | | |
1392 | 17.6k | double lastKnot = 0; |
1393 | 17.6k | unsigned repetitions = 0; |
1394 | | |
1395 | | // Read formula's static first four parameters |
1396 | 17.6k | if (paramType == 0x8a) |
1397 | 646 | { |
1398 | 646 | lastKnot = readDouble(input); |
1399 | 646 | degree = readU16(input); |
1400 | 646 | xType = readU8(input); |
1401 | 646 | yType = readU8(input); |
1402 | 646 | repetitions = readU32(input); |
1403 | 646 | } |
1404 | 17.0k | else |
1405 | 17.0k | { |
1406 | 17.0k | valueType = paramType; |
1407 | 17.0k | if (valueType == 0x20) |
1408 | 2.44k | lastKnot = readDouble(input); |
1409 | 14.5k | else |
1410 | 14.5k | lastKnot = readU16(input); |
1411 | | |
1412 | 17.0k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1413 | 17.0k | degree = readU16(input); |
1414 | 17.0k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1415 | 17.0k | xType = readU16(input); |
1416 | 17.0k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1417 | 17.0k | yType = readU16(input); |
1418 | 17.0k | } |
1419 | | |
1420 | | // Read sequences of (x, y, knot, weight) until finished |
1421 | 17.6k | unsigned long bytesRead = input->tell() - inputPos; |
1422 | 17.6k | unsigned char flag = 0; |
1423 | 17.6k | if (paramType != 0x8a) flag = readU8(input); |
1424 | 1.92M | while ((paramType == 0x8a ? repetitions > 0 : flag != 0x81) && bytesRead < length) |
1425 | 1.90M | { |
1426 | 1.90M | inputPos = input->tell(); |
1427 | 1.90M | double knot_ = 0; |
1428 | 1.90M | double weight_ = 0; |
1429 | 1.90M | double controlX = 0; |
1430 | 1.90M | double controlY = 0; |
1431 | | |
1432 | 1.90M | if (paramType == 0x8a) // Parameters have static format |
1433 | 22.3k | { |
1434 | 22.3k | controlX = readDouble(input); |
1435 | 22.3k | controlY = readDouble(input); |
1436 | 22.3k | knot_ = readDouble(input); |
1437 | 22.3k | weight_ = readDouble(input); |
1438 | 22.3k | } |
1439 | 1.88M | else // Parameters have types |
1440 | 1.88M | { |
1441 | 1.88M | valueType = flag; |
1442 | 1.88M | if (valueType == 0x20) |
1443 | 18.9k | controlX = readDouble(input); |
1444 | 1.86M | else |
1445 | 1.86M | controlX = readU16(input); |
1446 | | |
1447 | 1.88M | valueType = readU8(input); |
1448 | 1.88M | if (valueType == 0x20) |
1449 | 21.5k | controlY = readDouble(input); |
1450 | 1.86M | else |
1451 | 1.86M | controlY = readU16(input); |
1452 | | |
1453 | 1.88M | valueType = readU8(input); |
1454 | 1.88M | if (valueType == 0x20) |
1455 | 22.3k | knot_ = readDouble(input); |
1456 | 1.86M | else if (valueType == 0x62) |
1457 | 2.59k | knot_ = readU16(input); |
1458 | | |
1459 | 1.88M | valueType = readU8(input); |
1460 | 1.88M | if (valueType == 0x20) |
1461 | 18.8k | weight_ = readDouble(input); |
1462 | 1.86M | else if (valueType == 0x62) |
1463 | 2.05k | weight_ = readU16(input); |
1464 | 1.88M | } |
1465 | 1.90M | controlPoints.push_back(std::pair<double, double>(controlX, controlY)); |
1466 | 1.90M | knotVector.push_back(knot_); |
1467 | 1.90M | weights.push_back(weight_); |
1468 | | |
1469 | 1.90M | if (paramType != 0x8a) flag = readU8(input); |
1470 | 23.5k | else repetitions--; |
1471 | 1.90M | bytesRead += input->tell() - inputPos; |
1472 | 1.90M | } |
1473 | 17.6k | knotVector.push_back(knot); |
1474 | 17.6k | knotVector.push_back(lastKnot); |
1475 | 17.6k | weights.push_back(weight); |
1476 | | |
1477 | 17.6k | if (m_currentGeometryList) |
1478 | 11.8k | m_currentGeometryList->addNURBSTo(m_header.id, m_header.level, x, y, xType, |
1479 | 11.8k | yType, degree, controlPoints, knotVector, weights); |
1480 | 17.6k | } |
1481 | 8.00k | else // No formula found, use line |
1482 | 8.00k | { |
1483 | 8.00k | if (m_currentGeometryList) |
1484 | 854 | m_currentGeometryList->addLineTo(m_header.id, m_header.level, x, y); |
1485 | 8.00k | } |
1486 | 25.6k | } |
1487 | | |
1488 | | void libvisio::VSDParser::readPolylineTo(librevenge::RVNGInputStream *input) |
1489 | 59.7k | { |
1490 | 59.7k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1491 | 59.7k | double x = readDouble(input); |
1492 | 59.7k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1493 | 59.7k | double y = readDouble(input); |
1494 | | |
1495 | | // Detect whether to use Shape Data block |
1496 | 59.7k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1497 | 59.7k | unsigned useData = readU8(input); |
1498 | 59.7k | if (useData == 0x8b) |
1499 | 3.46k | { |
1500 | 3.46k | input->seek(3, librevenge::RVNG_SEEK_CUR); |
1501 | 3.46k | unsigned dataId = readU32(input); |
1502 | | |
1503 | 3.46k | if (m_currentGeometryList) |
1504 | 2.72k | m_currentGeometryList->addPolylineTo(m_header.id, m_header.level, x, y, dataId); |
1505 | 3.46k | return; |
1506 | 3.46k | } |
1507 | | |
1508 | | // Blocks start at 0x30 |
1509 | 56.2k | input->seek(0x9, librevenge::RVNG_SEEK_CUR); |
1510 | 56.2k | unsigned long chunkBytesRead = 0x30; |
1511 | | |
1512 | | // Find formula block referring to cell A (cell 2) |
1513 | 56.2k | unsigned cellRef = 0; |
1514 | 56.2k | unsigned length = 0; |
1515 | 56.2k | unsigned long inputPos = input->tell(); |
1516 | 738k | while (cellRef != 2 && !input->isEnd() && |
1517 | 704k | m_header.dataLength - chunkBytesRead > 4) |
1518 | 704k | { |
1519 | 704k | length = readU32(input); |
1520 | 704k | if (!length) |
1521 | 21.7k | break; |
1522 | 682k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1523 | 682k | cellRef = readU8(input); |
1524 | 682k | if (cellRef < 2) |
1525 | 11.3k | input->seek(length - 6, librevenge::RVNG_SEEK_CUR); |
1526 | 682k | chunkBytesRead += input->tell() - inputPos; |
1527 | 682k | inputPos = input->tell(); |
1528 | 682k | } |
1529 | | |
1530 | 56.2k | if (input->isEnd()) |
1531 | 6.42k | return; |
1532 | | |
1533 | | // Default to local co-ordinates if unspecified |
1534 | 49.8k | std::vector<std::pair<double, double> > points; |
1535 | | |
1536 | | // Only formula if block is found |
1537 | 49.8k | if (cellRef == 2) |
1538 | 4.93k | { |
1539 | 4.93k | unsigned long blockBytesRead = 0; |
1540 | 4.93k | inputPos = input->tell(); |
1541 | 4.93k | blockBytesRead += 6; |
1542 | | |
1543 | | // Parse static first two parameters to function |
1544 | 4.93k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1545 | 4.93k | unsigned char xType = readU16(input); |
1546 | 4.93k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1547 | 4.93k | unsigned char yType = readU16(input); |
1548 | | |
1549 | | // Parse pairs of x,y co-ordinates |
1550 | 4.93k | unsigned flag = readU8(input); |
1551 | 4.93k | unsigned valueType = 0; // Holds parameter type indicator |
1552 | 4.93k | blockBytesRead += input->tell() - inputPos; |
1553 | 933k | while (flag != 0x81 && blockBytesRead < length) |
1554 | 928k | { |
1555 | 928k | inputPos = input->tell(); |
1556 | 928k | double x2 = 0; |
1557 | 928k | double y2 = 0; |
1558 | | |
1559 | 928k | valueType = flag; |
1560 | 928k | if (valueType == 0x20) |
1561 | 9.37k | x2 = readDouble(input); |
1562 | 919k | else |
1563 | 919k | x2 = readU16(input); |
1564 | | |
1565 | 928k | valueType = readU8(input); |
1566 | 928k | if (valueType == 0x20) |
1567 | 10.3k | y2 = readDouble(input); |
1568 | 918k | else |
1569 | 918k | y2 = readU16(input); |
1570 | | |
1571 | 928k | points.push_back(std::pair<double, double>(x2, y2)); |
1572 | 928k | flag = readU8(input); |
1573 | 928k | blockBytesRead += input->tell() - inputPos; |
1574 | 928k | } |
1575 | | |
1576 | 4.93k | if (m_currentGeometryList) |
1577 | 2.33k | m_currentGeometryList->addPolylineTo(m_header.id, m_header.level, x, y, xType, |
1578 | 2.33k | yType, points); |
1579 | 4.93k | } |
1580 | 44.8k | else |
1581 | 44.8k | { |
1582 | 44.8k | if (m_currentGeometryList) |
1583 | 16.7k | m_currentGeometryList->addLineTo(m_header.id, m_header.level, x, y); |
1584 | 44.8k | } |
1585 | 49.8k | } |
1586 | | |
1587 | | void libvisio::VSDParser::readInfiniteLine(librevenge::RVNGInputStream *input) |
1588 | 100k | { |
1589 | 100k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1590 | 100k | double x1 = readDouble(input); |
1591 | 100k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1592 | 100k | double y1 = readDouble(input); |
1593 | 100k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1594 | 100k | double x2 = readDouble(input); |
1595 | 100k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1596 | 100k | double y2 = readDouble(input); |
1597 | 100k | if (m_currentGeometryList) |
1598 | 61.6k | m_currentGeometryList->addInfiniteLine(m_header.id, m_header.level, x1, y1, x2, y2); |
1599 | 100k | } |
1600 | | |
1601 | | void libvisio::VSDParser::readShapeData(librevenge::RVNGInputStream *input) |
1602 | 242k | { |
1603 | 242k | unsigned char dataType = readU8(input); |
1604 | | |
1605 | 242k | input->seek(15, librevenge::RVNG_SEEK_CUR); |
1606 | | // Polyline data |
1607 | 242k | if (dataType == 0x80) |
1608 | 9.14k | { |
1609 | 9.14k | std::vector<std::pair<double, double> > points; |
1610 | 9.14k | unsigned char xType = readU8(input); |
1611 | 9.14k | unsigned char yType = readU8(input); |
1612 | 9.14k | unsigned pointCount = readU32(input); |
1613 | 9.14k | if (pointCount > getRemainingLength(input) / 16) |
1614 | 5.94k | pointCount = getRemainingLength(input) / 16; |
1615 | | |
1616 | 11.7M | for (unsigned i = 0; i < pointCount; i++) |
1617 | 11.7M | { |
1618 | 11.7M | double x = readDouble(input); |
1619 | 11.7M | double y = readDouble(input); |
1620 | 11.7M | points.push_back(std::pair<double, double>(x, y)); |
1621 | 11.7M | } |
1622 | | |
1623 | 9.14k | PolylineData data; |
1624 | 9.14k | data.xType = xType; |
1625 | 9.14k | data.yType = yType; |
1626 | 9.14k | data.points = points; |
1627 | 9.14k | m_shape.m_polylineData[m_header.id] = data; |
1628 | 9.14k | } |
1629 | | |
1630 | | // NURBS data |
1631 | 233k | else if (dataType == 0x82) |
1632 | 34.6k | { |
1633 | 34.6k | double lastKnot = readDouble(input); |
1634 | | |
1635 | 34.6k | unsigned degree = readU16(input); |
1636 | 34.6k | unsigned char xType = readU8(input); |
1637 | 34.6k | unsigned char yType = readU8(input); |
1638 | 34.6k | unsigned pointCount = readU32(input); |
1639 | 34.6k | if (pointCount > getRemainingLength(input) / 32) |
1640 | 7.44k | pointCount = getRemainingLength(input) / 32; |
1641 | | |
1642 | 34.6k | std::vector<double> knotVector; |
1643 | 34.6k | std::vector<std::pair<double, double> > controlPoints; |
1644 | 34.6k | std::vector<double> weights; |
1645 | | |
1646 | 14.0M | for (unsigned i = 0; i < pointCount; i++) |
1647 | 14.0M | { |
1648 | 14.0M | double controlX = readDouble(input); |
1649 | 14.0M | double controlY = readDouble(input); |
1650 | 14.0M | double knot = readDouble(input); |
1651 | 14.0M | double weight = readDouble(input); |
1652 | | |
1653 | 14.0M | knotVector.push_back(knot); |
1654 | 14.0M | weights.push_back(weight); |
1655 | 14.0M | controlPoints.push_back(std::pair<double, double>(controlX, controlY)); |
1656 | 14.0M | } |
1657 | | |
1658 | 34.6k | NURBSData data; |
1659 | 34.6k | data.lastKnot = lastKnot; |
1660 | 34.6k | data.degree = degree; |
1661 | 34.6k | data.xType = xType; |
1662 | 34.6k | data.yType = yType; |
1663 | 34.6k | data.knots = knotVector; |
1664 | 34.6k | data.weights = weights; |
1665 | 34.6k | data.points = controlPoints; |
1666 | 34.6k | m_shape.m_nurbsData[m_header.id] = data; |
1667 | 34.6k | } |
1668 | 242k | } |
1669 | | |
1670 | | void libvisio::VSDParser::readSplineStart(librevenge::RVNGInputStream *input) |
1671 | 41.6k | { |
1672 | 41.6k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1673 | 41.6k | double x = readDouble(input); |
1674 | 41.6k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1675 | 41.6k | double y = readDouble(input); |
1676 | 41.6k | double secondKnot = readDouble(input); |
1677 | 41.6k | double firstKnot = readDouble(input); |
1678 | 41.6k | double lastKnot = readDouble(input); |
1679 | 41.6k | unsigned degree = readU8(input); |
1680 | | |
1681 | 41.6k | if (m_currentGeometryList) |
1682 | 30.7k | m_currentGeometryList->addSplineStart(m_header.id, m_header.level, x, y, secondKnot, firstKnot, lastKnot, degree); |
1683 | 41.6k | } |
1684 | | |
1685 | | void libvisio::VSDParser::readSplineKnot(librevenge::RVNGInputStream *input) |
1686 | 56.4k | { |
1687 | 56.4k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1688 | 56.4k | double x = readDouble(input); |
1689 | 56.4k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1690 | 56.4k | double y = readDouble(input); |
1691 | 56.4k | double knot = readDouble(input); |
1692 | | |
1693 | 56.4k | if (m_currentGeometryList) |
1694 | 37.2k | m_currentGeometryList->addSplineKnot(m_header.id, m_header.level, x, y, knot); |
1695 | 56.4k | } |
1696 | | |
1697 | | void libvisio::VSDParser::readNameList(librevenge::RVNGInputStream * /* input */) |
1698 | 29.4k | { |
1699 | 29.4k | m_shape.m_names.clear(); |
1700 | 29.4k | } |
1701 | | |
1702 | | void libvisio::VSDParser::readNameList2(librevenge::RVNGInputStream * /* input */) |
1703 | 4.06k | { |
1704 | 4.06k | m_names.clear(); |
1705 | 4.06k | } |
1706 | | |
1707 | | void libvisio::VSDParser::readFieldList(librevenge::RVNGInputStream *input) |
1708 | 12.9k | { |
1709 | 12.9k | if (m_header.trailer) |
1710 | 12.2k | { |
1711 | 12.2k | uint32_t subHeaderLength = readU32(input); |
1712 | 12.2k | uint32_t childrenListLength = readU32(input); |
1713 | 12.2k | input->seek(subHeaderLength, librevenge::RVNG_SEEK_CUR); |
1714 | 12.2k | if (childrenListLength > getRemainingLength(input)) |
1715 | 4.69k | childrenListLength = getRemainingLength(input); |
1716 | 12.2k | std::vector<unsigned> fieldOrder; |
1717 | 12.2k | fieldOrder.reserve(childrenListLength / sizeof(uint32_t)); |
1718 | 1.71M | for (size_t i = 0; i < (childrenListLength / sizeof(uint32_t)); i++) |
1719 | 1.70M | fieldOrder.push_back(readU32(input)); |
1720 | | |
1721 | 12.2k | m_shape.m_fields.setElementsOrder(fieldOrder); |
1722 | 12.2k | m_shape.m_fields.addFieldList(m_header.id, m_header.level); |
1723 | 12.2k | } |
1724 | 12.9k | } |
1725 | | |
1726 | | void libvisio::VSDParser::readColours(librevenge::RVNGInputStream *input) |
1727 | 9.12k | { |
1728 | 9.12k | input->seek(2, librevenge::RVNG_SEEK_CUR); |
1729 | 9.12k | unsigned numColours = readU8(input); |
1730 | 9.12k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1731 | 9.12k | m_colours.clear(); |
1732 | | |
1733 | 177k | for (unsigned i = 0; i < numColours; i++) |
1734 | 168k | { |
1735 | 168k | Colour tmpColour; |
1736 | 168k | tmpColour.r = readU8(input); |
1737 | 168k | tmpColour.g = readU8(input); |
1738 | 168k | tmpColour.b = readU8(input); |
1739 | 168k | tmpColour.a = readU8(input); |
1740 | | |
1741 | 168k | m_colours.push_back(tmpColour); |
1742 | 168k | } |
1743 | 9.12k | } |
1744 | | |
1745 | | void libvisio::VSDParser::readFont(librevenge::RVNGInputStream *input) |
1746 | 51.1k | { |
1747 | 51.1k | input->seek(4, librevenge::RVNG_SEEK_CUR); |
1748 | 51.1k | librevenge::RVNGBinaryData textStream; |
1749 | | |
1750 | 270k | for (unsigned i = 0; i < 32; i++) |
1751 | 250k | { |
1752 | 250k | unsigned char curchar = readU8(input); |
1753 | 250k | unsigned char nextchar = readU8(input); |
1754 | 250k | if (curchar == 0 && nextchar == 0) |
1755 | 30.9k | break; |
1756 | 219k | textStream.append(curchar); |
1757 | 219k | textStream.append(nextchar); |
1758 | 219k | } |
1759 | 51.1k | m_fonts[m_header.id] = VSDName(textStream, libvisio::VSD_TEXT_UTF16); |
1760 | 51.1k | } |
1761 | | |
1762 | | void libvisio::VSDParser::readFontIX(librevenge::RVNGInputStream *input) |
1763 | 63.7k | { |
1764 | 63.7k | long tmpAdjust = input->tell(); |
1765 | 63.7k | input->seek(2, librevenge::RVNG_SEEK_CUR); |
1766 | 63.7k | auto codePage = (unsigned char)(getUInt(input) & 0xff); |
1767 | 63.7k | tmpAdjust -= input->tell(); |
1768 | | |
1769 | 63.7k | std::string fontName; |
1770 | | |
1771 | 8.30M | for (long i = 0; i < (long)(m_header.dataLength + tmpAdjust); i++) |
1772 | 8.25M | { |
1773 | 8.25M | auto curchar = (char)readU8(input); |
1774 | 8.25M | if (curchar == 0) |
1775 | 22.9k | break; |
1776 | 8.23M | fontName.append(1, curchar); |
1777 | 8.23M | } |
1778 | | |
1779 | 63.7k | if (!codePage) |
1780 | 23.1k | { |
1781 | | // Try to parse the font name for codePage |
1782 | 23.1k | size_t length = fontName.length(); |
1783 | 23.1k | size_t found = std::string::npos; |
1784 | | |
1785 | 23.1k | if (length > 3 && (found=fontName.find(" CE", length - 3)) != std::string::npos) |
1786 | 163 | codePage = 0xee; |
1787 | 22.9k | else if (length > 9 && (found=fontName.rfind(" Cyrillic", length - 9)) != std::string::npos) |
1788 | 181 | codePage = 0xcc; |
1789 | 22.8k | else if (length > 4 && (found=fontName.rfind(" Cyr", length - 4)) != std::string::npos) |
1790 | 405 | codePage = 0xcc; |
1791 | 22.3k | else if (length > 4 && (found=fontName.rfind(" CYR", length - 4)) != std::string::npos) |
1792 | 6 | codePage = 0xcc; |
1793 | 22.3k | else if (length > 7 && (found=fontName.rfind(" Baltic", length - 7)) != std::string::npos) |
1794 | 210 | codePage = 0xba; |
1795 | 22.1k | else if (length > 6 && (found=fontName.rfind(" Greek", length - 6)) != std::string::npos) |
1796 | 346 | codePage = 0xa1; |
1797 | 21.8k | else if (length > 4 && (found=fontName.rfind(" Tur", length - 4)) != std::string::npos) |
1798 | 187 | codePage = 0xa2; |
1799 | 21.6k | else if (length > 4 && (found=fontName.rfind(" TUR", length - 4)) != std::string::npos) |
1800 | 56 | codePage = 0xa2; |
1801 | 21.5k | else if (length > 7 && (found=fontName.rfind(" Hebrew", length - 7)) != std::string::npos) |
1802 | 0 | codePage = 0xb1; |
1803 | 21.5k | else if (length > 7 && (found=fontName.rfind(" Arabic", length - 7)) != std::string::npos) |
1804 | 0 | codePage = 0xb2; |
1805 | 21.5k | else if (length > 5 && (found=fontName.rfind(" Thai", length - 5)) != std::string::npos) |
1806 | 0 | codePage = 0xde; |
1807 | 21.5k | else if (length >= 4 && (found=fontName.find("GOST", 0, 4)) != std::string::npos) |
1808 | 263 | { |
1809 | 263 | codePage = 0xcc; |
1810 | 263 | found = std::string::npos; |
1811 | 263 | } |
1812 | | |
1813 | 23.1k | if (found != std::string::npos) |
1814 | 1.55k | { |
1815 | 1.55k | fontName.erase(found, std::string::npos); |
1816 | 1.55k | } |
1817 | 23.1k | } |
1818 | | |
1819 | 63.7k | TextFormat format = libvisio::VSD_TEXT_ANSI; |
1820 | 63.7k | switch (codePage) |
1821 | 63.7k | { |
1822 | 21.3k | case 0: // ANSI |
1823 | 21.3k | format = libvisio::VSD_TEXT_ANSI; |
1824 | 21.3k | break; |
1825 | 1.51k | case 0x02: |
1826 | 1.51k | format = libvisio::VSD_TEXT_SYMBOL; |
1827 | 1.51k | break; |
1828 | 1.00k | case 0xa1: // GREEK |
1829 | 1.00k | format = libvisio::VSD_TEXT_GREEK; |
1830 | 1.00k | break; |
1831 | 1.07k | case 0xa2: // TURKISH |
1832 | 1.07k | format = libvisio::VSD_TEXT_TURKISH; |
1833 | 1.07k | break; |
1834 | 794 | case 0xa3: // VIETNAMESE |
1835 | 794 | format = libvisio::VSD_TEXT_VIETNAMESE; |
1836 | 794 | break; |
1837 | 883 | case 0xb1: // HEBREW |
1838 | 883 | format = libvisio::VSD_TEXT_HEBREW; |
1839 | 883 | break; |
1840 | 810 | case 0xb2: // ARABIC |
1841 | 810 | format = libvisio::VSD_TEXT_ARABIC; |
1842 | 810 | break; |
1843 | 923 | case 0xba: // BALTIC |
1844 | 923 | format = libvisio::VSD_TEXT_BALTIC; |
1845 | 923 | break; |
1846 | 1.58k | case 0xcc: // RUSSIAN |
1847 | 1.58k | format = libvisio::VSD_TEXT_RUSSIAN; |
1848 | 1.58k | break; |
1849 | 831 | case 0xde: // THAI |
1850 | 831 | format = libvisio::VSD_TEXT_THAI; |
1851 | 831 | break; |
1852 | 815 | case 0xee: // CENTRAL EUROPE |
1853 | 815 | format = libvisio::VSD_TEXT_CENTRAL_EUROPE; |
1854 | 815 | break; |
1855 | 3.00k | case 0x80: // SHIFTJIS |
1856 | 3.00k | format = libvisio::VSD_TEXT_JAPANESE; |
1857 | 3.00k | break; |
1858 | 1.02k | case 0x81: // HANGUL |
1859 | 1.02k | format = libvisio::VSD_TEXT_KOREAN; |
1860 | 1.02k | break; |
1861 | 874 | case 0x86: // GB2312 |
1862 | 874 | format = libvisio::VSD_TEXT_CHINESE_SIMPLIFIED; |
1863 | 874 | break; |
1864 | 2.24k | case 0x88: // CHINESEBIG5 |
1865 | 2.24k | format = libvisio::VSD_TEXT_CHINESE_TRADITIONAL; |
1866 | 2.24k | break; |
1867 | 6.58k | default: |
1868 | 6.58k | break; |
1869 | 63.7k | } |
1870 | | |
1871 | 45.2k | librevenge::RVNGBinaryData textStream((const unsigned char *)fontName.c_str(), fontName.length()); |
1872 | 45.2k | m_fonts[m_header.id] = VSDName(textStream, format); |
1873 | 45.2k | } |
1874 | | |
1875 | | /* StyleSheet readers */ |
1876 | | |
1877 | | void libvisio::VSDParser::readStyleSheet(librevenge::RVNGInputStream *input) |
1878 | 7.84k | { |
1879 | 7.84k | input->seek(0x22, librevenge::RVNG_SEEK_CUR); |
1880 | 7.84k | unsigned lineStyle = readU32(input); |
1881 | 7.84k | input->seek(4, librevenge::RVNG_SEEK_CUR); |
1882 | 7.84k | unsigned fillStyle = readU32(input); |
1883 | 7.84k | input->seek(4, librevenge::RVNG_SEEK_CUR); |
1884 | 7.84k | unsigned textStyle = readU32(input); |
1885 | | |
1886 | 7.84k | m_collector->collectStyleSheet(m_header.id, m_header.level, lineStyle, fillStyle, textStyle); |
1887 | 7.84k | } |
1888 | | |
1889 | | void libvisio::VSDParser::readPageSheet(librevenge::RVNGInputStream * /* input */) |
1890 | 20.6k | { |
1891 | 20.6k | m_currentShapeLevel = m_header.level; |
1892 | 20.6k | m_collector->collectPageSheet(m_header.id, m_header.level); |
1893 | 20.6k | } |
1894 | | |
1895 | | void libvisio::VSDParser::readText(librevenge::RVNGInputStream *input) |
1896 | 23.9k | { |
1897 | 23.9k | input->seek(8, librevenge::RVNG_SEEK_CUR); |
1898 | 23.9k | librevenge::RVNGBinaryData textStream; |
1899 | | |
1900 | | // Read up to end of chunk in byte pairs (except from last 2 bytes) |
1901 | 23.9k | unsigned long numBytesRead = 0; |
1902 | 23.9k | const unsigned char *tmpBuffer = input->read(m_header.dataLength - 8, numBytesRead); |
1903 | 23.9k | if (numBytesRead) |
1904 | 22.9k | { |
1905 | 22.9k | if (m_isStencilStarted) |
1906 | 407 | { |
1907 | 407 | VSD_DEBUG_MSG(("Found stencil text\n")); |
1908 | 407 | } |
1909 | 22.9k | textStream.append(tmpBuffer, numBytesRead); |
1910 | 22.9k | m_shape.m_text = textStream; |
1911 | 22.9k | } |
1912 | 988 | else |
1913 | 988 | m_shape.m_text.clear(); |
1914 | 23.9k | m_shape.m_textFormat = libvisio::VSD_TEXT_UTF16; |
1915 | 23.9k | } |
1916 | | |
1917 | | void libvisio::VSDParser::readCharIX(librevenge::RVNGInputStream *input) |
1918 | 31.5k | { |
1919 | 31.5k | VSDFont fontFace; |
1920 | 31.5k | unsigned charCount = readU32(input); |
1921 | 31.5k | unsigned fontID = readU16(input); |
1922 | 31.5k | VSDName font; |
1923 | 31.5k | std::map<unsigned, VSDName>::const_iterator iter = m_fonts.find(fontID); |
1924 | 31.5k | if (iter != m_fonts.end()) |
1925 | 8.07k | font = iter->second; |
1926 | 31.5k | input->seek(1, librevenge::RVNG_SEEK_CUR); // Color ID |
1927 | 31.5k | Colour fontColour; // Font Colour |
1928 | 31.5k | fontColour.r = readU8(input); |
1929 | 31.5k | fontColour.g = readU8(input); |
1930 | 31.5k | fontColour.b = readU8(input); |
1931 | 31.5k | fontColour.a = readU8(input); |
1932 | | |
1933 | 31.5k | bool bold(false); |
1934 | 31.5k | bool italic(false); |
1935 | 31.5k | bool underline(false); |
1936 | 31.5k | bool doubleunderline(false); |
1937 | 31.5k | bool strikeout(false); |
1938 | 31.5k | bool doublestrikeout(false); |
1939 | 31.5k | bool allcaps(false); |
1940 | 31.5k | bool initcaps(false); |
1941 | 31.5k | bool smallcaps(false); |
1942 | 31.5k | bool superscript(false); |
1943 | 31.5k | bool subscript(false); |
1944 | 31.5k | unsigned char fontMod = readU8(input); |
1945 | 31.5k | if (fontMod & 1) bold = true; |
1946 | 31.5k | if (fontMod & 2) italic = true; |
1947 | 31.5k | if (fontMod & 4) underline = true; |
1948 | 31.5k | if (fontMod & 8) smallcaps = true; |
1949 | 31.5k | fontMod = readU8(input); |
1950 | 31.5k | if (fontMod & 1) allcaps = true; |
1951 | 31.5k | if (fontMod & 2) initcaps = true; |
1952 | 31.5k | fontMod = readU8(input); |
1953 | 31.5k | if (fontMod & 1) superscript = true; |
1954 | 31.5k | if (fontMod & 2) subscript = true; |
1955 | | |
1956 | 31.5k | double scaleWidth = (double)(readU16(input)) / 10000.0; |
1957 | 31.5k | input->seek(2, librevenge::RVNG_SEEK_CUR); |
1958 | 31.5k | double fontSize = readDouble(input); |
1959 | | |
1960 | 31.5k | fontMod = readU8(input); |
1961 | 31.5k | if (fontMod & 1) doubleunderline = true; |
1962 | 31.5k | if (fontMod & 4) strikeout = true; |
1963 | 31.5k | if (fontMod & 0x20) doublestrikeout = true; |
1964 | | |
1965 | 31.5k | if (m_isInStyles) |
1966 | 2.74k | m_collector->collectCharIXStyle(m_header.id, m_header.level, charCount, font, fontColour, fontSize, |
1967 | 2.74k | bold, italic, underline, doubleunderline, strikeout, doublestrikeout, |
1968 | 2.74k | allcaps, initcaps, smallcaps, superscript, subscript, scaleWidth); |
1969 | 28.7k | else |
1970 | 28.7k | { |
1971 | 28.7k | if (m_isStencilStarted) |
1972 | 759 | { |
1973 | 759 | VSD_DEBUG_MSG(("Found stencil character style\n")); |
1974 | 759 | } |
1975 | | |
1976 | 28.7k | m_shape.m_charStyle.override(VSDOptionalCharStyle(charCount, font, fontColour, fontSize, |
1977 | 28.7k | bold, italic, underline, doubleunderline, strikeout, doublestrikeout, |
1978 | 28.7k | allcaps, initcaps, smallcaps, superscript, subscript, scaleWidth)); |
1979 | 28.7k | m_shape.m_charList.addCharIX(m_header.id, m_header.level, charCount, font, fontColour, fontSize, |
1980 | 28.7k | bold, italic, underline, doubleunderline, strikeout, doublestrikeout, |
1981 | 28.7k | allcaps, initcaps, smallcaps, superscript, subscript, scaleWidth); |
1982 | 28.7k | } |
1983 | 31.5k | } |
1984 | | |
1985 | | void libvisio::VSDParser::readParaIX(librevenge::RVNGInputStream *input) |
1986 | 30.2k | { |
1987 | 30.2k | long startPosition = input->tell(); |
1988 | 30.2k | unsigned charCount = readU32(input); |
1989 | 30.2k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1990 | 30.2k | double indFirst = readDouble(input); |
1991 | 30.2k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1992 | 30.2k | double indLeft = readDouble(input); |
1993 | 30.2k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1994 | 30.2k | double indRight = readDouble(input); |
1995 | 30.2k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1996 | 30.2k | double spLine = readDouble(input); |
1997 | 30.2k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
1998 | 30.2k | double spBefore = readDouble(input); |
1999 | 30.2k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
2000 | 30.2k | double spAfter = readDouble(input); |
2001 | 30.2k | unsigned char align = readU8(input); |
2002 | 30.2k | unsigned char bullet = readU8(input); |
2003 | 30.2k | input->seek(4, librevenge::RVNG_SEEK_CUR); |
2004 | 30.2k | unsigned fontID = readU16(input); |
2005 | 30.2k | VSDName bulletFont; |
2006 | 30.2k | if (fontID) |
2007 | 10.6k | { |
2008 | 10.6k | std::map<unsigned, VSDName>::const_iterator iter = m_fonts.find(fontID); |
2009 | 10.6k | if (iter != m_fonts.end()) |
2010 | 589 | bulletFont = iter->second; |
2011 | 10.6k | } |
2012 | 30.2k | input->seek(2, librevenge::RVNG_SEEK_CUR); |
2013 | 30.2k | double bulletFontSize = readDouble(input); |
2014 | 30.2k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
2015 | 30.2k | double textPosAfterBullet = readDouble(input); |
2016 | 30.2k | unsigned flags = readU32(input); |
2017 | 30.2k | input->seek(34, librevenge::RVNG_SEEK_CUR); |
2018 | 30.2k | long remainingData = m_header.dataLength - input->tell() + startPosition; |
2019 | 30.2k | unsigned blockLength = 0; |
2020 | 30.2k | VSDName bulletStr; |
2021 | | |
2022 | 39.5k | while (remainingData >= 4 && (blockLength = readU32(input))) |
2023 | 9.32k | { |
2024 | 9.32k | long blockEnd = blockLength-4 + input->tell(); |
2025 | 9.32k | unsigned char blockType = readU8(input); |
2026 | 9.32k | unsigned char blockIdx = readU8(input); |
2027 | 9.32k | if (blockType == 2 && blockIdx == 8) |
2028 | 742 | { |
2029 | 742 | input->seek(1, librevenge::RVNG_SEEK_CUR); |
2030 | 742 | unsigned long numBytes = 2*readU8(input); |
2031 | 742 | unsigned long numBytesRead = 0; |
2032 | 742 | const unsigned char *tmpBuffer = input->read(numBytes, numBytesRead); |
2033 | 742 | if (tmpBuffer && numBytesRead) |
2034 | 196 | { |
2035 | 196 | librevenge::RVNGBinaryData tmpBulletString(tmpBuffer, numBytesRead); |
2036 | 196 | bulletStr = VSDName(tmpBulletString, libvisio::VSD_TEXT_UTF16); |
2037 | 196 | } |
2038 | 742 | } |
2039 | 8.58k | else if (blockType == 2 && blockIdx == 3) |
2040 | 450 | { |
2041 | 450 | }; |
2042 | 9.32k | input->seek(blockEnd, librevenge::RVNG_SEEK_SET); |
2043 | 9.32k | remainingData -= blockLength; |
2044 | 9.32k | } |
2045 | | |
2046 | | |
2047 | 30.2k | if (m_isInStyles) |
2048 | 3.15k | m_collector->collectParaIXStyle(m_header.id, m_header.level, charCount, indFirst, indLeft, indRight, |
2049 | 3.15k | spLine, spBefore, spAfter, align, bullet, bulletStr, bulletFont, |
2050 | 3.15k | bulletFontSize, textPosAfterBullet, flags); |
2051 | 27.1k | else |
2052 | 27.1k | { |
2053 | 27.1k | if (m_isStencilStarted) |
2054 | 207 | { |
2055 | 207 | VSD_DEBUG_MSG(("Found stencil paragraph style\n")); |
2056 | 207 | } |
2057 | | |
2058 | 27.1k | m_shape.m_paraStyle.override(VSDOptionalParaStyle(charCount, indFirst, indLeft, indRight, |
2059 | 27.1k | spLine, spBefore, spAfter, align, bullet, |
2060 | 27.1k | bulletStr, bulletFont, bulletFontSize, |
2061 | 27.1k | textPosAfterBullet, flags)); |
2062 | 27.1k | m_shape.m_paraList.addParaIX(m_header.id, m_header.level, charCount, indFirst, |
2063 | 27.1k | indLeft, indRight, spLine, spBefore, spAfter, align, |
2064 | 27.1k | bullet, bulletStr, bulletFont, bulletFontSize, |
2065 | 27.1k | textPosAfterBullet, flags); |
2066 | 27.1k | } |
2067 | 30.2k | } |
2068 | | |
2069 | | |
2070 | | void libvisio::VSDParser::readFillAndShadow(librevenge::RVNGInputStream *input) |
2071 | 44.8k | { |
2072 | 44.8k | unsigned char colourFGIndex = readU8(input); |
2073 | 44.8k | Colour colourFG; |
2074 | 44.8k | colourFG.r = readU8(input); |
2075 | 44.8k | colourFG.g = readU8(input); |
2076 | 44.8k | colourFG.b = readU8(input); |
2077 | 44.8k | colourFG.a = readU8(input); |
2078 | 44.8k | unsigned char colourBGIndex = readU8(input); |
2079 | 44.8k | Colour colourBG; |
2080 | 44.8k | colourBG.r = readU8(input); |
2081 | 44.8k | colourBG.g = readU8(input); |
2082 | 44.8k | colourBG.b = readU8(input); |
2083 | 44.8k | colourBG.a = readU8(input); |
2084 | 44.8k | if (!colourFG && !colourBG) |
2085 | 17.3k | { |
2086 | 17.3k | colourFG = _colourFromIndex(colourFGIndex); |
2087 | 17.3k | colourBG = _colourFromIndex(colourBGIndex); |
2088 | 17.3k | } |
2089 | 44.8k | double fillFGTransparency = (double)colourFG.a / 255.0; |
2090 | 44.8k | double fillBGTransparency = (double)colourBG.a / 255.0; |
2091 | | |
2092 | 44.8k | unsigned char fillPattern = readU8(input); |
2093 | | |
2094 | 44.8k | unsigned char shadowFGIndex = readU8(input); |
2095 | 44.8k | Colour shadowFG; |
2096 | 44.8k | shadowFG.r = readU8(input); |
2097 | 44.8k | shadowFG.g = readU8(input); |
2098 | 44.8k | shadowFG.b = readU8(input); |
2099 | 44.8k | shadowFG.a = readU8(input); |
2100 | 44.8k | unsigned char shadowBGIndex = readU8(input); |
2101 | 44.8k | Colour shadowBG; |
2102 | 44.8k | shadowBG.r = readU8(input); |
2103 | 44.8k | shadowBG.g = readU8(input); |
2104 | 44.8k | shadowBG.b = readU8(input); |
2105 | 44.8k | shadowBG.a = readU8(input); |
2106 | 44.8k | if (!shadowFG && !shadowBG) |
2107 | 18.4k | { |
2108 | 18.4k | shadowFG = _colourFromIndex(shadowFGIndex); |
2109 | 18.4k | shadowBG = _colourFromIndex(shadowBGIndex); |
2110 | 18.4k | } |
2111 | | |
2112 | 44.8k | unsigned char shadowPattern = readU8(input); |
2113 | | |
2114 | | // only version 11 after that point |
2115 | 44.8k | input->seek(2, librevenge::RVNG_SEEK_CUR); // Shadow Type and Value format byte |
2116 | 44.8k | double shadowOffsetX = readDouble(input); |
2117 | 44.8k | input->seek(1, librevenge::RVNG_SEEK_CUR); // Value format byte |
2118 | 44.8k | double shadowOffsetY = readDouble(input); |
2119 | | |
2120 | | |
2121 | | |
2122 | 44.8k | if (m_isInStyles) |
2123 | 8.53k | m_collector->collectFillStyle(m_header.level, colourFG, colourBG, fillPattern, |
2124 | 8.53k | fillFGTransparency, fillBGTransparency, shadowPattern, shadowFG, |
2125 | 8.53k | shadowOffsetX, shadowOffsetY, -1, -1, -1); |
2126 | 36.3k | else |
2127 | 36.3k | { |
2128 | 36.3k | if (m_isStencilStarted) |
2129 | 287 | { |
2130 | 287 | VSD_DEBUG_MSG(("Found stencil fill\n")); |
2131 | 287 | } |
2132 | 36.3k | m_shape.m_fillStyle.override(VSDOptionalFillStyle(colourFG, colourBG, fillPattern, fillFGTransparency, |
2133 | 36.3k | fillBGTransparency, shadowFG, shadowPattern, |
2134 | 36.3k | shadowOffsetX, shadowOffsetY, -1, -1, -1, 0, 0)); |
2135 | 36.3k | } |
2136 | 44.8k | } |
2137 | | |
2138 | | void libvisio::VSDParser::readName(librevenge::RVNGInputStream *input) |
2139 | 4.46k | { |
2140 | 4.46k | unsigned long numBytesRead = 0; |
2141 | 4.46k | const unsigned char *tmpBuffer = input->read(m_header.dataLength, numBytesRead); |
2142 | 4.46k | if (numBytesRead) |
2143 | 1.64k | { |
2144 | 1.64k | librevenge::RVNGBinaryData name(tmpBuffer, numBytesRead); |
2145 | 1.64k | m_shape.m_names[m_header.id] = VSDName(name, libvisio::VSD_TEXT_UTF16); |
2146 | 1.64k | } |
2147 | 4.46k | } |
2148 | | |
2149 | | void libvisio::VSDParser::readName2(librevenge::RVNGInputStream *input) |
2150 | 12.8k | { |
2151 | 12.8k | unsigned short unicharacter = 0; |
2152 | 12.8k | librevenge::RVNGBinaryData name; |
2153 | 12.8k | input->seek(4, librevenge::RVNG_SEEK_CUR); // skip a dword that seems to be always 1 |
2154 | 87.1k | while ((unicharacter = readU16(input))) |
2155 | 74.3k | { |
2156 | 74.3k | name.append(unicharacter & 0xff); |
2157 | 74.3k | name.append((unicharacter & 0xff00) >> 8); |
2158 | 74.3k | } |
2159 | 12.8k | name.append(unicharacter & 0xff); |
2160 | 12.8k | name.append((unicharacter & 0xff00) >> 8); |
2161 | 12.8k | m_names[m_header.id] = VSDName(name, libvisio::VSD_TEXT_UTF16); |
2162 | 12.8k | } |
2163 | | |
2164 | | void libvisio::VSDParser::readTextField(librevenge::RVNGInputStream *input) |
2165 | 15.0k | { |
2166 | 15.0k | unsigned long initialPosition = input->tell(); |
2167 | 15.0k | input->seek(7, librevenge::RVNG_SEEK_CUR); |
2168 | 15.0k | unsigned char cellType = readU8(input); |
2169 | 15.0k | if (cellType == CELL_TYPE_StringWithoutUnit) |
2170 | 274 | { |
2171 | 274 | int nameId = readS32(input); |
2172 | 274 | input->seek(6, librevenge::RVNG_SEEK_CUR); |
2173 | 274 | int formatStringId = readS32(input); |
2174 | 274 | m_shape.m_fields.addTextField(m_header.id, m_header.level, nameId, formatStringId); |
2175 | 274 | } |
2176 | 14.8k | else |
2177 | 14.8k | { |
2178 | 14.8k | double numericValue = readDouble(input); |
2179 | 14.8k | input->seek(2, librevenge::RVNG_SEEK_CUR); |
2180 | 14.8k | int formatStringId = readS32(input); |
2181 | | |
2182 | 14.8k | unsigned blockIdx = 0; |
2183 | 14.8k | unsigned length = 0; |
2184 | 14.8k | unsigned short formatNumber = 0; |
2185 | 14.8k | input->seek(initialPosition+0x36, librevenge::RVNG_SEEK_SET); |
2186 | 16.6k | while (blockIdx != 2 && !input->isEnd() && (unsigned long) input->tell() < (unsigned long)(initialPosition+m_header.dataLength+m_header.trailer)) |
2187 | 3.25k | { |
2188 | 3.25k | unsigned long inputPos = input->tell(); |
2189 | 3.25k | length = readU32(input); |
2190 | 3.25k | if (!length) |
2191 | 1.45k | break; |
2192 | 1.80k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
2193 | 1.80k | blockIdx = readU8(input); |
2194 | 1.80k | if (blockIdx != 2) |
2195 | 1.29k | input->seek(inputPos + length, librevenge::RVNG_SEEK_SET); |
2196 | 509 | else |
2197 | 509 | { |
2198 | 509 | input->seek(1, librevenge::RVNG_SEEK_CUR); |
2199 | 509 | formatNumber = readU16(input); |
2200 | 509 | if (0x80 != readU8(input)) |
2201 | 252 | { |
2202 | 252 | input->seek(inputPos + length, librevenge::RVNG_SEEK_SET); |
2203 | 252 | blockIdx = 0; |
2204 | 252 | } |
2205 | 257 | else |
2206 | 257 | { |
2207 | 257 | if (0xc2 != readU8(input)) |
2208 | 255 | { |
2209 | 255 | input->seek(inputPos + length, librevenge::RVNG_SEEK_SET); |
2210 | 255 | blockIdx = 0; |
2211 | 255 | } |
2212 | 2 | else |
2213 | 2 | break; |
2214 | 257 | } |
2215 | 509 | } |
2216 | 1.80k | } |
2217 | | |
2218 | 14.8k | if (input->isEnd()) |
2219 | 1.79k | return; |
2220 | | |
2221 | 13.0k | if (blockIdx != 2) |
2222 | 12.4k | { |
2223 | 12.4k | if (cellType == CELL_TYPE_Date) |
2224 | 365 | formatNumber = VSD_FIELD_FORMAT_MsoDateShort; |
2225 | 12.0k | else |
2226 | 12.0k | formatNumber = VSD_FIELD_FORMAT_Unknown; |
2227 | 12.4k | } |
2228 | | |
2229 | 13.0k | m_shape.m_fields.addNumericField(m_header.id, m_header.level, formatNumber, cellType, numericValue, formatStringId); |
2230 | 13.0k | } |
2231 | 15.0k | } |
2232 | | |
2233 | | void libvisio::VSDParser::readMisc(librevenge::RVNGInputStream *input) |
2234 | 10.7k | { |
2235 | 10.7k | unsigned long initialPosition = input->tell(); |
2236 | 10.7k | unsigned char flags = readU8(input); |
2237 | 10.7k | if (flags & 0x20) |
2238 | 830 | m_shape.m_misc.m_hideText = true; |
2239 | 9.93k | else |
2240 | 9.93k | m_shape.m_misc.m_hideText = false; |
2241 | | |
2242 | 10.7k | input->seek(initialPosition+45, librevenge::RVNG_SEEK_SET); |
2243 | 29.6k | while (!input->isEnd() && (unsigned long) input->tell() < (unsigned long)(initialPosition+m_header.dataLength+m_header.trailer)) |
2244 | 24.6k | { |
2245 | 24.6k | unsigned long inputPos = input->tell(); |
2246 | 24.6k | unsigned length = readU32(input); |
2247 | 24.6k | if (!length) |
2248 | 5.75k | break; |
2249 | 18.8k | unsigned blockType = readU8(input); |
2250 | 18.8k | input->seek(1, librevenge::RVNG_SEEK_CUR); |
2251 | 18.8k | if (blockType == 2) |
2252 | 14.6k | { |
2253 | 14.6k | if (0x74 == readU8(input)) |
2254 | 627 | { |
2255 | 627 | if (0x6000004e == readU32(input)) |
2256 | 376 | { |
2257 | 376 | unsigned shapeId = readU32(input); |
2258 | 376 | if (0x7a == readU8(input)) |
2259 | 361 | { |
2260 | 361 | if (0x40000073 == readU32(input)) |
2261 | 340 | { |
2262 | 340 | if (!m_shape.m_xform1d) |
2263 | 7 | m_shape.m_xform1d = std::make_unique<XForm1D>(); |
2264 | 340 | if (m_shape.m_xform1d->beginId == MINUS_ONE) |
2265 | 173 | m_shape.m_xform1d->beginId = shapeId; |
2266 | 167 | else if (m_shape.m_xform1d->endId == MINUS_ONE) |
2267 | 167 | m_shape.m_xform1d->endId = shapeId; |
2268 | 340 | } |
2269 | 361 | } |
2270 | 376 | } |
2271 | 627 | } |
2272 | 14.6k | } |
2273 | 18.8k | input->seek(inputPos + length, librevenge::RVNG_SEEK_SET); |
2274 | 18.8k | } |
2275 | 10.7k | } |
2276 | | |
2277 | | libvisio::Colour libvisio::VSDParser::_colourFromIndex(unsigned idx) |
2278 | 547k | { |
2279 | 547k | if (idx < m_colours.size()) |
2280 | 30.9k | return m_colours[idx]; |
2281 | 516k | return libvisio::Colour(); |
2282 | 547k | } |
2283 | | |
2284 | | unsigned libvisio::VSDParser::getUInt(librevenge::RVNGInputStream *input) |
2285 | 842k | { |
2286 | 842k | return readU32(input); |
2287 | 842k | } |
2288 | | |
2289 | | int libvisio::VSDParser::getInt(librevenge::RVNGInputStream *input) |
2290 | 13.9k | { |
2291 | 13.9k | return readS32(input); |
2292 | 13.9k | } |
2293 | | |
2294 | | /* vim:set shiftwidth=2 softtabstop=2 expandtab: */ |