Instrument Neutral Distributed Interface INDI 2.2.5
indililxml.h
Go to the documentation of this file.
1/*
2 Copyright (C) 2022 by Pawel Soja <[email protected]>
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
34namespace INDI
35{
36
37// helper
38template <typename T>
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
204inline LilXmlValue::LilXmlValue(const char *value)
205 : mValue(value)
206 , mSize(value ? strlen(value) : 0)
207{ }
208
209inline LilXmlValue::LilXmlValue(const char *value, size_t size)
210 : mValue(value)
211 , mSize(size)
212{ }
213
214inline bool LilXmlValue::isValid() const
215{
216 return mValue != nullptr;
217}
218
219inline const void *LilXmlValue::data() const
220{
221 return mValue;
222}
223
224inline size_t LilXmlValue::size() const
225{
226 return mSize;
227}
228
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
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
260inline const char *LilXmlValue::toCString() const
261{
262 return isValid() ? mValue : "";
263}
264
265inline 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
298inline std::size_t LilXmlValue::indexOf(const char *needle, size_t from) const
299{
300 return toString().find_first_of(needle, from);
301}
302
303inline std::size_t LilXmlValue::indexOf(const std::string &needle, size_t from) const
304{
305 return toString().find_first_of(needle, from);
306}
307
308inline std::size_t LilXmlValue::lastIndexOf(const char *needle, size_t from) const
309{
310 return toString().find_last_of(needle, from);
311}
312
313inline std::size_t LilXmlValue::lastIndexOf(const std::string &needle, size_t from) const
314{
315 return toString().find_last_of(needle, from);
316}
317
318inline bool LilXmlValue::startsWith(const char *needle) const
319{
320 return indexOf(needle) == 0;
321}
322
323inline bool LilXmlValue::startsWith(const std::string &needle) const
324{
325 return indexOf(needle) == 0;
326}
327
328inline bool LilXmlValue::endsWith(const char *needle) const
329{
330 return lastIndexOf(needle) == (size() - strlen(needle));
331}
332
333inline 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
350inline bool LilXmlAttribute::isValid() const
351{
352 return mHandle != nullptr;
353}
354
355
356inline 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
372inline 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
405inline LilXmlAttribute LilXmlElement::getAttribute(const char *name) const
406{
407 return LilXmlAttribute(findXMLAtt(mHandle, name));
408}
409
410inline LilXmlAttribute LilXmlElement::addAttribute(const char *name, const char *value)
411{
412 return LilXmlAttribute(addXMLAtt(mHandle, name, value));
413}
414
415inline void LilXmlElement::removeAttribute(const char *name)
416{
417 rmXMLAtt(mHandle, name);
418}
419
424
425inline void LilXmlElement::setContext(const char *data)
426{
427 editXMLEle(mHandle, data);
428}
429
430inline void LilXmlElement::print(FILE *f, int level) const
431{
432 prXMLEle(f, handle(), level);
433}
434
435// LilXmlDocument Implementation
436
437inline LilXmlDocument::LilXmlDocument(XMLEle *root)
438 : mRoot(root, [](XMLEle* root) { if (root) delXMLEle(root); })
439{ }
440
441inline LilXmlDocument::LilXmlDocument(LilXmlDocument &&other)
442 : mRoot(std::move(other.mRoot))
443{ }
444
445inline 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
466inline 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
480inline LilXmlDocument LilXmlParser::readFromFile(const std::string &fileName)
481{
482 return readFromFile(fileName.c_str());
483}
484
485inline 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
501{
502 return mErrorMessage[0] != '\0';
503}
504
505inline const char *LilXmlParser::errorMessage() const
506{
507 return mErrorMessage;
508}
509
510}
LilXmlAttribute(XMLAtt *a)
Definition indililxml.h:340
const LilXmlValue & value() const
Definition indililxml.h:111
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
Constants and Data structure definitions for the interface to the reference INDI C API implementation...
ISState
Switch state.
Definition indiapi.h:148
@ ISS_OFF
Definition indiapi.h:149
IPerm
Permission hint, with respect to client.
Definition indiapi.h:181
@ IP_RO
Definition indiapi.h:182
IPState
Property state.
Definition indiapi.h:158
@ IPS_OK
Definition indiapi.h:160
ISRule
Switch vector rule hint.
Definition indiapi.h:170
@ ISR_1OFMANY
Definition indiapi.h:171
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:194
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:819
int crackIPState(const char *str, IPState *ip)
Extract property state (Idle, OK, Busy, Alert) from the supplied string.
Definition indidevapi.c:793
int crackISRule(const char *str, ISRule *ip)
Extract switch rule (OneOfMany, OnlyOne..etc) from the supplied string.
Definition indidevapi.c:832
int crackISState(const char *str, ISState *ip)
Extract switch state (On or Off) from the supplied string.
Definition indidevapi.c:808
Interface to the reference INDI C API device implementation on the Device Driver side.
#define MAXRBUF
Definition indidriver.c:52
XMLEle * nextXMLEle(XMLEle *ep, int init)
Iterate an XML element for a list of nesetd XML elements.
Definition lilxml.cpp:555
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
char * tagXMLEle(XMLEle *ep)
Return the tag of an XML element.
Definition lilxml.cpp:600
char * nameXMLAtt(XMLAtt *ap)
Return the name of an XML attribute.
Definition lilxml.cpp:618
XMLEle ** parseXMLChunk(LilXML *lp, char *buf, int size, char ynot[])
Process an XML chunk.
Definition lilxml.cpp:215
char * valuXMLAtt(XMLAtt *ap)
Return the value of an XML attribute.
Definition lilxml.cpp:624
void editXMLEle(XMLEle *ep, const char *pcdata)
set the pcdata of the given element
Definition lilxml.cpp:698
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
void delXMLEle(XMLEle *ep)
delXMLEle Delete XML element.
Definition lilxml.cpp:167
char * pcdataXMLEle(XMLEle *ep)
Return the pcdata of an XML element.
Definition lilxml.cpp:606
void delLilXML(LilXML *lp)
Delete a lilxml parser.
Definition lilxml.cpp:159
XMLAtt * addXMLAtt(XMLEle *ep, const char *name, const char *valu)
Add an XML attribute to an existing XML element.
Definition lilxml.cpp:706
XMLEle * readXMLFile(FILE *fp, LilXML *lp, char ynot[])
Handy wrapper to read one xml file.
Definition lilxml.cpp:653
int pcdatalenXMLEle(XMLEle *ep)
Return the number of characters in pcdata in an XML element.
Definition lilxml.cpp:612
A little DOM-style library to handle parsing and processing an XML file.
struct LilXML_ LilXML
Definition lilxml.h:82
struct xml_ele_ XMLEle
Definition lilxml.h:81
Namespace to encapsulate INDI client, drivers, and mediator classes.