1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /*
3  * This file is part of the libabw project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  */
9 
10 #include <string.h>
11 
12 #include <set>
13 #include <stack>
14 #include <utility>
15 
16 #include <libxml/xmlIO.h>
17 #include <libxml/xmlstring.h>
18 #include <librevenge-stream/librevenge-stream.h>
19 #include <boost/spirit/include/qi.hpp>
20 #include "ABWParser.h"
21 #include "ABWContentCollector.h"
22 #include "ABWStylesCollector.h"
23 #include "libabw_internal.h"
24 #include "ABWXMLHelper.h"
25 #include "ABWXMLTokenMap.h"
26 
27 
28 namespace libabw
29 {
30 
31 namespace
32 {
33 
findBool(const std::string & str,bool & res)34 static bool findBool(const std::string &str, bool &res)
35 {
36   using namespace boost::spirit::qi;
37 
38   if (str.empty())
39     return false;
40 
41   symbols<char, bool> bools;
42   bools.add
43   ("true", true)
44   ("false", false)
45   ("yes", true)
46   ("no", false)
47   ;
48 
49   auto it = str.cbegin();
50   return phrase_parse(it, str.cend(), no_case[bools], space, res) && it == str.cend();
51 }
52 
53 // small function needed to call the xml BAD_CAST on a char const *
call_BAD_CAST_OnConst(char const * str)54 static xmlChar *call_BAD_CAST_OnConst(char const *str)
55 {
56   return BAD_CAST(const_cast<char *>(str));
57 }
58 
59 /** try to find the parent's level corresponding to a level with some id
60     and use its original id to define the list id.
61 
62     Seen corresponds to the list of level that we have already examined,
63     it is used to check also for loop
64   */
_findAndUpdateListElementId(std::map<int,std::shared_ptr<ABWListElement>> & listElements,int id,std::set<int> & seen)65 static int _findAndUpdateListElementId(std::map<int, std::shared_ptr<ABWListElement>> &listElements, int id, std::set<int> &seen)
66 {
67   if (listElements.find(id)==listElements.end() || !listElements.find(id)->second)
68     return 0;
69   const std::shared_ptr<ABWListElement> &tmpElement= listElements.find(id)->second;
70   if (tmpElement->m_listId)
71     return tmpElement->m_listId;
72   if (seen.find(id)!=seen.end())
73   {
74     // oops, this means that we have a loop
75     tmpElement->m_parentId=0;
76   }
77   else
78     seen.insert(id);
79   if (!tmpElement->m_parentId)
80   {
81     tmpElement->m_listId=id;
82     return id;
83   }
84   tmpElement->m_listId=_findAndUpdateListElementId(listElements, tmpElement->m_parentId, seen);
85   return tmpElement->m_listId;
86 }
87 
88 /** try to update the final list id for each list elements */
updateListElementIds(std::map<int,std::shared_ptr<ABWListElement>> & listElements)89 static void updateListElementIds(std::map<int, std::shared_ptr<ABWListElement>> &listElements)
90 {
91   std::set<int> seens;
92   for (const auto &elem : listElements)
93   {
94     if (!elem.second) continue;
95     _findAndUpdateListElementId(listElements, elem.first, seens);
96   }
97 }
98 
99 } // anonymous namespace
100 
101 struct ABWParserState
102 {
103   ABWParserState();
104   ~ABWParserState();
105   std::map<int, int> m_tableSizes;
106   std::map<std::string, ABWData> m_data;
107   std::map<int, std::shared_ptr<ABWListElement>> m_listElements;
108 
109   bool m_inMetadata;
110   std::string m_currentMetadataKey;
111   bool m_inStyleParsing;
112   std::stack<std::unique_ptr<ABWCollector> > m_collectorStack;
113 };
114 
ABWParserState()115 ABWParserState::ABWParserState()
116   : m_tableSizes()
117   , m_data()
118   , m_listElements()
119   , m_inMetadata(false)
120   , m_currentMetadataKey()
121   , m_inStyleParsing(false)
122   , m_collectorStack()
123 {
124 }
125 
~ABWParserState()126 ABWParserState::~ABWParserState()
127 {
128 }
129 } // namespace libabw
130 
ABWParser(librevenge::RVNGInputStream * input,librevenge::RVNGTextInterface * iface)131 libabw::ABWParser::ABWParser(librevenge::RVNGInputStream *input, librevenge::RVNGTextInterface *iface)
132   : m_input(input), m_iface(iface), m_collector(), m_state(new ABWParserState())
133 {
134 }
135 
~ABWParser()136 libabw::ABWParser::~ABWParser()
137 {
138 }
139 
parse()140 bool libabw::ABWParser::parse()
141 {
142   if (!m_input)
143     return false;
144 
145   try
146   {
147     m_collector.reset(new ABWStylesCollector(m_state->m_tableSizes, m_state->m_data, m_state->m_listElements));
148     m_input->seek(0, librevenge::RVNG_SEEK_SET);
149     m_state->m_inStyleParsing=true;
150     if (!processXmlDocument(m_input))
151       return false;
152     updateListElementIds(m_state->m_listElements);
153     m_collector.reset(new ABWContentCollector(m_iface, m_state->m_tableSizes, m_state->m_data, m_state->m_listElements));
154     m_input->seek(0, librevenge::RVNG_SEEK_SET);
155     m_state->m_inStyleParsing=false;
156     return processXmlDocument(m_input) && m_state->m_collectorStack.empty();
157   }
158   catch (...)
159   {
160   }
161   return false;
162 }
163 
processXmlDocument(librevenge::RVNGInputStream * input)164 bool libabw::ABWParser::processXmlDocument(librevenge::RVNGInputStream *input)
165 {
166   if (!input)
167     return false;
168 
169   ABWXMLProgressWatcher watcher;
170   auto reader(xmlReaderForStream(input, &watcher));
171   if (!reader)
172     return false;
173   int ret = xmlTextReaderRead(reader.get());
174   while (1 == ret && !watcher.isStuck())
175   {
176     ret = processXmlNode(reader.get());
177     if (ret == 1)
178       ret = xmlTextReaderRead(reader.get());
179   }
180 
181   if (m_collector)
182     m_collector->endDocument();
183   return ret == 0 && !watcher.isStuck();
184 }
185 
processXmlNode(xmlTextReaderPtr reader)186 int libabw::ABWParser::processXmlNode(xmlTextReaderPtr reader)
187 {
188   if (!reader)
189     return -1;
190   int tokenId = getElementToken(reader);
191   int tokenType = xmlTextReaderNodeType(reader);
192   int emptyToken = xmlTextReaderIsEmptyElement(reader);
193   if (XML_READER_TYPE_SIGNIFICANT_WHITESPACE == tokenType)
194   {
195     const auto *text = (const char *)xmlTextReaderConstValue(reader);
196     if (!m_state->m_inMetadata && text && text[0]==' ' && text[1]==0)
197       m_collector->insertText(text);
198     return 1;
199   }
200   else if (XML_READER_TYPE_TEXT == tokenType)
201   {
202     const auto *text = (const char *)xmlTextReaderConstValue(reader);
203     ABW_DEBUG_MSG(("ABWParser::processXmlNode: text %s\n", text));
204     if (m_state->m_inMetadata)
205     {
206       if (m_state->m_currentMetadataKey.empty())
207       {
208         ABW_DEBUG_MSG(("there is no key for metadata entry '%s'\n", text));
209       }
210       else
211       {
212         m_collector->addMetadataEntry(m_state->m_currentMetadataKey.c_str(), text);
213         m_state->m_currentMetadataKey.clear();
214       }
215     }
216     else
217     {
218       m_collector->insertText(text);
219     }
220   }
221 
222   int ret = 1;
223 
224   switch (tokenId)
225   {
226   case XML_ABIWORD:
227     if (XML_READER_TYPE_ELEMENT == tokenType)
228       readAbiword(reader);
229     break;
230   case XML_METADATA:
231     if (XML_READER_TYPE_ELEMENT == tokenType)
232       m_state->m_inMetadata = true;
233     if ((XML_READER_TYPE_END_ELEMENT == tokenType) || (emptyToken > 0))
234       m_state->m_inMetadata = false;
235     break;
236   case XML_M:
237     if (XML_READER_TYPE_ELEMENT == tokenType)
238       readM(reader);
239     break;
240   case XML_HISTORY:
241     if (XML_READER_TYPE_ELEMENT == tokenType)
242       ret = readHistory(reader);
243     break;
244   case XML_REVISIONS:
245     if (XML_READER_TYPE_ELEMENT == tokenType)
246       ret = readRevisions(reader);
247     break;
248   case XML_IGNOREDWORDS:
249     if (XML_READER_TYPE_ELEMENT == tokenType)
250       ret = readIgnoredWords(reader);
251     break;
252   case XML_S:
253     if (XML_READER_TYPE_ELEMENT == tokenType)
254       readS(reader);
255     break;
256   case XML_L:
257     if (XML_READER_TYPE_ELEMENT == tokenType)
258       readL(reader);
259     break;
260   case XML_PAGESIZE:
261     if (XML_READER_TYPE_ELEMENT == tokenType)
262       readPageSize(reader);
263     break;
264   case XML_SECTION:
265     if (XML_READER_TYPE_ELEMENT == tokenType)
266       readSection(reader);
267     if (XML_READER_TYPE_END_ELEMENT == tokenType || emptyToken > 0)
268       if (m_collector)
269         m_collector->endSection();
270     break;
271   case XML_D:
272     if (XML_READER_TYPE_ELEMENT == tokenType)
273       ret = readD(reader);
274     break;
275   case XML_P:
276     if (XML_READER_TYPE_ELEMENT == tokenType)
277       readP(reader);
278     if (XML_READER_TYPE_END_ELEMENT == tokenType || emptyToken > 0)
279       if (m_collector)
280         m_collector->closeParagraphOrListElement();
281     break;
282   case XML_C:
283     if (XML_READER_TYPE_ELEMENT == tokenType)
284       readC(reader);
285     if (XML_READER_TYPE_END_ELEMENT == tokenType || emptyToken > 0)
286       if (m_collector)
287         m_collector->closeSpan();
288     break;
289   case XML_CBR:
290     if (XML_READER_TYPE_ELEMENT == tokenType)
291       m_collector->insertColumnBreak();
292     break;
293   case XML_PBR:
294     if (XML_READER_TYPE_ELEMENT == tokenType)
295       m_collector->insertPageBreak();
296     break;
297   case XML_BR:
298     if (XML_READER_TYPE_ELEMENT == tokenType)
299       m_collector->insertLineBreak();
300     break;
301   case XML_A:
302     if (XML_READER_TYPE_ELEMENT == tokenType)
303       readA(reader);
304     if (XML_READER_TYPE_END_ELEMENT == tokenType || emptyToken > 0)
305       m_collector->closeLink();
306     break;
307   case XML_FOOT:
308     if (XML_READER_TYPE_ELEMENT == tokenType)
309       readFoot(reader);
310     if (XML_READER_TYPE_END_ELEMENT == tokenType || emptyToken > 0)
311       m_collector->closeFoot();
312     break;
313   case XML_ENDNOTE:
314     if (XML_READER_TYPE_ELEMENT == tokenType)
315       readEndnote(reader);
316     if (XML_READER_TYPE_END_ELEMENT == tokenType || emptyToken > 0)
317       m_collector->closeEndnote();
318     break;
319   case XML_FIELD:
320     if (XML_READER_TYPE_ELEMENT == tokenType)
321       readField(reader);
322     if (XML_READER_TYPE_END_ELEMENT == tokenType || emptyToken > 0)
323       m_collector->closeField();
324     break;
325   case XML_TABLE:
326     if (XML_READER_TYPE_ELEMENT == tokenType)
327       readTable(reader);
328     if (XML_READER_TYPE_END_ELEMENT == tokenType || emptyToken > 0)
329       m_collector->closeTable();
330     break;
331   case XML_CELL:
332     if (XML_READER_TYPE_ELEMENT == tokenType)
333       readCell(reader);
334     if (XML_READER_TYPE_END_ELEMENT == tokenType || emptyToken > 0)
335       m_collector->closeCell();
336     break;
337   case XML_IMAGE:
338     if (XML_READER_TYPE_ELEMENT == tokenType)
339       readImage(reader);
340     break;
341   case XML_FRAME:
342     if (XML_READER_TYPE_ELEMENT == tokenType)
343       readFrame(reader);
344     if (XML_READER_TYPE_END_ELEMENT == tokenType || emptyToken > 0)
345       readCloseFrame();
346     break;
347   default:
348     break;
349   }
350 
351 #ifdef DEBUG
352   const xmlChar *name = xmlTextReaderConstName(reader);
353   const xmlChar *value = xmlTextReaderConstValue(reader);
354   int isEmptyElement = xmlTextReaderIsEmptyElement(reader);
355 
356   ABW_DEBUG_MSG(("%i %i %s", isEmptyElement, tokenType, name ? (const char *)name : ""));
357   if (xmlTextReaderNodeType(reader) == 1)
358   {
359     while (xmlTextReaderMoveToNextAttribute(reader))
360     {
361       const xmlChar *name1 = xmlTextReaderConstName(reader);
362       const xmlChar *value1 = xmlTextReaderConstValue(reader);
363       ABW_DEBUG_MSG((" %s=\"%s\"", name1, value1));
364     }
365   }
366 
367   if (!value)
368     ABW_DEBUG_MSG(("\n"));
369   else
370   {
371     ABW_DEBUG_MSG((" %s\n", value));
372   }
373 #endif
374 
375   return ret;
376 }
377 
getElementToken(xmlTextReaderPtr reader)378 int libabw::ABWParser::getElementToken(xmlTextReaderPtr reader)
379 {
380   return ABWXMLTokenMap::getTokenId(xmlTextReaderConstName(reader));
381 }
382 
readAbiword(xmlTextReaderPtr reader)383 void libabw::ABWParser::readAbiword(xmlTextReaderPtr reader)
384 {
385   const ABWXMLString props = xmlTextReaderGetAttribute(reader, call_BAD_CAST_OnConst("props"));
386   if (m_collector)
387     m_collector->collectDocumentProperties(static_cast<const char *>(props));
388 }
389 
readM(xmlTextReaderPtr reader)390 void libabw::ABWParser::readM(xmlTextReaderPtr reader)
391 {
392   const ABWXMLString key = xmlTextReaderGetAttribute(reader, call_BAD_CAST_OnConst("key"));
393   if (key)
394     m_state->m_currentMetadataKey = static_cast<const char *>(key);
395 }
396 
readHistory(xmlTextReaderPtr reader)397 int libabw::ABWParser::readHistory(xmlTextReaderPtr reader)
398 {
399   int ret = 1;
400   int tokenId = XML_TOKEN_INVALID;
401   int tokenType = -1;
402   do
403   {
404     ret = xmlTextReaderRead(reader);
405     tokenId = getElementToken(reader);
406     if (XML_TOKEN_INVALID == tokenId)
407     {
408       ABW_DEBUG_MSG(("ABWParser::readHistory: unknown token %s\n", xmlTextReaderConstName(reader)));
409     }
410     tokenType = xmlTextReaderNodeType(reader);
411     switch (tokenId)
412     {
413     default:
414       break;
415     }
416   }
417   while ((XML_HISTORY != tokenId || XML_READER_TYPE_END_ELEMENT != tokenType) && 1 == ret);
418   return ret;
419 }
420 
readRevisions(xmlTextReaderPtr reader)421 int libabw::ABWParser::readRevisions(xmlTextReaderPtr reader)
422 {
423   int ret = 1;
424   int tokenId = XML_TOKEN_INVALID;
425   int tokenType = -1;
426   do
427   {
428     ret = xmlTextReaderRead(reader);
429     tokenId = getElementToken(reader);
430     if (XML_TOKEN_INVALID == tokenId)
431     {
432       ABW_DEBUG_MSG(("ABWParser::readRevisions: unknown token %s\n", xmlTextReaderConstName(reader)));
433     }
434     tokenType = xmlTextReaderNodeType(reader);
435     (void)tokenType;
436     switch (tokenId)
437     {
438     default:
439       break;
440     }
441   }
442   while ((XML_REVISIONS != tokenId || XML_READER_TYPE_END_ELEMENT != tokenType) && 1 == ret);
443   return ret;
444 }
445 
readIgnoredWords(xmlTextReaderPtr reader)446 int libabw::ABWParser::readIgnoredWords(xmlTextReaderPtr reader)
447 {
448   int ret = 1;
449   int tokenId = XML_TOKEN_INVALID;
450   int tokenType = -1;
451   do
452   {
453     ret = xmlTextReaderRead(reader);
454     tokenId = getElementToken(reader);
455     if (XML_TOKEN_INVALID == tokenId)
456     {
457       ABW_DEBUG_MSG(("ABWParser::readIgnoreWords: unknown token %s\n", xmlTextReaderConstName(reader)));
458     }
459     tokenType = xmlTextReaderNodeType(reader);
460     switch (tokenId)
461     {
462     default:
463       break;
464     }
465   }
466   while ((XML_IGNOREDWORDS != tokenId || XML_READER_TYPE_END_ELEMENT != tokenType) && 1 == ret);
467   return ret;
468 }
469 
readPageSize(xmlTextReaderPtr reader)470 void libabw::ABWParser::readPageSize(xmlTextReaderPtr reader)
471 {
472   ABWXMLString width = xmlTextReaderGetAttribute(reader, call_BAD_CAST_OnConst("width"));
473   ABWXMLString height = xmlTextReaderGetAttribute(reader, call_BAD_CAST_OnConst("height"));
474   ABWXMLString units = xmlTextReaderGetAttribute(reader, call_BAD_CAST_OnConst("units"));
475   ABWXMLString pageScale = xmlTextReaderGetAttribute(reader, call_BAD_CAST_OnConst("page-scale"));
476   if (m_collector)
477     m_collector->collectPageSize((const char *)width, (const char *)height, (const char *)units, (const char *)pageScale);
478 }
479 
readSection(xmlTextReaderPtr reader)480 void libabw::ABWParser::readSection(xmlTextReaderPtr reader)
481 {
482   ABWXMLString id = xmlTextReaderGetAttribute(reader, call_BAD_CAST_OnConst("id"));
483   ABWXMLString type = xmlTextReaderGetAttribute(reader, call_BAD_CAST_OnConst("type"));
484   ABWXMLString footer = xmlTextReaderGetAttribute(reader, call_BAD_CAST_OnConst("footer"));
485   ABWXMLString footerLeft = xmlTextReaderGetAttribute(reader, call_BAD_CAST_OnConst("footer-even"));
486   ABWXMLString footerFirst = xmlTextReaderGetAttribute(reader, call_BAD_CAST_OnConst("footer-first"));
487   ABWXMLString footerLast = xmlTextReaderGetAttribute(reader, call_BAD_CAST_OnConst("footer-last"));
488   ABWXMLString header = xmlTextReaderGetAttribute(reader, call_BAD_CAST_OnConst("header"));
489   ABWXMLString headerLeft = xmlTextReaderGetAttribute(reader, call_BAD_CAST_OnConst("header-even"));
490   ABWXMLString headerFirst = xmlTextReaderGetAttribute(reader, call_BAD_CAST_OnConst("header-first"));
491   ABWXMLString headerLast = xmlTextReaderGetAttribute(reader, call_BAD_CAST_OnConst("header-last"));
492   ABWXMLString props = xmlTextReaderGetAttribute(reader, call_BAD_CAST_OnConst("props"));
493 
494   if (!type || (xmlStrncmp(type.get(), call_BAD_CAST_OnConst("header"), 6) && xmlStrncmp(type.get(), call_BAD_CAST_OnConst("footer"), 6)))
495   {
496     if (m_collector)
497       m_collector->collectSectionProperties((const char *)footer, (const char *)footerLeft,
498                                             (const char *)footerFirst, (const char *)footerLast,
499                                             (const char *)header, (const char *)headerLeft,
500                                             (const char *)headerFirst, (const char *)headerLast,
501                                             (const char *)props);
502   }
503   else
504   {
505     if (m_collector)
506       m_collector->collectHeaderFooter((const char *)id, (const char *)type);
507   }
508 }
509 
readD(xmlTextReaderPtr reader)510 int libabw::ABWParser::readD(xmlTextReaderPtr reader)
511 {
512   ABWXMLString name = xmlTextReaderGetAttribute(reader, call_BAD_CAST_OnConst("name"));
513   ABWXMLString mimeType = xmlTextReaderGetAttribute(reader, call_BAD_CAST_OnConst("mime-type"));
514 
515   ABWXMLString tmpBase64 = xmlTextReaderGetAttribute(reader, call_BAD_CAST_OnConst("base64"));
516   bool base64(false);
517   if (tmpBase64)
518   {
519     findBool((const char *)tmpBase64, base64);
520   }
521 
522   int ret = 1;
523   int tokenId = XML_TOKEN_INVALID;
524   int tokenType = -1;
525   do
526   {
527     ret = xmlTextReaderRead(reader);
528     tokenId = getElementToken(reader);
529     if (XML_TOKEN_INVALID == tokenId)
530     {
531       ABW_DEBUG_MSG(("ABWParser::readD: unknown token %s\n", xmlTextReaderConstName(reader)));
532     }
533     tokenType = xmlTextReaderNodeType(reader);
534     switch (tokenType)
535     {
536     case XML_READER_TYPE_TEXT:
537     case XML_READER_TYPE_CDATA:
538     {
539       const xmlChar *data = xmlTextReaderConstValue(reader);
540       if (data)
541       {
542         librevenge::RVNGBinaryData binaryData;
543         if (base64)
544           binaryData.appendBase64Data((const char *)data);
545         else
546           binaryData.append(data, (unsigned long) xmlStrlen(data));
547         if (m_collector)
548           m_collector->collectData((const char *)name, (const char *)mimeType, binaryData);
549       }
550       break;
551     }
552     default:
553       break;
554     }
555   }
556   while ((XML_D != tokenId || XML_READER_TYPE_END_ELEMENT != tokenType) && 1 == ret);
557   return ret;
558 }
559 
readS(xmlTextReaderPtr reader)560 void libabw::ABWParser::readS(xmlTextReaderPtr reader)
561 {
562   ABWXMLString type = xmlTextReaderGetAttribute(reader, call_BAD_CAST_OnConst("type"));
563   ABWXMLString name = xmlTextReaderGetAttribute(reader, call_BAD_CAST_OnConst("name"));
564   ABWXMLString basedon = xmlTextReaderGetAttribute(reader, call_BAD_CAST_OnConst("basedon"));
565   ABWXMLString followedby = xmlTextReaderGetAttribute(reader, call_BAD_CAST_OnConst("followedby"));
566   ABWXMLString props = xmlTextReaderGetAttribute(reader, call_BAD_CAST_OnConst("props"));
567   if (type)
568   {
569     if (m_collector)
570     {
571       switch (type[0])
572       {
573       case 'P':
574       case 'C':
575         m_collector->collectTextStyle((const char *)name, (const char *)basedon, (const char *)followedby, (const char *)props);
576         break;
577       default:
578         break;
579       }
580     }
581   }
582 }
583 
readA(xmlTextReaderPtr reader)584 void libabw::ABWParser::readA(xmlTextReaderPtr reader)
585 {
586   ABWXMLString href = xmlTextReaderGetAttribute(reader, call_BAD_CAST_OnConst("xlink:href"));
587   if (m_collector)
588     m_collector->openLink((const char *)href);
589 }
590 
readP(xmlTextReaderPtr reader)591 void libabw::ABWParser::readP(xmlTextReaderPtr reader)
592 {
593   ABWXMLString level = xmlTextReaderGetAttribute(reader, call_BAD_CAST_OnConst("level"));
594   ABWXMLString listid = xmlTextReaderGetAttribute(reader, call_BAD_CAST_OnConst("listid"));
595   ABWXMLString parentid = xmlTextReaderGetAttribute(reader, call_BAD_CAST_OnConst("listid"));
596   ABWXMLString style = xmlTextReaderGetAttribute(reader, call_BAD_CAST_OnConst("style"));
597   ABWXMLString props = xmlTextReaderGetAttribute(reader, call_BAD_CAST_OnConst("props"));
598   if (m_collector)
599     m_collector->collectParagraphProperties((const char *)level, (const char *)listid, (const char *)parentid,
600                                             (const char *)style, (const char *)props);
601 }
602 
readC(xmlTextReaderPtr reader)603 void libabw::ABWParser::readC(xmlTextReaderPtr reader)
604 {
605   ABWXMLString style = xmlTextReaderGetAttribute(reader, call_BAD_CAST_OnConst("style"));
606   ABWXMLString props = xmlTextReaderGetAttribute(reader, call_BAD_CAST_OnConst("props"));
607   if (m_collector)
608     m_collector->collectCharacterProperties((const char *)style, (const char *)props);
609 
610 }
611 
readEndnote(xmlTextReaderPtr reader)612 void libabw::ABWParser::readEndnote(xmlTextReaderPtr reader)
613 {
614   ABWXMLString id = xmlTextReaderGetAttribute(reader, call_BAD_CAST_OnConst("endnote-id"));
615   if (m_collector)
616     m_collector->openEndnote((const char *)id);
617 }
618 
readField(xmlTextReaderPtr reader)619 void libabw::ABWParser::readField(xmlTextReaderPtr reader)
620 {
621   ABWXMLString type = xmlTextReaderGetAttribute(reader, call_BAD_CAST_OnConst("type"));
622   //ABWXMLString style = xmlTextReaderGetAttribute(reader, call_BAD_CAST_OnConst("style"));
623   //ABWXMLString props = xmlTextReaderGetAttribute(reader, call_BAD_CAST_OnConst("props"));
624   ABWXMLString id = xmlTextReaderGetAttribute(reader, call_BAD_CAST_OnConst("xid"));
625   if (m_collector)
626     m_collector->openField(type, id);
627 }
628 
readFoot(xmlTextReaderPtr reader)629 void libabw::ABWParser::readFoot(xmlTextReaderPtr reader)
630 {
631   ABWXMLString id = xmlTextReaderGetAttribute(reader, call_BAD_CAST_OnConst("footnote-id"));
632   if (m_collector)
633     m_collector->openFoot((const char *)id);
634 }
635 
readTable(xmlTextReaderPtr reader)636 void libabw::ABWParser::readTable(xmlTextReaderPtr reader)
637 {
638   ABWXMLString props = xmlTextReaderGetAttribute(reader, call_BAD_CAST_OnConst("props"));
639   if (m_collector)
640     m_collector->openTable((const char *)props);
641 }
642 
readCell(xmlTextReaderPtr reader)643 void libabw::ABWParser::readCell(xmlTextReaderPtr reader)
644 {
645   ABWXMLString props = xmlTextReaderGetAttribute(reader, call_BAD_CAST_OnConst("props"));
646   if (m_collector)
647     m_collector->openCell((const char *)props);
648 }
649 
readImage(xmlTextReaderPtr reader)650 void libabw::ABWParser::readImage(xmlTextReaderPtr reader)
651 {
652   ABWXMLString props = xmlTextReaderGetAttribute(reader, call_BAD_CAST_OnConst("props"));
653   ABWXMLString dataid = xmlTextReaderGetAttribute(reader, call_BAD_CAST_OnConst("dataid"));
654   if (m_collector)
655     m_collector->insertImage((const char *)dataid, (const char *)props);
656 }
657 
readFrame(xmlTextReaderPtr reader)658 void libabw::ABWParser::readFrame(xmlTextReaderPtr reader)
659 {
660   if (!m_collector)
661     return;
662   ABWXMLString props = xmlTextReaderGetAttribute(reader, call_BAD_CAST_OnConst("props"));
663   ABWXMLString imageId = xmlTextReaderGetAttribute(reader, call_BAD_CAST_OnConst("strux-image-dataid"));
664   ABWXMLString title = xmlTextReaderGetAttribute(reader, call_BAD_CAST_OnConst("title"));
665   ABWXMLString alt = xmlTextReaderGetAttribute(reader, call_BAD_CAST_OnConst("alt"));
666   if (!m_state->m_inStyleParsing)
667   {
668     m_state->m_collectorStack.push(std::move(m_collector));
669     m_collector.reset(new ABWContentCollector(m_iface, m_state->m_tableSizes, m_state->m_data, m_state->m_listElements));
670   }
671   m_collector->openFrame((const char *)props, (const char *) imageId, (const char *) title, (const char *) alt);
672 }
673 
readCloseFrame()674 void libabw::ABWParser::readCloseFrame()
675 {
676   if (!m_collector)
677     return;
678   ABWOutputElements *elements=nullptr;
679   bool pageFrame=false;
680   m_collector->closeFrame(elements,pageFrame);
681   if (m_state->m_inStyleParsing)
682     return;
683   if (m_state->m_collectorStack.empty())
684   {
685     ABW_DEBUG_MSG(("libabw::ABWParser::readCloseFrame: oops, the collector stack is empty\n"));
686     return; // throw ?
687   }
688   if (elements)
689     m_state->m_collectorStack.top()->addFrameElements(*elements, pageFrame);
690   m_collector.swap(m_state->m_collectorStack.top());
691   m_state->m_collectorStack.pop();
692 }
693 
readL(xmlTextReaderPtr reader)694 void libabw::ABWParser::readL(xmlTextReaderPtr reader)
695 {
696   ABWXMLString id = xmlTextReaderGetAttribute(reader, call_BAD_CAST_OnConst("id"));
697   ABWXMLString listDecimal = xmlTextReaderGetAttribute(reader, call_BAD_CAST_OnConst("list-decimal"));
698   if (!listDecimal)
699     listDecimal = xmlCharStrdup("NULL");
700   ABWXMLString listDelim = xmlTextReaderGetAttribute(reader, call_BAD_CAST_OnConst("list-delim"));
701   ABWXMLString parentid = xmlTextReaderGetAttribute(reader, call_BAD_CAST_OnConst("parentid"));
702   ABWXMLString startValue = xmlTextReaderGetAttribute(reader, call_BAD_CAST_OnConst("start-value"));
703   ABWXMLString type = xmlTextReaderGetAttribute(reader, call_BAD_CAST_OnConst("type"));
704   if (m_collector)
705     m_collector->collectList((const char *)id, (const char *)listDecimal, (const char *)listDelim,
706                              (const char *)parentid, (const char *)startValue, (const char *)type);
707 }
708 
709 /* vim:set shiftwidth=2 softtabstop=2 expandtab: */
710