|
@@ -9,19 +9,23 @@
|
|
|
#include <stdio.h>
|
|
|
#include <stdlib.h>
|
|
|
#include <string.h> // strlen
|
|
|
+#include <ctype.h> // isspace
|
|
|
+#include <unistd.h> // read
|
|
|
|
|
|
#include "opcua.h"
|
|
|
+#include "ua_namespace.h"
|
|
|
|
|
|
|
|
|
typedef char const * const XML_Attr_t;
|
|
|
typedef char const * cstring_t;
|
|
|
struct XML_Stack;
|
|
|
-typedef UA_Int32 (*XML_decoder)(struct XML_Stack* s, XML_Attr_t* attr, void* dst);
|
|
|
+
|
|
|
+typedef UA_Int32 (*XML_decoder)(struct XML_Stack* s, XML_Attr_t* attr, void* dst, _Bool isStart);
|
|
|
|
|
|
typedef struct XML_child {
|
|
|
cstring_t name;
|
|
|
UA_Int32 type;
|
|
|
- XML_decoder handler;
|
|
|
+ XML_decoder elementHandler;
|
|
|
void* obj;
|
|
|
} XML_child_t;
|
|
|
|
|
@@ -29,6 +33,7 @@ typedef struct XML_Parent {
|
|
|
cstring_t name;
|
|
|
int textAttribIdx; // -1 - not set
|
|
|
cstring_t textAttrib;
|
|
|
+ int activeChild; // -1 - no active child
|
|
|
int len; // -1 - empty set
|
|
|
XML_child_t children[20];
|
|
|
} XML_Parent_t;
|
|
@@ -44,11 +49,12 @@ void XML_Stack_init(XML_Stack_t* p, cstring_t name) {
|
|
|
for (i=0;i<10;i++) {
|
|
|
p->parent[i].name = UA_NULL;
|
|
|
p->parent[i].len = 0;
|
|
|
+ p->parent[i].activeChild = -1;
|
|
|
p->parent[i].textAttrib = UA_NULL;
|
|
|
p->parent[i].textAttribIdx = -1;
|
|
|
for (j=0;j<20;j++) {
|
|
|
p->parent[i].children[j].name = UA_NULL;
|
|
|
- p->parent[i].children[j].handler = UA_NULL;
|
|
|
+ p->parent[i].children[j].elementHandler = UA_NULL;
|
|
|
p->parent[i].children[j].type = UA_INVALIDTYPE;
|
|
|
p->parent[i].children[j].obj = UA_NULL;
|
|
|
}
|
|
@@ -65,7 +71,7 @@ void XML_Stack_handleTextAs(XML_Stack_t* p,cstring_t textAttrib, unsigned int te
|
|
|
void XML_Stack_addChildHandler(XML_Stack_t* p,cstring_t name,XML_decoder handler, UA_Int32 type, void* dst) {
|
|
|
unsigned int len = p->parent[p->depth].len;
|
|
|
p->parent[p->depth].children[len].name = name;
|
|
|
- p->parent[p->depth].children[len].handler = handler;
|
|
|
+ p->parent[p->depth].children[len].elementHandler = handler;
|
|
|
p->parent[p->depth].children[len].type = type;
|
|
|
p->parent[p->depth].children[len].obj = dst;
|
|
|
p->parent[p->depth].len++;
|
|
@@ -82,87 +88,124 @@ UA_Int32 UA_NodeId_copycstring(cstring_t src,UA_NodeId* dst) {
|
|
|
|
|
|
typedef struct T_UA_NodeSet { int dummy; } UA_NodeSet;
|
|
|
|
|
|
-UA_Int32 UA_Array_decodeXML(XML_Stack_t* s, XML_Attr_t* attr, void* dst) {
|
|
|
- UA_UInt32 i;
|
|
|
+UA_Int32 UA_Array_decodeXML(XML_Stack_t* s, XML_Attr_t* attr, void* dst, _Bool isStart) {
|
|
|
+ // FIXME: Implement
|
|
|
return UA_SUCCESS;
|
|
|
}
|
|
|
|
|
|
-UA_Int32 UA_Int32_decodeXML(XML_Stack_t* s, XML_Attr_t* attr, UA_Int32* dst) {
|
|
|
- UA_UInt32 i;
|
|
|
- if (dst == UA_NULL) { UA_[UA_INT32].new((void**) &dst); }
|
|
|
+UA_Int32 UA_Int32_decodeXML(XML_Stack_t* s, XML_Attr_t* attr, UA_Int32* dst, _Bool isStart) {
|
|
|
+ if (isStart) {
|
|
|
+ if (dst == UA_NULL) { UA_Int32_new((void**) &dst); }
|
|
|
+ *dst = atoi(attr[1]);
|
|
|
+ }
|
|
|
return UA_SUCCESS;
|
|
|
}
|
|
|
|
|
|
-UA_Int32 UA_String_decodeXML(XML_Stack_t* s, XML_Attr_t* attr, UA_String* dst) {
|
|
|
+UA_Int32 UA_String_decodeXML(XML_Stack_t* s, XML_Attr_t* attr, UA_String* dst, _Bool isStart) {
|
|
|
UA_UInt32 i;
|
|
|
- if (dst == UA_NULL) { UA_[UA_STRING].new((void**) &dst); }
|
|
|
- if (s->parent[s->depth].len == 0 ) {
|
|
|
- XML_Stack_addChildHandler(s,"Data",(XML_decoder)UA_Array_decodeXML, UA_BYTE, &(dst->data));
|
|
|
- XML_Stack_addChildHandler(s,"Length",(XML_decoder)UA_Int32_decodeXML, UA_INT32, &(dst->length));
|
|
|
- XML_Stack_handleTextAs(s,"Data",0);
|
|
|
- }
|
|
|
- // set attributes
|
|
|
- for (i = 0; attr[i]; i += 2) {
|
|
|
- if (0==strncmp("Data",attr[i],strlen("Data"))) {
|
|
|
- UA_String_copycstring(attr[i+1],dst);
|
|
|
- } else {
|
|
|
- perror("Unknown attribute");
|
|
|
+ if (isStart) {
|
|
|
+ if (dst == UA_NULL) { UA_String_new((void**) &dst); }
|
|
|
+ if (s->parent[s->depth].len == 0 ) {
|
|
|
+ XML_Stack_addChildHandler(s,"Data",(XML_decoder)UA_Array_decodeXML, UA_BYTE, &(dst->data));
|
|
|
+ XML_Stack_addChildHandler(s,"Length",(XML_decoder)UA_Int32_decodeXML, UA_INT32, &(dst->length));
|
|
|
+ XML_Stack_handleTextAs(s,"Data",0);
|
|
|
+ }
|
|
|
+ // set attributes
|
|
|
+ for (i = 0; attr[i]; i += 2) {
|
|
|
+ if (0==strncmp("Data",attr[i],strlen("Data"))) {
|
|
|
+ UA_String_copycstring(attr[i+1],dst);
|
|
|
+ } else {
|
|
|
+ perror("Unknown attribute");
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
return UA_SUCCESS;
|
|
|
}
|
|
|
|
|
|
-UA_Int32 UA_LocalizedText_decodeXML(XML_Stack_t* s, XML_Attr_t* attr, UA_LocalizedText* dst) {
|
|
|
+UA_Int32 UA_LocalizedText_decodeXML(XML_Stack_t* s, XML_Attr_t* attr, UA_LocalizedText* dst, _Bool isStart) {
|
|
|
UA_UInt32 i;
|
|
|
- // create a new object if called with UA_NULL
|
|
|
- if (dst == UA_NULL) { UA_[UA_LOCALIZEDTEXT].new((void**) &dst); }
|
|
|
- if (s->parent[s->depth].len == 0 ) {
|
|
|
- XML_Stack_addChildHandler(s,"Text",(XML_decoder)UA_String_decodeXML, UA_STRING, &(dst->text));
|
|
|
- XML_Stack_addChildHandler(s,"Locale",(XML_decoder)UA_String_decodeXML, UA_STRING, &(dst->locale));
|
|
|
- XML_Stack_handleTextAs(s,"Data",0);
|
|
|
+ if (isStart) {
|
|
|
+ if (dst == UA_NULL) {
|
|
|
+ UA_LocalizedText_new((void**) &dst);
|
|
|
+ }
|
|
|
+ if (s->parent[s->depth].len == 0 ) {
|
|
|
+ XML_Stack_addChildHandler(s,"Text",(XML_decoder)UA_String_decodeXML, UA_STRING, &(dst->text));
|
|
|
+ XML_Stack_addChildHandler(s,"Locale",(XML_decoder)UA_String_decodeXML, UA_STRING, &(dst->locale));
|
|
|
+ XML_Stack_handleTextAs(s,"Data",0);
|
|
|
+ }
|
|
|
+ // set attributes
|
|
|
+ for (i = 0; attr[i]; i += 2) {
|
|
|
+ if (0==strncmp("Text",attr[i],strlen("Data"))) {
|
|
|
+ UA_String_copycstring(attr[i+1],&(dst->text));
|
|
|
+ dst->encodingMask |= UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT;
|
|
|
+ } else if (0==strncmp("Locale",attr[i],strlen("Data"))) {
|
|
|
+ UA_String_copycstring(attr[i+1],&(dst->locale));
|
|
|
+ dst->encodingMask |= UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_LOCALE;
|
|
|
+ } else {
|
|
|
+ perror("Unknown attribute");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ switch (s->parent[s->depth].activeChild) {
|
|
|
+ case 0:
|
|
|
+ dst->encodingMask |= UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT;
|
|
|
+ break;
|
|
|
+ case 1:
|
|
|
+ dst->encodingMask |= UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_LOCALE;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
}
|
|
|
return UA_SUCCESS;
|
|
|
}
|
|
|
|
|
|
-UA_Int32 UA_DataTypeNode_decodeXML(XML_Stack_t* s, XML_Attr_t* attr, UA_DataTypeNode* dst) {
|
|
|
+UA_Int32 UA_DataTypeNode_decodeXML(XML_Stack_t* s, XML_Attr_t* attr, UA_DataTypeNode* dst, _Bool isStart) {
|
|
|
UA_UInt32 i;
|
|
|
|
|
|
- // create a new object if called with UA_NULL
|
|
|
- if (dst == UA_NULL) { UA_[UA_DATATYPENODE].new((void**) &dst); }
|
|
|
+ if (isStart) {
|
|
|
+ // create a new object if called with UA_NULL
|
|
|
+ if (dst == UA_NULL) { UA_DataTypeNode_new((void**) &dst); }
|
|
|
|
|
|
- // add the handlers for the child objects
|
|
|
- if (s->parent[s->depth].len == 0 ) {
|
|
|
- XML_Stack_addChildHandler(s,"DisplayName",(XML_decoder)UA_LocalizedText_decodeXML, UA_LOCALIZEDTEXT, &(dst->displayName));
|
|
|
- XML_Stack_addChildHandler(s,"Description",(XML_decoder)UA_LocalizedText_decodeXML, UA_LOCALIZEDTEXT, &(dst->description));
|
|
|
- }
|
|
|
+ // add the handlers for the child objects
|
|
|
+ if (s->parent[s->depth].len == 0 ) {
|
|
|
+ XML_Stack_addChildHandler(s,"DisplayName",(XML_decoder)UA_LocalizedText_decodeXML, UA_LOCALIZEDTEXT, &(dst->displayName));
|
|
|
+ XML_Stack_addChildHandler(s,"Description",(XML_decoder)UA_LocalizedText_decodeXML, UA_LOCALIZEDTEXT, &(dst->description));
|
|
|
+ }
|
|
|
|
|
|
- // set missing but implicit attributes
|
|
|
- dst->nodeClass = UA_NODECLASS_DATATYPE;
|
|
|
-
|
|
|
- // set attributes
|
|
|
- for (i = 0; attr[i]; i += 2) {
|
|
|
- if (0==strncmp("NodeId",attr[i],strlen("NodeId"))) {
|
|
|
- UA_NodeId_copycstring(attr[i+1],&(dst->nodeId));
|
|
|
- } else if (0==strncmp("BrowseName",attr[i],strlen("BrowseName"))) {
|
|
|
- UA_String_copycstring(attr[i+1],&(dst->browseName.name));
|
|
|
- dst->browseName.namespaceIndex = 0;
|
|
|
-// } else if (0==strncmp("DisplayName",attr[i],strlen("DisplayName"))) {
|
|
|
-// UA_String_copycstring(attr[i+1],&(dst->displayName.text));
|
|
|
-// dst->displayName.encodingMask = UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT;
|
|
|
-// } else if (0==strncmp("Description",attr[i],strlen("Description"))) {
|
|
|
-// UA_String_copycstring(attr[i+1],&(dst->description.text));
|
|
|
-// dst->description.encodingMask = UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT;
|
|
|
- } else {
|
|
|
- perror("Unknown attribute");
|
|
|
+ // set missing but implicit attributes
|
|
|
+ dst->nodeClass = UA_NODECLASS_DATATYPE;
|
|
|
+
|
|
|
+ // set attributes
|
|
|
+ for (i = 0; attr[i]; i += 2) {
|
|
|
+ if (0==strncmp("NodeId",attr[i],strlen("NodeId"))) {
|
|
|
+ UA_NodeId_copycstring(attr[i+1],&(dst->nodeId));
|
|
|
+ } else if (0==strncmp("BrowseName",attr[i],strlen("BrowseName"))) {
|
|
|
+ UA_String_copycstring(attr[i+1],&(dst->browseName.name));
|
|
|
+ dst->browseName.namespaceIndex = 0;
|
|
|
+ } else if (0==strncmp("DisplayName",attr[i],strlen("DisplayName"))) {
|
|
|
+ UA_String_copycstring(attr[i+1],&(dst->displayName.text));
|
|
|
+ dst->displayName.encodingMask = UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT;
|
|
|
+ } else if (0==strncmp("Description",attr[i],strlen("Description"))) {
|
|
|
+ UA_String_copycstring(attr[i+1],&(dst->description.text));
|
|
|
+ dst->description.encodingMask = UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT;
|
|
|
+ } else {
|
|
|
+ perror("Unknown attribute");
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
return UA_SUCCESS;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
-UA_Int32 UA_NodeSet_decodeXML(XML_Stack_t* s, XML_Attr_t* attr, UA_NodeSet* dst) {
|
|
|
- if (s->parent[s->depth].len == 0 ) {
|
|
|
- XML_Stack_addChildHandler(s,"UADataType",(XML_decoder)UA_DataTypeNode_decodeXML, UA_DATATYPENODE, UA_NULL);
|
|
|
+UA_Int32 UA_NodeSet_decodeXML(XML_Stack_t* s, XML_Attr_t* attr, UA_NodeSet* dst, _Bool isStart) {
|
|
|
+ if (isStart) {
|
|
|
+ if (s->parent[s->depth].len == 0 ) {
|
|
|
+ XML_Stack_addChildHandler(s,"UADataType",(XML_decoder)UA_DataTypeNode_decodeXML, UA_DATATYPENODE, UA_NULL);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if (dst) {
|
|
|
+ // FIXME: add node to namespace
|
|
|
+ }
|
|
|
}
|
|
|
return UA_SUCCESS;
|
|
|
}
|
|
@@ -181,13 +224,15 @@ void startElement(void * data, const char *el, const char **attr) {
|
|
|
}
|
|
|
printf("%s\n",el);
|
|
|
|
|
|
+ cp->activeChild = i;
|
|
|
+
|
|
|
p->depth++;
|
|
|
p->parent[p->depth].name = el;
|
|
|
p->parent[p->depth].len = 0;
|
|
|
p->parent[p->depth].textAttribIdx = -1;
|
|
|
|
|
|
- // finally call the handler and return
|
|
|
- cp->children[i].handler(data,attr,cp->children[i].obj);
|
|
|
+ // finally call the elementHandler and return
|
|
|
+ cp->children[i].elementHandler(data,attr,cp->children[i].obj, TRUE);
|
|
|
return;
|
|
|
}
|
|
|
}
|
|
@@ -201,10 +246,9 @@ void startElement(void * data, const char *el, const char **attr) {
|
|
|
p->parent[p->depth].name = el;
|
|
|
// this should be sufficient to reject the children as well
|
|
|
p->parent[p->depth].len = 0;
|
|
|
-} /* End of start handler */
|
|
|
+}
|
|
|
|
|
|
UA_Int32 XML_isSpace(cstring_t s, int len) {
|
|
|
- UA_Int32 retval = UA_TRUE;
|
|
|
int i;
|
|
|
for (i=0; i<len; i++) {
|
|
|
if (! isspace(s[i])) {
|
|
@@ -216,33 +260,39 @@ UA_Int32 XML_isSpace(cstring_t s, int len) {
|
|
|
|
|
|
void handleText(void * data, const char *s, int len) {
|
|
|
XML_Stack_t* p = (XML_Stack_t*) data;
|
|
|
- int j, i;
|
|
|
|
|
|
if (len > 0 && ! XML_isSpace(s,len)) {
|
|
|
XML_Parent_t* cp = &(p->parent[p->depth]);
|
|
|
if (cp->textAttribIdx >= 0) {
|
|
|
- int childIdx = cp->textAttribIdx;
|
|
|
- char* buf; // need to copy s to add a 0 as terminator to string
|
|
|
+ cp->activeChild = cp->textAttribIdx;
|
|
|
+ char* buf; // need to copy s to add 0 as terminator to string
|
|
|
UA_alloc((void**)&buf,len+1);
|
|
|
strncpy(buf,s,len);
|
|
|
- buf[len+1] = 0;
|
|
|
+ buf[len] = 0;
|
|
|
XML_Attr_t attr[3] = { cp->textAttrib, buf, UA_NULL };
|
|
|
- cp->children[childIdx].handler(p,attr,cp->children[childIdx].obj);
|
|
|
+ cp->children[cp->activeChild].elementHandler(p,attr,cp->children[cp->activeChild].obj, TRUE);
|
|
|
UA_free(buf);
|
|
|
+ } else {
|
|
|
+ perror("ignore text data");
|
|
|
}
|
|
|
}
|
|
|
-} /* End of text handler */
|
|
|
+}
|
|
|
|
|
|
void endElement(void *data, const char *el) {
|
|
|
- XML_Stack_t* p = (XML_Stack_t*) data;
|
|
|
- p->depth--;
|
|
|
-} /* End of end handler */
|
|
|
+ XML_Stack_t* s = (XML_Stack_t*) data;
|
|
|
+ // the parent needs to know that we are finished, therefore depth-1 !
|
|
|
+ XML_Parent_t* cp = &(s->parent[s->depth-1]);
|
|
|
+ if (cp->activeChild >= 0) {
|
|
|
+ cp->children[cp->activeChild].elementHandler(s,UA_NULL,cp->children[cp->activeChild].obj, FALSE);
|
|
|
+ cp->activeChild = -1;
|
|
|
+ }
|
|
|
+ s->depth--;
|
|
|
+}
|
|
|
|
|
|
int main()
|
|
|
{
|
|
|
char buf[1024];
|
|
|
int len; /* len is the number of bytes in the current bufferful of data */
|
|
|
- int done;
|
|
|
XML_Stack_t p;
|
|
|
XML_Stack_init(&p, "ROOT");
|
|
|
XML_Stack_addChildHandler(&p,"UANodeSet", (XML_decoder) UA_NodeSet_decodeXML, UA_INVALIDTYPE, UA_NULL);
|