#ifdef _WIN32
#include "xmlrpc_win32.h"
#endif
#include <string.h>
#include <stdlib.h>
#include "xml_to_dandarpc.h"
#include "base64.h"
#define ELEM_METHODCALL "methodCall"
#define ELEM_METHODNAME "methodName"
#define ELEM_METHODRESPONSE "methodResponse"
#define ELEM_ROOT "simpleRPC"
#define ATTR_ARRAY "array"
#define ATTR_BASE64 "base64"
#define ATTR_BOOLEAN "boolean"
#define ATTR_DATETIME "dateTime.iso8601"
#define ATTR_DOUBLE "double"
#define ATTR_ID "id"
#define ATTR_INT "int"
#define ATTR_MIXED "mixed"
#define ATTR_SCALAR "scalar"
#define ATTR_STRING "string"
#define ATTR_STRUCT "struct"
#define ATTR_TYPE "type"
#define ATTR_VECTOR "vector"
#define ATTR_VERSION "version"
#define VAL_VERSION_0_9 "0.9"
XMLRPC_VALUE xml_element_to_DANDARPC_REQUEST_worker(XMLRPC_REQUEST request, XMLRPC_VALUE xCurrent, xml_element* el) {
if(!xCurrent) {
xCurrent = XMLRPC_CreateValueEmpty();
}
if(el->name) {
const char* id = NULL;
const char* type = NULL;
xml_element_attr* attr_iter = Q_Head(&el->attrs);
while(attr_iter) {
if(!strcmp(attr_iter->key, ATTR_ID)) {
id = attr_iter->val;
}
if(!strcmp(attr_iter->key, ATTR_TYPE)) {
type = attr_iter->val;
}
attr_iter = Q_Next(&el->attrs);
}
if(id) {
XMLRPC_SetValueID_Case(xCurrent, id, 0, xmlrpc_case_exact);
}
if(!strcmp(el->name, ATTR_SCALAR)) {
if(!type || !strcmp(type, ATTR_STRING)) {
XMLRPC_SetValueString(xCurrent, el->text.str, el->text.len);
}
else if(!strcmp(type, ATTR_INT)) {
XMLRPC_SetValueInt(xCurrent, atoi(el->text.str));
}
else if(!strcmp(type, ATTR_BOOLEAN)) {
XMLRPC_SetValueBoolean(xCurrent, atoi(el->text.str));
}
else if(!strcmp(type, ATTR_DOUBLE)) {
XMLRPC_SetValueDouble(xCurrent, atof(el->text.str));
}
else if(!strcmp(type, ATTR_DATETIME)) {
XMLRPC_SetValueDateTime_ISO8601(xCurrent, el->text.str);
}
else if(!strcmp(type, ATTR_BASE64)) {
struct buffer_st buf;
base64_decode_xmlrpc(&buf, el->text.str, el->text.len);
XMLRPC_SetValueBase64(xCurrent, buf.data, buf.offset);
buffer_delete(&buf);
}
}
else if(!strcmp(el->name, ATTR_VECTOR)) {
xml_element* iter = (xml_element*)Q_Head(&el->children);
if(!type || !strcmp(type, ATTR_MIXED)) {
XMLRPC_SetIsVector(xCurrent, xmlrpc_vector_mixed);
}
else if(!strcmp(type, ATTR_ARRAY)) {
XMLRPC_SetIsVector(xCurrent, xmlrpc_vector_array);
}
else if(!strcmp(type, ATTR_STRUCT)) {
XMLRPC_SetIsVector(xCurrent, xmlrpc_vector_struct);
}
while( iter ) {
XMLRPC_VALUE xNext = XMLRPC_CreateValueEmpty();
xml_element_to_DANDARPC_REQUEST_worker(request, xNext, iter);
XMLRPC_AddValueToVector(xCurrent, xNext);
iter = (xml_element*)Q_Next(&el->children);
}
}
else {
xml_element* iter = (xml_element*)Q_Head(&el->children);
while( iter ) {
xml_element_to_DANDARPC_REQUEST_worker(request, xCurrent, iter);
iter = (xml_element*)Q_Next(&el->children);
}
if(!strcmp(el->name, ELEM_METHODCALL)) {
if(request) {
XMLRPC_RequestSetRequestType(request, xmlrpc_request_call);
}
}
else if(!strcmp(el->name, ELEM_METHODRESPONSE)) {
if(request) {
XMLRPC_RequestSetRequestType(request, xmlrpc_request_response);
}
}
else if(!strcmp(el->name, ELEM_METHODNAME)) {
if(request) {
XMLRPC_RequestSetMethodName(request, el->text.str);
}
}
}
}
return xCurrent;
}
XMLRPC_VALUE xml_element_to_DANDARPC_VALUE(xml_element* el)
{
return xml_element_to_DANDARPC_REQUEST_worker(NULL, NULL, el);
}
XMLRPC_VALUE xml_element_to_DANDARPC_REQUEST(XMLRPC_REQUEST request, xml_element* el)
{
if(request) {
return XMLRPC_RequestSetData(request, xml_element_to_DANDARPC_REQUEST_worker(request, NULL, el));
}
return NULL;
}
xml_element* DANDARPC_to_xml_element_worker(XMLRPC_REQUEST request, XMLRPC_VALUE node) {
#define BUF_SIZE 512
xml_element* root = NULL;
if(node) {
char buf[BUF_SIZE];
const char* id = XMLRPC_GetValueID(node);
XMLRPC_VALUE_TYPE type = XMLRPC_GetValueType(node);
XMLRPC_REQUEST_OUTPUT_OPTIONS output = XMLRPC_RequestGetOutputOptions(request);
int bNoAddType = (type == xmlrpc_string && request && output && output->xml_elem_opts.verbosity == xml_elem_no_white_space);
xml_element* elem_val = xml_elem_new();
const char* pAttrType = NULL;
xml_element_attr* attr_type = bNoAddType ? NULL : malloc(sizeof(xml_element_attr));
if(attr_type) {
attr_type->key = strdup(ATTR_TYPE);
attr_type->val = 0;
Q_PushTail(&elem_val->attrs, attr_type);
}
elem_val->name = (type == xmlrpc_vector) ? strdup(ATTR_VECTOR) : strdup(ATTR_SCALAR);
if(id && *id) {
xml_element_attr* attr_id = malloc(sizeof(xml_element_attr));
if(attr_id) {
attr_id->key = strdup(ATTR_ID);
attr_id->val = strdup(id);
Q_PushTail(&elem_val->attrs, attr_id);
}
}
switch(type) {
case xmlrpc_string:
pAttrType = ATTR_STRING;
simplestring_addn(&elem_val->text, XMLRPC_GetValueString(node), XMLRPC_GetValueStringLen(node));
break;
case xmlrpc_int:
pAttrType = ATTR_INT;
snprintf(buf, BUF_SIZE, "%i", XMLRPC_GetValueInt(node));
simplestring_add(&elem_val->text, buf);
break;
case xmlrpc_boolean:
pAttrType = ATTR_BOOLEAN;
snprintf(buf, BUF_SIZE, "%i", XMLRPC_GetValueBoolean(node));
simplestring_add(&elem_val->text, buf);
break;
case xmlrpc_double:
pAttrType = ATTR_DOUBLE;
snprintf(buf, BUF_SIZE, "%f", XMLRPC_GetValueDouble(node));
simplestring_add(&elem_val->text, buf);
break;
case xmlrpc_datetime:
pAttrType = ATTR_DATETIME;
simplestring_add(&elem_val->text, XMLRPC_GetValueDateTime_ISO8601(node));
break;
case xmlrpc_base64:
{
struct buffer_st buf;
pAttrType = ATTR_BASE64;
base64_encode_xmlrpc(&buf, XMLRPC_GetValueBase64(node), XMLRPC_GetValueStringLen(node));
simplestring_addn(&elem_val->text, buf.data, buf.offset );
buffer_delete(&buf);
}
break;
case xmlrpc_vector:
{
XMLRPC_VECTOR_TYPE my_type = XMLRPC_GetVectorType(node);
XMLRPC_VALUE xIter = XMLRPC_VectorRewind(node);
switch(my_type) {
case xmlrpc_vector_array:
pAttrType = ATTR_ARRAY;
break;
case xmlrpc_vector_mixed:
pAttrType = ATTR_MIXED;
break;
case xmlrpc_vector_struct:
pAttrType = ATTR_STRUCT;
break;
default:
break;
}
while( xIter ) {
xml_element* next_el = DANDARPC_to_xml_element_worker(request, xIter);
if(next_el) {
Q_PushTail(&elem_val->children, next_el);
}
xIter = XMLRPC_VectorNext(node);
}
}
break;
default:
break;
}
if(pAttrType && attr_type && !bNoAddType) {
attr_type->val = strdup(pAttrType);
}
root = elem_val;
}
return root;
}
xml_element* DANDARPC_VALUE_to_xml_element(XMLRPC_VALUE node) {
return DANDARPC_to_xml_element_worker(NULL, node);
}
xml_element* DANDARPC_REQUEST_to_xml_element(XMLRPC_REQUEST request) {
xml_element* wrapper = NULL;
xml_element* root = NULL;
if(request) {
XMLRPC_REQUEST_TYPE request_type = XMLRPC_RequestGetRequestType(request);
const char* pStr = NULL;
xml_element_attr* version = malloc(sizeof(xml_element_attr));
version->key = strdup(ATTR_VERSION);
version->val = strdup(VAL_VERSION_0_9);
wrapper = xml_elem_new();
if(request_type == xmlrpc_request_response) {
pStr = ELEM_METHODRESPONSE;
}
else if(request_type == xmlrpc_request_call) {
pStr = ELEM_METHODCALL;
}
if(pStr) {
wrapper->name = strdup(pStr);
}
root = xml_elem_new();
root->name = strdup(ELEM_ROOT);
Q_PushTail(&root->attrs, version);
Q_PushTail(&root->children, wrapper);
pStr = XMLRPC_RequestGetMethodName(request);
if(pStr) {
xml_element* method = xml_elem_new();
method->name = strdup(ELEM_METHODNAME);
simplestring_add(&method->text, pStr);
Q_PushTail(&wrapper->children, method);
}
Q_PushTail(&wrapper->children,
DANDARPC_to_xml_element_worker(request, XMLRPC_RequestGetData(request)));
}
return root;
}