Instrument Neutral Distributed Interface INDI  2.0.2
indililxml.h
Go to the documentation of this file.
1 /*
2  Copyright (C) 2022 by Pawel Soja <kernel32.pl@gmail.com>
3 
4  This library is free software; you can redistribute it and/or
5  modify it under the terms of the GNU Lesser General Public
6  License as published by the Free Software Foundation; either
7  version 2.1 of the License, or (at your option) any later version.
8 
9  This library is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  Lesser General Public License for more details.
13 
14  You should have received a copy of the GNU Lesser General Public
15  License along with this library; if not, write to the Free Software
16  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18 #pragma once
19 
20 #include "lilxml.h"
21 #include "indiapi.h"
22 #include "indibase.h"
23 #include "indicom.h"
24 #include "indidevapi.h"
25 
26 #include <string>
27 #include <functional>
28 #include <list>
29 #include <stdexcept>
30 #include <memory>
31 
32 #include <cstring>
33 
34 namespace INDI
35 {
36 
37 // helper
38 template <typename T>
39 class safe_ptr
40 {
41  T fake, *ptr;
42 
43  public:
44  safe_ptr(T *ptr = nullptr): ptr(ptr ? ptr : &fake)
45  { }
46 
47  T& operator *() { return *ptr; }
48  operator bool() const { return true; }
49 };
50 
52 {
53  public:
54  explicit LilXmlValue(const char *value);
55  explicit LilXmlValue(const char *value, size_t size);
56 
57  public:
58  bool isValid() const;
59  const void *data() const;
60  size_t size() const;
61 
62  public:
63  int toInt(safe_ptr<bool> ok = nullptr) const;
64  double toDoubleSexa(safe_ptr<bool> ok = nullptr) const;
65  double toDouble(safe_ptr<bool> ok = nullptr) const;
66  const char *toCString() const;
67  std::string toString() const;
68  ISRule toISRule(safe_ptr<bool> ok = nullptr) const;
69  ISState toISState(safe_ptr<bool> ok = nullptr) const;
70  IPState toIPState(safe_ptr<bool> ok = nullptr) const;
71  IPerm toIPerm(safe_ptr<bool> ok = nullptr) const;
72 
73  public:
74  std::size_t indexOf(const char *needle, size_t from = 0) const;
75  std::size_t indexOf(const std::string &needle, size_t from = 0) const;
76 
77  std::size_t lastIndexOf(const char *needle, size_t from = 0) const;
78  std::size_t lastIndexOf(const std::string &needle, size_t from = 0) const;
79 
80  bool startsWith(const char *needle) const;
81  bool startsWith(const std::string &needle) const;
82 
83  bool endsWith(const char *needle) const;
84  bool endsWith(const std::string &needle) const;
85 
86  public:
87  operator const char *() const { return toCString(); }
88  operator double () const { return toDouble(); }
89  operator int () const { return toInt(); }
90  operator ISRule () const { return toISRule(); }
91  operator ISState () const { return toISState(); }
92  operator IPState () const { return toIPState(); }
93  operator IPerm () const { return toIPerm(); }
94  operator size_t () const { return toInt(); }
95 
96  protected:
97  const char *mValue;
98  size_t mSize;
99 };
100 
102 {
103  public:
104  explicit LilXmlAttribute(XMLAtt *a);
105 
106  public:
107  bool isValid() const;
108 
109  public:
110  std::string name() const;
111  const LilXmlValue &value() const { return *this; }
112 
113  public:
114  operator bool() const { return isValid(); }
115 
116  public:
117  XMLAtt *handle() const;
118 
119  protected:
121 };
122 
124 {
125  public:
126  using Elements = std::list<LilXmlElement>; // or implement custom container/iterators
127 
128  public:
129  explicit LilXmlElement(XMLEle *e);
130 
131  public:
132  bool isValid() const;
133  std::string tagName() const;
134 
135  public:
136  Elements getElements() const;
137  Elements getElementsByTagName(const char *tagName) const;
138  LilXmlAttribute getAttribute(const char *name) const;
139  LilXmlAttribute addAttribute(const char *name, const char *value);
140  void removeAttribute(const char *name);
141 
142  LilXmlValue context() const;
143  void setContext(const char *data);
144 
145  void print(FILE *f, int level = 0) const;
146 
147  public:
148  XMLEle *handle() const;
149 
150  protected:
152  char errmsg[128];
153 };
154 
156 {
157  LilXmlDocument(const LilXmlDocument &) = delete;
158  LilXmlDocument &operator=(const LilXmlDocument&) = delete;
159 
160  public:
161  explicit LilXmlDocument(XMLEle *root);
163  ~LilXmlDocument() = default;
164 
165  public:
166  bool isValid() const;
167  LilXmlElement root() const;
168 
169  protected:
170  std::unique_ptr<XMLEle, void(*)(XMLEle*)> mRoot;
171 };
172 
174 {
175  LilXmlParser(const LilXmlDocument &) = delete;
176  LilXmlParser &operator=(const LilXmlDocument&) = delete;
177  LilXmlParser(LilXmlDocument &&) = delete;
178  LilXmlParser &operator=(LilXmlDocument &&) = delete;
179 
180  public:
181  LilXmlParser();
182  ~LilXmlParser() = default;
183 
184  public:
185  LilXmlDocument readFromFile(FILE *file);
186  LilXmlDocument readFromFile(const char *fileName);
187  LilXmlDocument readFromFile(const std::string &fileName);
188 
189  public:
190  std::list<LilXmlDocument> parseChunk(const char *data, size_t size);
191 
192  public:
193  bool hasErrorMessage() const;
194  const char *errorMessage() const;
195 
196  protected:
197  std::unique_ptr<LilXML, void(*)(LilXML *)> mHandle;
198  char mErrorMessage[MAXRBUF] = {0, };
199 };
200 
201 
202 
203 // LilXmlValue Implementation
204 inline LilXmlValue::LilXmlValue(const char *value)
205  : mValue(value)
206  , mSize(value ? strlen(value) : 0)
207 { }
208 
209 inline LilXmlValue::LilXmlValue(const char *value, size_t size)
210  : mValue(value)
211  , mSize(size)
212 { }
213 
214 inline bool LilXmlValue::isValid() const
215 {
216  return mValue != nullptr;
217 }
218 
219 inline const void *LilXmlValue::data() const
220 {
221  return mValue;
222 }
223 
224 inline size_t LilXmlValue::size() const
225 {
226  return mSize;
227 }
228 
229 inline int LilXmlValue::toInt(safe_ptr<bool> ok) const
230 {
231  int result = 0;
232  try {
233  result = std::stoi(toString());
234  *ok = true;
235  } catch (...) {
236  *ok = false;
237  }
238  return result;
239 }
240 
242 {
243  double result = 0;
244  *ok = (isValid() && f_scansexa(mValue, &result) >= 0);
245  return result;
246 }
247 
248 inline double LilXmlValue::toDouble(safe_ptr<bool> ok) const
249 {
250  double result = 0;
251  try {
252  result = std::stod(toString());
253  *ok = true;
254  } catch (...) {
255  *ok = false;
256  }
257  return result;
258 }
259 
260 inline const char *LilXmlValue::toCString() const
261 {
262  return isValid() ? mValue : "";
263 }
264 
265 inline std::string LilXmlValue::toString() const
266 {
267  return isValid() ? mValue : "";
268 }
269 
271 {
272  ISRule rule = ISR_1OFMANY;
273  *ok = (isValid() && crackISRule(mValue, &rule) >= 0);
274  return rule;
275 }
276 
278 {
279  ISState state = ISS_OFF;
280  *ok = (isValid() && crackISState(mValue, &state) >= 0);
281  return state;
282 }
283 
285 {
286  IPState state = IPS_OK;
287  *ok = (isValid() && crackIPState(mValue, &state) >= 0);
288  return state;
289 }
290 
292 {
293  IPerm result = IP_RO;
294  *ok = (isValid() && crackIPerm(mValue, &result) >= 0);
295  return result;
296 }
297 
298 inline std::size_t LilXmlValue::indexOf(const char *needle, size_t from) const
299 {
300  return toString().find_first_of(needle, from);
301 }
302 
303 inline std::size_t LilXmlValue::indexOf(const std::string &needle, size_t from) const
304 {
305  return toString().find_first_of(needle, from);
306 }
307 
308 inline std::size_t LilXmlValue::lastIndexOf(const char *needle, size_t from) const
309 {
310  return toString().find_last_of(needle, from);
311 }
312 
313 inline std::size_t LilXmlValue::lastIndexOf(const std::string &needle, size_t from) const
314 {
315  return toString().find_last_of(needle, from);
316 }
317 
318 inline bool LilXmlValue::startsWith(const char *needle) const
319 {
320  return indexOf(needle) == 0;
321 }
322 
323 inline bool LilXmlValue::startsWith(const std::string &needle) const
324 {
325  return indexOf(needle) == 0;
326 }
327 
328 inline bool LilXmlValue::endsWith(const char *needle) const
329 {
330  return lastIndexOf(needle) == (size() - strlen(needle));
331 }
332 
333 inline bool LilXmlValue::endsWith(const std::string &needle) const
334 {
335  return lastIndexOf(needle) == (size() - needle.size());
336 }
337 
338 // LilXmlAttribute Implementation
339 
341  : LilXmlValue(a ? valuXMLAtt(a) : nullptr)
342  , mHandle(a)
343 { }
344 
346 {
347  return mHandle;
348 }
349 
350 inline bool LilXmlAttribute::isValid() const
351 {
352  return mHandle != nullptr;
353 }
354 
355 
356 inline std::string LilXmlAttribute::name() const
357 {
358  return isValid() ? nameXMLAtt(mHandle) : "";
359 }
360 
361 // LilXmlElement Implementation
362 
364  : mHandle(e)
365 { }
366 
368 {
369  return mHandle;
370 }
371 
372 inline std::string LilXmlElement::tagName() const
373 {
374  return tagXMLEle(mHandle);
375 }
376 
378 {
379  Elements result;
380  if (handle() == nullptr)
381  return result;
382 
383  for (XMLEle *ep = nextXMLEle(mHandle, 1); ep != nullptr; ep = nextXMLEle(mHandle, 0))
384  result.push_back(LilXmlElement(ep));
385  return result;
386 }
387 
389 {
391  if (handle() == nullptr)
392  return result;
393 
394  for (XMLEle *ep = nextXMLEle(mHandle, 1); ep != nullptr; ep = nextXMLEle(mHandle, 0))
395  {
396  LilXmlElement element(ep);
397  if (element.tagName() == tagName)
398  {
399  result.push_back(element);
400  }
401  }
402  return result;
403 }
404 
405 inline LilXmlAttribute LilXmlElement::getAttribute(const char *name) const
406 {
407  return LilXmlAttribute(findXMLAtt(mHandle, name));
408 }
409 
410 inline LilXmlAttribute LilXmlElement::addAttribute(const char *name, const char *value)
411 {
412  return LilXmlAttribute(addXMLAtt(mHandle, name, value));
413 }
414 
415 inline void LilXmlElement::removeAttribute(const char *name)
416 {
417  rmXMLAtt(mHandle, name);
418 }
419 
421 {
423 }
424 
425 inline void LilXmlElement::setContext(const char *data)
426 {
427  editXMLEle(mHandle, data);
428 }
429 
430 inline void LilXmlElement::print(FILE *f, int level) const
431 {
432  prXMLEle(f, handle(), level);
433 }
434 
435 // LilXmlDocument Implementation
436 
437 inline LilXmlDocument::LilXmlDocument(XMLEle *root)
438  : mRoot(root, [](XMLEle* root) { if (root) delXMLEle(root); })
439 { }
440 
441 inline LilXmlDocument::LilXmlDocument(LilXmlDocument &&other)
442  : mRoot(std::move(other.mRoot))
443 { }
444 
445 inline bool LilXmlDocument::isValid() const
446 {
447  return mRoot != nullptr;
448 }
449 
451 {
452  return LilXmlElement(mRoot.get());
453 }
454 
455 // LilXmlParser Implementation
456 
458  : mHandle(newLilXML(), [](LilXML *handle) { delLilXML(handle); })
459 { }
460 
462 {
463  return LilXmlDocument(readXMLFile(file, mHandle.get(), mErrorMessage));
464 }
465 
466 inline LilXmlDocument LilXmlParser::readFromFile(const char *fileName)
467 {
468  FILE *fp = fopen(fileName, "r");
469  if (fp == nullptr)
470  {
471  snprintf(mErrorMessage, sizeof(mErrorMessage), "Error loading file %s", fileName);
472  return LilXmlDocument(nullptr);
473  }
474 
475  LilXmlDocument result = readFromFile(fp);
476  fclose(fp);
477  return result;
478 }
479 
480 inline LilXmlDocument LilXmlParser::readFromFile(const std::string &fileName)
481 {
482  return readFromFile(fileName.c_str());
483 }
484 
485 inline std::list<LilXmlDocument> LilXmlParser::parseChunk(const char *data, size_t size)
486 {
487  std::list<LilXmlDocument> result;
488  XMLEle ** nodes = parseXMLChunk(mHandle.get(), const_cast<char*>(data), int(size), mErrorMessage);
489  if (nodes != nullptr)
490  {
491  for (auto it = nodes; *it; ++it)
492  {
493  result.push_back(LilXmlDocument(*it));
494  }
495  free(nodes);
496  }
497  return result;
498 }
499 
500 inline bool LilXmlParser::hasErrorMessage() const
501 {
502  return mErrorMessage[0] != '\0';
503 }
504 
505 inline const char *LilXmlParser::errorMessage() const
506 {
507  return mErrorMessage;
508 }
509 
510 }
const LilXmlValue & value() const
Definition: indililxml.h:111
LilXmlAttribute(XMLAtt *a)
Definition: indililxml.h:340
std::string name() const
Definition: indililxml.h:356
XMLAtt * handle() const
Definition: indililxml.h:345
bool isValid() const
Definition: indililxml.h:350
~LilXmlDocument()=default
std::unique_ptr< XMLEle, void(*)(XMLEle *)> mRoot
Definition: indililxml.h:170
bool isValid() const
Definition: indililxml.h:445
LilXmlElement root() const
Definition: indililxml.h:450
Elements getElementsByTagName(const char *tagName) const
Definition: indililxml.h:388
bool isValid() const
Elements getElements() const
Definition: indililxml.h:377
LilXmlAttribute addAttribute(const char *name, const char *value)
Definition: indililxml.h:410
LilXmlValue context() const
Definition: indililxml.h:420
void removeAttribute(const char *name)
Definition: indililxml.h:415
XMLEle * handle() const
Definition: indililxml.h:367
std::string tagName() const
Definition: indililxml.h:372
LilXmlAttribute getAttribute(const char *name) const
Definition: indililxml.h:405
std::list< LilXmlElement > Elements
Definition: indililxml.h:126
LilXmlElement(XMLEle *e)
Definition: indililxml.h:363
void setContext(const char *data)
Definition: indililxml.h:425
void print(FILE *f, int level=0) const
Definition: indililxml.h:430
std::unique_ptr< LilXML, void(*)(LilXML *)> mHandle
Definition: indililxml.h:197
const char * errorMessage() const
Definition: indililxml.h:505
~LilXmlParser()=default
bool hasErrorMessage() const
Definition: indililxml.h:500
std::list< LilXmlDocument > parseChunk(const char *data, size_t size)
Definition: indililxml.h:485
LilXmlDocument readFromFile(FILE *file)
Definition: indililxml.h:461
char mErrorMessage[MAXRBUF]
Definition: indililxml.h:198
IPState toIPState(safe_ptr< bool > ok=nullptr) const
Definition: indililxml.h:284
std::size_t indexOf(const char *needle, size_t from=0) const
Definition: indililxml.h:298
std::size_t lastIndexOf(const char *needle, size_t from=0) const
Definition: indililxml.h:308
std::string toString() const
Definition: indililxml.h:265
double toDouble(safe_ptr< bool > ok=nullptr) const
Definition: indililxml.h:248
ISState toISState(safe_ptr< bool > ok=nullptr) const
Definition: indililxml.h:277
IPerm toIPerm(safe_ptr< bool > ok=nullptr) const
Definition: indililxml.h:291
LilXmlValue(const char *value)
Definition: indililxml.h:204
int toInt(safe_ptr< bool > ok=nullptr) const
Definition: indililxml.h:229
size_t size() const
Definition: indililxml.h:224
double toDoubleSexa(safe_ptr< bool > ok=nullptr) const
Definition: indililxml.h:241
const char * mValue
Definition: indililxml.h:97
ISRule toISRule(safe_ptr< bool > ok=nullptr) const
Definition: indililxml.h:270
const char * toCString() const
Definition: indililxml.h:260
bool isValid() const
Definition: indililxml.h:214
bool endsWith(const char *needle) const
Definition: indililxml.h:328
bool startsWith(const char *needle) const
Definition: indililxml.h:318
const void * data() const
Definition: indililxml.h:219
safe_ptr(T *ptr=nullptr)
Definition: indililxml.h:44
T & operator*()
Definition: indililxml.h:47
Constants and Data structure definitions for the interface to the reference INDI C API implementation...
ISState
Switch state.
Definition: indiapi.h:150
@ ISS_OFF
Definition: indiapi.h:151
IPerm
Permission hint, with respect to client.
Definition: indiapi.h:183
@ IP_RO
Definition: indiapi.h:184
IPState
Property state.
Definition: indiapi.h:160
@ IPS_OK
Definition: indiapi.h:162
ISRule
Switch vector rule hint.
Definition: indiapi.h:172
@ ISR_1OFMANY
Definition: indiapi.h:173
int f_scansexa(const char *str0, double *dp)
convert sexagesimal string str AxBxC to double. x can be anything non-numeric. Any missing A,...
Definition: indicom.c:205
Implementations for common driver routines.
int crackIPerm(const char *str, IPerm *ip)
Extract property permission state (RW, RO, WO) from the supplied string.
Definition: indidevapi.c:602
int crackIPState(const char *str, IPState *ip)
Extract property state (Idle, OK, Busy, Alert) from the supplied string.
Definition: indidevapi.c:576
int crackISRule(const char *str, ISRule *ip)
Extract switch rule (OneOfMany, OnlyOne..etc) from the supplied string.
Definition: indidevapi.c:615
int crackISState(const char *str, ISState *ip)
Extract switch state (On or Off) from the supplied string.
Definition: indidevapi.c:591
Interface to the reference INDI C API device implementation on the Device Driver side.
#define MAXRBUF
Definition: indiserver.cpp:102
XMLAtt * findXMLAtt(XMLEle *ep, const char *name)
Find an XML attribute within an XML element.
Definition: lilxml.cpp:524
LilXML * newLilXML()
Create a new lilxml parser.
Definition: lilxml.cpp:150
XMLEle ** parseXMLChunk(LilXML *lp, char *buf, int size, char ynot[])
Process an XML chunk.
Definition: lilxml.cpp:215
XMLAtt * addXMLAtt(XMLEle *ep, const char *name, const char *valu)
Add an XML attribute to an existing XML element.
Definition: lilxml.cpp:706
char * pcdataXMLEle(XMLEle *ep)
Return the pcdata of an XML element.
Definition: lilxml.cpp:606
void editXMLEle(XMLEle *ep, const char *pcdata)
set the pcdata of the given element
Definition: lilxml.cpp:698
char * tagXMLEle(XMLEle *ep)
Return the tag of an XML element.
Definition: lilxml.cpp:600
void rmXMLAtt(XMLEle *ep, const char *name)
Remove an XML attribute from an XML element.
Definition: lilxml.cpp:715
void prXMLEle(FILE *fp, XMLEle *ep, int level)
Print an XML element.
Definition: lilxml.cpp:844
XMLEle * readXMLFile(FILE *fp, LilXML *lp, char ynot[])
Handy wrapper to read one xml file.
Definition: lilxml.cpp:653
XMLEle * nextXMLEle(XMLEle *ep, int init)
Iterate an XML element for a list of nesetd XML elements.
Definition: lilxml.cpp:555
char * nameXMLAtt(XMLAtt *ap)
Return the name of an XML attribute.
Definition: lilxml.cpp:618
void delXMLEle(XMLEle *ep)
delXMLEle Delete XML element.
Definition: lilxml.cpp:167
void delLilXML(LilXML *lp)
Delete a lilxml parser.
Definition: lilxml.cpp:159
int pcdatalenXMLEle(XMLEle *ep)
Return the number of characters in pcdata in an XML element.
Definition: lilxml.cpp:612
char * valuXMLAtt(XMLAtt *ap)
Return the value of an XML attribute.
Definition: lilxml.cpp:624
A little DOM-style library to handle parsing and processing an XML file.
struct LilXML_ LilXML
Definition: lilxml.h:76
struct xml_ele_ XMLEle
Definition: lilxml.h:75
Namespace to encapsulate INDI client, drivers, and mediator classes.
Definition: json.h:4973