|
/***************************************************************************
|
|
$RCSfile$
|
|
-------------------
|
|
cvs : $Id$
|
|
begin : Fri Jul 04 2003
|
|
copyright : (C) 2003 by Martin Preuss
|
|
email : martin@libchipcard.de
|
|
|
|
***************************************************************************
|
|
* *
|
|
* This library is free software; you can redistribute it and/or *
|
|
* modify it under the terms of the GNU Lesser General Public *
|
|
* License as published by the Free Software Foundation; either *
|
|
* version 2.1 of the License, or (at your option) any later version. *
|
|
* *
|
|
* This library is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
|
* Lesser General Public License for more details. *
|
|
* *
|
|
* You should have received a copy of the GNU Lesser General Public *
|
|
* License along with this library; if not, write to the Free Software *
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
|
|
* MA 02111-1307 USA *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include <config.h>
|
|
#endif
|
|
|
|
|
|
#include <gwenhyfwar/gwenhyfwarapi.h>
|
|
#include <msgengine_p.h>
|
|
#include <gwenhyfwar/xml.h>
|
|
#include <gwenhyfwar/text.h>
|
|
#include <gwenhyfwar/misc.h>
|
|
#include <gwenhyfwar/path.h>
|
|
#include <gwenhyfwar/debug.h>
|
|
#include <gwenhyfwar/buffer.h>
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
|
|
|
|
|
|
GWEN_MSGENGINE *GWEN_MsgEngine_new(){
|
|
GWEN_MSGENGINE *e;
|
|
|
|
GWEN_NEW_OBJECT(GWEN_MSGENGINE, e);
|
|
e->charsToEscape=strdup(GWEN_MSGENGINE_CHARSTOESCAPE);
|
|
e->delimiters=strdup(GWEN_MSGENGINE_DEFAULT_DELIMITERS);
|
|
e->globalValues=GWEN_DB_Group_new("globalvalues");
|
|
return e;
|
|
}
|
|
|
|
|
|
void GWEN_MsgEngine_free(GWEN_MSGENGINE *e){
|
|
if (e) {
|
|
GWEN_XMLNode_free(e->defs);
|
|
free(e->charsToEscape);
|
|
free(e->secMode);
|
|
GWEN_DB_Group_free(e->globalValues);
|
|
}
|
|
}
|
|
|
|
|
|
void GWEN_MsgEngine_SetFormat(GWEN_MSGENGINE *e, GWEN_MSGENGINE_FORMAT f){
|
|
assert(e);
|
|
e->msgFormat=f;
|
|
}
|
|
|
|
|
|
|
|
GWEN_MSGENGINE_FORMAT GWEN_MsgEngine_GetFormat(GWEN_MSGENGINE *e){
|
|
assert(e);
|
|
return e->msgFormat;
|
|
}
|
|
|
|
|
|
|
|
void GWEN_MsgEngine_SetEscapeChar(GWEN_MSGENGINE *e, char c){
|
|
assert(e);
|
|
e->escapeChar=c;
|
|
}
|
|
|
|
|
|
|
|
char GWEN_MsgEngine_GetEscapeChar(GWEN_MSGENGINE *e){
|
|
assert(e);
|
|
return e->escapeChar;
|
|
}
|
|
|
|
|
|
|
|
void GWEN_MsgEngine_SetCharsToEscape(GWEN_MSGENGINE *e, const char *c){
|
|
assert(e);
|
|
free(e->charsToEscape);
|
|
e->charsToEscape=strdup(c);
|
|
}
|
|
|
|
|
|
|
|
const char *GWEN_MsgEngine_GetCharsToEscape(GWEN_MSGENGINE *e){
|
|
assert(e);
|
|
return e->charsToEscape;
|
|
}
|
|
|
|
|
|
|
|
void GWEN_MsgEngine_SetMode(GWEN_MSGENGINE *e, const char *mode){
|
|
assert(e);
|
|
free(e->secMode);
|
|
if (mode)
|
|
e->secMode=strdup(mode);
|
|
else
|
|
e->secMode=0;
|
|
}
|
|
|
|
|
|
const char *GWEN_MsgEngine_GetMode(GWEN_MSGENGINE *e){
|
|
assert(e);
|
|
return e->secMode;
|
|
}
|
|
|
|
|
|
|
|
|
|
unsigned int GWEN_MsgEngine_GetConfigMode(GWEN_MSGENGINE *e){
|
|
assert(e);
|
|
return e->cfgMode;
|
|
}
|
|
|
|
|
|
void GWEN_MsgEngine_SetConfigMode(GWEN_MSGENGINE *e, unsigned int m){
|
|
assert(e);
|
|
e->cfgMode=m;
|
|
}
|
|
|
|
|
|
GWEN_XMLNODE *GWEN_MsgEngine_GetDefinitions(GWEN_MSGENGINE *e){
|
|
assert(e);
|
|
return e->defs;
|
|
}
|
|
|
|
|
|
void GWEN_MsgEngine_SetDefinitions(GWEN_MSGENGINE *e, GWEN_XMLNODE *n){
|
|
assert(e);
|
|
GWEN_XMLNode_free(e->defs);
|
|
e->defs=n;
|
|
}
|
|
|
|
|
|
|
|
void GWEN_MsgEngine_SetTypeCheckFunction(GWEN_MSGENGINE *e,
|
|
GWEN_MSGENGINE_TYPECHECK_PTR p){
|
|
assert(e);
|
|
e->typeCheckPtr=p;
|
|
}
|
|
|
|
|
|
|
|
GWEN_MSGENGINE_TYPECHECK_PTR
|
|
GWEN_MsgEngine_GetTypeCheckFunction(GWEN_MSGENGINE *e){
|
|
assert(e);
|
|
return e->typeCheckPtr;
|
|
}
|
|
|
|
|
|
|
|
void GWEN_MsgEngine_SetTypeReadFunction(GWEN_MSGENGINE *e,
|
|
GWEN_MSGENGINE_TYPEREAD_PTR p){
|
|
assert(e);
|
|
e->typeReadPtr=p;
|
|
}
|
|
|
|
|
|
|
|
GWEN_MSGENGINE_TYPEREAD_PTR
|
|
GWEN_MsgEngine_GetTypeReadFunction(GWEN_MSGENGINE *e){
|
|
assert(e);
|
|
return e->typeReadPtr;
|
|
}
|
|
|
|
|
|
|
|
void GWEN_MsgEngine_SetTypeWriteFunction(GWEN_MSGENGINE *e,
|
|
GWEN_MSGENGINE_TYPEWRITE_PTR p){
|
|
assert(e);
|
|
e->typeWritePtr=p;
|
|
}
|
|
|
|
|
|
|
|
GWEN_MSGENGINE_TYPEWRITE_PTR
|
|
GWEN_MsgEngine_GetTypeWriteFunction(GWEN_MSGENGINE *e){
|
|
assert(e);
|
|
return e->typeWritePtr;
|
|
}
|
|
|
|
|
|
|
|
void GWEN_MsgEngine_SetBinTypeReadFunction(GWEN_MSGENGINE *e,
|
|
GWEN_MSGENGINE_BINTYPEREAD_PTR p){
|
|
assert(e);
|
|
e->binTypeReadPtr=p;
|
|
}
|
|
|
|
|
|
|
|
GWEN_MSGENGINE_BINTYPEREAD_PTR
|
|
GWEN_MsgEngine_GetBinTypeReadFunction(GWEN_MSGENGINE *e){
|
|
assert(e);
|
|
return e->binTypeReadPtr;
|
|
}
|
|
|
|
|
|
|
|
void
|
|
GWEN_MsgEngine_SetBinTypeWriteFunction(GWEN_MSGENGINE *e,
|
|
GWEN_MSGENGINE_BINTYPEWRITE_PTR p){
|
|
assert(e);
|
|
e->binTypeWritePtr=p;
|
|
}
|
|
|
|
|
|
|
|
GWEN_MSGENGINE_BINTYPEWRITE_PTR
|
|
GWEN_MsgEngine_GetBinTypeWriteFunction(GWEN_MSGENGINE *e){
|
|
assert(e);
|
|
return e->binTypeWritePtr;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void *GWEN_MsgEngine_GetInheritorData(GWEN_MSGENGINE *e){
|
|
assert(e);
|
|
return e->inheritorData;
|
|
}
|
|
|
|
|
|
|
|
void GWEN_MsgEngine_SetInheritorData(GWEN_MSGENGINE *e, void *d){
|
|
assert(e);
|
|
e->inheritorData=d;
|
|
}
|
|
|
|
|
|
|
|
int GWEN_MsgEngine__CheckValue(GWEN_MSGENGINE *e,
|
|
const char *value,
|
|
GWEN_XMLNODE *node,
|
|
char escapeChar) {
|
|
unsigned int len;
|
|
const char *p;
|
|
unsigned int minsize;
|
|
unsigned int maxsize;
|
|
const char *type;
|
|
int rv;
|
|
|
|
p=value;
|
|
len=0;
|
|
|
|
/* get some sizes */
|
|
minsize=atoi(GWEN_XMLNode_GetProperty(node, "minsize","0"));
|
|
maxsize=atoi(GWEN_XMLNode_GetProperty(node, "maxsize","0"));
|
|
type=GWEN_XMLNode_GetProperty(node, "type","ASCII");
|
|
|
|
rv=1;
|
|
if (e->typeCheckPtr) {
|
|
rv=e->typeCheckPtr(e,
|
|
value,
|
|
node,
|
|
escapeChar);
|
|
}
|
|
if (rv==-1){
|
|
DBG_INFO(0, "External type check failed");
|
|
return -1;
|
|
}
|
|
else if (rv==1) {
|
|
if (strcasecmp(type,"AN")==0) {
|
|
int lastWasEscape;
|
|
|
|
lastWasEscape=0;
|
|
while(*p) {
|
|
int c;
|
|
|
|
c=(unsigned char)*p;
|
|
if (c<32) {
|
|
DBG_ERROR(0, "Unescaped control character in value");
|
|
return -1;
|
|
}
|
|
if (lastWasEscape) {
|
|
lastWasEscape=0;
|
|
switch(c) {
|
|
case 'r': c='\r'; break;
|
|
case 'n': c='\n'; break;
|
|
case 'f': c='\f'; break;
|
|
case 't': c='\t'; break;
|
|
default: c=(unsigned char)*p;
|
|
} /* switch */
|
|
}
|
|
else {
|
|
if (*p==escapeChar) {
|
|
lastWasEscape=1;
|
|
len--;
|
|
c=-1;
|
|
}
|
|
else
|
|
c=(unsigned char)*p;
|
|
}
|
|
if (c!=-1) {
|
|
/* ugly workaround */
|
|
if (iscntrl(c)) {
|
|
DBG_ERROR(0, "Non-alphanumeric character in value");
|
|
return -1;
|
|
}
|
|
}
|
|
p++;
|
|
len++;
|
|
} /* while */
|
|
}
|
|
else if (strcasecmp(type,"ALPHA")==0) {
|
|
int lastWasEscape;
|
|
|
|
lastWasEscape=0;
|
|
while(*p) {
|
|
int c;
|
|
|
|
c=(unsigned char)*p;
|
|
if (c<32) {
|
|
DBG_ERROR(0, "Unescaped control character in value");
|
|
return -1;
|
|
}
|
|
if (lastWasEscape) {
|
|
lastWasEscape=0;
|
|
switch(c) {
|
|
case 'r': c='\r'; break;
|
|
case 'n': c='\n'; break;
|
|
case 'f': c='\f'; break;
|
|
case 't': c='\t'; break;
|
|
default: c=(unsigned char)*p;
|
|
} /* switch */
|
|
}
|
|
else {
|
|
if (*p==escapeChar) {
|
|
lastWasEscape=1;
|
|
len--;
|
|
c=-1;
|
|
}
|
|
else
|
|
c=(unsigned char)*p;
|
|
}
|
|
if (c!=-1) {
|
|
if (!isalpha(c)) {
|
|
DBG_ERROR(0, "Non-alpha character in value");
|
|
return -1;
|
|
}
|
|
}
|
|
p++;
|
|
len++;
|
|
} /* while */
|
|
}
|
|
else if (strcasecmp(type,"ASCII")==0) {
|
|
int lastWasEscape;
|
|
|
|
lastWasEscape=0;
|
|
while(*p) {
|
|
int c;
|
|
|
|
c=(unsigned char)*p;
|
|
if (c<32) {
|
|
DBG_ERROR(0, "Unescaped control character in value");
|
|
return -1;
|
|
}
|
|
|
|
if (lastWasEscape) {
|
|
lastWasEscape=0;
|
|
switch(c) {
|
|
case 'r': c='\r'; break;
|
|
case 'n': c='\n'; break;
|
|
case 'f': c='\f'; break;
|
|
case 't': c='\t'; break;
|
|
default: c=(unsigned char)*p;
|
|
} /* switch */
|
|
}
|
|
else {
|
|
if (*p==escapeChar) {
|
|
lastWasEscape=1;
|
|
len--;
|
|
c=-1;
|
|
}
|
|
else
|
|
c=(unsigned char)*p;
|
|
}
|
|
if (c!=-1) {
|
|
#ifdef isascii
|
|
if (!isascii(c)) {
|
|
DBG_ERROR(0, "Non-ASCII character in value");
|
|
return -1;
|
|
}
|
|
#else
|
|
if (c>127 || c<32) {
|
|
DBG_ERROR(0, "Non-ASCII character in value");
|
|
return -1;
|
|
}
|
|
#endif
|
|
}
|
|
p++;
|
|
len++;
|
|
} /* while */
|
|
}
|
|
else if (strcasecmp(type,"NUM")==0) {
|
|
int lastWasEscape;
|
|
|
|
lastWasEscape=0;
|
|
while(*p) {
|
|
int c;
|
|
|
|
c=(unsigned char)*p;
|
|
if (c<32) {
|
|
DBG_ERROR(0, "Unescaped control character in value");
|
|
return -1;
|
|
}
|
|
|
|
if (lastWasEscape) {
|
|
lastWasEscape=0;
|
|
switch(c) {
|
|
case 'r': c='\r'; break;
|
|
case 'n': c='\n'; break;
|
|
case 'f': c='\f'; break;
|
|
case 't': c='\t'; break;
|
|
default: c=(unsigned char)*p;
|
|
} /* switch */
|
|
}
|
|
else {
|
|
if (*p==escapeChar) {
|
|
lastWasEscape=1;
|
|
len--;
|
|
c=-1;
|
|
}
|
|
else
|
|
c=(unsigned char)*p;
|
|
}
|
|
if (c!=-1) {
|
|
if (!isdigit(c)) {
|
|
DBG_ERROR(0, "Non-alphanumeric character in value");
|
|
return -1;
|
|
}
|
|
}
|
|
p++;
|
|
len++;
|
|
} /* while */
|
|
}
|
|
else if (strcasecmp(type,"HEX")==0 ||
|
|
strcasecmp(type,"BIN")==0) {
|
|
int lastWasEscape;
|
|
|
|
lastWasEscape=0;
|
|
while(*p) {
|
|
int c;
|
|
|
|
c=(unsigned char)*p;
|
|
if (c<32) {
|
|
DBG_ERROR(0, "Unescaped control character in value");
|
|
return -1;
|
|
}
|
|
|
|
if (lastWasEscape) {
|
|
lastWasEscape=0;
|
|
switch(c) {
|
|
case 'r': c='\r'; break;
|
|
case 'n': c='\n'; break;
|
|
case 'f': c='\f'; break;
|
|
case 't': c='\t'; break;
|
|
default: c=(unsigned char)*p;
|
|
} /* switch */
|
|
}
|
|
else {
|
|
if (*p==escapeChar) {
|
|
lastWasEscape=1;
|
|
len--;
|
|
c=-1;
|
|
}
|
|
else
|
|
c=(unsigned char)*p;
|
|
}
|
|
if (c!=-1) {
|
|
if (!isxdigit(c)) {
|
|
DBG_ERROR(0, "Non-hex character in value");
|
|
return -1;
|
|
}
|
|
}
|
|
p++;
|
|
len++;
|
|
} /* while */
|
|
if (len&1) {
|
|
DBG_ERROR(0, "Uneven number of hex characters in value");
|
|
return -1;
|
|
}
|
|
if (strcasecmp(type,"BIN")==0) {
|
|
char lbuffer[32];
|
|
|
|
sprintf(lbuffer, "@%d@", len);
|
|
len=len/2; /* only half the size needed for binary data */
|
|
}
|
|
}
|
|
else if (strcasecmp(type,"FLOAT")==0) {
|
|
float f;
|
|
|
|
if (sscanf(value, "%f", &f)!=1) {
|
|
DBG_ERROR(0, "Bad float value \"%s\"", value);
|
|
}
|
|
len=strlen(value);
|
|
}
|
|
else {
|
|
DBG_ERROR(0, "Unknown type \"%s\"", type);
|
|
return -1;
|
|
}
|
|
|
|
if (minsize && len<minsize) {
|
|
DBG_ERROR(0, "Value too short (%d<%d)", len, minsize);
|
|
return -1;
|
|
}
|
|
if (maxsize && len>maxsize) {
|
|
DBG_ERROR(0, "Value too long (%d>%d)", len, maxsize);
|
|
return -1;
|
|
}
|
|
} /* if not external type */
|
|
|
|
DBG_DEBUG(0, "Type check ok");
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int GWEN_MsgEngine__WriteValue(GWEN_MSGENGINE *e,
|
|
GWEN_BUFFER *gbuf,
|
|
GWEN_BUFFER *data,
|
|
GWEN_XMLNODE *node) {
|
|
unsigned int minsize;
|
|
unsigned int maxsize;
|
|
const char *type;
|
|
int rv;
|
|
|
|
/* get some sizes */
|
|
minsize=atoi(GWEN_XMLNode_GetProperty(node, "minsize","0"));
|
|
maxsize=atoi(GWEN_XMLNode_GetProperty(node, "maxsize","0"));
|
|
type=GWEN_XMLNode_GetProperty(node, "type","ASCII");
|
|
|
|
/* copy value to buffer */
|
|
rv=1;
|
|
if (e->typeWritePtr) {
|
|
rv=e->typeWritePtr(e,
|
|
gbuf,
|
|
data,
|
|
node);
|
|
}
|
|
if (rv==-1) {
|
|
DBG_INFO(0, "External type writing failed");
|
|
return -1;
|
|
}
|
|
else if (rv==1) {
|
|
int i;
|
|
|
|
/* type not handled externally, so handle it myself */
|
|
if (strcasecmp(type, "bin")==0) {
|
|
if (GWEN_Buffer_RoomLeft(gbuf)<10+GWEN_Buffer_GetUsedBytes(data)) {
|
|
DBG_ERROR(0, "Buffer too small");
|
|
return -1;
|
|
}
|
|
sprintf(GWEN_Buffer_GetPosPointer(gbuf),
|
|
"@%d@",
|
|
GWEN_Buffer_GetUsedBytes(data));
|
|
|
|
|
|
i=strlen(GWEN_Buffer_GetPosPointer(gbuf));
|
|
GWEN_Buffer_IncrementPos(gbuf, i);
|
|
GWEN_Buffer_AppendBuffer(gbuf, data);
|
|
} /* if type is "bin" */
|
|
else if (strcasecmp(type, "num")==0) {
|
|
int num;
|
|
int len;
|
|
int lj;
|
|
|
|
num=atoi(GWEN_Buffer_GetPosPointer(data));
|
|
len=strlen(GWEN_Buffer_GetPosPointer(data));
|
|
|
|
if (atoi(GWEN_XMLNode_GetProperty(node, "leftfill","0"))) {
|
|
if ((maxsize+1)>=GWEN_Buffer_RoomLeft(gbuf)) {
|
|
DBG_ERROR(0, "Buffer too small");
|
|
return -1;
|
|
}
|
|
|
|
/* fill left */
|
|
for (lj=0; lj<(maxsize-len); lj++)
|
|
GWEN_Buffer_AppendByte(gbuf, '0');
|
|
|
|
/* write value */
|
|
for (lj=0; lj<len; lj++)
|
|
GWEN_Buffer_AppendByte(gbuf, GWEN_Buffer_ReadByte(data));
|
|
}
|
|
else if (atoi(GWEN_XMLNode_GetProperty(node, "rightfill","0"))) {
|
|
if ((maxsize+1)>=GWEN_Buffer_RoomLeft(gbuf)) {
|
|
DBG_ERROR(0, "Buffer too small");
|
|
return -1;
|
|
}
|
|
|
|
/* write value */
|
|
for (lj=0; lj<len; lj++)
|
|
GWEN_Buffer_AppendByte(gbuf, GWEN_Buffer_ReadByte(data));
|
|
|
|
/* fill right */
|
|
for (lj=0; lj<(maxsize-len); lj++)
|
|
GWEN_Buffer_AppendByte(gbuf, '0');
|
|
}
|
|
else {
|
|
if ((maxsize+1)>=GWEN_Buffer_RoomLeft(gbuf)) {
|
|
DBG_ERROR(0, "Maxsize in XML file is higher than the buffer size");
|
|
return -1;
|
|
}
|
|
for (lj=0; lj<len; lj++)
|
|
GWEN_Buffer_AppendByte(gbuf, GWEN_Buffer_ReadByte(data));
|
|
}
|
|
} /* if type is num */
|
|
else {
|
|
/* TODO: Check for valids */
|
|
const char *p;
|
|
int lastWasEscape;
|
|
int pcount;
|
|
|
|
p=GWEN_Buffer_GetPosPointer(data);
|
|
pcount=0;
|
|
lastWasEscape=0;
|
|
while(*p && pcount<GWEN_Buffer_GetUsedBytes(data)) {
|
|
int c;
|
|
|
|
c=(unsigned char)*p;
|
|
if (lastWasEscape) {
|
|
lastWasEscape=0;
|
|
switch(c) {
|
|
case 'r': c='\r'; break;
|
|
case 'n': c='\n'; break;
|
|
case 'f': c='\f'; break;
|
|
case 't': c='\t'; break;
|
|
default: c=(unsigned char)*p;
|
|
} /* switch */
|
|
}
|
|
else {
|
|
if (*p=='\\') {
|
|
lastWasEscape=1;
|
|
c=-1;
|
|
}
|
|
else
|
|
c=(unsigned char)*p;
|
|
}
|
|
if (c!=-1) {
|
|
int needsEscape;
|
|
|
|
needsEscape=0;
|
|
if (c==e->escapeChar)
|
|
needsEscape=1;
|
|
else {
|
|
if (e->charsToEscape)
|
|
if (strchr(e->charsToEscape, c))
|
|
needsEscape=1;
|
|
}
|
|
if (needsEscape) {
|
|
/* write escape char */
|
|
if (GWEN_Buffer_AppendByte(gbuf,
|
|
e->escapeChar)) {
|
|
return -1;
|
|
}
|
|
}
|
|
if (GWEN_Buffer_AppendByte(gbuf, c)) {
|
|
return -1;
|
|
}
|
|
}
|
|
p++;
|
|
pcount++;
|
|
} /* while */
|
|
if (pcount<GWEN_Buffer_GetUsedBytes(data)) {
|
|
DBG_WARN(0, "Premature end of string (%d<%d)",
|
|
pcount, GWEN_Buffer_GetUsedBytes(data));
|
|
}
|
|
if (*p) {
|
|
DBG_WARN(0, "String is longer than expected (no #0 at pos=%d)",
|
|
GWEN_Buffer_GetUsedBytes(data)-1);
|
|
}
|
|
} /* if type is not BIN */
|
|
} /* if type not external */
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int GWEN_MsgEngine__IsCharTyp(const char *type) {
|
|
return
|
|
(strcasecmp(type, "alpha")==0) ||
|
|
(strcasecmp(type, "ascii")==0) ||
|
|
(strcasecmp(type, "an")==0);
|
|
}
|
|
|
|
|
|
|
|
int GWEN_MsgEngine__IsIntTyp(const char *type) {
|
|
return
|
|
(strcasecmp(type, "num")==0);
|
|
}
|
|
|
|
|
|
|
|
int GWEN_MsgEngine__IsBinTyp(const char *type) {
|
|
return
|
|
(strcasecmp(type, "bin")==0);
|
|
}
|
|
|
|
|
|
|
|
int GWEN_MsgEngine__WriteElement(GWEN_MSGENGINE *e,
|
|
GWEN_BUFFER *gbuf,
|
|
GWEN_XMLNODE *node,
|
|
GWEN_XMLNODE *rnode,
|
|
GWEN_DB_NODE *gr,
|
|
int loopNr,
|
|
int isOptional) {
|
|
const char *name;
|
|
const char *type;
|
|
unsigned int minsize;
|
|
unsigned int maxsize;
|
|
char numbuffer[256];
|
|
|
|
const char *pdata;
|
|
unsigned int datasize;
|
|
GWEN_BUFFER *data;
|
|
|
|
pdata=0;
|
|
|
|
/* get type */
|
|
type=GWEN_XMLNode_GetProperty(node, "type","ASCII");
|
|
|
|
/* get some sizes */
|
|
minsize=atoi(GWEN_XMLNode_GetProperty(node, "minsize","0"));
|
|
maxsize=atoi(GWEN_XMLNode_GetProperty(node, "maxsize","0"));
|
|
|
|
/* get name */
|
|
name=GWEN_XMLNode_GetProperty(node, "name", 0);
|
|
if (!name) {
|
|
/* get data from within the XML node */
|
|
GWEN_XMLNODE *n;
|
|
|
|
n=GWEN_XMLNode_GetChild(node);
|
|
DBG_DEBUG(0, "Current node is %8x (new node is %8x)",
|
|
(unsigned int)node,
|
|
(unsigned int)n);
|
|
if (!n) {
|
|
DBG_DEBUG(0, "No child");
|
|
}
|
|
while(n) {
|
|
if (GWEN_XMLNode_GetType(n)==GWEN_XMLNodeTypeData)
|
|
break;
|
|
n=GWEN_XMLNode_Next(n);
|
|
} /* while */
|
|
if (n) {
|
|
pdata=GWEN_XMLNode_GetData(n);
|
|
datasize=strlen(pdata);
|
|
}
|
|
else {
|
|
pdata="";
|
|
datasize=strlen(pdata);
|
|
}
|
|
} /* if (!name) */
|
|
else {
|
|
char nbuffer[256];
|
|
const char *nptr;
|
|
|
|
if (loopNr==0) {
|
|
nptr=name;
|
|
}
|
|
else {
|
|
/* create new element name including the loop number (e.g. var1) */
|
|
if (strlen(name)+10>=sizeof(nbuffer)) {
|
|
DBG_ERROR(0, "Buffer too small");
|
|
return -1;
|
|
}
|
|
|
|
sprintf(nbuffer, "%s%d", name, loopNr);
|
|
nptr=nbuffer;
|
|
}
|
|
|
|
if (gr) {
|
|
/* get the value of the given var from the db */
|
|
if (GWEN_MsgEngine__IsCharTyp(type)) {
|
|
pdata=GWEN_DB_GetCharValue(gr, nptr, 0, 0);
|
|
if (pdata)
|
|
datasize=strlen(pdata);
|
|
else
|
|
datasize=0;
|
|
}
|
|
else if (GWEN_MsgEngine__IsIntTyp(type)) {
|
|
int idata;
|
|
|
|
idata=GWEN_DB_GetIntValue(gr, nptr, 0, 0);
|
|
if (-1==GWEN_Text_NumToString(idata, numbuffer,
|
|
sizeof(numbuffer),0)) {
|
|
DBG_ERROR(0, "Buffer too small");
|
|
return -1;
|
|
}
|
|
pdata=numbuffer;
|
|
datasize=strlen(numbuffer);
|
|
}
|
|
else if (GWEN_MsgEngine__IsBinTyp(type)) {
|
|
pdata=GWEN_DB_GetBinValue(gr, nptr, 0, 0, 0, &datasize);
|
|
}
|
|
else {
|
|
DBG_ERROR(0, "Bad parameter type");
|
|
return -1;
|
|
}
|
|
}
|
|
if (!pdata)
|
|
/* still no data, try to get it from the XML file */
|
|
pdata=GWEN_MsgEngine__SearchForValue(e, node, rnode, nptr,
|
|
&datasize);
|
|
|
|
if (pdata==0) {
|
|
if (isOptional) {
|
|
DBG_INFO(0, "Value not found, omitting element \"%s[%d]\"",
|
|
name, loopNr);
|
|
return 1;
|
|
}
|
|
else {
|
|
DBG_ERROR(0, "Value for element \"%s[%d]\" not found",
|
|
name, loopNr);
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
data=GWEN_Buffer_new((char*)pdata,
|
|
datasize,
|
|
datasize,
|
|
0 /* dont take ownership*/ );
|
|
|
|
/* write value */
|
|
if (GWEN_MsgEngine__WriteValue(e,
|
|
gbuf,
|
|
data,
|
|
node)!=0) {
|
|
DBG_INFO(0, "Could not write value");
|
|
GWEN_Buffer_free(data);
|
|
return -1;
|
|
}
|
|
GWEN_Buffer_free(data);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
GWEN_XMLNODE *GWEN_MsgEngine_FindGroupByProperty(GWEN_MSGENGINE *e,
|
|
const char *pname,
|
|
int version,
|
|
const char *pvalue) {
|
|
return GWEN_MsgEngine_FindNodeByProperty(e, "GROUP", pname, version, pvalue);
|
|
}
|
|
|
|
|
|
|
|
GWEN_XMLNODE *GWEN_MsgEngine_FindNodeByProperty(GWEN_MSGENGINE *e,
|
|
const char *t,
|
|
const char *pname,
|
|
int version,
|
|
const char *pvalue) {
|
|
GWEN_XMLNODE *n;
|
|
const char *p;
|
|
int i;
|
|
char *mode;
|
|
char buffer[256];
|
|
|
|
if ((strlen(t)+4)>sizeof(buffer)) {
|
|
DBG_ERROR(0, "Type name too long.");
|
|
return 0;
|
|
}
|
|
|
|
mode=e->secMode;
|
|
if (!e->defs) {
|
|
DBG_ERROR(0, "No definitions available");
|
|
return 0;
|
|
}
|
|
n=e->defs;
|
|
n=GWEN_XMLNode_GetChild(n);
|
|
|
|
/* find type+"S" */
|
|
strcpy(buffer, t);
|
|
strcat(buffer,"S");
|
|
while(n) {
|
|
if (GWEN_XMLNode_GetType(n)==GWEN_XMLNodeTypeTag) {
|
|
p=GWEN_XMLNode_GetData(n);
|
|
assert(p);
|
|
if (strcasecmp(p, buffer)==0)
|
|
break;
|
|
}
|
|
n=GWEN_XMLNode_Next(n);
|
|
} /* while */
|
|
|
|
if (!n) {
|
|
DBG_ERROR(0, "No definitions available for type \"%s\"", t);
|
|
return 0;
|
|
}
|
|
|
|
/* find approppriate group definition */
|
|
if (!mode)
|
|
mode="";
|
|
n=GWEN_XMLNode_GetChild(n);
|
|
if (!n) {
|
|
DBG_ERROR(0, "No definitions inside \"%s\"", buffer);
|
|
return 0;
|
|
}
|
|
|
|
/* find type+"def" */
|
|
strcpy(buffer, t);
|
|
strcat(buffer,"def");
|
|
while(n) {
|
|
if (GWEN_XMLNode_GetType(n)==GWEN_XMLNodeTypeTag) {
|
|
p=GWEN_XMLNode_GetData(n);
|
|
assert(p);
|
|
if (strcasecmp(p, buffer)==0) {
|
|
/*DBG_INFO(0, "Candidate found (1)"); */
|
|
p=GWEN_XMLNode_GetProperty(n, pname,"");
|
|
if (strcasecmp(p, pvalue)==0) {
|
|
/*DBG_INFO(0, "Candidate found (2)"); */
|
|
i=atoi(GWEN_XMLNode_GetProperty(n, "version" ,"0"));
|
|
if (version==0 || version==i) {
|
|
/* DBG_INFO(0, "Candidate found (3)"); */
|
|
p=GWEN_XMLNode_GetProperty(n, "mode","");
|
|
if (strcasecmp(p, mode)==0 || !*p) {
|
|
DBG_DEBUG(0, "Group definition for \"%s=%s\" found",
|
|
pname, pvalue);
|
|
return n;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
n=GWEN_XMLNode_Next(n);
|
|
} /* while */
|
|
|
|
DBG_ERROR(0, "Group definition for \"%s=%s\" not found", pname, pvalue);
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
const char *GWEN_MsgEngine__TransformValue(GWEN_MSGENGINE *e,
|
|
const char *pvalue,
|
|
GWEN_XMLNODE *node) {
|
|
const char *p;
|
|
static char pbuffer[256];
|
|
|
|
if (pvalue) {
|
|
/* check whether the value is a property */
|
|
p=pvalue;
|
|
while (*p && isspace(*p))
|
|
p++;
|
|
if (*p=='$' || *p=='+') {
|
|
/* global property */
|
|
int incr;
|
|
|
|
incr=(*p=='+');
|
|
p++;
|
|
|
|
DBG_INFO(0, "Getting global property \"%s\"", p);
|
|
if (incr) {
|
|
int z;
|
|
|
|
z=GWEN_DB_GetIntValue(e->globalValues, p, 0, 0);
|
|
DBG_INFO(0, "Incrementing global property \"%s\" (%d)",
|
|
p, z);
|
|
if (GWEN_Text_NumToString(z, pbuffer, sizeof(pbuffer),0)<1) {
|
|
DBG_ERROR(0, "Error converting num to string");
|
|
return 0;
|
|
}
|
|
|
|
z++;
|
|
DBG_DEBUG(0, "Setting global property \"%s\"=%d", p, z);
|
|
GWEN_DB_SetIntValue(e->globalValues,
|
|
GWEN_DB_FLAGS_DEFAULT |
|
|
GWEN_DB_FLAGS_OVERWRITE_VARS,
|
|
p, z);
|
|
pvalue=pbuffer;
|
|
}
|
|
else {
|
|
pvalue=GWEN_DB_GetCharValue(e->globalValues, p, 0, "");
|
|
|
|
}
|
|
DBG_DEBUG(0, "Transformed value \"%s\"", pvalue);
|
|
}
|
|
else if (*p=='%') {
|
|
/* local property */
|
|
p++;
|
|
|
|
DBG_INFO(0, "Getting property \"%s\"", p);
|
|
pvalue=GWEN_XMLNode_GetProperty(node, p, 0);
|
|
DBG_DEBUG(0, "Transformed value \"%s\"", pvalue);
|
|
}
|
|
}
|
|
return pvalue;
|
|
}
|
|
|
|
|
|
|
|
const char *GWEN_MsgEngine__SearchForValue(GWEN_MSGENGINE *e,
|
|
GWEN_XMLNODE *node,
|
|
GWEN_XMLNODE *refnode,
|
|
const char *name,
|
|
unsigned int *datasize) {
|
|
const char *pvalue;
|
|
GWEN_XMLNODE *pn;
|
|
char *bufferPtr;
|
|
int topDown;
|
|
const char *lastValue;
|
|
|
|
DBG_INFO(0, "Searching for value of \"%s\" in <VALUES>", name);
|
|
topDown=atoi(GWEN_XMLNode_GetProperty(node, "topdown","0"));
|
|
lastValue=0;
|
|
|
|
bufferPtr=0;
|
|
pn=GWEN_XMLNode_GetParent(node);
|
|
pvalue=GWEN_MsgEngine__findInValues(e, pn, name);
|
|
if (pvalue) {
|
|
if (!topDown) {
|
|
*datasize=strlen(pvalue);
|
|
return pvalue;
|
|
}
|
|
DBG_INFO(0, "Found a value (%s), but will look further", pvalue);
|
|
lastValue=pvalue;
|
|
}
|
|
|
|
pn=refnode;
|
|
while(pn) {
|
|
const char *ppath;
|
|
|
|
ppath=GWEN_XMLNode_GetProperty(pn, "name", "");
|
|
|
|
if (*ppath) {
|
|
int i;
|
|
char *tmpptr;
|
|
|
|
if (bufferPtr) {
|
|
i=strlen(bufferPtr)+strlen(ppath)+2;
|
|
tmpptr=(char*)malloc(i);
|
|
assert(tmpptr);
|
|
sprintf(tmpptr, "%s/%s", ppath, bufferPtr);
|
|
free(bufferPtr);
|
|
bufferPtr=tmpptr;
|
|
}
|
|
else {
|
|
i=strlen(ppath)+strlen(name)+2;
|
|
tmpptr=(char*)malloc(i);
|
|
assert(tmpptr);
|
|
sprintf(tmpptr, "%s/%s", ppath, name);
|
|
bufferPtr=tmpptr;
|
|
}
|
|
name=bufferPtr;
|
|
}
|
|
pvalue=GWEN_MsgEngine__findInValues(e, pn, name);
|
|
|
|
if (pvalue) {
|
|
if (!topDown) {
|
|
free(bufferPtr);
|
|
*datasize=strlen(pvalue);
|
|
return pvalue;
|
|
}
|
|
DBG_INFO(0, "Found a value (%s), but will look further", pvalue);
|
|
lastValue=pvalue;
|
|
}
|
|
pn=GWEN_XMLNode_GetParent(pn);
|
|
} /* while */
|
|
free(bufferPtr);
|
|
if (lastValue)
|
|
*datasize=strlen(lastValue);
|
|
else
|
|
*datasize=0;
|
|
return lastValue;
|
|
}
|
|
|
|
|
|
|
|
const char *GWEN_MsgEngine__findInValues(GWEN_MSGENGINE *e,
|
|
GWEN_XMLNODE *node,
|
|
const char *name) {
|
|
GWEN_XMLNODE *pn;
|
|
|
|
DBG_DEBUG(0, "Looking for value of \"%s\" in <VALUES>", name);
|
|
pn=GWEN_XMLNode_GetChild(node);
|
|
|
|
while(pn) {
|
|
if (GWEN_XMLNode_GetType(pn)==GWEN_XMLNodeTypeTag) {
|
|
GWEN_XMLNODE *n;
|
|
const char *p;
|
|
|
|
p=GWEN_XMLNode_GetData(pn);
|
|
assert(p);
|
|
DBG_DEBUG(0, "Checking %s",p);
|
|
if (strcasecmp(p, "VALUES")==0) {
|
|
DBG_DEBUG(0, "<values> found");
|
|
/* <preset> found, check all values */
|
|
n=GWEN_XMLNode_GetChild(pn);
|
|
while(n) {
|
|
if (GWEN_XMLNode_GetType(n)==GWEN_XMLNodeTypeTag) {
|
|
const char *p;
|
|
|
|
p=GWEN_XMLNode_GetData(n);
|
|
assert(p);
|
|
if (strcasecmp(p, "VALUE")==0) {
|
|
const char *pname;
|
|
const char *pvalue;
|
|
|
|
pname=GWEN_XMLNode_GetProperty(n, "path", 0);
|
|
if (pname) {
|
|
DBG_DEBUG(0, "Comparing against \"%s\"", pname);
|
|
if (strcasecmp(name, pname)==0) {
|
|
GWEN_XMLNODE *dn;
|
|
|
|
dn=GWEN_XMLNode_GetChild(n);
|
|
while (dn) {
|
|
if (GWEN_XMLNode_GetType(dn)==GWEN_XMLNodeTypeData) {
|
|
pvalue=GWEN_XMLNode_GetData(dn);
|
|
pvalue=GWEN_MsgEngine__TransformValue(e, pvalue, node);
|
|
if (pvalue)
|
|
return pvalue;
|
|
}
|
|
dn=GWEN_XMLNode_Next(dn);
|
|
} /* while dn */
|
|
} /* if path matches name */
|
|
} /* if path given */
|
|
} /* if VALUE tag */
|
|
} /* if TAG */
|
|
n=GWEN_XMLNode_Next(n);
|
|
} /* while */
|
|
break; /* REMOVE this to check multiple groups */
|
|
} /* if <preset> found */
|
|
} /* if tag */
|
|
pn=GWEN_XMLNode_Next(pn);
|
|
} /* while node */
|
|
|
|
DBG_DEBUG(0, "No value found for \"%s\" in <VALUES>", name);
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int GWEN_MsgEngine__WriteGroup(GWEN_MSGENGINE *e,
|
|
GWEN_BUFFER *gbuf,
|
|
GWEN_XMLNODE *node,
|
|
GWEN_XMLNODE *rnode,
|
|
GWEN_DB_NODE *gr,
|
|
int groupIsOptional) {
|
|
GWEN_XMLNODE *n;
|
|
const char *p;
|
|
char delimiter;
|
|
char terminator;
|
|
int isFirstElement;
|
|
int omittedElements;
|
|
int hasEntries;
|
|
|
|
/* get some settings */
|
|
if (rnode) {
|
|
/* get delimiter */
|
|
p=GWEN_XMLNode_GetProperty(rnode,
|
|
"delimiter",
|
|
GWEN_XMLNode_GetProperty(node,
|
|
"delimiter",
|
|
""));
|
|
delimiter=*p;
|
|
|
|
/* get terminating char, if any */
|
|
p=GWEN_XMLNode_GetProperty(rnode,
|
|
"terminator",
|
|
GWEN_XMLNode_GetProperty(node,
|
|
"terminator",
|
|
""));
|
|
terminator=*p;
|
|
}
|
|
else {
|
|
/* get delimiter */
|
|
p=GWEN_XMLNode_GetProperty(node,
|
|
"delimiter",
|
|
"");
|
|
delimiter=*p;
|
|
|
|
/* get terminating char, if any */
|
|
p=GWEN_XMLNode_GetProperty(node, "terminator","");
|
|
terminator=*p;
|
|
}
|
|
|
|
/* handle all child entries */
|
|
n=GWEN_XMLNode_GetChild(node);
|
|
isFirstElement=1;
|
|
omittedElements=0;
|
|
hasEntries=0;
|
|
|
|
while(n) {
|
|
int t;
|
|
unsigned int minnum;
|
|
unsigned int maxnum;
|
|
int gversion;
|
|
const char *addEmptyMode;
|
|
int loopNr;
|
|
|
|
minnum=atoi(GWEN_XMLNode_GetProperty(n, "minnum","1"));
|
|
maxnum=atoi(GWEN_XMLNode_GetProperty(n, "maxnum","1"));
|
|
gversion=atoi(GWEN_XMLNode_GetProperty(n, "version","0"));
|
|
addEmptyMode=GWEN_XMLNode_GetProperty(n, "addemptymode","one");
|
|
|
|
DBG_DEBUG(0, "Omitted elements: %d", omittedElements);
|
|
t=GWEN_XMLNode_GetType(n);
|
|
if (t==GWEN_XMLNodeTypeTag) {
|
|
const char *typ;
|
|
|
|
typ=GWEN_XMLNode_GetData(n);
|
|
if (typ==0) {
|
|
DBG_ERROR(0, "Unnamed tag found (internal error?)");
|
|
return -1;
|
|
}
|
|
if (strcasecmp(typ, "ELEM")==0) {
|
|
/* element tag found */
|
|
int j;
|
|
int rv;
|
|
|
|
/* write element as often as needed */
|
|
for (loopNr=0; loopNr<maxnum; loopNr++) {
|
|
unsigned int posBeforeElement;
|
|
|
|
posBeforeElement=GWEN_Buffer_GetPos(gbuf);
|
|
|
|
/* write delimiter, if needed */
|
|
if (!isFirstElement && delimiter) {
|
|
for (j=0; j<omittedElements+1; j++) {
|
|
if (GWEN_Buffer_AppendByte(gbuf, delimiter)) {
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
rv=GWEN_MsgEngine__WriteElement(e,
|
|
gbuf,
|
|
n,
|
|
rnode,
|
|
gr,
|
|
loopNr,
|
|
loopNr>=minnum ||
|
|
(groupIsOptional && !hasEntries));
|
|
if (rv==-1) {
|
|
DBG_INFO(0, "Error writing element");
|
|
return -1;
|
|
}
|
|
else if (rv==0) {
|
|
isFirstElement=0;
|
|
omittedElements=0;
|
|
hasEntries=1;
|
|
DBG_DEBUG(0, "Element written");
|
|
}
|
|
else {
|
|
/* element is optional, not found */
|
|
/* restore position */
|
|
GWEN_Buffer_SetPos(gbuf, posBeforeElement);
|
|
GWEN_Buffer_SetUsedBytes(gbuf, posBeforeElement);
|
|
|
|
if (strcasecmp(addEmptyMode, "max")==0) {
|
|
DBG_DEBUG(0, "Adding max empty");
|
|
omittedElements+=(maxnum-loopNr);
|
|
}
|
|
else if (strcasecmp(addEmptyMode, "min")==0) {
|
|
DBG_DEBUG(0, "Adding min empty");
|
|
if (loopNr<minnum)
|
|
omittedElements+=(minnum-loopNr);
|
|
}
|
|
else if (strcasecmp(addEmptyMode, "one")==0) {
|
|
if (loopNr==0)
|
|
omittedElements++;
|
|
}
|
|
else if (strcasecmp(addEmptyMode, "none")==0) {
|
|
}
|
|
else {
|
|
DBG_ERROR(0, "Unknown addemptymode \"%s\"",
|
|
addEmptyMode);
|
|
return -1;
|
|
}
|
|
break;
|
|
}
|
|
} /* for */
|
|
}
|
|
else if (strcasecmp(typ, "VALUES")==0) {
|
|
}
|
|
else {
|
|
/* group tag found */
|
|
GWEN_XMLNODE *gn;
|
|
GWEN_DB_NODE *gcfg;
|
|
const char *gname;
|
|
const char *gtype;
|
|
unsigned int posBeforeGroup;
|
|
|
|
gcfg=0;
|
|
gtype=GWEN_XMLNode_GetProperty(n, "type",0);
|
|
if (!gtype) {
|
|
/* no "type" property, so use this group directly */
|
|
DBG_INFO(0, "<%s> tag has no \"type\" property", typ);
|
|
gtype="";
|
|
gn=n;
|
|
}
|
|
else {
|
|
gn=GWEN_MsgEngine_FindNodeByProperty(e, typ, "id", gversion, gtype);
|
|
if (!gn) {
|
|
DBG_INFO(0, "Definition for type \"%s\" not found", typ);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
gname=0;
|
|
gcfg=0;
|
|
if (gr) {
|
|
gname=GWEN_XMLNode_GetProperty(n, "name",0);
|
|
if (gname)
|
|
gcfg=GWEN_DB_GetFirstGroup(gr);
|
|
else
|
|
gcfg=gr;
|
|
}
|
|
|
|
/* write group as often as needed */
|
|
for (loopNr=0; loopNr<maxnum; loopNr++) {
|
|
int rv;
|
|
|
|
posBeforeGroup=GWEN_Buffer_GetPos(gbuf);
|
|
|
|
/* find next matching group */
|
|
if (gname) {
|
|
while(gcfg) {
|
|
if (strcasecmp(GWEN_DB_GroupName(gcfg), gname)==0)
|
|
break;
|
|
gcfg=GWEN_DB_GetNextGroup(gcfg);
|
|
} /* while */
|
|
}
|
|
|
|
/* write delimiter, if needed */
|
|
if (!isFirstElement && delimiter) {
|
|
int j;
|
|
|
|
for (j=0; j<omittedElements+1; j++) {
|
|
if (GWEN_Buffer_AppendByte(gbuf, delimiter)) {
|
|
return -1;
|
|
}
|
|
}
|
|
omittedElements=0;
|
|
}
|
|
else
|
|
isFirstElement=0;
|
|
|
|
/* write group */
|
|
rv=GWEN_MsgEngine__WriteGroup(e,
|
|
gbuf,
|
|
gn,
|
|
n,
|
|
gcfg,
|
|
loopNr>=minnum || groupIsOptional);
|
|
if (rv==-1){
|
|
DBG_INFO(0, "Could not write group \"%s\"", gtype);
|
|
return -1;
|
|
}
|
|
else if (rv==0) {
|
|
hasEntries=1;
|
|
}
|
|
else {
|
|
DBG_INFO(0, "Empty Group");
|
|
GWEN_Buffer_SetPos(gbuf, posBeforeGroup);
|
|
GWEN_Buffer_SetUsedBytes(gbuf, posBeforeGroup);
|
|
|
|
if (loopNr>=minnum) {
|
|
DBG_INFO(0, "No data for group \"%s[%d]\", omitting",
|
|
gname, loopNr);
|
|
if (strcasecmp(addEmptyMode, "max")==0) {
|
|
DBG_DEBUG(0, "Adding max empty");
|
|
omittedElements+=(maxnum-loopNr);
|
|
}
|
|
else if (strcasecmp(addEmptyMode, "min")==0) {
|
|
DBG_DEBUG(0, "Adding min empty");
|
|
if (loopNr<minnum)
|
|
omittedElements+=(minnum-loopNr);
|
|
}
|
|
else if (strcasecmp(addEmptyMode, "one")==0) {
|
|
if (loopNr==0)
|
|
omittedElements++;
|
|
}
|
|
else if (strcasecmp(addEmptyMode, "none")==0) {
|
|
}
|
|
else {
|
|
DBG_ERROR(0, "Unknown addemptymode \"%s\"",
|
|
addEmptyMode);
|
|
return -1;
|
|
}
|
|
break;
|
|
}
|
|
else {
|
|
DBG_ERROR(0, "No data for group \"%s[%d]\"",
|
|
gname, loopNr);
|
|
return -1;
|
|
}
|
|
} /* if empty group */
|
|
} /* for */
|
|
}
|
|
}
|
|
else if (t==GWEN_XMLNodeTypeData) {
|
|
}
|
|
else {
|
|
DBG_DEBUG(0, "Unhandled node type %d", t);
|
|
}
|
|
n=GWEN_XMLNode_Next(n);
|
|
} /* while */
|
|
|
|
/* write terminating character, if any */
|
|
if (terminator) {
|
|
if (GWEN_Buffer_AppendByte(gbuf, terminator)) {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return hasEntries?0:1;
|
|
}
|
|
|
|
|
|
|
|
int GWEN_MsgEngine_CreateMessageFromNode(GWEN_MSGENGINE *e,
|
|
GWEN_XMLNODE *node,
|
|
GWEN_BUFFER *gbuf,
|
|
GWEN_DB_NODE *msgData){
|
|
assert(e);
|
|
assert(node);
|
|
assert(msgData);
|
|
|
|
if (GWEN_MsgEngine__WriteGroup(e,
|
|
gbuf,
|
|
node,
|
|
0,
|
|
msgData,
|
|
0)) {
|
|
const char *p;
|
|
|
|
p=GWEN_XMLNode_GetData(node);
|
|
if (p) {
|
|
DBG_INFO(0, "Error writing group \"%s\"", p);
|
|
}
|
|
else {
|
|
DBG_INFO(0, "Error writing group");
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int GWEN_MsgEngine_CreateMessage(GWEN_MSGENGINE *e,
|
|
const char *msgName,
|
|
int msgVersion,
|
|
GWEN_BUFFER *gbuf,
|
|
GWEN_DB_NODE *msgData) {
|
|
GWEN_XMLNODE *group;
|
|
|
|
group=GWEN_MsgEngine_FindGroupByProperty(e, "id", msgVersion, msgName);
|
|
if (!group) {
|
|
DBG_ERROR(0, "Group \"%s\" not found\n", msgName);
|
|
return -1;
|
|
}
|
|
return GWEN_MsgEngine_CreateMessageFromNode(e,
|
|
group,
|
|
gbuf,
|
|
msgData);
|
|
}
|
|
|
|
|
|
|
|
int GWEN_MsgEngine_AddDefinitions(GWEN_MSGENGINE *e,
|
|
GWEN_XMLNODE *node) {
|
|
GWEN_XMLNODE *nsrc, *ndst;
|
|
|
|
assert(e);
|
|
assert(node);
|
|
|
|
if (!e->defs) {
|
|
e->defs=GWEN_XMLNode_dup(node);
|
|
return 0;
|
|
}
|
|
|
|
nsrc=GWEN_XMLNode_GetChild(node);
|
|
while(nsrc) {
|
|
if (GWEN_XMLNode_GetType(nsrc)==GWEN_XMLNodeTypeTag) {
|
|
ndst=GWEN_XMLNode_FindNode(e->defs, GWEN_XMLNodeTypeTag,
|
|
GWEN_XMLNode_GetData(nsrc));
|
|
if (ndst) {
|
|
GWEN_XMLNODE *n;
|
|
|
|
n=GWEN_XMLNode_GetChild(nsrc);
|
|
while (n) {
|
|
GWEN_XMLNODE *newNode;
|
|
|
|
DBG_DEBUG(0, "Adding node \"%s\"", GWEN_XMLNode_GetData(n));
|
|
newNode=GWEN_XMLNode_dup(n);
|
|
GWEN_XMLNode_AddChild(ndst, newNode);
|
|
n=GWEN_XMLNode_Next(n);
|
|
} /* while n */
|
|
}
|
|
else {
|
|
GWEN_XMLNODE *newNode;
|
|
|
|
DBG_DEBUG(0, "Adding branch \"%s\"", GWEN_XMLNode_GetData(nsrc));
|
|
newNode=GWEN_XMLNode_dup(nsrc);
|
|
GWEN_XMLNode_AddChild(e->defs, newNode);
|
|
}
|
|
} /* if TAG */
|
|
nsrc=GWEN_XMLNode_Next(nsrc);
|
|
} /* while */
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int GWEN_MsgEngine__ShowElement(GWEN_MSGENGINE *e,
|
|
const char *path,
|
|
GWEN_XMLNODE *node,
|
|
GWEN_STRINGLIST *sl,
|
|
unsigned int flags) {
|
|
const char *name;
|
|
const char *type;
|
|
const char *npath;
|
|
unsigned int minsize;
|
|
unsigned int maxsize;
|
|
unsigned int minnum;
|
|
unsigned int maxnum;
|
|
int j;
|
|
int isSet;
|
|
char nbuffer[256];
|
|
GWEN_STRINGLISTENTRY *en;
|
|
|
|
/* get type */
|
|
type=GWEN_XMLNode_GetProperty(node, "type","ASCII");
|
|
|
|
/* get some sizes */
|
|
minsize=atoi(GWEN_XMLNode_GetProperty(node, "minsize","0"));
|
|
maxsize=atoi(GWEN_XMLNode_GetProperty(node, "maxsize","0"));
|
|
minnum=atoi(GWEN_XMLNode_GetProperty(node, "minnum","1"));
|
|
maxnum=atoi(GWEN_XMLNode_GetProperty(node, "maxnum","1"));
|
|
|
|
npath="";
|
|
isSet=0;
|
|
|
|
/* get name */
|
|
name=GWEN_XMLNode_GetProperty(node, "name", 0);
|
|
if (path==0)
|
|
path="";
|
|
|
|
if (name) {
|
|
/* get value of a config variable */
|
|
if (strlen(path)+strlen(name)+10>=sizeof(nbuffer)) {
|
|
DBG_ERROR(0, "Buffer too small");
|
|
return -1;
|
|
}
|
|
if (*path)
|
|
sprintf(nbuffer, "%s/%s", path, name);
|
|
else
|
|
sprintf(nbuffer, "%s", name);
|
|
npath=nbuffer;
|
|
}
|
|
|
|
en=GWEN_StringList_FirstEntry(sl);
|
|
while(en) {
|
|
if (GWEN_StringListEntry_Data(en))
|
|
if (strcasecmp(GWEN_StringListEntry_Data(en), npath)==0) {
|
|
isSet=1;
|
|
break;
|
|
}
|
|
en=GWEN_StringListEntry_Next(en);
|
|
} /* while */
|
|
|
|
if (isSet && (flags & GWEN_MSGENGINE_SHOW_FLAGS_NOSET))
|
|
return 0;
|
|
|
|
fprintf(stdout, " %s",
|
|
npath);
|
|
j=GWEN_MSGENGINE_VARNAME_WIDTH-strlen(npath);
|
|
if (j>0) {
|
|
int i;
|
|
|
|
for (i=0; i<j; i++)
|
|
fprintf(stdout, " ");
|
|
}
|
|
fprintf(stdout, "| %s", type);
|
|
j=GWEN_MSGENGINE_TYPENAME_WIDTH-strlen(type);
|
|
if (j>0) {
|
|
int i;
|
|
|
|
for (i=0; i<j; i++)
|
|
fprintf(stdout, " ");
|
|
}
|
|
fprintf(stdout, "| %4d-%4d", minsize, maxsize);
|
|
fprintf(stdout," | %3d ", maxnum);
|
|
fprintf(stdout," |");
|
|
if (minnum==0)
|
|
fprintf(stdout," optvar");
|
|
if (flags & GWEN_MSGENGINE_SHOW_FLAGS_OPTIONAL)
|
|
fprintf(stdout," optgrp");
|
|
|
|
if (isSet) {
|
|
fprintf(stdout," set");
|
|
}
|
|
|
|
fprintf(stdout,"\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int GWEN_MsgEngine__ShowGroup(GWEN_MSGENGINE *e,
|
|
const char *path,
|
|
GWEN_XMLNODE *node,
|
|
GWEN_XMLNODE *rnode,
|
|
GWEN_STRINGLIST *sl,
|
|
unsigned int flags) {
|
|
GWEN_XMLNODE *n;
|
|
int isFirstElement;
|
|
int omittedElements;
|
|
int rv;
|
|
|
|
/* setup data */
|
|
n=GWEN_XMLNode_GetChild(node);
|
|
|
|
if (path==0)
|
|
path="";
|
|
if (*path=='/')
|
|
path++;
|
|
|
|
while(n) {
|
|
if (GWEN_XMLNode_GetType(n)==GWEN_XMLNodeTypeTag) {
|
|
const char *p;
|
|
|
|
p=GWEN_XMLNode_GetData(n);
|
|
assert(p);
|
|
DBG_DEBUG(0, "Checking %s",p);
|
|
if (strcasecmp(p, "VALUES")==0)
|
|
break;
|
|
} /* if tag */
|
|
n=GWEN_XMLNode_Next(n);
|
|
} /* while */
|
|
|
|
if (n) {
|
|
DBG_DEBUG(0, "<preset> found");
|
|
/* <preset> found, handle all values */
|
|
n=GWEN_XMLNode_GetChild(n);
|
|
while(n) {
|
|
if (GWEN_XMLNode_GetType(n)==GWEN_XMLNodeTypeTag) {
|
|
const char *p;
|
|
|
|
p=GWEN_XMLNode_GetData(n);
|
|
assert(p);
|
|
if (strcasecmp(p, "VALUE")==0) {
|
|
const char *pname;
|
|
const char *pvalue;
|
|
|
|
pname=GWEN_XMLNode_GetProperty(n, "path", 0);
|
|
if (pname) {
|
|
GWEN_XMLNODE *dn;
|
|
|
|
/* path found, find data */
|
|
dn=GWEN_XMLNode_GetChild(n);
|
|
while (dn) {
|
|
if (GWEN_XMLNode_GetType(dn)==GWEN_XMLNodeTypeData) {
|
|
pvalue=GWEN_XMLNode_GetData(dn);
|
|
if (pvalue) {
|
|
char pbuffer[256];
|
|
|
|
/* check whether the value is a property */
|
|
p=pvalue;
|
|
while (*p && isspace(*p))
|
|
p++;
|
|
if (strlen(path)+strlen(pname)+2>sizeof(pbuffer)) {
|
|
DBG_ERROR(0, "Buffer too small");
|
|
return -1;
|
|
}
|
|
if (*path)
|
|
sprintf(pbuffer, "%s/%s", path, pname);
|
|
else
|
|
sprintf(pbuffer, "%s", pname);
|
|
GWEN_StringList_AppendString(sl,
|
|
pbuffer,
|
|
0,
|
|
1);
|
|
}
|
|
break;
|
|
}
|
|
dn=GWEN_XMLNode_Next(dn);
|
|
} /* while dn */
|
|
} /* if path given */
|
|
} /* if VALUE tag */
|
|
} /* if TAG */
|
|
n=GWEN_XMLNode_Next(n);
|
|
} /* while */
|
|
} /* if <preset> found */
|
|
|
|
/* now handle all child entries */
|
|
n=GWEN_XMLNode_GetChild(node);
|
|
isFirstElement=1;
|
|
omittedElements=0;
|
|
while(n) {
|
|
int t;
|
|
unsigned int minnum;
|
|
unsigned int maxnum;
|
|
int gversion;
|
|
const char *addEmptyMode;
|
|
int loopNr;
|
|
unsigned int lflags;
|
|
|
|
minnum=atoi(GWEN_XMLNode_GetProperty(n, "minnum","1"));
|
|
maxnum=atoi(GWEN_XMLNode_GetProperty(n, "maxnum","1"));
|
|
gversion=atoi(GWEN_XMLNode_GetProperty(n, "version","0"));
|
|
addEmptyMode=GWEN_XMLNode_GetProperty(n, "addemptymode","one");
|
|
|
|
lflags=flags;
|
|
|
|
DBG_DEBUG(0, "Omitted elements: %d", omittedElements);
|
|
t=GWEN_XMLNode_GetType(n);
|
|
if (t==GWEN_XMLNodeTypeTag) {
|
|
const char *typ;
|
|
|
|
typ=GWEN_XMLNode_GetData(n);
|
|
if (typ==0) {
|
|
DBG_ERROR(0, "Unnamed tag found (internal error?)");
|
|
return -1;
|
|
}
|
|
if (strcasecmp(typ, "ELEM")==0) {
|
|
/* element tag found */
|
|
|
|
/* write element as often as needed */
|
|
rv=GWEN_MsgEngine__ShowElement(e,
|
|
path,
|
|
n,
|
|
sl,
|
|
lflags);
|
|
if (rv==-1)
|
|
return -1;
|
|
else {
|
|
isFirstElement=0;
|
|
omittedElements=0;
|
|
}
|
|
}
|
|
else if (strcasecmp(typ, "VALUES")==0) {
|
|
}
|
|
else {
|
|
/* group tag found */
|
|
GWEN_XMLNODE *gn;
|
|
const char *gname;
|
|
const char *gtype;
|
|
|
|
if (minnum==0)
|
|
lflags|=GWEN_MSGENGINE_SHOW_FLAGS_OPTIONAL;
|
|
|
|
gtype=GWEN_XMLNode_GetProperty(n, "type",0);
|
|
if (!gtype) {
|
|
/* no "type" property, so use this group directly */
|
|
DBG_INFO(0, "<%s> tag has no \"type\" property", typ);
|
|
gtype="";
|
|
gn=n;
|
|
}
|
|
else {
|
|
gn=GWEN_MsgEngine_FindNodeByProperty(e, typ, "id", gversion, gtype);
|
|
if (!gn) {
|
|
DBG_DEBUG(0, "Definition for type \"%s\" not found", typ);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/* write group as often as needed */
|
|
for (loopNr=0; loopNr<maxnum; loopNr++) {
|
|
/* find group */
|
|
char pbuffer[256];
|
|
const char *npath;
|
|
|
|
/* get configuration */
|
|
gname=GWEN_XMLNode_GetProperty(n, "name",0);
|
|
if (gname) {
|
|
if (loopNr==0) {
|
|
if (strlen(path)+strlen(gname)+1>sizeof(pbuffer)) {
|
|
DBG_ERROR(0, "Buffer too small");
|
|
return -1;
|
|
}
|
|
sprintf(pbuffer, "%s/%s", path, gname);
|
|
npath=pbuffer;
|
|
}
|
|
else {
|
|
/* this is not the first one, so create new name */
|
|
if (strlen(path)+strlen(gname)+10>sizeof(pbuffer)) {
|
|
DBG_ERROR(0, "Buffer too small");
|
|
return -1;
|
|
}
|
|
if (*path)
|
|
sprintf(pbuffer, "%s/%s%d", path, gname, loopNr);
|
|
else
|
|
sprintf(pbuffer, "%s%d", gname, loopNr);
|
|
/* get the value of the given var */
|
|
npath=pbuffer;
|
|
}
|
|
} /* if name given */
|
|
else
|
|
npath=path;
|
|
|
|
/* write group */
|
|
if (GWEN_MsgEngine__ShowGroup(e,
|
|
npath,
|
|
gn,
|
|
n,
|
|
sl,
|
|
lflags)) {
|
|
DBG_INFO(0, "Could not show group \"%s\"", gtype);
|
|
return -1;
|
|
}
|
|
} /* for */
|
|
}
|
|
}
|
|
n=GWEN_XMLNode_Next(n);
|
|
} /* while */
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int GWEN_MsgEngine_ShowMessage(GWEN_MSGENGINE *e,
|
|
const char *typ,
|
|
const char *msgName,
|
|
int msgVersion,
|
|
unsigned int flags) {
|
|
GWEN_XMLNODE *group;
|
|
GWEN_STRINGLIST *sl;
|
|
int i, j;
|
|
const char *p;
|
|
|
|
sl=GWEN_StringList_new();
|
|
|
|
fprintf(stdout, "Message \"%s\" version %d\n",
|
|
msgName, msgVersion);
|
|
for (i=0; i<76; i++)
|
|
fprintf(stdout, "=");
|
|
fprintf(stdout, "\n");
|
|
p=" Variable";
|
|
fprintf(stdout, "%s", p);
|
|
i=GWEN_MSGENGINE_VARNAME_WIDTH-strlen(p);
|
|
for (j=0; j<i; j++)
|
|
fprintf(stdout," ");
|
|
|
|
fprintf(stdout," |");
|
|
p=" Type";
|
|
fprintf(stdout, "%s", p);
|
|
i=GWEN_MSGENGINE_TYPENAME_WIDTH-strlen(p);
|
|
for (j=0; j<i; j++)
|
|
fprintf(stdout," ");
|
|
|
|
fprintf(stdout," | Size | Num | Flags\n");
|
|
for (i=0; i<76; i++)
|
|
fprintf(stdout, "-");
|
|
fprintf(stdout, "\n");
|
|
|
|
group=GWEN_MsgEngine_FindNodeByProperty(e, typ, "id", msgVersion, msgName);
|
|
if (!group) {
|
|
DBG_ERROR(0, "Group \"%s\" not found\n", msgName);
|
|
GWEN_StringList_free(sl);
|
|
return -1;
|
|
}
|
|
|
|
if (GWEN_MsgEngine__ShowGroup(e,
|
|
"",
|
|
group,
|
|
0,
|
|
sl,
|
|
flags)) {
|
|
DBG_INFO(0, "Error showing group \"%s\"", msgName);
|
|
GWEN_StringList_free(sl);
|
|
return -1;
|
|
}
|
|
|
|
GWEN_StringList_free(sl);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int GWEN_MsgEngine__ReadValue(GWEN_MSGENGINE *e,
|
|
GWEN_BUFFER *msgbuf,
|
|
GWEN_XMLNODE *node,
|
|
GWEN_BUFFER *vbuf,
|
|
const char *delimiters) {
|
|
unsigned int minsize;
|
|
unsigned int maxsize;
|
|
unsigned int minnum;
|
|
const char *type;
|
|
int rv;
|
|
|
|
|
|
/* get some sizes */
|
|
minsize=atoi(GWEN_XMLNode_GetProperty(node, "minsize","0"));
|
|
maxsize=atoi(GWEN_XMLNode_GetProperty(node, "maxsize","0"));
|
|
minnum=atoi(GWEN_XMLNode_GetProperty(node, "minnum","1"));
|
|
type=GWEN_XMLNode_GetProperty(node, "type","ASCII");
|
|
|
|
rv=1;
|
|
if (e->typeReadPtr) {
|
|
rv=e->typeReadPtr(e,
|
|
msgbuf,
|
|
node,
|
|
vbuf,
|
|
'\\',
|
|
delimiters);
|
|
}
|
|
if (rv==-1) {
|
|
DBG_INFO(0, "External type reading failed on type \"%s\"", type);
|
|
return -1;
|
|
}
|
|
else if (rv==1) {
|
|
if (strcasecmp(type, "bin")==0) {
|
|
if (GWEN_Buffer_BytesLeft(msgbuf)==0) {
|
|
DBG_ERROR(0, "Premature end of message (@num@ expected)");
|
|
return -1;
|
|
}
|
|
else {
|
|
char lbuffer[16];
|
|
int c;
|
|
char *p;
|
|
int l;
|
|
|
|
p=lbuffer;
|
|
c=GWEN_Buffer_ReadByte(msgbuf);
|
|
if (c!='@') {
|
|
DBG_ERROR(0, "\"@num@\" expected");
|
|
return -1;
|
|
}
|
|
|
|
c=0;
|
|
while(GWEN_Buffer_BytesLeft(msgbuf)>0) {
|
|
c=GWEN_Buffer_ReadByte(msgbuf);
|
|
if (c==-1) {
|
|
DBG_ERROR(0, "\"@\" expected");
|
|
return -1;
|
|
}
|
|
if (c=='@')
|
|
break;
|
|
*p=(char)c;
|
|
p++;
|
|
} /* while */
|
|
*p=0;
|
|
if (c!='@') {
|
|
DBG_ERROR(0, "\"@num@\" expected");
|
|
return -1;
|
|
}
|
|
if (sscanf(lbuffer, "%d", &l)!=1) {
|
|
DBG_ERROR(0, "Bad number format");
|
|
return -1;
|
|
}
|
|
DBG_INFO(0, "Reading binary: %d bytes from pos %d (msgsize=%d)",
|
|
l,
|
|
GWEN_Buffer_GetPos(msgbuf),
|
|
GWEN_Buffer_GetUsedBytes(msgbuf));
|
|
if (GWEN_Buffer_BytesLeft(msgbuf)<l) {
|
|
DBG_ERROR(0, "Premature end of message (binary beyond end)");
|
|
return -1;
|
|
}
|
|
if (GWEN_Buffer_AppendBytes(vbuf,
|
|
GWEN_Buffer_GetPosPointer(msgbuf),
|
|
l)) {
|
|
DBG_DEBUG(0, "Called from here");
|
|
return -1;
|
|
}
|
|
GWEN_Buffer_IncrementPos(msgbuf,l);
|
|
}
|
|
} /* if bin */
|
|
else {
|
|
/* type is not bin */
|
|
int lastWasEscape;
|
|
int isEscaped;
|
|
|
|
isEscaped=0;
|
|
lastWasEscape=0;
|
|
|
|
while(GWEN_Buffer_BytesLeft(msgbuf)) {
|
|
int c;
|
|
|
|
c=GWEN_Buffer_ReadByte(msgbuf);
|
|
if (lastWasEscape) {
|
|
lastWasEscape=0;
|
|
isEscaped=1;
|
|
}
|
|
else {
|
|
isEscaped=0;
|
|
if (c==e->escapeChar) {
|
|
lastWasEscape=1;
|
|
c=-1;
|
|
}
|
|
}
|
|
if (c!=-1) {
|
|
int needsEscape;
|
|
|
|
if (!isEscaped && strchr(delimiters, c)==0) {
|
|
needsEscape=0;
|
|
if (c=='\\' || iscntrl(c))
|
|
needsEscape=1;
|
|
|
|
if (needsEscape) {
|
|
/* write escape char */
|
|
if (GWEN_Buffer_AppendByte(vbuf, '\\')) {
|
|
DBG_DEBUG(0, "Called from here");
|
|
return -1;
|
|
}
|
|
}
|
|
if (GWEN_Buffer_AppendByte(vbuf, c)) {
|
|
DBG_DEBUG(0, "Called from here");
|
|
return -1;
|
|
}
|
|
}
|
|
else {
|
|
/* delimiter found, step back */
|
|
GWEN_Buffer_DecrementPos(msgbuf,1);
|
|
break;
|
|
}
|
|
}
|
|
} /* while */
|
|
if (GWEN_Buffer_AppendByte(vbuf, 0)) {
|
|
DBG_DEBUG(0, "Called from here");
|
|
return -1;
|
|
}
|
|
} /* if !bin */
|
|
} /* if type not external */
|
|
|
|
/* check the value */
|
|
if (GWEN_Buffer_GetUsedBytes(vbuf)==0) {
|
|
DBG_INFO(0, "Datasize is 0");
|
|
if (minnum==0) {
|
|
DBG_INFO(0, "... but thats ok");
|
|
/* value is empty, and that is allowed */
|
|
return 1;
|
|
}
|
|
else {
|
|
DBG_ERROR(0, "Value missing");
|
|
GWEN_XMLNode_Dump(node, stderr, 1);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/* -1 because the trailing zero doesn't count */
|
|
if (minsize!=0 && minsize-1<GWEN_Buffer_GetUsedBytes(vbuf)) {
|
|
DBG_INFO(0, "Value too short (%d<%d).", minsize,
|
|
GWEN_Buffer_GetUsedBytes(vbuf));
|
|
return -1;
|
|
}
|
|
|
|
/* -1 because the trailing zero doesn't count */
|
|
if (maxsize!=0 && GWEN_Buffer_GetUsedBytes(vbuf)-1>maxsize) {
|
|
DBG_INFO(0, "Value too long (%d>%d).",
|
|
GWEN_Buffer_GetUsedBytes(vbuf), maxsize);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int GWEN_MsgEngine__ReadGroup(GWEN_MSGENGINE *e,
|
|
GWEN_BUFFER *msgbuf,
|
|
GWEN_XMLNODE *node,
|
|
GWEN_XMLNODE *rnode,
|
|
GWEN_DB_NODE *gr,
|
|
const char *delimiters) {
|
|
unsigned int minsize;
|
|
unsigned int maxsize;
|
|
unsigned int minnum;
|
|
unsigned int maxnum;
|
|
const char *name;
|
|
const char *p;
|
|
char delimiter;
|
|
char terminator;
|
|
GWEN_XMLNODE *n;
|
|
int abortLoop;
|
|
|
|
/* get some settings */
|
|
if (rnode) {
|
|
/* get delimiter */
|
|
p=GWEN_XMLNode_GetProperty(rnode,
|
|
"delimiter",
|
|
GWEN_XMLNode_GetProperty(node,
|
|
"delimiter",
|
|
""));
|
|
delimiter=*p;
|
|
|
|
/* get terminating char, if any */
|
|
p=GWEN_XMLNode_GetProperty(rnode,
|
|
"terminator",
|
|
GWEN_XMLNode_GetProperty(node,
|
|
"terminator",
|
|
""));
|
|
terminator=*p;
|
|
}
|
|
else {
|
|
/* get delimiter */
|
|
p=GWEN_XMLNode_GetProperty(node,
|
|
"delimiter",
|
|
"");
|
|
delimiter=*p;
|
|
|
|
/* get terminating char, if any */
|
|
p=GWEN_XMLNode_GetProperty(node, "terminator","");
|
|
terminator=*p;
|
|
}
|
|
|
|
DBG_DEBUG(0, "Delimiters are \"%s\" and \"%c\"",
|
|
delimiters, delimiter);
|
|
|
|
n=GWEN_XMLNode_GetChild(node);
|
|
while (n) {
|
|
if (GWEN_XMLNode_GetType(n)==GWEN_XMLNodeTypeTag) {
|
|
const char *type;
|
|
|
|
if (GWEN_Buffer_BytesLeft(msgbuf)==0)
|
|
break;
|
|
//if (strchr(delimiters, msg[*pos]))
|
|
// break;
|
|
|
|
type=GWEN_XMLNode_GetData(n);
|
|
if (strcasecmp(type, "ELEM")==0) {
|
|
unsigned int loopNr;
|
|
|
|
/* get some sizes */
|
|
minsize=atoi(GWEN_XMLNode_GetProperty(n, "minsize","0"));
|
|
maxsize=atoi(GWEN_XMLNode_GetProperty(n, "maxsize","0"));
|
|
minnum=atoi(GWEN_XMLNode_GetProperty(n, "minnum","1"));
|
|
maxnum=atoi(GWEN_XMLNode_GetProperty(n, "maxnum","1"));
|
|
name=GWEN_XMLNode_GetProperty(n, "name", 0);
|
|
|
|
loopNr=0;
|
|
abortLoop=0;
|
|
while(loopNr<maxnum && !abortLoop) {
|
|
int c;
|
|
|
|
DBG_DEBUG(0, "Reading %s", name);
|
|
if (GWEN_Buffer_BytesLeft(msgbuf)==0)
|
|
break;
|
|
c=GWEN_Buffer_PeekByte(msgbuf);
|
|
if (c==-1) {
|
|
DBG_DEBUG(0, "called from here");
|
|
return -1;
|
|
}
|
|
|
|
DBG_DEBUG(0, "Checking delimiter (whether \"%c\" is in \"%s\")",
|
|
c, delimiters);
|
|
if (strchr(delimiters, c)) {
|
|
abortLoop=1;
|
|
DBG_DEBUG(0, "Found delimiter (\"%c\" is in \"%s\")",
|
|
c, delimiters);
|
|
} /* if delimiter found */
|
|
else {
|
|
/* current char is not a delimiter */
|
|
if (name==0) {
|
|
}
|
|
else {
|
|
/* name is given */
|
|
int rv;
|
|
const char *dtype;
|
|
GWEN_BUFFER *vbuf;
|
|
|
|
vbuf=GWEN_Buffer_new(0,
|
|
GWEN_MSGENGINE_MAX_VALUE_LEN,
|
|
0,0);
|
|
DBG_DEBUG(0, "Reading value from here:\n");
|
|
GWEN_Text_DumpString(GWEN_Buffer_GetPosPointer(msgbuf),
|
|
GWEN_Buffer_BytesLeft(msgbuf));
|
|
|
|
rv=GWEN_MsgEngine__ReadValue(e,
|
|
msgbuf,
|
|
n,
|
|
vbuf,
|
|
":+'");
|
|
GWEN_Buffer_SetPos(vbuf, 0);
|
|
if (rv==1) {
|
|
DBG_INFO(0, "Empty value");
|
|
}
|
|
else if (rv==-1) {
|
|
DBG_INFO(0, "Error parsing node \"%s\"", type);
|
|
GWEN_Buffer_free(vbuf);
|
|
return -1;
|
|
}
|
|
|
|
/* special handling for binary data */
|
|
dtype=GWEN_XMLNode_GetProperty(n, "type", "");
|
|
if (GWEN_MsgEngine__IsBinTyp(dtype)) {
|
|
if (e->binTypeReadPtr)
|
|
rv=e->binTypeReadPtr(e, n, gr, vbuf);
|
|
else
|
|
rv=1;
|
|
if (rv==-1) {
|
|
DBG_INFO(0, "Called from here");
|
|
GWEN_Buffer_free(vbuf);
|
|
return -1;
|
|
}
|
|
else if (rv==1) {
|
|
/* bin type not handled, so handle it myself */
|
|
if (GWEN_DB_SetBinValue(gr,
|
|
GWEN_DB_FLAGS_DEFAULT,
|
|
name,
|
|
GWEN_Buffer_GetStart(vbuf),
|
|
GWEN_Buffer_GetUsedBytes(vbuf))) {
|
|
DBG_INFO(0, "Could not set value for \"%s\"", name);
|
|
GWEN_Buffer_free(vbuf);
|
|
return -1;
|
|
}
|
|
}
|
|
} /* if type is bin */
|
|
else if (GWEN_MsgEngine__IsIntTyp(dtype)) {
|
|
int z;
|
|
|
|
if (1!=sscanf(GWEN_Buffer_GetStart(vbuf), "%d", &z)) {
|
|
DBG_INFO(0, "Value for \"%s\" is not an integer",
|
|
name);
|
|
return -1;
|
|
}
|
|
if (GWEN_DB_SetIntValue(gr,
|
|
GWEN_DB_FLAGS_DEFAULT,
|
|
name, z)) {
|
|
DBG_INFO(0, "Could not set int value for \"%s\"", name);
|
|
return -1;
|
|
}
|
|
} /* if type is int */
|
|
else {
|
|
DBG_INFO(0, "Value is \"%s\"",
|
|
GWEN_Buffer_GetStart(vbuf));
|
|
if (GWEN_DB_SetCharValue(gr,
|
|
GWEN_DB_FLAGS_DEFAULT,
|
|
name,
|
|
GWEN_Buffer_GetStart(vbuf))){
|
|
DBG_INFO(0, "Could not set value for \"%s\"", name);
|
|
return -1;
|
|
}
|
|
} /* if !bin */
|
|
GWEN_Buffer_free(vbuf);
|
|
} /* if name is given */
|
|
} /* if current char is not a delimiter */
|
|
|
|
if (GWEN_Buffer_BytesLeft(msgbuf)) {
|
|
if (delimiter) {
|
|
if (GWEN_Buffer_PeekByte(msgbuf)==delimiter) {
|
|
GWEN_Buffer_IncrementPos(msgbuf,1);
|
|
}
|
|
}
|
|
}
|
|
loopNr++;
|
|
} /* while */
|
|
if (loopNr<minnum) {
|
|
DBG_ERROR(0, "Premature end of message (too few ELEM repeats)");
|
|
return -1;
|
|
}
|
|
n=GWEN_XMLNode_Next(n);
|
|
} /* if ELEM */
|
|
else if (strcasecmp(type, "VALUES")==0) {
|
|
n=GWEN_XMLNode_Next(n);
|
|
}
|
|
else {
|
|
/* group tag found */
|
|
GWEN_XMLNODE *gn;
|
|
GWEN_DB_NODE *gcfg;
|
|
const char *gname;
|
|
const char *gtype;
|
|
unsigned int gversion;
|
|
int loopNr;
|
|
|
|
minnum=atoi(GWEN_XMLNode_GetProperty(n, "minnum","1"));
|
|
maxnum=atoi(GWEN_XMLNode_GetProperty(n, "maxnum","1"));
|
|
gversion=atoi(GWEN_XMLNode_GetProperty(n, "version","0"));
|
|
gtype=GWEN_XMLNode_GetProperty(n, "type",0);
|
|
if (!gtype) {
|
|
/* no "type" property, so use this group directly */
|
|
DBG_INFO(0, "<%s> tag has no \"type\" property", type);
|
|
gtype="";
|
|
gn=n;
|
|
}
|
|
else {
|
|
gn=GWEN_MsgEngine_FindNodeByProperty(e, type, "id",
|
|
gversion, gtype);
|
|
if (!gn) {
|
|
DBG_INFO(0, "Definition for type \"%s\" not found", type);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/* get configuration */
|
|
loopNr=0;
|
|
abortLoop=0;
|
|
while(loopNr<maxnum && !abortLoop) {
|
|
DBG_INFO(0, "Reading group type %s", gtype);
|
|
if (GWEN_Buffer_BytesLeft(msgbuf)==0)
|
|
break;
|
|
if (strchr(delimiters, GWEN_Buffer_PeekByte(msgbuf))) {
|
|
abortLoop=1;
|
|
}
|
|
else {
|
|
gname=GWEN_XMLNode_GetProperty(n, "name",0);
|
|
if (gname) {
|
|
gcfg=GWEN_DB_GetGroup(gr,
|
|
GWEN_PATH_FLAGS_NAMECREATE,
|
|
gname);
|
|
if (!gcfg) {
|
|
DBG_ERROR(0, "Could not select group \"%s\"",
|
|
gname);
|
|
return -1;
|
|
}
|
|
} /* if name given */
|
|
else
|
|
gcfg=gr;
|
|
|
|
/* read group */
|
|
DBG_INFO(0, "Reading group \"%s\"", gname);
|
|
if (GWEN_MsgEngine__ReadGroup(e,
|
|
msgbuf,
|
|
gn,
|
|
n,
|
|
gcfg,
|
|
delimiters)) {
|
|
DBG_INFO(0, "Could not read group \"%s\"", gtype);
|
|
return -1;
|
|
}
|
|
}
|
|
if (GWEN_Buffer_BytesLeft(msgbuf)) {
|
|
if (delimiter) {
|
|
if (GWEN_Buffer_PeekByte(msgbuf)==delimiter) {
|
|
GWEN_Buffer_IncrementPos(msgbuf, 1);
|
|
}
|
|
}
|
|
}
|
|
loopNr++;
|
|
} /* while */
|
|
if (loopNr<minnum) {
|
|
DBG_ERROR(0, "Premature end of message (too few group repeats)");
|
|
return -1;
|
|
}
|
|
n=GWEN_XMLNode_Next(n);
|
|
} /* if GROUP */
|
|
} /* if TAG */
|
|
else {
|
|
n=GWEN_XMLNode_Next(n);
|
|
}
|
|
} /* while */
|
|
|
|
/* check whether there still are nodes which have not been read */
|
|
while(n) {
|
|
if (GWEN_XMLNode_GetType(n)==GWEN_XMLNodeTypeTag) {
|
|
if (strcasecmp(GWEN_XMLNode_GetData(n), "ELEM")==0 ||
|
|
strcasecmp(GWEN_XMLNode_GetData(n), "GROUP")==0) {
|
|
unsigned int i;
|
|
|
|
i=atoi(GWEN_XMLNode_GetProperty(n, "minnum", "1"));
|
|
if (i) {
|
|
DBG_ERROR(0, "Premature end of message (still tags to parse)");
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
n=GWEN_XMLNode_Next(n);
|
|
}
|
|
|
|
|
|
if (terminator) {
|
|
/* skip terminator */
|
|
if (GWEN_Buffer_BytesLeft(msgbuf)) {
|
|
if (GWEN_Buffer_PeekByte(msgbuf)==terminator) {
|
|
GWEN_Buffer_IncrementPos(msgbuf, 1);
|
|
}
|
|
else {
|
|
DBG_ERROR(0, "Terminating character missing (pos=%d)",
|
|
GWEN_Buffer_GetPos(msgbuf));
|
|
GWEN_XMLNode_Dump(node, stderr, 1);
|
|
return -1;
|
|
}
|
|
}
|
|
else {
|
|
DBG_ERROR(0, "Terminating character missing");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int GWEN_MsgEngine_ParseMessage(GWEN_MSGENGINE *e,
|
|
GWEN_XMLNODE *group,
|
|
GWEN_BUFFER *msgbuf,
|
|
GWEN_DB_NODE *msgData){
|
|
|
|
if (GWEN_MsgEngine__ReadGroup(e,
|
|
msgbuf,
|
|
group,
|
|
0,
|
|
msgData,
|
|
e->delimiters)) {
|
|
DBG_INFO(0, "Error reading group");
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int GWEN_MsgEngine_SetValue(GWEN_MSGENGINE *e,
|
|
const char *path,
|
|
const char *value){
|
|
assert(e);
|
|
assert(e->globalValues);
|
|
return GWEN_DB_SetCharValue(e->globalValues,
|
|
GWEN_DB_FLAGS_DEFAULT |
|
|
GWEN_DB_FLAGS_OVERWRITE_VARS,
|
|
path, value);
|
|
}
|
|
|
|
|
|
|
|
int GWEN_MsgEngine_SetIntValue(GWEN_MSGENGINE *e,
|
|
const char *path,
|
|
int value){
|
|
assert(e);
|
|
assert(e->globalValues);
|
|
return GWEN_DB_SetIntValue(e->globalValues,
|
|
GWEN_DB_FLAGS_DEFAULT |
|
|
GWEN_DB_FLAGS_OVERWRITE_VARS,
|
|
path, value);
|
|
}
|
|
|
|
|
|
|
|
const char *GWEN_MsgEngine_GetValue(GWEN_MSGENGINE *e,
|
|
const char *path,
|
|
const char *defValue){
|
|
assert(e);
|
|
assert(e->globalValues);
|
|
return GWEN_DB_GetCharValue(e->globalValues,
|
|
path, 0, defValue);
|
|
}
|
|
|
|
|
|
|
|
int GWEN_MsgEngine_GetIntValue(GWEN_MSGENGINE *e,
|
|
const char *path,
|
|
int defValue){
|
|
assert(e);
|
|
assert(e->globalValues);
|
|
return GWEN_DB_GetIntValue(e->globalValues,
|
|
path, 0, defValue);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|