ua_xml.c 49 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213
  1. /*
  2. * ua_xml.c
  3. *
  4. * Created on: 03.05.2014
  5. * Author: mrt
  6. */
  7. #include "ua_xml.h"
  8. #include <fcntl.h> // open, O_RDONLY
  9. UA_Int32 UA_TypedArray_init(UA_TypedArray* p) {
  10. p->size = -1;
  11. p->vt = &UA_[UA_INVALIDTYPE];
  12. p->elements = UA_NULL;
  13. return UA_SUCCESS;
  14. }
  15. UA_Int32 UA_TypedArray_new(UA_TypedArray** p) {
  16. UA_alloc((void** )p, sizeof(UA_TypedArray));
  17. UA_TypedArray_init(*p);
  18. return UA_SUCCESS;
  19. }
  20. UA_Int32 UA_TypedArray_setType(UA_TypedArray* p, UA_Int32 type) {
  21. UA_Int32 retval = UA_ERR_INVALID_VALUE;
  22. if (type >= UA_BOOLEAN && type <= UA_INVALIDTYPE) {
  23. p->vt = &UA_[type];
  24. retval = UA_SUCCESS;
  25. }
  26. return retval;
  27. }
  28. // FIXME: We might want to have these classes and their methods
  29. // defined in opcua.h via generate_builtin and the plugin-concept
  30. // or in ua_basictypes.c
  31. UA_Int32 UA_NodeSetAlias_init(UA_NodeSetAlias* p) {
  32. UA_String_init(&(p->alias));
  33. UA_String_init(&(p->value));
  34. return UA_SUCCESS;
  35. }
  36. UA_Int32 UA_NodeSetAlias_new(UA_NodeSetAlias** p) {
  37. UA_alloc((void** )p, sizeof(UA_NodeSetAlias));
  38. UA_NodeSetAlias_init(*p);
  39. return UA_SUCCESS;
  40. }
  41. UA_Int32 UA_NodeSetAliases_init(UA_NodeSetAliases* p) {
  42. p->size = -1;
  43. p->aliases = UA_NULL;
  44. return UA_SUCCESS;
  45. }
  46. UA_Int32 UA_NodeSetAliases_new(UA_NodeSetAliases** p) {
  47. UA_alloc((void** )p, sizeof(UA_NodeSetAliases));
  48. UA_NodeSetAliases_init(*p);
  49. return UA_SUCCESS;
  50. }
  51. UA_Int32 UA_NodeSetAliases_println(cstring label, UA_NodeSetAliases *p) {
  52. UA_Int32 i;
  53. for (i = 0; i < p->size; i++) {
  54. UA_NodeSetAlias* a = p->aliases[i];
  55. printf("%s{addr=%p", label, (void*) a);
  56. if (a) {
  57. printf(",alias='%.*s', value='%.*s'", a->alias.length, a->alias.data, a->value.length, a->value.data);
  58. }
  59. printf("}\n");
  60. }
  61. return UA_SUCCESS;
  62. }
  63. UA_Int32 UA_NodeSet_init(UA_NodeSet* p, UA_UInt32 nsid) {
  64. Namespace_new(&(p->ns), 100, nsid);
  65. p->aliases.size = -1;
  66. p->aliases.aliases = UA_NULL;
  67. return UA_SUCCESS;
  68. }
  69. UA_Int32 UA_NodeSet_new(UA_NodeSet** p, UA_UInt32 nsid) {
  70. UA_alloc((void** )p, sizeof(UA_NodeSet));
  71. UA_NodeSet_init(*p, nsid);
  72. return UA_SUCCESS;
  73. }
  74. UA_Int32 _UA_NodeId_copycstring(cstring src, UA_NodeId* dst, UA_NodeSetAliases* aliases) {
  75. UA_Int32 retval = UA_SUCCESS;
  76. if (src != UA_NULL && dst != UA_NULL ) {
  77. if (src[0] == 'i' && src[1] == '=') { // namespace zero numeric identifier
  78. dst->identifier.numeric = atoi(&src[2]);
  79. } else if (src[0] == 'n' && src[1] == 's' && src[2] == '=') { // namespace
  80. dst->namespace = atoi(&src[3]);
  81. src = strchr(&src[3],';');
  82. if (src != UA_NULL)
  83. retval = _UA_NodeId_copycstring(src+1,dst,aliases); // +1 to start beyond ;
  84. else
  85. retval = UA_ERR_INVALID_VALUE;
  86. } else if (aliases != UA_NULL ) { // try for aliases
  87. UA_Int32 i;
  88. for (i = 0; i < aliases->size && dst->identifier.numeric == 0; ++i) {
  89. if (0 == strncmp((char const*) src, (char const*) aliases->aliases[i]->alias.data,
  90. aliases->aliases[i]->alias.length)) {
  91. _UA_NodeId_copycstring((cstring)aliases->aliases[i]->alias.data,dst,UA_NULL); // substitute text of alias
  92. }
  93. }
  94. } else {
  95. retval = UA_ERR_NOT_IMPLEMENTED;
  96. }
  97. } else {
  98. retval = UA_ERR_INVALID_VALUE;
  99. }
  100. DBG_VERBOSE(printf("UA_NodeId_copycstring src=%s,id=%d\n", src, dst->identifier.numeric));
  101. return retval;
  102. }
  103. UA_Int32 UA_NodeId_copycstring(cstring src, UA_NodeId* dst, UA_NodeSetAliases* aliases) {
  104. dst->encodingByte = UA_NODEIDTYPE_FOURBYTE;
  105. dst->namespace = 0;
  106. dst->identifier.numeric = 0;
  107. return _UA_NodeId_copycstring(src,dst,aliases);
  108. }
  109. UA_Int32 UA_ReferenceNode_println(cstring label, UA_ReferenceNode *a) {
  110. printf("%s{referenceType=%d, target=%d, isInverse=%d}\n",
  111. label,
  112. a->referenceTypeId.identifier.numeric,
  113. a->targetId.nodeId.identifier.numeric,
  114. a->isInverse);
  115. return UA_SUCCESS;
  116. }
  117. UA_Int32 UA_ExpandedNodeId_copycstring(cstring src, UA_ExpandedNodeId* dst, UA_NodeSetAliases* aliases) {
  118. dst->nodeId.encodingByte = UA_NODEIDTYPE_FOURBYTE;
  119. dst->nodeId.namespace = 0;
  120. dst->nodeId.identifier.numeric = 0;
  121. UA_NodeId_copycstring(src, &(dst->nodeId), aliases);
  122. DBG_VERBOSE(printf("UA_ExpandedNodeId_copycstring src=%s,id=%d\n", src, dst->nodeId.identifier.numeric));
  123. return UA_SUCCESS;
  124. }
  125. void XML_Stack_init(XML_Stack* p, UA_UInt32 nsid, cstring name) {
  126. unsigned int i, j;
  127. p->depth = 0;
  128. for (i = 0; i < XML_STACK_MAX_DEPTH; i++) {
  129. p->parent[i].name = UA_NULL;
  130. p->parent[i].len = 0;
  131. p->parent[i].activeChild = -1;
  132. p->parent[i].textAttrib = UA_NULL;
  133. p->parent[i].textAttribIdx = -1;
  134. p->parent[i].totalGatherLength = -1;
  135. UA_list_init(&(p->parent[i].textGatherList));
  136. for (j = 0; j < XML_STACK_MAX_CHILDREN; j++) {
  137. p->parent[i].children[j].name = UA_NULL;
  138. p->parent[i].children[j].length = -1;
  139. p->parent[i].children[j].elementHandler = UA_NULL;
  140. p->parent[i].children[j].type = UA_INVALIDTYPE;
  141. p->parent[i].children[j].obj = UA_NULL;
  142. }
  143. }
  144. p->nsid = nsid;
  145. p->parent[0].name = name;
  146. }
  147. char path_buffer[1024];
  148. char * XML_Stack_path(XML_Stack* s) {
  149. UA_Int32 i;
  150. char *p = &path_buffer[0];
  151. for (i = 0; i <= s->depth; i++) {
  152. strcpy(p, s->parent[i].name);
  153. p += strlen(s->parent[i].name);
  154. *p = '/';
  155. p++;
  156. }
  157. *p=0;
  158. return &path_buffer[0];
  159. }
  160. void XML_Stack_print(XML_Stack* s) {
  161. printf("%s", XML_Stack_path(s));
  162. }
  163. // FIXME: we might want to calculate textAttribIdx from a string and the information given on the stack
  164. void XML_Stack_handleTextAsElementOf(XML_Stack* p, cstring textAttrib, unsigned int textAttribIdx) {
  165. p->parent[p->depth].textAttrib = textAttrib;
  166. p->parent[p->depth].textAttribIdx = textAttribIdx;
  167. }
  168. void XML_Stack_addChildHandler(XML_Stack* p, cstring name, UA_Int32 length, XML_decoder handler, UA_Int32 type, void* dst) {
  169. unsigned int len = p->parent[p->depth].len;
  170. p->parent[p->depth].children[len].name = name;
  171. p->parent[p->depth].children[len].length = length;
  172. p->parent[p->depth].children[len].elementHandler = handler;
  173. p->parent[p->depth].children[len].type = type;
  174. p->parent[p->depth].children[len].obj = dst;
  175. p->parent[p->depth].len++;
  176. }
  177. UA_Int32 UA_Int16_copycstring(cstring src, UA_Int16* dst) {
  178. *dst = atoi(src);
  179. return UA_SUCCESS;
  180. }
  181. UA_Int32 UA_UInt16_copycstring(cstring src, UA_UInt16* dst) {
  182. *dst = atoi(src);
  183. return UA_SUCCESS;
  184. }
  185. UA_Int32 UA_Int16_decodeXML(XML_Stack* s, XML_Attr* attr, UA_Int16* dst, _Bool isStart) {
  186. DBG_VERBOSE(printf("UA_Int32 entered with dst=%p,isStart=%d\n", (void* ) dst, isStart));
  187. if (isStart) {
  188. if (dst == UA_NULL) {
  189. UA_Int16_new(&dst);
  190. s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst;
  191. }
  192. UA_Int16_copycstring((cstring) attr[1], dst);
  193. }
  194. return UA_SUCCESS;
  195. }
  196. UA_Int32 UA_Int32_decodeXML(XML_Stack* s, XML_Attr* attr, UA_Int32* dst, _Bool isStart) {
  197. DBG_VERBOSE(printf("UA_Int32 entered with dst=%p,isStart=%d\n", (void* ) dst, isStart));
  198. if (isStart) {
  199. if (dst == UA_NULL) {
  200. UA_Int32_new(&dst);
  201. s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst;
  202. }
  203. *dst = atoi(attr[1]);
  204. }
  205. return UA_SUCCESS;
  206. }
  207. UA_Int32 UA_Text_decodeXML(XML_Stack* s, XML_Attr* attr, UA_Byte** dst, _Bool isStart) {
  208. DBG_VERBOSE(printf("UA_String entered with dst=%p,isStart=%d\n", (void* ) dst, isStart));
  209. UA_UInt32 i;
  210. if (isStart) {
  211. if (dst == UA_NULL) {
  212. UA_alloc((void**)&dst,sizeof(void*));
  213. s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst;
  214. }
  215. // set attributes
  216. for (i = 0; attr[i]; i += 2) {
  217. if (0 == strncmp("Data", attr[i], strlen("Data"))) {
  218. char* tmp;
  219. UA_alloc((void**)&tmp,strlen(attr[i+1])+1);
  220. strncpy(tmp,attr[i+1],strlen(attr[i+1]));
  221. tmp[strlen(attr[i+1])] = 0;
  222. *dst = (UA_Byte*) tmp;
  223. } else {
  224. printf("UA_Text_decodeXML - Unknown attribute - name=%s, value=%s\n", attr[i], attr[i+1]);
  225. }
  226. }
  227. }
  228. return UA_SUCCESS;
  229. }
  230. UA_Int32 UA_String_decodeXML(XML_Stack* s, XML_Attr* attr, UA_String* dst, _Bool isStart) {
  231. DBG_VERBOSE(printf("UA_String entered with dst=%p,isStart=%d\n", (void* ) dst, isStart));
  232. UA_UInt32 i;
  233. if (isStart) {
  234. if (dst == UA_NULL) {
  235. UA_String_new(&dst);
  236. s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst;
  237. }
  238. s->parent[s->depth].len = 0;
  239. XML_Stack_addChildHandler(s, "Data", strlen("Data"), (XML_decoder) UA_Text_decodeXML, UA_BYTE, &(dst->data));
  240. XML_Stack_addChildHandler(s, "Length", strlen("Length"), (XML_decoder) UA_Int32_decodeXML, UA_INT32, &(dst->length));
  241. XML_Stack_handleTextAsElementOf(s, "Data", 0);
  242. // set attributes
  243. for (i = 0; attr[i]; i += 2) {
  244. if (0 == strncmp("Data", attr[i], strlen("Data"))) {
  245. UA_String_copycstring(attr[i + 1], dst);
  246. } else {
  247. printf("UA_String_decodeXML - Unknown attribute - name=%s, value=%s\n", attr[i], attr[i+1]);
  248. }
  249. }
  250. } else {
  251. switch (s->parent[s->depth - 1].activeChild) {
  252. case 0:
  253. if (dst != UA_NULL && dst->data != UA_NULL && dst->length == -1) {
  254. dst->length = strlen((char const*)dst->data);
  255. }
  256. break;
  257. }
  258. }
  259. return UA_SUCCESS;
  260. }
  261. UA_Int32 UA_NodeId_decodeXML(XML_Stack* s, XML_Attr* attr, UA_NodeId* dst, _Bool isStart) {
  262. DBG_VERBOSE(printf("UA_NodeId entered with dst=%p,isStart=%d\n", (void* ) dst, isStart));
  263. UA_UInt32 i;
  264. if (isStart) {
  265. if (dst == UA_NULL) {
  266. UA_NodeId_new(&dst);
  267. s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst;
  268. }
  269. s->parent[s->depth].len = 0;
  270. XML_Stack_addChildHandler(s, "Namespace", strlen("Namespace"), (XML_decoder) UA_Int16_decodeXML, UA_INT16, &(dst->namespace));
  271. XML_Stack_addChildHandler(s, "Numeric", strlen("Numeric"), (XML_decoder) UA_Int32_decodeXML, UA_INT32, &(dst->identifier.numeric));
  272. XML_Stack_addChildHandler(s, "Identifier", strlen("Identifier"), (XML_decoder) UA_String_decodeXML, UA_STRING, UA_NULL);
  273. XML_Stack_handleTextAsElementOf(s, "Data", 2);
  274. // set attributes
  275. for (i = 0; attr[i]; i += 2) {
  276. if (0 == strncmp("Namespace", attr[i], strlen("Namespace"))) {
  277. dst->namespace = atoi(attr[i + 1]);
  278. } else if (0 == strncmp("Numeric", attr[i], strlen("Numeric"))) {
  279. dst->identifier.numeric = atoi(attr[i + 1]);
  280. dst->encodingByte = UA_NODEIDTYPE_FOURBYTE;
  281. } else {
  282. printf("UA_NodeId_decodeXML - Unknown attribute name=%s, value=%s\n", attr[i], attr[i+1]);
  283. }
  284. }
  285. } else {
  286. if (s->parent[s->depth - 1].activeChild == 2) {
  287. UA_NodeId_copycstring((cstring)((UA_String*)attr)->data,dst,s->aliases);
  288. }
  289. }
  290. return UA_SUCCESS;
  291. }
  292. UA_Int32 UA_ExpandedNodeId_decodeXML(XML_Stack* s, XML_Attr* attr, UA_ExpandedNodeId* dst, _Bool isStart) {
  293. DBG_VERBOSE(printf("UA_ExpandedNodeId entered with dst=%p,isStart=%d\n", (void* ) dst, isStart));
  294. UA_UInt32 i;
  295. if (isStart) {
  296. if (dst == UA_NULL) {
  297. UA_ExpandedNodeId_new(&dst);
  298. s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst;
  299. }
  300. s->parent[s->depth].len = 0;
  301. XML_Stack_addChildHandler(s, "NodeId", strlen("NodeId"), (XML_decoder) UA_NodeId_decodeXML, UA_NODEID, &(dst->nodeId));
  302. XML_Stack_addChildHandler(s, "Namespace", strlen("Namespace"),(XML_decoder) UA_Int16_decodeXML, UA_INT16, &(dst->nodeId.namespace));
  303. XML_Stack_addChildHandler(s, "Numeric", strlen("Numeric"),(XML_decoder) UA_Int32_decodeXML, UA_INT32,
  304. &(dst->nodeId.identifier.numeric));
  305. XML_Stack_addChildHandler(s, "Id", strlen("Id"),(XML_decoder) UA_String_decodeXML, UA_STRING, UA_NULL);
  306. XML_Stack_handleTextAsElementOf(s, "Data", 3);
  307. // set attributes
  308. for (i = 0; attr[i]; i += 2) {
  309. if (0 == strncmp("Namespace", attr[i], strlen("Namespace"))) {
  310. UA_UInt16_copycstring((cstring) attr[i + 1], &(dst->nodeId.namespace));
  311. } else if (0 == strncmp("Numeric", attr[i], strlen("Numeric"))) {
  312. UA_NodeId_copycstring((cstring) attr[i + 1], &(dst->nodeId), s->aliases);
  313. } else if (0 == strncmp("NodeId", attr[i], strlen("NodeId"))) {
  314. UA_NodeId_copycstring((cstring) attr[i + 1], &(dst->nodeId), s->aliases);
  315. } else {
  316. printf("UA_ExpandedNodeId_decodeXML - unknown attribute name=%s, value=%s\n", attr[i], attr[i+1]);
  317. }
  318. }
  319. }
  320. return UA_SUCCESS;
  321. }
  322. UA_Int32 UA_LocalizedText_decodeXML(XML_Stack* s, XML_Attr* attr, UA_LocalizedText* dst, _Bool isStart) {
  323. DBG_VERBOSE(printf("UA_LocalizedText entered with dst=%p,isStart=%d\n", (void* ) dst, isStart));
  324. UA_UInt32 i;
  325. if (isStart) {
  326. if (dst == UA_NULL) {
  327. UA_LocalizedText_new(&dst);
  328. s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst;
  329. }
  330. // s->parent[s->depth].len = 0;
  331. XML_Stack_addChildHandler(s, "Text", strlen("Text"), (XML_decoder) UA_String_decodeXML, UA_STRING, &(dst->text));
  332. XML_Stack_addChildHandler(s, "Locale", strlen("Locale"), (XML_decoder) UA_String_decodeXML, UA_STRING, &(dst->locale));
  333. XML_Stack_handleTextAsElementOf(s, "Data", 0);
  334. // set attributes
  335. for (i = 0; attr[i]; i += 2) {
  336. if (0 == strncmp("Text", attr[i], strlen("Text"))) {
  337. UA_String_copycstring(attr[i + 1], &(dst->text));
  338. dst->encodingMask |= UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT;
  339. } else if (0 == strncmp("Locale", attr[i], strlen("Locale"))) {
  340. UA_String_copycstring(attr[i + 1], &(dst->locale));
  341. dst->encodingMask |= UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_LOCALE;
  342. } else {
  343. perror("Unknown attribute");
  344. }
  345. }
  346. } else {
  347. switch (s->parent[s->depth - 1].activeChild) {
  348. case 0:
  349. dst->encodingMask |= UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT;
  350. break;
  351. case 1:
  352. dst->encodingMask |= UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_LOCALE;
  353. break;
  354. default:
  355. break;
  356. }
  357. }
  358. return UA_SUCCESS;
  359. }
  360. UA_Int32 UA_QualifiedName_decodeXML(XML_Stack* s, XML_Attr* attr, UA_QualifiedName* dst, _Bool isStart) {
  361. DBG_VERBOSE(printf("UA_QualifiedName entered with dst=%p,isStart=%d\n", (void* ) dst, isStart));
  362. UA_UInt32 i;
  363. if (isStart) {
  364. if (dst == UA_NULL) {
  365. UA_QualifiedName_new(&dst);
  366. s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst;
  367. }
  368. s->parent[s->depth].len = 0;
  369. XML_Stack_addChildHandler(s, "Name", strlen("Name"), (XML_decoder) UA_String_decodeXML, UA_STRING, &(dst->name));
  370. XML_Stack_addChildHandler(s, "NamespaceIndex", strlen("NamespaceIndex"), (XML_decoder) UA_Int16_decodeXML, UA_INT16,
  371. &(dst->namespaceIndex));
  372. XML_Stack_handleTextAsElementOf(s, "Data", 0);
  373. // set attributes
  374. for (i = 0; attr[i]; i += 2) {
  375. if (0 == strncmp("NamespaceIndex", attr[i], strlen("NamespaceIndex"))) {
  376. dst->namespaceIndex = atoi(attr[i + 1]);
  377. } else if (0 == strncmp("Name", attr[i], strlen("Name"))) {
  378. UA_String_copycstring(attr[i + 1], &(dst->name));
  379. } else {
  380. perror("Unknown attribute");
  381. }
  382. }
  383. }
  384. return UA_SUCCESS;
  385. }
  386. UA_Int32 UA_ReferenceNode_decodeXML(XML_Stack* s, XML_Attr* attr, UA_ReferenceNode* dst, _Bool isStart) {
  387. DBG_VERBOSE(printf("UA_ReferenceNode_decodeXML entered with dst=%p,isStart=%d\n", (void* ) dst, isStart));
  388. if (isStart) {
  389. // create if necessary
  390. if (dst == UA_NULL) {
  391. UA_ReferenceNode_new(&dst);
  392. s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst;
  393. }
  394. // set handlers
  395. s->parent[s->depth].len = 0;
  396. XML_Stack_addChildHandler(s, "ReferenceType", strlen("ReferenceType"),(XML_decoder) UA_NodeId_decodeXML, UA_NODEID, &(dst->referenceTypeId));
  397. XML_Stack_addChildHandler(s, "IsForward", strlen("IsForward"), (XML_decoder) UA_Boolean_decodeXML, UA_BOOLEAN, &(dst->isInverse));
  398. XML_Stack_addChildHandler(s, "Target", strlen("Target"), (XML_decoder) UA_ExpandedNodeId_decodeXML, UA_EXPANDEDNODEID, &(dst->targetId));
  399. XML_Stack_handleTextAsElementOf(s, "NodeId", 2);
  400. // set attributes
  401. UA_Int32 i;
  402. for (i = 0; attr[i]; i += 2) {
  403. if (0 == strncmp("ReferenceType", attr[i], strlen("ReferenceType"))) {
  404. UA_NodeId_copycstring(attr[i + 1], &(dst->referenceTypeId), s->aliases);
  405. } else if (0 == strncmp("IsForward", attr[i], strlen("IsForward"))) {
  406. UA_Boolean_copycstring(attr[i + 1], &(dst->isInverse));
  407. dst->isInverse = !dst->isInverse;
  408. } else if (0 == strncmp("Target", attr[i], strlen("Target"))) {
  409. UA_ExpandedNodeId_copycstring(attr[i + 1], &(dst->targetId), s->aliases);
  410. } else {
  411. DBG_ERR(XML_Stack_print(s));DBG_ERR(printf("%s - unknown attribute\n", attr[i]));
  412. }
  413. }
  414. }
  415. return UA_SUCCESS;
  416. }
  417. UA_Int32 UA_TypedArray_decodeXML(XML_Stack* s, XML_Attr* attr, UA_TypedArray* dst, _Bool isStart) {
  418. UA_Int32 type = s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].type;
  419. cstring names = s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].name;
  420. DBG_VERBOSE(printf("UA_TypedArray_decodeXML - entered with dst=%p,isStart=%d,type={%d,%s},name=%s\n", (void* ) dst, isStart,type,UA_[type].name, names));
  421. if (isStart) {
  422. if (dst == UA_NULL) {
  423. UA_TypedArray_new(&dst);
  424. UA_TypedArray_setType(dst, type);
  425. s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = dst;
  426. }
  427. // need to map from ArrayName to member name
  428. // References - Reference
  429. // Aliases - Alias
  430. // ListOfXX - XX
  431. UA_Int32 length = 0;
  432. if (0 == strncmp("ListOf",names,strlen("ListOf"))) {
  433. names = &names[strlen("ListOf")];
  434. length = strlen(names);
  435. } else if ( 0 == strncmp("References",names,strlen("References"))){
  436. length = strlen(names) - 1;
  437. } else if ( 0 == strncmp("Aliases",names,strlen("Aliases"))){
  438. length = strlen(names) - 2;
  439. }
  440. DBG(printf("UA_TypedArray_decodeXML - add handler for {%.*s}\n", length, names));
  441. XML_Stack_addChildHandler(s, names, length, (XML_decoder) UA_[type].decodeXML, type, UA_NULL);
  442. } else {
  443. // sub element is ready, add to array
  444. if (dst->size < 0 || dst->size == 0) {
  445. dst->size = 1;
  446. UA_alloc((void** )&(dst->elements), dst->size * sizeof(void*));
  447. DBG(printf("UA_TypedArray_decodeXML - allocate elements:dst=%p, aliases=%p, size=%d\n", (void* )dst, (void* )(dst->elements),dst->size));
  448. } else {
  449. dst->size++;
  450. dst->elements = realloc(dst->elements, dst->size * sizeof(void*));
  451. DBG(printf("UA_TypedArray_decodeXML - reallocate elements:dst=%p, aliases=%p, size=%d\n", (void* )dst,(void* )(dst->elements), dst->size));
  452. }
  453. // index starts with 0, therefore size-1
  454. DBG_VERBOSE(printf("UA_TypedArray_decodeXML - assign element[%d], src=%p\n", dst->size - 1, (void* )attr));
  455. dst->elements[dst->size - 1] = (void*) attr;
  456. DBG_VERBOSE(printf("UA_TypedArray_decodeXML - clear %p\n",(void* ) (s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj)));
  457. s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = UA_NULL;
  458. }
  459. return UA_SUCCESS;
  460. }
  461. UA_Int32 UA_DataTypeNode_decodeXML(XML_Stack* s, XML_Attr* attr, UA_DataTypeNode* dst, _Bool isStart) {
  462. DBG_VERBOSE(printf("UA_DataTypeNode entered with dst=%p,isStart=%d\n", (void* ) dst, isStart));
  463. UA_UInt32 i;
  464. if (isStart) {
  465. // create a new object if called with UA_NULL
  466. if (dst == UA_NULL) {
  467. UA_DataTypeNode_new(&dst);
  468. s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst;
  469. }
  470. s->parent[s->depth].len = 0;
  471. XML_Stack_addChildHandler(s, "DisplayName", strlen("DisplayName"), (XML_decoder) UA_LocalizedText_decodeXML, UA_LOCALIZEDTEXT, &(dst->displayName));
  472. XML_Stack_addChildHandler(s, "Description", strlen("Description"),(XML_decoder) UA_LocalizedText_decodeXML, UA_LOCALIZEDTEXT, &(dst->description));
  473. XML_Stack_addChildHandler(s, "BrowseName", strlen("BrowseName"),(XML_decoder) UA_QualifiedName_decodeXML, UA_QUALIFIEDNAME, &(dst->description));
  474. XML_Stack_addChildHandler(s, "IsAbstract", strlen("IsAbstract"),(XML_decoder) UA_Boolean_decodeXML, UA_BOOLEAN, &(dst->description));
  475. XML_Stack_addChildHandler(s, "References", strlen("References"),(XML_decoder) UA_TypedArray_decodeXML, UA_REFERENCENODE, UA_NULL);
  476. // set missing default attributes
  477. dst->nodeClass = UA_NODECLASS_DATATYPE;
  478. // set attributes
  479. for (i = 0; attr[i]; i += 2) {
  480. if (0 == strncmp("NodeId", attr[i], strlen("NodeId"))) {
  481. UA_NodeId_copycstring(attr[i + 1], &(dst->nodeId), s->aliases);
  482. } else if (0 == strncmp("BrowseName", attr[i], strlen("BrowseName"))) {
  483. UA_String_copycstring(attr[i + 1], &(dst->browseName.name));
  484. dst->browseName.namespaceIndex = 0;
  485. } else if (0 == strncmp("DisplayName", attr[i], strlen("DisplayName"))) {
  486. UA_String_copycstring(attr[i + 1], &(dst->displayName.text));
  487. dst->displayName.encodingMask = UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT;
  488. } else if (0 == strncmp("IsAbstract", attr[i], strlen("IsAbstract"))) {
  489. UA_Boolean_copycstring(attr[i + 1], &(dst->isAbstract));
  490. dst->displayName.encodingMask = UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT;
  491. } else if (0 == strncmp("Description", attr[i], strlen("Description"))) {
  492. UA_String_copycstring(attr[i + 1], &(dst->description.text));
  493. dst->description.encodingMask = UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT;
  494. } else {
  495. DBG_ERR(XML_Stack_print(s));DBG_ERR(printf("%s - unknown attribute\n", attr[i]));
  496. }
  497. }
  498. } else {
  499. switch (s->parent[s->depth - 1].activeChild) {
  500. case 4: // References
  501. if (attr != UA_NULL) {
  502. UA_TypedArray* array = (UA_TypedArray *) attr;
  503. DBG_VERBOSE(printf("finished aliases: references=%p, size=%d\n",(void*)array,(array==UA_NULL)?-1:array->size));
  504. dst->referencesSize = array->size;
  505. dst->references = (UA_ReferenceNode**) array->elements;
  506. }
  507. break;
  508. }
  509. }
  510. return UA_SUCCESS;
  511. }
  512. UA_Int32 UA_ObjectTypeNode_decodeXML(XML_Stack* s, XML_Attr* attr, UA_ObjectTypeNode* dst, _Bool isStart) {
  513. DBG_VERBOSE(printf("UA_DataTypeNode entered with dst=%p,isStart=%d\n", (void* ) dst, isStart));
  514. UA_UInt32 i;
  515. if (isStart) {
  516. // create a new object if called with UA_NULL
  517. if (dst == UA_NULL) {
  518. UA_ObjectTypeNode_new(&dst);
  519. s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst;
  520. }
  521. s->parent[s->depth].len = 0;
  522. XML_Stack_addChildHandler(s, "DisplayName", strlen("DisplayName"), (XML_decoder) UA_LocalizedText_decodeXML, UA_LOCALIZEDTEXT, &(dst->displayName));
  523. XML_Stack_addChildHandler(s, "Description", strlen("Description"),(XML_decoder) UA_LocalizedText_decodeXML, UA_LOCALIZEDTEXT, &(dst->description));
  524. XML_Stack_addChildHandler(s, "BrowseName", strlen("BrowseName"),(XML_decoder) UA_QualifiedName_decodeXML, UA_QUALIFIEDNAME, &(dst->description));
  525. XML_Stack_addChildHandler(s, "IsAbstract", strlen("IsAbstract"),(XML_decoder) UA_Boolean_decodeXML, UA_BOOLEAN, &(dst->description));
  526. XML_Stack_addChildHandler(s, "References", strlen("References"),(XML_decoder) UA_TypedArray_decodeXML, UA_REFERENCENODE, UA_NULL);
  527. // set missing default attributes
  528. dst->nodeClass = UA_NODECLASS_OBJECTTYPE;
  529. // set attributes
  530. for (i = 0; attr[i]; i += 2) {
  531. if (0 == strncmp("NodeId", attr[i], strlen("NodeId"))) {
  532. UA_NodeId_copycstring(attr[i + 1], &(dst->nodeId), s->aliases);
  533. } else if (0 == strncmp("BrowseName", attr[i], strlen("BrowseName"))) {
  534. UA_String_copycstring(attr[i + 1], &(dst->browseName.name));
  535. dst->browseName.namespaceIndex = 0;
  536. } else if (0 == strncmp("DisplayName", attr[i], strlen("DisplayName"))) {
  537. UA_String_copycstring(attr[i + 1], &(dst->displayName.text));
  538. dst->displayName.encodingMask = UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT;
  539. } else if (0 == strncmp("IsAbstract", attr[i], strlen("IsAbstract"))) {
  540. UA_Boolean_copycstring(attr[i + 1], &(dst->isAbstract));
  541. dst->displayName.encodingMask = UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT;
  542. } else if (0 == strncmp("Description", attr[i], strlen("Description"))) {
  543. UA_String_copycstring(attr[i + 1], &(dst->description.text));
  544. dst->description.encodingMask = UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT;
  545. } else {
  546. DBG_ERR(XML_Stack_print(s));DBG_ERR(printf("%s - unknown attribute\n", attr[i]));
  547. }
  548. }
  549. } else {
  550. switch (s->parent[s->depth - 1].activeChild) {
  551. case 4: // References
  552. if (attr != UA_NULL) {
  553. UA_TypedArray* array = (UA_TypedArray *) attr;
  554. DBG_VERBOSE(printf("finished aliases: references=%p, size=%d\n",(void*)array,(array==UA_NULL)?-1:array->size));
  555. dst->referencesSize = array->size;
  556. dst->references = (UA_ReferenceNode**) array->elements;
  557. }
  558. break;
  559. }
  560. }
  561. return UA_SUCCESS;
  562. }
  563. UA_Int32 UA_VariableTypeNode_decodeXML(XML_Stack* s, XML_Attr* attr, UA_VariableTypeNode* dst, _Bool isStart) {
  564. DBG_VERBOSE(printf("UA_DataTypeNode entered with dst=%p,isStart=%d\n", (void* ) dst, isStart));
  565. UA_UInt32 i;
  566. if (isStart) {
  567. // create a new object if called with UA_NULL
  568. if (dst == UA_NULL) {
  569. UA_VariableTypeNode_new(&dst);
  570. s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst;
  571. }
  572. s->parent[s->depth].len = 0;
  573. XML_Stack_addChildHandler(s, "DisplayName", strlen("DisplayName"), (XML_decoder) UA_LocalizedText_decodeXML, UA_LOCALIZEDTEXT, &(dst->displayName));
  574. XML_Stack_addChildHandler(s, "Description", strlen("Description"),(XML_decoder) UA_LocalizedText_decodeXML, UA_LOCALIZEDTEXT, &(dst->description));
  575. XML_Stack_addChildHandler(s, "BrowseName", strlen("BrowseName"),(XML_decoder) UA_QualifiedName_decodeXML, UA_QUALIFIEDNAME, &(dst->description));
  576. XML_Stack_addChildHandler(s, "IsAbstract", strlen("IsAbstract"),(XML_decoder) UA_Boolean_decodeXML, UA_BOOLEAN, &(dst->description));
  577. XML_Stack_addChildHandler(s, "References", strlen("References"),(XML_decoder) UA_TypedArray_decodeXML, UA_REFERENCENODE, UA_NULL);
  578. // set missing default attributes
  579. dst->nodeClass = UA_NODECLASS_VARIABLETYPE;
  580. // set attributes
  581. for (i = 0; attr[i]; i += 2) {
  582. if (0 == strncmp("NodeId", attr[i], strlen("NodeId"))) {
  583. UA_NodeId_copycstring(attr[i + 1], &(dst->nodeId), s->aliases);
  584. } else if (0 == strncmp("BrowseName", attr[i], strlen("BrowseName"))) {
  585. UA_String_copycstring(attr[i + 1], &(dst->browseName.name));
  586. dst->browseName.namespaceIndex = 0;
  587. } else if (0 == strncmp("DisplayName", attr[i], strlen("DisplayName"))) {
  588. UA_String_copycstring(attr[i + 1], &(dst->displayName.text));
  589. dst->displayName.encodingMask = UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT;
  590. } else if (0 == strncmp("IsAbstract", attr[i], strlen("IsAbstract"))) {
  591. UA_Boolean_copycstring(attr[i + 1], &(dst->isAbstract));
  592. dst->displayName.encodingMask = UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT;
  593. } else if (0 == strncmp("Description", attr[i], strlen("Description"))) {
  594. UA_String_copycstring(attr[i + 1], &(dst->description.text));
  595. dst->description.encodingMask = UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT;
  596. } else {
  597. DBG_ERR(XML_Stack_print(s));DBG_ERR(printf("%s - unknown attribute\n", attr[i]));
  598. }
  599. }
  600. } else {
  601. switch (s->parent[s->depth - 1].activeChild) {
  602. case 4: // References
  603. if (attr != UA_NULL) {
  604. UA_TypedArray* array = (UA_TypedArray *) attr;
  605. DBG_VERBOSE(printf("finished aliases: references=%p, size=%d\n",(void*)array,(array==UA_NULL)?-1:array->size));
  606. dst->referencesSize = array->size;
  607. dst->references = (UA_ReferenceNode**) array->elements;
  608. }
  609. break;
  610. }
  611. }
  612. return UA_SUCCESS;
  613. }
  614. UA_Int32 UA_ObjectNode_decodeXML(XML_Stack* s, XML_Attr* attr, UA_ObjectNode* dst, _Bool isStart) {
  615. DBG_VERBOSE(printf("UA_ObjectNode entered with dst=%p,isStart=%d\n", (void* ) dst, isStart));
  616. UA_UInt32 i;
  617. if (isStart) {
  618. // create a new object if called with UA_NULL
  619. if (dst == UA_NULL) {
  620. UA_ObjectNode_new(&dst);
  621. s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst;
  622. }
  623. XML_Stack_addChildHandler(s, "DisplayName", strlen("DisplayName"), (XML_decoder) UA_LocalizedText_decodeXML, UA_LOCALIZEDTEXT, &(dst->displayName));
  624. XML_Stack_addChildHandler(s, "Description", strlen("Description"), (XML_decoder) UA_LocalizedText_decodeXML, UA_LOCALIZEDTEXT, &(dst->description));
  625. XML_Stack_addChildHandler(s, "BrowseName", strlen("BrowseName"), (XML_decoder) UA_QualifiedName_decodeXML, UA_QUALIFIEDNAME, &(dst->browseName));
  626. XML_Stack_addChildHandler(s, "SymbolicName", strlen("SymbolicName"), (XML_decoder) UA_QualifiedName_decodeXML, UA_QUALIFIEDNAME,&(dst->browseName));
  627. XML_Stack_addChildHandler(s, "References", strlen("References"), (XML_decoder) UA_TypedArray_decodeXML, UA_REFERENCENODE, UA_NULL);
  628. // set missing default attributes
  629. dst->nodeClass = UA_NODECLASS_OBJECT;
  630. // set attributes
  631. for (i = 0; attr[i]; i += 2) {
  632. if (0 == strncmp("NodeId", attr[i], strlen("NodeId"))) {
  633. UA_NodeId_copycstring(attr[i + 1], &(dst->nodeId), s->aliases);
  634. } else if (0 == strncmp("SymbolicName", attr[i], strlen("SymbolicName"))) {
  635. UA_String_copycstring(attr[i + 1], &(dst->browseName.name));
  636. dst->browseName.namespaceIndex = 0;
  637. } else if (0 == strncmp("BrowseName", attr[i], strlen("BrowseName"))) {
  638. UA_String_copycstring(attr[i + 1], &(dst->browseName.name));
  639. dst->browseName.namespaceIndex = 0;
  640. } else if (0 == strncmp("DisplayName", attr[i], strlen("DisplayName"))) {
  641. UA_String_copycstring(attr[i + 1], &(dst->displayName.text));
  642. dst->displayName.encodingMask = UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT;
  643. } else if (0 == strncmp("Description", attr[i], strlen("Description"))) {
  644. UA_String_copycstring(attr[i + 1], &(dst->description.text));
  645. dst->description.encodingMask = UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT;
  646. } else {
  647. DBG_ERR(XML_Stack_print(s));DBG_ERR(printf("%s - unknown attribute\n", attr[i]));
  648. }
  649. }
  650. } else {
  651. if (s->parent[s->depth - 1].activeChild == 4 && attr != UA_NULL ) { // References Array
  652. UA_TypedArray* array = (UA_TypedArray*) attr;
  653. DBG(printf("UA_ObjectNode_decodeXML finished references: references=%p, size=%d\n",(void*)array,(array==UA_NULL)?-1:array->size));
  654. dst->referencesSize = array->size;
  655. dst->references = (UA_ReferenceNode**) array->elements;
  656. s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = UA_NULL;
  657. }
  658. }
  659. return UA_SUCCESS;
  660. }
  661. UA_Int32 UA_Variant_decodeXML(XML_Stack* s, XML_Attr* attr, UA_Variant* dst, _Bool isStart) {
  662. DBG_VERBOSE(printf("UA_Variant entered with dst=%p,isStart=%d\n", (void* ) dst, isStart));
  663. UA_UInt32 i;
  664. if (isStart) {
  665. // create a new object if called with UA_NULL
  666. if (dst == UA_NULL) {
  667. UA_Variant_new(&dst);
  668. s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst;
  669. }
  670. s->parent[s->depth].len = 0;
  671. XML_Stack_addChildHandler(s, "ListOfExtensionObject", strlen("ListOfExtensionObject"), (XML_decoder) UA_TypedArray_decodeXML, UA_EXTENSIONOBJECT, UA_NULL);
  672. XML_Stack_addChildHandler(s, "ListOfLocalizedText", strlen("ListOfLocalizedText"), (XML_decoder) UA_TypedArray_decodeXML, UA_LOCALIZEDTEXT, UA_NULL);
  673. // set attributes
  674. for (i = 0; attr[i]; i += 2) {
  675. {
  676. DBG_ERR(XML_Stack_print(s));
  677. DBG_ERR(printf("%s - unknown attribute\n", attr[i]));
  678. }
  679. }
  680. } else {
  681. if (s->parent[s->depth - 1].activeChild == 0 && attr != UA_NULL ) { // ExtensionObject
  682. UA_TypedArray* array = (UA_TypedArray*) attr;
  683. DBG_VERBOSE(printf("UA_Variant_decodeXML - finished array: references=%p, size=%d\n",(void*)array,(array==UA_NULL)?-1:array->size));
  684. dst->arrayLength = array->size;
  685. dst->data = array->elements;
  686. dst->vt = &UA_[UA_EXTENSIONOBJECT];
  687. dst->encodingMask = UA_EXTENSIONOBJECT_NS0 & UA_VARIANT_ENCODINGMASKTYPE_ARRAY;
  688. s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = UA_NULL;
  689. } else if (s->parent[s->depth - 1].activeChild == 1 && attr != UA_NULL ) { // LocalizedText
  690. UA_TypedArray* array = (UA_TypedArray*) attr;
  691. DBG_VERBOSE(printf("UA_Variant_decodeXML - finished array: references=%p, size=%d\n",(void*)array,(array==UA_NULL)?-1:array->size));
  692. dst->arrayLength = array->size;
  693. dst->data = array->elements;
  694. dst->vt = &UA_[UA_LOCALIZEDTEXT];
  695. dst->encodingMask = UA_LOCALIZEDTEXT_NS0 & UA_VARIANT_ENCODINGMASKTYPE_ARRAY;
  696. s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = UA_NULL;
  697. }
  698. }
  699. return UA_SUCCESS;
  700. }
  701. UA_Int32 UA_ExtensionObject_decodeXML(XML_Stack* s, XML_Attr* attr, UA_ExtensionObject* dst, _Bool isStart) {
  702. DBG_VERBOSE(printf("UA_ExtensionObject entered with dst=%p,isStart=%d\n", (void* ) dst, isStart));
  703. UA_UInt32 i;
  704. if (isStart) {
  705. // create a new object if called with UA_NULL
  706. if (dst == UA_NULL) {
  707. UA_ExtensionObject_new(&dst);
  708. s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst;
  709. }
  710. s->parent[s->depth].len = 0;
  711. XML_Stack_addChildHandler(s, "TypeId", strlen("TypeId"), (XML_decoder) UA_NodeId_decodeXML, UA_NODEID, &(dst->typeId));
  712. // XML_Stack_addChildHandler(s, "Body", strlen("Body"), (XML_decoder) UA_Body_decodeXML, UA_LOCALIZEDTEXT, UA_NULL);
  713. // set attributes
  714. for (i = 0; attr[i]; i += 2) {
  715. {
  716. DBG_ERR(XML_Stack_print(s));
  717. DBG_ERR(printf("%s - unknown attribute\n", attr[i]));
  718. }
  719. }
  720. }
  721. return UA_SUCCESS;
  722. }
  723. _Bool UA_NodeId_isBuiltinType(UA_NodeId* nodeid) {
  724. return (nodeid->namespace == 0 &&
  725. nodeid->identifier.numeric >= UA_BOOLEAN_NS0 &&
  726. nodeid->identifier.numeric <= UA_DIAGNOSTICINFO_NS0
  727. );
  728. }
  729. UA_Int32 UA_VariableNode_decodeXML(XML_Stack* s, XML_Attr* attr, UA_VariableNode* dst, _Bool isStart) {
  730. DBG_VERBOSE(printf("UA_VariableNode entered with dst=%p,isStart=%d\n", (void* ) dst, isStart));
  731. UA_UInt32 i;
  732. if (isStart) {
  733. // create a new object if called with UA_NULL
  734. if (dst == UA_NULL) {
  735. UA_VariableNode_new(&dst);
  736. s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst;
  737. }
  738. s->parent[s->depth].len = 0;
  739. XML_Stack_addChildHandler(s, "DisplayName", strlen("DisplayName"), (XML_decoder) UA_LocalizedText_decodeXML, UA_LOCALIZEDTEXT,
  740. &(dst->displayName));
  741. XML_Stack_addChildHandler(s, "Description", strlen("Description"),(XML_decoder) UA_LocalizedText_decodeXML, UA_LOCALIZEDTEXT,
  742. &(dst->description));
  743. XML_Stack_addChildHandler(s, "DataType", strlen("DataType"),(XML_decoder) UA_NodeId_decodeXML, UA_NODEID, &(dst->dataType));
  744. XML_Stack_addChildHandler(s, "ValueRank", strlen("ValueRank"),(XML_decoder) UA_Int32_decodeXML, UA_INT32, &(dst->valueRank));
  745. XML_Stack_addChildHandler(s, "Value", strlen("Value"),(XML_decoder) UA_Variant_decodeXML, UA_VARIANT, &(dst->value));
  746. XML_Stack_addChildHandler(s, "References", strlen("References"), (XML_decoder) UA_TypedArray_decodeXML, UA_REFERENCENODE,
  747. UA_NULL);
  748. // set missing default attributes
  749. dst->nodeClass = UA_NODECLASS_VARIABLE;
  750. // set attributes
  751. for (i = 0; attr[i]; i += 2) {
  752. if (0 == strncmp("NodeId", attr[i], strlen("NodeId"))) {
  753. UA_NodeId_copycstring(attr[i + 1], &(dst->nodeId), s->aliases);
  754. } else if (0 == strncmp("DataType", attr[i], strlen("DataType"))) {
  755. UA_NodeId_copycstring(attr[i + 1], &(dst->dataType), s->aliases);
  756. if (UA_NodeId_isBuiltinType(&(dst->dataType))) {
  757. dst->value.encodingMask = dst->dataType.identifier.numeric;
  758. dst->value.vt = &UA_[UA_ns0ToVTableIndex(dst->dataType.identifier.numeric)];
  759. } else {
  760. dst->value.encodingMask = UA_EXTENSIONOBJECT_NS0;
  761. dst->value.vt = &UA_[UA_EXTENSIONOBJECT];
  762. }
  763. } else if (0 == strncmp("ValueRank", attr[i], strlen("ValueRank"))) {
  764. dst->valueRank = atoi(attr[i + 1]);
  765. } else if (0 == strncmp("ParentNodeId", attr[i], strlen("ParentNodeId"))) {
  766. // FIXME: this seems to be redundant to the hasProperty-reference
  767. } else if (0 == strncmp("BrowseName", attr[i], strlen("BrowseName"))) {
  768. UA_String_copycstring(attr[i + 1], &(dst->browseName.name));
  769. dst->browseName.namespaceIndex = 0;
  770. } else if (0 == strncmp("DisplayName", attr[i], strlen("DisplayName"))) {
  771. UA_String_copycstring(attr[i + 1], &(dst->displayName.text));
  772. dst->displayName.encodingMask = UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT;
  773. } else if (0 == strncmp("Description", attr[i], strlen("Description"))) {
  774. UA_String_copycstring(attr[i + 1], &(dst->description.text));
  775. dst->description.encodingMask = UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT;
  776. } else {
  777. DBG_ERR(XML_Stack_print(s));
  778. DBG_ERR(printf("%s - unknown attribute\n", attr[i]));
  779. }
  780. }
  781. } else {
  782. if (s->parent[s->depth - 1].activeChild == 5 && attr != UA_NULL) { // References
  783. UA_TypedArray* array = (UA_TypedArray*) attr;
  784. DBG(printf("UA_VariableNode_decodeXML - finished references=%p, size=%d\n",(void*)array,(array==UA_NULL)?-1:array->size));
  785. dst->referencesSize = array->size;
  786. dst->references = (UA_ReferenceNode**) array->elements;
  787. s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = UA_NULL;
  788. }
  789. }
  790. return UA_SUCCESS;
  791. }
  792. void print_node(UA_Node const * node) {
  793. if (node != UA_NULL) {
  794. UA_NodeId_printf("node.nodeId=", &(node->nodeId));
  795. printf("\t.browseName='%.*s'\n", node->browseName.name.length, node->browseName.name.data);
  796. printf("\t.displayName='%.*s'\n", node->displayName.text.length, node->displayName.text.data);
  797. printf("\t.description='%.*s%s'\n", node->description.text.length > 40 ? 40 : node->description.text.length,
  798. node->description.text.data, node->description.text.length > 40 ? "..." : "");
  799. printf("\t.nodeClass=%d\n", node->nodeClass);
  800. printf("\t.writeMask=%d\n", node->writeMask);
  801. printf("\t.userWriteMask=%d\n", node->userWriteMask);
  802. printf("\t.references.size=%d\n", node->referencesSize);
  803. UA_Int32 i;
  804. for (i=0;i<node->referencesSize;i++) {
  805. printf("\t\t.element[%d]", i);
  806. UA_ReferenceNode_println("=",node->references[i]);
  807. }
  808. switch (node->nodeClass) {
  809. case UA_NODECLASS_VARIABLE: {
  810. UA_VariableNode const * p = (UA_VariableNode const *) node;
  811. printf("\t----- UA_VariableNode ----- \n");
  812. UA_NodeId_printf("\t.dataType=", &(p->dataType));
  813. printf("\t.valueRank=%d\n", p->valueRank);
  814. printf("\t.accessLevel=%d\n", p->accessLevel);
  815. printf("\t.userAccessLevel=%d\n", p->userAccessLevel);
  816. printf("\t.arrayDimensionsSize=%d\n", p->arrayDimensionsSize);
  817. printf("\t.minimumSamplingInterval=%f\n", p->minimumSamplingInterval);
  818. printf("\t.historizing=%d\n", p->historizing);
  819. printf("\t----- UA_Variant ----- \n");
  820. printf("\t.value.type.name=%s\n", p->value.vt->name);
  821. printf("\t.value.array.length=%d\n", p->value.arrayLength);
  822. UA_Int32 i;
  823. for (i=0;i<p->value.arrayLength || (p->value.arrayLength==-1 && i==0);++i) {
  824. printf("\t.value.array.element[%d]=%p", i, (p->value.data == UA_NULL ? UA_NULL : p->value.data[i]));
  825. switch (p->value.vt->ns0Id) {
  826. case UA_LOCALIZEDTEXT_NS0: {
  827. if (p->value.data != UA_NULL) {
  828. UA_LocalizedText* ltp = (UA_LocalizedText*) p->value.data[i];
  829. printf(",enc=%d,locale={%d,{%.*s}},text={%d,{%.*s}}",ltp->encodingMask,ltp->locale.length,ltp->locale.length,ltp->locale.data,ltp->text.length,ltp->text.length,ltp->text.data);
  830. }
  831. }
  832. break;
  833. case UA_EXTENSIONOBJECT_NS0: {
  834. if (p->value.data != UA_NULL) {
  835. UA_ExtensionObject* eo = (UA_ExtensionObject*) p->value.data[i];
  836. if (eo == UA_NULL) {
  837. printf(",(null)");
  838. } else {
  839. printf(",enc=%d,typeId={i=%d}",eo->encoding,eo->typeId.identifier.numeric);
  840. }
  841. }
  842. }
  843. break;
  844. default:
  845. break;
  846. }
  847. printf("\n");
  848. }
  849. }
  850. break;
  851. // case UA_NODECLASS_DATATYPE:
  852. default:
  853. break;
  854. }
  855. }
  856. }
  857. UA_Int32 UA_NodeSetAlias_decodeXML(XML_Stack* s, XML_Attr* attr, UA_NodeSetAlias* dst, _Bool isStart) {
  858. DBG_VERBOSE(printf("UA_NodeSetAlias entered with dst=%p,isStart=%d\n", (void* ) dst, isStart));
  859. if (isStart) {
  860. // create if necessary
  861. if (dst == UA_NULL) {
  862. UA_NodeSetAlias_new(&dst);
  863. s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst;
  864. }
  865. // set handlers
  866. s->parent[s->depth].len = 0;
  867. XML_Stack_addChildHandler(s, "Alias", strlen("Alias"), (XML_decoder) UA_String_decodeXML, UA_STRING, &(dst->alias));
  868. XML_Stack_addChildHandler(s, "Value", strlen("Value"), (XML_decoder) UA_String_decodeXML, UA_STRING, &(dst->value));
  869. XML_Stack_handleTextAsElementOf(s, "Data", 1);
  870. // set attributes
  871. UA_Int32 i;
  872. for (i = 0; attr[i]; i += 2) {
  873. if (0 == strncmp("Alias", attr[i], strlen("Alias"))) {
  874. UA_String_copycstring(attr[i + 1], &(dst->alias));
  875. } else if (0 == strncmp("Value", attr[i], strlen("Value"))) {
  876. UA_String_copycstring(attr[i + 1], &(dst->value));
  877. } else {
  878. DBG_ERR(XML_Stack_print(s));DBG_ERR(printf("%s - unknown attribute\n", attr[i]));
  879. }
  880. }
  881. }
  882. return UA_SUCCESS;
  883. }
  884. UA_Int32 UA_NodeSetAliases_decodeXML(XML_Stack* s, XML_Attr* attr, UA_NodeSetAliases* dst, _Bool isStart) {
  885. DBG_VERBOSE(printf("UA_NodeSetALiases entered with dst=%p,isStart=%d\n", (void* ) dst, isStart));
  886. if (isStart) {
  887. if (dst == UA_NULL) {
  888. UA_NodeSetAliases_new(&dst);
  889. s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst;
  890. }
  891. s->parent[s->depth].len = 0;
  892. XML_Stack_addChildHandler(s, "Alias", strlen("Alias"), (XML_decoder) UA_NodeSetAlias_decodeXML, UA_INVALIDTYPE, UA_NULL);
  893. } else {
  894. // sub element is ready, add to array
  895. if (dst->size < 0 || dst->size == 0) {
  896. dst->size = 1;
  897. UA_alloc((void** )&(dst->aliases), dst->size * sizeof(UA_NodeSetAlias*));
  898. DBG_VERBOSE(
  899. printf("allocate aliases:dst=%p, aliases=%p, size=%d\n", (void* )dst, (void* )(dst->aliases),
  900. dst->size));
  901. } else {
  902. dst->size++;
  903. dst->aliases = realloc(dst->aliases, dst->size * sizeof(UA_NodeSetAlias*));
  904. DBG_VERBOSE(
  905. printf("reallocate aliases:dst=%p, aliases=%p, size=%d\n", (void* )dst, (void* )(dst->aliases),
  906. dst->size));
  907. }
  908. // index starts with 0, therefore size-1
  909. DBG_VERBOSE(printf("assign alias:dst=%p, src=%p\n", (void* )dst->aliases[dst->size - 1], (void* )attr));
  910. dst->aliases[dst->size - 1] = (UA_NodeSetAlias*) attr;
  911. DBG_VERBOSE(printf("UA_NodeSetAliases clears %p\n", (void* ) (s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj)));
  912. s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = UA_NULL;
  913. }
  914. return UA_SUCCESS;
  915. }
  916. UA_Int32 UA_NodeSet_decodeXML(XML_Stack* s, XML_Attr* attr, UA_NodeSet* dst, _Bool isStart) {
  917. DBG_VERBOSE(printf("UA_NodeSet entered with dst=%p,isStart=%d\n", (void* ) dst, isStart));
  918. if (isStart) {
  919. if (dst == UA_NULL) {
  920. UA_NodeSet_new(&dst, s->nsid);
  921. s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst;
  922. }
  923. s->parent[s->depth].len = 0;
  924. XML_Stack_addChildHandler(s, "Aliases", strlen("Aliases"), (XML_decoder) UA_NodeSetAliases_decodeXML, UA_INVALIDTYPE,
  925. &(dst->aliases));
  926. XML_Stack_addChildHandler(s, "UADataType", strlen("UADataType"), (XML_decoder) UA_DataTypeNode_decodeXML, UA_DATATYPENODE, UA_NULL);
  927. XML_Stack_addChildHandler(s, "UAVariableType", strlen("UAVariableType"), (XML_decoder) UA_VariableTypeNode_decodeXML, UA_VARIABLETYPENODE, UA_NULL);
  928. XML_Stack_addChildHandler(s, "UAVariable", strlen("UAVariable"), (XML_decoder) UA_VariableNode_decodeXML, UA_VARIABLENODE, UA_NULL);
  929. XML_Stack_addChildHandler(s, "UAObjectType", strlen("UAObjectType"), (XML_decoder) UA_ObjectTypeNode_decodeXML, UA_OBJECTTYPENODE, UA_NULL);
  930. XML_Stack_addChildHandler(s, "UAObject", strlen("UAObject"), (XML_decoder) UA_ObjectNode_decodeXML, UA_OBJECTNODE, UA_NULL);
  931. } else {
  932. if (s->parent[s->depth - 1].activeChild == 0 && attr != UA_NULL) {
  933. UA_NodeSetAliases* aliases = (UA_NodeSetAliases*) attr;
  934. DBG(printf("UA_NodeSet_decodeXML - finished aliases: aliases=%p, size=%d\n",(void*)aliases,(aliases==UA_NULL)?-1:aliases->size));
  935. s->aliases = aliases;
  936. s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = UA_NULL;
  937. } else {
  938. UA_Node* node = (UA_Node*) attr;
  939. DBG(printf("UA_NodeSet_decodeXML - finished node: node=%p\n", (void* )node));
  940. Namespace_insert(dst->ns, node);
  941. DBG(printf("UA_NodeSet_decodeXML - Inserting "));
  942. DBG(print_node(node));
  943. s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = UA_NULL;
  944. }
  945. }
  946. return UA_SUCCESS;
  947. }
  948. /** lookup if element is a known child of parent, if yes go for it otherwise ignore */
  949. void XML_Stack_startElement(void * data, const char *el, const char **attr) {
  950. XML_Stack* s = (XML_Stack*) data;
  951. int i;
  952. // scan expected children
  953. XML_Parent* cp = &s->parent[s->depth];
  954. for (i = 0; i < cp->len; i++) {
  955. if (0 == strncmp(cp->children[i].name, el, cp->children[i].length)) {
  956. DBG_VERBOSE(XML_Stack_print(s));
  957. DBG_VERBOSE(printf("%s - processing\n", el));
  958. cp->activeChild = i;
  959. s->depth++;
  960. s->parent[s->depth].name = el;
  961. s->parent[s->depth].len = 0;
  962. s->parent[s->depth].textAttribIdx = -1;
  963. s->parent[s->depth].activeChild = -1;
  964. // finally call the elementHandler and return
  965. cp->children[i].elementHandler(data, attr, cp->children[i].obj, TRUE);
  966. return;
  967. }
  968. }
  969. // if we come here we rejected the processing of el
  970. DBG_VERBOSE(XML_Stack_print(s));
  971. DBG_VERBOSE(printf("%s - rejected\n", el));
  972. s->depth++;
  973. s->parent[s->depth].name = el;
  974. // this should be sufficient to reject the children as well
  975. s->parent[s->depth].len = 0;
  976. }
  977. UA_Int32 XML_isSpace(cstring s, int len) {
  978. int i;
  979. for (i = 0; i < len; i++) {
  980. if (!isspace(s[i])) {
  981. return UA_FALSE;
  982. }
  983. }
  984. return UA_TRUE;
  985. }
  986. /* gather text */
  987. void XML_Stack_handleText(void * data, const char *txt, int len) {
  988. XML_Stack* s = (XML_Stack*) data;
  989. if (len > 0 && !XML_isSpace(txt, len)) {
  990. XML_Parent* cp = &(s->parent[s->depth]); // determine current element
  991. UA_ByteString src = { len+1, (UA_Byte*) txt };
  992. UA_ByteString *dst;
  993. UA_ByteString_new(&dst); // alloc dst
  994. UA_ByteString_copy(&src,dst); // alloc dst->data and copy txt
  995. dst->data[len] = 0; // add terminating zero to handle single line efficiently
  996. UA_list_addPayloadToBack(&(cp->textGatherList), (void*) dst);
  997. if (cp->totalGatherLength == -1) {
  998. cp->totalGatherLength = len;
  999. } else {
  1000. cp->totalGatherLength += len;
  1001. }
  1002. }
  1003. }
  1004. char* theGatherBuffer;
  1005. void textGatherListTotalLength(void* payload) {
  1006. UA_ByteString* b = (UA_ByteString*) payload;
  1007. UA_ByteString_printf("\t",b);
  1008. UA_memcpy(theGatherBuffer,b->data,b->length-1); // remove trailing zero
  1009. theGatherBuffer += (b->length-1);
  1010. }
  1011. /** if we are an activeChild of a parent we call the child-handler */
  1012. void XML_Stack_endElement(void *data, const char *el) {
  1013. XML_Stack* s = (XML_Stack*) data;
  1014. XML_Parent* ce = &(s->parent[s->depth]);
  1015. if (ce->textAttribIdx >= 0 && ce->totalGatherLength > 0 ) {
  1016. ce->activeChild = ce->textAttribIdx;
  1017. char* buf;
  1018. if (UA_list_getFirst(&(ce->textGatherList)) == UA_list_getLast(&(ce->textGatherList)) ) {
  1019. buf = (char*) ((UA_ByteString*) UA_list_getFirst(&(ce->textGatherList))->payload)->data;
  1020. } else {
  1021. printf("XML_Stack_endElement - more than one text snippet with total length=%d:\n",ce->totalGatherLength);
  1022. UA_alloc((void**)&theGatherBuffer,ce->totalGatherLength+1);
  1023. buf = theGatherBuffer;
  1024. UA_list_iteratePayload(&(ce->textGatherList), textGatherListTotalLength);
  1025. buf[ce->totalGatherLength] = 0;
  1026. printf("XML_Stack_endElement - gatherBuffer %s:\n",buf);
  1027. }
  1028. XML_Attr attr[3] = { ce->textAttrib, buf, UA_NULL };
  1029. DBG(printf("handleText @ %s calls start elementHandler %s with dst=%p, buf={%s}\n", XML_Stack_path(s),ce->children[ce->activeChild].name, ce->children[ce->activeChild].obj, buf));
  1030. ce->children[ce->activeChild].elementHandler(s, attr, ce->children[ce->activeChild].obj, TRUE);
  1031. if (s->parent[s->depth-1].activeChild > 0) {
  1032. XML_child* c = &(s->parent[s->depth-1].children[s->parent[s->depth-1].activeChild]);
  1033. c->elementHandler(s, UA_NULL, c->obj, FALSE);
  1034. }
  1035. if (UA_list_getFirst(&(ce->textGatherList)) != UA_list_getLast(&(ce->textGatherList)) ) {
  1036. UA_free(buf);
  1037. }
  1038. UA_list_destroy(&(ce->textGatherList),(UA_list_PayloadVisitor) UA_ByteString_delete);
  1039. UA_list_init(&(ce->textGatherList)); // don't know if destroy leaves the list in usable state...
  1040. ce->totalGatherLength = -1;
  1041. }
  1042. // the parent of the parent (pop) of the element knows the elementHandler, therefore depth-2!
  1043. if (s->depth > 1) {
  1044. // inform parents elementHandler that everything is done
  1045. XML_Parent* cp = &(s->parent[s->depth - 1]);
  1046. XML_Parent* cpp = &(s->parent[s->depth - 2]);
  1047. if (cpp->activeChild >= 0 && cp->activeChild >= 0) {
  1048. DBG_VERBOSE(XML_Stack_print(s));
  1049. DBG_VERBOSE(
  1050. printf(" - inform pop %s, arg=%p\n", cpp->children[cpp->activeChild].name,
  1051. (void* ) cp->children[cp->activeChild].obj));
  1052. cpp->children[cpp->activeChild].elementHandler(s, (XML_Attr*) cp->children[cp->activeChild].obj,
  1053. cpp->children[cpp->activeChild].obj, FALSE);
  1054. }
  1055. // reset
  1056. cp->activeChild = -1;
  1057. }
  1058. s->depth--;
  1059. }
  1060. typedef UA_Int32 (*XML_Stack_Loader) (char* buf, int len);
  1061. #define XML_BUFFER_LEN 1024
  1062. UA_Int32 Namespace_loadXml(Namespace **ns,UA_UInt32 nsid,const char* rootName, XML_Stack_Loader getNextBufferFull) {
  1063. UA_Int32 retval = UA_SUCCESS;
  1064. char buf[XML_BUFFER_LEN];
  1065. int len; /* len is the number of bytes in the current bufferful of data */
  1066. XML_Stack s;
  1067. XML_Stack_init(&s, nsid, rootName);
  1068. UA_NodeSet n;
  1069. UA_NodeSet_init(&n, 0);
  1070. *ns = n.ns;
  1071. XML_Stack_addChildHandler(&s, "UANodeSet", strlen("UANodeSet"), (XML_decoder) UA_NodeSet_decodeXML, UA_INVALIDTYPE, &n);
  1072. XML_Parser parser = XML_ParserCreate(NULL);
  1073. XML_SetUserData(parser, &s);
  1074. XML_SetElementHandler(parser, XML_Stack_startElement, XML_Stack_endElement);
  1075. XML_SetCharacterDataHandler(parser, XML_Stack_handleText);
  1076. while ((len = getNextBufferFull(buf, XML_BUFFER_LEN)) > 0) {
  1077. if (XML_Parse(parser, buf, len, (len < XML_BUFFER_LEN)) == XML_STATUS_ERROR) {
  1078. retval = UA_ERR_INVALID_VALUE;
  1079. break;
  1080. }
  1081. }
  1082. XML_ParserFree(parser);
  1083. DBG_VERBOSE(printf("Namespace_loadXml - aliases addr=%p, size=%d\n", (void*) &(n.aliases), n.aliases.size));
  1084. DBG_VERBOSE(UA_NodeSetAliases_println("Namespace_loadXml - elements=", &n.aliases));
  1085. return retval;
  1086. }
  1087. static int theFile = 0;
  1088. UA_Int32 readFromTheFile(char*buf,int len) {
  1089. return read(theFile,buf,len);
  1090. }
  1091. UA_Int32 Namespace_loadFromFile(Namespace **ns,UA_UInt32 nsid,const char* rootName,const char* fileName) {
  1092. if (fileName == UA_NULL)
  1093. theFile = 0; // stdin
  1094. else if ((theFile = open(fileName, O_RDONLY)) == -1)
  1095. return UA_ERR_INVALID_VALUE;
  1096. UA_Int32 retval = Namespace_loadXml(ns,nsid,rootName,readFromTheFile);
  1097. close(theFile);
  1098. return retval;
  1099. }
  1100. static const char* theBuffer = UA_NULL;
  1101. static const char* theBufferEnd = UA_NULL;
  1102. UA_Int32 readFromTheBuffer(char*buf,int len) {
  1103. if (len == 0) return 0;
  1104. if (theBuffer + XML_BUFFER_LEN > theBufferEnd)
  1105. len = theBufferEnd - theBuffer + 1;
  1106. else
  1107. len = XML_BUFFER_LEN;
  1108. memcpy(buf,theBuffer,len);
  1109. theBuffer = theBuffer + len;
  1110. return len;
  1111. }
  1112. UA_Int32 Namespace_loadFromString(Namespace **ns,UA_UInt32 nsid,const char* rootName,const char* buffer) {
  1113. theBuffer = buffer;
  1114. theBufferEnd = buffer + strlen(buffer) - 1;
  1115. return Namespace_loadXml(ns,nsid,rootName,readFromTheBuffer);
  1116. }