1 /* -*- Mode: C++; c-default-style: "k&r"; indent-tabs-mode: nil; tab-width: 2; c-basic-offset: 2 -*- */
2 
3 /* libstaroffice
4 * Version: MPL 2.0 / LGPLv2+
5 *
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 2.0 (the "License"); you may not use this file except in compliance with
8 * the License or as specified alternatively below. You may obtain a copy of
9 * the License at http://www.mozilla.org/MPL/
10 *
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
15 *
16 * Major Contributor(s):
17 * Copyright (C) 2002 William Lachance (wrlach@gmail.com)
18 * Copyright (C) 2002,2004 Marc Maurer (uwog@uwog.net)
19 * Copyright (C) 2004-2006 Fridrich Strba (fridrich.strba@bluewin.ch)
20 * Copyright (C) 2006, 2007 Andrew Ziem
21 * Copyright (C) 2011, 2012 Alonso Laurent (alonso@loria.fr)
22 *
23 *
24 * All Rights Reserved.
25 *
26 * For minor contributions see the git repository.
27 *
28 * Alternatively, the contents of this file may be used under the terms of
29 * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
30 * in which case the provisions of the LGPLv2+ are applicable
31 * instead of those above.
32 */
33 
34 #include <cstring>
35 #include <iomanip>
36 #include <iostream>
37 #include <limits>
38 #include <sstream>
39 
40 #include <librevenge/librevenge.h>
41 
42 #include "SWFieldManager.hxx"
43 
44 #include "StarObject.hxx"
45 #include "StarState.hxx"
46 #include "StarZone.hxx"
47 
48 #include "STOFFListener.hxx"
49 #include "STOFFSubDocument.hxx"
50 
51 /** Internal: the structures of a SWFieldManager */
52 namespace SWFieldManagerInternal
53 {
updateDatabaseName(librevenge::RVNGString const & name,librevenge::RVNGPropertyList & pList)54 static void updateDatabaseName(librevenge::RVNGString const &name, librevenge::RVNGPropertyList &pList)
55 {
56   librevenge::RVNGString delim, dbName, tableName;
57   libstoff::appendUnicode(0xff, delim);
58   libstoff::splitString(name,delim, dbName, tableName);
59   if (tableName.empty()) {
60     if (!dbName.empty())
61       pList.insert("text:table-name", dbName);
62   }
63   else {
64     pList.insert("text:table-name", tableName);
65     if (!dbName.empty())
66       pList.insert("text:database-name", dbName);
67   }
68   // checkme: always table or is it a function of subtype
69   pList.insert("text:table-type", "table");
70 }
71 
~Field()72 Field::~Field()
73 {
74 }
75 
print(std::ostream & o) const76 void Field::print(std::ostream &o) const
77 {
78   if (m_type>=0 && m_type<40) {
79     char const *wh[]= {"db", "user", "filename", "dbName",
80                        "inDate40", "inTime40", "pageNumber", "author",
81                        "chapter", "docStat", "getExp", "setExp",
82                        "getRef", "hiddenText", "postIt", "fixDate",
83                        "fixTime", "reg", "varReg", "setRef", // checkme: 17-19
84                        "input", "macro", "dde", "tbl",
85                        "hiddenPara", "docInfo", "templName", "dbNextSet", // checkme: 27
86                        "dbNumSet", "dbSetNumber", "extUser", "pageSet", // checkme: 29,31
87                        "pageGet", "INet", "jumpEdit", "script", // checkme: 32-33,35
88                        "dateTime", "authority", "combinedChar", "dropDown" // checkme: 36-39
89                       };
90     o << wh[m_type];
91     if (m_subType>=0) o << "[" << m_subType << "]";
92     o << ",";
93   }
94   else if (m_type>=0)
95     o << "###field[type]=" << m_type << ",";
96   if (m_format>=0)
97     o << "format=" << m_format << ",";
98   if (!m_name.empty())
99     o << "name=" << m_name.cstr() << ",";
100   if (!m_content.empty())
101     o << "content=" << m_content.cstr() << ",";
102   if (!m_textValue.empty())
103     o << "val=" << m_textValue.cstr() << ",";
104   else if (m_doubleValue<0||m_doubleValue>0)
105     o << "val=" << m_doubleValue << ",";
106   if (m_level)
107     o << "level=" << m_level << ",";
108 }
109 
send(STOFFListenerPtr & listener,StarState & state) const110 bool Field::send(STOFFListenerPtr &listener, StarState &state) const
111 {
112   if (!listener || !listener->canWriteText()) {
113     STOFF_DEBUG_MSG(("SWFieldManagerInternal::Field::send: can not find the listener\n"));
114     return false;
115   }
116   STOFFField field;
117   if (m_type==1) {
118     if (m_name.empty()) {
119       STOFF_DEBUG_MSG(("SWFieldManagerInternal::Field::send: can not find the user name\n"));
120       return false;
121     }
122     field.m_propertyList.insert("librevenge:field-type", "text:user-defined");
123     field.m_propertyList.insert("text:name", m_name);
124     if (!m_content.empty())
125       field.m_propertyList.insert("office:string-value", m_content);
126     else if (!m_textValue.empty())
127       field.m_propertyList.insert("office:string-value", m_textValue);
128     else if (m_doubleValue<0 || m_doubleValue>0)
129       field.m_propertyList.insert("office:value", m_doubleValue, librevenge::RVNG_GENERIC);
130   }
131   else if (m_type==2) {
132     field.m_propertyList.insert("librevenge:field-type", "text:file-name");
133     if (m_format>=0 && m_format<=5) {
134       char const *wh[]= {"name-and-extension", "full", "path", "name", "name"/*uiname*/, "area" /* range*/ };
135       field.m_propertyList.insert("text:display", wh[m_format]);
136     }
137     else {
138       STOFF_DEBUG_MSG(("SWFieldManagerInternal::Field::send: unknown filename type=%d\n", m_format));
139     }
140   }
141   else if (m_type==3) {
142     if (m_name.empty()) {
143       STOFF_DEBUG_MSG(("SWFieldManagerInternal::Field::send: can not find the dbName\n"));
144       return false;
145     }
146     field.m_propertyList.insert("librevenge:field-type", "text:database-name");
147     updateDatabaseName(m_name, field.m_propertyList);
148     field.m_propertyList.insert("librevenge:field-content", m_name);
149   }
150   else if (m_type==7)
151     field.m_propertyList.insert("librevenge:field-type", "text:author-name");
152   else if (m_type==8) {
153     field.m_propertyList.insert("librevenge:field-type", "text:chapter");
154     if (m_format>=0 && m_format<=2) {
155       char const *wh[]= {"number", "name", "number-and-name"};
156       field.m_propertyList.insert("text:display", wh[m_format]);
157     }
158     else {
159       STOFF_DEBUG_MSG(("SWFieldManagerInternal::Field::send: unknown chapter type=%d\n", m_format));
160     }
161     if (m_level>=0)
162       field.m_propertyList.insert("text:outline-level", m_level+1);
163   }
164   else if (m_type==9) {
165     if (m_subType>=0 && m_subType<=6) {
166       char const *wh[]= {
167         "text:page-count", "text:paragraph-count", "text:word-count", "text:character-count", "text:table-count",
168         "text:image-count","text:object-count"
169       };
170       field.m_propertyList.insert("librevenge:field-type", wh[m_subType]);
171     }
172     else {
173       STOFF_DEBUG_MSG(("SWFieldManagerInternal::Field::send: unknown doc type=%d\n", m_subType));
174       return false;
175     }
176   }
177   else if (m_type==10) {
178     if (m_name.empty() || m_content.empty()) {
179       STOFF_DEBUG_MSG(("SWFieldManagerInternal::Field::send: can not find the expression values\n"));
180       return false;
181     }
182     if (m_subType&0x10) {
183       field.m_propertyList.insert("librevenge:field-type", "text:expression");
184       field.m_propertyList.insert("text:formula", m_name);
185       field.m_propertyList.insert("office:string-value", m_content);
186     }
187     else {
188       field.m_propertyList.insert("librevenge:field-type", "text:variable-get");
189       field.m_propertyList.insert("text:name", m_name);
190     }
191     if (!m_content.empty())
192       field.m_propertyList.insert("librevenge:field-content", m_content);
193   }
194   else if (m_type==12) {
195     if (m_name.empty()) {
196       STOFF_DEBUG_MSG(("SWFieldManagerInternal::Field::send: can not find the getRef values\n"));
197       return false;
198     }
199     field.m_propertyList.insert("librevenge:field-type", "text:reference-ref");
200     field.m_propertyList.insert("text:ref-name", m_name);
201     if (m_format>=0 && m_format<=10) {
202       char const *wh[]= {"page", "chapter", "text", "direction",
203                          "text"/* as page style*/, "category-and-value", "caption", "number",
204                          "number"/* new ref*/, "number"/*no context*/, "number"/*full context*/
205                         };
206       field.m_propertyList.insert("text:reference-format",wh[m_format]);
207     }
208     else {
209       STOFF_DEBUG_MSG(("SWFieldManagerInternal::Field::send: unknown getRef format=%d\n", m_format));
210     }
211     if (!m_content.empty())
212       field.m_propertyList.insert("librevenge:field-content", m_content);
213   }
214   else if (m_type==23) {
215     if (m_name.empty()) {
216       STOFF_DEBUG_MSG(("SWFieldManagerInternal::Field::send: can not find the expression values\n"));
217       return false;
218     }
219     field.m_propertyList.insert("librevenge:field-type", "text:expression");
220     field.m_propertyList.insert("text:formula", m_name);
221     if (!m_content.empty()) {
222       field.m_propertyList.insert("office:string-value", m_content);
223       field.m_propertyList.insert("librevenge:field-content", m_content);
224     }
225   }
226   else if (m_type==25) {
227     int subType=m_subType&0x7FF;
228     if (subType>=4 && subType<8) {
229       field.m_propertyList.insert("librevenge:field-type", "text:user-defined");
230       field.m_propertyList.insert("text:name", state.m_global->m_object.getUserNameMetaData(subType-4));
231     }
232     else if (subType==9) {
233       if (m_format>=0 && m_format<=2) {
234         char const *wh[]= {
235           "text:creator", "text:modification-time", "text:modification-date"
236         };
237         field.m_propertyList.insert("librevenge:field-type", wh[m_format]);
238       }
239       else {
240         STOFF_DEBUG_MSG(("SWFieldManagerInternal::Field::send: sending custom type %d is not implemented\n", m_format));
241       }
242     }
243     else if (subType==10) {
244       if (m_format>=0 && m_format<=2) {
245         char const *wh[]= {
246           "text:printed-by", "text:print-time", "text:print-date"
247         };
248         field.m_propertyList.insert("librevenge:field-type", wh[m_format]);
249       }
250       else {
251         STOFF_DEBUG_MSG(("SWFieldManagerInternal::Field::send: sending custom type %d is not implemented\n", m_format));
252       }
253     }
254     else if (subType>=0 && subType<=12) {
255       char const *wh[]= {
256         "text:title", "text:subject", "text:keywords", "text:description",
257         "text:Info1", "text:Info2", "text:Info3", "text:Info4",
258         "text:editing-cycles", "", "",  "text:editing-cycles",
259         "text:editing-duration"
260       };
261       field.m_propertyList.insert("librevenge:field-type", wh[subType]);
262     }
263     else {
264       STOFF_DEBUG_MSG(("SWFieldManagerInternal::Field::send: sending docInfo %d is not implemented\n", subType));
265       return false;
266     }
267   }
268   else if (m_type==20) {
269     field.m_propertyList.insert("librevenge:field-type", "text:text-input");
270     field.m_propertyList.insert("text:description", m_name);
271     field.m_propertyList.insert("librevenge:field-content", m_content);
272   }
273   else if (m_type==21) {
274     static bool first=true;
275     if (first) {
276       STOFF_DEBUG_MSG(("SWFieldManagerInternal::Field::send: sending macros is not implemented\n"));
277       first=false;
278     }
279     return true;
280   }
281   else if (m_type==26) {
282     int subType=m_format&0x7FF;
283     if (subType>=0 && subType<=5) {
284       char const *wh[]= {"name-and-extension", "full", "path", "name", "title"/*uiname*/, "area" /* range*/ };
285       field.m_propertyList.insert("librevenge:field-type", "text:template-name");
286       field.m_propertyList.insert("text:display", wh[subType]);
287     }
288     else {
289       STOFF_DEBUG_MSG(("SWFieldManagerInternal::Field::send: unknown template type=%d\n", m_format));
290       return false;
291     }
292   }
293   else if (m_type==30) {
294     if (m_subType>=0 && m_subType<=16) {
295       char const *wh[]= {
296         "text:sender-company", "text:sender-firstname", "text:sender-lastname", "text:sender-initials", "text:sender-street",
297         "text:sender-country", "text:sender-postal-code", "text:sender-city", "text:sender-title", "text:sender-position",
298         "text:sender-phone-private", "text:sender-phone-work", "text:sender-fax", "text:sender-email", "text:sender-state-or-province",
299         "text:sender-lastname" /*father name*/, "text:sender-street" /* appartement*/
300       };
301       field.m_propertyList.insert("librevenge:field-type", wh[m_subType]);
302     }
303     else {
304       STOFF_DEBUG_MSG(("SWFieldManagerInternal::Field::send: unknown extUser type=%d\n", m_subType));
305       return false;
306     }
307   }
308   else {
309     STOFF_DEBUG_MSG(("SWFieldManagerInternal::Field::send: sending type=%d is not implemented\n", m_type));
310     return false;
311   }
312   listener->insertField(field);
313   return true;
314 }
315 
316 //! Internal: a fixed date time field
317 struct FieldDateTime final : public Field {
318   //! constructor
FieldDateTimeSWFieldManagerInternal::FieldDateTime319   FieldDateTime() : Field(), m_dateTime(0), m_time(0), m_offset(0)
320   {
321   }
322   //! copy constructor
FieldDateTimeSWFieldManagerInternal::FieldDateTime323   explicit FieldDateTime(Field const &orig) : Field(orig), m_dateTime(0), m_time(0), m_offset(0)
324   {
325   }
326   //! destructor
327   ~FieldDateTime() final;
328   //! add to send the zone data
329   bool send(STOFFListenerPtr &listener, StarState &state) const final;
330   //! print a field
printSWFieldManagerInternal::FieldDateTime331   void print(std::ostream &o) const final
332   {
333     Field::print(o);
334     if (m_dateTime) o << "date/time=" << m_dateTime << ",";
335     if (m_offset) o << "offset=" << m_offset << ",";
336   }
337   //! the dateTime
338   long m_dateTime;
339   //! the time
340   long m_time;
341   //! the offset
342   long m_offset;
343 };
344 
~FieldDateTime()345 FieldDateTime::~FieldDateTime()
346 {
347 }
348 
send(STOFFListenerPtr & listener,StarState & state) const349 bool FieldDateTime::send(STOFFListenerPtr &listener, StarState &state) const
350 {
351   if (!listener || !listener->canWriteText()) {
352     STOFF_DEBUG_MSG(("SWFieldManagerInternal::FieldDateTime::send: can not find the listener\n"));
353     return false;
354   }
355   STOFFField field;
356 
357   if (m_type==4 || m_type==36)
358     field.m_propertyList.insert("librevenge:field-type", "text:date");
359   else if (m_type==5)
360     field.m_propertyList.insert("librevenge:field-type", "text:time");
361   else if (m_type==15) {
362     field.m_propertyList.insert("librevenge:field-type", "text:date");
363     field.m_propertyList.insert("text:fixed", true);
364     if (m_dateTime) {
365       field.m_propertyList.insert("librevenge:year", int(m_dateTime/10000));
366       field.m_propertyList.insert("librevenge:month", int((m_dateTime/100)%100));
367       field.m_propertyList.insert("librevenge:day", int(m_dateTime%100));
368     }
369   }
370   else if (m_type==16) {
371     // FIXME: does not works because libodfgen does not regenerate the text zone...
372     field.m_propertyList.insert("librevenge:field-type", "text:time");
373     field.m_propertyList.insert("text:fixed", true);
374     if (m_dateTime) {
375       field.m_propertyList.insert("librevenge:hours", int(m_dateTime/1000000));
376       field.m_propertyList.insert("librevenge:minutes", int((m_dateTime/10000)%100));
377       field.m_propertyList.insert("librevenge:seconds", int((m_dateTime/100)%100));
378     }
379   }
380   else
381     return Field::send(listener, state);
382   //TODO: set the format
383   listener->insertField(field);
384   return true;
385 }
386 
387 //! Internal: a DB field field
388 struct FieldDBField final : public Field {
389   //! constructor
FieldDBFieldSWFieldManagerInternal::FieldDBField390   FieldDBField()
391     : Field()
392     , m_dbName("")
393     , m_colName("")
394     , m_longNumber(0)
395   {
396   }
397   //! copy constructor
FieldDBFieldSWFieldManagerInternal::FieldDBField398   explicit FieldDBField(Field const &orig) : Field(orig), m_dbName(""), m_colName(""), m_longNumber(0)
399   {
400   }
401   //! destructor
402   ~FieldDBField() final;
403   //! add to send the zone data
404   bool send(STOFFListenerPtr &listener, StarState &state) const final;
405   //! print a field
printSWFieldManagerInternal::FieldDBField406   void print(std::ostream &o) const final
407   {
408     Field::print(o);
409     if (!m_dbName.empty()) o << "dbName=" << m_dbName.cstr() << ",";
410     if (!m_colName.empty()) o << "colName=" << m_colName.cstr() << ",";
411     else if (m_longNumber) o << "number=" << m_longNumber << ",";
412   }
413   //! the dbName
414   librevenge::RVNGString m_dbName;
415   //! the column name
416   librevenge::RVNGString m_colName;
417   //! the number as num
418   long m_longNumber;
419 };
420 
~FieldDBField()421 FieldDBField::~FieldDBField()
422 {
423 }
424 
send(STOFFListenerPtr & listener,StarState & state) const425 bool FieldDBField::send(STOFFListenerPtr &listener, StarState &state) const
426 {
427   if (!listener || !listener->canWriteText()) {
428     STOFF_DEBUG_MSG(("SWFieldManagerInternal::FieldDBField::send: can not find the listener\n"));
429     return false;
430   }
431   STOFFField field;
432 
433   if (m_type==0) {
434     if (m_colName.empty()) {
435       STOFF_DEBUG_MSG(("SWFieldManagerInternal::FieldDBField::send: can not find the col value\n"));
436       return false;
437     }
438     field.m_propertyList.insert("librevenge:field-type", "text:database-display");
439     if (!m_dbName.empty())
440       updateDatabaseName(m_dbName, field.m_propertyList);
441     field.m_propertyList.insert("text:column-name", m_colName);
442   }
443   else
444     return Field::send(listener, state);
445   //TODO: set the format
446   listener->insertField(field);
447   return true;
448 }
449 
450 //! Internal: a hidden text/para field
451 struct FieldHiddenText final : public Field {
452   //! constructor
FieldHiddenTextSWFieldManagerInternal::FieldHiddenText453   FieldHiddenText()
454     : Field()
455     , m_hidden(true)
456     , m_condition("")
457   {
458   }
459   //! copy constructor
FieldHiddenTextSWFieldManagerInternal::FieldHiddenText460   explicit FieldHiddenText(Field const &orig) : Field(orig), m_hidden(true), m_condition("")
461   {
462   }
463   //! destructor
464   ~FieldHiddenText() final;
465   //! add to send the zone data
466   bool send(STOFFListenerPtr &listener, StarState &state) const final;
467   //! print a field
printSWFieldManagerInternal::FieldHiddenText468   void print(std::ostream &o) const final
469   {
470     Field::print(o);
471     if (!m_condition.empty()) o << "condition=" << m_condition.cstr() << ",";
472     if (!m_hidden) o << "hidden=false,";
473   }
474   //! the hidden flag
475   bool m_hidden;
476   //! the condition
477   librevenge::RVNGString m_condition;
478 };
479 
~FieldHiddenText()480 FieldHiddenText::~FieldHiddenText()
481 {
482 }
483 
send(STOFFListenerPtr & listener,StarState & state) const484 bool FieldHiddenText::send(STOFFListenerPtr &listener, StarState &state) const
485 {
486   if (!listener || !listener->canWriteText()) {
487     STOFF_DEBUG_MSG(("SWFieldManagerInternal::FieldHiddenText::send: can not find the listener\n"));
488     return false;
489   }
490   STOFFField field;
491   if (m_type==13) {
492     if (m_condition.empty()) {
493       STOFF_DEBUG_MSG(("SWFieldManagerInternal::FieldHiddenText::send: can not find the condition\n"));
494       return false;
495     }
496     field.m_propertyList.insert("librevenge:field-type", "text:conditional-text");
497     field.m_propertyList.insert("text:condition", m_condition);
498     if (!m_content.empty()) {
499       librevenge::RVNGString trueValue, falseValue;
500       libstoff::splitString(m_content, "|", trueValue, falseValue);
501       if (!trueValue.empty())
502         field.m_propertyList.insert("text:string-value-if-true", trueValue);
503       if (!falseValue.empty())
504         field.m_propertyList.insert("text:string-value-if-false", falseValue);
505     }
506   }
507   else if (m_type==24) {
508     if (m_condition.empty()) {
509       STOFF_DEBUG_MSG(("SWFieldManagerInternal::FieldHiddenText::send: can not find the condition\n"));
510       return false;
511     }
512     field.m_propertyList.insert("librevenge:field-type", "text:hidden-paragraph");
513     field.m_propertyList.insert("text:condition", m_condition);
514     field.m_propertyList.insert("text:is-hidden", m_hidden);
515   }
516   else // also ....
517     return Field::send(listener, state);
518   //TODO: set the format
519   listener->insertField(field);
520   return true;
521 }
522 
523 //! Internal: a set field field
524 struct FieldINet final : public Field {
525   //! constructor
FieldINetSWFieldManagerInternal::FieldINet526   FieldINet()
527     : Field()
528     , m_url("")
529     , m_target("")
530     , m_libNames()
531   {
532   }
533   //! copy constructor
FieldINetSWFieldManagerInternal::FieldINet534   explicit FieldINet(Field const &orig)
535     : Field(orig)
536     , m_url("")
537     , m_target("")
538     , m_libNames()
539   {
540   }
541   //! destructor
542   ~FieldINet() final;
543   //! add to send the zone data
544   bool send(STOFFListenerPtr &listener, StarState &state) const final;
545   //! print a field
printSWFieldManagerInternal::FieldINet546   void print(std::ostream &o) const final
547   {
548     Field::print(o);
549     if (!m_url.empty()) o << "url=" << m_url.cstr() << ",";
550     if (!m_target.empty()) o << "target=" << m_target.cstr() << ",";
551     if (!m_libNames.empty()) {
552       o << "libNames=[";
553       for (size_t i=0; i+1<m_libNames.size(); i+=2)
554         o << m_libNames[i].cstr() << ":" <<  m_libNames[i+1].cstr() << ",";
555       o << "],";
556     }
557   }
558   //! the url
559   librevenge::RVNGString m_url;
560   //! the target
561   librevenge::RVNGString m_target;
562   //! the lib names
563   std::vector<librevenge::RVNGString> m_libNames;
564 };
565 
~FieldINet()566 FieldINet::~FieldINet()
567 {
568 }
569 
send(STOFFListenerPtr & listener,StarState & state) const570 bool FieldINet::send(STOFFListenerPtr &listener, StarState &state) const
571 {
572   if (!listener || !listener->canWriteText()) {
573     STOFF_DEBUG_MSG(("SWFieldManagerInternal::FieldINet::send: can not find the listener\n"));
574     return false;
575   }
576   if (m_type!=33)
577     return Field::send(listener, state);
578   if (m_url.empty()) {
579     STOFF_DEBUG_MSG(("SWFieldManagerInternal::FieldINet::send: the url is empty\n"));
580     return false;
581   }
582   STOFFLink link;
583   link.m_HRef=m_url.cstr();
584   listener->openLink(link);
585   if (!m_target.empty())
586     listener->insertUnicodeString(m_target);
587   else {
588     STOFF_DEBUG_MSG(("SWFieldManagerInternal::FieldINet::send: can not find any representation\n"));
589   }
590   listener->closeLink();
591   return true;
592 }
593 
594 //! Internal: a jump edit field
595 struct FieldJumpEdit final : public Field {
596   //! constructor
FieldJumpEditSWFieldManagerInternal::FieldJumpEdit597   FieldJumpEdit()
598     : Field()
599     , m_help("")
600   {
601   }
602   //! copy constructor
FieldJumpEditSWFieldManagerInternal::FieldJumpEdit603   explicit FieldJumpEdit(Field const &orig)
604     : Field(orig)
605     , m_help("")
606   {
607   }
608   //! destructor
609   ~FieldJumpEdit() final;
610   //! add to send the zone data
611   bool send(STOFFListenerPtr &listener, StarState &state) const final;
612   //! print a field
printSWFieldManagerInternal::FieldJumpEdit613   void print(std::ostream &o) const final
614   {
615     Field::print(o);
616     if (!m_help.empty()) o << "help=" << m_help.cstr() << ",";
617   }
618   //! the help
619   librevenge::RVNGString m_help;
620 };
621 
~FieldJumpEdit()622 FieldJumpEdit::~FieldJumpEdit()
623 {
624 }
625 
send(STOFFListenerPtr & listener,StarState & state) const626 bool FieldJumpEdit::send(STOFFListenerPtr &listener, StarState &state) const
627 {
628   if (!listener || !listener->canWriteText()) {
629     STOFF_DEBUG_MSG(("SWFieldManagerInternal::FieldJumpEdit::send: can not find the listener\n"));
630     return false;
631   }
632   STOFFField field;
633   if (m_type==34) {
634     field.m_propertyList.insert("librevenge:field-type", "text:placeholder");
635     field.m_propertyList.insert("librevenge:field-content", m_content);
636     if (m_format>=0 && m_format<=4) {
637       char const *wh[]= {"text", "table", "text-box", "image", "object"};
638       field.m_propertyList.insert("text:placeholder-type",wh[m_format]);
639     }
640     else {
641       STOFF_DEBUG_MSG(("SWFieldManagerInternal::FieldJumpEdit::send: unknown format=%d\n", m_format));
642     }
643     if (!m_help.empty())
644       field.m_propertyList.insert("text:description", m_help);
645   }
646   else
647     return Field::send(listener, state);
648   listener->insertField(field);
649   return true;
650 }
651 
652 //! Internal: a pageNumber field
653 struct FieldPageNumber final : public Field {
654   //! constructor
FieldPageNumberSWFieldManagerInternal::FieldPageNumber655   FieldPageNumber()
656     : Field()
657     , m_userString("")
658     , m_offset(0)
659     , m_isOn(true)
660   {
661   }
662   //! copy constructor
FieldPageNumberSWFieldManagerInternal::FieldPageNumber663   explicit FieldPageNumber(Field const &orig) : Field(orig), m_userString(""), m_offset(0), m_isOn(true)
664   {
665   }
666   //! destructor
667   ~FieldPageNumber() final;
668   //! add to send the zone data
669   bool send(STOFFListenerPtr &listener, StarState &state) const final;
670   //! print a field
printSWFieldManagerInternal::FieldPageNumber671   void print(std::ostream &o) const final
672   {
673     Field::print(o);
674     if (!m_userString.empty())
675       o << "userString=" << m_userString.cstr() << ",";
676     if (m_offset) o << "offset=" << m_offset << ",";
677     if (!m_isOn) o << "off,";
678   }
679   //! the userString
680   librevenge::RVNGString m_userString;
681   //! the offset
682   int m_offset;
683   //! a flag to know if isOn
684   bool m_isOn;
685 };
686 
~FieldPageNumber()687 FieldPageNumber::~FieldPageNumber()
688 {
689 }
690 
send(STOFFListenerPtr & listener,StarState & state) const691 bool FieldPageNumber::send(STOFFListenerPtr &listener, StarState &state) const
692 {
693   if (!listener || !listener->canWriteText()) {
694     STOFF_DEBUG_MSG(("SWFieldManagerInternal::FieldPageNumber::send: can not find the listener\n"));
695     return false;
696   }
697   STOFFField field;
698   if (m_type==6) {
699     field.m_propertyList.insert("librevenge:field-type", "text:page-number");
700     if (m_offset<0)
701       field.m_propertyList.insert("text:select-page", "previous");
702     else if (m_offset>0)
703       field.m_propertyList.insert("text:select-page", "next");
704   }
705   else // also 31 which is setPageRef
706     return Field::send(listener, state);
707   //TODO: set the format
708   listener->insertField(field);
709   return true;
710 }
711 
712 //! Internal: a postit field
713 struct FieldPostIt final : public Field {
714   //! constructor
FieldPostItSWFieldManagerInternal::FieldPostIt715   FieldPostIt()
716     : Field()
717     , m_author("")
718     , m_date(0)
719   {
720   }
721   //! copy constructor
FieldPostItSWFieldManagerInternal::FieldPostIt722   explicit FieldPostIt(Field const &orig)
723     : Field(orig)
724     , m_author("")
725     , m_date(0)
726   {
727   }
728   //! destructor
729   ~FieldPostIt() final;
730   //! add to send the zone data
731   bool send(STOFFListenerPtr &listener, StarState &state) const final;
732   //! print a field
printSWFieldManagerInternal::FieldPostIt733   void print(std::ostream &o) const final
734   {
735     Field::print(o);
736     if (!m_author.empty()) o << "author=" << m_author.cstr() << ",";
737     if (m_date) o << "date=" << m_date << ",";
738   }
739   //! the author
740   librevenge::RVNGString m_author;
741   //! the date
742   long m_date;
743 };
744 
~FieldPostIt()745 FieldPostIt::~FieldPostIt()
746 {
747 }
748 
749 //! Internal: a script field
750 struct FieldScript final : public Field {
751   //! constructor
FieldScriptSWFieldManagerInternal::FieldScript752   FieldScript()
753     : Field()
754     , m_code("")
755     , m_scriptType("")
756   {
757   }
758   //! copy constructor
FieldScriptSWFieldManagerInternal::FieldScript759   explicit FieldScript(Field const &orig)
760     : Field(orig)
761     , m_code("")
762     , m_scriptType("")
763   {
764   }
765   //! destructor
766   ~FieldScript() final;
767   //! print a field
printSWFieldManagerInternal::FieldScript768   void print(std::ostream &o) const final
769   {
770     Field::print(o);
771     if (!m_code.empty()) o << "code=" << m_code.cstr() << ",";
772     if (!m_scriptType.empty()) o << "script[type]=" << m_scriptType.cstr() << ",";
773   }
774   //! the code
775   librevenge::RVNGString m_code;
776   //! the scriptType
777   librevenge::RVNGString m_scriptType;
778 };
779 
~FieldScript()780 FieldScript::~FieldScript()
781 {
782 }
783 
784 //! Internal: a set expr field
785 struct FieldSetExp final : public Field {
786   //! constructor
FieldSetExpSWFieldManagerInternal::FieldSetExp787   FieldSetExp()
788     : Field()
789     , m_fieldType(0)
790     , m_formula("")
791     , m_prompt("")
792     , m_seqVal(0)
793     , m_seqNo(0)
794     , m_delim('.')
795   {
796   }
797   //! copy constructor
FieldSetExpSWFieldManagerInternal::FieldSetExp798   explicit FieldSetExp(Field const &orig)
799     : Field(orig)
800     , m_fieldType(0)
801     , m_formula("")
802     , m_prompt("")
803     , m_seqVal(0)
804     , m_seqNo(0)
805     , m_delim('.')
806   {
807   }
808   //! destructor
809   ~FieldSetExp() final;
810   //! add to send the zone data
811   bool send(STOFFListenerPtr &listener, StarState &state) const final;
812   //! print a field
printSWFieldManagerInternal::FieldSetExp813   void print(std::ostream &o) const final
814   {
815     Field::print(o);
816     if (m_fieldType) o << "fieldType=" << m_fieldType << ",";
817     if (!m_formula.empty()) o << "formula=" << m_formula.cstr() << ",";
818     if (!m_prompt.empty()) o << "prompt=" << m_prompt.cstr() << ",";
819     if (m_seqVal) o << "seqVal=" << m_seqVal << ",";
820     if (m_seqNo) o << "seqNo=" << m_seqNo << ",";
821     if (m_delim!='.') o << "delim=" << m_delim << ",";
822   }
823   //! the field type
824   int m_fieldType;
825   //! the formula
826   librevenge::RVNGString m_formula;
827   //! the prompt
828   librevenge::RVNGString m_prompt;
829   //! the seq value
830   int m_seqVal;
831   //! the seq number
832   int m_seqNo;
833   //! the deliminator
834   char m_delim;
835 };
836 
~FieldSetExp()837 FieldSetExp::~FieldSetExp()
838 {
839 }
840 
send(STOFFListenerPtr & listener,StarState & state) const841 bool FieldSetExp::send(STOFFListenerPtr &listener, StarState &state) const
842 {
843   if (!listener || !listener->canWriteText()) {
844     STOFF_DEBUG_MSG(("SWFieldManagerInternal::FieldSetExp::send: can not find the listener\n"));
845     return false;
846   }
847   //TODO: set the format
848   STOFFField field;
849   if (m_type==11) {
850     if (m_format&8) // we must also set text:ref-name
851       field.m_propertyList.insert("librevenge:field-type", "text:sequence");
852     else
853       field.m_propertyList.insert("librevenge:field-type", "text:variable-set");
854     if (!m_name.empty())
855       field.m_propertyList.insert("text:name", m_name);
856     if (!m_formula.empty()) {
857       if (m_format&8)
858         field.m_propertyList.insert("text:formula", m_formula);
859       else
860         field.m_propertyList.insert("office:string-value", m_formula);
861     }
862     if (!m_content.empty())
863       field.m_propertyList.insert("librevenge:field-content", m_content);
864   }
865   else
866     return Field::send(listener, state);
867   listener->insertField(field);
868   return true;
869 }
870 
871 //! Internal: a set field field
872 struct FieldSetField final : public Field {
873   //! constructor
FieldSetFieldSWFieldManagerInternal::FieldSetField874   FieldSetField()
875     : Field()
876     , m_condition("")
877     , m_dbName("")
878     , m_textNumber("")
879     , m_longNumber(0)
880   {
881   }
882   //! copy constructor
FieldSetFieldSWFieldManagerInternal::FieldSetField883   explicit FieldSetField(Field const &orig)
884     : Field(orig)
885     , m_condition("")
886     , m_dbName("")
887     , m_textNumber("")
888     , m_longNumber(0)
889   {
890   }
891   //! destructor
892   ~FieldSetField() final;
893   //! add to send the zone data
894   bool send(STOFFListenerPtr &listener, StarState &state) const final;
895   //! print a field
printSWFieldManagerInternal::FieldSetField896   void print(std::ostream &o) const final
897   {
898     Field::print(o);
899     if (!m_condition.empty()) o << "condition=" << m_condition.cstr() << ",";
900     if (!m_dbName.empty()) o << "dbName=" << m_dbName.cstr() << ",";
901     if (!m_textNumber.empty()) o << "number=" << m_textNumber.cstr() << ",";
902     else if (m_longNumber) o << "number=" << m_longNumber << ",";
903   }
904   //! the condition
905   librevenge::RVNGString m_condition;
906   //! the dbName
907   librevenge::RVNGString m_dbName;
908   //! the number as text
909   librevenge::RVNGString m_textNumber;
910   //! the number as num
911   long m_longNumber;
912 };
913 
~FieldSetField()914 FieldSetField::~FieldSetField()
915 {
916 }
917 
send(STOFFListenerPtr & listener,StarState & state) const918 bool FieldSetField::send(STOFFListenerPtr &listener, StarState &state) const
919 {
920   if (!listener || !listener->canWriteText()) {
921     STOFF_DEBUG_MSG(("SWFieldManagerInternal::FieldSetField::send: can not find the listener\n"));
922     return false;
923   }
924   //TODO: set the format
925   STOFFField field;
926   if (m_type==28) {
927     field.m_propertyList.insert("librevenge:field-type", "text:database-row-select");
928     updateDatabaseName(m_dbName, field.m_propertyList);
929     if (!m_condition.empty())
930       field.m_propertyList.insert("text:condition", m_condition);
931     if (!m_textNumber.empty())
932       field.m_propertyList.insert("text:row-number", m_textNumber);
933     else
934       field.m_propertyList.insert("text:row-number", int(m_longNumber));
935     // CHECKME: we need to set also text:table-type
936   }
937   else // also 27,29...
938     return Field::send(listener, state);
939   listener->insertField(field);
940   return true;
941 }
942 
943 ////////////////////////////////////////
944 //! Internal: the state of a SWFieldManager
945 struct State {
946   //! constructor
StateSWFieldManagerInternal::State947   State()
948   {
949   }
950 };
951 
952 ////////////////////////////////////////
953 //! Internal: the subdocument of a SWFieldManger
954 class SubDocument final : public STOFFSubDocument
955 {
956 public:
SubDocument(librevenge::RVNGString const & text)957   explicit SubDocument(librevenge::RVNGString const &text)
958     : STOFFSubDocument(nullptr, STOFFInputStreamPtr(), STOFFEntry())
959     , m_text(text) {}
960 
961   //! destructor
~SubDocument()962   ~SubDocument() override {}
963 
964   //! operator!=
operator !=(STOFFSubDocument const & doc) const965   bool operator!=(STOFFSubDocument const &doc) const final
966   {
967     if (STOFFSubDocument::operator!=(doc)) return true;
968     auto const *sDoc = dynamic_cast<SubDocument const *>(&doc);
969     if (!sDoc) return true;
970     if (m_text != sDoc->m_text) return true;
971     return false;
972   }
973 
974   //! the parser function
975   void parse(STOFFListenerPtr &listener, libstoff::SubDocumentType type) final;
976 
977 protected:
978   //! the text
979   librevenge::RVNGString m_text;
980 };
981 
parse(STOFFListenerPtr & listener,libstoff::SubDocumentType)982 void SubDocument::parse(STOFFListenerPtr &listener, libstoff::SubDocumentType /*type*/)
983 {
984   if (!listener.get()) {
985     STOFF_DEBUG_MSG(("SWFielManagerInternal::SubDocument::parse: no listener\n"));
986     return;
987   }
988   if (m_text.empty())
989     listener->insertChar(' ');
990   else
991     listener->insertUnicodeString(m_text);
992 }
993 
send(STOFFListenerPtr & listener,StarState & state) const994 bool FieldPostIt::send(STOFFListenerPtr &listener, StarState &state) const
995 {
996   if (!listener || !listener->canWriteText()) {
997     STOFF_DEBUG_MSG(("SWFieldManagerInternal::FieldPostIt::send: can not find the listener\n"));
998     return false;
999   }
1000   if (m_type==14) {
1001     std::shared_ptr<STOFFSubDocument> doc(new SubDocument(m_content));
1002     librevenge::RVNGString date;
1003     if (m_date)
1004       date.sprintf("%d/%d/%d", int((m_date/100)%100), int(m_date%100), int(m_date/10000));
1005     listener->insertComment(doc, m_author, date);
1006     return true;
1007   }
1008   return Field::send(listener, state);
1009 }
1010 
1011 }
1012 
1013 ////////////////////////////////////////////////////////////
1014 // constructor/destructor, ...
1015 ////////////////////////////////////////////////////////////
SWFieldManager()1016 SWFieldManager::SWFieldManager()
1017   : m_state(new SWFieldManagerInternal::State)
1018 {
1019 }
1020 
~SWFieldManager()1021 SWFieldManager::~SWFieldManager()
1022 {
1023 }
1024 
readField(StarZone & zone,unsigned char cKind)1025 std::shared_ptr<SWFieldManagerInternal::Field> SWFieldManager::readField(StarZone &zone, unsigned char cKind)
1026 {
1027   STOFFInputStreamPtr input=zone.input();
1028   libstoff::DebugFile &ascFile=zone.ascii();
1029   unsigned char type;
1030   long pos=input->tell();
1031   std::shared_ptr<SWFieldManagerInternal::Field> field;
1032   if (cKind!='_' && (input->peek()!=cKind || !zone.openSWRecord(type))) {
1033     input->seek(pos, librevenge::RVNG_SEEK_SET);
1034     return field;
1035   }
1036 
1037   // sw_sw3field.cxx inFieldType('Y') or inField('y' or '_')
1038   field.reset(new SWFieldManagerInternal::Field);
1039   libstoff::DebugStream f;
1040   if (cKind!='_')
1041     f << "Entries(SWFieldType)[" << cKind << "-" << zone.getRecordLevel() << "]:";
1042   else
1043     f << "Entries(SWFieldType)[" << zone.getRecordLevel() << "]:";
1044   field->m_type=int(input->readULong(cKind=='Y' ? 1 : 2));
1045   if (cKind!='Y') {
1046     if (zone.isCompatibleWith(0x202)) {
1047       field->m_format=int(input->readULong(4));
1048       field->m_subType=int(input->readULong(2));
1049     }
1050     else if (zone.isCompatibleWith(0x200))
1051       field->m_format=int(input->readULong(4));
1052     else
1053       field->m_format=int(input->readULong(2));
1054   }
1055   int val;
1056   std::vector<uint32_t> name;
1057   librevenge::RVNGString poolName;
1058   long lastPos=zone.getRecordLastPosition();
1059   switch (field->m_type) {
1060   case 0: { // dbfld: cKind=='Y' call lcl_sw3io_InDBFieldType
1061     std::shared_ptr<SWFieldManagerInternal::FieldDBField> dBField(new SWFieldManagerInternal::FieldDBField(*field));
1062     field=dBField;
1063     if (cKind=='Y' || !zone.isCompatibleWith(0x202)) {
1064       if (!zone.isCompatibleWith(0xa)) {
1065         if (!zone.readString(name)) {
1066           f << "###string,";
1067           STOFF_DEBUG_MSG(("SWFieldManager::readField: can not read a string\n"));
1068           break;
1069         }
1070         else
1071           dBField->m_colName=libstoff::getString(name);
1072       }
1073       else {
1074         val=int(input->readULong(2));
1075         if (!zone.getPoolName(val, dBField->m_colName))
1076           f << "###nPoolId=" << val << ",";
1077       }
1078       if (cKind=='Y') {
1079         if (zone.isCompatibleWith(0x10,0x22, 0x101)) {
1080           val=int(input->readULong(2));
1081           if (!zone.getPoolName(val, dBField->m_dbName)) // dbName
1082             f << "###nDbName=" << val << ",";
1083         }
1084         break;
1085       }
1086       // lcl_sw3io_InDBField40
1087       if (!zone.readString(name)) {
1088         f << "###expand,";
1089         STOFF_DEBUG_MSG(("SWFieldManager::readField: can not read a string\n"));
1090         break;
1091       }
1092       else if (!name.empty())
1093         field->m_content=libstoff::getString(name); // expand
1094       if (zone.isCompatibleWith(0xa))
1095         f << "cFlag=" << std::hex << input->readULong(1) << std::dec << ",";
1096       if (zone.isCompatibleWith(0x10,0x22, 0x101)) {
1097         val=int(input->readULong(2));
1098         if (!zone.getPoolName(val, dBField->m_dbName)) // dbName
1099           f << "###nDbName=" << val << ",";
1100       }
1101       break;
1102     }
1103     // lcl_sw3io_InDBField
1104     auto cFlag=int(input->readULong(1));
1105     if (cFlag)
1106       f << "cFlag=" << std::hex << cFlag << std::dec << ",";
1107     val=int(input->readULong(2));
1108     if (!zone.getPoolName(val, dBField->m_colName)) // colName
1109       f << "###nColNamePoolId=" << val << ",";
1110     val=int(input->readULong(2));
1111     if (!zone.getPoolName(val, dBField->m_dbName))
1112       f << "###dbNamePoolId=" << val << ",";
1113     if (cFlag&1) {
1114       bool isNan;
1115       if (!input->readDoubleReverted8(field->m_doubleValue, isNan)) {
1116         STOFF_DEBUG_MSG(("SWFieldManager::readField: can not read a double\n"));
1117         f << "##value,";
1118       }
1119     }
1120     else if (!zone.readString(name)) {
1121       STOFF_DEBUG_MSG(("SWFieldManager::readField: can not read a string value\n"));
1122       f << "##value,";
1123       break;
1124     }
1125     else
1126       field->m_textValue=libstoff::getString(name);
1127     break;
1128   }
1129   case 1: {
1130     // userfld: cKind==Y lcl_sw3io_InUserFieldType|lcl_sw3io_InUserFieldType40
1131     if (!zone.isCompatibleWith(0xa)) {
1132       if (!zone.readString(name)) {
1133         f << "###string,";
1134         STOFF_DEBUG_MSG(("SWFieldManager::readField: can not read a string\n"));
1135         break;
1136       }
1137       else
1138         field->m_name=libstoff::getString(name);
1139     }
1140     else {
1141       val=int(input->readULong(2));
1142       if (!zone.getPoolName(val, field->m_name))
1143         f << "###name=" << val << ",";
1144     }
1145     if (cKind!='Y' && zone.isCompatibleWith(0xa)) break;
1146     std::vector<uint32_t> text;
1147     if (!zone.readString(text)) {
1148       f << "###aContent,";
1149       STOFF_DEBUG_MSG(("SWFieldManager::readField: can not read a aContent\n"));
1150       break;
1151     }
1152     else
1153       field->m_content=libstoff::getString(text);
1154     if (!zone.isCompatibleWith(0x0202)) {
1155       if (!zone.readString(text)) {
1156         f << "###aValue,";
1157         STOFF_DEBUG_MSG(("SWFieldManager::readField: can not read a aValue\n"));
1158         break;
1159       }
1160       else
1161         field->m_textValue=libstoff::getString(text);
1162     }
1163     else {
1164       bool isNan;
1165       if (!input->readDoubleReverted8(field->m_doubleValue, isNan)) {
1166         STOFF_DEBUG_MSG(("SWFieldManager::readField: can not read a double\n"));
1167         f << "##value,";
1168         break;
1169       }
1170     }
1171     val=int(input->readULong(2)); // StoreMe
1172     f << "type=" << val << ",";
1173     break;
1174   }
1175   case 2:
1176     if (cKind=='Y') break;
1177     // lcl_sw3io_InFileNameField
1178     if (input->tell()>=lastPos) break;
1179     if (!zone.readString(name)) {
1180       f << "###string,";
1181       STOFF_DEBUG_MSG(("SWFieldManager::readField: can not read a string\n"));
1182       break;
1183     }
1184     else if (!name.empty())
1185       field->m_name=libstoff::getString(name);
1186     break;
1187   case 3:
1188     if (cKind=='Y') break;
1189     // lcl_sw3io_InDBNameField
1190     if (zone.isCompatibleWith(0x10,0x22, 0x101)) {
1191       val=int(input->readULong(2));
1192       if (!zone.getPoolName(val, field->m_name))
1193         f << "###nDbName=" << val << ",";
1194     }
1195     break;
1196   case 4:
1197   // lcl_sw3io_InDateField40
1198   case 5:
1199     // lcl_sw3io_InTimeField40
1200     field.reset(new SWFieldManagerInternal::FieldDateTime(*field));
1201     break;
1202   case 6: {
1203     std::shared_ptr<SWFieldManagerInternal::FieldPageNumber> pageNumber(new SWFieldManagerInternal::FieldPageNumber(*field));
1204     field=pageNumber;
1205     if (cKind=='Y') break;
1206     // lcl_sw3io_InPageNumberField40 && lcl_sw3io_InPageNumberField
1207     if (!zone.isCompatibleWith(0x202)) {
1208       pageNumber->m_offset=int(input->readLong(2));
1209       pageNumber->m_subType=int(input->readULong(2)); // 1: next, 2:prev
1210       if (!zone.isCompatibleWith(0x9)) break;
1211       if (!zone.readString(name)) {
1212         f << "###string,";
1213         STOFF_DEBUG_MSG(("SWFieldManager::readField: can not read a string\n"));
1214         break;
1215       }
1216       pageNumber->m_userString=libstoff::getString(name);
1217       if (zone.isCompatibleWith(0x14,0x22) && (pageNumber->m_subType==1 || pageNumber->m_subType==2))
1218         pageNumber->m_offset=int(input->readLong(2));
1219       break;
1220     }
1221     pageNumber->m_offset=int(input->readLong(2));
1222     if (!zone.readString(name)) {
1223       f << "###string,";
1224       STOFF_DEBUG_MSG(("SWFieldManager::readField: can not read a string\n"));
1225       break;
1226     }
1227     pageNumber->m_userString=libstoff::getString(name);
1228     break;
1229   }
1230   case 7:
1231     // lcl_sw3io_InAuthorField
1232     if (cKind=='Y') break;
1233     if (zone.isCompatibleWith(0x204)) {
1234       if (!zone.readString(name)) {
1235         f << "###string,";
1236         STOFF_DEBUG_MSG(("SWFieldManager::readField: can not read a string\n"));
1237         break;
1238       }
1239       field->m_content=libstoff::getString(name);
1240     }
1241     break;
1242   case 8:
1243     if (cKind=='Y') break;
1244     // lcl_sw3io_InChapterField
1245     if (zone.isCompatibleWith(0x9))
1246       field->m_level=int(input->readULong(1));
1247     break;
1248   case 9:
1249     if (cKind=='Y') break;
1250     // lcl_sw3io_InDocStatField40 or lcl_sw3io_InDocStatField
1251     if (!zone.isCompatibleWith(0x202))
1252       field->m_subType=int(input->readULong(2));
1253     break;
1254   case 10:
1255     if (cKind=='Y') break;
1256     // lcl_sw3io_InGetExpField40 or lcl_sw3io_InGetExpField
1257     if (!zone.readString(name)) {
1258       f << "###string,";
1259       STOFF_DEBUG_MSG(("SWFieldManager::readField: can not read a string\n"));
1260       break;
1261     }
1262     field->m_name=libstoff::getString(name);
1263     if (!zone.readString(name)) {
1264       f << "###string,";
1265       STOFF_DEBUG_MSG(("SWFieldManager::readField: can not read a string\n"));
1266       break;
1267     }
1268     field->m_content=libstoff::getString(name).cstr();
1269     if (!zone.isCompatibleWith(0x202)) {
1270       field->m_subType=int(input->readULong(2));
1271     }
1272     break;
1273   case 11: { // setexpfield: ckind=y call lcl_sw3io_InSetExpFieldType
1274     std::shared_ptr<SWFieldManagerInternal::FieldSetExp> setExp(new SWFieldManagerInternal::FieldSetExp(*field));
1275     field=setExp;
1276     if (cKind!='Y' && zone.isCompatibleWith(0x202)) {
1277       // lcl_sw3io_InSetExpField
1278       auto cFlags=int(input->readULong(1));
1279       if (cFlags) f << "flag=" << cFlags << ",";
1280       val=int(input->readULong(2));
1281       if (!zone.getPoolName(val, field->m_name)) // checkme
1282         f << "###nName=" << val << ",";
1283       if (!zone.readString(name)) {
1284         f << "###formula,";
1285         STOFF_DEBUG_MSG(("SWFieldManager::readField: can not read a string\n"));
1286         break;
1287       }
1288       else
1289         setExp->m_formula=libstoff::getString(name);
1290       if (cFlags & 0x10) {
1291         if (!zone.readString(name)) {
1292           f << "###prompt,";
1293           STOFF_DEBUG_MSG(("SWFieldManager::readField: can not read a string\n"));
1294           break;
1295         }
1296         else
1297           setExp->m_prompt=libstoff::getString(name);
1298       }
1299       if (cFlags & 0x20) {
1300         setExp->m_seqVal=int(input->readULong(2));
1301         setExp->m_seqNo=int(input->readULong(2));
1302       }
1303       if (cFlags & 0x40) {
1304         if (!zone.readString(name)) {
1305           f << "###expand,";
1306           STOFF_DEBUG_MSG(("SWFieldManager::readField: can not read a string\n"));
1307           break;
1308         }
1309         else
1310           field->m_content=libstoff::getString(name);
1311       }
1312       break;
1313     }
1314     if (cKind=='Y')
1315       setExp->m_fieldType=int(input->readULong(2));
1316     if (!zone.isCompatibleWith(0xa)) {
1317       if (!zone.readString(name)) {
1318         f << "###string,";
1319         STOFF_DEBUG_MSG(("SWFieldManager::readField: can not read a string\n"));
1320         break;
1321       }
1322       else
1323         field->m_name=libstoff::getString(name);
1324     }
1325     else {
1326       val=int(input->readULong(2));
1327       if (!zone.getPoolName(val, field->m_name))
1328         f << "###name=" << val << ",";
1329     }
1330     if (cKind=='Y') {
1331       if ((setExp->m_fieldType&8) && zone.isCompatibleWith(0x202)) {
1332         setExp->m_delim=char(input->readULong(1));
1333         setExp->m_level=int(input->readULong(1));
1334       }
1335       break;
1336     }
1337     // lcl_sw3io_InSetExpField40 end
1338     auto cFlags=int(input->readULong(1));
1339     if (cFlags)
1340       f << "cFlags=" << cFlags << ",";
1341     if (!zone.readString(name)) {
1342       f << "###formula,";
1343       STOFF_DEBUG_MSG(("SWFieldManager::readField: can not read a string\n"));
1344       break;
1345     }
1346     else
1347       setExp->m_formula=libstoff::getString(name);
1348     if (!zone.readString(name)) {
1349       f << "###expand,";
1350       STOFF_DEBUG_MSG(("SWFieldManager::readField: can not read a string\n"));
1351       break;
1352     }
1353     else
1354       setExp->m_content=libstoff::getString(name);
1355     if ((cFlags & 0x10) && zone.isCompatibleWith(0x10)) {
1356       if (!zone.readString(name)) {
1357         f << "###prompt,";
1358         STOFF_DEBUG_MSG(("SWFieldManager::readField: can not read a string\n"));
1359         break;
1360       }
1361       else
1362         setExp->m_prompt=libstoff::getString(name);
1363     }
1364     if (cFlags & 0x20)
1365       setExp->m_seqNo=int(input->readULong(2));
1366     break;
1367   }
1368   case 12:
1369     if (cKind=='Y') break;
1370     // lcl_sw3io_InGetRefField40 or lcl_sw3io_InGetRefField
1371     if (!zone.readString(name)) {
1372       f << "###string,";
1373       STOFF_DEBUG_MSG(("SWFieldManager::readField: can not read a string\n"));
1374       break;
1375     }
1376     else
1377       field->m_name=libstoff::getString(name);
1378     if (!zone.readString(name)) {
1379       f << "###string,";
1380       STOFF_DEBUG_MSG(("SWFieldManager::readField: can not read a string\n"));
1381       break;
1382     }
1383     else
1384       field->m_content=libstoff::getString(name);
1385     if (zone.isCompatibleWith(0x21,0x22)) {
1386       field->m_format=int(input->readULong(2));
1387       field->m_subType=int(input->readULong(2));
1388     }
1389     else if (zone.isCompatibleWith(0x101,0x202))
1390       field->m_subType=int(input->readULong(2));
1391     f << "nSeqNo=" << input->readULong(2) << ",";
1392     break;
1393   case 13: {
1394     std::shared_ptr<SWFieldManagerInternal::FieldHiddenText> hiddenText(new SWFieldManagerInternal::FieldHiddenText(*field));
1395     field=hiddenText;
1396     if (cKind=='Y') break;
1397     // lcl_sw3io_InHiddenTxtField40 or lcl_sw3io_InHiddenTxtField
1398     f << "cFlags=" << input->readULong(1) << ",";
1399     if (!zone.readString(name)) {
1400       f << "###string,";
1401       STOFF_DEBUG_MSG(("SWFieldManager::readField: can not read a string\n"));
1402       break;
1403     }
1404     else
1405       hiddenText->m_content=libstoff::getString(name);
1406     if (!zone.readString(name)) {
1407       f << "###string,";
1408       STOFF_DEBUG_MSG(("SWFieldManager::readField: can not read a string\n"));
1409       break;
1410     }
1411     else
1412       hiddenText->m_condition=libstoff::getString(name);
1413     if (!zone.isCompatibleWith(0x202))
1414       field->m_subType=int(input->readULong(2));
1415     break;
1416   }
1417   case 14: {
1418     std::shared_ptr<SWFieldManagerInternal::FieldPostIt> postIt(new SWFieldManagerInternal::FieldPostIt(*field));
1419     field=postIt;
1420     if (cKind=='Y') break;
1421     // lcl_sw3io_InPostItField
1422     postIt->m_date=long(input->readULong(4));
1423     if (!zone.readString(name)) {
1424       f << "###string,";
1425       STOFF_DEBUG_MSG(("SWFieldManager::readField: can not read a string\n"));
1426       break;
1427     }
1428     else
1429       postIt->m_author=libstoff::getString(name);
1430     if (!zone.readString(name)) {
1431       f << "###string,";
1432       STOFF_DEBUG_MSG(("SWFieldManager::readField: can not read a string\n"));
1433       break;
1434     }
1435     else if (!name.empty())
1436       postIt->m_content=libstoff::getString(name);
1437     break;
1438   }
1439   case 15: // date
1440   case 16: { // time
1441     std::shared_ptr<SWFieldManagerInternal::FieldDateTime> dateTime(new SWFieldManagerInternal::FieldDateTime(*field));
1442     field=dateTime;
1443     if (cKind=='Y' || zone.isCompatibleWith(0x202)) break;
1444     // lcl_sw3io_InFixDateField40 or lcl_sw3io_InFixTimeField40
1445     dateTime->m_dateTime=long(input->readULong(4));
1446     break;
1447   }
1448   case 17:
1449     // unknown code
1450     break;
1451   case 18:
1452     // unknown code
1453     break;
1454   case 19:
1455     // unknown code
1456     break;
1457   case 20:
1458     if (cKind=='Y') break;
1459     // lcl_sw3io_InInputField40 or lcl_sw3io_InInputField
1460     if (!zone.readString(name)) {
1461       f << "###string,";
1462       STOFF_DEBUG_MSG(("SWFieldManager::readField: can not read a string\n"));
1463       break;
1464     }
1465     field->m_content=libstoff::getString(name);
1466     if (!zone.readString(name)) {
1467       f << "###string,";
1468       STOFF_DEBUG_MSG(("SWFieldManager::readField: can not read a string\n"));
1469       break;
1470     }
1471     else
1472       field->m_name=libstoff::getString(name); // the prompt
1473     if (!zone.isCompatibleWith(0x202))
1474       field->m_subType=int(input->readULong(2));
1475     break;
1476   case 21:
1477     if (cKind=='Y') break;
1478     // lcl_sw3io_InMacroField
1479     if (!zone.readString(name)) {
1480       f << "###string,";
1481       STOFF_DEBUG_MSG(("SWFieldManager::readField: can not read a string\n"));
1482       break;
1483     }
1484     else
1485       field->m_name=libstoff::getString(name);
1486     if (!zone.readString(name)) {
1487       f << "###string,";
1488       STOFF_DEBUG_MSG(("SWFieldManager::readField: can not read a string\n"));
1489       break;
1490     }
1491     else
1492       field->m_content=libstoff::getString(name);
1493     break;
1494   case 22: { // ddefld: cKind=Y call lcl_sw3io_InDDEFieldType
1495     if (cKind!='Y' && !zone.isCompatibleWith(0xa)) {
1496       val=int(input->readULong(2));
1497       if (!zone.getPoolName(val, field->m_name))
1498         f << "###name=" << val << ",";
1499       break;
1500     }
1501     // lcl_sw3io_InDDEField
1502     val=int(input->readULong(2));
1503     f << "nType=" << val << ","; // linkAlway, onUpdate, ...
1504     if (!zone.isCompatibleWith(0xa)) {
1505       if (!zone.readString(name)) {
1506         f << "###string,";
1507         STOFF_DEBUG_MSG(("SWFieldManager::readField: can not read a string\n"));
1508         break;
1509       }
1510       else
1511         field->m_name=libstoff::getString(name);
1512     }
1513     else {
1514       val=int(input->readULong(2));
1515       if (!zone.getPoolName(val, field->m_name))
1516         f << "###name=" << val << ",";
1517     }
1518     std::vector<uint32_t> text;
1519     if (!zone.readString(text)) {
1520       f << "###text,";
1521       STOFF_DEBUG_MSG(("SWFieldManager::readField: can not read a text\n"));
1522       break;
1523     }
1524     else
1525       field->m_content=libstoff::getString(text);
1526     break;
1527   }
1528   case 23:
1529     if (cKind=='Y') break;
1530     // lcl_sw3io_InTblField
1531     if (!zone.readString(name)) {
1532       f << "###string,";
1533       STOFF_DEBUG_MSG(("SWFieldManager::readField: can not read a string\n"));
1534       break;
1535     }
1536     else // formula
1537       field->m_name=libstoff::getString(name);
1538     if (!zone.readString(name)) {
1539       f << "###string,";
1540       STOFF_DEBUG_MSG(("SWFieldManager::readField: can not read a string\n"));
1541       break;
1542     }
1543     else
1544       field->m_content=libstoff::getString(name).cstr();
1545     if (!zone.isCompatibleWith(0x202))
1546       field->m_subType=int(input->readULong(2));
1547     break;
1548   case 24: {
1549     std::shared_ptr<SWFieldManagerInternal::FieldHiddenText> hiddenPara(new SWFieldManagerInternal::FieldHiddenText(*field));
1550     field=hiddenPara;
1551     if (cKind=='Y') break;
1552     // lcl_sw3io_InHiddenParaField
1553     *input >> hiddenPara->m_hidden;
1554     if (!zone.readString(name)) {
1555       f << "###string,";
1556       STOFF_DEBUG_MSG(("SWFieldManager::readField: can not read a string\n"));
1557       break;
1558     }
1559     else
1560       hiddenPara->m_condition=libstoff::getString(name);
1561     break;
1562   }
1563   case 25:
1564     if (cKind=='Y') break;
1565     // lcl_sw3io_InDocInfoField40 or lcl_sw3io_InDocInfoField
1566     if (!zone.isCompatibleWith(0x202))
1567       field->m_subType=int(input->readULong(2));
1568     else {
1569       auto flag=int(input->readULong(1));
1570       if (!zone.readString(name)) {
1571         f << "###string,";
1572         STOFF_DEBUG_MSG(("SWFieldManager::readField: can not read a string\n"));
1573         break;
1574       }
1575       else
1576         field->m_content=libstoff::getString(name);
1577       if (flag&1) {
1578         bool isNan;
1579         if (!input->readDoubleReverted8(field->m_doubleValue, isNan)) {
1580           STOFF_DEBUG_MSG(("SWFieldManager::readField: can not read a double\n"));
1581           f << "##value,";
1582           break;
1583         }
1584       }
1585     }
1586     break;
1587   case 26:
1588     // lcl_sw3io_InTemplNameField
1589     break;
1590   case 27: {
1591     std::shared_ptr<SWFieldManagerInternal::FieldSetField> setField(new SWFieldManagerInternal::FieldSetField(*field));
1592     field=setField;
1593     if (cKind=='Y') break;
1594     // lcl_sw3io_InDBNextSetField
1595     if (!zone.readString(name)) {
1596       f << "###string,";
1597       STOFF_DEBUG_MSG(("SWFieldManager::readField: can not read a string\n"));
1598       break;
1599     }
1600     else
1601       setField->m_condition=libstoff::getString(name);
1602     if (!zone.readString(name)) {
1603       f << "###string,";
1604       STOFF_DEBUG_MSG(("SWFieldManager::readField: can not read a string\n"));
1605       break;
1606     }
1607     else
1608       setField->m_name=libstoff::getString(name).cstr();
1609     if (zone.isCompatibleWith(0x10,0x22, 0x101)) {
1610       val=int(input->readULong(2));
1611       if (!zone.getPoolName(val, setField->m_dbName))
1612         f << "###dbName=" << val << ",";
1613     }
1614     break;
1615   }
1616   case 28: {
1617     std::shared_ptr<SWFieldManagerInternal::FieldSetField> setField(new SWFieldManagerInternal::FieldSetField(*field));
1618     field=setField;
1619     if (cKind=='Y') break;
1620     // lcl_sw3io_InDBNumSetField
1621     bool inverted=(zone.isCompatibleWith(0x22,0x101));
1622     if (!zone.readString(name)) {
1623       f << "###string,";
1624       STOFF_DEBUG_MSG(("SWFieldManager::readField: can not read a string\n"));
1625       break;
1626     }
1627     else if (inverted)
1628       setField->m_textNumber=libstoff::getString(name);
1629     else
1630       setField->m_condition=libstoff::getString(name);
1631     if (!zone.readString(name)) {
1632       f << "###string,";
1633       STOFF_DEBUG_MSG(("SWFieldManager::readField: can not read a string\n"));
1634       break;
1635     }
1636     else if (!inverted)
1637       setField->m_textNumber=libstoff::getString(name);
1638     else
1639       setField->m_condition=libstoff::getString(name);
1640     if (zone.isCompatibleWith(0x10,0x22, 0x101)) {
1641       val=int(input->readULong(2));
1642       if (!zone.getPoolName(val, setField->m_dbName))
1643         f << "###dbName=" << val << ",";
1644     }
1645     break;
1646   }
1647   case 29: {
1648     std::shared_ptr<SWFieldManagerInternal::FieldSetField> setField(new SWFieldManagerInternal::FieldSetField(*field));
1649     field=setField;
1650     if (cKind=='Y') break;
1651     // lcl_sw3io_InDBSetNumberField
1652     setField->m_longNumber=long(input->readULong(4));
1653     if (zone.isCompatibleWith(0x10,0x22, 0x101)) {
1654       val=int(input->readULong(2));
1655       if (!zone.getPoolName(val, setField->m_dbName))
1656         f << "###dbName=" << val << ",";
1657     }
1658     break;
1659   }
1660   case 30:
1661     if (cKind=='Y') break;
1662     // lcl_sw3io_InExtUserField40 or lcl_sw3io_InExtUserField
1663     if (!zone.readString(name)) {
1664       f << "###string,";
1665       STOFF_DEBUG_MSG(("SWFieldManager::readField: can not read a string\n"));
1666       break;
1667     }
1668     else // data
1669       field->m_name=libstoff::getString(name);
1670     if (!zone.isCompatibleWith(0x202))
1671       field->m_subType=int(input->readULong(2));
1672     else if (zone.isCompatibleWith(0x204)) {
1673       if (!zone.readString(name)) {
1674         f << "###string,";
1675         STOFF_DEBUG_MSG(("SWFieldManager::readField: can not read a string\n"));
1676         break;
1677       }
1678       else
1679         field->m_content=libstoff::getString(name);
1680     }
1681     break;
1682   case 31: {
1683     std::shared_ptr<SWFieldManagerInternal::FieldPageNumber> pageNumber(new SWFieldManagerInternal::FieldPageNumber(*field));
1684     field=pageNumber;
1685     if (cKind=='Y') break;
1686     // lcl_sw3io_InRefPageSetField
1687     pageNumber->m_offset=int(input->readLong(2));
1688     *input >> pageNumber->m_isOn;
1689     break;
1690   }
1691   case 32:
1692     if (cKind=='Y') break;
1693     // lcl_sw3io_InRefPageGetField
1694     if (!zone.readString(name)) {
1695       f << "###string,";
1696       STOFF_DEBUG_MSG(("SWFieldManager::readField: can not read a string\n"));
1697       break;
1698     }
1699     else
1700       field->m_content=libstoff::getString(name);
1701     break;
1702   case 33: {
1703     std::shared_ptr<SWFieldManagerInternal::FieldINet> iNet(new SWFieldManagerInternal::FieldINet(*field));
1704     field=iNet;
1705     if (cKind=='Y' || zone.isCompatibleWith(0x202)) break;
1706     // lcl_sw3io_InINetField31
1707     if (!zone.readString(name)) {
1708       f << "###string,";
1709       STOFF_DEBUG_MSG(("SWFieldManager::readField: can not read a string\n"));
1710       break;
1711     }
1712     else
1713       iNet->m_url=libstoff::getString(name).cstr();
1714     if (!zone.readString(name)) {
1715       f << "###string,";
1716       STOFF_DEBUG_MSG(("SWFieldManager::readField: can not read a string\n"));
1717       break;
1718     }
1719     else // text
1720       iNet->m_content=libstoff::getString(name);
1721     if (zone.isCompatibleWith(0x11,0x22)) {
1722       if (!zone.readString(name)) {
1723         f << "###string,";
1724         STOFF_DEBUG_MSG(("SWFieldManager::readField: can not read a string\n"));
1725         break;
1726       }
1727       else
1728         iNet->m_target=libstoff::getString(name);
1729     }
1730     if (zone.isCompatibleWith(0x11,0x13)) {
1731       auto nCnt=int(input->readULong(2));
1732       for (int i=0; i<nCnt; ++i) {
1733         if (input->tell()>lastPos) {
1734           STOFF_DEBUG_MSG(("SWFieldManager::readField: can not read a libmac name\n"));
1735           f << "###libname,";
1736           break;
1737         }
1738         if (!zone.readString(name)) {
1739           f << "###string,";
1740           STOFF_DEBUG_MSG(("SWFieldManager::readField: can not read a string\n"));
1741           break;
1742         }
1743         else
1744           iNet->m_libNames.push_back(libstoff::getString(name).cstr());
1745         if (!zone.readString(name)) {
1746           f << "###string,";
1747           STOFF_DEBUG_MSG(("SWFieldManager::readField: can not read a string\n"));
1748           break;
1749         }
1750         else
1751           iNet->m_libNames.push_back(libstoff::getString(name).cstr());
1752       }
1753     }
1754     break;
1755   }
1756   case 34: {
1757     std::shared_ptr<SWFieldManagerInternal::FieldJumpEdit> jumpEdit(new SWFieldManagerInternal::FieldJumpEdit(*field));
1758     field=jumpEdit;
1759     if (cKind=='Y') break;
1760     // lcl_sw3io_InJumpEditField
1761     if (!zone.readString(name)) {
1762       f << "###string,";
1763       STOFF_DEBUG_MSG(("SWFieldManager::readField: can not read a string\n"));
1764       break;
1765     }
1766     else
1767       field->m_content=libstoff::getString(name);
1768     if (!zone.readString(name)) {
1769       f << "###string,";
1770       STOFF_DEBUG_MSG(("SWFieldManager::readField: can not read a string\n"));
1771       break;
1772     }
1773     else
1774       jumpEdit->m_help=libstoff::getString(name);
1775     break;
1776   }
1777   case 35: {
1778     std::shared_ptr<SWFieldManagerInternal::FieldScript> script(new SWFieldManagerInternal::FieldScript(*field));
1779     field=script;
1780     if (cKind=='Y') break;
1781     // lcl_sw3io_InScriptField40 or lcl_sw3io_InScriptField
1782     if (!zone.readString(name)) {
1783       f << "###string,";
1784       STOFF_DEBUG_MSG(("SWFieldManager::readField: can not read a string\n"));
1785       break;
1786     }
1787     else
1788       script->m_scriptType=libstoff::getString(name);
1789     if (!zone.readString(name)) {
1790       f << "###string,";
1791       STOFF_DEBUG_MSG(("SWFieldManager::readField: can not read a string\n"));
1792       break;
1793     }
1794     else
1795       script->m_code=libstoff::getString(name);
1796     if (zone.isCompatibleWith(0x200))
1797       f << "cFlags=" << input->readULong(1) << ",";
1798     break;
1799   }
1800   case 36: {
1801     std::shared_ptr<SWFieldManagerInternal::FieldDateTime> dateTime(new SWFieldManagerInternal::FieldDateTime(*field));
1802     field=dateTime;
1803     if (cKind=='Y' || !zone.isCompatibleWith(0x202)) break;
1804     // lcl_sw3io_InDateTimeField
1805     bool isNan;
1806     if (!input->readDoubleReverted8(dateTime->m_doubleValue, isNan)) {
1807       STOFF_DEBUG_MSG(("SWFieldManager::readField: can not read a double\n"));
1808       f << "##value,";
1809       break;
1810     }
1811     if (zone.isCompatibleWith(0x205))
1812       dateTime->m_offset=long(input->readULong(4));
1813     break;
1814   }
1815   case 37: { // cKind==Y call lcl_sw3io_InAuthorityFieldType
1816     // TODO: store me
1817     if (cKind!='Y' && zone.isCompatibleWith(0x202)) {
1818       // lcl_sw3io_InAuthorityField
1819       zone.openFlagZone();
1820       f << "nPos=" << input->readULong(2) << ",";
1821       zone.closeFlagZone();
1822       break;
1823     }
1824     if (cKind!='Y') break;
1825     val=int(zone.openFlagZone());
1826     if (val&0xf0) f << "flag=" << (val>>4) << ",";
1827     auto N=int(input->readULong(2));
1828     if (N) f << "N=" << N << ",";
1829     val=int(input->readULong(1));
1830     if (val) f << "cPrefix=" << val << ",";
1831     val=int(input->readULong(1));
1832     if (val) f << "cSuffix=" << val << ",";
1833     auto nSort=int(input->readULong(2));
1834     if (nSort) f << "cSortCount=" << nSort << ",";
1835     zone.closeFlagZone();
1836 
1837     bool ok=true;
1838     for (int i=0; i<N; ++i) {
1839       long actPos=input->tell();
1840       input->seek(actPos, librevenge::RVNG_SEEK_SET);
1841 
1842       unsigned char authType;
1843       libstoff::DebugStream f2;
1844       f2<<"SWFieldType[auth-A" << i << "]:";
1845       if (input->peek()!='E' || !zone.openSWRecord(authType)) {
1846         STOFF_DEBUG_MSG(("SWFieldManager::readField: can not read an authority zone\n"));
1847 
1848         f2<< "###";
1849         ascFile.addPos(actPos);
1850         ascFile.addNote(f2.str().c_str());
1851         ok=false;
1852         break;
1853       }
1854       ascFile.addPos(actPos);
1855       ascFile.addNote(f2.str().c_str());
1856       zone.closeSWRecord(authType, "SWFieldType");
1857     }
1858     if (!ok || !nSort) break;
1859     long actPos=input->tell();
1860     libstoff::DebugStream f2;
1861     f2<<"SWFieldType[auth-B]:";
1862     if (input->tell()+3*nSort>zone.getRecordLastPosition()) {
1863       STOFF_DEBUG_MSG(("SWFieldManager::readField: can not read sort data\n"));
1864       f2 << "###";
1865       ascFile.addPos(actPos);
1866       ascFile.addNote(f2.str().c_str());
1867       break;
1868     }
1869     f2 << "sort[flag:type]=[";
1870     for (int i=0; i<nSort; ++i) {
1871       f2 << std::hex << input->readULong(1) << std::dec << ":" << input->readULong(2) << ",";
1872     }
1873     f2 << "],";
1874     ascFile.addPos(actPos);
1875     ascFile.addNote(f2.str().c_str());
1876     break;
1877   }
1878   case 38: // combinedChar
1879     break;
1880   case 39: // dropdown108791
1881     break;
1882   default:
1883     STOFF_DEBUG_MSG(("SWFieldManager::readField: find unexpected flag\n"));
1884     break;
1885   }
1886   f << *field;
1887 
1888   if (input->tell()!=zone.getRecordLastPosition() && cKind=='_') {
1889     STOFF_DEBUG_MSG(("SWFieldManager::readField: find extra data\n"));
1890     f << "###extra";
1891     ascFile.addDelimiter(input->tell(),'|');
1892   }
1893   ascFile.addPos(pos);
1894   ascFile.addNote(f.str().c_str());
1895 
1896   if (cKind!='_')
1897     zone.closeSWRecord(cKind, "SWFieldType");
1898   return field;
1899 }
1900 
readPersistField(StarZone & zone,long lastPos)1901 std::shared_ptr<SWFieldManagerInternal::Field> SWFieldManager::readPersistField(StarZone &zone, long lastPos)
1902 {
1903   std::shared_ptr<SWFieldManagerInternal::Field> field;
1904   // pstm.cxx SvPersistStream::ReadObj
1905   STOFFInputStreamPtr input=zone.input();
1906   long pos=input->tell();
1907   libstoff::DebugFile &ascii=zone.ascii();
1908   libstoff::DebugStream f;
1909   f << "Entries(PersistField)["<< zone.getRecordLevel() << "]:";
1910   // SvPersistStream::ReadId
1911   uint8_t hdr;
1912   *input >> hdr;
1913   long id=0, classId=0;
1914   bool ok=true;
1915   if (hdr&0x80) // nId=0
1916     ;
1917   else {
1918     if ((hdr&0xf)==0) {
1919       if ((hdr&0x20) || !(hdr&0x40))
1920         ok=input->readCompressedLong(id);
1921     }
1922     else if (hdr&0x10)
1923       ok=input->readCompressedLong(id);
1924     if (hdr&0x60)
1925       ok=input->readCompressedLong(classId);
1926   }
1927   if (id) f << "id=" << id << ",";
1928   if (classId) f << "id[class]=" << classId << ",";
1929   if (!ok || !hdr || input->tell()>lastPos) {
1930     STOFF_DEBUG_MSG(("SWFieldManager::readPersistField: find unexpected header\n"));
1931     f << "###header";
1932     ascii.addPos(pos);
1933     ascii.addNote(f.str().c_str());
1934     return field;
1935   }
1936   if (hdr&0x80 || (hdr&0x40)==0) {
1937     ascii.addPos(pos);
1938     ascii.addNote(f.str().c_str());
1939     return std::make_shared<SWFieldManagerInternal::Field>();
1940   }
1941   if (hdr&0x20) {
1942     ok=zone.openSCRecord();
1943     if (!ok || zone.getRecordLastPosition()>lastPos) {
1944       STOFF_DEBUG_MSG(("SWFieldManager::readPersistField: can not open main zone\n"));
1945       if (ok) zone.closeSCRecord("PersistField");
1946       f << "###,";
1947       ascii.addPos(pos);
1948       ascii.addNote(f.str().c_str());
1949       return field;
1950     }
1951     lastPos=zone.getRecordLastPosition();
1952   }
1953   if (hdr&0x40) {
1954     switch (classId) {
1955     // case 1 SvxFieldData::
1956     case 2: {
1957       // SvxDateField::Load
1958       if (input->tell()+8>lastPos) {
1959         STOFF_DEBUG_MSG(("SWFieldManager::readPersistField: can not read date field\n"));
1960         f << "###,";
1961         break;
1962       }
1963       auto dateTime=std::make_shared<SWFieldManagerInternal::FieldDateTime>();
1964       field=dateTime;
1965       dateTime->m_type=15;
1966       dateTime->m_dateTime=long(input->readULong(4));
1967       dateTime->m_subType=int(input->readULong(2));
1968       dateTime->m_format=int(input->readULong(2));
1969       if (dateTime->m_dateTime && dateTime->m_subType==1) // type==0: mean fixed
1970         dateTime->m_type=4;
1971       f << "date[field],";
1972       f << "date=" << dateTime->m_dateTime << ",";
1973       f << "type=" << dateTime->m_subType << ",";
1974       f << "format=" << dateTime->m_format << ",";
1975       break;
1976     }
1977     case 3: { // flditem.cxx:void SvxURLField::Load
1978       f << "urlData,";
1979       auto inet=std::make_shared<SWFieldManagerInternal::FieldINet>();
1980       field=inet;
1981       field->m_type=33;
1982       field->m_format=int(input->readULong(2));
1983       if (field->m_format) f << "format=" << field->m_format << ",";
1984       for (int i=0; i<2; ++i) {
1985         std::vector<uint32_t> text;
1986         if (!zone.readString(text) || input->tell()>lastPos) {
1987           STOFF_DEBUG_MSG(("SWFieldManager::readPersistField: can not read a string\n"));
1988           f << "##string";
1989           break;
1990         }
1991         else if (!text.empty()) {
1992           if (i==0)
1993             inet->m_url=libstoff::getString(text);
1994           else
1995             inet->m_target=libstoff::getString(text);
1996           f << (i==0 ? "url" : "representation") << "=" << libstoff::getString(text).cstr() << ",";
1997         }
1998       }
1999       if (input->tell()==lastPos)
2000         break;
2001       uint32_t nFrameMarker;
2002       *input>>nFrameMarker;
2003       uint16_t val;
2004       switch (nFrameMarker) {
2005       case 0x21981357:
2006         *input>>val;
2007         if (val) f << "char[set]=" << val << ",";
2008         break;
2009       case 0x21981358:
2010         for (int i=0; i<2; ++i) {
2011           *input>>val;
2012           if (val) f << "f" << i << "=" << val << ",";
2013         }
2014         break;
2015       default:
2016         input->seek(-4, librevenge::RVNG_SEEK_CUR);
2017         break;
2018       }
2019       break;
2020     }
2021     case 50: // SdrMeasureField(unsure)
2022       f << "measureField,";
2023       if (input->tell()+2>lastPos) {
2024         STOFF_DEBUG_MSG(("SWFieldManager::readPersistField: can not read measure field\n"));
2025         f << "###,";
2026         break;
2027       }
2028       f << "kind=" << input->readULong(2) << ",";
2029       break;
2030     case 100: // flditem.cxx
2031       field=std::make_shared<SWFieldManagerInternal::FieldPageNumber>();
2032       field->m_type=6;
2033       f << "pageField,";
2034       break;
2035     case 101:
2036       field=std::make_shared<SWFieldManagerInternal::Field>();
2037       field->m_type=9;
2038       field->m_subType=0;
2039       f << "pagesField,";
2040       break;
2041     case 102:
2042       field=std::make_shared<SWFieldManagerInternal::FieldDateTime>();
2043       field->m_type=5;
2044       f << "timeField,";
2045       break;
2046     case 103:
2047       field=std::make_shared<SWFieldManagerInternal::Field>();
2048       field->m_type=2;
2049       f << "fileField,";
2050       break;
2051     case 104:
2052       f << "tableField,";
2053       break;
2054     case 105: {
2055       f << "timeField[extended],";
2056       if (input->tell()+8>lastPos) {
2057         STOFF_DEBUG_MSG(("SWFieldManager::readPersistField: can not read extended time field\n"));
2058         f << "###,";
2059         break;
2060       }
2061       auto dateTime=std::make_shared<SWFieldManagerInternal::FieldDateTime>();
2062       field=dateTime;
2063       dateTime->m_type=16;
2064       dateTime->m_dateTime=long(input->readULong(4));
2065       dateTime->m_subType=int(input->readULong(2));
2066       dateTime->m_format=int(input->readULong(2));
2067       if (dateTime->m_dateTime && dateTime->m_subType==1)  // type==0: mean fixed
2068         dateTime->m_type=5;
2069 
2070       f << "date[field],";
2071       if (dateTime->m_dateTime)
2072         f << "time=" << dateTime->m_dateTime << ",";
2073       f << "type=" << dateTime->m_subType << ",";
2074       f << "format=" << dateTime->m_format << ",";
2075       break;
2076     }
2077     case 106: {
2078       f << "fileField[extended],";
2079       field=std::make_shared<SWFieldManagerInternal::Field>();
2080       field->m_type=2;
2081       std::vector<uint32_t> text;
2082       if (!zone.readString(text) || input->tell()+4>lastPos) {
2083         STOFF_DEBUG_MSG(("SWFieldManager::readPersistField: can not read a string\n"));
2084         f << "##string";
2085         break;
2086       }
2087       else if (!text.empty())
2088         f << libstoff::getString(text).cstr() << ",";
2089       f << "type=" << input->readULong(2) << ",";
2090       field->m_format=int(input->readULong(2));
2091       f << "format=" << field->m_format << ",";
2092       break;
2093     }
2094     case 107: {
2095       field=std::make_shared<SWFieldManagerInternal::Field>();
2096       field->m_type=7;
2097       f << "authorField,";
2098       bool fieldOk=true;
2099       for (int i=0; i<3; ++i) {
2100         std::vector<uint32_t> text;
2101         if (!zone.readString(text) || input->tell()>lastPos) {
2102           STOFF_DEBUG_MSG(("SWFieldManager::readPersistField: can not read a string\n"));
2103           f << "##string";
2104           fieldOk=false;
2105           break;
2106         }
2107         else if (!text.empty())
2108           f << (i==0 ? "name" : i==1 ? "first[name]": "last[name]") << "=" << libstoff::getString(text).cstr() << ",";
2109       }
2110       if (!fieldOk) break;
2111       if (input->tell()+4>lastPos) {
2112         STOFF_DEBUG_MSG(("SWFieldManager::readPersistField: can not read author field\n"));
2113         f << "###,";
2114         break;
2115       }
2116       f << "type=" << input->readULong(2) << ",";
2117       field->m_format=int(input->readULong(2));
2118       f << "format=" << field->m_format << ",";
2119       break;
2120     }
2121     default:
2122       STOFF_DEBUG_MSG(("SWFieldManager::readPersistField: unknown class id\n"));
2123       f << "##classId";
2124       break;
2125     }
2126   }
2127   if (input->tell()!=lastPos)
2128     ascii.addDelimiter(input->tell(),'|');
2129   input->seek(lastPos, librevenge::RVNG_SEEK_SET);
2130   if (hdr&0x20)
2131     zone.closeSCRecord("PersistField");
2132 
2133   ascii.addPos(pos);
2134   ascii.addNote(f.str().c_str());
2135   if (field) return field;
2136   return std::make_shared<SWFieldManagerInternal::Field>(); // create a dummy field
2137 }
2138 
2139 // vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab:
2140