123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334 |
- /*
- * xml2ns0.c
- *
- * Created on: 21.04.2014
- * Author: mrt
- */
- #include <expat.h>
- #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, _Bool isStart);
- typedef struct XML_child {
- cstring_t name;
- UA_Int32 type;
- XML_decoder elementHandler;
- void* obj;
- } XML_child_t;
- 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;
- typedef struct XML_Stack {
- int depth;
- XML_Parent_t parent[10];
- } XML_Stack_t;
- void XML_Stack_init(XML_Stack_t* p, cstring_t name) {
- unsigned int i,j;
- p->depth = 0;
- 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].elementHandler = UA_NULL;
- p->parent[i].children[j].type = UA_INVALIDTYPE;
- p->parent[i].children[j].obj = UA_NULL;
- }
- }
- p->parent[0].name = name;
- }
- void XML_Stack_print(XML_Stack_t* s) {
- UA_Int32 i;
- for (i=0;i<=s->depth;i++) {
- printf("%s.",s->parent[i].name);
- }
- }
- // FIXME: we might want to calculate textAttribIdx
- void XML_Stack_handleTextAs(XML_Stack_t* p,cstring_t textAttrib, unsigned int textAttribIdx) {
- p->parent[p->depth].textAttrib = textAttrib;
- p->parent[p->depth].textAttribIdx = textAttribIdx;
- }
- 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].elementHandler = handler;
- p->parent[p->depth].children[len].type = type;
- p->parent[p->depth].children[len].obj = dst;
- p->parent[p->depth].len++;
- }
- UA_Int32 UA_NodeId_copycstring(cstring_t src,UA_NodeId* dst) {
- dst->encodingByte = UA_NODEIDTYPE_FOURBYTE;
- dst->namespace = 0;
- // FIXME: assumes i=nnnn, does not care for aliases as of now
- dst->identifier.numeric = atoi(&src[2]);
- return UA_SUCCESS;
- }
- typedef struct T_UA_NodeSet { int dummy; } UA_NodeSet;
- 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, _Bool isStart) {
- if (isStart) {
- if (dst == UA_NULL) { UA_Int32_new(&dst); }
- *dst = atoi(attr[1]);
- }
- return UA_SUCCESS;
- }
- UA_Int32 UA_String_decodeXML(XML_Stack_t* s, XML_Attr_t* attr, UA_String* dst, _Bool isStart) {
- UA_UInt32 i;
- if (isStart) {
- if (dst == UA_NULL) { UA_String_new(&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, _Bool isStart) {
- UA_UInt32 i;
- if (isStart) {
- if (dst == UA_NULL) {
- UA_LocalizedText_new(&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("Text"))) {
- UA_String_copycstring(attr[i+1],&(dst->text));
- dst->encodingMask |= UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT;
- } else if (0==strncmp("Locale",attr[i],strlen("Locale"))) {
- 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, _Bool isStart) {
- UA_UInt32 i;
- if (isStart) {
- // create a new object if called with UA_NULL
- if (dst == UA_NULL) {
- UA_DataTypeNode_new(&dst);
- s->parent[s->depth-1].children[s->parent[s->depth-1].activeChild].obj = (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));
- }
- // set missing default 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 {
- DBG_ERR(XML_Stack_print(s));
- DBG_ERR(printf("%s - unknown attribute\n",attr[i]));
- }
- }
- }
- return UA_SUCCESS;
- }
- 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 ) {
- // FIXME: add the other node types as well
- XML_Stack_addChildHandler(s,"UADataType",(XML_decoder)UA_DataTypeNode_decodeXML, UA_DATATYPENODE, UA_NULL);
- }
- } else {
- // FIXME: mockup code for debugging, should actually add node to namespace
- if (attr != UA_NULL) {
- UA_DataTypeNode* dtn = (UA_DataTypeNode*) attr;
- printf("node.browseName=%.*s\n", dtn->browseName.name.length, dtn->browseName.name.data);
- } else {
- DBG_ERR(printf("nodeset endElement called with null-ptr\n"));
- }
- }
- return UA_SUCCESS;
- }
- /** lookup if element is a known child of parent, if yes go for it otherwise ignore */
- void startElement(void * data, const char *el, const char **attr) {
- XML_Stack_t* s = (XML_Stack_t*) data;
- int i;
- // scan expected children
- XML_Parent_t* cp = &s->parent[s->depth];
- for (i = 0; i < cp->len; i++) {
- if (0 == strncmp(cp->children[i].name,el,strlen(cp->children[i].name))) {
- DBG_VERBOSE(XML_Stack_print(s));
- DBG_VERBOSE(printf("%s - processing\n",el));
- cp->activeChild = i;
- s->depth++;
- s->parent[s->depth].name = el;
- s->parent[s->depth].len = 0;
- s->parent[s->depth].textAttribIdx = -1;
- // finally call the elementHandler and return
- cp->children[i].elementHandler(data,attr,cp->children[i].obj, TRUE);
- return;
- }
- }
- // if we come here we rejected the processing of el
- DBG_VERBOSE(XML_Stack_print(s));
- DBG_VERBOSE(printf("%s - rejected\n",el));
- s->depth++;
- s->parent[s->depth].name = el;
- // this should be sufficient to reject the children as well
- s->parent[s->depth].len = 0;
- }
- UA_Int32 XML_isSpace(cstring_t s, int len) {
- int i;
- for (i=0; i<len; i++) {
- if (! isspace(s[i])) {
- return UA_FALSE;
- }
- }
- return UA_TRUE;
- }
- /* simulates startElement, endElement behaviour */
- void handleText(void * data, const char *txt, int len) {
- XML_Stack_t* s = (XML_Stack_t*) data;
- if (len > 0 && ! XML_isSpace(txt,len)) {
- XML_Parent_t* cp = &(s->parent[s->depth]);
- if (cp->textAttribIdx >= 0) {
- cp->activeChild = cp->textAttribIdx;
- char* buf; // need to copy txt to add 0 as string terminator
- UA_alloc((void**)&buf,len+1);
- strncpy(buf,txt,len);
- buf[len] = 0;
- XML_Attr_t attr[3] = { cp->textAttrib, buf, UA_NULL };
- cp->children[cp->activeChild].elementHandler(s,attr,cp->children[cp->activeChild].obj, TRUE);
- cp->children[cp->activeChild].elementHandler(s,UA_NULL,cp->children[cp->activeChild].obj, FALSE);
- UA_free(buf);
- } else {
- DBG_ERR(XML_Stack_print(s));
- DBG_ERR(printf("textData - ignore text data '%.*s'\n",len,txt));
- }
- }
- }
- /** if we are an activeChild of a parent we call the child-handler */
- void endElement(void *data, const char *el) {
- XML_Stack_t* s = (XML_Stack_t*) data;
- // the parent knows the elementHandler, therefore depth-1 !
- if (s->depth>1) {
- // inform parents elementHandler that everything is done
- XML_Parent_t* cp = &(s->parent[s->depth-1]);
- XML_Parent_t* cpp = &(s->parent[s->depth-2]);
- if (cpp->activeChild >= 0 && cp->activeChild >= 0) {
- DBG_VERBOSE(XML_Stack_print(s));
- DBG_VERBOSE(printf(" - inform parent %s\n", cpp->children[cpp->activeChild].name));
- cpp->children[cpp->activeChild].elementHandler(s,(XML_Attr_t*)cp->children[cp->activeChild].obj,cpp->children[cpp->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 */
- XML_Stack_t s;
- XML_Stack_init(&s, "ROOT");
- XML_Stack_addChildHandler(&s,"UANodeSet", (XML_decoder) UA_NodeSet_decodeXML, UA_INVALIDTYPE, UA_NULL);
- XML_Parser parser = XML_ParserCreate(NULL);
- XML_SetUserData(parser, &s);
- XML_SetElementHandler(parser, startElement, endElement);
- XML_SetCharacterDataHandler(parser, handleText);
- while ((len = read(0,buf,1024)) > 0) {
- if (!XML_Parse(parser, buf, len, (len<1024))) {
- return 1;
- }
- }
- XML_ParserFree(parser);
- return 0;
- }
|