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 <iomanip>
35 #include <map>
36 #include <sstream>
37 #include <stack>
38 
39 #include "MWAWCell.hxx"
40 #include "MWAWDebug.hxx"
41 #include "MWAWFont.hxx"
42 #include "MWAWFontConverter.hxx"
43 #include "MWAWParagraph.hxx"
44 #include "MWAWSection.hxx"
45 
46 #include "RagTime5Document.hxx"
47 #include "RagTime5StructManager.hxx"
48 
49 #include "RagTime5StyleManager.hxx"
50 
51 /** Internal: the structures of a RagTime5Style */
52 namespace RagTime5StyleManagerInternal
53 {
54 ////////////////////////////////////////
55 //! Internal: the helper to read field color field for a RagTime5StyleManager
56 struct ColorFieldParser final : public RagTime5StructManager::FieldParser {
57   //! constructor
ColorFieldParserRagTime5StyleManagerInternal::ColorFieldParser58   ColorFieldParser()
59     : RagTime5StructManager::FieldParser("GraphColor")
60     , m_colorsList()
61   {
62     m_regroupFields=false;
63   }
64   //! destructor
65   ~ColorFieldParser() final;
66   //! return the debug name corresponding to a field
getZoneNameRagTime5StyleManagerInternal::ColorFieldParser67   std::string getZoneName(int n) const final
68   {
69     std::stringstream s;
70     s << "GraphColor-GC" << n;
71     return s.str();
72   }
73   //! parse a field
parseFieldRagTime5StyleManagerInternal::ColorFieldParser74   bool parseField(RagTime5StructManager::Field &field, RagTime5Zone &/*zone*/, int n, libmwaw::DebugStream &f) final
75   {
76     if (field.m_type!=RagTime5StructManager::Field::T_FieldList) {
77       MWAW_DEBUG_MSG(("RagTime5StyleManagerInternal::ColorFieldParser::parseField: find unexpected field type \n"));
78       f << "##field,";
79       return true;
80     }
81     switch (field.m_fileType) {
82     case 0x7d02a:
83       for (auto const &child : field.m_fieldList) {
84         // checkme:
85         if (child.m_type==RagTime5StructManager::Field::T_Color && child.m_fileType==0x84040) {
86           if (n>=0 && int(m_colorsList.size())<n)
87             m_colorsList.resize(size_t(n));
88           if (n>=1 && n<=int(m_colorsList.size()))
89             m_colorsList[size_t(n-1)]=child.m_color;
90           else {
91             MWAW_DEBUG_MSG(("RagTime5StyleManagerInternal::ColorFieldParser::parseField: find bad n\n"));
92             f << "col=" << child.m_color << "[###],";
93           }
94           continue;
95         }
96         MWAW_DEBUG_MSG(("RagTime5StyleManagerInternal::ColorFieldParser::parseField: find some unknown color block\n"));
97         f << "##col=" << child << ",";
98       }
99       break;
100     case 0x17d481a:
101       for (auto const &child : field.m_fieldList) {
102         if (child.m_type==RagTime5StructManager::Field::T_Long && child.m_fileType==0x3b880) {
103           f << "id=" << child.m_longValue[0] << ",";
104           continue;
105         }
106         MWAW_DEBUG_MSG(("RagTime5StyleManagerInternal::ColorFieldParser::parseField: find some unknown id block\n"));
107         f << "##id=" << child << ",";
108       }
109       break;
110     case 0x17d484a: // always 0:1
111       for (auto const &child : field.m_fieldList) {
112         if (child.m_type==RagTime5StructManager::Field::T_2Long && child.m_fileType==0x34800) {
113           f << "unkn0=" << child.m_longValue[0] << "x" << child.m_longValue[1] << ",";
114           continue;
115         }
116         MWAW_DEBUG_MSG(("RagTime5StyleManagerInternal::ColorFieldParser::parseField: find some unknown unkn0 block\n"));
117         f << "##unkn0=" << child << ",";
118       }
119       break;
120     case 0x17d486a:
121       for (auto const &child : field.m_fieldList) {
122         if (child.m_type==RagTime5StructManager::Field::T_Bool && child.m_fileType==0x360c0) {
123           f << "fl0=" << child.m_longValue[0] << ",";
124           continue;
125         }
126         MWAW_DEBUG_MSG(("RagTime5StyleManagerInternal::ColorFieldParser::parseField: find some unknown fl0 block\n"));
127         f << "##fl0=" << child << ",";
128       }
129       break;
130     default:
131       MWAW_DEBUG_MSG(("RagTime5StyleManagerInternal::ColorFieldParser::parseField: find some unknown block\n"));
132       f << "###" << field;
133       break;
134     }
135     return true;
136   }
137 
138   //! the list of color
139   std::vector<MWAWColor> m_colorsList;
140 };
141 
~ColorFieldParser()142 ColorFieldParser::~ColorFieldParser()
143 {
144 }
145 
146 ////////////////////////////////////////
147 //! Internal: the helper to read field graphic field for a RagTime5StyleManager
148 struct GraphicFieldParser final : public RagTime5StructManager::FieldParser {
149   //! constructor
GraphicFieldParserRagTime5StyleManagerInternal::GraphicFieldParser150   explicit GraphicFieldParser(std::vector<MWAWColor> const &colorList)
151     : RagTime5StructManager::FieldParser("GraphStyle")
152     , m_colorsList(colorList)
153     , m_styleList()
154   {
155     m_regroupFields=true;
156   }
157   //! destructor
158   ~GraphicFieldParser() final;
159   //! return the debug name corresponding to a field
getZoneNameRagTime5StyleManagerInternal::GraphicFieldParser160   std::string getZoneName(int n) const final
161   {
162     // we need to resize here (if the style does not contains any field)
163     if (n>=int(m_styleList.size()))
164       const_cast<GraphicFieldParser *>(this)->m_styleList.resize(size_t(n+1));
165     std::stringstream s;
166     s << "GraphStyle-GS" << n;
167     return s.str();
168   }
169   //! parse a header field
parseHeaderFieldRagTime5StyleManagerInternal::GraphicFieldParser170   bool parseHeaderField(RagTime5StructManager::Field &field, RagTime5Zone &zone, int n, libmwaw::DebugStream &f) final
171   {
172     if (n>=int(m_styleList.size()))
173       m_styleList.resize(size_t(n+1));
174     auto &style=m_styleList[size_t(n)];
175     MWAWInputStreamPtr input=zone.getInput();
176     if (style.read(input, field, m_colorsList))
177       f << style;
178     else
179       f << "###" << field;
180     return true;
181   }
182   //! parse a field
parseFieldRagTime5StyleManagerInternal::GraphicFieldParser183   bool parseField(RagTime5StructManager::Field &field, RagTime5Zone &zone, int n, libmwaw::DebugStream &f) final
184   {
185     if (n<=0) {
186       MWAW_DEBUG_MSG(("RagTime5StyleManagerInternal::GraphicFieldParser::parseField: n=%d is bad\n", n));
187       n=0;
188     }
189     if (n>=int(m_styleList.size()))
190       m_styleList.resize(size_t(n+1));
191     auto &style=m_styleList[size_t(n)];
192     MWAWInputStreamPtr input=zone.getInput();
193     if (style.read(input, field, m_colorsList)) {
194       RagTime5StyleManager::GraphicStyle modStyle;
195       modStyle.read(input, field, m_colorsList);
196       f << modStyle;
197     }
198     else
199       f << "##" << field;
200     return true;
201   }
202 
203   // !the main color map
204   std::vector<MWAWColor> const &m_colorsList;
205 //! the list of graphic style
206   std::vector<RagTime5StyleManager::GraphicStyle> m_styleList;
207 };
208 
~GraphicFieldParser()209 GraphicFieldParser::~GraphicFieldParser()
210 {
211 }
212 
213 ////////////////////////////////////////
214 //! Internal: the helper to read style for a RagTime5StyleManager
215 struct TextFieldParser final : public RagTime5StructManager::FieldParser {
216   //! constructor
TextFieldParserRagTime5StyleManagerInternal::TextFieldParser217   TextFieldParser()
218     : RagTime5StructManager::FieldParser("TextStyle")
219     , m_styleList()
220   {
221   }
222   //! destructor
223   ~TextFieldParser() final;
224   //! return the debug name corresponding to a field
getZoneNameRagTime5StyleManagerInternal::TextFieldParser225   std::string getZoneName(int n) const final
226   {
227     std::stringstream s;
228     s << "TextStyle-TS" << n;
229     return s.str();
230   }
231   //! parse a header field
parseHeaderFieldRagTime5StyleManagerInternal::TextFieldParser232   bool parseHeaderField(RagTime5StructManager::Field &field, RagTime5Zone &/*zone*/, int n, libmwaw::DebugStream &f) final
233   {
234     if (n>=int(m_styleList.size()))
235       m_styleList.resize(size_t(n+1));
236     auto &style=m_styleList[size_t(n)];
237     if (style.read(field))
238       f << style;
239     else
240       f << "###" << field;
241     return true;
242   }
243   //! parse a field
parseFieldRagTime5StyleManagerInternal::TextFieldParser244   bool parseField(RagTime5StructManager::Field &field, RagTime5Zone &/*zone*/, int n, libmwaw::DebugStream &f) final
245   {
246     if (n<=0) {
247       MWAW_DEBUG_MSG(("RagTime5StyleManagerInternal::TextFieldParser::parseField: n=%d is bad\n", n));
248       n=0;
249     }
250     if (n>=int(m_styleList.size()))
251       m_styleList.resize(size_t(n+1));
252     auto &style=m_styleList[size_t(n)];
253     if (style.read(field)) {
254       RagTime5StyleManager::TextStyle modStyle;
255       modStyle.read(field);
256       f << modStyle;
257     }
258     else
259       f << "#" << field;
260     return true;
261   }
262 
263   //! the list of read style
264   std::vector<RagTime5StyleManager::TextStyle> m_styleList;
265 };
266 
267 //! Internal: the state of a RagTime5Style
268 struct State {
269   //! constructor
StateRagTime5StyleManagerInternal::State270   State()
271     : m_colorsList()
272     , m_formatList()
273     , m_graphicStyleList()
274     , m_textStyleList()
275   {
276   }
277   //! init the color list (if empty)
278   void initColorsList();
279   //! the list of color
280   std::vector<MWAWColor> m_colorsList;
281   //! the list of format
282   std::vector<MWAWCell::Format> m_formatList;
283   //! the list of graphic styles
284   std::vector<RagTime5StyleManager::GraphicStyle> m_graphicStyleList;
285   //! the list of text styles
286   std::vector<RagTime5StyleManager::TextStyle> m_textStyleList;
287 };
288 
~TextFieldParser()289 TextFieldParser::~TextFieldParser()
290 {
291 }
292 
initColorsList()293 void State::initColorsList()
294 {
295   if (!m_colorsList.empty()) return;
296   MWAW_DEBUG_MSG(("RagTime5StyleManagerInternal::State::initColorsList: colors' list is empty, set it to default\n"));
297   m_colorsList.push_back(MWAWColor::white());
298   m_colorsList.push_back(MWAWColor(0,0,0,0)); // transparent
299   m_colorsList.push_back(MWAWColor::black());
300 }
301 }
302 
303 ////////////////////////////////////////////////////////////
304 // constructor/destructor, ...
305 ////////////////////////////////////////////////////////////
RagTime5StyleManager(RagTime5Document & doc)306 RagTime5StyleManager::RagTime5StyleManager(RagTime5Document &doc)
307   : m_document(doc)
308   , m_parserState(doc.getParserState())
309   , m_state(new RagTime5StyleManagerInternal::State)
310 {
311 }
312 
~RagTime5StyleManager()313 RagTime5StyleManager::~RagTime5StyleManager()
314 {
315 }
316 
317 ////////////////////////////////////////////////////////////
318 // read style
319 ////////////////////////////////////////////////////////////
readGraphicColors(RagTime5ClusterManager::Cluster & cluster)320 bool RagTime5StyleManager::readGraphicColors(RagTime5ClusterManager::Cluster &cluster)
321 {
322   RagTime5StyleManagerInternal::ColorFieldParser fieldParser;
323   if (!m_document.readStructZone(cluster.m_dataLink, fieldParser, 14, &cluster.m_nameLink))
324     return false;
325   m_state->m_colorsList=fieldParser.m_colorsList;
326   return true;
327 }
328 
readGraphicStyles(RagTime5ClusterManager::Cluster & cluster)329 bool RagTime5StyleManager::readGraphicStyles(RagTime5ClusterManager::Cluster &cluster)
330 {
331   m_state->initColorsList();
332   RagTime5StyleManagerInternal::GraphicFieldParser fieldParser(m_state->m_colorsList);
333   if (!m_document.readStructZone(cluster.m_dataLink, fieldParser, 14, &cluster.m_nameLink))
334     return false;
335   if (fieldParser.m_styleList.empty())
336     fieldParser.m_styleList.resize(1);
337 
338   //
339   // check parent relation, check for loop, ...
340   //
341   std::vector<size_t> rootList;
342   std::stack<size_t> toCheck;
343   std::multimap<size_t, size_t> idToChildIpMap;
344   auto numStyles=size_t(fieldParser.m_styleList.size());
345   for (size_t i=0; i<numStyles; ++i) {
346     auto &style=fieldParser.m_styleList[i];
347     if (style.m_parentId>=0 && style.m_parentId>=static_cast<int>(numStyles)) {
348       MWAW_DEBUG_MSG(("RagTime5StyleManager::readGraphicStyles: find unexpected parent %d for style %d\n",
349                       static_cast<int>(style.m_parentId), static_cast<int>(i)));
350       style.m_parentId=0;
351       continue;
352     }
353     else if (style.m_parentId>=0) {
354       idToChildIpMap.insert(std::multimap<size_t, size_t>::value_type(size_t(style.m_parentId),i));
355       continue;
356     }
357     rootList.push_back(i);
358     toCheck.push(i);
359   }
360   std::set<size_t> seens;
361   while (true) {
362     size_t posToCheck=0; // to make clang happy
363     if (!toCheck.empty()) {
364       posToCheck=toCheck.top();
365       toCheck.pop();
366     }
367     else if (seens.size()+1==numStyles)
368       break;
369     else {
370       bool ok=false;
371       for (size_t i=1; i<numStyles; ++i) {
372         if (seens.find(i)!=seens.end())
373           continue;
374         MWAW_DEBUG_MSG(("RagTime5StyleManager::readGraphicStyles: find unexpected root %d\n", static_cast<int>(i)));
375         posToCheck=i;
376         rootList.push_back(i);
377 
378         auto &style=fieldParser.m_styleList[i];
379         style.m_parentId=0;
380         ok=true;
381         break;
382       }
383       if (!ok)
384         break;
385     }
386     if (seens.find(posToCheck)!=seens.end()) {
387       MWAW_DEBUG_MSG(("RagTime5StyleManager::readGraphicStyles: oops, %d is already seens\n", static_cast<int>(posToCheck)));
388       continue;
389     }
390     seens.insert(posToCheck);
391     auto childIt=idToChildIpMap.lower_bound(posToCheck);
392     std::vector<size_t> badChildList;
393     while (childIt!=idToChildIpMap.end() && childIt->first==posToCheck) {
394       size_t childId=childIt++->second;
395       if (seens.find(childId)!=seens.end()) {
396         MWAW_DEBUG_MSG(("RagTime5StyleManager::readGraphicStyles: find loop for child %d\n", static_cast<int>(childId)));
397         RagTime5StyleManager::GraphicStyle &style=fieldParser.m_styleList[childId];
398         style.m_parentId=0;
399         badChildList.push_back(childId);
400         continue;
401       }
402       toCheck.push(childId);
403     }
404     for (auto badId : badChildList) {
405       childIt=idToChildIpMap.lower_bound(posToCheck);
406       while (childIt!=idToChildIpMap.end() && childIt->first==posToCheck) {
407         if (childIt->second==badId) {
408           idToChildIpMap.erase(childIt);
409           break;
410         }
411         ++childIt;
412       }
413     }
414   }
415 
416   if (!m_state->m_graphicStyleList.empty()) {
417     MWAW_DEBUG_MSG(("RagTime5StyleManager::readGraphicStyles: Ooops, we already set some graphicStyles\n"));
418   }
419 
420   // now let generate the final style
421   m_state->m_graphicStyleList.resize(numStyles);
422   seens.clear();
423   for (auto id : rootList) {
424     if (id>=numStyles) {
425       MWAW_DEBUG_MSG(("RagTime5StyleManager::readGraphicStyles: find loop for id=%d\n", static_cast<int>(id)));
426       continue;
427     }
428     updateGraphicStyles(id, fieldParser.m_styleList[id], fieldParser.m_styleList, idToChildIpMap, seens);
429   }
430   return true;
431 }
432 
updateGraphicStyles(size_t id,RagTime5StyleManager::GraphicStyle const & style,std::vector<RagTime5StyleManager::GraphicStyle> const & listReadStyles,std::multimap<size_t,size_t> const & idToChildIpMap,std::set<size_t> & seens)433 void RagTime5StyleManager::updateGraphicStyles
434 (size_t id, RagTime5StyleManager::GraphicStyle const &style, std::vector<RagTime5StyleManager::GraphicStyle> const &listReadStyles,
435  std::multimap<size_t, size_t> const &idToChildIpMap, std::set<size_t> &seens)
436 {
437   if (id>=m_state->m_graphicStyleList.size() || seens.find(id)!=seens.end()) {
438     MWAW_DEBUG_MSG(("RagTime5StyleManager::updateGraphicStyles: problem with style with id=%d\n", static_cast<int>(id)));
439     return;
440   }
441   seens.insert(id);
442   m_state->m_graphicStyleList[id]=style;
443 
444   auto childIt=idToChildIpMap.lower_bound(id);
445   while (childIt!=idToChildIpMap.end() && childIt->first==id) {
446     size_t childId=childIt++->second;
447     if (childId>=listReadStyles.size()) {
448       MWAW_DEBUG_MSG(("RagTime5StyleManager::updateGraphicStyles: problem with style with childId=%d\n", static_cast<int>(childId)));
449       continue;
450     }
451     auto childStyle=style;
452     childStyle.insert(listReadStyles[childId]);
453     updateGraphicStyles(childId, childStyle, listReadStyles, idToChildIpMap, seens);
454   }
455 }
456 
getLineColor(int gId,MWAWColor & color) const457 bool RagTime5StyleManager::getLineColor(int gId, MWAWColor &color) const
458 {
459   if (gId<=0 || gId>=static_cast<int>(m_state->m_graphicStyleList.size())) {
460     MWAW_DEBUG_MSG(("RagTime5StyleManager::getLineColor: can not find graphic style %d\n", gId));
461     return false;
462   }
463   auto const &style=m_state->m_graphicStyleList[size_t(gId)];
464   color=style.m_colors[0].get();
465   if (style.m_colorsAlpha[0]>=0 && style.m_colorsAlpha[0]<1)
466     color=MWAWColor::barycenter(style.m_colorsAlpha[0],color,1-style.m_colorsAlpha[0],MWAWColor::white());
467 
468   return true;
469 }
470 
getCellBorder(int gId,MWAWBorder & border) const471 bool RagTime5StyleManager::getCellBorder(int gId, MWAWBorder &border) const
472 {
473   if (gId<=0 || gId>=static_cast<int>(m_state->m_graphicStyleList.size())) {
474     MWAW_DEBUG_MSG(("RagTime5StyleManager::getCellBorder: can not find graphic style %d\n", gId));
475     border.m_width=0;
476     return false;
477   }
478   auto const &gStyle=m_state->m_graphicStyleList[size_t(gId)];
479   if (gStyle.m_width>=0)
480     border.m_width=double(gStyle.m_width);
481   else
482     border.m_width=1;
483   if (gStyle.m_pattern) {
484     MWAWColor color;
485     if (gStyle.m_pattern->getAverageColor(color)) {
486       if (gStyle.m_colors[0].isSet() || gStyle.m_colors[1].isSet()) {
487         float alpha=(float(color.getRed())+float(color.getGreen())+float(color.getBlue()))/765.f;
488         border.m_color=MWAWColor::barycenter(1.f-alpha, *gStyle.m_colors[0], alpha, *gStyle.m_colors[1]);
489       }
490       else
491         border.m_color=color;
492     }
493   }
494   else if (gStyle.m_colors[0].isSet())
495     border.m_color=gStyle.m_colors[0].get();
496   else // default
497     border.m_color=MWAWColor(0,0,0);
498   if (gStyle.m_dash.isSet() && gStyle.m_dash->size()>=4) {
499     long fullWidth=0, emptyWidth=0;
500     for (size_t i=0; i<gStyle.m_dash->size(); i+=2) {
501       if ((i%4)==0)
502         fullWidth+= (*gStyle.m_dash)[i];
503       else
504         emptyWidth+=(*gStyle.m_dash)[i];
505     }
506     if (fullWidth==2 && emptyWidth==2)
507       border.m_style=MWAWBorder::Dot;
508     else if (fullWidth==10 && emptyWidth==5)
509       border.m_style=MWAWBorder::Dash;
510     else // ok, specific dash, let use large dot
511       border.m_style=MWAWBorder::LargeDot;
512   }
513   return true;
514 
515 }
516 
getCellBackgroundColor(int gId,MWAWColor & color) const517 bool RagTime5StyleManager::getCellBackgroundColor(int gId, MWAWColor &color) const
518 {
519   if (gId<=0 || gId>=static_cast<int>(m_state->m_graphicStyleList.size())) {
520     MWAW_DEBUG_MSG(("RagTime5StyleManager::getCellBackgroundColor: can not find graphic style %d\n", gId));
521     return false;
522   }
523   auto const &gStyle=m_state->m_graphicStyleList[size_t(gId)];
524   if (gStyle.m_pattern) {
525     MWAWColor col;
526     if (gStyle.m_pattern->getAverageColor(col)) {
527       if (gStyle.m_colors[0].isSet() || gStyle.m_colors[1].isSet()) {
528         float alpha=(float(col.getRed())+float(col.getGreen())+float(col.getBlue()))/765.f;
529         color=MWAWColor::barycenter(1.f-alpha, *gStyle.m_colors[0], alpha, *gStyle.m_colors[1]);
530       }
531       else
532         color=col;
533     }
534   }
535   else if (gStyle.m_colors[0].isSet())
536     color=gStyle.m_colors[0].get();
537   else // default is white
538     color=MWAWColor(255,255,255);
539 
540   return true;
541 }
542 
updateBorderStyle(int gId,MWAWGraphicStyle & style,bool isLine) const543 bool RagTime5StyleManager::updateBorderStyle(int gId, MWAWGraphicStyle &style, bool isLine) const
544 {
545   if (gId<=0 || gId>=static_cast<int>(m_state->m_graphicStyleList.size())) {
546     MWAW_DEBUG_MSG(("RagTime5StyleManager::updateBorderStyle: can not find graphic style %d\n", gId));
547     style.m_lineWidth=0;
548     return false;
549   }
550   auto const &gStyle=m_state->m_graphicStyleList[size_t(gId)];
551   if (gStyle.m_width>=0)
552     style.m_lineWidth=gStyle.m_width;
553   else
554     style.m_lineWidth=1;
555   if (gStyle.m_pattern) {
556     MWAWColor color;
557     if (gStyle.m_pattern->getAverageColor(color)) {
558       if (gStyle.m_colors[0].isSet() || gStyle.m_colors[1].isSet()) {
559         float alpha=(float(color.getRed())+float(color.getGreen())+float(color.getBlue()))/765.f;
560         style.m_lineColor=MWAWColor::barycenter(1.f-alpha, *gStyle.m_colors[0], alpha, *gStyle.m_colors[1]);
561       }
562       else
563         style.m_lineColor=color;
564     }
565   }
566   else if (isLine || gStyle.m_colors[0].isSet())
567     style.m_lineColor=gStyle.m_colors[0].get();
568   else // default is blue
569     style.m_lineColor=MWAWColor(0,0,255);
570   if (gStyle.m_colorsAlpha[0]>=0)
571     style.m_lineOpacity=gStyle.m_colorsAlpha[0];
572   if (gStyle.m_dash.isSet() && gStyle.m_dash->size()>=4) {
573     for (size_t i=0; i<gStyle.m_dash->size(); i+=2)
574       style.m_lineDashWidth.push_back(float((*gStyle.m_dash)[i]));
575   }
576   return true;
577 }
578 
updateFrameStyle(int gId,MWAWGraphicStyle & style) const579 bool RagTime5StyleManager::updateFrameStyle(int gId, MWAWGraphicStyle &style) const
580 {
581   if (gId<=0 || gId>=static_cast<int>(m_state->m_graphicStyleList.size())) {
582     MWAW_DEBUG_MSG(("RagTime5StyleManager::updateSurfaceStyle: can not find graphic style %d\n", gId));
583     return false;
584   }
585   auto const &gStyle=m_state->m_graphicStyleList[size_t(gId)];
586   if (gStyle.m_colorsAlpha[0]<=0 && gStyle.m_colorsAlpha[0]>=0)
587     return true;
588   float alpha=gStyle.m_colorsAlpha[0]>=0 ? gStyle.m_colorsAlpha[0] : 1;
589   if (((gStyle.m_gradient>=1 && gStyle.m_gradient<=2) || gStyle.m_pattern) &&
590       gStyle.m_colors[0].isSet() && gStyle.m_colors[1].isSet())
591     style.setBackgroundColor(MWAWColor::barycenter(0.5, gStyle.m_colors[0].get(),
592                              0.5, gStyle.m_colors[1].get()),
593                              0.5f*gStyle.m_colorsAlpha[0]+0.5f*gStyle.m_colorsAlpha[1]);
594   else if (gStyle.m_colors[0].isSet())
595     style.setBackgroundColor(gStyle.m_colors[0].get(), alpha);
596   return true;
597 }
598 
updateSurfaceStyle(int gId,MWAWGraphicStyle & style) const599 bool RagTime5StyleManager::updateSurfaceStyle(int gId, MWAWGraphicStyle &style) const
600 {
601   if (gId<=0 || gId>=static_cast<int>(m_state->m_graphicStyleList.size())) {
602     MWAW_DEBUG_MSG(("RagTime5StyleManager::updateSurfaceStyle: can not find graphic style %d\n", gId));
603     return false;
604   }
605   auto const &gStyle=m_state->m_graphicStyleList[size_t(gId)];
606   if (gStyle.m_colorsAlpha[0]<=0 && gStyle.m_colorsAlpha[0]>=0)
607     return true;
608   float alpha=gStyle.m_colorsAlpha[0]>=0 ? gStyle.m_colorsAlpha[0] : 1;
609   if (gStyle.m_gradient>=1 && gStyle.m_gradient<=2) {
610     auto &finalGrad=style.m_gradient;
611     finalGrad.m_type=gStyle.m_gradient==2 ? MWAWGraphicStyle::Gradient::G_Radial : MWAWGraphicStyle::Gradient::G_Linear;
612     finalGrad.m_stopList.resize(0);
613     if (gStyle.m_gradient==1)
614       finalGrad.m_stopList.push_back(MWAWGraphicStyle::Gradient::Stop(0, MWAWColor::white()));
615     else
616       finalGrad.m_stopList.push_back(MWAWGraphicStyle::Gradient::Stop(0, gStyle.m_colors[0].get()));
617     finalGrad.m_stopList.push_back(MWAWGraphicStyle::Gradient::Stop(1, gStyle.m_colors[1].get()));
618     if (gStyle.m_gradientCenter.isSet())
619       finalGrad.m_percentCenter=*gStyle.m_gradientCenter;
620     if (gStyle.m_gradientRotation>-1000)
621       finalGrad.m_angle=gStyle.m_gradientRotation+90;
622   }
623   else if (gStyle.m_pattern) {
624     auto pat=*gStyle.m_pattern;
625     if (gStyle.m_colors[0].isSet())
626       pat.m_colors[1]=*gStyle.m_colors[0];
627     if (gStyle.m_colors[1].isSet())
628       pat.m_colors[0]=*gStyle.m_colors[1];
629     style.setPattern(pat, alpha);
630   }
631   else if (gStyle.m_colors[0].isSet())
632     style.setSurfaceColor(gStyle.m_colors[0].get(), alpha);
633   return true;
634 }
635 
readTextStyles(RagTime5ClusterManager::Cluster & cluster)636 bool RagTime5StyleManager::readTextStyles(RagTime5ClusterManager::Cluster &cluster)
637 {
638   RagTime5StyleManagerInternal::TextFieldParser fieldParser;
639   if (!m_document.readStructZone(cluster.m_dataLink, fieldParser, 14, &cluster.m_nameLink))
640     return false;
641 
642   if (fieldParser.m_styleList.empty())
643     fieldParser.m_styleList.resize(1);
644 
645   //
646   // check parent relation, check for loop, ...
647   //
648   std::vector<size_t> rootList;
649   std::stack<size_t> toCheck;
650   std::multimap<size_t, size_t> idToChildIpMap;
651   auto numStyles=size_t(fieldParser.m_styleList.size());
652   for (size_t i=0; i<numStyles; ++i) {
653     RagTime5StyleManager::TextStyle &style=fieldParser.m_styleList[i];
654     if (!style.m_fontName.empty()) // update the font it
655       style.m_fontId=m_parserState->m_fontConverter->getId(style.m_fontName.cstr());
656     bool ok=true;
657     for (auto &parentId : style.m_parentId) {
658       if (parentId<=0)
659         continue;
660       if (parentId>=static_cast<int>(numStyles)) {
661         MWAW_DEBUG_MSG(("RagTime5StyleManager::readTextStyles: find unexpected parent %d for style %d\n",
662                         static_cast<int>(parentId), static_cast<int>(i)));
663         parentId=0;
664         continue;
665       }
666       ok=false;
667       idToChildIpMap.insert(std::multimap<size_t, size_t>::value_type(size_t(parentId),i));
668     }
669     if (!ok) continue;
670     rootList.push_back(i);
671     toCheck.push(i);
672   }
673   std::set<size_t> seens;
674   while (true) {
675     size_t posToCheck=0; // to make clang happy
676     if (!toCheck.empty()) {
677       posToCheck=toCheck.top();
678       toCheck.pop();
679     }
680     else if (seens.size()+1==numStyles)
681       break;
682     else {
683       bool ok=false;
684       for (size_t i=1; i<numStyles; ++i) {
685         if (seens.find(i)!=seens.end())
686           continue;
687         MWAW_DEBUG_MSG(("RagTime5StyleManager::readTextStyles: find unexpected root %d\n", static_cast<int>(i)));
688         posToCheck=i;
689         rootList.push_back(i);
690 
691         auto &style=fieldParser.m_styleList[i];
692         style.m_parentId[0]=style.m_parentId[1]=0;
693         ok=true;
694         break;
695       }
696       if (!ok)
697         break;
698     }
699     if (seens.find(posToCheck)!=seens.end()) {
700       MWAW_DEBUG_MSG(("RagTime5StyleManager::readTextStyles: oops, %d is already seens\n", static_cast<int>(posToCheck)));
701       continue;
702     }
703     seens.insert(posToCheck);
704     auto childIt=idToChildIpMap.lower_bound(posToCheck);
705     std::vector<size_t> badChildList;
706     while (childIt!=idToChildIpMap.end() && childIt->first==posToCheck) {
707       size_t childId=childIt++->second;
708       if (seens.find(childId)!=seens.end()) {
709         MWAW_DEBUG_MSG(("RagTime5StyleManager::readTextStyles: find loop for child %d\n", static_cast<int>(childId)));
710         auto &style=fieldParser.m_styleList[childId];
711         if (style.m_parentId[0]==static_cast<int>(posToCheck))
712           style.m_parentId[0]=0;
713         if (style.m_parentId[1]==static_cast<int>(posToCheck))
714           style.m_parentId[1]=0;
715         badChildList.push_back(childId);
716         continue;
717       }
718       toCheck.push(childId);
719     }
720     for (auto badId : badChildList) {
721       childIt=idToChildIpMap.lower_bound(posToCheck);
722       while (childIt!=idToChildIpMap.end() && childIt->first==posToCheck) {
723         if (childIt->second==badId) {
724           idToChildIpMap.erase(childIt);
725           break;
726         }
727         ++childIt;
728       }
729     }
730   }
731 
732   if (!m_state->m_textStyleList.empty()) {
733     MWAW_DEBUG_MSG(("RagTime5StyleManager::readTextStyles: Ooops, we already set some textStyles\n"));
734   }
735 
736   // now let generate the final style
737   m_state->m_textStyleList.resize(numStyles);
738   seens.clear();
739   for (auto id : rootList) {
740     if (id>=numStyles) {
741       MWAW_DEBUG_MSG(("RagTime5StyleManager::readTextStyles: find loop for id=%d\n", static_cast<int>(id)));
742       continue;
743     }
744     updateTextStyles(id, fieldParser.m_styleList[id], fieldParser.m_styleList, idToChildIpMap, seens);
745   }
746   return true;
747 }
748 
updateTextStyles(size_t id,RagTime5StyleManager::TextStyle const & style,std::vector<RagTime5StyleManager::TextStyle> const & listReadStyles,std::multimap<size_t,size_t> const & idToChildIpMap,std::set<size_t> & seens)749 void RagTime5StyleManager::updateTextStyles
750 (size_t id, RagTime5StyleManager::TextStyle const &style, std::vector<RagTime5StyleManager::TextStyle> const &listReadStyles,
751  std::multimap<size_t, size_t> const &idToChildIpMap, std::set<size_t> &seens)
752 {
753   if (id>=m_state->m_textStyleList.size() || seens.find(id)!=seens.end()) {
754     MWAW_DEBUG_MSG(("RagTime5StyleManager::updateTextStyles: problem with style with id=%d\n", static_cast<int>(id)));
755     return;
756   }
757   seens.insert(id);
758   auto styl=style;
759   styl.m_fontFlags[0]&=(~style.m_fontFlags[1]);
760   m_state->m_textStyleList[id]=styl;
761 
762   auto childIt=idToChildIpMap.lower_bound(id);
763   while (childIt!=idToChildIpMap.end() && childIt->first==id) {
764     size_t childId=childIt++->second;
765     if (childId>=listReadStyles.size()) {
766       MWAW_DEBUG_MSG(("RagTime5StyleManager::updateTextStyles: problem with style with childId=%d\n", static_cast<int>(childId)));
767       continue;
768     }
769     auto childStyle=styl;
770     childStyle.insert(listReadStyles[childId]);
771     updateTextStyles(childId, childStyle, listReadStyles, idToChildIpMap, seens);
772   }
773 }
774 
updateTextStyles(int tId,MWAWFont & font,MWAWParagraph & para,MWAWSection & section,double totalWidth) const775 bool RagTime5StyleManager::updateTextStyles(int tId, MWAWFont &font, MWAWParagraph &para, MWAWSection &section, double totalWidth) const
776 {
777   font=MWAWFont();
778   para=MWAWParagraph();
779   section=MWAWSection();
780 
781   if (tId<=0 || tId>=static_cast<int>(m_state->m_textStyleList.size())) {
782     MWAW_DEBUG_MSG(("RagTime5StyleManager::updateTextStyles: can not find text style %d\n", tId));
783     return false;
784   }
785   auto const &style=m_state->m_textStyleList[size_t(tId)];
786   if (style.m_fontId>0) font.setId(style.m_fontId);
787   if (style.m_fontSize>0) font.setSize(float(style.m_fontSize));
788 
789   MWAWFont::Line underline(MWAWFont::Line::None);
790   uint32_t flag=style.m_fontFlags[0];
791   uint32_t flags=0;
792   if (flag&0x1) flags |= MWAWFont::boldBit;
793   if (flag&0x2) flags |= MWAWFont::italicBit;
794   if (flag&0x4) font.setUnderlineStyle(MWAWFont::Line::Simple); // checkme
795   if (flag&0x8) flags |= MWAWFont::embossBit;
796   if (flag&0x10) flags |= MWAWFont::shadowBit;
797 
798   if (flag&0x200) font.setStrikeOutStyle(MWAWFont::Line::Simple);
799   if (flag&0x400) flags |= MWAWFont::smallCapsBit;
800   // flag&0x800: kumorarya
801   if (flag&0x2000)
802     underline.m_word=true;
803   switch (style.m_caps) {
804   case 1:
805     flags |= MWAWFont::uppercaseBit;
806     break;
807   case 2:
808     flags |= MWAWFont::lowercaseBit;
809     break;
810   case 3:
811     flags |= MWAWFont::initialcaseBit;
812     break;
813   default:
814     break;
815   }
816   switch (style.m_underline) {
817   case 1:
818     underline.m_style=MWAWFont::Line::Simple;
819     font.setUnderline(underline);
820     break;
821   case 2:
822     underline.m_style=MWAWFont::Line::Simple;
823     underline.m_type=MWAWFont::Line::Double;
824     font.setUnderline(underline);
825     break;
826   default:
827     break;
828   }
829   if (style.m_letterSpacings[0]>0 || style.m_letterSpacings[0]<0)
830     font.setDeltaLetterSpacing(float(1+style.m_letterSpacings[0]), librevenge::RVNG_PERCENT);
831   if (style.m_widthStreching>0)
832     font.setWidthStreching(float(style.m_widthStreching));
833   if (style.m_scriptPosition.isSet() || style.m_fontScaling>=0) {
834     float scaling=style.m_fontScaling>0 ? style.m_fontScaling : 1;
835     font.set(MWAWFont::Script(*style.m_scriptPosition*100,librevenge::RVNG_PERCENT,int(scaling*100)));
836   }
837   if (style.m_language>0) {
838     std::string lang=TextStyle::getLanguageLocale(style.m_language);
839     if (!lang.empty())
840       font.setLanguage(lang);
841   }
842   font.setFlags(flags);
843   MWAWColor color;
844   if (style.m_graphStyleId>0 && getLineColor(style.m_graphStyleId, color))
845     font.setColor(color);
846 
847   //
848   // para
849   //
850   if (style.m_keepWithNext.isSet() && *style.m_keepWithNext)
851     para.m_breakStatus = para.m_breakStatus.get()|MWAWParagraph::NoBreakWithNextBit;
852   switch (style.m_justify) {
853   case 0:
854     break;
855   case 1:
856     para.m_justify = MWAWParagraph::JustificationCenter;
857     break;
858   case 2:
859     para.m_justify = MWAWParagraph::JustificationRight ;
860     break;
861   case 3:
862     para.m_justify = MWAWParagraph::JustificationFull;
863     break;
864   case 4:
865     para.m_justify = MWAWParagraph::JustificationFullAllLines;
866     break;
867   default:
868     break;
869   }
870   // TODO: use style.m_breakMethod
871   para.m_marginsUnit=librevenge::RVNG_POINT;
872   for (int i=0; i<3; ++i) {
873     if (style.m_margins[i]<0) continue;
874     if (i==2)
875       para.m_margins[0]=style.m_margins[2]-*para.m_margins[1];
876     else
877       para.m_margins[i+1] = style.m_margins[i];
878   }
879   if (style.m_spacings[0]>0) {
880     if (style.m_spacingUnits[0]==0)
881       para.setInterline(style.m_spacings[0], librevenge::RVNG_PERCENT);
882     else if (style.m_spacingUnits[0]==1)
883       para.setInterline(style.m_spacings[0], librevenge::RVNG_POINT);
884   }
885   for (int i=1; i<3; ++i) {
886     if (style.m_spacings[i]<0) continue;
887     if (style.m_spacingUnits[i]==0)
888       para.m_spacings[i]=style.m_spacings[i]*12./72.;
889     else if (style.m_spacingUnits[0]==1)
890       para.m_spacings[i]=style.m_spacings[i]/72.;
891   }
892   // tabs stop
893   for (auto const &tab : style.m_tabList) {
894     MWAWTabStop newTab;
895     newTab.m_position = double(tab.m_position)/72.;
896     switch (tab.m_type) {
897     case 2:
898     case 5: // kintou waritsuke
899       newTab.m_alignment = MWAWTabStop::CENTER;
900       break;
901     case 3:
902       newTab.m_alignment = MWAWTabStop::RIGHT;
903       break;
904     case 4:
905       newTab.m_alignment = MWAWTabStop::DECIMAL;
906       break;
907     case 1: // left
908     default:
909       break;
910     }
911     newTab.m_leaderCharacter=tab.m_leaderChar;
912     para.m_tabs->push_back(newTab);
913   }
914   if (totalWidth>0 && style.m_numColumns>1)
915     section.setColumns(style.m_numColumns, totalWidth/double(style.m_numColumns), librevenge::RVNG_POINT, style.m_columnGap>0 ? style.m_columnGap/72. : 0.05);
916   return true;
917 }
918 
readFormats(RagTime5ClusterManager::Cluster & cluster)919 bool RagTime5StyleManager::readFormats(RagTime5ClusterManager::Cluster &cluster)
920 {
921   RagTime5ClusterManager::Link const &link=cluster.m_dataLink;
922   if (link.m_ids.size()<2 || !link.m_ids[1])
923     return false;
924 
925   std::map<int, librevenge::RVNGString> idToNameMap;
926   if (!cluster.m_nameLink.empty()) {
927     m_document.readUnicodeStringList(cluster.m_nameLink, idToNameMap);
928     cluster.m_nameLink=RagTime5ClusterManager::NameLink();
929   }
930   std::vector<long> decal;
931   if (link.m_ids[0])
932     m_document.readPositions(link.m_ids[0], decal);
933   if (decal.empty())
934     decal=link.m_longList;
935   int const dataId=link.m_ids[1];
936   auto dataZone=m_document.getDataZone(dataId);
937   auto N=int(decal.size());
938 
939   if (!dataZone || !dataZone->m_entry.valid() ||
940       dataZone->getKindLastPart(dataZone->m_kinds[1].empty())!="ItemData" || N<=1) {
941     if (N==1 && dataZone && !dataZone->m_entry.valid()) {
942       // a zone with 0 zone is ok...
943       dataZone->m_isParsed=true;
944       return true;
945     }
946     MWAW_DEBUG_MSG(("RagTime5StyleManager::readFormats: the data zone %d seems bad\n", dataId));
947     return false;
948   }
949 
950   dataZone->m_isParsed=true;
951   MWAWEntry entry=dataZone->m_entry;
952   libmwaw::DebugFile &ascFile=dataZone->ascii();
953   libmwaw::DebugStream f;
954   f << "Entries(FormatDef)[" << *dataZone << "]:";
955   ascFile.addPos(entry.end());
956   ascFile.addNote("_");
957   ascFile.addPos(entry.begin());
958   ascFile.addNote(f.str().c_str());
959 
960   MWAWInputStreamPtr input=dataZone->getInput();
961   input->setReadInverted(!dataZone->m_hiLoEndian);
962   long debPos=entry.begin();
963   long endPos=entry.end();
964   if (!input->checkPosition(endPos)) {
965     MWAW_DEBUG_MSG(("RagTime5StyleManager::readFormats:bad endPos\n"));
966     return false;
967   }
968   m_state->m_formatList.resize(size_t(N ? N-1 : 0));
969   for (int i=1; i<N; ++i) {
970     long pos=debPos+decal[size_t(i-1)], endDPos=debPos+decal[size_t(i)];
971     if (pos==endDPos) continue;
972     if (pos<debPos || endDPos>endPos || endDPos-pos<4) {
973       MWAW_DEBUG_MSG(("RagTime5StyleManager::readFormats: can not read the data zone %d-%d seems bad\n", dataId, i));
974       continue;
975     }
976     input->seek(pos, librevenge::RVNG_SEEK_SET);
977     f.str("");
978     f << "FormatDef-Fo" << i << ":";
979     auto val=static_cast<int>(input->readLong(4));
980     if (val) f << "num[used]=" << val << ",";
981     if (endDPos-pos<10) {
982       if (endDPos!=pos+4) f << "###";
983       ascFile.addPos(pos);
984       ascFile.addNote(f.str().c_str());
985       continue;
986     }
987     auto nId=static_cast<int>(input->readLong(2));
988     if (idToNameMap.find(i)!=idToNameMap.end())
989       f << "\"" << idToNameMap.find(i)->second.cstr() << "\",";
990     else {
991       MWAW_DEBUG_MSG(("RagTime5StyleManager::readFormats: can not find the format name for zone %d\n", dataId));
992       f << "###name[id]=" << nId << ",";
993     }
994     auto numFormat=static_cast<int>(input->readLong(1));
995     if (numFormat!=1)
996       f << "numFormat=" << numFormat << ",";
997     auto type=static_cast<int>(input->readLong(1)); // 6, 10 abd one time 4(slide number) and 14(unknown)
998     if (type==10) f << "dateTime,";
999     else if (type!=6) f << "#type=" << type << ",";
1000     for (int fo=0; fo<numFormat; ++fo) {
1001       MWAWCell::Format format;
1002       f << "form" << fo << "=[";
1003       auto type2=static_cast<int>(input->readULong(1));
1004       bool isDateTime=false, isMoneyThousand=false, isCurrency=false;
1005       switch (type2) {
1006       case 0:
1007         f << "general,";
1008         format.m_format=MWAWCell::F_NUMBER;
1009         format.m_numberFormat=MWAWCell::F_NUMBER_GENERIC;
1010         break;
1011       case 1: // number normal
1012         format.m_format=MWAWCell::F_NUMBER;
1013         format.m_numberFormat=MWAWCell::F_NUMBER_DECIMAL;
1014         break;
1015       case 4:
1016         f << "money/thousand,";
1017         format.m_format=MWAWCell::F_NUMBER;
1018         format.m_numberFormat=MWAWCell::F_NUMBER_DECIMAL;
1019         isMoneyThousand=true;
1020         break;
1021       default:
1022         isDateTime=true;
1023         format.m_format=MWAWCell::F_DATE; // or time
1024         if (type2&0x80) f << "%a";
1025         if (type2&0x40) f << "%y";
1026         if (type2&0x20) f << "%m";
1027         if (type2&8) f << "%d";
1028         if (type2&4) f << "%H";
1029         if (type2&2) f << "%M";
1030         if (type2&1) f << "%S";
1031         if (type2&0x10)
1032           f << "#type2[high]";
1033         f << ",";
1034         break;
1035       }
1036       val=static_cast<int>(input->readULong(1));
1037       if (val) f << "num[decim]=" << val << ",";
1038       if (format.m_format==MWAWCell::F_NUMBER && format.m_numberFormat!=MWAWCell::F_NUMBER_GENERIC)
1039         format.m_digits=val;
1040       for (int j=0; j<4; ++j) {
1041         val=static_cast<int>(input->readULong(1));
1042         if (val) f << "fl" << j << "=" << std::hex << val << std::dec << ",";
1043       }
1044       auto fSz=static_cast<int>(input->readULong(1));
1045       if (input->tell()+fSz>endDPos) {
1046         MWAW_DEBUG_MSG(("RagTime5StyleManager::readFormats: can not read the string format zone %d\n", dataId));
1047         f << "###fSz=" << fSz << ",";
1048         break;
1049       }
1050       f << "format=\"";
1051       for (int j=0; j<fSz; ++j) {
1052         val=static_cast<int>(input->readULong(1));
1053         if (isMoneyThousand && val!=2 && val!=3 && val!=5 && !isCurrency)
1054           isCurrency=true;
1055         switch (val) {
1056         case 1: // general digit
1057           f << "*";
1058           break;
1059         case 2: // decimal digit
1060           f << "0";
1061           break;
1062         case 3: // potential digit (ie. diese)
1063           f << "1";
1064           break;
1065         case 5: // commas
1066           f << ".";
1067           if (isDateTime)
1068             format.m_DTFormat.append(".");
1069           break;
1070         case 6:
1071           if (isDateTime)
1072             format.m_DTFormat.append("%y");
1073           f << "%y";
1074           break;
1075         case 7: // year or fraction
1076           if (isDateTime) {
1077             format.m_DTFormat.append("%Y");
1078             f << "%Y";
1079             break;
1080           }
1081           f << "/";
1082           if (format.m_format==MWAWCell::F_NUMBER && format.m_numberFormat==MWAWCell::F_NUMBER_DECIMAL)
1083             format.m_numberFormat=MWAWCell::F_NUMBER_FRACTION;
1084           break;
1085         case 8:
1086           if (isDateTime)
1087             format.m_DTFormat.append("%m");
1088           f << "%m";
1089           break;
1090         case 9: // month with two digits
1091           if (isDateTime)
1092             format.m_DTFormat.append("%m");
1093           f << "%0m";
1094           break;
1095         case 0xa: // month abbrev or exponant
1096           if (isDateTime) {
1097             format.m_DTFormat.append("%b");
1098             f << "%b";
1099             break;
1100           }
1101           f << "e";
1102           if (format.m_format==MWAWCell::F_NUMBER && format.m_numberFormat==MWAWCell::F_NUMBER_DECIMAL)
1103             format.m_numberFormat=MWAWCell::F_NUMBER_SCIENTIFIC;
1104           break;
1105         case 0xb: // month
1106           if (isDateTime)
1107             format.m_DTFormat.append("%B");
1108           f << "%B";
1109           break;
1110         case 0xc: // day or percent
1111           if (isDateTime) {
1112             format.m_DTFormat.append("%d");
1113             f << "%d";
1114             break;
1115           }
1116           f << "%";
1117           if (format.m_format==MWAWCell::F_NUMBER && format.m_numberFormat==MWAWCell::F_NUMBER_DECIMAL)
1118             format.m_numberFormat=MWAWCell::F_NUMBER_PERCENT;
1119           break;
1120         case 0xd: // day 2 digits
1121           if (isDateTime)
1122             format.m_DTFormat.append("%d");
1123           f << "%0d";
1124           break;
1125         case 0xe: // checkme
1126           if (isDateTime)
1127             format.m_DTFormat.append("%a");
1128           f << "%a";
1129           break;
1130         case 0xf:
1131           if (isDateTime)
1132             format.m_DTFormat.append("%A");
1133           f << "%A";
1134           break;
1135         case 0x10: // pm (precedeed by c0)
1136           if (isDateTime)
1137             format.m_DTFormat.append("%p");
1138           f << "%p";
1139           break;
1140         case 0x14: // hour
1141           if (isDateTime)
1142             format.m_DTFormat.append("%H");
1143           f << "%0H";
1144           break;
1145         case 0x15:
1146           if (isDateTime)
1147             format.m_DTFormat.append("%H");
1148           f << "%H";
1149           break;
1150         case 0x16:
1151           if (isDateTime)
1152             format.m_DTFormat.append("%M");
1153           f << "%0M";
1154           break;
1155         case 0x17: // minute
1156           if (isDateTime)
1157             format.m_DTFormat.append("%M");
1158           f << "%M";
1159           break;
1160         case 0x19: // second
1161           if (isDateTime)
1162             format.m_DTFormat.append("%S");
1163           f << "%S";
1164           break;
1165         case 0x1f:
1166           if (isDateTime)
1167             format.m_DTFormat.append("%p");
1168           f << "%p";
1169           break;
1170         case 0xa3: // pound symbol
1171           f << "[pound]";
1172           break;
1173         case 0xc0: // pm/am condition?
1174           if (j+1>=fSz) {
1175             f << "[##c0]";
1176             break;
1177           }
1178           break;
1179         case 0xfd: // parenthesis delimiter ?
1180           if (j+1>=fSz) {
1181             f << "[##fd]";
1182             break;
1183           }
1184           ++j;
1185           input->seek(1, librevenge::RVNG_SEEK_CUR);
1186           break;
1187         case 0xff: // unicode
1188           if (j+2>=fSz) {
1189             f << "[##ff]";
1190             break;
1191           }
1192           j+=2;
1193           f << "[U" << std::hex << input->readULong(2) << std::dec << "]";
1194           break;
1195         default:
1196           if (val>=0x20 && val<0x80) {
1197             f << char(val);
1198             if (isDateTime)
1199               format.m_DTFormat+=char(val);
1200             else if (format.m_format==MWAWCell::F_NUMBER && val=='(')
1201               format.m_parenthesesForNegative=true;
1202           }
1203           else
1204             f << "[#" << std::hex << val << std::dec << "]";
1205           break;
1206         }
1207       }
1208       f << "\",";
1209       f << "],";
1210       if (isCurrency)
1211         format.m_numberFormat=MWAWCell::F_NUMBER_CURRENCY;
1212       else if (isMoneyThousand)
1213         format.m_thousandHasSeparator=true;
1214       if (fo==0)
1215         m_state->m_formatList[size_t(i-1)]=format;
1216     }
1217     f << "],";
1218 
1219     if (input->tell()!=endDPos)
1220       ascFile.addDelimiter(input->tell(),'|');
1221     ascFile.addPos(pos);
1222     ascFile.addNote(f.str().c_str());
1223   }
1224 
1225   input->setReadInverted(false);
1226 
1227   for (auto lnk : cluster.m_linksList) {
1228     lnk.m_name=std::string("FormatUnkn")+(lnk.m_fileType[0]==0x3e800 ? "A" : lnk.m_fileType[0]==0x35800 ? "B" : lnk.getZoneName().c_str());
1229     if (lnk.m_fileType[0]==0x3e800 || lnk.m_fileType[0]==0x35800) {
1230       /* rare only find in two files,
1231         FormA: list of 0 or small int: next list?,
1232         FormB: list of 0, 80000000 or small int: prev list ?
1233         when the value are small ints, FormB(FormA(val)+1)=val
1234       */
1235       std::vector<long> data;
1236       m_document.readLongList(lnk, data);
1237     }
1238     else
1239       m_document.readFixedSizeZone(lnk, lnk.m_name);
1240   }
1241 
1242   return true;
1243 }
1244 
updateCellFormat(int formatId,MWAWCell & cell) const1245 bool RagTime5StyleManager::updateCellFormat(int formatId, MWAWCell &cell) const
1246 {
1247   if (formatId<=0 || formatId>static_cast<int>(m_state->m_formatList.size())) {
1248     MWAW_DEBUG_MSG(("RagTime5StyleManager::updateCellFormat: can not find format %d\n", formatId));
1249     return false;
1250   }
1251   auto format=m_state->m_formatList[size_t(formatId-1)];
1252   auto cellType=cell.getFormat().m_format;
1253   if (cellType==format.m_format && (cellType==MWAWCell::F_NUMBER || cellType==MWAWCell::F_DATE))
1254     cell.setFormat(format);
1255   else if (cellType==MWAWCell::F_TIME && format.m_format==MWAWCell::F_DATE) {
1256     format.m_format=MWAWCell::F_TIME;
1257     cell.setFormat(format);
1258   }
1259   return true;
1260 }
1261 
1262 ////////////////////////////////////////////////////////////
1263 // parse cluster
1264 ////////////////////////////////////////////////////////////
1265 
1266 //
1267 // graphic style
1268 //
~GraphicStyle()1269 RagTime5StyleManager::GraphicStyle::~GraphicStyle()
1270 {
1271 }
1272 
read(MWAWInputStreamPtr & input,RagTime5StructManager::Field const & field,std::vector<MWAWColor> const & colorList)1273 bool RagTime5StyleManager::GraphicStyle::read(MWAWInputStreamPtr &input, RagTime5StructManager::Field const &field, std::vector<MWAWColor> const &colorList)
1274 {
1275   std::stringstream s;
1276   if (field.m_type==RagTime5StructManager::Field::T_Long) { // header
1277     switch (field.m_fileType) {
1278     case 0x148c042: // -2<->8
1279       if (field.m_longValue[0])
1280         s << "H" << RagTime5StyleManager::printType(field.m_fileType) << "=" << field.m_longValue[0] << ",";
1281       else
1282         s << "H" << RagTime5StyleManager::printType(field.m_fileType) << ",";
1283       m_extra+=s.str();
1284       return true;
1285     case 0x1460042: // -3-23
1286       s << "lineStyle,";
1287       if (field.m_longValue[0]!=-3)
1288         s << "pId?=" << field.m_longValue[0] << ",";
1289       m_extra += s.str();
1290       return true;
1291     case 0x145e042: // -2<->24 : fill style CHECKME related to parent id?
1292     case 0x1489842: // -2<->19
1293       m_parentId=static_cast<int>(field.m_longValue[0]);
1294       return true;
1295     default:
1296       return false;
1297     }
1298   }
1299   else if (field.m_type==RagTime5StructManager::Field::T_FieldList) {
1300     switch (field.m_fileType) {
1301     case 0x7d02a:
1302     case 0x145e05a: {
1303       int wh=field.m_fileType==0x7d02a ? 0 : 1;
1304       for (auto const &child : field.m_fieldList) {
1305         if (child.m_type==RagTime5StructManager::Field::T_Color && child.m_fileType==0x84040) {
1306           if (child.m_longValue[0]==50) {
1307             if (!updateColor(field.m_fileType==0x7d02a, int(child.m_longValue[1])+1, colorList)) {
1308               MWAW_DEBUG_MSG(("RagTime5StyleManager::GraphicStyle::read: find some unknown color %ld block\n", child.m_longValue[1]+1));
1309               s << "###";
1310             }
1311             s << "col=GC" << child.m_longValue[1]+1 << ",";
1312             continue;
1313           }
1314           m_colors[wh]=child.m_color;
1315           m_colorsAlpha[wh]=1; // checkme
1316           continue;
1317         }
1318         MWAW_DEBUG_MSG(("RagTime5StyleManager::GraphicStyle::read: find some unknown color %d block\n", wh));
1319         s << "##col[" << wh << "]=" << child << ",";
1320       }
1321       m_extra+=s.str();
1322       return true;
1323     }
1324     case 0x145e02a:
1325     case 0x145e0ea: {
1326       int wh=field.m_fileType==0x145e02a ? 0 : 1;
1327       for (auto const &child : field.m_fieldList) {
1328         if (child.m_type==RagTime5StructManager::Field::T_Double && child.m_fileType==0xb6000) {
1329           m_colorsAlpha[wh]=float(child.m_doubleValue);
1330           continue;
1331         }
1332         MWAW_DEBUG_MSG(("RagTime5StyleManager::GraphicStyle::read: find some unknown colorAlpha[%d] block\n", wh));
1333         s << "###colorAlpha[" << wh << "]=" << child << ",";
1334       }
1335       m_extra+=s.str();
1336       return true;
1337     }
1338     case 0x145e01a: {
1339       for (auto const &child : field.m_fieldList) {
1340         if (child.m_type==RagTime5StructManager::Field::T_Long && child.m_fileType==0x147c080) {
1341           if (m_parentId>-1000) {
1342             MWAW_DEBUG_MSG(("RagTime5StyleManager::GraphicStyle::read: parent id is already set\n"));
1343             s << "###newParentId,";
1344           }
1345           m_parentId=static_cast<int>(child.m_longValue[0]);
1346           continue;
1347         }
1348         MWAW_DEBUG_MSG(("RagTime5StyleManager::GraphicStyle::read: find some unknown parent block\n"));
1349         s << "###parent=" << child << ",";
1350       }
1351       m_extra+=s.str();
1352       return true;
1353     }
1354     case 0x7d04a:
1355       for (auto  const &child : field.m_fieldList) {
1356         if (child.m_type==RagTime5StructManager::Field::T_Double && child.m_fileType==0x1494800) {
1357           m_width=float(child.m_doubleValue);
1358           continue;
1359         }
1360         MWAW_DEBUG_MSG(("RagTime5StyleManager::GraphicStyle::read: find some unknown width block\n"));
1361         s << "###w=" << child << ",";
1362       }
1363       m_extra+=s.str();
1364       return true;
1365     case 0x145e0ba: {
1366       for (auto const &child : field.m_fieldList) {
1367         if (child.m_type==RagTime5StructManager::Field::T_Bool && child.m_fileType==0x360c0) {
1368           m_hidden=child.m_longValue[0]!=0;
1369           continue;
1370         }
1371         MWAW_DEBUG_MSG(("RagTime5StyleManager::GraphicStyle::read: find some unknown no print block\n"));
1372         s << "###hidden=" << child << ",";
1373       }
1374       m_extra+=s.str();
1375       return true;
1376     }
1377 
1378     case 0x14600ca:
1379       for (auto const &child : field.m_fieldList) {
1380         if (child.m_type==RagTime5StructManager::Field::T_LongList && child.m_fileType==(unsigned long)(long(0x80033000))) {
1381           m_dash=child.m_longList;
1382           continue;
1383         }
1384         MWAW_DEBUG_MSG(("RagTime5StyleManager::GraphicStyle::read: find some unknown dash block\n"));
1385         s << "###dash=" << child << ",";
1386       }
1387       m_extra+=s.str();
1388       return true;
1389     case 0x146005a:
1390       for (auto const &child : field.m_fieldList) {
1391         if (child.m_type==RagTime5StructManager::Field::T_Code && child.m_fileType==0x8d000) {
1392           if (child.m_string=="LiOu")
1393             m_position=3;
1394           else if (child.m_string=="LiCe") // checkme
1395             m_position=2;
1396           else if (child.m_string=="LiIn")
1397             m_position=1;
1398           else if (child.m_string=="LiRo")
1399             m_position=4;
1400           else {
1401             MWAW_DEBUG_MSG(("RagTime5StyleManager::GraphicStyle::read: find some unknown position string %s\n", child.m_string.cstr()));
1402             s << "##pos=" << child.m_string.cstr() << ",";
1403           }
1404           continue;
1405         }
1406         MWAW_DEBUG_MSG(("RagTime5StyleManager::GraphicStyle::read: find some unknown position block\n"));
1407         s << "###pos=" << child << ",";
1408       }
1409       m_extra+=s.str();
1410       return true;
1411     case 0x146007a:
1412       for (auto const &child : field.m_fieldList) {
1413         if (child.m_type==RagTime5StructManager::Field::T_Code && child.m_fileType==0x8d000) {
1414           if (child.m_string=="LiRo")
1415             m_mitter=2;
1416           else if (child.m_string=="LiBe")
1417             m_mitter=3;
1418           else {
1419             MWAW_DEBUG_MSG(("RagTime5StyleManager::GraphicStyle::read: find some unknown mitter string %s\n", child.m_string.cstr()));
1420             s << "##mitter=" << child.m_string.cstr() << ",";
1421           }
1422           continue;
1423         }
1424         MWAW_DEBUG_MSG(("RagTime5StyleManager::GraphicStyle::read: find some unknown mitter block\n"));
1425         s << "###mitter=" << child << ",";
1426       }
1427       m_extra+=s.str();
1428       return true;
1429     case 0x148981a:
1430       for (auto const &child : field.m_fieldList) {
1431         if (child.m_type==RagTime5StructManager::Field::T_Code && child.m_fileType==0x8d000) {
1432           if (child.m_string=="GrNo")
1433             m_gradient=1;
1434           else if (child.m_string=="GrRa")
1435             m_gradient=2;
1436           else {
1437             MWAW_DEBUG_MSG(("RagTime5StyleManager::GraphicStyle::read: find some unknown gradient string %s\n", child.m_string.cstr()));
1438             s << "##gradient=" << child.m_string.cstr() << ",";
1439           }
1440           continue;
1441         }
1442         MWAW_DEBUG_MSG(("RagTime5StyleManager::GraphicStyle::read: find some unknown gradient block\n"));
1443         s << "###gradient=" << child << ",";
1444       }
1445       m_extra+=s.str();
1446       return true;
1447     case 0x14600aa:
1448       for (auto const &child : field.m_fieldList) {
1449         if (child.m_type==RagTime5StructManager::Field::T_Code && child.m_fileType==0x8d000) {
1450           if (child.m_string=="CaRo")
1451             m_cap=2;
1452           else if (child.m_string=="CaSq")
1453             m_cap=3;
1454           else {
1455             MWAW_DEBUG_MSG(("RagTime5StyleManager::GraphicStyle::read: find some unknown cap string %s\n", child.m_string.cstr()));
1456             s << "##cap=" << child.m_string.cstr() << ",";
1457           }
1458           continue;
1459         }
1460         MWAW_DEBUG_MSG(("RagTime5StyleManager::GraphicStyle::read: find some unknown cap block\n"));
1461         s << "###cap=" << child << ",";
1462       }
1463       m_extra+=s.str();
1464       return true;
1465     case 0x148985a: // checkme
1466       for (auto const &child : field.m_fieldList) {
1467         if (child.m_type==RagTime5StructManager::Field::T_Double && child.m_fileType==0x1495800) {
1468           m_gradientRotation=float(360*child.m_doubleValue);
1469           continue;
1470         }
1471         MWAW_DEBUG_MSG(("RagTime5StyleManager::GraphicStyle::read: find some unknown grad rotation block\n"));
1472         s << "###rot[grad]=" << child << ",";
1473       }
1474       m_extra+=s.str();
1475       return true;
1476     case 0x148983a: // checkme
1477       for (auto const &child : field.m_fieldList) {
1478         if (child.m_type==RagTime5StructManager::Field::T_DoubleList && child.m_doubleList.size()==2 && child.m_fileType==0x74040) {
1479           m_gradientCenter=MWAWVec2f(float(child.m_doubleList[0]), float(child.m_doubleList[1]));
1480           continue;
1481         }
1482         MWAW_DEBUG_MSG(("RagTime5StyleManager::GraphicStyle::read: find some unknown grad center block\n"));
1483         s << "###rot[center]=" << child << ",";
1484       }
1485       m_extra+=s.str();
1486       return true;
1487     case 0x146008a:
1488       for (auto const &child : field.m_fieldList) {
1489         if (child.m_type==RagTime5StructManager::Field::T_Double && child.m_fileType==0xb6000) {
1490           m_limitPercent=float(child.m_doubleValue);
1491           continue;
1492         }
1493         MWAW_DEBUG_MSG(("RagTime5StyleManager::GraphicStyle::read: find some unknown limit percent block\n"));
1494         s << "###limitPercent=" << child << ",";
1495       }
1496       m_extra+=s.str();
1497       return true;
1498     // unknown small id
1499     case 0x145e11a: // frequent
1500     case 0x145e12a: {  // unknown small int 2|3
1501       for (auto const &child : field.m_fieldList) {
1502         if (child.m_type==RagTime5StructManager::Field::T_Long && child.m_fileType==0x17d5880) {
1503           if (!updateColor(field.m_fileType==0x145e11a, int(child.m_longValue[0]), colorList)) {
1504             MWAW_DEBUG_MSG(("RagTime5StyleManager::GraphicStyle::read: find some unknown color %ld block\n", child.m_longValue[0]));
1505             s << "###";
1506           }
1507           s << "col=GC" << child.m_longValue[0] << ",";
1508           continue;
1509         }
1510         MWAW_DEBUG_MSG(("RagTime5StyleManager::GraphicStyle::read: find some unknown unkn0 block\n"));
1511         s << "###unkn0=" << child << ",";
1512       }
1513       m_extra+=s.str();
1514       return true;
1515     }
1516     default:
1517       break;
1518     }
1519   }
1520   else if (field.m_type==RagTime5StructManager::Field::T_Unstructured) {
1521     switch (field.m_fileType) {
1522     case 0x148c01a: {
1523       if (field.m_entry.length()!=12) {
1524         MWAW_DEBUG_MSG(("RagTime5StyleManager::GraphicStyle::read: find some odd size for pattern\n"));
1525         s << "##pattern=" << field << ",";
1526         m_extra+=s.str();
1527         return true;
1528       }
1529       input->seek(field.m_entry.begin(), librevenge::RVNG_SEEK_SET);
1530       for (int i=0; i<2; ++i) {
1531         static int const expected[]= {0xb, 0x40};
1532         auto val=static_cast<int>(input->readULong(2));
1533         if (val!=expected[i])
1534           s << "pat" << i << "=" << std::hex << val << std::dec << ",";
1535       }
1536       m_pattern.reset(new MWAWGraphicStyle::Pattern);
1537       m_pattern->m_colors[0]=MWAWColor::white();
1538       m_pattern->m_colors[1]=MWAWColor::black();
1539       m_pattern->m_dim=MWAWVec2i(8,8);
1540       m_pattern->m_data.resize(8);
1541       for (auto &data : m_pattern->m_data) data=static_cast<unsigned char>(input->readULong(1));
1542       m_extra+=s.str();
1543       return true;
1544     }
1545     default:
1546       break;
1547     }
1548   }
1549   return false;
1550 }
1551 
updateColor(bool first,int colorId,std::vector<MWAWColor> const & colorList)1552 bool RagTime5StyleManager::GraphicStyle::updateColor(bool first, int colorId, std::vector<MWAWColor> const &colorList)
1553 {
1554   if (colorId>=1 && colorId <= int(colorList.size())) {
1555     auto const &color=colorList[size_t(colorId-1)];
1556     m_colors[first ? 0 : 1]=color;
1557     if (color.getAlpha()<255)
1558       m_colorsAlpha[first ? 0 : 1]=float(color.getAlpha())/255.f;
1559     return true;
1560   }
1561   return false;
1562 }
1563 
insert(RagTime5StyleManager::GraphicStyle const & childStyle)1564 void RagTime5StyleManager::GraphicStyle::insert(RagTime5StyleManager::GraphicStyle const &childStyle)
1565 {
1566   if (childStyle.m_width>=0) m_width=childStyle.m_width;
1567   bool updateCol=true;
1568   if (childStyle.m_dash.isSet()) m_dash=childStyle.m_dash;
1569   if (childStyle.m_pattern) m_pattern=childStyle.m_pattern;
1570   if (childStyle.m_gradient>=0) m_gradient=childStyle.m_gradient;
1571   else if (m_gradient==1) updateCol=false; // we need to use the gradient color
1572   if (childStyle.m_gradientRotation>-1000) m_gradientRotation=childStyle.m_gradientRotation;
1573   if (childStyle.m_gradientCenter.isSet()) m_gradientCenter=childStyle.m_gradientCenter;
1574   if (childStyle.m_position>=0) m_position=childStyle.m_position;
1575   if (childStyle.m_cap>=0) m_cap=childStyle.m_cap;
1576   if (childStyle.m_mitter>=0) m_mitter=childStyle.m_mitter;
1577   if (childStyle.m_limitPercent>=0) m_limitPercent=childStyle.m_limitPercent;
1578   if (childStyle.m_hidden.isSet()) m_hidden=childStyle.m_hidden;
1579   if (updateCol) {
1580     if (childStyle.m_colors[0].isSet()) m_colors[0]=*childStyle.m_colors[0];
1581     if (childStyle.m_colors[1].isSet()) m_colors[1]=*childStyle.m_colors[1];
1582     for (int i=0; i<2; ++i) {
1583       if (childStyle.m_colorsAlpha[i]>=0)
1584         m_colorsAlpha[i]=childStyle.m_colorsAlpha[i];
1585     }
1586   }
1587   m_extra+=childStyle.m_extra;
1588 }
1589 
operator <<(std::ostream & o,RagTime5StyleManager::GraphicStyle const & style)1590 std::ostream &operator<<(std::ostream &o, RagTime5StyleManager::GraphicStyle const &style)
1591 {
1592   if (style.m_parentId>-1000) {
1593     if (style.m_parentId<0)
1594       o << "parent=def" << -style.m_parentId << ",";
1595     else if (style.m_parentId)
1596       o << "parent=GS" << style.m_parentId << ",";
1597   }
1598   if (style.m_width>=0) o << "w=" << style.m_width << ",";
1599   if (style.m_colors[0].isSet()) o << "color0=" << *style.m_colors[0] << ",";
1600   if (style.m_colors[1].isSet()) o << "color1=" << *style.m_colors[1] << ",";
1601   for (int i=0; i<2; ++i) {
1602     if (style.m_colorsAlpha[i]>=0)
1603       o << "color" << i << "[alpha]=" << style.m_colorsAlpha[i] << ",";
1604   }
1605   if (style.m_dash.isSet()) {
1606     o << "dash=";
1607     for (auto dash : *style.m_dash)
1608       o << dash << ":";
1609     o << ",";
1610   }
1611   if (style.m_pattern)
1612     o << "pattern=[" << *style.m_pattern << "],";
1613   switch (style.m_gradient) {
1614   case -1:
1615     break;
1616   case 0:
1617     break;
1618   case 1:
1619     o << "grad[normal],";
1620     break;
1621   case 2:
1622     o << "grad[radial],";
1623     break;
1624   default:
1625     o<< "##gradient=" << style.m_gradient;
1626     break;
1627   }
1628   if (style.m_gradientRotation>-1000 && (style.m_gradientRotation<0 || style.m_gradientRotation>0))
1629     o << "rot[grad]=" << style.m_gradientRotation << ",";
1630   if (style.m_gradientCenter.isSet())
1631     o << "center[grad]=" << *style.m_gradientCenter << ",";
1632   switch (style.m_position) {
1633   case -1:
1634     break;
1635   case 1:
1636     o << "pos[inside],";
1637     break;
1638   case 2:
1639     break;
1640   case 3:
1641     o << "pos[outside],";
1642     break;
1643   case 4:
1644     o << "pos[round],";
1645     break;
1646   default:
1647     o << "#pos=" << style.m_position << ",";
1648     break;
1649   }
1650   switch (style.m_cap) {
1651   case -1:
1652     break;
1653   case 1: // triangle
1654     break;
1655   case 2:
1656     o << "cap[round],";
1657     break;
1658   case 3:
1659     o << "cap[square],";
1660     break;
1661   default:
1662     o << "#cap=" << style.m_cap << ",";
1663     break;
1664   }
1665   switch (style.m_mitter) {
1666   case -1:
1667     break;
1668   case 1: // no add
1669     break;
1670   case 2:
1671     o << "mitter[round],";
1672     break;
1673   case 3:
1674     o << "mitter[out],";
1675     break;
1676   default:
1677     o << "#mitter=" << style.m_mitter << ",";
1678     break;
1679   }
1680   if (style.m_limitPercent>=0 && style.m_limitPercent<1)
1681     o << "limit=" << 100*style.m_limitPercent << "%,";
1682   if (style.m_hidden.get())
1683     o << "hidden,";
1684   o << style.m_extra;
1685   return o;
1686 }
1687 
1688 //
1689 // text style
1690 //
~TextStyle()1691 RagTime5StyleManager::TextStyle::~TextStyle()
1692 {
1693 }
1694 
getLanguageLocale(int id)1695 std::string RagTime5StyleManager::TextStyle::getLanguageLocale(int id)
1696 {
1697   switch (id) {
1698   case 1:
1699     return "hr_HR";
1700   case 4:
1701     return "ru_RU";
1702   case 8:
1703     return "da_DK";
1704   case 9:
1705     return "sv_SE";
1706   case 0xa:
1707     return "nl_NL";
1708   case 0xb:
1709     return "fi_FI";
1710   case 0xc:
1711     return "it_IT";
1712   case 0xd: // initial accent
1713   case 0x800d:
1714     return "es_ES";
1715   case 0xf:
1716     return "gr_GR";
1717   case 0x11:
1718     return "ja_JP";
1719   case 0x16:
1720     return "tr_TR";
1721   case 0x4005:
1722   case 0x8005: // initial accent
1723     return "fr_FR";
1724   case 0x4006: // old?
1725   case 0x6006:
1726     return "de_CH";
1727   case 0x8006: // old?
1728   case 0xa006:
1729     return "de_DE";
1730   case 0x4007:
1731     return "en_GB";
1732   case 0x8007:
1733     return "en_US";
1734   case 0x400e:
1735     return "pt_BR";
1736   case 0x800e:
1737     return "pt_PT";
1738   case 0x4012:
1739     return "nn_NO";
1740   case 0x8012:
1741     return "no_NO";
1742   default:
1743     break;
1744   }
1745   return "";
1746 }
1747 
read(RagTime5StructManager::Field const & field)1748 bool RagTime5StyleManager::TextStyle::read(RagTime5StructManager::Field const &field)
1749 {
1750   std::stringstream s;
1751   if (field.m_type==RagTime5StructManager::Field::T_Long) { // header
1752     switch (field.m_fileType) {
1753     case 0: // one time with 0
1754       return true;
1755     case 0x1475042: // -3<->32 : ?
1756     case 0x147e842: // always 0?
1757     case 0x14b2042: // always 0?
1758       if (field.m_longValue[0])
1759         s << "H" << RagTime5StyleManager::printType(field.m_fileType) << "=" << field.m_longValue[0] << ",";
1760       else
1761         s << "H" << RagTime5StyleManager::printType(field.m_fileType) << ",";
1762       m_extra+=s.str();
1763       return true;
1764     case 0x1474042: // -1<->39 : CHECKME related to parent id?
1765       s << "parent[id]?=" << field.m_longValue[0] << ",";
1766       m_extra+=s.str();
1767       return true;
1768     default:
1769       return false;
1770     }
1771   }
1772   else if (field.m_type==RagTime5StructManager::Field::T_FieldList) {
1773     switch (field.m_fileType) {
1774     case 0x7a0aa: // style parent id?
1775     case 0x1474042: // main parent id?
1776     case 0x147551a: { // find one time with 3
1777       int wh=field.m_fileType==0x1474042 ? 0 : 1;
1778       for (auto const &child : field.m_fieldList) {
1779         if (child.m_type==RagTime5StructManager::Field::T_Long && child.m_fileType==0x1479080) {
1780           if (field.m_fileType==0x147551a)
1781             s << "unkn[pId]=" << child.m_longValue[0] << ",";
1782           else
1783             m_parentId[wh]=static_cast<int>(child.m_longValue[0]);
1784           continue;
1785         }
1786         MWAW_DEBUG_MSG(("RagTime5StyleManager::TextStyle::read: find some unknown parent id[%d] block\n", wh));
1787         s << "###parent" << wh << "[id]=" << child << ",";
1788       }
1789       m_extra+=s.str();
1790       return true;
1791     }
1792     case 0x14741fa:
1793       for (auto const &child : field.m_fieldList) {
1794         if (child.m_type==RagTime5StructManager::Field::T_LongList && child.m_fileType==(unsigned long)(long(0x80045080))) {
1795           for (auto val : child.m_longList)
1796             m_linkIdList.push_back(static_cast<int>(val));
1797           continue;
1798         }
1799         MWAW_DEBUG_MSG(("RagTime5StyleManager::TextStyle::read: find some unknown link id block\n"));
1800         s << "###link[id]=" << child << ",";
1801       }
1802       m_extra+=s.str();
1803       return true;
1804     case 0x1469840:
1805       for (auto const &child : field.m_fieldList) {
1806         if (child.m_type==RagTime5StructManager::Field::T_Long && child.m_fileType==0x147b880) {
1807           m_dateStyleId=static_cast<int>(child.m_longValue[0]);
1808           continue;
1809         }
1810         MWAW_DEBUG_MSG(("RagTime5StyleManager::TextStyle::read: find some unknown date style block\n"));
1811         s << "###date[id]=" << child << ",";
1812       }
1813       m_extra+=s.str();
1814       return true;
1815     case 0x145e01a:
1816     case 0x14741ea:
1817       for (auto const &child : field.m_fieldList) {
1818         if (child.m_type==RagTime5StructManager::Field::T_Long && child.m_fileType==0x147c080) {
1819           if (field.m_fileType==0x145e01a)
1820             m_graphStyleId=static_cast<int>(child.m_longValue[0]);
1821           else
1822             m_graphLineStyleId=static_cast<int>(child.m_longValue[0]);
1823           continue;
1824         }
1825         MWAW_DEBUG_MSG(("RagTime5StyleManager::TextStyle::read: find some unknown graphic style block\n"));
1826         s << "###graph[" << RagTime5StyleManager::printType(field.m_fileType) << "]=" << child << ",";
1827       }
1828       m_extra+=s.str();
1829       return true;
1830 
1831     //
1832     // para
1833     //
1834     case 0x14750ea:
1835       for (auto const &child : field.m_fieldList) {
1836         if (child.m_type==RagTime5StructManager::Field::T_Bool && child.m_fileType==0x360c0) {
1837           m_keepWithNext=child.m_longValue[0]!=0;
1838           continue;
1839         }
1840         MWAW_DEBUG_MSG(("RagTime5StyleManager::TextStyle::read: find some unknown keep with next block\n"));
1841         s << "###keep[withNext]=" << child << ",";
1842       }
1843       m_extra+=s.str();
1844       return true;
1845     case 0x147505a: // left margin
1846     case 0x147506a: // right margin
1847     case 0x147507a: { // first margin
1848       auto wh=int(((field.m_fileType&0xF0)>>4)-5);
1849       for (auto const &child : field.m_fieldList) {
1850         if (child.m_type==RagTime5StructManager::Field::T_Double && child.m_fileType==0x1493800) {
1851           m_margins[wh]=child.m_doubleValue;
1852           continue;
1853         }
1854         MWAW_DEBUG_MSG(("RagTime5StyleManager::TextStyle::read: find some unknown margins[%d] block\n", wh));
1855         s << "###margins[" << wh << "]=" << child << ",";
1856       }
1857       m_extra+=s.str();
1858       return true;
1859     }
1860     case 0x147501a:
1861       for (auto const &child : field.m_fieldList) {
1862         if (child.m_type==RagTime5StructManager::Field::T_Code && child.m_fileType==0x8d000) {
1863           if (child.m_string=="----") // checkme
1864             m_justify=-1;
1865           else if (child.m_string=="left")
1866             m_justify=0;
1867           else if (child.m_string=="cent")
1868             m_justify=1;
1869           else if (child.m_string=="rght")
1870             m_justify=2;
1871           else if (child.m_string=="full")
1872             m_justify=3;
1873           else if (child.m_string=="fful")
1874             m_justify=4;
1875           // find also thgr
1876           else {
1877             MWAW_DEBUG_MSG(("RagTime5StyleManager::TextStyle::read: find some justify block %s\n", child.m_string.cstr()));
1878             s << "##justify=" << child.m_string.cstr() << ",";
1879           }
1880           continue;
1881         }
1882         MWAW_DEBUG_MSG(("RagTime5StyleManager::TextStyle::read: find some unknown justify block\n"));
1883         s << "###justify=" << child << ",";
1884       }
1885       m_extra+=s.str();
1886       return true;
1887     case 0x147502a:
1888     case 0x14750aa:
1889     case 0x14750ba: {
1890       int wh=field.m_fileType==0x147502a ? 0 : field.m_fileType==0x14750aa ? 1 : 2;
1891       for (auto const &child : field.m_fieldList) {
1892         if (child.m_type==RagTime5StructManager::Field::T_LongDouble && child.m_fileType==0x149a940) {
1893           m_spacings[wh]=child.m_doubleValue;
1894           m_spacingUnits[wh]=static_cast<int>(child.m_longValue[0]);
1895           continue;
1896         }
1897         MWAW_DEBUG_MSG(("RagTime5StyleManager::TextStyle::read: find some unknown spacings %d block\n", wh));
1898         s << "###spacings[" << wh << "]=" << child << ",";
1899       }
1900       m_extra+=s.str();
1901       return true;
1902     }
1903     case 0x14752da:
1904     case 0x147536a:
1905     case 0x147538a: {
1906       int wh=field.m_fileType==0x14752da ? 0 : field.m_fileType==0x147536a ? 1 : 2;
1907       for (auto const &child : field.m_fieldList) {
1908         if (child.m_type==RagTime5StructManager::Field::T_Double && child.m_fileType==0x1495000) {
1909           s << "delta[" << (wh==0 ? "interline" : wh==1 ? "before" : "after") << "]=" << child.m_doubleValue << ",";
1910           continue;
1911         }
1912         MWAW_DEBUG_MSG(("RagTime5StyleManager::TextStyle::read: find some unknown spacings delta %d block\n", wh));
1913         s << "###delta[spacings" << wh << "]=" << child << ",";
1914       }
1915       m_extra+=s.str();
1916       return true;
1917     }
1918     case 0x147530a:
1919       for (auto const &child : field.m_fieldList) {
1920         if (child.m_type==RagTime5StructManager::Field::T_Code && child.m_fileType==0x8d000) {
1921           if (child.m_string=="----") // checkme
1922             m_breakMethod=0;
1923           else if (child.m_string=="nxtC")
1924             m_breakMethod=1;
1925           else if (child.m_string=="nxtP")
1926             m_breakMethod=2;
1927           else if (child.m_string=="nxtE")
1928             m_breakMethod=3;
1929           else if (child.m_string=="nxtO")
1930             m_breakMethod=4;
1931           else {
1932             MWAW_DEBUG_MSG(("RagTime5StyleManager::TextStyle::read: find some unknown break method block %s\n", child.m_string.cstr()));
1933             s << "##break[method]=" << child.m_string.cstr() << ",";
1934           }
1935           continue;
1936         }
1937         MWAW_DEBUG_MSG(("RagTime5StyleManager::TextStyle::read: find some unknown break method block\n"));
1938         s << "###break[method]=" << child << ",";
1939       }
1940       m_extra+=s.str();
1941       return true;
1942     case 0x147550a:
1943       for (auto const &child : field.m_fieldList) {
1944         if (child.m_type==RagTime5StructManager::Field::T_Bool && child.m_fileType==0x360c0) {
1945           if (child.m_longValue[0])
1946             s << "text[margins]=canOverlap,";
1947           continue;
1948         }
1949         MWAW_DEBUG_MSG(("RagTime5StyleManager::TextStyle::read: find some unknown text margin overlap block\n"));
1950         s << "###text[margins]=" << child << ",";
1951       }
1952       m_extra+=s.str();
1953       return true;
1954     case 0x147516a:
1955       for (auto const &child : field.m_fieldList) {
1956         if (child.m_type==RagTime5StructManager::Field::T_Bool && child.m_fileType==0x360c0) {
1957           if (child.m_longValue[0])
1958             s << "line[align]=ongrid,";
1959           continue;
1960         }
1961         MWAW_DEBUG_MSG(("RagTime5StyleManager::TextStyle::read: find some unknown line grid align block\n"));
1962         s << "###line[gridalign]=" << child << ",";
1963       }
1964       m_extra+=s.str();
1965       return true;
1966     case 0x147546a:
1967     case 0x147548a:
1968     case 0x14754aa: { // find one time with 1
1969       std::string wh(field.m_fileType==0x147546a ? "orphan" :
1970                      field.m_fileType==0x147548a ?  "widows" : "unkn54aa");
1971       for (auto const &child : field.m_fieldList) {
1972         if (child.m_type==RagTime5StructManager::Field::T_Long && child.m_fileType==0x328c0) {
1973           s << wh << "=" << child.m_longValue[0];
1974           continue;
1975         }
1976         MWAW_DEBUG_MSG(("RagTime5StyleManager::TextStyle::read: find some unknown number %s block\n", wh.c_str()));
1977         s << "###" << wh << "=" << child << ",";
1978       }
1979       m_extra+=s.str();
1980       return true;
1981     }
1982     case 0x14754ba:
1983       for (auto const &child : field.m_fieldList) {
1984         if (child.m_type==RagTime5StructManager::Field::T_Unstructured && child.m_fileType==0x1476840) {
1985           // height in line, number of character, first line with text, scaling
1986           s << "drop[initial]=" << child.m_extra << ",";
1987           continue;
1988         }
1989         MWAW_DEBUG_MSG(("RagTime5StyleManager::TextStyle::read: find some unknown drop initial block\n"));
1990         s << "###drop[initial]=" << child << ",";
1991       }
1992       m_extra+=s.str();
1993       return true;
1994     case 0x14750ca: // one tab, remove tab?
1995     case 0x147510a:
1996       if (field.m_fileType==0x14750ca) s << "#tab0";
1997       for (auto const &child : field.m_fieldList) {
1998         if (child.m_type==RagTime5StructManager::Field::T_TabList && (child.m_fileType==(unsigned long)(long(0x81474040)) || child.m_fileType==0x1474040)) {
1999           m_tabList=child.m_tabList;
2000           continue;
2001         }
2002         MWAW_DEBUG_MSG(("RagTime5StyleManager::TextStyle::read: find some unknown tab block\n"));
2003         s << "###tab=" << child << ",";
2004       }
2005       m_extra+=s.str();
2006       return true;
2007 
2008     //
2009     // char
2010     //
2011     case 0x7a05a:
2012       for (auto const &child : field.m_fieldList) {
2013         if (child.m_type==RagTime5StructManager::Field::T_Double && child.m_fileType==0x1495000) {
2014           m_fontSize=float(child.m_doubleValue);
2015           continue;
2016         }
2017         MWAW_DEBUG_MSG(("RagTime5StyleManager::TextStyle::read: find some unknown font size block\n"));
2018         s << "###size[font]=" << child << ",";
2019       }
2020       m_extra+=s.str();
2021       return true;
2022 
2023     case 0xa7017:
2024     case 0xa7037:
2025     case 0xa7047:
2026     case 0xa7057:
2027     case 0xa7067: {
2028       auto wh=int(((field.m_fileType&0x70)>>4)-1);
2029       for (auto const &child : field.m_fieldList) {
2030         if (child.m_type==RagTime5StructManager::Field::T_Unicode && child.m_fileType==0xc8042) {
2031           if (wh==2)
2032             m_fontName=child.m_string;
2033           else {
2034             static char const *what[]= {"[full]" /* unsure */, "[##UNDEF]", "", "[style]" /* regular, ...*/, "[from]", "[full2]"};
2035             s << "font" << what[wh] << "=\"" << child.m_string.cstr() << "\",";
2036           }
2037           continue;
2038         }
2039         MWAW_DEBUG_MSG(("RagTime5StyleManager::TextStyle::read: find some font name[%d] block\n", wh));
2040         s << "###font[" << wh << "]=" << child << ",";
2041       }
2042       m_extra+=s.str();
2043       return true;
2044     }
2045     case 0xa7077:
2046     case 0x147407a:
2047     case 0x147408a:
2048       for (auto const &child : field.m_fieldList) {
2049         if (child.m_type==RagTime5StructManager::Field::T_Long && child.m_fileType==0x3b880) {
2050           switch (field.m_fileType) {
2051           case 0xa7077:
2052             m_fontId=static_cast<int>(child.m_longValue[0]);
2053             break;
2054           case 0x147407a:
2055             s << "hyph[minSyl]=" << child.m_longValue[0] << ",";
2056             break;
2057           case 0x147408a:
2058             s << "hyph[minWord]=" << child.m_longValue[0] << ",";
2059             break;
2060           default:
2061             MWAW_DEBUG_MSG(("RagTime5StyleManager::TextStyle::read: find some unknown long=%lx\n", static_cast<unsigned long>(field.m_fileType)));
2062             break;
2063           }
2064           continue;
2065         }
2066         MWAW_DEBUG_MSG(("RagTime5StyleManager::TextStyle::read: find some unknown long=%lx block\n", static_cast<unsigned long>(field.m_fileType)));
2067         s << "###long[" << RagTime5StyleManager::printType(field.m_fileType) << "]=" << child << ",";
2068       }
2069       m_extra+=s.str();
2070       return true;
2071     case 0x7a09a:
2072       for (auto const &child : field.m_fieldList) {
2073         if (child.m_type==RagTime5StructManager::Field::T_2Long && child.m_fileType==0xa4840) {
2074           m_fontFlags[0]=static_cast<uint32_t>(child.m_longValue[0]);
2075           m_fontFlags[1]=static_cast<uint32_t>(child.m_longValue[1]);
2076           continue;
2077         }
2078         if (child.m_type==RagTime5StructManager::Field::T_Long && child.m_fileType==0xa4000) {
2079           m_fontFlags[0]=static_cast<uint32_t>(child.m_longValue[0]);
2080           continue;
2081         }
2082         MWAW_DEBUG_MSG(("RagTime5StyleManager::TextStyle::read: find some unknown font flags block\n"));
2083         s << "###flags[font]=" << child << ",";
2084       }
2085       m_extra+=s.str();
2086       return true;
2087     case 0x14740ba:
2088       for (auto const &child : field.m_fieldList) {
2089         if (child.m_type==RagTime5StructManager::Field::T_Code && child.m_fileType==0x8d000) {
2090           if (child.m_string=="----") // checkme
2091             m_underline=0;
2092           else if (child.m_string=="undl")
2093             m_underline=1;
2094           else if (child.m_string=="Dund")
2095             m_underline=2;
2096           else {
2097             MWAW_DEBUG_MSG(("RagTime5StyleManager::TextStyle::read: find some unknown underline block %s\n", child.m_string.cstr()));
2098             s << "##underline=" << child.m_string.cstr() << ",";
2099           }
2100           continue;
2101         }
2102         MWAW_DEBUG_MSG(("RagTime5StyleManager::TextStyle::read: find some underline block\n"));
2103         s << "###underline=" << child << ",";
2104       }
2105       m_extra+=s.str();
2106       return true;
2107     case 0x147403a:
2108       for (auto const &child : field.m_fieldList) {
2109         if (child.m_type==RagTime5StructManager::Field::T_Code && child.m_fileType==0x8d000) {
2110           if (child.m_string=="----") // checkme
2111             m_caps=0;
2112           else if (child.m_string=="alcp")
2113             m_caps=1;
2114           else if (child.m_string=="lowc")
2115             m_caps=2;
2116           else if (child.m_string=="Icas")
2117             m_caps=3;
2118           else {
2119             MWAW_DEBUG_MSG(("RagTime5StyleManager::TextStyle::read: find some unknown caps block %s\n", child.m_string.cstr()));
2120             s << "##caps=" << child.m_string.cstr() << ",";
2121           }
2122           continue;
2123         }
2124         MWAW_DEBUG_MSG(("RagTime5StyleManager::TextStyle::read: find some caps block\n"));
2125         s << "###caps=" << child << ",";
2126       }
2127       m_extra+=s.str();
2128       return true;
2129     case 0x14753aa: // min spacing
2130     case 0x14753ca: // optimal spacing
2131     case 0x14753ea: { // max spacing
2132       int wh=field.m_fileType==0x14753aa ? 2 : field.m_fileType==0x14753ca ? 1 : 3;
2133       for (auto const &child : field.m_fieldList) {
2134         if (child.m_type==RagTime5StructManager::Field::T_Double && child.m_fileType==0xb6000) {
2135           m_letterSpacings[wh]=child.m_doubleValue;
2136           continue;
2137         }
2138         MWAW_DEBUG_MSG(("RagTime5StyleManager::TextStyle::read: find some unknown spacings[%d] block\n", wh));
2139         s << "###spacings[" << wh << "]=" << child << ",";
2140       }
2141       m_extra+=s.str();
2142       return true;
2143     }
2144 
2145     case 0x147404a: // space scaling
2146       for (auto const &child : field.m_fieldList) {
2147         if (child.m_type==RagTime5StructManager::Field::T_LongDouble && child.m_fileType==0x149c940) {
2148           m_letterSpacings[0]=child.m_doubleValue;
2149           // no sure what do to about this int : a number between 0 and 256...
2150           if (child.m_longValue[0]) s << "[" << child.m_longValue[0] << "],";
2151           else s << ",";
2152           continue;
2153         }
2154         MWAW_DEBUG_MSG(("RagTime5StyleManager::TextStyle::read: find some unknown space scaling block\n"));
2155         s << "###space[scaling]=" << child << ",";
2156       }
2157       m_extra+=s.str();
2158       return true;
2159 
2160     case 0x147405a: // script position
2161       for (auto const &child : field.m_fieldList) {
2162         if (child.m_type==RagTime5StructManager::Field::T_LongDouble && child.m_fileType==0x149c940) {
2163           m_scriptPosition=float(child.m_doubleValue);
2164           if ((child.m_doubleValue<0 || child.m_doubleValue>0) && m_fontScaling<0)
2165             m_fontScaling=0.75;
2166           // no sure what do to about this int : a number between 0 and 256...
2167           if (child.m_longValue[0]) s << "script2[pos]?=" << child.m_longValue[0] << ",";
2168           continue;
2169         }
2170         MWAW_DEBUG_MSG(("RagTime5StyleManager::TextStyle::read: find some unknown font script block\n"));
2171         s << "###font[script]=" << child << ",";
2172       }
2173       m_extra+=s.str();
2174       return true;
2175 
2176     case 0x14741ba:
2177       for (auto const &child : field.m_fieldList) {
2178         if (child.m_type==RagTime5StructManager::Field::T_Double && child.m_fileType==0xb6000) {
2179           m_fontScaling=float(child.m_doubleValue);
2180           continue;
2181         }
2182         MWAW_DEBUG_MSG(("RagTime5StyleManager::TextStyle::read: find some unknown font scaling block\n"));
2183         s << "###scaling=" << child << ",";
2184       }
2185       m_extra+=s.str();
2186       return true;
2187 
2188     case 0x14740ea: // horizontal streching
2189     case 0x147418a: // small cap horizontal scaling
2190     case 0x14741aa: { // small cap vertical scaling
2191       std::string wh(field.m_fileType==0x14740ea ? "font[strech]" :
2192                      field.m_fileType==0x147418a ? "font[smallScaleH]" : "font[smallScaleV]");
2193       for (auto const &child : field.m_fieldList) {
2194         if (child.m_type==RagTime5StructManager::Field::T_Double && child.m_fileType==0xb6000) {
2195           if (field.m_fileType==0x14740ea)
2196             m_widthStreching=child.m_doubleValue;
2197           else
2198             s << wh << "=" << child.m_doubleValue << ",";
2199           continue;
2200         }
2201         MWAW_DEBUG_MSG(("RagTime5StyleManager::TextStyle::read: find some unknown %s block\n", wh.c_str()));
2202         s << "###" << wh << "=" << child << ",";
2203       }
2204       m_extra+=s.str();
2205       return true;
2206     }
2207     case 0x147406a: // automatic hyphenation
2208     case 0x147552a: { // ignore 1 word ( for spacings )
2209       std::string wh(field.m_fileType==0x147406a ? "hyphen" : "spacings[ignore1Word]");
2210       for (auto const &child : field.m_fieldList) {
2211         if (child.m_type==RagTime5StructManager::Field::T_Bool && child.m_fileType==0x360c0) {
2212           if (child.m_longValue[0])
2213             s << wh << ",";
2214           else
2215             s << wh << "=no,";
2216           continue;
2217         }
2218         MWAW_DEBUG_MSG(("RagTime5StyleManager::TextStyle::read: find some unknown %s block\n", wh.c_str()));
2219         s << "###" << wh << "=" << child << ",";
2220       }
2221       m_extra+=s.str();
2222       return true;
2223     }
2224     case 0x147402a: // language
2225       for (auto const &child : field.m_fieldList) {
2226         if (child.m_type==RagTime5StructManager::Field::T_Long && child.m_fileType==0x34080) {
2227           m_language=static_cast<int>(child.m_longValue[0]);
2228           continue;
2229         }
2230         MWAW_DEBUG_MSG(("RagTime5StyleManager::TextStyle::read: find some unknown language block\n"));
2231         s << "###language=" << child << ",";
2232       }
2233       m_extra+=s.str();
2234       return true;
2235 
2236     //
2237     // columns
2238     //
2239     case 0x147512a:
2240       for (auto const &child : field.m_fieldList) {
2241         if (child.m_type==RagTime5StructManager::Field::T_Long && child.m_fileType==0x328c0) {
2242           m_numColumns=static_cast<int>(child.m_longValue[0]);
2243           continue;
2244         }
2245         MWAW_DEBUG_MSG(("RagTime5StyleManager::TextStyle::read: find some unknown column's number block\n"));
2246         s << "###num[cols]=" << child << ",";
2247       }
2248       m_extra+=s.str();
2249       return true;
2250     case 0x147513a:
2251       for (auto const &child : field.m_fieldList) {
2252         if (child.m_type==RagTime5StructManager::Field::T_Double && child.m_fileType==0x1493800) {
2253           m_columnGap=child.m_doubleValue;
2254           continue;
2255         }
2256         MWAW_DEBUG_MSG(("RagTime5StyleManager::TextStyle::read: find some unknown columns gaps block\n"));
2257         s << "###col[gap]=" << child << ",";
2258       }
2259       m_extra+=s.str();
2260       return true;
2261 
2262     default:
2263       break;
2264     }
2265   }
2266   return false;
2267 }
2268 
insert(RagTime5StyleManager::TextStyle const & child)2269 void RagTime5StyleManager::TextStyle::insert(RagTime5StyleManager::TextStyle const &child)
2270 {
2271   if (!child.m_linkIdList.empty()) m_linkIdList=child.m_linkIdList; // usefull?
2272   if (child.m_graphStyleId>=0) m_graphStyleId=child.m_graphStyleId;
2273   if (child.m_graphLineStyleId>=0) m_graphLineStyleId=child.m_graphLineStyleId;
2274   if (child.m_dateStyleId>=0) m_dateStyleId=child.m_dateStyleId;
2275   if (child.m_keepWithNext.isSet()) m_keepWithNext=child.m_keepWithNext;
2276   if (child.m_justify>=0) m_justify=child.m_justify;
2277   if (child.m_breakMethod>=0) m_breakMethod=child.m_breakMethod;
2278   for (int i=0; i<3; ++i) {
2279     if (child.m_margins[i]>=0) m_margins[i]=child.m_margins[i];
2280   }
2281   for (int i=0; i<3; ++i) {
2282     if (child.m_spacings[i]<0) continue;
2283     m_spacings[i]=child.m_spacings[i];
2284     m_spacingUnits[i]=child.m_spacingUnits[i];
2285   }
2286   if (!child.m_tabList.empty()) m_tabList=child.m_tabList; // append ?
2287   // char
2288   if (!child.m_fontName.empty()) m_fontName=child.m_fontName;
2289   if (child.m_fontId>=0) m_fontId=child.m_fontId;
2290   if (child.m_fontSize>=0) m_fontSize=child.m_fontSize;
2291   for (int i=0; i<2; ++i) {
2292     uint32_t fl=child.m_fontFlags[i];
2293     if (!fl) continue;
2294     if (i==0) m_fontFlags[0]|=fl;
2295     else m_fontFlags[0]&=(~fl);
2296   }
2297   if (child.m_caps>=0) m_caps=child.m_caps;
2298   if (child.m_underline>=0) m_underline=child.m_underline;
2299   if (child.m_scriptPosition.isSet()) m_scriptPosition=child.m_scriptPosition;
2300   if (child.m_fontScaling>=0) m_fontScaling=child.m_fontScaling;
2301 
2302   for (int i=0; i<4; ++i) {
2303     if (child.m_letterSpacings[i]>0 || child.m_letterSpacings[i]<0)
2304       m_letterSpacings[i]=child.m_letterSpacings[i];
2305   }
2306   if (child.m_language>=0) m_language=child.m_language;
2307   if (child.m_widthStreching>=0) m_widthStreching=child.m_widthStreching;
2308   // column
2309   if (child.m_numColumns>=0) m_numColumns=child.m_numColumns;
2310   if (child.m_columnGap>=0) m_columnGap=child.m_columnGap;
2311 }
2312 
operator <<(std::ostream & o,RagTime5StyleManager::TextStyle const & style)2313 std::ostream &operator<<(std::ostream &o, RagTime5StyleManager::TextStyle const &style)
2314 {
2315   if (style.m_parentId[0]>=0) o << "parent=TS" << style.m_parentId[0] << ",";
2316   if (style.m_parentId[1]>=0) o << "parent[style?]=TS" << style.m_parentId[1] << ",";
2317   if (!style.m_linkIdList.empty()) {
2318     // fixme: 3 text style's id values with unknown meaning, probably important...
2319     o << "link=[";
2320     for (auto id : style.m_linkIdList)
2321       o << "TS" << id << ",";
2322     o << "],";
2323   }
2324   if (style.m_graphStyleId>=0) o << "graph[id]=GS" << style.m_graphStyleId << ",";
2325   if (style.m_graphLineStyleId>=0) o << "graphLine[id]=GS" << style.m_graphLineStyleId << ",";
2326   if (style.m_dateStyleId>=0) o << "date[id]=DS" << style.m_dateStyleId << ",";
2327   if (style.m_keepWithNext.isSet()) {
2328     o << "keep[withNext]";
2329     if (!*style.m_keepWithNext)
2330       o << "=false,";
2331     else
2332       o << ",";
2333   }
2334   switch (style.m_justify) {
2335   case 0: // left
2336     break;
2337   case 1:
2338     o << "justify=center,";
2339     break;
2340   case 2:
2341     o << "justify=right,";
2342     break;
2343   case 3:
2344     o << "justify=full,";
2345     break;
2346   case 4:
2347     o << "justify=full[all],";
2348     break;
2349   default:
2350     if (style.m_justify>=0)
2351       o << "##justify=" << style.m_justify << ",";
2352   }
2353 
2354   switch (style.m_breakMethod) {
2355   case 0: // as is
2356     break;
2357   case 1:
2358     o << "break[method]=next[container],";
2359     break;
2360   case 2:
2361     o << "break[method]=next[page],";
2362     break;
2363   case 3:
2364     o << "break[method]=next[evenP],";
2365     break;
2366   case 4:
2367     o << "break[method]=next[oddP],";
2368     break;
2369   default:
2370     if (style.m_breakMethod>=0)
2371       o << "##break[method]=" << style.m_breakMethod << ",";
2372   }
2373   for (int i=0; i<3; ++i) {
2374     if (style.m_margins[i]<0) continue;
2375     static char const *wh[]= {"left", "right", "first"};
2376     o << "margins[" << wh[i] << "]=" << style.m_margins[i] << ",";
2377   }
2378   for (int i=0; i<3; ++i) {
2379     if (style.m_spacings[i]<0) continue;
2380     o << (i==0 ? "interline" : i==1 ? "before[spacing]" : "after[spacing]");
2381     o << "=" << style.m_spacings[i];
2382     if (style.m_spacingUnits[i]==0)
2383       o << "%";
2384     else if (style.m_spacingUnits[i]==1)
2385       o << "pt";
2386     else
2387       o << "[###unit]=" << style.m_spacingUnits[i];
2388     o << ",";
2389   }
2390   if (!style.m_tabList.empty()) {
2391     o << "tabs=[";
2392     for (auto const &tab : style.m_tabList)
2393       o << tab << ",";
2394     o << "],";
2395   }
2396   // char
2397   if (!style.m_fontName.empty())
2398     o << "font=\"" << style.m_fontName.cstr() << "\",";
2399   if (style.m_fontId>=0)
2400     o << "id[font]=" << style.m_fontId << ",";
2401   if (style.m_fontSize>=0)
2402     o << "sz[font]=" << style.m_fontSize << ",";
2403   for (int i=0; i<2; ++i) {
2404     uint32_t fl=style.m_fontFlags[i];
2405     if (!fl) continue;
2406     if (i==1)
2407       o << "flag[rm]=[";
2408     if (fl&1) o << "bold,";
2409     if (fl&2) o << "it,";
2410     // 4 underline?
2411     if (fl&8) o << "outline,";
2412     if (fl&0x10) o << "shadow,";
2413     if (fl&0x200) o << "strike[through],";
2414     if (fl&0x400) o << "small[caps],";
2415     if (fl&0x800) o << "kumoraru,"; // ie. with some char overlapping
2416     if (fl&0x20000) o << "underline[word],";
2417     if (fl&0x80000) o << "key[pairing],";
2418     fl &= 0xFFF5F1E4;
2419     if (fl) o << "#fontFlags=" << std::hex << fl << std::dec << ",";
2420     if (i==1)
2421       o << "],";
2422   }
2423   switch (style.m_caps) {
2424   case 0:
2425     break;
2426   case 1:
2427     o << "upper[caps],";
2428     break;
2429   case 2:
2430     o << "lower[caps],";
2431     break;
2432   case 3:
2433     o << "upper[initial+...],";
2434     break;
2435   default:
2436     if (style.m_caps >= 0)
2437       o << "###caps=" << style.m_caps << ",";
2438     break;
2439   }
2440   switch (style.m_underline) {
2441   case 0:
2442     break;
2443   case 1:
2444     o << "underline=single,";
2445     break;
2446   case 2:
2447     o << "underline=double,";
2448     break;
2449   default:
2450     if (style.m_underline>=0)
2451       o << "###underline=" << style.m_underline << ",";
2452   }
2453   if (style.m_scriptPosition.isSet())
2454     o << "ypos[font]=" << *style.m_scriptPosition << "%,";
2455   if (style.m_fontScaling>=0)
2456     o << "scale[font]=" << style.m_fontScaling << "%,";
2457 
2458   for (int i=0; i<4; ++i) {
2459     if (style.m_letterSpacings[i]<=0&&style.m_letterSpacings[i]>=0) continue;
2460     static char const *wh[]= {"", "[optimal]", "[min]", "[max]"};
2461     o << "letterSpacing" << wh[i] << "=" << style.m_letterSpacings[i] << ",";
2462   }
2463   if (style.m_widthStreching>=0)
2464     o << "width[streching]=" << style.m_widthStreching*100 << "%,";
2465   if (style.m_language>0) {
2466     std::string lang=RagTime5StyleManager::TextStyle::getLanguageLocale(style.m_language);
2467     if (!lang.empty())
2468       o << lang << ",";
2469     else
2470       o << "##language=" << std::hex << style.m_language << std::dec << ",";
2471   }
2472   // column
2473   if (style.m_numColumns>=0)
2474     o << "num[col]=" << style.m_numColumns << ",";
2475   if (style.m_columnGap>=0)
2476     o << "col[gap]=" << style.m_columnGap << ",";
2477   o << style.m_extra;
2478   return o;
2479 }
2480 
2481 
2482 // vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab:
2483