Line data Source code
1 : /// IndiXmlParser.cpp
2 : ///
3 : /// @author Paul Grenz
4 : ///
5 : ////////////////////////////////////////////////////////////////////////////////
6 :
7 : #include <stdexcept>
8 : #include <string>
9 : #include <cstring>
10 : #include <cstdlib>
11 : #include <iostream>
12 : #include <iomanip>
13 : #include <sstream>
14 : #include "../liblilxml/base64.h"
15 : #include "IndiMessage.hpp"
16 : #include "IndiProperty.hpp"
17 : #include "IndiXmlParser.hpp"
18 :
19 : using std::runtime_error;
20 : using std::string;
21 : using std::stringbuf;
22 : using std::stringstream;
23 : using std::boolalpha;
24 : using std::vector;
25 : using std::istream;
26 : using std::ostream;
27 : using pcf::IndiElement;
28 : using pcf::IndiMessage;
29 : using pcf::IndiProperty;
30 : using pcf::IndiXmlParser;
31 :
32 : ////////////////////////////////////////////////////////////////////////////////
33 : /// Constructor.
34 :
35 12 : IndiXmlParser::IndiXmlParser( const string &szProtocolVersion )
36 : {
37 12 : init( szProtocolVersion );
38 12 : }
39 :
40 : ////////////////////////////////////////////////////////////////////////////////
41 : /// Constructor from an existing IndiMessage.
42 :
43 10 : IndiXmlParser::IndiXmlParser( const IndiMessage &imSend,
44 10 : const string &szProtocolVersion )
45 : {
46 10 : init( szProtocolVersion );
47 :
48 10 : const IndiProperty &ipSend = imSend.getProperty();
49 :
50 : // Each Indi message has different attributes depending on the type of message.
51 10 : switch ( imSend.getType() )
52 : {
53 0 : case IndiMessage::Define:
54 0 : switch ( ipSend.getType() )
55 : {
56 0 : case IndiProperty::BLOB: createDefBLOBVector( ipSend ); break;
57 0 : case IndiProperty::Light: createDefLightVector( ipSend ); break;
58 0 : case IndiProperty::Number: createDefNumberVector( ipSend ); break;
59 0 : case IndiProperty::Switch: createDefSwitchVector( ipSend ); break;
60 0 : case IndiProperty::Text: createDefTextVector( ipSend ); break;
61 0 : default:
62 : case IndiProperty::Unknown:
63 0 : throw runtime_error( "Unknown INDI property DEF type is not allowed." );
64 : break;
65 : }
66 0 : break;
67 :
68 0 : case IndiMessage::Delete:
69 0 : createDelProperty( ipSend );
70 0 : break;
71 :
72 0 : case IndiMessage::EnableBLOB:
73 0 : createEnableBLOB( ipSend );
74 0 : break;
75 :
76 10 : case IndiMessage::GetProperties:
77 10 : createGetProperties( ipSend );
78 10 : break;
79 :
80 0 : case IndiMessage::Message:
81 0 : createMessage( ipSend );
82 0 : break;
83 :
84 0 : case IndiMessage::NewProperty:
85 0 : switch ( ipSend.getType() )
86 : {
87 0 : case IndiProperty::BLOB: createNewBLOBVector( ipSend ); break;
88 0 : case IndiProperty::Number: createNewNumberVector( ipSend ); break;
89 0 : case IndiProperty::Switch: createNewSwitchVector( ipSend ); break;
90 0 : case IndiProperty::Text: createNewTextVector( ipSend ); break;
91 0 : default:
92 : case IndiProperty::Unknown:
93 0 : throw runtime_error( "Unknown INDI property NEW type is not allowed." );
94 : break;
95 : }
96 0 : break;
97 :
98 0 : case IndiMessage::SetProperty:
99 0 : switch ( ipSend.getType() )
100 : {
101 0 : case IndiProperty::BLOB: createSetBLOBVector( ipSend ); break;
102 0 : case IndiProperty::Light: createSetLightVector( ipSend ); break;
103 0 : case IndiProperty::Number: createSetNumberVector( ipSend ); break;
104 0 : case IndiProperty::Switch: createSetSwitchVector( ipSend ); break;
105 0 : case IndiProperty::Text: createSetTextVector( ipSend ); break;
106 0 : default:
107 : case IndiProperty::Unknown:
108 0 : throw runtime_error( "Unknown INDI property SET type is not allowed." );
109 : break;
110 : }
111 0 : break;
112 :
113 0 : case IndiMessage::Unknown:
114 0 : throw runtime_error( "Unknown INDI property type is not allowed." );
115 : break;
116 : }
117 10 : }
118 :
119 : ////////////////////////////////////////////////////////////////////////////////
120 : /// createSafeXmlString
121 : /// This takes any string and replaces the '&', '<', '>', '\', and '"'
122 : /// with its equivalent XML entity: & < > ' and "
123 :
124 0 : string IndiXmlParser::createSafeXmlString( const string &szText )
125 : {
126 0 : return ::entityXML( (char*)( szText.c_str() ) );
127 : }
128 :
129 : ////////////////////////////////////////////////////////////////////////////////
130 : // DefTextVector REQUIRED: device name state perm
131 : // DefTextVector IMPLIED: label group timeout timestamp message
132 : // DefText REQUIRED: name
133 : // DefText IMPLIED: label
134 :
135 0 : void IndiXmlParser::createDefTextVector( const IndiProperty &ip )
136 : {
137 : // What kind of message is this?
138 0 : string szTag = "defTextVector";
139 0 : string szElementTag = "defText";
140 0 : string szDescrip = szTag + " '" + ip.getName() + "'";
141 :
142 : // Clear out the xml stream.
143 0 : m_ssXml.str("");
144 0 : m_ssXml << "<" << szTag;
145 :
146 : // "required" means that the attribute must be added and contain a valid
147 : // entry. If it is not part of the generated XML, it is an error.
148 0 : if ( ip.hasValidDevice() == false )
149 0 : throw runtime_error( szDescrip + " must have attribute 'device' defined." );
150 0 : if ( ip.hasValidName() == false )
151 0 : throw runtime_error( szDescrip + " must have attribute 'name' defined." );
152 0 : if ( ip.hasValidState() == false )
153 0 : throw runtime_error( szDescrip + " must have attribute 'state' defined." );
154 0 : if ( ip.hasValidPerm() == false )
155 0 : throw runtime_error( szDescrip + " must have attribute 'perm' defined." );
156 :
157 0 : m_ssXml << " device=\"" << ip.getDevice() << "\"";
158 0 : m_ssXml << " name=\"" << ip.getName() << "\"";
159 0 : m_ssXml << " state=\"" << ip.getPropertyStateString( ip.getState() ) << "\"";
160 0 : m_ssXml << " perm=\"" << ip.getPropertyPermString( ip.getPerm() ) << "\"";
161 :
162 : // "implied" means that if they are not defined, don't add them. Adding an
163 : // empty "implied" attribute to the generated XML is an error.
164 0 : if ( ip.hasValidLabel() == true )
165 0 : m_ssXml << " label=\"" << ip.getLabel() << "\"";
166 0 : if ( ip.hasValidGroup() == true )
167 0 : m_ssXml << " group=\"" << ip.getGroup() << "\"";
168 0 : if ( ip.hasValidTimeout() == true )
169 0 : m_ssXml << " timeout=\"" << ip.getTimeout() << "\"";
170 0 : m_ssXml << " timestamp=\"" << ip.getTimeStamp().getFormattedIso8601Str() << "\"";
171 0 : if ( ip.hasValidMessage() == true )
172 0 : m_ssXml << " message=\"" << ip.getMessage() << "\"";
173 :
174 0 : m_ssXml << ">\r\n";
175 :
176 0 : for ( unsigned int ii = 0; ii < ip.getNumElements(); ii++ )
177 : {
178 0 : m_ssXml << "\t<" << szElementTag;
179 :
180 : // "required" means that the attribute must be added and contain a valid
181 : // entry. If it is not part of the generated XML, it is an error.
182 0 : if ( ip[ii].hasValidName() == false )
183 0 : throw runtime_error( szElementTag + " must have attribute 'name' defined." );
184 :
185 0 : m_ssXml << " name=\"" << ip[ii].getName() << "\"";
186 :
187 : // "implied" means that if they are not defined, don't add them. Adding an
188 : // empty "implied" attribute to the generated XML is an error.
189 0 : if ( ip[ii].hasValidLabel() == true )
190 0 : m_ssXml << " label=\"" << ip[ii].getLabel() << "\"";
191 :
192 0 : m_ssXml << ">\r\n";
193 :
194 : // Now add the data for the element...
195 0 : m_ssXml << createSafeXmlString( ip[ii].getValue() ) << "\r\n";
196 0 : m_ssXml << "\t</" << szElementTag << ">\r\n";
197 : }
198 0 : m_ssXml << "</" << szTag << ">\r\n";
199 0 : }
200 :
201 : ////////////////////////////////////////////////////////////////////////////////
202 : // SetTextVector REQUIRED: device name
203 : // SetTextVector IMPLIED: state timeout timestamp message
204 : // oneText REQUIRED: name
205 :
206 0 : void IndiXmlParser::createSetTextVector( const IndiProperty &ip )
207 : {
208 : // What kind of message is this?
209 0 : string szTag = "setTextVector";
210 0 : string szElementTag = "oneText";
211 0 : string szDescrip = szTag + " '" + ip.getName() + "'";
212 :
213 : // Clear out the xml stream.
214 0 : m_ssXml.str("");
215 0 : m_ssXml << "<" << szTag;
216 :
217 : // "required" means that the attribute must be added and contain a valid
218 : // entry. If it is not part of the generated XML, it is an error.
219 0 : if ( ip.hasValidDevice() == false )
220 0 : throw runtime_error( szDescrip + " must have attribute 'device' defined." );
221 0 : if ( ip.hasValidName() == false )
222 0 : throw runtime_error( szDescrip + " must have attribute 'name' defined." );
223 :
224 0 : m_ssXml << " device=\"" << ip.getDevice() << "\"";
225 0 : m_ssXml << " name=\"" << ip.getName() << "\"";
226 :
227 : // "implied" means that if they are not defined, don't add them. Adding an
228 : // empty "implied" attribute to the generated XML is an error.
229 0 : if ( ip.hasValidState() == true )
230 0 : m_ssXml << " state=\"" << ip.getPropertyStateString( ip.getState() ) << "\"";
231 0 : if ( ip.hasValidTimeout() == true )
232 0 : m_ssXml << " timeout=\"" << ip.getTimeout() << "\"";
233 0 : m_ssXml << " timestamp=\"" << ip.getTimeStamp().getFormattedIso8601Str() << "\"";
234 0 : if ( ip.hasValidMessage() == true )
235 0 : m_ssXml << " message=\"" << ip.getMessage() << "\"";
236 :
237 0 : m_ssXml << ">\r\n";
238 :
239 0 : for ( unsigned int ii = 0; ii < ip.getNumElements(); ii++ )
240 : {
241 0 : m_ssXml << "\t<" << szElementTag;
242 :
243 : // "required" means that the attribute must be added and contain a valid
244 : // entry. If it is not part of the generated XML, it is an error.
245 0 : if ( ip[ii].hasValidName() == false )
246 0 : throw runtime_error( szElementTag + " must have attribute 'name' defined." );
247 :
248 0 : m_ssXml << " name=\"" << ip[ii].getName() << "\"";
249 :
250 0 : m_ssXml << ">\r\n";
251 :
252 : // Now add the data for the element...
253 0 : m_ssXml << createSafeXmlString( ip[ii].getValue() ) << "\r\n";
254 0 : m_ssXml << "\t</" << szElementTag << ">\r\n";
255 : }
256 0 : m_ssXml << "</" << szTag << ">\r\n";
257 0 : }
258 :
259 : ////////////////////////////////////////////////////////////////////////////////
260 : // NewTextVector REQUIRED: device name
261 : // NewTextVector IMPLIED: timestamp
262 : // oneText REQUIRED: name
263 :
264 0 : void IndiXmlParser::createNewTextVector( const IndiProperty &ip )
265 : {
266 : // What kind of message is this?
267 0 : string szTag = "newTextVector";
268 0 : string szElementTag = "oneText";
269 0 : string szDescrip = szTag + " '" + ip.getName() + "'";
270 :
271 : // Clear out the xml stream.
272 0 : m_ssXml.str("");
273 0 : m_ssXml << "<" << szTag;
274 :
275 : // "required" means that the attribute must be added and contain a valid
276 : // entry. If it is not part of the generated XML, it is an error.
277 0 : if ( ip.hasValidDevice() == false )
278 0 : throw runtime_error( szDescrip + " must have attribute 'device' defined." );
279 0 : if ( ip.hasValidName() == false )
280 0 : throw runtime_error( szDescrip + " must have attribute 'name' defined." );
281 :
282 0 : m_ssXml << " device=\"" << ip.getDevice() << "\"";
283 0 : m_ssXml << " name=\"" << ip.getName() << "\"";
284 :
285 : // "implied" means that if they are not defined, don't add them. Adding an
286 : // empty "implied" attribute to the generated XML is an error.
287 0 : m_ssXml << " timestamp=\"" << ip.getTimeStamp().getFormattedIso8601Str() << "\"";
288 :
289 0 : m_ssXml << ">\r\n";
290 :
291 0 : for ( unsigned int ii = 0; ii < ip.getNumElements(); ii++ )
292 : {
293 0 : m_ssXml << "\t<" << szElementTag;
294 :
295 : // "required" means that the attribute must be added and contain a valid
296 : // entry. If it is not part of the generated XML, it is an error.
297 0 : if ( ip[ii].hasValidName() == false )
298 0 : throw runtime_error( szElementTag + " must have attribute 'name' defined." );
299 :
300 0 : m_ssXml << " name=\"" << ip[ii].getName() << "\"";
301 :
302 0 : m_ssXml << ">\r\n";
303 :
304 : // Now add the data for the element...
305 0 : m_ssXml << createSafeXmlString( ip[ii].getValue() ) << "\r\n";
306 0 : m_ssXml << "\t</" << szElementTag << ">\r\n";
307 : }
308 0 : m_ssXml << "</" << szTag << ">\r\n";
309 0 : }
310 :
311 : ////////////////////////////////////////////////////////////////////////////////
312 : // DefNumberVector REQUIRED: device name state perm
313 : // DefNumberVector IMPLIED: label group timeout timestamp message
314 : // DefNumber REQUIRED: name format min max step
315 : // DefNumber IMPLIED: label
316 :
317 0 : void IndiXmlParser::createDefNumberVector( const IndiProperty &ip )
318 : {
319 : // What kind of message is this?
320 0 : string szTag = "defNumberVector";
321 0 : string szElementTag = "defNumber";
322 0 : string szDescrip = szTag + " '" + ip.getName() + "'";
323 :
324 : // Clear out the xml stream.
325 0 : m_ssXml.str("");
326 0 : m_ssXml << "<" << szTag;
327 :
328 : // "required" means that the attribute must be added and contain a valid
329 : // entry. If it is not part of the generated XML, it is an error.
330 0 : if ( ip.hasValidDevice() == false )
331 0 : throw runtime_error( szDescrip + " must have attribute 'device' defined." );
332 0 : if ( ip.hasValidName() == false )
333 0 : throw runtime_error( szDescrip + " must have attribute 'name' defined." );
334 0 : if ( ip.hasValidState() == false )
335 0 : throw runtime_error( szDescrip + " must have attribute 'state' defined." );
336 0 : if ( ip.hasValidPerm() == false )
337 0 : throw runtime_error( szDescrip + " must have attribute 'perm' defined." );
338 :
339 0 : m_ssXml << " device=\"" << ip.getDevice() << "\"";
340 0 : m_ssXml << " name=\"" << ip.getName() << "\"";
341 0 : m_ssXml << " state=\"" << ip.getPropertyStateString( ip.getState() ) << "\"";
342 0 : m_ssXml << " perm=\"" << ip.getPropertyPermString( ip.getPerm() ) << "\"";
343 :
344 : // "implied" means that if they are not defined, don't add them. Adding an
345 : // empty "implied" attribute to the generated XML is an error.
346 0 : if ( ip.hasValidLabel() == true )
347 0 : m_ssXml << " label=\"" << ip.getLabel() << "\"";
348 0 : if ( ip.hasValidGroup() == true )
349 0 : m_ssXml << " group=\"" << ip.getGroup() << "\"";
350 0 : if ( ip.hasValidTimeout() == true )
351 0 : m_ssXml << " timeout=\"" << ip.getTimeout() << "\"";
352 0 : m_ssXml << " timestamp=\"" << ip.getTimeStamp().getFormattedIso8601Str() << "\"";
353 0 : if ( ip.hasValidMessage() == true )
354 0 : m_ssXml << " message=\"" << ip.getMessage() << "\"";
355 :
356 0 : m_ssXml << ">\r\n";
357 :
358 0 : for ( unsigned int ii = 0; ii < ip.getNumElements(); ii++ )
359 : {
360 0 : m_ssXml << "\t<" << szElementTag;
361 :
362 : // "required" means that the attribute must be added and contain a valid
363 : // entry. If it is not part of the generated XML, it is an error.
364 0 : if ( ip[ii].hasValidName() == false )
365 0 : throw runtime_error( szElementTag + " must have attribute 'name' defined." );
366 0 : if ( ip[ii].hasValidFormat() == false )
367 0 : throw runtime_error( szElementTag + " must have attribute 'format' defined." );
368 0 : if ( ip[ii].hasValidMin() == false )
369 0 : throw runtime_error( szElementTag + " must have attribute 'min' defined." );
370 0 : if ( ip[ii].hasValidMax() == false )
371 0 : throw runtime_error( szElementTag + " must have attribute 'max' defined." );
372 0 : if ( ip[ii].hasValidStep() == false )
373 0 : throw runtime_error( szElementTag + " must have attribute 'step' defined." );
374 :
375 0 : m_ssXml << " name=\"" << ip[ii].getName() << "\"";
376 0 : m_ssXml << " format=\"" << ip[ii].getFormat() << "\"";
377 0 : m_ssXml << " min=\"" << ip[ii].getMin() << "\"";
378 0 : m_ssXml << " max=\"" << ip[ii].getMax() << "\"";
379 0 : m_ssXml << " step=\"" << ip[ii].getStep() << "\"";
380 :
381 : // "implied" means that if they are not defined, don't add them. Adding an
382 : // empty "implied" attribute to the generated XML is an error.
383 0 : if ( ip[ii].hasValidLabel() == true )
384 0 : m_ssXml << " label=\"" << ip[ii].getLabel() << "\"";
385 :
386 0 : m_ssXml << ">\r\n";
387 :
388 : // Now add the data for the element...
389 0 : m_ssXml << createSafeXmlString( ip[ii].getValue() ) << "\r\n";
390 0 : m_ssXml << "\t</" << szElementTag << ">\r\n";
391 : }
392 0 : m_ssXml << "</" << szTag << ">\r\n";
393 0 : }
394 :
395 : ////////////////////////////////////////////////////////////////////////////////
396 : // SetNumberVector REQUIRED: device name
397 : // SetNumberVector IMPLIED: state timeout timestamp message
398 : // oneNumber REQUIRED: name
399 :
400 0 : void IndiXmlParser::createSetNumberVector( const IndiProperty &ip )
401 : {
402 : // What kind of message is this?
403 0 : string szTag = "setNumberVector";
404 0 : string szElementTag = "oneNumber";
405 0 : string szDescrip = szTag + " '" + ip.getName() + "'";
406 :
407 : // Clear out the xml stream.
408 0 : m_ssXml.str("");
409 0 : m_ssXml << "<" << szTag;
410 :
411 : // "required" means that the attribute must be added and contain a valid
412 : // entry. If it is not part of the generated XML, it is an error.
413 0 : if ( ip.hasValidDevice() == false )
414 0 : throw runtime_error( szDescrip + " must have attribute 'device' defined." );
415 0 : if ( ip.hasValidName() == false )
416 0 : throw runtime_error( szDescrip + " must have attribute 'name' defined." );
417 :
418 0 : m_ssXml << " device=\"" << ip.getDevice() << "\"";
419 0 : m_ssXml << " name=\"" << ip.getName() << "\"";
420 :
421 : // "implied" means that if they are not defined, don't add them. Adding an
422 : // empty "implied" attribute to the generated XML is an error.
423 0 : if ( ip.hasValidState() == true )
424 0 : m_ssXml << " state=\"" << ip.getPropertyStateString( ip.getState() ) << "\"";
425 0 : if ( ip.hasValidTimeout() == true )
426 0 : m_ssXml << " timeout=\"" << ip.getTimeout() << "\"";
427 0 : m_ssXml << " timestamp=\"" << ip.getTimeStamp().getFormattedIso8601Str() << "\"";
428 0 : if ( ip.hasValidMessage() == true )
429 0 : m_ssXml << " message=\"" << ip.getMessage() << "\"";
430 :
431 0 : m_ssXml << ">\r\n";
432 :
433 0 : for ( unsigned int ii = 0; ii < ip.getNumElements(); ii++ )
434 : {
435 0 : m_ssXml << "\t<" << szElementTag;
436 :
437 : // "required" means that the attribute must be added and contain a valid
438 : // entry. If it is not part of the generated XML, it is an error.
439 0 : if ( ip[ii].hasValidName() == false )
440 0 : throw runtime_error( szElementTag + " must have attribute 'name' defined." );
441 :
442 0 : m_ssXml << " name=\"" << ip[ii].getName() << "\"";
443 :
444 0 : m_ssXml << ">\r\n";
445 :
446 : // Now add the data for the element...
447 0 : m_ssXml << createSafeXmlString( ip[ii].getValue() ) << "\r\n";
448 0 : m_ssXml << "\t</" << szElementTag << ">\r\n";
449 : }
450 0 : m_ssXml << "</" << szTag << ">\r\n";
451 0 : }
452 :
453 : ////////////////////////////////////////////////////////////////////////////////
454 : // NewNumberVector REQUIRED: device name
455 : // NewNumberVector IMPLIED: timestamp
456 : // oneNumber REQUIRED: name
457 :
458 0 : void IndiXmlParser::createNewNumberVector( const IndiProperty &ip )
459 : {
460 : // What kind of message is this?
461 0 : string szTag = "newNumberVector";
462 0 : string szElementTag = "oneNumber";
463 0 : string szDescrip = szTag + " '" + ip.getName() + "'";
464 :
465 : // Clear out the xml stream.
466 0 : m_ssXml.str("");
467 0 : m_ssXml << "<" << szTag;
468 :
469 : // "required" means that the attribute must be added and contain a valid
470 : // entry. If it is not part of the generated XML, it is an error.
471 0 : if ( ip.hasValidDevice() == false )
472 0 : throw runtime_error( szDescrip + " must have attribute 'device' defined." );
473 0 : if ( ip.hasValidName() == false )
474 0 : throw runtime_error( szDescrip + " must have attribute 'name' defined." );
475 :
476 0 : m_ssXml << " device=\"" << ip.getDevice() << "\"";
477 0 : m_ssXml << " name=\"" << ip.getName() << "\"";
478 :
479 : // "implied" means that if they are not defined, don't add them. Adding an
480 : // empty "implied" attribute to the generated XML is an error.
481 0 : m_ssXml << " timestamp=\"" << ip.getTimeStamp().getFormattedIso8601Str() << "\"";
482 :
483 0 : m_ssXml << ">\r\n";
484 :
485 0 : for ( unsigned int ii = 0; ii < ip.getNumElements(); ii++ )
486 : {
487 0 : m_ssXml << "\t<" << szElementTag;
488 :
489 : // "required" means that the attribute must be added and contain a valid
490 : // entry. If it is not part of the generated XML, it is an error.
491 0 : if ( ip[ii].hasValidName() == false )
492 0 : throw runtime_error( szElementTag + " must have attribute 'name' defined." );
493 :
494 0 : m_ssXml << " name=\"" << ip[ii].getName() << "\"";
495 :
496 0 : m_ssXml << ">\r\n";
497 :
498 : // Now add the data for the element...
499 0 : m_ssXml << createSafeXmlString( ip[ii].getValue() ) << "\r\n";
500 0 : m_ssXml << "\t</" << szElementTag << ">\r\n";
501 : }
502 0 : m_ssXml << "</" << szTag << ">\r\n";
503 0 : }
504 :
505 : ////////////////////////////////////////////////////////////////////////////////
506 : // DefSwitchVector REQUIRED: device name state perm rule
507 : // DefSwitchVector IMPLIED: label group timeout timestamp message
508 : // DefSwitch REQUIRED: name
509 : // DefSwitch IMPLIED: label
510 :
511 0 : void IndiXmlParser::createDefSwitchVector( const IndiProperty &ip )
512 : {
513 : // What kind of message is this?
514 0 : string szTag = "defSwitchVector";
515 0 : string szElementTag = "defSwitch";
516 0 : string szDescrip = szTag + " '" + ip.getName() + "'";
517 :
518 : // Clear out the xml stream.
519 0 : m_ssXml.str("");
520 0 : m_ssXml << "<" << szTag;
521 :
522 : // "required" means that the attribute must be added and contain a valid
523 : // entry. If it is not part of the generated XML, it is an error.
524 0 : if ( ip.hasValidDevice() == false )
525 0 : throw runtime_error( szDescrip + " must have attribute 'device' defined." );
526 0 : if ( ip.hasValidName() == false )
527 0 : throw runtime_error( szDescrip + " must have attribute 'name' defined." );
528 0 : if ( ip.hasValidState() == false )
529 0 : throw runtime_error( szDescrip + " must have attribute 'state' defined." );
530 0 : if ( ip.hasValidPerm() == false )
531 0 : throw runtime_error( szDescrip + " must have attribute 'perm' defined." );
532 0 : if ( ip.hasValidRule() == false )
533 0 : throw runtime_error( szDescrip + " must have attribute 'rule' defined." );
534 :
535 0 : m_ssXml << " device=\"" << ip.getDevice() << "\"";
536 0 : m_ssXml << " name=\"" << ip.getName() << "\"";
537 0 : m_ssXml << " state=\"" << ip.getPropertyStateString( ip.getState() ) << "\"";
538 0 : m_ssXml << " perm=\"" << ip.getPropertyPermString( ip.getPerm() ) << "\"";
539 0 : m_ssXml << " rule=\"" << ip.getSwitchRuleString( ip.getRule() ) << "\"";
540 :
541 : // "implied" means that if they are not defined, don't add them. Adding an
542 : // empty "implied" attribute to the generated XML is an error.
543 0 : if ( ip.hasValidLabel() == true )
544 0 : m_ssXml << " label=\"" << ip.getLabel() << "\"";
545 0 : if ( ip.hasValidGroup() == true )
546 0 : m_ssXml << " group=\"" << ip.getGroup() << "\"";
547 0 : if ( ip.hasValidTimeout() == true )
548 0 : m_ssXml << " timeout=\"" << ip.getTimeout() << "\"";
549 0 : m_ssXml << " timestamp=\"" << ip.getTimeStamp().getFormattedIso8601Str() << "\"";
550 0 : if ( ip.hasValidMessage() == true )
551 0 : m_ssXml << " message=\"" << ip.getMessage() << "\"";
552 :
553 0 : m_ssXml << ">\r\n";
554 :
555 0 : for ( unsigned int ii = 0; ii < ip.getNumElements(); ii++ )
556 : {
557 0 : m_ssXml << "\t<" << szElementTag;
558 :
559 : // "required" means that the attribute must be added and contain a valid
560 : // entry. If it is not part of the generated XML, it is an error.
561 0 : if ( ip[ii].hasValidName() == false )
562 0 : throw runtime_error( szElementTag + " must have attribute 'name' defined." );
563 :
564 0 : m_ssXml << " name=\"" << ip[ii].getName() << "\"";
565 :
566 : // "implied" means that if they are not defined, don't add them. Adding an
567 : // empty "implied" attribute to the generated XML is an error.
568 0 : if ( ip[ii].hasValidLabel() == true )
569 0 : m_ssXml << " label=\"" << ip[ii].getLabel() << "\"";
570 :
571 0 : m_ssXml << ">\r\n";
572 :
573 : // Now add the data for the element...
574 0 : m_ssXml << IndiElement::getSwitchStateString( ip[ii].getSwitchState() ) << "\r\n";
575 0 : m_ssXml << "\t</" << szElementTag << ">\r\n";
576 : }
577 0 : m_ssXml << "</" << szTag << ">\r\n";
578 0 : }
579 :
580 : ////////////////////////////////////////////////////////////////////////////////
581 : // SetSwitchVector REQUIRED: device name
582 : // SetSwitchVector IMPLIED: state timeout timestamp message
583 : // oneSwitch REQUIRED: name
584 :
585 0 : void IndiXmlParser::createSetSwitchVector( const IndiProperty &ip )
586 : {
587 : // What kind of message is this?
588 0 : string szTag = "setSwitchVector";
589 0 : string szElementTag = "oneSwitch";
590 0 : string szDescrip = szTag + " '" + ip.getName() + "'";
591 :
592 : // Clear out the xml stream.
593 0 : m_ssXml.str("");
594 0 : m_ssXml << "<" << szTag;
595 :
596 : // "required" means that the attribute must be added and contain a valid
597 : // entry. If it is not part of the generated XML, it is an error.
598 0 : if ( ip.hasValidDevice() == false )
599 0 : throw runtime_error( szDescrip + " must have attribute 'device' defined." );
600 0 : if ( ip.hasValidName() == false )
601 0 : throw runtime_error( szDescrip + " must have attribute 'name' defined." );
602 :
603 0 : m_ssXml << " device=\"" << ip.getDevice() << "\"";
604 0 : m_ssXml << " name=\"" << ip.getName() << "\"";
605 :
606 : // "implied" means that if they are not defined, don't add them. Adding an
607 : // empty "implied" attribute to the generated XML is an error.
608 0 : if ( ip.hasValidState() == true )
609 0 : m_ssXml << " state=\"" << IndiProperty::getPropertyStateString( ip.getState() ) << "\"";
610 0 : if ( ip.hasValidTimeout() == true )
611 0 : m_ssXml << " timeout=\"" << ip.getTimeout() << "\"";
612 0 : m_ssXml << " timestamp=\"" << ip.getTimeStamp().getFormattedIso8601Str() << "\"";
613 0 : if ( ip.hasValidMessage() == true )
614 0 : m_ssXml << " message=\"" << ip.getMessage() << "\"";
615 :
616 0 : m_ssXml << ">\r\n";
617 :
618 0 : for ( unsigned int ii = 0; ii < ip.getNumElements(); ii++ )
619 : {
620 0 : m_ssXml << "\t<" << szElementTag;
621 :
622 : // "required" means that the attribute must be added and contain a valid
623 : // entry. If it is not part of the generated XML, it is an error.
624 0 : if ( ip[ii].hasValidName() == false )
625 0 : throw runtime_error( szElementTag + " must have attribute 'name' defined." );
626 :
627 0 : m_ssXml << " name=\"" << ip[ii].getName() << "\"";
628 :
629 0 : m_ssXml << ">\r\n";
630 :
631 : // Now add the data for the element...
632 0 : m_ssXml << IndiElement::getSwitchStateString( ip[ii].getSwitchState() ) << "\r\n";
633 0 : m_ssXml << "\t</" << szElementTag << ">\r\n";
634 : }
635 0 : m_ssXml << "</" << szTag << ">\r\n";
636 0 : }
637 :
638 : ////////////////////////////////////////////////////////////////////////////////
639 : // NewSwitchVector REQUIRED: device name
640 : // NewSwitchVector IMPLIED: timestamp
641 : // oneSwitch REQUIRED: name
642 :
643 0 : void IndiXmlParser::createNewSwitchVector( const IndiProperty &ip )
644 : {
645 : // What kind of message is this?
646 0 : string szTag = "newSwitchVector";
647 0 : string szElementTag = "oneSwitch";
648 0 : string szDescrip = szTag + " '" + ip.getName() + "'";
649 :
650 : // Clear out the xml stream.
651 0 : m_ssXml.str("");
652 0 : m_ssXml << "<" << szTag;
653 :
654 : // "required" means that the attribute must be added and contain a valid
655 : // entry. If it is not part of the generated XML, it is an error.
656 0 : if ( ip.hasValidDevice() == false )
657 0 : throw runtime_error( szDescrip + " must have attribute 'device' defined." );
658 0 : if ( ip.hasValidName() == false )
659 0 : throw runtime_error( szDescrip + " must have attribute 'name' defined." );
660 :
661 0 : m_ssXml << " device=\"" << ip.getDevice() << "\"";
662 0 : m_ssXml << " name=\"" << ip.getName() << "\"";
663 :
664 : // "implied" means that if they are not defined, don't add them. Adding an
665 : // empty "implied" attribute to the generated XML is an error.
666 0 : m_ssXml << " timestamp=\"" << ip.getTimeStamp().getFormattedIso8601Str() << "\"";
667 :
668 0 : m_ssXml << ">\r\n";
669 :
670 0 : for ( unsigned int ii = 0; ii < ip.getNumElements(); ii++ )
671 : {
672 0 : m_ssXml << "\t<" << szElementTag;
673 :
674 : // "required" means that the attribute must be added and contain a valid
675 : // entry. If it is not part of the generated XML, it is an error.
676 0 : if ( ip[ii].hasValidName() == false )
677 0 : throw runtime_error( szElementTag + " must have attribute 'name' defined." );
678 :
679 0 : m_ssXml << " name=\"" << ip[ii].getName() << "\"";
680 :
681 0 : m_ssXml << ">\r\n";
682 :
683 : // Now add the data for the element...
684 0 : m_ssXml << IndiElement::getSwitchStateString( ip[ii].getSwitchState() ) << "\r\n";
685 0 : m_ssXml << "\t</" << szElementTag << ">\r\n";
686 : }
687 0 : m_ssXml << "</" << szTag << ">\r\n";
688 0 : }
689 :
690 : ////////////////////////////////////////////////////////////////////////////////
691 : // DefLightVector REQUIRED: device name state
692 : // DefLightVector IMPLIED: label group timestamp message
693 : // DefLight REQUIRED: name
694 : // DefLight IMPLIED: label
695 :
696 0 : void IndiXmlParser::createDefLightVector( const IndiProperty &ip )
697 : {
698 : // What kind of message is this?
699 0 : string szTag = "defLightVector";
700 0 : string szElementTag = "defLight";
701 0 : string szDescrip = szTag + " '" + ip.getName() + "'";
702 :
703 : // Clear out the xml stream.
704 0 : m_ssXml.str("");
705 0 : m_ssXml << "<" << szTag;
706 :
707 : // "required" means that the attribute must be added and contain a valid
708 : // entry. If it is not part of the generated XML, it is an error.
709 0 : if ( ip.hasValidDevice() == false )
710 0 : throw runtime_error( szDescrip + " must have attribute 'device' defined." );
711 0 : if ( ip.hasValidName() == false )
712 0 : throw runtime_error( szDescrip + " must have attribute 'name' defined." );
713 0 : if ( ip.hasValidState() == false )
714 0 : throw runtime_error( szDescrip + " must have attribute 'state' defined." );
715 :
716 0 : m_ssXml << " device=\"" << ip.getDevice() << "\"";
717 0 : m_ssXml << " name=\"" << ip.getName() << "\"";
718 0 : m_ssXml << " state=\"" << ip.getPropertyStateString( ip.getState() ) << "\"";
719 :
720 : // "implied" means that if they are not defined, don't add them. Adding an
721 : // empty "implied" attribute to the generated XML is an error.
722 0 : if ( ip.hasValidLabel() == true )
723 0 : m_ssXml << " label=\"" << ip.getLabel() << "\"";
724 0 : if ( ip.hasValidGroup() == true )
725 0 : m_ssXml << " group=\"" << ip.getGroup() << "\"";
726 0 : m_ssXml << " timestamp=\"" << ip.getTimeStamp().getFormattedIso8601Str() << "\"";
727 0 : if ( ip.hasValidMessage() == true )
728 0 : m_ssXml << " message=\"" << ip.getMessage() << "\"";
729 :
730 0 : m_ssXml << ">\r\n";
731 :
732 0 : for ( unsigned int ii = 0; ii < ip.getNumElements(); ii++ )
733 : {
734 0 : m_ssXml << "\t<" << szElementTag;
735 :
736 : // "required" means that the attribute must be added and contain a valid
737 : // entry. If it is not part of the generated XML, it is an error.
738 0 : if ( ip[ii].hasValidName() == false )
739 0 : throw runtime_error( szElementTag + " must have attribute 'name' defined." );
740 :
741 0 : m_ssXml << " name=\"" << ip[ii].getName() << "\"";
742 :
743 : // "implied" means that if they are not defined, don't add them. Adding an
744 : // empty "implied" attribute to the generated XML is an error.
745 0 : if ( ip[ii].hasValidLabel() == true )
746 0 : m_ssXml << " label=\"" << ip[ii].getLabel() << "\"";
747 :
748 0 : m_ssXml << ">\r\n";
749 :
750 : // Now add the data for the element...
751 0 : m_ssXml << IndiElement::getLightStateString( ip[ii].getLightState() ) << "\r\n";
752 0 : m_ssXml << "\t</" << szElementTag << ">\r\n";
753 : }
754 0 : m_ssXml << "</" << szTag << ">\r\n";
755 0 : }
756 :
757 : ////////////////////////////////////////////////////////////////////////////////
758 : // SetLightVector REQUIRED: device name
759 : // SetLightVector IMPLIED: state timestamp message
760 : // oneLight REQUIRED: name
761 :
762 0 : void IndiXmlParser::createSetLightVector( const IndiProperty &ip )
763 : {
764 : // What kind of message is this?
765 0 : string szTag = "setLightVector";
766 0 : string szElementTag = "oneLight";
767 0 : string szDescrip = szTag + " '" + ip.getName() + "'";
768 :
769 : // Clear out the xml stream.
770 0 : m_ssXml.str("");
771 0 : m_ssXml << "<" << szTag;
772 :
773 : // "required" means that the attribute must be added and contain a valid
774 : // entry. If it is not part of the generated XML, it is an error.
775 0 : if ( ip.hasValidDevice() == false )
776 0 : throw runtime_error( szDescrip + " must have attribute 'device' defined." );
777 0 : if ( ip.hasValidName() == false )
778 0 : throw runtime_error( szDescrip + " must have attribute 'name' defined." );
779 :
780 0 : m_ssXml << " device=\"" << ip.getDevice() << "\"";
781 0 : m_ssXml << " name=\"" << ip.getName() << "\"";
782 :
783 : // "implied" means that if they are not defined, don't add them. Adding an
784 : // empty "implied" attribute to the generated XML is an error.
785 0 : if ( ip.hasValidState() == true )
786 0 : m_ssXml << " state=\"" << ip.getPropertyStateString( ip.getState() ) << "\"";
787 0 : m_ssXml << " timestamp=\"" << ip.getTimeStamp().getFormattedIso8601Str() << "\"";
788 0 : if ( ip.hasValidMessage() == true )
789 0 : m_ssXml << " message=\"" << ip.getMessage() << "\"";
790 :
791 0 : m_ssXml << ">\r\n";
792 :
793 0 : for ( unsigned int ii = 0; ii < ip.getNumElements(); ii++ )
794 : {
795 0 : m_ssXml << "\t<" << szElementTag;
796 :
797 : // "required" means that the attribute must be added and contain a valid
798 : // entry. If it is not part of the generated XML, it is an error.
799 0 : if ( ip[ii].hasValidName() == false )
800 0 : throw runtime_error( szElementTag + " must have attribute 'name' defined." );
801 :
802 0 : m_ssXml << " name=\"" << ip[ii].getName() << "\"";
803 :
804 0 : m_ssXml << ">\r\n";
805 :
806 : // Now add the data for the element...
807 0 : m_ssXml << IndiElement::getLightStateString( ip[ii].getLightState() ) << "\r\n";
808 0 : m_ssXml << "\t</" << szElementTag << ">\r\n";
809 : }
810 0 : m_ssXml << "</" << szTag << ">\r\n";
811 0 : }
812 :
813 : ////////////////////////////////////////////////////////////////////////////////
814 : // DefBLOBVector REQUIRED: device name state perm
815 : // DefBLOBVector IMPLIED: label group timeout timestamp message
816 : // DefBLOB REQUIRED: name
817 : // DefBLOB IMPLIED: label
818 :
819 0 : void IndiXmlParser::createDefBLOBVector( const IndiProperty &ip )
820 : {
821 : // What kind of message is this?
822 0 : string szTag = "defBLOBVector";
823 0 : string szElementTag = "defBLOB";
824 0 : string szDescrip = szTag + " '" + ip.getName() + "'";
825 :
826 : // Clear out the xml stream.
827 0 : m_ssXml.str("");
828 0 : m_ssXml << "<" << szTag;
829 :
830 : // "required" means that the attribute must be added and contain a valid
831 : // entry. If it is not part of the generated XML, it is an error.
832 0 : if ( ip.hasValidDevice() == false )
833 0 : throw runtime_error( szDescrip + " must have attribute 'device' defined." );
834 0 : if ( ip.hasValidName() == false )
835 0 : throw runtime_error( szDescrip + " must have attribute 'name' defined." );
836 0 : if ( ip.hasValidState() == false )
837 0 : throw runtime_error( szDescrip + " must have attribute 'state' defined." );
838 0 : if ( ip.hasValidPerm() == false )
839 0 : throw runtime_error( szDescrip + " must have attribute 'perm' defined." );
840 :
841 0 : m_ssXml << " device=\"" << ip.getDevice() << "\"";
842 0 : m_ssXml << " name=\"" << ip.getName() << "\"";
843 0 : m_ssXml << " state=\"" << ip.getPropertyStateString( ip.getState() ) << "\"";
844 0 : m_ssXml << " perm=\"" << ip.getPropertyPermString( ip.getPerm() ) << "\"";
845 :
846 : // "implied" means that if they are not defined, don't add them. Adding an
847 : // empty "implied" attribute to the generated XML is an error.
848 0 : if ( ip.hasValidLabel() == true )
849 0 : m_ssXml << " label=\"" << ip.getLabel() << "\"";
850 0 : if ( ip.hasValidGroup() == true )
851 0 : m_ssXml << " group=\"" << ip.getGroup() << "\"";
852 0 : if ( ip.hasValidTimeout() == true )
853 0 : m_ssXml << " timeout=\"" << ip.getTimeout() << "\"";
854 0 : m_ssXml << " timestamp=\"" << ip.getTimeStamp().getFormattedIso8601Str() << "\"";
855 0 : if ( ip.hasValidMessage() == true )
856 0 : m_ssXml << " message=\"" << ip.getMessage() << "\"";
857 :
858 0 : m_ssXml << ">\r\n";
859 :
860 0 : for ( unsigned int ii = 0; ii < ip.getNumElements(); ii++ )
861 : {
862 0 : m_ssXml << "\t<" << szElementTag;
863 :
864 : // "required" means that the attribute must be added and contain a valid
865 : // entry. If it is not part of the generated XML, it is an error.
866 0 : if ( ip[ii].hasValidName() == false )
867 0 : throw runtime_error( szElementTag + " must have attribute 'name' defined." );
868 :
869 0 : m_ssXml << " name=\"" << ip[ii].getName() << "\"";
870 :
871 : // "implied" means that if they are not defined, don't add them. Adding an
872 : // empty "implied" attribute to the generated XML is an error.
873 0 : if ( ip[ii].hasValidLabel() == true )
874 0 : m_ssXml << " label=\"" << ip[ii].getLabel() << "\"";
875 :
876 0 : m_ssXml << ">\r\n";
877 :
878 : // Now add the data for the element...
879 : // todo: This may need to be removed, as the BLOB has no initial value.
880 : // No data here!
881 0 : m_ssXml << "\t</" << szElementTag << ">\r\n";
882 : }
883 0 : m_ssXml << "</" << szTag << ">\r\n";
884 0 : }
885 :
886 : ////////////////////////////////////////////////////////////////////////////////
887 : // SetBLOBVector REQUIRED: device name
888 : // SetBLOBVector IMPLIED: state timeout timestamp message
889 : // oneBLOB REQUIRED: name size format
890 :
891 0 : void IndiXmlParser::createSetBLOBVector( const IndiProperty &ip )
892 : {
893 : // What kind of message is this?
894 0 : string szTag = "setBLOBVector";
895 0 : string szElementTag = "oneBLOB";
896 0 : string szDescrip = szTag + " '" + ip.getName() + "'";
897 :
898 : // Clear out the xml stream.
899 0 : m_ssXml.str("");
900 0 : m_ssXml << "<" << szTag;
901 :
902 : // "required" means that the attribute must be added and contain a valid
903 : // entry. If it is not part of the generated XML, it is an error.
904 0 : if ( ip.hasValidDevice() == false )
905 0 : throw runtime_error( szDescrip + " must have attribute 'device' defined." );
906 0 : if ( ip.hasValidName() == false )
907 0 : throw runtime_error( szDescrip + " must have attribute 'name' defined." );
908 :
909 0 : m_ssXml << " device=\"" << ip.getDevice() << "\"";
910 0 : m_ssXml << " name=\"" << ip.getName() << "\"";
911 :
912 : // "implied" means that if they are not defined, don't add them. Adding an
913 : // empty "implied" attribute to the generated XML is an error.
914 0 : if ( ip.hasValidState() == true )
915 0 : m_ssXml << " state=\"" << ip.getPropertyStateString( ip.getState() ) << "\"";
916 0 : if ( ip.hasValidTimeout() == true )
917 0 : m_ssXml << " timeout=\"" << ip.getTimeout() << "\"";
918 0 : m_ssXml << " timestamp=\"" << ip.getTimeStamp().getFormattedIso8601Str() << "\"";
919 0 : if ( ip.hasValidMessage() == true )
920 0 : m_ssXml << " message=\"" << ip.getMessage() << "\"";
921 :
922 0 : m_ssXml << ">\r\n";
923 :
924 0 : for ( unsigned int ii = 0; ii < ip.getNumElements(); ii++ )
925 : {
926 0 : m_ssXml << "\t<" << szElementTag;
927 :
928 : // "required" means that the attribute must be added and contain a valid
929 : // entry. If it is not part of the generated XML, it is an error.
930 0 : if ( ip[ii].hasValidName() == false )
931 0 : throw runtime_error( szElementTag + " must have attribute 'name' defined." );
932 0 : if ( ip[ii].hasValidSize() == false )
933 0 : throw runtime_error( szElementTag + " must have attribute 'size' defined." );
934 0 : if ( ip[ii].hasValidFormat() == false )
935 0 : throw runtime_error( szElementTag + " must have attribute 'format' defined." );
936 :
937 0 : m_ssXml << " name=\"" << ip[ii].getName() << "\"";
938 0 : m_ssXml << " size=\"" << ip[ii].getSize() << "\"";
939 0 : m_ssXml << " format=\"" << ip[ii].getFormat() << "\"";
940 :
941 0 : m_ssXml << ">\r\n";
942 :
943 : // Allocate a big buffer to hold the base64 encoded data.
944 0 : vector<unsigned char> vecBase64Buf( 4 * ip[ii].getValue().size() / 3 + 4 );
945 :
946 : // Now base64 encode the data.
947 0 : unsigned char *pcBase64Buf = &vecBase64Buf[0];
948 0 : unsigned char *pcValueBuf = (unsigned char *)( ip[ii].getValue().c_str() );
949 0 : unsigned int uiValueBufLen = ip[ii].getValue().size();
950 : // unsigned int uiBase64BufLen =
951 0 : ::to64frombits( pcBase64Buf, pcValueBuf, uiValueBufLen );
952 :
953 : // Now add the data for the element...
954 0 : m_ssXml << pcBase64Buf << "\r\n";
955 0 : m_ssXml << "\t</" << szElementTag << ">\r\n";
956 0 : }
957 0 : m_ssXml << "</" << szTag << ">\r\n";
958 0 : }
959 :
960 : ////////////////////////////////////////////////////////////////////////////////
961 : // NewBLOBVector REQUIRED: device name
962 : // NewBLOBVector IMPLIED: timestamp
963 : // oneBLOB REQUIRED: name size format
964 :
965 0 : void IndiXmlParser::createNewBLOBVector( const IndiProperty &ip )
966 : {
967 : // What kind of message is this?
968 0 : string szTag = "newBLOBVector";
969 0 : string szElementTag = "oneBLOB";
970 0 : string szDescrip = szTag + " '" + ip.getName() + "'";
971 :
972 : // Clear out the xml stream.
973 0 : m_ssXml.str("");
974 0 : m_ssXml << "<" << szTag;
975 :
976 : // "required" means that the attribute must be added and contain a valid
977 : // entry. If it is not part of the generated XML, it is an error.
978 0 : if ( ip.hasValidDevice() == false )
979 0 : throw runtime_error( szDescrip + " must have attribute 'device' defined." );
980 0 : if ( ip.hasValidName() == false )
981 0 : throw runtime_error( szDescrip + " must have attribute 'name' defined." );
982 :
983 0 : m_ssXml << " device=\"" << ip.getDevice() << "\"";
984 0 : m_ssXml << " name=\"" << ip.getName() << "\"";
985 :
986 : // "implied" means that if they are not defined, don't add them. Adding an
987 : // empty "implied" attribute to the generated XML is an error.
988 0 : m_ssXml << " timestamp=\"" << ip.getTimeStamp().getFormattedIso8601Str() << "\"";
989 :
990 0 : m_ssXml << ">\r\n";
991 :
992 0 : for ( unsigned int ii = 0; ii < ip.getNumElements(); ii++ )
993 : {
994 0 : m_ssXml << "\t<" << szElementTag;
995 :
996 : // "required" means that the attribute must be added and contain a valid
997 : // entry. If it is not part of the generated XML, it is an error.
998 0 : if ( ip[ii].hasValidName() == false )
999 0 : throw runtime_error( szElementTag + " must have attribute 'name' defined." );
1000 0 : if ( ip[ii].hasValidSize() == false )
1001 0 : throw runtime_error( szElementTag + " must have attribute 'size' defined." );
1002 0 : if ( ip[ii].hasValidFormat() == false )
1003 0 : throw runtime_error( szElementTag + " must have attribute 'format' defined." );
1004 :
1005 0 : m_ssXml << " name=\"" << ip[ii].getName() << "\"";
1006 0 : m_ssXml << " size=\"" << ip[ii].getSize() << "\"";
1007 0 : m_ssXml << " format=\"" << ip[ii].getFormat() << "\"";
1008 :
1009 0 : m_ssXml << ">\r\n";
1010 :
1011 : // Allocate a big buffer to hold the base64 encoded data.
1012 0 : vector<unsigned char> vecBase64Buf( 4 * ip[ii].getValue().size() / 3 + 4 );
1013 :
1014 : // Now base64 encode the data.
1015 0 : unsigned char *pcBase64Buf = &vecBase64Buf[0];
1016 0 : unsigned char *pcValueBuf = (unsigned char *)( ip[ii].getValue().c_str() );
1017 0 : unsigned int uiValueBufLen = ip[ii].getValue().size();
1018 : //unsigned int uiBase64BufLen =
1019 0 : ::to64frombits( pcBase64Buf, pcValueBuf, uiValueBufLen );
1020 :
1021 : // Now add the data for the element...
1022 0 : m_ssXml << pcBase64Buf << "\r\n";
1023 0 : m_ssXml << "\t</" << szElementTag << ">\r\n";
1024 0 : }
1025 0 : m_ssXml << "</" << szTag << ">\r\n";
1026 0 : }
1027 :
1028 : ////////////////////////////////////////////////////////////////////////////////
1029 : // Message REQUIRED:
1030 : // Message IMPLIED: device timestamp message
1031 :
1032 0 : void IndiXmlParser::createMessage( const IndiProperty &ip )
1033 : {
1034 : // What kind of message is this?
1035 0 : string szTag = "message";
1036 :
1037 : // Clear out the xml stream.
1038 0 : m_ssXml.str("");
1039 0 : m_ssXml << "<" << szTag;
1040 :
1041 : // "implied" means that if they are not defined, don't add them. Adding an
1042 : // empty "implied" attribute to the generated XML is an error.
1043 0 : if ( ip.hasValidDevice() == true )
1044 0 : m_ssXml << " device=\"" << ip.getDevice() << "\"";
1045 0 : m_ssXml << " timestamp=\"" << ip.getTimeStamp().getFormattedIso8601Str() << "\"";
1046 0 : if ( ip.hasValidMessage() == true )
1047 0 : m_ssXml << " message=\"" << ip.getMessage() << "\"";
1048 :
1049 0 : m_ssXml << ">\r\n";
1050 0 : m_ssXml << "</" << szTag << ">\r\n";
1051 0 : }
1052 :
1053 : ////////////////////////////////////////////////////////////////////////////////
1054 : // DelProperty REQUIRED: device
1055 : // DelProperty IMPLIED: name timestamp message
1056 :
1057 0 : void IndiXmlParser::createDelProperty( const IndiProperty &ip )
1058 : {
1059 : // What kind of message is this?
1060 0 : string szTag = "delProperty";
1061 0 : string szDescrip = szTag + " '" + ip.getName() + "'";
1062 :
1063 : // Clear out the xml stream.
1064 0 : m_ssXml.str("");
1065 0 : m_ssXml << "<" << szTag;
1066 :
1067 : // "required" means that the attribute must be added and contain a valid
1068 : // entry. If it is not part of the generated XML, it is an error.
1069 0 : if ( ip.hasValidDevice() == false )
1070 0 : throw runtime_error( szDescrip + " must have attribute 'device' defined." );
1071 :
1072 0 : m_ssXml << " device=\"" << ip.getDevice() << "\"";
1073 :
1074 : // "implied" means that if they are not defined, don't add them. Adding an
1075 : // empty "implied" attribute to the generated XML is an error.
1076 0 : if ( ip.hasValidName() == true )
1077 0 : m_ssXml << " name=\"" << ip.getName() << "\"";
1078 0 : m_ssXml << " timestamp=\"" << ip.getTimeStamp().getFormattedIso8601Str() << "\"";
1079 0 : if ( ip.hasValidMessage() == true )
1080 0 : m_ssXml << " message=\"" << ip.getMessage() << "\"";
1081 :
1082 0 : m_ssXml << ">\r\n";
1083 0 : m_ssXml << "</" << szTag << ">\r\n";
1084 0 : }
1085 :
1086 : ////////////////////////////////////////////////////////////////////////////////
1087 : // GetProperties REQUIRED:
1088 : // GetProperties IMPLIED: device name
1089 :
1090 10 : void IndiXmlParser::createGetProperties( const IndiProperty &ip )
1091 : {
1092 : // What kind of message is this?
1093 10 : string szTag = "getProperties";
1094 :
1095 : // Clear out the xml stream.
1096 20 : m_ssXml.str("");
1097 10 : m_ssXml << "<" << szTag;
1098 :
1099 : // "implied" means that if they are not defined, don't add them. Adding an
1100 : // empty "implied" attribute to the generated XML is an error.
1101 10 : if ( ip.hasValidDevice() == true )
1102 10 : m_ssXml << " device=\"" << ip.getDevice() << "\"";
1103 10 : if ( ip.hasValidName() == true )
1104 10 : m_ssXml << " name=\"" << ip.getName() << "\"";
1105 :
1106 10 : m_ssXml << " version=\"" << m_szProtocolVersion << "\"";
1107 :
1108 10 : m_ssXml << ">\r\n";
1109 10 : m_ssXml << "</" << szTag << ">\r\n";
1110 10 : }
1111 :
1112 : ////////////////////////////////////////////////////////////////////////////////
1113 : // EnableBLOB REQUIRED: device
1114 : // EnableBLOB IMPLIED: name
1115 :
1116 0 : void IndiXmlParser::createEnableBLOB( const IndiProperty &ip )
1117 : {
1118 : // What kind of message is this?
1119 0 : string szTag = "enableBLOB";
1120 0 : string szDescrip = szTag + " '" + ip.getName() + "'";
1121 :
1122 : // Clear out the xml stream.
1123 0 : m_ssXml.str("");
1124 0 : m_ssXml << "<" << szTag;
1125 :
1126 : // "required" means that the attribute must be added and contain a valid
1127 : // entry. If it is not part of the generated XML, it is an error.
1128 0 : if ( ip.hasValidDevice() == false )
1129 0 : throw runtime_error( szDescrip + " must have attribute 'device' defined." );
1130 :
1131 0 : m_ssXml << " device=\"" << ip.getDevice() << "\"";
1132 :
1133 : // "implied" means that if they are not defined, don't add them. Adding an
1134 : // empty "implied" attribute to the generated XML is an error.
1135 0 : if ( ip.hasValidName() == true )
1136 0 : m_ssXml << " name=\"" << ip.getName() << "\"";
1137 :
1138 0 : m_ssXml << ">\r\n";
1139 0 : m_ssXml << IndiProperty::getBLOBEnableString( ip.getBLOBEnable() ) << "\r\n";
1140 0 : m_ssXml << "</" << szTag << ">\r\n";
1141 0 : }
1142 :
1143 : ////////////////////////////////////////////////////////////////////////////////
1144 : /// Copy constructor.
1145 :
1146 0 : IndiXmlParser::IndiXmlParser( const IndiXmlParser &ixp )
1147 : {
1148 0 : m_plxMessage = ::cloneLilXML( ixp.m_plxMessage );
1149 0 : m_pxeRoot = ::cloneXMLEle( ixp.m_pxeRoot );
1150 0 : ::memcpy( m_pcMessage, ixp.m_pcMessage, MaxErrorMsgSize );
1151 0 : m_szPrevXml = ixp.m_szPrevXml;
1152 0 : }
1153 :
1154 : ////////////////////////////////////////////////////////////////////////////////
1155 : /// Destructor.
1156 :
1157 22 : IndiXmlParser::~IndiXmlParser()
1158 : {
1159 22 : ::delLilXML( m_plxMessage );
1160 22 : ::delXMLEle( m_pxeRoot );
1161 22 : }
1162 :
1163 : ////////////////////////////////////////////////////////////////////////////////
1164 : /// Assigns the internal data of this object from an existing one.
1165 :
1166 0 : const IndiXmlParser &IndiXmlParser::operator=( const IndiXmlParser &ixpRhs )
1167 : {
1168 0 : if ( &ixpRhs != this )
1169 : {
1170 0 : ::delLilXML( m_plxMessage );
1171 0 : ::delXMLEle( m_pxeRoot );
1172 0 : m_plxMessage = ::cloneLilXML( ixpRhs.m_plxMessage );
1173 0 : m_pxeRoot = ::cloneXMLEle( ixpRhs.m_pxeRoot );
1174 0 : ::memcpy( m_pcMessage, ixpRhs.m_pcMessage, MaxErrorMsgSize );
1175 0 : m_szPrevXml = ixpRhs.m_szPrevXml;
1176 : }
1177 0 : return *this;
1178 : }
1179 :
1180 : ////////////////////////////////////////////////////////////////////////////////
1181 : /// Remove all attributes and reset this object.
1182 :
1183 0 : void IndiXmlParser::clear()
1184 : {
1185 0 : ::delLilXML( m_plxMessage );
1186 0 : ::delXMLEle( m_pxeRoot );
1187 0 : m_plxMessage = ::newLilXML();
1188 0 : m_pxeRoot = NULL;
1189 0 : ::memset( m_pcMessage, 0, MaxErrorMsgSize*sizeof(char) );
1190 0 : m_szPrevXml = "";
1191 0 : m_ssXml.str( "" );
1192 0 : }
1193 :
1194 : ////////////////////////////////////////////////////////////////////////////////
1195 : /// Initialize all data - assume we have just been created.
1196 :
1197 22 : void IndiXmlParser::init( const string &szProtocolVersion )
1198 : {
1199 22 : m_szProtocolVersion = szProtocolVersion;
1200 22 : m_plxMessage = ::newLilXML();
1201 22 : m_pxeRoot = NULL;
1202 22 : ::memset( m_pcMessage, 0, MaxErrorMsgSize*sizeof(char) );
1203 22 : }
1204 :
1205 : ////////////////////////////////////////////////////////////////////////////////
1206 : /// Returns the data formatted as an xml string.
1207 :
1208 10 : string IndiXmlParser::createXmlString() const
1209 : {
1210 10 : string szXml;
1211 :
1212 10 : if ( m_pxeRoot != NULL )
1213 : {
1214 0 : int nNumChars = 1 + ::sprlXMLEle( m_pxeRoot, 0 );
1215 : //szXml.reserve( nNumChars );
1216 0 : char *pcXml = ( char * )( ::malloc( nNumChars * sizeof( char ) ) );
1217 0 : ::memset( pcXml, 0, sizeof( char ) * nNumChars );
1218 0 : ::sprXMLEle( pcXml, m_pxeRoot, 0 );
1219 0 : szXml = string( pcXml );
1220 : }
1221 10 : else if ( m_ssXml.str().size() > 0 )
1222 : {
1223 10 : szXml = m_ssXml.str();
1224 : }
1225 :
1226 10 : return szXml;
1227 0 : }
1228 :
1229 : ////////////////////////////////////////////////////////////////////////////////
1230 :
1231 0 : IndiXmlParser::State IndiXmlParser::getState() const
1232 : {
1233 0 : return ( m_pxeRoot != NULL ) ? ( CompleteState ) : ( IncompleteState );
1234 : }
1235 :
1236 : ////////////////////////////////////////////////////////////////////////////////
1237 : /// Sets all the data in this object from formatted xml. First clears all
1238 : /// internal data, then parses the xml.
1239 :
1240 0 : void IndiXmlParser::parseXml( const char *pcXml,
1241 : const unsigned int &uiNumBytes,
1242 : string &szErrorMsg )
1243 : {
1244 0 : parseXml( string( pcXml, uiNumBytes ), szErrorMsg );
1245 0 : }
1246 :
1247 : ////////////////////////////////////////////////////////////////////////////////
1248 : /// Sets all the data in this object from formatted xml. First clears all
1249 : /// internal data, then parses the xml.
1250 :
1251 0 : void IndiXmlParser::parseXml( const string &szXml,
1252 : string &szErrorMsg )
1253 : {
1254 : // Do we have any text left from a previous call?
1255 0 : string szCurrXml = m_szPrevXml + szXml;
1256 :
1257 : // Make sure the message is empty.
1258 0 : szErrorMsg.clear();
1259 0 : ::memset( m_pcMessage, 0, MaxErrorMsgSize * sizeof(char) );
1260 :
1261 : // Reset the internal data.
1262 0 : ::delXMLEle( m_pxeRoot );
1263 0 : m_pxeRoot = NULL;
1264 :
1265 0 : unsigned int uiProcessed = 0;
1266 0 : XMLEle *pxeNewRoot = NULL;
1267 : // The pxeNewRoot will be NULL until the document is complete.
1268 0 : for ( ; uiProcessed < szCurrXml.size() && pxeNewRoot == NULL; uiProcessed++ )
1269 : {
1270 0 : pxeNewRoot = ::readXMLEle( m_plxMessage,
1271 0 : ( int )( szCurrXml[uiProcessed] ),
1272 0 : ( char * )( m_pcMessage ) );
1273 : // At this point, if there was an error, pxeNewRoot will be null, and
1274 : // m_pcMessage will contain why.
1275 0 : if ( ::strlen( ( char * )( m_pcMessage ) ) > 0 )
1276 : {
1277 : // Save the message.
1278 0 : szErrorMsg = string( ( const char * )( m_pcMessage ) );
1279 : std::cerr << "Error processing XML: '"
1280 0 : << szXml << "'" << std::endl
1281 0 : << "Error message: '" << szErrorMsg << "'" << std::endl;
1282 : // Clear out the existing data and start over.
1283 0 : clear();
1284 0 : break;
1285 : }
1286 : }
1287 :
1288 : // When we get here, the message was empty, so there was no error.
1289 : // We may or may not be complete.
1290 0 : m_pxeRoot = pxeNewRoot;
1291 :
1292 : // Store the left-over text for the next call.
1293 0 : m_szPrevXml = szCurrXml.substr( uiProcessed, szCurrXml.size() );
1294 0 : }
1295 :
1296 : ////////////////////////////////////////////////////////////////////////////////
1297 : /// Returns the attribute value with name szAttributeName.
1298 :
1299 0 : string IndiXmlParser::getAttributeValue( const string &szAttributeName,
1300 : XMLEle *pxeRoot ) const
1301 : {
1302 0 : if ( pxeRoot == NULL )
1303 0 : return "";
1304 :
1305 0 : XMLAtt *attrib = ::findXMLAtt( pxeRoot, szAttributeName.c_str() );
1306 :
1307 0 : if ( attrib == NULL )
1308 0 : return "";
1309 :
1310 0 : return string( ::valuXMLAtt( attrib ) );
1311 : }
1312 :
1313 : ////////////////////////////////////////////////////////////////////////////////
1314 : /// Get the IndiMessage created from the xml data.
1315 :
1316 0 : IndiMessage IndiXmlParser::createIndiMessage() const
1317 : {
1318 : IndiMessage::Type tMsgType;
1319 0 : IndiProperty ipNew;
1320 0 : string szValue;
1321 :
1322 0 : if ( m_pxeRoot != NULL )
1323 : {
1324 : // What type of message is this?
1325 0 : string szType = string( ::tagXMLEle( m_pxeRoot ) );
1326 0 : IndiXmlParser::MessageType tType = convertStringToType( szType );
1327 :
1328 0 : switch ( tType )
1329 : {
1330 0 : case UnknownType:
1331 0 : tMsgType = IndiMessage::Unknown;
1332 0 : break;
1333 : // Define properties.
1334 0 : case DefBLOBVector:
1335 0 : ipNew = IndiProperty( IndiProperty::BLOB );
1336 0 : tMsgType = IndiMessage::Define;
1337 0 : break;
1338 0 : case DefLightVector:
1339 0 : ipNew = IndiProperty( IndiProperty::Light );
1340 0 : tMsgType = IndiMessage::Define;
1341 0 : break;
1342 0 : case DefNumberVector:
1343 0 : ipNew = IndiProperty( IndiProperty::Number );
1344 0 : tMsgType = IndiMessage::Define;
1345 0 : break;
1346 0 : case DefSwitchVector:
1347 0 : ipNew = IndiProperty( IndiProperty::Switch );
1348 0 : tMsgType = IndiMessage::Define;
1349 0 : break;
1350 0 : case DefTextVector:
1351 0 : ipNew = IndiProperty( IndiProperty::Text );
1352 0 : tMsgType = IndiMessage::Define;
1353 0 : break;
1354 : // Delete properties.
1355 0 : case DelProperty:
1356 0 : ipNew = IndiProperty( IndiProperty::Unknown );
1357 0 : tMsgType = IndiMessage::Delete;
1358 0 : break;
1359 : // Enable blobs for a client.
1360 0 : case EnableBLOB:
1361 0 : ipNew = IndiProperty( IndiProperty::Unknown );
1362 0 : tMsgType = IndiMessage::EnableBLOB;
1363 0 : break;
1364 : // Command to enable snooping messages from other devices.
1365 0 : case GetProperties:
1366 0 : ipNew = IndiProperty( IndiProperty::Unknown );
1367 0 : tMsgType = IndiMessage::GetProperties;
1368 0 : break;
1369 : // A message.
1370 0 : case Message:
1371 0 : ipNew = IndiProperty( IndiProperty::Unknown );
1372 0 : tMsgType = IndiMessage::Message;
1373 0 : break;
1374 : // Update properties.
1375 0 : case NewBLOBVector:
1376 0 : ipNew = IndiProperty( IndiProperty::BLOB );
1377 0 : tMsgType = IndiMessage::NewProperty;
1378 0 : break;
1379 0 : case NewNumberVector:
1380 0 : ipNew = IndiProperty( IndiProperty::Number );
1381 0 : tMsgType = IndiMessage::NewProperty;
1382 0 : break;
1383 0 : case NewSwitchVector:
1384 0 : ipNew = IndiProperty( IndiProperty::Switch );
1385 0 : tMsgType = IndiMessage::NewProperty;
1386 0 : break;
1387 0 : case NewTextVector:
1388 0 : ipNew = IndiProperty( IndiProperty::Text );
1389 0 : tMsgType = IndiMessage::NewProperty;
1390 0 : break;
1391 : // Set properties.
1392 0 : case SetBLOBVector:
1393 0 : ipNew = IndiProperty( IndiProperty::BLOB );
1394 0 : tMsgType = IndiMessage::SetProperty;
1395 0 : break;
1396 0 : case SetLightVector:
1397 0 : ipNew = IndiProperty( IndiProperty::Light );
1398 0 : tMsgType = IndiMessage::SetProperty;
1399 0 : break;
1400 0 : case SetNumberVector:
1401 0 : ipNew = IndiProperty( IndiProperty::Number );
1402 0 : tMsgType = IndiMessage::SetProperty;
1403 0 : break;
1404 0 : case SetSwitchVector:
1405 0 : ipNew = IndiProperty( IndiProperty::Switch );
1406 0 : tMsgType = IndiMessage::SetProperty;
1407 0 : break;
1408 0 : case SetTextVector:
1409 0 : ipNew = IndiProperty( IndiProperty::Text );
1410 0 : tMsgType = IndiMessage::SetProperty;
1411 0 : break;
1412 : };
1413 :
1414 : // Set the attributes.
1415 0 : if ( ( szValue = getAttributeValue( "device", m_pxeRoot ) ).size() > 0 )
1416 0 : ipNew.setDevice( szValue );
1417 0 : if ( ( szValue = getAttributeValue( "group", m_pxeRoot ) ).size() > 0 )
1418 0 : ipNew.setGroup( szValue );
1419 0 : if ( ( szValue = getAttributeValue( "label", m_pxeRoot ) ).size() > 0 )
1420 0 : ipNew.setLabel( szValue );
1421 0 : if ( ( szValue = getAttributeValue( "message", m_pxeRoot ) ).size() > 0 )
1422 0 : ipNew.setMessage( szValue );
1423 0 : if ( ( szValue = getAttributeValue( "name", m_pxeRoot ) ).size() > 0 )
1424 0 : ipNew.setName( szValue );
1425 0 : if ( ( szValue = getAttributeValue( "perm", m_pxeRoot ) ).size() > 0 )
1426 0 : ipNew.setPerm( IndiProperty::getPropertyPermType( szValue ) );
1427 0 : if ( ( szValue = getAttributeValue( "rule", m_pxeRoot ) ).size() > 0 )
1428 0 : ipNew.setRule( IndiProperty::getSwitchRuleType( szValue ) );
1429 0 : if ( ( szValue = getAttributeValue( "state", m_pxeRoot ) ).size() > 0 )
1430 0 : ipNew.setState( IndiProperty::getPropertyStateType( szValue ) );
1431 0 : if ( ( szValue = getAttributeValue( "timeout", m_pxeRoot ) ).size() > 0 )
1432 : {
1433 0 : stringstream ssTimeout;
1434 0 : ssTimeout << szValue;
1435 : double xTimeout;
1436 0 : ssTimeout >> xTimeout;
1437 0 : ipNew.setTimeout( xTimeout );
1438 0 : }
1439 0 : if ( ( szValue = getAttributeValue( "timestamp", m_pxeRoot ) ).size() > 0 )
1440 : {
1441 0 : TimeStamp tsMod;
1442 0 : tsMod.fromFormattedIso8601Str( szValue );
1443 0 : ipNew.setTimeStamp( tsMod );
1444 0 : }
1445 0 : if ( ( szValue = getAttributeValue( "version", m_pxeRoot ) ).size() > 0 )
1446 0 : ipNew.setVersion( szValue );
1447 :
1448 : // A special case is a BLOB enable message - it has no elements,
1449 : // but has data in it.
1450 0 : if ( tType == EnableBLOB )
1451 : {
1452 0 : ipNew = IndiProperty::getBLOBEnableType( ::pcdataXMLEle( m_pxeRoot ) );
1453 : }
1454 : else
1455 : {
1456 : // Now iterate over all the child elements and add them to the message.
1457 : // The first time we call 'nextXMLEle' nInit is 1 to start fresh,
1458 : // then it is 0 and will step through each one to the end.
1459 0 : int nInit = 1;
1460 0 : XMLEle *pxeChild = NULL;
1461 :
1462 : // We need to iterate over each child element.
1463 0 : while ( pxeChild != NULL || nInit == 1 )
1464 : {
1465 0 : pxeChild = ::nextXMLEle( m_pxeRoot, nInit );
1466 :
1467 : // No children = we reached the end of the child elements.
1468 0 : if ( pxeChild != NULL )
1469 : {
1470 : // We need a new element....
1471 0 : IndiElement ieNew;
1472 :
1473 0 : if ( ( szValue = string( ::findXMLAttValu( pxeChild, "format" ) ) ).size() > 0 )
1474 0 : ieNew.setFormat( szValue );
1475 0 : if ( ( szValue = string( ::findXMLAttValu( pxeChild, "label" ) ) ).size() > 0 )
1476 0 : ieNew.setLabel( szValue );
1477 0 : if ( ( szValue = string( ::findXMLAttValu( pxeChild, "max" ) ) ).size() > 0 )
1478 0 : ieNew.setMax( szValue );
1479 0 : if ( ( szValue = string( ::findXMLAttValu( pxeChild, "min" ) ) ).size() > 0 )
1480 0 : ieNew.setMin( szValue );
1481 0 : if ( ( szValue = string( ::findXMLAttValu( pxeChild, "name" ) ) ).size() > 0 )
1482 0 : ieNew.setName( szValue );
1483 0 : if ( ( szValue = string( ::findXMLAttValu( pxeChild, "size" ) ) ).size() > 0 )
1484 0 : ieNew.setSize( szValue );
1485 0 : if ( ( szValue = string( ::findXMLAttValu( pxeChild, "step" ) ) ).size() > 0 )
1486 0 : ieNew.setStep( szValue );
1487 :
1488 0 : szValue = string( ::pcdataXMLEle( pxeChild ) );
1489 :
1490 : // The different types have different data...
1491 0 : switch ( tType )
1492 : {
1493 0 : case DefLightVector:
1494 : case SetLightVector:
1495 0 : ieNew.setLightState( IndiElement::getLightStateType( szValue ) );
1496 0 : break;
1497 0 : case DefSwitchVector:
1498 : case NewSwitchVector:
1499 : case SetSwitchVector:
1500 0 : ieNew.setSwitchState( IndiElement::getSwitchStateType( szValue ) );
1501 0 : break;
1502 0 : default:
1503 0 : ieNew.setValue( szValue );
1504 : }
1505 :
1506 : // Now add this element to the message.
1507 0 : ipNew.add( ieNew );
1508 0 : }
1509 0 : nInit = 0;
1510 : }
1511 : }
1512 0 : }
1513 :
1514 0 : return IndiMessage( tMsgType, ipNew );
1515 0 : }
1516 :
1517 : ////////////////////////////////////////////////////////////////////////////////
1518 : /// This handles streaming from input and other stream-like constructs.
1519 :
1520 0 : istream &operator>>( istream &strmIn, IndiXmlParser &ixpRhs )
1521 : {
1522 0 : if ( strmIn.good() )
1523 : {
1524 0 : stringbuf sbData;
1525 0 : strmIn.get( sbData );
1526 : // We need a string for the error message, if any.
1527 0 : string szErrorMsg;
1528 0 : ixpRhs.parseXml( sbData.str(), szErrorMsg );
1529 0 : }
1530 0 : return strmIn;
1531 : }
1532 :
1533 : ////////////////////////////////////////////////////////////////////////////////
1534 : /// This handles streaming to output and other stream-like constructs.
1535 :
1536 0 : ostream &operator<<( ostream &strmOut, const IndiXmlParser &ixpRhs )
1537 : {
1538 0 : strmOut << ixpRhs.createXmlString();
1539 0 : return strmOut;
1540 : }
1541 :
1542 : ////////////////////////////////////////////////////////////////////////////////
1543 : // If this xml contains a complete INDI message, this returns true,
1544 : // and start and stop will be the indices of the start and stop of it.
1545 : /*
1546 : IndiMessage::Type IndiXmlParser::extractMessage( const std::string &szXml,
1547 : int &nStart,
1548 : int &nStop )
1549 : {
1550 : string szOpenTag;
1551 : string szCloseTag;
1552 : size_t tBegin = string::npos;
1553 : size_t tEnd = string::npos;
1554 :
1555 : // Do we have an open and close for any INDI Message type?
1556 : szOpenTag = "defBLOBVector";
1557 : if ( tBegin = szXml.find( szOpenTag ) != string::npos )
1558 : {
1559 : // Find the first close after the open, above.
1560 : szCloseTag = "/defBLOBVector";
1561 : if ( tEnd = szXml.find( szCloseTag, szOpenTag.size() ) != string::npos )
1562 : {
1563 : nStart = (int)( tBegin );
1564 : nStop = (int)( tEnd ) + szCloseTag.size();
1565 : return IndiMessage::DefBLOBVector;
1566 : }
1567 : }
1568 : szOpenTag = "defLightVector";
1569 : if ( tBegin = szXml.find( szOpenTag ) != string::npos )
1570 : {
1571 : // Find the first close after the open, above.
1572 : szCloseTag = "/defLightVector";
1573 : if ( tEnd = szXml.find( szCloseTag, szOpenTag.size() ) != string::npos )
1574 : {
1575 : nStart = (int)( tBegin );
1576 : nStop = (int)( tEnd ) + szCloseTag.size();
1577 : return IndiMessage::DefLightVector;
1578 : }
1579 : }
1580 : szOpenTag = "defNumberVector";
1581 : if ( tBegin = szXml.find( szOpenTag ) != string::npos )
1582 : {
1583 : // Find the first close after the open, above.
1584 : szCloseTag = "/defNumberVector";
1585 : if ( tEnd = szXml.find( szCloseTag, szOpenTag.size() ) != string::npos )
1586 : {
1587 : nStart = (int)( tBegin );
1588 : nStop = (int)( tEnd ) + szCloseTag.size();
1589 : return IndiMessage::DefNumberVector;
1590 : }
1591 : }
1592 : szOpenTag = "defSwitchVector";
1593 : if ( tBegin = szXml.find( szOpenTag ) != string::npos )
1594 : {
1595 : // Find the first close after the open, above.
1596 : szCloseTag = "/defSwitchVector";
1597 : if ( tEnd = szXml.find( szCloseTag, szOpenTag.size() ) != string::npos )
1598 : {
1599 : nStart = (int)( tBegin );
1600 : nStop = (int)( tEnd ) + szCloseTag.size();
1601 : return IndiMessage::DefSwitchVector;
1602 : }
1603 : }
1604 : szOpenTag = "defTextVector";
1605 : if ( tBegin = szXml.find( szOpenTag ) != string::npos )
1606 : {
1607 : // Find the first close after the open, above.
1608 : szCloseTag = "/defTextVector";
1609 : if ( tEnd = szXml.find( szCloseTag, szOpenTag.size() ) != string::npos )
1610 : {
1611 : nStart = (int)( tBegin );
1612 : nStop = (int)( tEnd ) + szCloseTag.size();
1613 : return IndiMessage::DefTextVector;
1614 : }
1615 : }
1616 : szOpenTag = "delProperty";
1617 : if ( tBegin = szXml.find( szOpenTag ) != string::npos )
1618 : {
1619 : // Find the first close after the open, above.
1620 : szCloseTag = "/delProperty";
1621 : if ( tEnd = szXml.find( szCloseTag, szOpenTag.size() ) != string::npos )
1622 : {
1623 : nStart = (int)( tBegin );
1624 : nStop = (int)( tEnd ) + szCloseTag.size();
1625 : return IndiMessage::DelProperty;
1626 : }
1627 : }
1628 : szOpenTag = "enableBLOB";
1629 : if ( tBegin = szXml.find( szOpenTag ) != string::npos )
1630 : {
1631 : // Find the first close after the open, above.
1632 : szCloseTag = "/enableBLOB";
1633 : if ( tEnd = szXml.find( szCloseTag, szOpenTag.size() ) != string::npos )
1634 : {
1635 : nStart = (int)( tBegin );
1636 : nStop = (int)( tEnd ) + szCloseTag.size();
1637 : return IndiMessage::EnableBLOB;
1638 : }
1639 : }
1640 : szOpenTag = "getProperties";
1641 : if ( tBegin = szXml.find( szOpenTag ) != string::npos )
1642 : {
1643 : // Find the first close after the open, above.
1644 : szCloseTag = "/getProperties";
1645 : if ( tEnd = szXml.find( szCloseTag, szOpenTag.size() ) != string::npos )
1646 : {
1647 : nStart = (int)( tBegin );
1648 : nStop = (int)( tEnd ) + szCloseTag.size();
1649 : return IndiMessage::GetProperties;
1650 : }
1651 : }
1652 : szOpenTag = "message";
1653 : if ( tBegin = szXml.find( szOpenTag ) != string::npos )
1654 : {
1655 : // Find the first close after the open, above.
1656 : szCloseTag = "/message";
1657 : if ( tEnd = szXml.find( szCloseTag, szOpenTag.size() ) != string::npos )
1658 : {
1659 : nStart = (int)( tBegin );
1660 : nStop = (int)( tEnd ) + szCloseTag.size();
1661 : return IndiMessage::Message;
1662 : }
1663 : }
1664 : szOpenTag = "newBLOBVector";
1665 : if ( tBegin = szXml.find( szOpenTag ) != string::npos )
1666 : {
1667 : // Find the first close after the open, above.
1668 : szCloseTag = "/newBLOBVector";
1669 : if ( tEnd = szXml.find( szCloseTag, szOpenTag.size() ) != string::npos )
1670 : {
1671 : nStart = (int)( tBegin );
1672 : nStop = (int)( tEnd ) + szCloseTag.size();
1673 : return IndiMessage::NewBLOBVector;
1674 : }
1675 : }
1676 : szOpenTag = "newNumberVector";
1677 : if ( tBegin = szXml.find( szOpenTag ) != string::npos )
1678 : {
1679 : // Find the first close after the open, above.
1680 : szCloseTag = "/newNumberVector";
1681 : if ( tEnd = szXml.find( szCloseTag, szOpenTag.size() ) != string::npos )
1682 : {
1683 : nStart = (int)( tBegin );
1684 : nStop = (int)( tEnd ) + szCloseTag.size();
1685 : return IndiMessage::NewNumberVector;
1686 : }
1687 : }
1688 : szOpenTag = "newSwitchVector";
1689 : if ( tBegin = szXml.find( szOpenTag ) != string::npos )
1690 : {
1691 : // Find the first close after the open, above.
1692 : szCloseTag = "/newSwitchVector";
1693 : if ( tEnd = szXml.find( szCloseTag, szOpenTag.size() ) != string::npos )
1694 : {
1695 : nStart = (int)( tBegin );
1696 : nStop = (int)( tEnd ) + szCloseTag.size();
1697 : return IndiMessage::NewSwitchVector;
1698 : }
1699 : }
1700 : szOpenTag = "newTextVector";
1701 : if ( tBegin = szXml.find( szOpenTag ) != string::npos )
1702 : {
1703 : // Find the first close after the open, above.
1704 : szCloseTag = "/newTextVector";
1705 : if ( tEnd = szXml.find( szCloseTag, szOpenTag.size() ) != string::npos )
1706 : {
1707 : nStart = (int)( tBegin );
1708 : nStop = (int)( tEnd ) + szCloseTag.size();
1709 : return IndiMessage::NewTextVector;
1710 : }
1711 : }
1712 : szOpenTag = "setBLOBVector";
1713 : if ( tBegin = szXml.find( szOpenTag ) != string::npos )
1714 : {
1715 : // Find the first close after the open, above.
1716 : szCloseTag = "/setBLOBVector";
1717 : if ( tEnd = szXml.find( szCloseTag, szOpenTag.size() ) != string::npos )
1718 : {
1719 : nStart = (int)( tBegin );
1720 : nStop = (int)( tEnd ) + szCloseTag.size();
1721 : return IndiMessage::SetBLOBVector;
1722 : }
1723 : }
1724 : szOpenTag = "setLightVector";
1725 : if ( tBegin = szXml.find( szOpenTag ) != string::npos )
1726 : {
1727 : // Find the first close after the open, above.
1728 : szCloseTag = "/setLightVector";
1729 : if ( tEnd = szXml.find( szCloseTag, szOpenTag.size() ) != string::npos )
1730 : {
1731 : nStart = (int)( tBegin );
1732 : nStop = (int)( tEnd ) + szCloseTag.size();
1733 : return IndiMessage::SetLightVector;
1734 : }
1735 : }
1736 : szOpenTag = "setNumberVector";
1737 : if ( tBegin = szXml.find( szOpenTag ) != string::npos )
1738 : {
1739 : // Find the first close after the open, above.
1740 : szCloseTag = "/setNumberVector";
1741 : if ( tEnd = szXml.find( szCloseTag, szOpenTag.size() ) != string::npos )
1742 : {
1743 : nStart = (int)( tBegin );
1744 : nStop = (int)( tEnd ) + szCloseTag.size();
1745 : return IndiMessage::SetNumberVector;
1746 : }
1747 : }
1748 : szOpenTag = "setSwitchVector";
1749 : if ( tBegin = szXml.find( szOpenTag ) != string::npos )
1750 : {
1751 : // Find the first close after the open, above.
1752 : szCloseTag = "/setSwitchVector";
1753 : if ( tEnd = szXml.find( szCloseTag, szOpenTag.size() ) != string::npos )
1754 : {
1755 : nStart = (int)( tBegin );
1756 : nStop = (int)( tEnd ) + szCloseTag.size();
1757 : return IndiMessage::SetSwitchVector;
1758 : }
1759 : }
1760 : szOpenTag = "setTextVector";
1761 : if ( tBegin = szXml.find( szOpenTag ) != string::npos )
1762 : {
1763 : // Find the first close after the open, above.
1764 : szCloseTag = "/setTextVector";
1765 : if ( tEnd = szXml.find( szCloseTag, szOpenTag.size() ) != string::npos )
1766 : {
1767 : nStart = (int)( tBegin );
1768 : nStop = (int)( tEnd ) + szCloseTag.size();
1769 : return IndiMessage::SetTextVector;
1770 : }
1771 : }
1772 :
1773 : // If we got here, we do not have a valid XML document (yet).
1774 : return IndiMessage::UnknownType;
1775 : }
1776 : */
1777 : ////////////////////////////////////////////////////////////////////////////////
1778 : /// Returns the string type given the enumerated type.
1779 :
1780 0 : string IndiXmlParser::convertTypeToString( const IndiXmlParser::MessageType &tType )
1781 : {
1782 0 : string szType = "";
1783 :
1784 0 : switch ( tType )
1785 : {
1786 0 : case UnknownType:
1787 0 : szType = "";
1788 0 : break;
1789 :
1790 : // Define properties.
1791 0 : case DefBLOBVector:
1792 0 : szType = "defBLOBVector";
1793 0 : break;
1794 0 : case DefLightVector:
1795 0 : szType = "defLightVector";
1796 0 : break;
1797 0 : case DefNumberVector:
1798 0 : szType = "defNumberVector";
1799 0 : break;
1800 0 : case DefSwitchVector:
1801 0 : szType = "defSwitchVector";
1802 0 : break;
1803 0 : case DefTextVector:
1804 0 : szType = "defTextVector";
1805 0 : break;
1806 :
1807 : // Delete properties.
1808 0 : case DelProperty:
1809 0 : szType = "delProperty";
1810 0 : break;
1811 :
1812 : // Enable blobs for a client.
1813 0 : case EnableBLOB:
1814 0 : szType = "enableBLOB";
1815 0 : break;
1816 :
1817 : // Command to enable snooping messages from other devices.
1818 0 : case GetProperties:
1819 0 : szType = "getProperties";
1820 0 : break;
1821 :
1822 : // A message.
1823 0 : case Message:
1824 0 : szType = "message";
1825 0 : break;
1826 :
1827 : // Update properties.
1828 0 : case NewBLOBVector:
1829 0 : szType = "newBLOBVector";
1830 0 : break;
1831 0 : case NewNumberVector:
1832 0 : szType = "newNumberVector";
1833 0 : break;
1834 0 : case NewSwitchVector:
1835 0 : szType = "newSwitchVector";
1836 0 : break;
1837 0 : case NewTextVector:
1838 0 : szType = "newTextVector";
1839 0 : break;
1840 :
1841 : // Set properties.
1842 0 : case SetBLOBVector:
1843 0 : szType = "setBLOBVector";
1844 0 : break;
1845 0 : case SetLightVector:
1846 0 : szType = "setLightVector";
1847 0 : break;
1848 0 : case SetNumberVector:
1849 0 : szType = "setNumberVector";
1850 0 : break;
1851 0 : case SetSwitchVector:
1852 0 : szType = "setSwitchVector";
1853 0 : break;
1854 0 : case SetTextVector:
1855 0 : szType = "setTextVector";
1856 0 : break;
1857 : }
1858 :
1859 0 : return szType;
1860 0 : }
1861 :
1862 : ////////////////////////////////////////////////////////////////////////////////
1863 : /// Sets the protocol version of this software.
1864 :
1865 12 : void IndiXmlParser::setProtocolVersion( const string &szProtocolVersion )
1866 : {
1867 12 : m_szProtocolVersion = szProtocolVersion;
1868 12 : }
1869 :
1870 : ////////////////////////////////////////////////////////////////////////////////
1871 : /// Returns the protocol version of this software.
1872 :
1873 22 : string IndiXmlParser::getProtocolVersion() const
1874 : {
1875 22 : return m_szProtocolVersion;
1876 : }
1877 :
1878 : ////////////////////////////////////////////////////////////////////////////////
1879 : /// Returns the enumerated type given the tag.
1880 :
1881 0 : IndiXmlParser::MessageType IndiXmlParser::convertStringToType( const string &szTag )
1882 : {
1883 0 : MessageType tType = UnknownType;
1884 :
1885 : // Define properties.
1886 0 : if ( szTag == "defBLOBVector" )
1887 0 : tType = DefBLOBVector;
1888 0 : else if ( szTag == "defLightVector" )
1889 0 : tType = DefLightVector;
1890 0 : else if ( szTag == "defNumberVector" )
1891 0 : tType = DefNumberVector;
1892 0 : else if ( szTag == "defSwitchVector" )
1893 0 : tType = DefSwitchVector;
1894 0 : else if ( szTag == "defTextVector" )
1895 0 : tType = DefTextVector;
1896 :
1897 : // Delete properties.
1898 0 : else if ( szTag == "delProperty" )
1899 0 : tType = DelProperty;
1900 :
1901 : // Enable blobs for a client.
1902 0 : else if ( szTag == "enableBLOB" )
1903 0 : tType = EnableBLOB;
1904 :
1905 : // Command to enable snooping messages from other devices.
1906 0 : else if ( szTag == "getProperties" )
1907 0 : tType = GetProperties;
1908 :
1909 : // A message.
1910 0 : else if ( szTag == "message" )
1911 0 : tType = Message;
1912 :
1913 : // Update properties.
1914 0 : else if ( szTag == "newBLOBVector" )
1915 0 : tType = NewBLOBVector;
1916 0 : else if ( szTag == "newNumberVector" )
1917 0 : tType = NewNumberVector;
1918 0 : else if ( szTag == "newSwitchVector" )
1919 0 : tType = NewSwitchVector;
1920 0 : else if ( szTag == "newTextVector" )
1921 0 : tType = NewTextVector;
1922 :
1923 : // Set properties.
1924 0 : else if ( szTag == "setBLOBVector" )
1925 0 : tType = SetBLOBVector;
1926 0 : else if ( szTag == "setLightVector" )
1927 0 : tType = SetLightVector;
1928 0 : else if ( szTag == "setNumberVector" )
1929 0 : tType = SetNumberVector;
1930 0 : else if ( szTag == "setSwitchVector" )
1931 0 : tType = SetSwitchVector;
1932 0 : else if ( szTag == "setTextVector" )
1933 0 : tType = SetTextVector;
1934 :
1935 0 : return tType;
1936 : }
1937 :
1938 : ////////////////////////////////////////////////////////////////////////////////
|