xml2ns0.c 32 KB

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