xml2ns0.c 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959
  1. /*
  2. * xml2ns0.c
  3. *
  4. * Created on: 21.04.2014
  5. * Author: mrt
  6. */
  7. #include <expat.h>
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <string.h> // strlen
  11. #include <ctype.h> // isspace
  12. #include <unistd.h> // read
  13. #include "opcua.h"
  14. #include "ua_namespace.h"
  15. // some typedefs for typical arguments in this module
  16. typedef char const * const XML_Attr_t;
  17. typedef char const * cstring_t;
  18. // FIXME: We might want to have these classes and their methods defined in opcua.h
  19. /** NodeSetAlias - a readable shortcut for References */
  20. typedef struct UA_NodeSetAlias_T {
  21. UA_String alias;
  22. UA_String value;
  23. } UA_NodeSetAlias;
  24. UA_Int32 UA_NodeSetAlias_init(UA_NodeSetAlias* p) {
  25. UA_String_init(&(p->alias));
  26. UA_String_init(&(p->value));
  27. return UA_SUCCESS;
  28. }
  29. UA_Int32 UA_NodeSetAlias_new(UA_NodeSetAlias** p) {
  30. UA_alloc((void** )p, sizeof(UA_NodeSetAlias));
  31. UA_NodeSetAlias_init(*p);
  32. return UA_SUCCESS;
  33. }
  34. /* References */
  35. typedef struct UA_NodeSetReferences_T {
  36. UA_Int32 size;
  37. UA_ReferenceNode** references;
  38. } UA_NodeSetReferences;
  39. UA_Int32 UA_NodeSetReferences_init(UA_NodeSetReferences* p) {
  40. p->size = -1;
  41. p->references = UA_NULL;
  42. return UA_SUCCESS;
  43. }
  44. UA_Int32 UA_NodeSetReferences_new(UA_NodeSetReferences** p) {
  45. UA_alloc((void** )p, sizeof(UA_NodeSetReferences));
  46. UA_NodeSetReferences_init(*p);
  47. return UA_SUCCESS;
  48. }
  49. UA_Int32 UA_ReferenceNode_println(cstring_t label, UA_ReferenceNode *a) {
  50. printf("%s{referenceType=%d, target=%d, isInverse=%d}\n",
  51. label,
  52. a->referenceTypeId.identifier.numeric,
  53. a->targetId.nodeId.identifier.numeric,
  54. a->isInverse);
  55. return UA_SUCCESS;
  56. }
  57. UA_Int32 UA_NodeSetReferences_println(cstring_t label, UA_NodeSetReferences *p) {
  58. UA_Int32 i;
  59. for (i = 0; i < p->size; i++) {
  60. UA_ReferenceNode* a = p->references[i];
  61. printf("References addr=%p, ", (void*) a);
  62. if (a) {
  63. UA_ReferenceNode_println("node=",a);
  64. }
  65. printf("\n");
  66. }
  67. return UA_SUCCESS;
  68. }
  69. /* The current set of aliases */
  70. typedef struct UA_NodeSetAliases_T {
  71. UA_Int32 size;
  72. UA_NodeSetAlias** aliases;
  73. } UA_NodeSetAliases;
  74. UA_Int32 UA_NodeSetAliases_init(UA_NodeSetAliases* p) {
  75. p->size = -1;
  76. p->aliases = UA_NULL;
  77. return UA_SUCCESS;
  78. }
  79. UA_Int32 UA_NodeSetAliases_new(UA_NodeSetAliases** p) {
  80. UA_alloc((void** )p, sizeof(UA_NodeSetAliases));
  81. UA_NodeSetAliases_init(*p);
  82. return UA_SUCCESS;
  83. }
  84. UA_Int32 UA_NodeSetAliases_println(cstring_t label, UA_NodeSetAliases *p) {
  85. UA_Int32 i;
  86. for (i = 0; i < p->size; i++) {
  87. UA_NodeSetAlias* a = p->aliases[i];
  88. printf("Alias addr=%p, ", (void*) a);
  89. if (a) {
  90. printf("alias='%.*s', value='%.*s'", a->alias.length, a->alias.data, a->value.length, a->value.data);
  91. }
  92. printf("\n");
  93. }
  94. return UA_SUCCESS;
  95. }
  96. /* A nodeset consist of a namespace and a list of aliases */
  97. typedef struct T_UA_NodeSet {
  98. namespace* ns;
  99. UA_NodeSetAliases aliases;
  100. } UA_NodeSet;
  101. UA_Int32 UA_NodeSet_init(UA_NodeSet* p) {
  102. create_ns(&(p->ns), 100);
  103. p->aliases.size = -1;
  104. p->aliases.aliases = UA_NULL;
  105. return UA_SUCCESS;
  106. }
  107. UA_Int32 UA_NodeSet_new(UA_NodeSet** p) {
  108. UA_alloc((void** )p, sizeof(UA_NodeSet));
  109. UA_NodeSet_init(*p);
  110. return UA_SUCCESS;
  111. }
  112. UA_Int32 UA_NodeId_copycstring(cstring_t src, UA_NodeId* dst, UA_NodeSetAliases* aliases) {
  113. dst->encodingByte = UA_NODEIDTYPE_FOURBYTE;
  114. dst->namespace = 0;
  115. dst->identifier.numeric = 0;
  116. // FIXME: assumes i=nnnn, does not care for aliases as of now
  117. if (src[1] == '=') {
  118. dst->identifier.numeric = atoi(&src[2]);
  119. } else {
  120. UA_Int32 i;
  121. for (i = 0; i < aliases->size && dst->identifier.numeric == 0; ++i) {
  122. if (0
  123. == strncmp((char const*) src, (char const*) aliases->aliases[i]->alias.data,
  124. aliases->aliases[i]->alias.length)) {
  125. dst->identifier.numeric = atoi((char const*) &(aliases->aliases[i]->value.data[2]));
  126. }
  127. }
  128. }
  129. DBG_VERBOSE(printf("UA_NodeId_copycstring src=%s,id=%d\n", src, dst->identifier.numeric));
  130. return UA_SUCCESS;
  131. }
  132. UA_Int32 UA_ExpandedNodeId_copycstring(cstring_t src, UA_ExpandedNodeId* dst, UA_NodeSetAliases* aliases) {
  133. dst->nodeId.encodingByte = UA_NODEIDTYPE_FOURBYTE;
  134. dst->nodeId.namespace = 0;
  135. dst->nodeId.identifier.numeric = 0;
  136. // FIXME: assumes i=nnnn, does not care for aliases as of now
  137. UA_NodeId_copycstring(src, &(dst->nodeId), aliases);
  138. DBG_VERBOSE(printf("UA_ExpandedNodeId_copycstring src=%s,id=%d\n", src, dst->nodeId.identifier.numeric));
  139. return UA_SUCCESS;
  140. }
  141. /* the stack and it's elements */
  142. #define XML_STACK_MAX_DEPTH 10
  143. #define XML_STACK_MAX_CHILDREN 40
  144. struct XML_Stack;
  145. typedef UA_Int32 (*XML_decoder)(struct XML_Stack* s, XML_Attr_t* attr, void* dst, _Bool isStart);
  146. typedef struct XML_child {
  147. cstring_t name;
  148. UA_Int32 type;
  149. XML_decoder elementHandler;
  150. void* obj;
  151. } XML_child_t;
  152. typedef struct XML_Parent {
  153. cstring_t name;
  154. int textAttribIdx; // -1 - not set
  155. cstring_t textAttrib;
  156. int activeChild; // -1 - no active child
  157. int len; // -1 - empty set
  158. XML_child_t children[XML_STACK_MAX_CHILDREN];
  159. } XML_Parent_t;
  160. typedef struct XML_Stack {
  161. int depth;
  162. XML_Parent_t parent[XML_STACK_MAX_DEPTH];
  163. UA_NodeSetAliases* aliases; // shall point to the aliases of the NodeSet after reading
  164. } XML_Stack_t;
  165. void XML_Stack_init(XML_Stack_t* p, cstring_t name) {
  166. unsigned int i, j;
  167. p->depth = 0;
  168. for (i = 0; i < XML_STACK_MAX_DEPTH; i++) {
  169. p->parent[i].name = UA_NULL;
  170. p->parent[i].len = 0;
  171. p->parent[i].activeChild = -1;
  172. p->parent[i].textAttrib = UA_NULL;
  173. p->parent[i].textAttribIdx = -1;
  174. for (j = 0; j < XML_STACK_MAX_CHILDREN; j++) {
  175. p->parent[i].children[j].name = UA_NULL;
  176. p->parent[i].children[j].elementHandler = UA_NULL;
  177. p->parent[i].children[j].type = UA_INVALIDTYPE;
  178. p->parent[i].children[j].obj = UA_NULL;
  179. }
  180. }
  181. p->parent[0].name = name;
  182. }
  183. void XML_Stack_print(XML_Stack_t* s) {
  184. UA_Int32 i;
  185. for (i = 0; i <= s->depth; i++) {
  186. printf("%s.", s->parent[i].name);
  187. }
  188. }
  189. // FIXME: we might want to calculate textAttribIdx
  190. void XML_Stack_handleTextAsElementOf(XML_Stack_t* p, cstring_t textAttrib, unsigned int textAttribIdx) {
  191. p->parent[p->depth].textAttrib = textAttrib;
  192. p->parent[p->depth].textAttribIdx = textAttribIdx;
  193. }
  194. void XML_Stack_addChildHandler(XML_Stack_t* p, cstring_t name, XML_decoder handler, UA_Int32 type, void* dst) {
  195. unsigned int len = p->parent[p->depth].len;
  196. p->parent[p->depth].children[len].name = name;
  197. p->parent[p->depth].children[len].elementHandler = handler;
  198. p->parent[p->depth].children[len].type = type;
  199. p->parent[p->depth].children[len].obj = dst;
  200. p->parent[p->depth].len++;
  201. }
  202. UA_Int32 UA_Array_decodeXML(XML_Stack_t* s, XML_Attr_t* attr, void* dst, _Bool isStart) {
  203. // FIXME: Implement
  204. return UA_SUCCESS;
  205. }
  206. UA_Int32 UA_Boolean_copycstring(cstring_t src, UA_Boolean* dst) {
  207. *dst = UA_FALSE;
  208. if (0 == strncmp(src, "true", 4) || 0 == strncmp(src, "TRUE", 4)) {
  209. *dst = UA_TRUE;
  210. }
  211. return UA_SUCCESS;
  212. }
  213. UA_Int32 UA_Boolean_decodeXML(XML_Stack_t* s, XML_Attr_t* attr, UA_Boolean* dst, _Bool isStart) {
  214. DBG_VERBOSE(printf("UA_Boolean entered with dst=%p,isStart=%d\n", (void* ) dst, isStart));
  215. if (isStart) {
  216. if (dst == UA_NULL) {
  217. UA_Boolean_new(&dst);
  218. s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst;
  219. }
  220. UA_Boolean_copycstring((cstring_t) attr[1], dst);
  221. } else {
  222. // TODO: It is a design flaw that we need to do this here, isn't it?
  223. s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj =
  224. UA_NULL;
  225. }
  226. return UA_SUCCESS;
  227. }
  228. UA_Int32 UA_Int16_copycstring(cstring_t src, UA_Int16* dst) {
  229. *dst = atoi(src);
  230. return UA_SUCCESS;
  231. }
  232. UA_Int32 UA_UInt16_copycstring(cstring_t src, UA_UInt16* dst) {
  233. *dst = atoi(src);
  234. return UA_SUCCESS;
  235. }
  236. UA_Int32 UA_Int16_decodeXML(XML_Stack_t* s, XML_Attr_t* attr, UA_Int16* dst, _Bool isStart) {
  237. DBG_VERBOSE(printf("UA_Int32 entered with dst=%p,isStart=%d\n", (void* ) dst, isStart));
  238. if (isStart) {
  239. if (dst == UA_NULL) {
  240. UA_Int16_new(&dst);
  241. s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst;
  242. }
  243. UA_Int16_copycstring((cstring_t) attr[1], dst);
  244. } else {
  245. // TODO: It is a design flaw that we need to do this here, isn't it?
  246. s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj =
  247. UA_NULL;
  248. }
  249. return UA_SUCCESS;
  250. }
  251. UA_Int32 UA_Int32_decodeXML(XML_Stack_t* s, XML_Attr_t* attr, UA_Int32* dst, _Bool isStart) {
  252. DBG_VERBOSE(printf("UA_Int32 entered with dst=%p,isStart=%d\n", (void* ) dst, isStart));
  253. if (isStart) {
  254. if (dst == UA_NULL) {
  255. UA_Int32_new(&dst);
  256. s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst;
  257. }
  258. *dst = atoi(attr[1]);
  259. } else {
  260. // TODO: It is a design flaw that we need to do this here, isn't it?
  261. s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj =
  262. UA_NULL;
  263. }
  264. return UA_SUCCESS;
  265. }
  266. UA_Int32 UA_String_decodeXML(XML_Stack_t* s, XML_Attr_t* attr, UA_String* dst, _Bool isStart) {
  267. DBG_VERBOSE(printf("UA_String entered with dst=%p,isStart=%d\n", (void* ) dst, isStart));
  268. UA_UInt32 i;
  269. if (isStart) {
  270. if (dst == UA_NULL) {
  271. UA_String_new(&dst);
  272. s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst;
  273. }
  274. s->parent[s->depth].len = 0;
  275. XML_Stack_addChildHandler(s, "Data", (XML_decoder) UA_Array_decodeXML, UA_BYTE, &(dst->data));
  276. XML_Stack_addChildHandler(s, "Length", (XML_decoder) UA_Int32_decodeXML, UA_INT32, &(dst->length));
  277. XML_Stack_handleTextAsElementOf(s, "Data", 0);
  278. // set attributes
  279. for (i = 0; attr[i]; i += 2) {
  280. if (0 == strncmp("Data", attr[i], strlen("Data"))) {
  281. UA_String_copycstring(attr[i + 1], dst);
  282. } else {
  283. printf("UA_String_decodeXML - Unknown attribute - name=%s, value=%s\n", attr[i], attr[i+1]);
  284. }
  285. }
  286. } else {
  287. // TODO: It is a design flaw that we need to do this here, isn't it?
  288. DBG_VERBOSE(
  289. printf("UA_String clears %p\n",
  290. (void* ) (s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj)));
  291. s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = UA_NULL;
  292. }
  293. return UA_SUCCESS;
  294. }
  295. UA_Int32 UA_NodeId_decodeXML(XML_Stack_t* s, XML_Attr_t* attr, UA_NodeId* dst, _Bool isStart) {
  296. DBG_VERBOSE(printf("UA_NodeId entered with dst=%p,isStart=%d\n", (void* ) dst, isStart));
  297. UA_UInt32 i;
  298. if (isStart) {
  299. if (dst == UA_NULL) {
  300. UA_NodeId_new(&dst);
  301. s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst;
  302. }
  303. s->parent[s->depth].len = 0;
  304. XML_Stack_addChildHandler(s, "Namespace", (XML_decoder) UA_Int16_decodeXML, UA_INT16, &(dst->namespace));
  305. XML_Stack_addChildHandler(s, "Numeric", (XML_decoder) UA_Int32_decodeXML, UA_INT32, &(dst->identifier.numeric));
  306. XML_Stack_addChildHandler(s, "Id", (XML_decoder) UA_String_decodeXML, UA_STRING, UA_NULL);
  307. XML_Stack_handleTextAsElementOf(s, "Data", 2);
  308. // set attributes
  309. for (i = 0; attr[i]; i += 2) {
  310. if (0 == strncmp("Namespace", attr[i], strlen("Namespace"))) {
  311. dst->namespace = atoi(attr[i + 1]);
  312. } else if (0 == strncmp("Numeric", attr[i], strlen("Numeric"))) {
  313. dst->identifier.numeric = atoi(attr[i + 1]);
  314. dst->encodingByte = UA_NODEIDTYPE_FOURBYTE;
  315. } else {
  316. printf("UA_NodeId_decodeXML - Unknown attribute name=%s, value=%s\n", attr[i], attr[i+1]);
  317. }
  318. }
  319. } else {
  320. switch (s->parent[s->depth - 1].activeChild) {
  321. case 2:
  322. UA_NodeId_copycstring((cstring_t)((UA_String*)attr)->data,dst,s->aliases);
  323. break;
  324. default:
  325. break;
  326. }
  327. // TODO: It is a design flaw that we need to do this here, isn't it?
  328. DBG_VERBOSE(
  329. printf("UA_String clears %p\n",
  330. (void* ) (s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj)));
  331. s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = UA_NULL;
  332. }
  333. return UA_SUCCESS;
  334. }
  335. UA_Int32 UA_ExpandedNodeId_decodeXML(XML_Stack_t* s, XML_Attr_t* attr, UA_ExpandedNodeId* dst, _Bool isStart) {
  336. DBG_VERBOSE(printf("UA_ExpandedNodeId entered with dst=%p,isStart=%d\n", (void* ) dst, isStart));
  337. UA_UInt32 i;
  338. if (isStart) {
  339. if (dst == UA_NULL) {
  340. UA_ExpandedNodeId_new(&dst);
  341. s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst;
  342. }
  343. s->parent[s->depth].len = 0;
  344. XML_Stack_addChildHandler(s, "NodeId", (XML_decoder) UA_NodeId_decodeXML, UA_NODEID, &(dst->nodeId));
  345. XML_Stack_addChildHandler(s, "Namespace", (XML_decoder) UA_Int16_decodeXML, UA_INT16, &(dst->nodeId.namespace));
  346. XML_Stack_addChildHandler(s, "Numeric", (XML_decoder) UA_Int32_decodeXML, UA_INT32,
  347. &(dst->nodeId.identifier.numeric));
  348. XML_Stack_addChildHandler(s, "Id", (XML_decoder) UA_String_decodeXML, UA_STRING, UA_NULL);
  349. XML_Stack_handleTextAsElementOf(s, "Data", 3);
  350. // set attributes
  351. for (i = 0; attr[i]; i += 2) {
  352. if (0 == strncmp("Namespace", attr[i], strlen("Namespace"))) {
  353. UA_UInt16_copycstring((cstring_t) attr[i + 1], &(dst->nodeId.namespace));
  354. } else if (0 == strncmp("Numeric", attr[i], strlen("Numeric"))) {
  355. UA_NodeId_copycstring((cstring_t) attr[i + 1], &(dst->nodeId), s->aliases);
  356. } else if (0 == strncmp("NodeId", attr[i], strlen("NodeId"))) {
  357. UA_NodeId_copycstring((cstring_t) attr[i + 1], &(dst->nodeId), s->aliases);
  358. } else {
  359. printf("UA_ExpandedNodeId_decodeXML - unknown attribute name=%s, value=%s\n", attr[i], attr[i+1]);
  360. }
  361. }
  362. } else {
  363. // TODO: It is a design flaw that we need to do this here, isn't it?
  364. DBG_VERBOSE(
  365. printf("UA_String clears %p\n",
  366. (void* ) (s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj)));
  367. s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = UA_NULL;
  368. }
  369. return UA_SUCCESS;
  370. }
  371. UA_Int32 UA_LocalizedText_decodeXML(XML_Stack_t* s, XML_Attr_t* attr, UA_LocalizedText* dst, _Bool isStart) {
  372. DBG_VERBOSE(printf("UA_LocalizedText entered with dst=%p,isStart=%d\n", (void* ) dst, isStart));
  373. UA_UInt32 i;
  374. if (isStart) {
  375. if (dst == UA_NULL) {
  376. UA_LocalizedText_new(&dst);
  377. s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst;
  378. }
  379. s->parent[s->depth].len = 0;
  380. XML_Stack_addChildHandler(s, "Text", (XML_decoder) UA_String_decodeXML, UA_STRING, &(dst->text));
  381. XML_Stack_addChildHandler(s, "Locale", (XML_decoder) UA_String_decodeXML, UA_STRING, &(dst->locale));
  382. XML_Stack_handleTextAsElementOf(s, "Data", 0);
  383. // set attributes
  384. for (i = 0; attr[i]; i += 2) {
  385. if (0 == strncmp("Text", attr[i], strlen("Text"))) {
  386. UA_String_copycstring(attr[i + 1], &(dst->text));
  387. dst->encodingMask |= UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT;
  388. } else if (0 == strncmp("Locale", attr[i], strlen("Locale"))) {
  389. UA_String_copycstring(attr[i + 1], &(dst->locale));
  390. dst->encodingMask |= UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_LOCALE;
  391. } else {
  392. perror("Unknown attribute");
  393. }
  394. }
  395. } else {
  396. switch (s->parent[s->depth - 1].activeChild) {
  397. case 0:
  398. dst->encodingMask |= UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT;
  399. break;
  400. case 1:
  401. dst->encodingMask |= UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_LOCALE;
  402. break;
  403. default:
  404. break;
  405. }
  406. // TODO: I think it is a design flaw that we need to do this here, isn't it?
  407. DBG_VERBOSE(
  408. printf("UA_LocalizedText clears %p\n",
  409. (void* ) (s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj)));
  410. s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = UA_NULL;
  411. }
  412. return UA_SUCCESS;
  413. }
  414. UA_Int32 UA_QualifiedName_decodeXML(XML_Stack_t* s, XML_Attr_t* attr, UA_QualifiedName* dst, _Bool isStart) {
  415. DBG_VERBOSE(printf("UA_QualifiedName entered with dst=%p,isStart=%d\n", (void* ) dst, isStart));
  416. UA_UInt32 i;
  417. if (isStart) {
  418. if (dst == UA_NULL) {
  419. UA_QualifiedName_new(&dst);
  420. s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst;
  421. }
  422. s->parent[s->depth].len = 0;
  423. XML_Stack_addChildHandler(s, "Name", (XML_decoder) UA_String_decodeXML, UA_STRING, &(dst->name));
  424. XML_Stack_addChildHandler(s, "NamespaceIndex", (XML_decoder) UA_Int16_decodeXML, UA_STRING,
  425. &(dst->namespaceIndex));
  426. XML_Stack_handleTextAsElementOf(s, "Data", 0);
  427. // set attributes
  428. for (i = 0; attr[i]; i += 2) {
  429. if (0 == strncmp("NamespaceIndex", attr[i], strlen("NamespaceIndex"))) {
  430. dst->namespaceIndex = atoi(attr[i + 1]);
  431. } else if (0 == strncmp("Name", attr[i], strlen("Name"))) {
  432. UA_String_copycstring(attr[i + 1], &(dst->name));
  433. } else {
  434. perror("Unknown attribute");
  435. }
  436. }
  437. } else {
  438. // TODO: I think it is a design flaw that we need to do this here, isn't it?
  439. DBG_VERBOSE(
  440. printf("UA_LocalizedText clears %p\n",
  441. (void* ) (s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj)));
  442. s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = UA_NULL;
  443. }
  444. return UA_SUCCESS;
  445. }
  446. UA_Int32 UA_ReferenceNode_decodeXML(XML_Stack_t* s, XML_Attr_t* attr, UA_ReferenceNode* dst, _Bool isStart) {
  447. DBG_VERBOSE(printf("UA_ReferenceNode_decodeXML entered with dst=%p,isStart=%d\n", (void* ) dst, isStart));
  448. if (isStart) {
  449. // create if necessary
  450. if (dst == UA_NULL) {
  451. UA_ReferenceNode_new(&dst);
  452. s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst;
  453. }
  454. // set handlers
  455. s->parent[s->depth].len = 0;
  456. XML_Stack_addChildHandler(s, "ReferenceType", (XML_decoder) UA_NodeId_decodeXML, UA_STRING,
  457. &(dst->referenceTypeId));
  458. XML_Stack_addChildHandler(s, "IsForward", (XML_decoder) UA_Boolean_decodeXML, UA_STRING, &(dst->isInverse));
  459. XML_Stack_addChildHandler(s, "Target", (XML_decoder) UA_ExpandedNodeId_decodeXML, UA_STRING, &(dst->targetId));
  460. XML_Stack_handleTextAsElementOf(s, "NodeId", 2);
  461. // set attributes
  462. UA_Int32 i;
  463. for (i = 0; attr[i]; i += 2) {
  464. if (0 == strncmp("ReferenceType", attr[i], strlen("ReferenceType"))) {
  465. UA_NodeId_copycstring(attr[i + 1], &(dst->referenceTypeId), s->aliases);
  466. } else if (0 == strncmp("IsForward", attr[i], strlen("IsForward"))) {
  467. UA_Boolean_copycstring(attr[i + 1], &(dst->isInverse));
  468. } else if (0 == strncmp("Target", attr[i], strlen("Target"))) {
  469. UA_ExpandedNodeId_copycstring(attr[i + 1], &(dst->targetId), s->aliases);
  470. } else {
  471. DBG_ERR(XML_Stack_print(s));DBG_ERR(printf("%s - unknown attribute\n", attr[i]));
  472. }
  473. }
  474. } else {
  475. // sub element is ready
  476. // TODO: It is a design flaw that we need to do this here, isn't it?
  477. DBG_VERBOSE(
  478. printf("UA_ReferenceNode clears %p\n",
  479. (void* ) (s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj)));
  480. s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = UA_NULL;
  481. }
  482. return UA_SUCCESS;
  483. }
  484. UA_Int32 UA_NodeSetReferences_decodeXML(XML_Stack_t* s, XML_Attr_t* attr, UA_NodeSetReferences* dst, _Bool isStart) {
  485. DBG_VERBOSE(printf("UA_NodeSetReferences entered with dst=%p,isStart=%d\n", (void* ) dst, isStart));
  486. if (isStart) {
  487. if (dst == UA_NULL) {
  488. UA_NodeSetReferences_new(&dst);
  489. s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst;
  490. }
  491. s->parent[s->depth].len = 0;
  492. XML_Stack_addChildHandler(s, "Reference", (XML_decoder) UA_ReferenceNode_decodeXML, UA_REFERENCENODE, UA_NULL);
  493. } else {
  494. // sub element is ready, add to array
  495. if (dst->size < 0 || dst->size == 0) {
  496. dst->size = 1;
  497. UA_alloc((void** )&(dst->references), dst->size * sizeof(UA_ReferenceNode*));
  498. DBG_VERBOSE(
  499. printf("allocate references:dst=%p, aliases=%p, size=%d\n", (void* )dst, (void* )(dst->references),
  500. dst->size));
  501. } else {
  502. dst->size++;
  503. dst->references = realloc(dst->references, dst->size * sizeof(UA_NodeSetAlias*));
  504. DBG_VERBOSE(
  505. printf("reallocate references:dst=%p, aliases=%p, size=%d\n", (void* )dst,
  506. (void* )(dst->references), dst->size));
  507. }
  508. // index starts with 0, therefore size-1
  509. DBG_VERBOSE(printf("assign alias:dst=%p, src=%p\n", (void* )dst->references[dst->size - 1], (void* )attr));
  510. dst->references[dst->size - 1] = (UA_ReferenceNode*) attr;
  511. // TODO: It is a design flaw that we need to do this here, isn't it?
  512. DBG_VERBOSE(
  513. printf("UA_NodeSetReferences clears %p\n",
  514. (void* ) (s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj)));
  515. s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj =
  516. UA_NULL;
  517. }
  518. return UA_SUCCESS;
  519. }
  520. UA_Int32 UA_DataTypeNode_decodeXML(XML_Stack_t* s, XML_Attr_t* attr, UA_DataTypeNode* dst, _Bool isStart) {
  521. DBG_VERBOSE(printf("UA_DataTypeNode entered with dst=%p,isStart=%d\n", (void* ) dst, isStart));
  522. UA_UInt32 i;
  523. if (isStart) {
  524. // create a new object if called with UA_NULL
  525. if (dst == UA_NULL) {
  526. UA_DataTypeNode_new(&dst);
  527. s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst;
  528. }
  529. s->parent[s->depth].len = 0;
  530. XML_Stack_addChildHandler(s, "DisplayName", (XML_decoder) UA_LocalizedText_decodeXML, UA_LOCALIZEDTEXT,
  531. &(dst->displayName));
  532. XML_Stack_addChildHandler(s, "Description", (XML_decoder) UA_LocalizedText_decodeXML, UA_LOCALIZEDTEXT,
  533. &(dst->description));
  534. XML_Stack_addChildHandler(s, "BrowseName", (XML_decoder) UA_QualifiedName_decodeXML, UA_QUALIFIEDNAME,
  535. &(dst->description));
  536. XML_Stack_addChildHandler(s, "References", (XML_decoder) UA_NodeSetReferences_decodeXML, UA_INVALIDTYPE,
  537. UA_NULL);
  538. // set missing default attributes
  539. dst->nodeClass = UA_NODECLASS_DATATYPE;
  540. // set attributes
  541. for (i = 0; attr[i]; i += 2) {
  542. if (0 == strncmp("NodeId", attr[i], strlen("NodeId"))) {
  543. UA_NodeId_copycstring(attr[i + 1], &(dst->nodeId), s->aliases);
  544. } else if (0 == strncmp("BrowseName", attr[i], strlen("BrowseName"))) {
  545. UA_String_copycstring(attr[i + 1], &(dst->browseName.name));
  546. dst->browseName.namespaceIndex = 0;
  547. } else if (0 == strncmp("DisplayName", attr[i], strlen("DisplayName"))) {
  548. UA_String_copycstring(attr[i + 1], &(dst->displayName.text));
  549. dst->displayName.encodingMask = UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT;
  550. } else if (0 == strncmp("Description", attr[i], strlen("Description"))) {
  551. UA_String_copycstring(attr[i + 1], &(dst->description.text));
  552. dst->description.encodingMask = UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT;
  553. } else {
  554. DBG_ERR(XML_Stack_print(s));DBG_ERR(printf("%s - unknown attribute\n", attr[i]));
  555. }
  556. }
  557. } else {
  558. switch (s->parent[s->depth - 1].activeChild) {
  559. case 3: // References
  560. if (attr != UA_NULL) {
  561. UA_NodeSetReferences* references = (UA_NodeSetReferences*) attr;
  562. DBG_VERBOSE(
  563. printf("finished aliases: references=%p, size=%d\n",(void*)references,(references==UA_NULL)?-1:references->size));
  564. dst->referencesSize = references->size;
  565. dst->references = references->references;
  566. }
  567. break;
  568. default:
  569. break;
  570. }
  571. // TODO: It is a design flaw that we need to do this here, isn't it?
  572. DBG_VERBOSE(
  573. printf("UA_DataTypeNode clears %p\n",
  574. (void* ) (s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj)));
  575. s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj =
  576. UA_NULL;
  577. }
  578. return UA_SUCCESS;
  579. }
  580. UA_Int32 UA_VariableNode_decodeXML(XML_Stack_t* s, XML_Attr_t* attr, UA_VariableNode* dst, _Bool isStart) {
  581. DBG_VERBOSE(printf("UA_VariableNode entered with dst=%p,isStart=%d\n", (void* ) dst, isStart));
  582. UA_UInt32 i;
  583. if (isStart) {
  584. // create a new object if called with UA_NULL
  585. if (dst == UA_NULL) {
  586. UA_VariableNode_new(&dst);
  587. s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst;
  588. }
  589. s->parent[s->depth].len = 0;
  590. XML_Stack_addChildHandler(s, "DisplayName", (XML_decoder) UA_LocalizedText_decodeXML, UA_LOCALIZEDTEXT,
  591. &(dst->displayName));
  592. XML_Stack_addChildHandler(s, "Description", (XML_decoder) UA_LocalizedText_decodeXML, UA_LOCALIZEDTEXT,
  593. &(dst->description));
  594. // XML_Stack_addChildHandler(s, "DataType", (XML_decoder) UA_NodeId_decodeXML, UA_NODEID, &(dst->dataType));
  595. XML_Stack_addChildHandler(s, "ValueRank", (XML_decoder) UA_Int32_decodeXML, UA_INT32, &(dst->valueRank));
  596. XML_Stack_addChildHandler(s, "References", (XML_decoder) UA_NodeSetReferences_decodeXML, UA_INVALIDTYPE,
  597. UA_NULL);
  598. // set missing default attributes
  599. dst->nodeClass = UA_NODECLASS_VARIABLE;
  600. // set attributes
  601. for (i = 0; attr[i]; i += 2) {
  602. if (0 == strncmp("NodeId", attr[i], strlen("NodeId"))) {
  603. UA_NodeId_copycstring(attr[i + 1], &(dst->nodeId), s->aliases);
  604. } else if (0 == strncmp("DataType", attr[i], strlen("DataType"))) {
  605. UA_NodeId_copycstring(attr[i + 1], &(dst->dataType), s->aliases);
  606. } else if (0 == strncmp("ValueRank", attr[i], strlen("ValueRank"))) {
  607. dst->valueRank = atoi(attr[i + 1]);
  608. } else if (0 == strncmp("ParentNodeId", attr[i], strlen("ParentNodeId"))) {
  609. // FIXME: I do not know what to do with this parameter
  610. } else if (0 == strncmp("BrowseName", attr[i], strlen("BrowseName"))) {
  611. UA_String_copycstring(attr[i + 1], &(dst->browseName.name));
  612. dst->browseName.namespaceIndex = 0;
  613. } else if (0 == strncmp("DisplayName", attr[i], strlen("DisplayName"))) {
  614. UA_String_copycstring(attr[i + 1], &(dst->displayName.text));
  615. dst->displayName.encodingMask = UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT;
  616. } else if (0 == strncmp("Description", attr[i], strlen("Description"))) {
  617. UA_String_copycstring(attr[i + 1], &(dst->description.text));
  618. dst->description.encodingMask = UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT;
  619. } else {
  620. DBG_ERR(XML_Stack_print(s));DBG_ERR(printf("%s - unknown attribute\n", attr[i]));
  621. }
  622. }
  623. } else {
  624. switch (s->parent[s->depth - 1].activeChild) {
  625. case 3: // References
  626. if (attr != UA_NULL) {
  627. UA_NodeSetReferences* references = (UA_NodeSetReferences*) attr;
  628. DBG_VERBOSE(
  629. printf("finished aliases: references=%p, size=%d\n",(void*)references,(references==UA_NULL)?-1:references->size));
  630. dst->referencesSize = references->size;
  631. dst->references = references->references;
  632. }
  633. break;
  634. default:
  635. break;
  636. }
  637. // TODO: It is a design flaw that we need to do this here, isn't it?
  638. DBG_VERBOSE(
  639. printf("UA_DataTypeNode clears %p\n",
  640. (void* ) (s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj)));
  641. s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj =
  642. UA_NULL;
  643. }
  644. return UA_SUCCESS;
  645. }
  646. void print_node(UA_Node const * node) {
  647. if (node != UA_NULL) {
  648. UA_NodeId_printf("--- node.nodeId=", &(node->nodeId));
  649. printf("\t.browseName='%.*s'\n", node->browseName.name.length, node->browseName.name.data);
  650. printf("\t.displayName='%.*s'\n", node->displayName.text.length, node->displayName.text.data);
  651. printf("\t.description='%.*s%s'\n", node->description.text.length > 40 ? 40 : node->description.text.length,
  652. node->description.text.data, node->description.text.length > 40 ? "..." : "");
  653. printf("\t.nodeClass=%d\n", node->nodeClass);
  654. printf("\t.writeMask=%d\n", node->writeMask);
  655. printf("\t.userWriteMask=%d\n", node->userWriteMask);
  656. printf("\t.referencesSize=%d\n", node->referencesSize);
  657. UA_Int32 i;
  658. for (i=0;i<node->referencesSize;i++) {
  659. printf("\t .references[%d]", i);
  660. UA_ReferenceNode_println("=",node->references[i]);
  661. }
  662. switch (node->nodeClass) {
  663. case UA_NODECLASS_VARIABLE: {
  664. UA_VariableNode const * p = (UA_VariableNode const *) node;
  665. printf("\t----- UA_VariableNode ----- \n");
  666. UA_NodeId_printf("\t.dataType=", &(p->dataType));
  667. printf("\t.valueRank=%d\n", p->valueRank);
  668. printf("\t.accessLevel=%d\n", p->accessLevel);
  669. printf("\t.userAccessLevel=%d\n", p->userAccessLevel);
  670. printf("\t.arrayDimensionsSize=%d\n", p->arrayDimensionsSize);
  671. printf("\t.minimumSamplingInterval=%f\n", p->minimumSamplingInterval);
  672. printf("\t.historizing=%d\n", p->historizing);
  673. }
  674. break;
  675. // case UA_NODECLASS_DATATYPE:
  676. default:
  677. break;
  678. }
  679. }
  680. }
  681. UA_Int32 UA_NodeSetAlias_decodeXML(XML_Stack_t* s, XML_Attr_t* attr, UA_NodeSetAlias* dst, _Bool isStart) {
  682. DBG_VERBOSE(printf("UA_NodeSetAlias entered with dst=%p,isStart=%d\n", (void* ) dst, isStart));
  683. if (isStart) {
  684. // create if necessary
  685. if (dst == UA_NULL) {
  686. UA_NodeSetAlias_new(&dst);
  687. s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst;
  688. }
  689. // set handlers
  690. s->parent[s->depth].len = 0;
  691. XML_Stack_addChildHandler(s, "Alias", (XML_decoder) UA_String_decodeXML, UA_STRING, &(dst->alias));
  692. XML_Stack_addChildHandler(s, "Value", (XML_decoder) UA_String_decodeXML, UA_STRING, &(dst->value));
  693. XML_Stack_handleTextAsElementOf(s, "Data", 1);
  694. // set attributes
  695. UA_Int32 i;
  696. for (i = 0; attr[i]; i += 2) {
  697. if (0 == strncmp("Alias", attr[i], strlen("Alias"))) {
  698. UA_String_copycstring(attr[i + 1], &(dst->alias));
  699. } else if (0 == strncmp("Value", attr[i], strlen("Value"))) {
  700. UA_String_copycstring(attr[i + 1], &(dst->value));
  701. } else {
  702. DBG_ERR(XML_Stack_print(s));DBG_ERR(printf("%s - unknown attribute\n", attr[i]));
  703. }
  704. }
  705. } else {
  706. // sub element is ready
  707. // TODO: It is a design flaw that we need to do this here, isn't it?
  708. DBG_VERBOSE(
  709. printf("UA_NodeSetAlias clears %p\n",
  710. (void* ) (s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj)));
  711. s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = UA_NULL;
  712. }
  713. return UA_SUCCESS;
  714. }
  715. UA_Int32 UA_NodeSetAliases_decodeXML(XML_Stack_t* s, XML_Attr_t* attr, UA_NodeSetAliases* dst, _Bool isStart) {
  716. DBG_VERBOSE(printf("UA_NodeSetALiases entered with dst=%p,isStart=%d\n", (void* ) dst, isStart));
  717. if (isStart) {
  718. if (dst == UA_NULL) {
  719. UA_NodeSetAliases_new(&dst);
  720. s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst;
  721. }
  722. s->parent[s->depth].len = 0;
  723. XML_Stack_addChildHandler(s, "Alias", (XML_decoder) UA_NodeSetAlias_decodeXML, UA_INVALIDTYPE, UA_NULL);
  724. } else {
  725. // sub element is ready, add to array
  726. if (dst->size < 0 || dst->size == 0) {
  727. dst->size = 1;
  728. UA_alloc((void** )&(dst->aliases), dst->size * sizeof(UA_NodeSetAlias*));
  729. DBG_VERBOSE(
  730. printf("allocate aliases:dst=%p, aliases=%p, size=%d\n", (void* )dst, (void* )(dst->aliases),
  731. dst->size));
  732. } else {
  733. dst->size++;
  734. dst->aliases = realloc(dst->aliases, dst->size * sizeof(UA_NodeSetAlias*));
  735. DBG_VERBOSE(
  736. printf("reallocate aliases:dst=%p, aliases=%p, size=%d\n", (void* )dst, (void* )(dst->aliases),
  737. dst->size));
  738. }
  739. // index starts with 0, therefore size-1
  740. DBG_VERBOSE(printf("assign alias:dst=%p, src=%p\n", (void* )dst->aliases[dst->size - 1], (void* )attr));
  741. dst->aliases[dst->size - 1] = (UA_NodeSetAlias*) attr;
  742. // TODO: It is a design flaw that we need to do this here, isn't it?
  743. DBG_VERBOSE(
  744. printf("UA_NodeSetAliases clears %p\n",
  745. (void* ) (s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj)));
  746. s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj =
  747. UA_NULL;
  748. }
  749. return UA_SUCCESS;
  750. }
  751. UA_Int32 UA_NodeSet_decodeXML(XML_Stack_t* s, XML_Attr_t* attr, UA_NodeSet* dst, _Bool isStart) {
  752. DBG_VERBOSE(printf("UA_NodeSet entered with dst=%p,isStart=%d\n", (void* ) dst, isStart));
  753. if (isStart) {
  754. if (dst == UA_NULL) {
  755. UA_NodeSet_new(&dst);
  756. s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst;
  757. }
  758. s->parent[s->depth].len = 0;
  759. XML_Stack_addChildHandler(s, "Aliases", (XML_decoder) UA_NodeSetAliases_decodeXML, UA_INVALIDTYPE,
  760. &(dst->aliases));
  761. XML_Stack_addChildHandler(s, "UADataType", (XML_decoder) UA_DataTypeNode_decodeXML, UA_DATATYPENODE, UA_NULL);
  762. XML_Stack_addChildHandler(s, "UAVariable", (XML_decoder) UA_VariableNode_decodeXML, UA_VARIABLENODE, UA_NULL);
  763. } else {
  764. switch (s->parent[s->depth - 1].activeChild) {
  765. case 0: // Aliases
  766. if (attr != UA_NULL) {
  767. UA_NodeSetAliases* aliases = (UA_NodeSetAliases*) attr;
  768. DBG_VERBOSE(
  769. printf("finished aliases: aliases=%p, size=%d\n",(void*)aliases,(aliases==UA_NULL)?-1:aliases->size));
  770. s->aliases = aliases;
  771. }
  772. break;
  773. case 1:
  774. case 2:
  775. if (attr != UA_NULL) {
  776. UA_Node* node = (UA_Node*) attr;
  777. DBG_VERBOSE(printf("finished node: node=%p\n", (void* )node));
  778. insert_node(dst->ns, node);
  779. DBG_VERBOSE(printf("Inserting "));DBG_VERBOSE(print_node(node));
  780. }
  781. break;
  782. default:
  783. break;
  784. }
  785. // TODO: It is a design flaw that we need to do this here, isn't it?
  786. DBG_VERBOSE(
  787. printf("UA_NodeSet clears %p\n",
  788. (void* ) (s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj)));
  789. s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = UA_NULL;
  790. }
  791. return UA_SUCCESS;
  792. }
  793. /** lookup if element is a known child of parent, if yes go for it otherwise ignore */
  794. void XML_Stack_startElement(void * data, const char *el, const char **attr) {
  795. XML_Stack_t* s = (XML_Stack_t*) data;
  796. int i;
  797. // scan expected children
  798. XML_Parent_t* cp = &s->parent[s->depth];
  799. for (i = 0; i < cp->len; i++) {
  800. if (0 == strncmp(cp->children[i].name, el, strlen(cp->children[i].name))) {
  801. DBG_VERBOSE(XML_Stack_print(s));
  802. DBG_VERBOSE(printf("%s - processing\n", el));
  803. cp->activeChild = i;
  804. s->depth++;
  805. s->parent[s->depth].name = el;
  806. s->parent[s->depth].len = 0;
  807. s->parent[s->depth].textAttribIdx = -1;
  808. s->parent[s->depth].activeChild = -1;
  809. // finally call the elementHandler and return
  810. cp->children[i].elementHandler(data, attr, cp->children[i].obj,
  811. TRUE);
  812. return;
  813. }
  814. }
  815. // if we come here we rejected the processing of el
  816. DBG_VERBOSE(XML_Stack_print(s));
  817. DBG_VERBOSE(printf("%s - rejected\n", el));
  818. s->depth++;
  819. s->parent[s->depth].name = el;
  820. // this should be sufficient to reject the children as well
  821. s->parent[s->depth].len = 0;
  822. }
  823. UA_Int32 XML_isSpace(cstring_t s, int len) {
  824. int i;
  825. for (i = 0; i < len; i++) {
  826. if (!isspace(s[i])) {
  827. return UA_FALSE;
  828. }
  829. }
  830. return UA_TRUE;
  831. }
  832. /* simulates startElement, endElement behaviour */
  833. void XML_Stack_handleText(void * data, const char *txt, int len) {
  834. XML_Stack_t* s = (XML_Stack_t*) data;
  835. if (len > 0 && !XML_isSpace(txt, len)) {
  836. XML_Parent_t* cp = &(s->parent[s->depth]);
  837. if (cp->textAttribIdx >= 0) {
  838. cp->activeChild = cp->textAttribIdx;
  839. char* buf; // need to copy txt to add 0 as string terminator
  840. UA_alloc((void** )&buf, len + 1);
  841. strncpy(buf, txt, len);
  842. buf[len] = 0;
  843. XML_Attr_t attr[3] = { cp->textAttrib, buf, UA_NULL };
  844. DBG_VERBOSE(
  845. printf("handleText calls start elementHandler %s with dst=%p, attr=%p\n",
  846. cp->children[cp->activeChild].name, cp->children[cp->activeChild].obj, (void* ) attr));
  847. cp->children[cp->activeChild].elementHandler(s, attr, cp->children[cp->activeChild].obj, TRUE);
  848. // FIXME: The indices of this call are simply wrong, so no finishing as of yet
  849. // DBG_VERBOSE(printf("handleText calls finish elementHandler %s with dst=%p, attr=(nil)\n", cp->children[cp->activeChild].name, cp->children[cp->activeChild].obj));
  850. // cp->children[cp->activeChild].elementHandler(s, UA_NULL, cp->children[cp->activeChild].obj, FALSE);
  851. UA_free(buf);
  852. } else {
  853. DBG_VERBOSE(XML_Stack_print(s));
  854. DBG_VERBOSE(printf("textData - ignore text data '%.*s'\n", len, txt));
  855. }
  856. }
  857. }
  858. /** if we are an activeChild of a parent we call the child-handler */
  859. void XML_Stack_endElement(void *data, const char *el) {
  860. XML_Stack_t* s = (XML_Stack_t*) data;
  861. // the parent of the parent of the element knows the elementHandler, therefore depth-2!
  862. if (s->depth > 1) {
  863. // inform parents elementHandler that everything is done
  864. XML_Parent_t* cp = &(s->parent[s->depth - 1]);
  865. XML_Parent_t* cpp = &(s->parent[s->depth - 2]);
  866. if (cpp->activeChild >= 0 && cp->activeChild >= 0) {
  867. DBG_VERBOSE(XML_Stack_print(s));
  868. DBG_VERBOSE(
  869. printf(" - inform pop %s, arg=%p\n", cpp->children[cpp->activeChild].name,
  870. (void* ) cp->children[cp->activeChild].obj));
  871. cpp->children[cpp->activeChild].elementHandler(s, (XML_Attr_t*) cp->children[cp->activeChild].obj,
  872. cpp->children[cpp->activeChild].obj, FALSE);
  873. }
  874. // reset
  875. cp->activeChild = -1;
  876. }
  877. s->depth--;
  878. }
  879. int main() {
  880. char buf[1024];
  881. int len; /* len is the number of bytes in the current bufferful of data */
  882. XML_Stack_t s;
  883. XML_Stack_init(&s, "ROOT");
  884. UA_NodeSet n;
  885. UA_NodeSet_init(&n);
  886. XML_Stack_addChildHandler(&s, "UANodeSet", (XML_decoder) UA_NodeSet_decodeXML, UA_INVALIDTYPE, &n);
  887. XML_Parser parser = XML_ParserCreate(NULL);
  888. XML_SetUserData(parser, &s);
  889. XML_SetElementHandler(parser, XML_Stack_startElement, XML_Stack_endElement);
  890. XML_SetCharacterDataHandler(parser, XML_Stack_handleText);
  891. while ((len = read(0, buf, 1024)) > 0) {
  892. if (!XML_Parse(parser, buf, len, (len < 1024))) {
  893. return 1;
  894. }
  895. }
  896. XML_ParserFree(parser);
  897. iterate_ns(n.ns, print_node);
  898. printf("aliases addr=%p, size=%d\n", (void*) &(n.aliases), n.aliases.size);
  899. UA_NodeSetAliases_println("aliases in nodeset: ", &n.aliases);
  900. return 0;
  901. }