1 /* -*- Mode: C++; c-default-style: "k&r"; indent-tabs-mode: nil; tab-width: 2; c-basic-offset: 2 -*- */
2
3 /* libmwaw
4 * Version: MPL 2.0 / LGPLv2+
5 *
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 2.0 (the "License"); you may not use this file except in compliance with
8 * the License or as specified alternatively below. You may obtain a copy of
9 * the License at http://www.mozilla.org/MPL/
10 *
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
15 *
16 * Major Contributor(s):
17 * Copyright (C) 2002 William Lachance (wrlach@gmail.com)
18 * Copyright (C) 2002,2004 Marc Maurer (uwog@uwog.net)
19 * Copyright (C) 2004-2006 Fridrich Strba (fridrich.strba@bluewin.ch)
20 * Copyright (C) 2006, 2007 Andrew Ziem
21 * Copyright (C) 2011, 2012 Alonso Laurent (alonso@loria.fr)
22 *
23 *
24 * All Rights Reserved.
25 *
26 * For minor contributions see the git repository.
27 *
28 * Alternatively, the contents of this file may be used under the terms of
29 * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
30 * in which case the provisions of the LGPLv2+ are applicable
31 * instead of those above.
32 */
33
34 #include <cmath>
35 #include <iomanip>
36 #include <iostream>
37 #include <limits>
38 #include <map>
39 #include <set>
40 #include <sstream>
41 #include <stack>
42
43 #include <librevenge/librevenge.h>
44
45 #include "MWAWFont.hxx"
46 #include "MWAWFontConverter.hxx"
47 #include "MWAWListener.hxx"
48 #include "MWAWParagraph.hxx"
49 #include "MWAWPosition.hxx"
50 #include "MWAWSubDocument.hxx"
51
52 #include "RagTime5ClusterManager.hxx"
53 #include "RagTime5Document.hxx"
54 #include "RagTime5StructManager.hxx"
55 #include "RagTime5StyleManager.hxx"
56
57 #include "RagTime5Pipeline.hxx"
58
59 #include "libmwaw_internal.hxx"
60
61 /** Internal: the structures of a RagTime5Pipeline */
62 namespace RagTime5PipelineInternal
63 {
64 //! the pipeline cluster ( 4001 zone)
65 struct ClusterPipeline final : public RagTime5ClusterManager::Cluster {
66 //! constructor
ClusterPipelineRagTime5PipelineInternal::ClusterPipeline67 ClusterPipeline()
68 : Cluster(C_Pipeline)
69 , m_dataId(0)
70 , m_masterId(0)
71 , m_layoutId(0)
72 , m_data2Link()
73 {
74 }
75 //! destructor
76 ~ClusterPipeline() final;
77 //! the data id
78 int m_dataId;
79 //! the master id
80 int m_masterId;
81 //! the layout id
82 int m_layoutId;
83 //! the second data link(rare)
84 RagTime5ClusterManager::Link m_data2Link;
85 };
86
~ClusterPipeline()87 ClusterPipeline::~ClusterPipeline()
88 {
89 }
90
91 ////////////////////////////////////////
92 //! Internal: the state of a RagTime5Pipeline
93 struct State {
94 //! constructor
StateRagTime5PipelineInternal::State95 State()
96 : m_idPipelineMap()
97 {
98 }
99 //! map data id to text zone
100 std::map<int, std::shared_ptr<ClusterPipeline> > m_idPipelineMap;
101 };
102
103 }
104
105 ////////////////////////////////////////////////////////////
106 // constructor/destructor, ...
107 ////////////////////////////////////////////////////////////
RagTime5Pipeline(RagTime5Document & doc)108 RagTime5Pipeline::RagTime5Pipeline(RagTime5Document &doc)
109 : m_document(doc)
110 , m_structManager(m_document.getStructManager())
111 , m_parserState(doc.getParserState())
112 , m_state(new RagTime5PipelineInternal::State)
113 {
114 }
115
~RagTime5Pipeline()116 RagTime5Pipeline::~RagTime5Pipeline()
117 {
118 }
119
version() const120 int RagTime5Pipeline::version() const
121 {
122 return m_parserState->m_version;
123 }
124
send(int pipelineId,MWAWListenerPtr listener,MWAWPosition const & pos,int partId,double totalWidth)125 bool RagTime5Pipeline::send(int pipelineId, MWAWListenerPtr listener, MWAWPosition const &pos, int partId, double totalWidth)
126 {
127 if (m_state->m_idPipelineMap.find(pipelineId)==m_state->m_idPipelineMap.end() ||
128 !m_state->m_idPipelineMap.find(pipelineId)->second) {
129 MWAW_DEBUG_MSG(("RagTime5Pipeline::send: can not find container for pipeline %d\n", pipelineId));
130 return false;
131 }
132 int dataId=m_state->m_idPipelineMap.find(pipelineId)->second->m_dataId;
133 if (dataId==0)
134 return true;
135 return m_document.send(dataId, listener, pos, partId, 0, totalWidth);
136 }
137
getContainerType(int pipelineId) const138 RagTime5ClusterManager::Cluster::Type RagTime5Pipeline::getContainerType(int pipelineId) const
139 {
140 if (m_state->m_idPipelineMap.find(pipelineId)==m_state->m_idPipelineMap.end() ||
141 !m_state->m_idPipelineMap.find(pipelineId)->second) {
142 MWAW_DEBUG_MSG(("RagTime5Pipeline::getContainerType: can not find container for pipeline %d\n", pipelineId));
143 return RagTime5ClusterManager::Cluster::C_Unknown;
144 }
145 int dataId=m_state->m_idPipelineMap.find(pipelineId)->second->m_dataId;
146 if (dataId==0) // rare, but can happens
147 return RagTime5ClusterManager::Cluster::C_Unknown;
148 return m_document.getClusterType(dataId);
149 }
150
151 ////////////////////////////////////////////////////////////
152 //
153 // Intermediate level
154 //
155 ////////////////////////////////////////////////////////////
156
157 ////////////////////////////////////////////////////////////
158 //
159 // Low level
160 //
161 ////////////////////////////////////////////////////////////
162
163 ////////////////////////////////////////////////////////////
164 // interface send function
165 ////////////////////////////////////////////////////////////
flushExtra()166 void RagTime5Pipeline::flushExtra()
167 {
168 MWAW_DEBUG_MSG(("RagTime5Pipeline::flushExtra: not implemented\n"));
169 }
170
171 ////////////////////////////////////////////////////////////
172 // cluster parser
173 ////////////////////////////////////////////////////////////
174
175 namespace RagTime5PipelineInternal
176 {
177 //! Internal: the helper to read a clustList
178 struct ClustListParser final : public RagTime5StructManager::DataParser {
179 //! constructor
ClustListParserRagTime5PipelineInternal::ClustListParser180 ClustListParser(RagTime5ClusterManager &clusterManager, int fieldSize, std::string const &zoneName)
181 : RagTime5StructManager::DataParser(zoneName)
182 , m_fieldSize(fieldSize)
183 , m_linkList()
184 , m_clusterManager(clusterManager)
185 {
186 if (m_fieldSize<56) {
187 MWAW_DEBUG_MSG(("RagTime5PipelineInternal::ClustListParser: bad field size\n"));
188 m_fieldSize=0;
189 }
190 }
191 //! destructor
192 ~ClustListParser() final;
193 //! return the cluster name
getClusterDebugNameRagTime5PipelineInternal::ClustListParser194 std::string getClusterDebugName(int id) const
195 {
196 return m_clusterManager.getClusterDebugName(id);
197 }
198 //! returns the not null list dataId list
getIdListRagTime5PipelineInternal::ClustListParser199 std::vector<int> getIdList() const
200 {
201 std::vector<int> res;
202 for (auto const &lnk : m_linkList) {
203 if (lnk.m_dataId>0)
204 res.push_back(lnk.m_dataId);
205 }
206 return res;
207 }
208 //! try to parse a data
parseDataRagTime5PipelineInternal::ClustListParser209 bool parseData(MWAWInputStreamPtr &input, long endPos, RagTime5Zone &/*zone*/, int /*n*/, libmwaw::DebugStream &f) final
210 {
211 // find only cluster with one field
212 long pos=input->tell();
213 if (endPos-pos!=m_fieldSize) {
214 MWAW_DEBUG_MSG(("RagTime5PipelineInternal::ClustListParser::parse: bad data size\n"));
215 return false;
216 }
217 std::vector<int> listIds;
218 if (!RagTime5StructManager::readDataIdList(input, 1, listIds)) {
219 MWAW_DEBUG_MSG(("RagTime5PipelineInternal::ClustListParser::parse: can not read an cluster id\n"));
220 f << "##clusterIds,";
221 return false;
222 }
223 RagTime5StructManager::ZoneLink link;
224 link.m_dataId=listIds[0];
225 if (listIds[0])
226 f << getClusterDebugName(listIds[0]) << ",";
227 link.m_subZoneId[0]=long(input->readULong(4)); // subId[3]
228 f << link;
229 float dim[2];
230 for (auto &d : dim) d=float(input->readULong(4))/65536.f;
231 f << "dim=" << MWAWVec2f(dim[0],dim[1]) << ",";
232 int val;
233 f << "unkn=[";
234 for (int i=0; i<8; ++i) {
235 val=static_cast<int>(input->readLong(2));
236 if (val) f << val << ",";
237 else f << "_,";
238 }
239 f << "],";
240 for (int i=0; i<12; ++i) { // always 0
241 val=static_cast<int>(input->readLong(2));
242 if (val) f << "f" << i << "=" << val << ",";
243 }
244 m_linkList.push_back(link);
245 return true;
246 }
247
248 //! the field size
249 int m_fieldSize;
250 //! the list of read cluster
251 std::vector<RagTime5StructManager::ZoneLink> m_linkList;
252 private:
253 //! the main zone manager
254 RagTime5ClusterManager &m_clusterManager;
255 //! copy constructor, not implemented
256 ClustListParser(ClustListParser &orig) = delete;
257 //! copy operator, not implemented
258 ClustListParser &operator=(ClustListParser &orig) = delete;
259 };
260
~ClustListParser()261 ClustListParser::~ClustListParser()
262 {
263 }
264
265 //! Internal: the helper to read a unknown
266 struct UnknownParser final : public RagTime5StructManager::DataParser {
267 //! constructor
UnknownParserRagTime5PipelineInternal::UnknownParser268 UnknownParser(int fieldSize, std::string const &zoneName)
269 : RagTime5StructManager::DataParser(zoneName)
270 , m_fieldSize(fieldSize)
271 {
272 if (m_fieldSize<12) {
273 MWAW_DEBUG_MSG(("RagTime5PipelineInternal::UnknownParser: bad field size\n"));
274 m_fieldSize=0;
275 }
276 }
277 //! destructor
278 ~UnknownParser() final;
279 //! try to parse a data
parseDataRagTime5PipelineInternal::UnknownParser280 bool parseData(MWAWInputStreamPtr &input, long endPos, RagTime5Zone &/*zone*/, int /*n*/, libmwaw::DebugStream &f) final
281 {
282 long pos=input->tell();
283 if (endPos-pos!=m_fieldSize) {
284 MWAW_DEBUG_MSG(("RagTime5PipelineInternal::UnknownParser::parse: bad data size\n"));
285 return false;
286 }
287 for (int i=0; i<6; ++i) { // f0=1, f1=5|6, f2=1|2, f5=0|1
288 auto val=static_cast<int>(input->readLong(2));
289 if (val)
290 f << "f" << i << "=" << val << ",";
291 }
292 return true;
293 }
294
295 //! the field size
296 int m_fieldSize;
297 private:
298 //! copy constructor, not implemented
299 UnknownParser(UnknownParser &orig) = delete;
300 //! copy operator, not implemented
301 UnknownParser &operator=(UnknownParser &orig) = delete;
302 };
303
~UnknownParser()304 UnknownParser::~UnknownParser()
305 {
306 }
307
308 //
309 //! try to read a pipeline cluster: 104,204,4104, 4204
310 //
311 struct PipelineCParser final : public RagTime5ClusterManager::ClusterParser {
312 //! constructor
PipelineCParserRagTime5PipelineInternal::PipelineCParser313 PipelineCParser(RagTime5ClusterManager &parser, int type)
314 : ClusterParser(parser, type, "ClustPipeline")
315 , m_cluster(new ClusterPipeline)
316 {
317 }
318 //! destructor
319 ~PipelineCParser() final;
320 //! return the current cluster
getClusterRagTime5PipelineInternal::PipelineCParser321 std::shared_ptr<RagTime5ClusterManager::Cluster> getCluster() final
322 {
323 return m_cluster;
324 }
325 //! return the pipeline cluster
getPipelineClusterRagTime5PipelineInternal::PipelineCParser326 std::shared_ptr<ClusterPipeline> getPipelineCluster()
327 {
328 return m_cluster;
329 }
330 //! parse a field
parseFieldRagTime5PipelineInternal::PipelineCParser331 bool parseField(RagTime5StructManager::Field const &field, int /*m*/, libmwaw::DebugStream &f) final
332 {
333 if (field.m_type==RagTime5StructManager::Field::T_FieldList && field.m_fileType==0x146c015) {
334 f << "unkn0=[";
335 for (auto const &child : field.m_fieldList) {
336 if (child.m_type==RagTime5StructManager::Field::T_Unstructured && child.m_fileType==0xce017) { // find 2
337 f << child << ",";
338 continue;
339 }
340 MWAW_DEBUG_MSG(("RagTime5PipelineInternal::PipelineCParser::parseField: find unexpected child\n"));
341 f << "##[" << child << "],";
342 }
343 f << "],";
344 }
345 else {
346 MWAW_DEBUG_MSG(("RagTime5PipelineInternal::PipelineCParser::parseField: find unknow field\n"));
347 f << "##[" << field << "],";
348 }
349 return true;
350 }
351 //! parse a zone
parseZoneRagTime5PipelineInternal::PipelineCParser352 bool parseZone(MWAWInputStreamPtr &input, long fSz, int N, int flag, libmwaw::DebugStream &f) final
353 {
354 if (flag!=0x31)
355 f << "fl=" << std::hex << flag << std::dec << ",";
356 if (m_dataId || N!=-5) {
357 MWAW_DEBUG_MSG(("RagTime5PipelineInternal::PipelineCParser::parseZone: find unexpected header\n"));
358 f << "###type" << std::hex << N << std::dec;
359 return true;
360 }
361 if (fSz!=76 && fSz!=110) {
362 MWAW_DEBUG_MSG(("RagTime5PipelineInternal::PipelineCParser::parseZone: find unexpected file size\n"));
363 f << "###fSz=" << fSz << ",";
364 return true;
365 }
366 int val;
367 for (int i=0; i<2; ++i) { // always 0?
368 val=static_cast<int>(input->readLong(2));
369 if (val) f << "f" << i+1 << "=" << val << ",";
370 }
371 val=static_cast<int>(input->readLong(2));
372 f << "id=" << val << ",";
373 val=static_cast<int>(input->readULong(2));
374 if (val!=m_type) {
375 MWAW_DEBUG_MSG(("RagTime5PipelineInternal::PipelineCParser::parseZone: the zone type seems odd\n"));
376 f << "##zoneType=" << std::hex << val << std::dec << ",";
377 }
378 val=static_cast<int>(input->readLong(2)); // always 0?
379 if (val) f << "f4=" << val << ",";
380 for (int i=0; i<7; ++i) { // g1, g2, g3 small int other 0
381 val=static_cast<int>(input->readLong(4));
382 if (i==2)
383 m_link.m_N=val;
384 else if (val) f << "g" << i << "=" << val << ",";
385 }
386 m_link.m_fileType[1]=input->readULong(2);
387 m_link.m_fieldSize=static_cast<int>(input->readULong(2));
388
389 std::vector<int> listIds;
390 long actPos=input->tell();
391 if (!RagTime5StructManager::readDataIdList(input, 2, listIds)) {
392 MWAW_DEBUG_MSG(("RagTime5PipelineInternal::PipelineCParser::parseZone: can not read the first list id\n"));
393 f << "##listIds,";
394 input->seek(actPos, librevenge::RVNG_SEEK_SET);
395 }
396 else {
397 if (listIds[0]) {
398 m_link.m_ids.push_back(listIds[0]);
399 m_cluster->m_parentLink=m_link;
400 f << "parent[list]=data" << listIds[0] << "A,";
401 }
402 if (listIds[1]) { // the object corresponding to the pipeline
403 m_cluster->m_dataId=listIds[1];
404 f << "data[id]=" << getClusterDebugName(listIds[1]) << ",";
405 }
406 }
407 unsigned long ulVal=input->readULong(4);
408 if (ulVal) {
409 f << "h0=" << (ulVal&0x7FFFFFFF);
410 if (ulVal&0x80000000) f << "[h],";
411 else f << ",";
412 }
413 val=static_cast<int>(input->readLong(2)); // always 1?
414 if (val!=1) f << "h1=" << val << ",";
415 listIds.clear();
416 if (!RagTime5StructManager::readDataIdList(input, 2, listIds)) {
417 MWAW_DEBUG_MSG(("RagTime5PipelineInternal::PipelineCParser::parseZone: can not read the cluster list id\n"));
418 f << "##listClusterIds,";
419 return true;
420 }
421 if (listIds[0]) { // find some master layout and some master pipeline
422 m_cluster->m_masterId=listIds[0];
423 f << "id[master]=" << getClusterDebugName(listIds[0]) << ",";
424 }
425 if (listIds[1]) { // find always layout
426 m_cluster->m_layoutId=listIds[1];
427 f << "id[layout]=" << getClusterDebugName(listIds[1]) << ",";
428 }
429 val=static_cast<int>(input->readULong(2)); // 2[08a][01]
430 f << "fl=" << std::hex << val << std::dec << ",";
431 for (int i=0; i<2; ++i) { // h2=0|4|a, h3=small number
432 val=static_cast<int>(input->readLong(2));
433 if (val) f << "h" << i+2 << "=" << val << ",";
434 }
435 if (fSz==76) return true;
436
437 for (int i=0; i<7; ++i) { // g1, g2, g3 small int other 0
438 val=static_cast<int>(input->readLong(i==0 ? 2 : 4));
439 if (i==2)
440 m_link.m_N=val;
441 else if (val) f << "g" << i << "=" << val << ",";
442 }
443 m_link.m_fileType[1]=input->readULong(2);
444 m_link.m_fieldSize=static_cast<int>(input->readULong(2));
445
446 listIds.clear();
447 if (!RagTime5StructManager::readDataIdList(input, 1, listIds)) {
448 MWAW_DEBUG_MSG(("RagTime5PipelineInternal::PipelineCParser::parseZone: can not read the second list id\n"));
449 f << "##listIds2,";
450 return true;
451 }
452 if (listIds[0]) {
453 m_link.m_ids.clear();
454 m_link.m_ids.push_back(listIds[0]);
455 m_cluster->m_data2Link=m_link;
456 f << "data2=data" << listIds[0] << "A,";
457 }
458 return true;
459 }
460 protected:
461 //! the current cluster
462 std::shared_ptr<ClusterPipeline> m_cluster;
463 };
464
~PipelineCParser()465 PipelineCParser::~PipelineCParser()
466 {
467 }
468
469 }
470
readPipelineCluster(RagTime5Zone & zone,int zoneType)471 std::shared_ptr<RagTime5ClusterManager::Cluster> RagTime5Pipeline::readPipelineCluster(RagTime5Zone &zone, int zoneType)
472 {
473 auto clusterManager=m_document.getClusterManager();
474 if (!clusterManager) {
475 MWAW_DEBUG_MSG(("RagTime5Pipeline::readPipelineCluster: oops can not find the cluster manager\n"));
476 return std::shared_ptr<RagTime5ClusterManager::Cluster>();
477 }
478 RagTime5PipelineInternal::PipelineCParser parser(*clusterManager, zoneType);
479 if (!clusterManager->readCluster(zone, parser) || !parser.getPipelineCluster()) {
480 MWAW_DEBUG_MSG(("RagTime5Pipeline::readPipelineCluster: oops can not find the cluster\n"));
481 return std::shared_ptr<RagTime5ClusterManager::Cluster>();
482 }
483
484 auto cluster=parser.getPipelineCluster();
485 if (cluster->m_parentLink.empty()) {
486 MWAW_DEBUG_MSG(("RagTime5Document::readClusterPipelineData: can not find the parent zone\n"));
487 }
488 else {
489 RagTime5PipelineInternal::ClustListParser linkParser(*clusterManager, cluster->m_parentLink.m_fieldSize, "PipelineParent");
490 m_document.readFixedSizeZone(cluster->m_parentLink, linkParser);
491 m_document.checkClusterList(linkParser.m_linkList);
492 }
493
494 if (!cluster->m_data2Link.empty()) {
495 RagTime5PipelineInternal::UnknownParser data2Parser(cluster->m_data2Link.m_fieldSize, "PipelineUnknown");
496 m_document.readFixedSizeZone(cluster->m_data2Link, data2Parser);
497 }
498
499 if (m_state->m_idPipelineMap.find(zone.m_ids[0])!=m_state->m_idPipelineMap.end()) {
500 MWAW_DEBUG_MSG(("RagTime5Pipeline::readPipelineCluster: cluster %d already exists\n", zone.m_ids[0]));
501 }
502 else
503 m_state->m_idPipelineMap[zone.m_ids[0]]=cluster;
504 return cluster;
505 }
506
507 // vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab:
508