Browse Source
Unbundle ext/xmlrpc
Unbundle ext/xmlrpc
According to <https://wiki.php.net/rfc/unbundle_xmlprc> we unbundle ext/xmlrpc.pull/5642/head
80 changed files with 16 additions and 12388 deletions
-
3CONTRIBUTING.md
-
5EXTENSIONS
-
56README.REDIST.BINS
-
1azure/configure.yml
-
1azure/i386/job.yml
-
1azure/macos/job.yml
-
4build/Makefile.gcov
-
1ext/standard/credits_ext.h
-
2ext/xmlrpc/CREDITS
-
5ext/xmlrpc/EXPERIMENTAL
-
103ext/xmlrpc/config.m4
-
20ext/xmlrpc/config.w32
-
21ext/xmlrpc/libxmlrpc/README.md
-
191ext/xmlrpc/libxmlrpc/base64.c
-
37ext/xmlrpc/libxmlrpc/base64.h
-
110ext/xmlrpc/libxmlrpc/encodings.c
-
46ext/xmlrpc/libxmlrpc/encodings.h
-
977ext/xmlrpc/libxmlrpc/queue.c
-
89ext/xmlrpc/libxmlrpc/queue.h
-
264ext/xmlrpc/libxmlrpc/simplestring.c
-
76ext/xmlrpc/libxmlrpc/simplestring.h
-
372ext/xmlrpc/libxmlrpc/system_methods.c
-
87ext/xmlrpc/libxmlrpc/system_methods_private.h
-
763ext/xmlrpc/libxmlrpc/xml_element.c
-
202ext/xmlrpc/libxmlrpc/xml_element.h
-
315ext/xmlrpc/libxmlrpc/xml_to_dandarpc.c
-
44ext/xmlrpc/libxmlrpc/xml_to_dandarpc.h
-
664ext/xmlrpc/libxmlrpc/xml_to_soap.c
-
44ext/xmlrpc/libxmlrpc/xml_to_soap.h
-
407ext/xmlrpc/libxmlrpc/xml_to_xmlrpc.c
-
45ext/xmlrpc/libxmlrpc/xml_to_xmlrpc.h
-
3005ext/xmlrpc/libxmlrpc/xmlrpc.c
-
452ext/xmlrpc/libxmlrpc/xmlrpc.h
-
598ext/xmlrpc/libxmlrpc/xmlrpc_introspection.c
-
98ext/xmlrpc/libxmlrpc/xmlrpc_introspection.h
-
102ext/xmlrpc/libxmlrpc/xmlrpc_introspection_private.h
-
177ext/xmlrpc/libxmlrpc/xmlrpc_private.h
-
72ext/xmlrpc/php_xmlrpc.h
-
51ext/xmlrpc/tests/001.phpt
-
45ext/xmlrpc/tests/002.phpt
-
108ext/xmlrpc/tests/003.phpt
-
18ext/xmlrpc/tests/004.phpt
-
43ext/xmlrpc/tests/005.phpt
-
25ext/xmlrpc/tests/006.phpt
-
25ext/xmlrpc/tests/007.phpt
-
23ext/xmlrpc/tests/bug18916.phpt
-
64ext/xmlrpc/tests/bug37057.phpt
-
25ext/xmlrpc/tests/bug38431.phpt
-
77ext/xmlrpc/tests/bug40576.phpt
-
77ext/xmlrpc/tests/bug40576_64bit.phpt
-
15ext/xmlrpc/tests/bug42189.phpt
-
56ext/xmlrpc/tests/bug42736.phpt
-
51ext/xmlrpc/tests/bug44996.phpt
-
55ext/xmlrpc/tests/bug45226.phpt
-
22ext/xmlrpc/tests/bug45555.phpt
-
34ext/xmlrpc/tests/bug45556.phpt
-
41ext/xmlrpc/tests/bug47818.phpt
-
43ext/xmlrpc/tests/bug50282.phpt
-
117ext/xmlrpc/tests/bug50285.phpt
-
64ext/xmlrpc/tests/bug50761.phpt
-
16ext/xmlrpc/tests/bug51288.phpt
-
16ext/xmlrpc/tests/bug61097.phpt
-
19ext/xmlrpc/tests/bug61264.phpt
-
44ext/xmlrpc/tests/bug68027.phpt
-
14ext/xmlrpc/tests/bug70526.phpt
-
31ext/xmlrpc/tests/bug70728.phpt
-
31ext/xmlrpc/tests/bug70728_64bit.phpt
-
23ext/xmlrpc/tests/bug71501.phpt
-
27ext/xmlrpc/tests/bug72155.phpt
-
36ext/xmlrpc/tests/bug72647.phpt
-
56ext/xmlrpc/tests/bug74975.phpt
-
10ext/xmlrpc/tests/bug77242.phpt
-
17ext/xmlrpc/tests/bug77380.phpt
-
1377ext/xmlrpc/xmlrpc-epi-php.c
-
35ext/xmlrpc/xmlrpc.stub.php
-
109ext/xmlrpc/xmlrpc_arginfo.h
-
1php.ini-development
-
1php.ini-production
-
1scripts/dev/tidy.php
-
1travis/compile.sh
@ -1,2 +0,0 @@ |
|||
xmlrpc |
|||
Dan Libby |
|||
@ -1,5 +0,0 @@ |
|||
this extension is experimental, |
|||
its functions may change their names |
|||
or move to extension all together |
|||
so do not rely to much on them |
|||
you have been warned! |
|||
@ -1,103 +0,0 @@ |
|||
PHP_ARG_WITH([xmlrpc], |
|||
[whether to build with XMLRPC-EPI support], |
|||
[AS_HELP_STRING([[--with-xmlrpc[=DIR]]], |
|||
[Include XMLRPC-EPI support])]) |
|||
|
|||
PHP_ARG_WITH([expat], |
|||
[whether to build with expat support], |
|||
[AS_HELP_STRING([--with-expat], |
|||
[XMLRPC-EPI: use expat instead of libxml2])], |
|||
[no], |
|||
[no]) |
|||
|
|||
PHP_ARG_WITH([iconv-dir], |
|||
[iconv dir for XMLRPC-EPI], |
|||
[AS_HELP_STRING([--with-iconv-dir=DIR], |
|||
[XMLRPC-EPI: iconv dir for XMLRPC-EPI])], |
|||
[no], |
|||
[no]) |
|||
|
|||
if test "$PHP_XMLRPC" != "no"; then |
|||
|
|||
PHP_ADD_EXTENSION_DEP(xmlrpc, libxml) |
|||
PHP_SUBST(XMLRPC_SHARED_LIBADD) |
|||
AC_DEFINE(HAVE_XMLRPC,1,[ ]) |
|||
|
|||
dnl |
|||
dnl Default to libxml2 if --with-expat is not specified. |
|||
dnl |
|||
if test "$PHP_EXPAT" = "no"; then |
|||
|
|||
if test "$PHP_LIBXML" = "no"; then |
|||
AC_MSG_ERROR([XML-RPC extension requires LIBXML extension, add --with-libxml]) |
|||
fi |
|||
|
|||
PHP_SETUP_LIBXML(XMLRPC_SHARED_LIBADD, [ |
|||
if test "$PHP_XML" = "no"; then |
|||
PHP_ADD_SOURCES(ext/xml, compat.c) |
|||
PHP_ADD_BUILD_DIR(ext/xml) |
|||
fi |
|||
]) |
|||
else |
|||
PHP_SETUP_EXPAT([XMLRPC_SHARED_LIBADD]) |
|||
fi |
|||
|
|||
dnl if iconv is shared or missing then we should build iconv ourselves |
|||
if test "$PHP_ICONV_SHARED" = "yes" || test "$PHP_ICONV" = "no"; then |
|||
|
|||
if test "$PHP_ICONV_DIR" != "no"; then |
|||
PHP_ICONV=$PHP_ICONV_DIR |
|||
fi |
|||
|
|||
if test -z "$PHP_ICONV" || test "$PHP_ICONV" = "no"; then |
|||
PHP_ICONV=yes |
|||
fi |
|||
|
|||
PHP_SETUP_ICONV(XMLRPC_SHARED_LIBADD, [], [ |
|||
AC_MSG_ERROR([iconv not found, in order to build xmlrpc you need the iconv library]) |
|||
]) |
|||
fi |
|||
fi |
|||
|
|||
if test "$PHP_XMLRPC" = "yes"; then |
|||
PHP_NEW_EXTENSION(xmlrpc,xmlrpc-epi-php.c libxmlrpc/base64.c \ |
|||
libxmlrpc/simplestring.c libxmlrpc/xml_to_dandarpc.c \ |
|||
libxmlrpc/xmlrpc_introspection.c libxmlrpc/encodings.c \ |
|||
libxmlrpc/system_methods.c libxmlrpc/xml_to_xmlrpc.c \ |
|||
libxmlrpc/queue.c libxmlrpc/xml_element.c libxmlrpc/xmlrpc.c \ |
|||
libxmlrpc/xml_to_soap.c,$ext_shared,, |
|||
-I@ext_srcdir@/libxmlrpc -DVERSION="0.50") |
|||
PHP_ADD_BUILD_DIR($ext_builddir/libxmlrpc) |
|||
XMLRPC_MODULE_TYPE=builtin |
|||
AC_DEFINE(HAVE_XMLRPC_BUNDLED, 1, [ ]) |
|||
|
|||
elif test "$PHP_XMLRPC" != "no"; then |
|||
|
|||
if test -r $PHP_XMLRPC/include/xmlrpc.h; then |
|||
XMLRPC_DIR=$PHP_XMLRPC/include |
|||
elif test -r $PHP_XMLRPC/include/xmlrpc-epi/xmlrpc.h; then |
|||
dnl Some xmlrpc-epi header files have generic file names like queue.h or |
|||
dnl base64.h. Distributions have to create dir for xmlrpc-epi because of |
|||
dnl this. |
|||
XMLRPC_DIR=$PHP_XMLRPC/include/xmlrpc-epi |
|||
else |
|||
AC_MSG_CHECKING(for XMLRPC-EPI in default path) |
|||
for i in /usr/local /usr; do |
|||
if test -r $i/include/xmlrpc.h; then |
|||
XMLRPC_DIR=$i/include |
|||
AC_MSG_RESULT(found in $i) |
|||
break |
|||
fi |
|||
done |
|||
fi |
|||
|
|||
if test -z "$XMLRPC_DIR"; then |
|||
AC_MSG_RESULT(not found) |
|||
AC_MSG_ERROR(Please reinstall the XMLRPC-EPI distribution) |
|||
fi |
|||
|
|||
PHP_ADD_INCLUDE($XMLRPC_DIR) |
|||
PHP_ADD_LIBRARY_WITH_PATH(xmlrpc, $XMLRPC_DIR/$PHP_LIBDIR, XMLRPC_SHARED_LIBADD) |
|||
PHP_NEW_EXTENSION(xmlrpc,xmlrpc-epi-php.c, $ext_shared) |
|||
XMLRPC_MODULE_TYPE=external |
|||
fi |
|||
@ -1,20 +0,0 @@ |
|||
// vim:ft=javascript |
|||
|
|||
ARG_WITH("xmlrpc", "XMLRPC-EPI support", "no"); |
|||
|
|||
if (PHP_XMLRPC != "no") { |
|||
if (CHECK_HEADER_ADD_INCLUDE("xmlrpc.h", "CFLAGS_XMLRPC", configure_module_dirname + "/libxmlrpc") |
|||
&& CHECK_HEADER_ADD_INCLUDE("iconv.h", "CFLAGS_XMLRPC") |
|||
&& CHECK_HEADER_ADD_INCLUDE("libxml/parser.h", "CFLAGS_XMLRPC", PHP_PHP_BUILD + "\\include\\libxml2") |
|||
&& ADD_EXTENSION_DEP('xmlrpc', 'libxml') |
|||
&& ADD_EXTENSION_DEP('xmlrpc', 'xml')) { |
|||
EXTENSION('xmlrpc', 'xmlrpc-epi-php.c', PHP_XMLRPC_SHARED, "-DVERSION=\"0.50\""); |
|||
ADD_SOURCES(configure_module_dirname + "/libxmlrpc", "base64.c simplestring.c xml_to_dandarpc.c \ |
|||
xmlrpc_introspection.c encodings.c system_methods.c xml_to_xmlrpc.c \ |
|||
queue.c xml_element.c xmlrpc.c xml_to_soap.c", "xmlrpc"); |
|||
AC_DEFINE("HAVE_XMLRPC_BUNDLED", 1); |
|||
} else { |
|||
WARNING("xmlrpc support can't be enabled, libraries or headers are missing") |
|||
PHP_XMLRPC = "no"; |
|||
} |
|||
} |
|||
@ -1,21 +0,0 @@ |
|||
# libxmlrpc |
|||
|
|||
This is a fork of the [xmlrpc-epi library](http://xmlrpc-epi.sourceforge.net/) |
|||
written by Dan Libby. |
|||
|
|||
## Original coding conventions |
|||
|
|||
Organization of this directory is moving towards this approach: |
|||
|
|||
* `<module>.h` -- public API and data types |
|||
* `<module>_private.h` -- protected API and data types |
|||
* `<module>.c` -- implementation and private API / types |
|||
|
|||
The rules are: |
|||
|
|||
* `.c` files may include `*_private.h`. |
|||
* `.h` files may not include `*_private.h` |
|||
|
|||
This allows us to have a nicely encapsulated C api with opaque data types and |
|||
private functions that are nonetheless shared between source files without |
|||
redundant extern declarations.. |
|||
@ -1,191 +0,0 @@ |
|||
/* |
|||
|
|||
Encode or decode file as MIME base64 (RFC 1341) |
|||
|
|||
by John Walker |
|||
http://www.fourmilab.ch/ |
|||
|
|||
This program is in the public domain. |
|||
|
|||
*/ |
|||
#include <stdio.h> |
|||
|
|||
/* ENCODE -- Encode binary file into base64. */ |
|||
#include <stdlib.h> |
|||
#include <ctype.h> |
|||
#include <php.h> |
|||
|
|||
#include "base64.h" |
|||
|
|||
static unsigned char dtable[512]; |
|||
|
|||
void buffer_new(struct buffer_st *b) |
|||
{ |
|||
b->length = 512; |
|||
b->data = emalloc(sizeof(char)*(b->length)); |
|||
b->data[0] = 0; |
|||
b->ptr = b->data; |
|||
b->offset = 0; |
|||
} |
|||
|
|||
void buffer_add(struct buffer_st *b, char c) |
|||
{ |
|||
if ((INT_MAX - b->length) <= 512) { |
|||
return; |
|||
} |
|||
*(b->ptr++) = c; |
|||
b->offset++; |
|||
if (b->offset == b->length) { |
|||
b->length += 512; |
|||
b->data = erealloc(b->data, b->length); |
|||
b->ptr = b->data + b->offset; |
|||
} |
|||
} |
|||
|
|||
void buffer_delete(struct buffer_st *b) |
|||
{ |
|||
efree(b->data); |
|||
b->length = 0; |
|||
b->offset = 0; |
|||
b->ptr = NULL; |
|||
b->data = NULL; |
|||
} |
|||
|
|||
void base64_encode_xmlrpc(struct buffer_st *b, const char *source, int length) |
|||
{ |
|||
int i, hiteof = 0; |
|||
int offset = 0; |
|||
|
|||
buffer_new(b); |
|||
|
|||
/* Fill dtable with character encodings. */ |
|||
|
|||
for (i = 0; i < 26; i++) { |
|||
dtable[i] = 'A' + i; |
|||
dtable[26 + i] = 'a' + i; |
|||
} |
|||
for (i = 0; i < 10; i++) { |
|||
dtable[52 + i] = '0' + i; |
|||
} |
|||
dtable[62] = '+'; |
|||
dtable[63] = '/'; |
|||
|
|||
while (!hiteof) { |
|||
unsigned char igroup[3], ogroup[4]; |
|||
int c, n; |
|||
|
|||
igroup[0] = igroup[1] = igroup[2] = 0; |
|||
for (n = 0; n < 3; n++) { |
|||
c = *(source++); |
|||
offset++; |
|||
if (offset > length || offset <= 0) { |
|||
hiteof = 1; |
|||
break; |
|||
} |
|||
igroup[n] = (unsigned char) c; |
|||
} |
|||
if (n > 0) { |
|||
ogroup[0] = dtable[igroup[0] >> 2]; |
|||
ogroup[1] = dtable[((igroup[0] & 3) << 4) | (igroup[1] >> 4)]; |
|||
ogroup[2] = dtable[((igroup[1] & 0xF) << 2) | (igroup[2] >> 6)]; |
|||
ogroup[3] = dtable[igroup[2] & 0x3F]; |
|||
|
|||
/* Replace characters in output stream with "=" pad |
|||
characters if fewer than three characters were |
|||
read from the end of the input stream. */ |
|||
|
|||
if (n < 3) { |
|||
ogroup[3] = '='; |
|||
if (n < 2) { |
|||
ogroup[2] = '='; |
|||
} |
|||
} |
|||
for (i = 0; i < 4; i++) { |
|||
buffer_add(b, ogroup[i]); |
|||
if (!(b->offset % 72)) { |
|||
/* buffer_add(b, '\r'); */ |
|||
buffer_add(b, '\n'); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
/* buffer_add(b, '\r'); */ |
|||
buffer_add(b, '\n'); |
|||
} |
|||
|
|||
void base64_decode_xmlrpc(struct buffer_st *bfr, const char *source, int length) |
|||
{ |
|||
int i; |
|||
int offset = 0; |
|||
int endoffile; |
|||
int count; |
|||
|
|||
buffer_new(bfr); |
|||
|
|||
for (i = 0; i < 255; i++) { |
|||
dtable[i] = 0x80; |
|||
} |
|||
for (i = 'A'; i <= 'Z'; i++) { |
|||
dtable[i] = 0 + (i - 'A'); |
|||
} |
|||
for (i = 'a'; i <= 'z'; i++) { |
|||
dtable[i] = 26 + (i - 'a'); |
|||
} |
|||
for (i = '0'; i <= '9'; i++) { |
|||
dtable[i] = 52 + (i - '0'); |
|||
} |
|||
dtable['+'] = 62; |
|||
dtable['/'] = 63; |
|||
dtable['='] = 0; |
|||
|
|||
endoffile = 0; |
|||
|
|||
/*CONSTANTCONDITION*/ |
|||
while (1) { |
|||
unsigned char a[4], b[4], o[3]; |
|||
|
|||
for (i = 0; i < 4; i++) { |
|||
int c; |
|||
while (1) { |
|||
c = *(source++); |
|||
offset++; |
|||
if (offset > length) endoffile = 1; |
|||
if (isspace(c) || c == '\n' || c == '\r') continue; |
|||
break; |
|||
} |
|||
|
|||
if (endoffile) { |
|||
/* |
|||
if (i > 0) { |
|||
fprintf(stderr, "Input file incomplete.\n"); |
|||
exit(1); |
|||
} |
|||
*/ |
|||
return; |
|||
} |
|||
|
|||
if (dtable[(unsigned char)c] & 0x80) { |
|||
/* |
|||
fprintf(stderr, "Offset %i length %i\n", offset, length); |
|||
fprintf(stderr, "character '%c:%x:%c' in input file.\n", c, c, dtable[c]); |
|||
exit(1); |
|||
*/ |
|||
i--; |
|||
continue; |
|||
} |
|||
a[i] = (unsigned char) c; |
|||
b[i] = (unsigned char) dtable[c]; |
|||
} |
|||
o[0] = (b[0] << 2) | (b[1] >> 4); |
|||
o[1] = (b[1] << 4) | (b[2] >> 2); |
|||
o[2] = (b[2] << 6) | b[3]; |
|||
i = a[2] == '=' ? 1 : (a[3] == '=' ? 2 : 3); |
|||
count = 0; |
|||
while (count < i) { |
|||
buffer_add(bfr, o[count++]); |
|||
} |
|||
if (i < 3) { |
|||
return; |
|||
} |
|||
} |
|||
} |
|||
@ -1,37 +0,0 @@ |
|||
/* |
|||
|
|||
Encode or decode file as MIME base64 (RFC 1341) |
|||
|
|||
by John Walker |
|||
http://www.fourmilab.ch/ |
|||
|
|||
This program is in the public domain. |
|||
|
|||
*/ |
|||
|
|||
|
|||
struct buffer_st { |
|||
char *data; |
|||
int length; |
|||
char *ptr; |
|||
int offset; |
|||
}; |
|||
|
|||
void buffer_new(struct buffer_st *b); |
|||
void buffer_add(struct buffer_st *b, char c); |
|||
void buffer_delete(struct buffer_st *b); |
|||
|
|||
void base64_encode_xmlrpc(struct buffer_st *b, const char *source, int length); |
|||
void base64_decode_xmlrpc(struct buffer_st *b, const char *source, int length); |
|||
|
|||
/* |
|||
#define DEBUG_MALLOC |
|||
*/ |
|||
|
|||
#ifdef DEBUG_MALLOC |
|||
void *_malloc_real(size_t s, char *file, int line); |
|||
void _free_real(void *p, char *file, int line); |
|||
|
|||
#define malloc(s) _malloc_real(s,__FILE__,__LINE__) |
|||
#define free(p) _free_real(p, __FILE__,__LINE__) |
|||
#endif |
|||
@ -1,110 +0,0 @@ |
|||
/* |
|||
This file is part of libXMLRPC - a C library for xml-encoded function calls. |
|||
|
|||
Author: Dan Libby (dan@libby.com) |
|||
Epinions.com may be contacted at feedback@epinions-inc.com |
|||
*/ |
|||
|
|||
/* |
|||
Copyright 2000 Epinions, Inc. |
|||
|
|||
Subject to the following 3 conditions, Epinions, Inc. permits you, free |
|||
of charge, to (a) use, copy, distribute, modify, perform and display this |
|||
software and associated documentation files (the "Software"), and (b) |
|||
permit others to whom the Software is furnished to do so as well. |
|||
|
|||
1) The above copyright notice and this permission notice shall be included |
|||
without modification in all copies or substantial portions of the |
|||
Software. |
|||
|
|||
2) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTY OR CONDITION OF |
|||
ANY KIND, EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION ANY |
|||
IMPLIED WARRANTIES OF ACCURACY, MERCHANTABILITY, FITNESS FOR A PARTICULAR |
|||
PURPOSE OR NONINFRINGEMENT. |
|||
|
|||
3) IN NO EVENT SHALL EPINIONS, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, |
|||
SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT |
|||
OF OR IN CONNECTION WITH THE SOFTWARE (HOWEVER ARISING, INCLUDING |
|||
NEGLIGENCE), EVEN IF EPINIONS, INC. IS AWARE OF THE POSSIBILITY OF SUCH |
|||
DAMAGES. |
|||
|
|||
*/ |
|||
|
|||
#include <php.h> |
|||
|
|||
#include <errno.h> |
|||
#include <string.h> |
|||
|
|||
#ifdef HAVE_GICONV_H |
|||
#include <giconv.h> |
|||
#else |
|||
#include <iconv.h> |
|||
#endif |
|||
|
|||
#include "encodings.h" |
|||
|
|||
#ifndef ICONV_CSNMAXLEN |
|||
#define ICONV_CSNMAXLEN 64 |
|||
#endif |
|||
|
|||
static char* convert(const char* src, int src_len, int *new_len, const char* from_enc, const char* to_enc) { |
|||
char* outbuf = 0; |
|||
|
|||
if(src && src_len && from_enc && to_enc) { |
|||
size_t outlenleft = src_len; |
|||
size_t inlenleft = src_len; |
|||
int outlen = src_len; |
|||
iconv_t ic; |
|||
char* out_ptr = 0; |
|||
|
|||
if(strlen(to_enc) >= ICONV_CSNMAXLEN || strlen(from_enc) >= ICONV_CSNMAXLEN) { |
|||
return NULL; |
|||
} |
|||
ic = iconv_open(to_enc, from_enc); |
|||
if(ic != (iconv_t)-1) { |
|||
size_t st; |
|||
outbuf = (char*)emalloc(outlen + 1); |
|||
|
|||
out_ptr = (char*)outbuf; |
|||
while(inlenleft) { |
|||
st = iconv(ic, (char**)&src, &inlenleft, &out_ptr, &outlenleft); |
|||
if(st == -1) { |
|||
if(errno == E2BIG) { |
|||
int diff = out_ptr - outbuf; |
|||
outlen += inlenleft; |
|||
outlenleft += inlenleft; |
|||
outbuf = (char*)erealloc(outbuf, outlen + 1); |
|||
out_ptr = outbuf + diff; |
|||
} |
|||
else { |
|||
efree(outbuf); |
|||
outbuf = 0; |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
iconv_close(ic); |
|||
} |
|||
outlen -= outlenleft; |
|||
|
|||
if(new_len) { |
|||
*new_len = outbuf ? outlen : 0; |
|||
} |
|||
if(outbuf) { |
|||
outbuf[outlen] = 0; |
|||
} |
|||
} |
|||
return outbuf; |
|||
} |
|||
|
|||
/* returns a new string that must be freed */ |
|||
char* utf8_encode(const char *s, int len, int *newlen, const char* encoding) |
|||
{ |
|||
return convert(s, len, newlen, encoding, "UTF-8"); |
|||
} |
|||
|
|||
/* returns a new string, possibly decoded */ |
|||
char* utf8_decode(const char *s, int len, int *newlen, const char* encoding) |
|||
{ |
|||
return convert(s, len, newlen, "UTF-8", encoding); |
|||
} |
|||
@ -1,46 +0,0 @@ |
|||
/* |
|||
This file is part of libXMLRPC - a C library for xml-encoded function calls. |
|||
|
|||
Author: Dan Libby (dan@libby.com) |
|||
Epinions.com may be contacted at feedback@epinions-inc.com |
|||
*/ |
|||
|
|||
/* |
|||
Copyright 2000 Epinions, Inc. |
|||
|
|||
Subject to the following 3 conditions, Epinions, Inc. permits you, free |
|||
of charge, to (a) use, copy, distribute, modify, perform and display this |
|||
software and associated documentation files (the "Software"), and (b) |
|||
permit others to whom the Software is furnished to do so as well. |
|||
|
|||
1) The above copyright notice and this permission notice shall be included |
|||
without modification in all copies or substantial portions of the |
|||
Software. |
|||
|
|||
2) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTY OR CONDITION OF |
|||
ANY KIND, EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION ANY |
|||
IMPLIED WARRANTIES OF ACCURACY, MERCHANTABILITY, FITNESS FOR A PARTICULAR |
|||
PURPOSE OR NONINFRINGEMENT. |
|||
|
|||
3) IN NO EVENT SHALL EPINIONS, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, |
|||
SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT |
|||
OF OR IN CONNECTION WITH THE SOFTWARE (HOWEVER ARISING, INCLUDING |
|||
NEGLIGENCE), EVEN IF EPINIONS, INC. IS AWARE OF THE POSSIBILITY OF SUCH |
|||
DAMAGES. |
|||
|
|||
*/ |
|||
|
|||
|
|||
#ifndef __ENCODINGS__H |
|||
#define __ENCODINGS__H |
|||
|
|||
/* these defines are for legacy purposes. */ |
|||
#define encoding_utf_8 "UTF-8" |
|||
typedef const char* ENCODING_ID; |
|||
#define utf8_get_encoding_id_string(desired_enc) ((const char*)desired_enc) |
|||
#define utf8_get_encoding_id_from_string(id_string) ((ENCODING_ID)id_string) |
|||
|
|||
char* utf8_encode(const char *s, int len, int *newlen, ENCODING_ID encoding); |
|||
char* utf8_decode(const char *s, int len, int *newlen, ENCODING_ID encoding); |
|||
|
|||
#endif /* __ENCODINGS__H */ |
|||
@ -1,977 +0,0 @@ |
|||
/* |
|||
* Date last modified: Jan 2001 |
|||
* Modifications by Dan Libby (dan@libby.com), including: |
|||
* - various fixes, null checks, etc |
|||
* - addition of Q_Iter funcs, macros |
|||
*/ |
|||
|
|||
|
|||
/*-************************************************************** |
|||
* |
|||
* File : q.c |
|||
* |
|||
* Author: Peter Yard [1993.01.02] -- 02 Jan 1993 |
|||
* |
|||
* Disclaimer: This code is released to the public domain. |
|||
* |
|||
* Description: |
|||
* Generic double ended queue (Deque pronounced DEK) for handling |
|||
* any data types, with sorting. |
|||
* |
|||
* By use of various functions in this module the caller |
|||
* can create stacks, queues, lists, doubly linked lists, |
|||
* sorted lists, indexed lists. All lists are dynamic. |
|||
* |
|||
* It is the responsibility of the caller to malloc and free |
|||
* memory for insertion into the queue. A pointer to the object |
|||
* is used so that not only can any data be used but various kinds |
|||
* of data can be pushed on the same queue if one so wished e.g. |
|||
* various length string literals mixed with pointers to structures |
|||
* or integers etc. |
|||
* |
|||
* Enhancements: |
|||
* A future improvement would be the option of multiple "cursors" |
|||
* so that multiple locations could occur in the one queue to allow |
|||
* placemarkers and additional flexibility. Perhaps even use queue |
|||
* itself to have a list of cursors. |
|||
* |
|||
* Usage: |
|||
* |
|||
* /x init queue x/ |
|||
* queue q; |
|||
* Q_Init(&q); |
|||
* |
|||
* To create a stack : |
|||
* |
|||
* Q_PushHead(&q, &mydata1); /x push x/ |
|||
* Q_PushHead(&q, &mydata2); |
|||
* ..... |
|||
* data_ptr = Q_PopHead(&q); /x pop x/ |
|||
* ..... |
|||
* data_ptr = Q_Head(&q); /x top of stack x/ |
|||
* |
|||
* To create a FIFO: |
|||
* |
|||
* Q_PushHead(&q, &mydata1); |
|||
* ..... |
|||
* data_ptr = Q_PopTail(&q); |
|||
* |
|||
* To create a double list: |
|||
* |
|||
* data_ptr = Q_Head(&q); |
|||
* .... |
|||
* data_ptr = Q_Next(&q); |
|||
* data_ptr = Q_Tail(&q); |
|||
* if (Q_IsEmpty(&q)) .... |
|||
* ..... |
|||
* data_ptr = Q_Previous(&q); |
|||
* |
|||
* To create a sorted list: |
|||
* |
|||
* Q_PushHead(&q, &mydata1); /x push x/ |
|||
* Q_PushHead(&q, &mydata2); |
|||
* ..... |
|||
* if (!Q_Sort(&q, MyFunction)) |
|||
* .. error .. |
|||
* |
|||
* /x fill in key field of mydata1. |
|||
* * NB: Q_Find does linear search |
|||
* x/ |
|||
* |
|||
* if (Q_Find(&q, &mydata1, MyFunction)) |
|||
* { |
|||
* /x found it, queue cursor now at correct record x/ |
|||
* /x can retrieve with x/ |
|||
* data_ptr = Q_Get(&q); |
|||
* |
|||
* /x alter data , write back with x/ |
|||
* Q_Put(&q, data_ptr); |
|||
* } |
|||
* |
|||
* /x Search with binary search x/ |
|||
* if (Q_Seek(&q, &mydata, MyFunction)) |
|||
* /x etc x/ |
|||
* |
|||
* |
|||
****************************************************************/ |
|||
|
|||
#include <stdlib.h> |
|||
#include <php.h> |
|||
#include "queue.h" |
|||
|
|||
static void QuickSort(void *list[], int low, int high, |
|||
int (*Comp)(const void *, const void *)); |
|||
static int Q_BSearch(queue *q, void *key, |
|||
int (*Comp)(const void *, const void *)); |
|||
|
|||
/* The index: a pointer to pointers */ |
|||
|
|||
static void **queue_index; |
|||
static datanode **queue_posn_index; |
|||
|
|||
|
|||
/*** |
|||
* |
|||
** function : Q_Init |
|||
* |
|||
** purpose : Initialise queue object and pointers. |
|||
* |
|||
** parameters : 'queue' pointer. |
|||
* |
|||
** returns : True_ if init successful else False_ |
|||
* |
|||
** comments : |
|||
***/ |
|||
|
|||
int Q_Init(queue *q) |
|||
{ |
|||
if(q) { |
|||
q->head = q->tail = NULL; |
|||
q->cursor = q->head; |
|||
q->size = 0; |
|||
q->sorted = False_; |
|||
} |
|||
|
|||
return True_; |
|||
} |
|||
|
|||
/*** |
|||
* |
|||
** function : Q_AtHead |
|||
* |
|||
** purpose : tests if cursor is at head of queue |
|||
* |
|||
** parameters : 'queue' pointer. |
|||
* |
|||
** returns : boolean - True_ is at head else False_ |
|||
* |
|||
** comments : |
|||
* |
|||
***/ |
|||
|
|||
int Q_AtHead(queue *q) |
|||
{ |
|||
return(q && q->cursor == q->head); |
|||
} |
|||
|
|||
|
|||
/*** |
|||
* |
|||
** function : Q_AtTail |
|||
* |
|||
** purpose : boolean test if cursor at tail of queue |
|||
* |
|||
** parameters : 'queue' pointer to test. |
|||
* |
|||
** returns : True_ or False_ |
|||
* |
|||
** comments : |
|||
* |
|||
***/ |
|||
|
|||
int Q_AtTail(queue *q) |
|||
{ |
|||
return(q && q->cursor == q->tail); |
|||
} |
|||
|
|||
|
|||
/*** |
|||
* |
|||
** function : Q_IsEmpty |
|||
* |
|||
** purpose : test if queue has nothing in it. |
|||
* |
|||
** parameters : 'queue' pointer |
|||
* |
|||
** returns : True_ if IsEmpty queue, else False_ |
|||
* |
|||
** comments : |
|||
* |
|||
***/ |
|||
|
|||
inline int Q_IsEmpty(queue *q) |
|||
{ |
|||
return(!q || q->size == 0); |
|||
} |
|||
|
|||
/*** |
|||
* |
|||
** function : Q_Size |
|||
* |
|||
** purpose : return the number of elements in the queue |
|||
* |
|||
** parameters : queue pointer |
|||
* |
|||
** returns : number of elements |
|||
* |
|||
** comments : |
|||
* |
|||
***/ |
|||
|
|||
int Q_Size(queue *q) |
|||
{ |
|||
return q ? q->size : 0; |
|||
} |
|||
|
|||
|
|||
/*** |
|||
* |
|||
** function : Q_Head |
|||
* |
|||
** purpose : position queue cursor to first element (head) of queue. |
|||
* |
|||
** parameters : 'queue' pointer |
|||
* |
|||
** returns : pointer to data at head. If queue is IsEmpty returns NULL |
|||
* |
|||
** comments : |
|||
* |
|||
***/ |
|||
|
|||
void *Q_Head(queue *q) |
|||
{ |
|||
if(Q_IsEmpty(q)) |
|||
return NULL; |
|||
|
|||
q->cursor = q->head; |
|||
|
|||
return q->cursor->data; |
|||
} |
|||
|
|||
|
|||
/*** |
|||
* |
|||
** function : Q_Tail |
|||
* |
|||
** purpose : locate cursor at tail of queue. |
|||
* |
|||
** parameters : 'queue' pointer |
|||
* |
|||
** returns : pointer to data at tail , if queue IsEmpty returns NULL |
|||
* |
|||
** comments : |
|||
* |
|||
***/ |
|||
|
|||
void *Q_Tail(queue *q) |
|||
{ |
|||
if(Q_IsEmpty(q)) |
|||
return NULL; |
|||
|
|||
q->cursor = q->tail; |
|||
|
|||
return q->cursor->data; |
|||
} |
|||
|
|||
|
|||
/*** |
|||
* |
|||
** function : Q_PushHead |
|||
* |
|||
** purpose : put a data pointer at the head of the queue |
|||
* |
|||
** parameters : 'queue' pointer, void pointer to the data. |
|||
* |
|||
** returns : True_ if success else False_ if unable to push data. |
|||
* |
|||
** comments : |
|||
* |
|||
***/ |
|||
|
|||
int Q_PushHead(queue *q, void *d) |
|||
{ |
|||
if(q && d) { |
|||
node *n; |
|||
datanode *p; |
|||
|
|||
p = emalloc(sizeof(datanode)); |
|||
if(p == NULL) |
|||
return False_; |
|||
|
|||
n = q->head; |
|||
|
|||
q->head = (node*)p; |
|||
q->head->prev = NULL; |
|||
|
|||
if(q->size == 0) { |
|||
q->head->next = NULL; |
|||
q->tail = q->head; |
|||
} |
|||
else { |
|||
q->head->next = (datanode*)n; |
|||
n->prev = q->head; |
|||
} |
|||
|
|||
q->head->data = d; |
|||
q->size++; |
|||
|
|||
q->cursor = q->head; |
|||
|
|||
q->sorted = False_; |
|||
|
|||
return True_; |
|||
} |
|||
return False_; |
|||
} |
|||
|
|||
|
|||
|
|||
/*** |
|||
* |
|||
** function : Q_PushTail |
|||
* |
|||
** purpose : put a data element pointer at the tail of the queue |
|||
* |
|||
** parameters : queue pointer, pointer to the data |
|||
* |
|||
** returns : True_ if data pushed, False_ if data not inserted. |
|||
* |
|||
** comments : |
|||
* |
|||
***/ |
|||
|
|||
int Q_PushTail(queue *q, void *d) |
|||
{ |
|||
if(q && d) { |
|||
node *p; |
|||
datanode *n; |
|||
|
|||
n = emalloc(sizeof(datanode)); |
|||
if(n == NULL) |
|||
return False_; |
|||
|
|||
p = q->tail; |
|||
q->tail = (node *)n; |
|||
|
|||
if(q->size == 0) { |
|||
q->tail->prev = NULL; |
|||
q->head = q->tail; |
|||
} |
|||
else { |
|||
q->tail->prev = (datanode *)p; |
|||
p->next = q->tail; |
|||
} |
|||
|
|||
q->tail->next = NULL; |
|||
|
|||
q->tail->data = d; |
|||
q->cursor = q->tail; |
|||
q->size++; |
|||
|
|||
q->sorted = False_; |
|||
|
|||
return True_; |
|||
} |
|||
return False_; |
|||
} |
|||
|
|||
|
|||
|
|||
/*** |
|||
* |
|||
** function : Q_PopHead |
|||
* |
|||
** purpose : remove and return the top element at the head of the |
|||
* queue. |
|||
* |
|||
** parameters : queue pointer |
|||
* |
|||
** returns : pointer to data element or NULL if queue is IsEmpty. |
|||
* |
|||
** comments : |
|||
* |
|||
***/ |
|||
|
|||
void *Q_PopHead(queue *q) |
|||
{ |
|||
datanode *n; |
|||
void *d; |
|||
|
|||
if(Q_IsEmpty(q)) |
|||
return NULL; |
|||
|
|||
d = q->head->data; |
|||
n = q->head->next; |
|||
efree(q->head); |
|||
|
|||
q->size--; |
|||
|
|||
if(q->size == 0) |
|||
q->head = q->tail = q->cursor = NULL; |
|||
else { |
|||
q->head = (node *)n; |
|||
q->head->prev = NULL; |
|||
q->cursor = q->head; |
|||
} |
|||
|
|||
q->sorted = False_; |
|||
|
|||
return d; |
|||
} |
|||
|
|||
|
|||
/*** |
|||
* |
|||
** function : Q_PopTail |
|||
* |
|||
** purpose : remove element from tail of queue and return data. |
|||
* |
|||
** parameters : queue pointer |
|||
* |
|||
** returns : pointer to data element that was at tail. NULL if queue |
|||
* IsEmpty. |
|||
* |
|||
** comments : |
|||
* |
|||
***/ |
|||
|
|||
void *Q_PopTail(queue *q) |
|||
{ |
|||
datanode *p; |
|||
void *d; |
|||
|
|||
if(Q_IsEmpty(q)) |
|||
return NULL; |
|||
|
|||
d = q->tail->data; |
|||
p = q->tail->prev; |
|||
efree(q->tail); |
|||
q->size--; |
|||
|
|||
if(q->size == 0) |
|||
q->head = q->tail = q->cursor = NULL; |
|||
else { |
|||
q->tail = (node *)p; |
|||
q->tail->next = NULL; |
|||
q->cursor = q->tail; |
|||
} |
|||
|
|||
q->sorted = False_; |
|||
|
|||
return d; |
|||
} |
|||
|
|||
|
|||
|
|||
/*** |
|||
* |
|||
** function : Q_Next |
|||
* |
|||
** purpose : Move to the next element in the queue without popping |
|||
* |
|||
** parameters : queue pointer. |
|||
* |
|||
** returns : pointer to data element of new element or NULL if end |
|||
* of the queue. |
|||
* |
|||
** comments : This uses the cursor for the current position. Q_Next |
|||
* only moves in the direction from the head of the queue |
|||
* to the tail. |
|||
***/ |
|||
|
|||
void *Q_Next(queue *q) |
|||
{ |
|||
if(!q) |
|||
return NULL; |
|||
|
|||
if(!q->cursor || q->cursor->next == NULL) |
|||
return NULL; |
|||
|
|||
q->cursor = (node *)q->cursor->next; |
|||
|
|||
return q->cursor->data ; |
|||
} |
|||
|
|||
|
|||
|
|||
/*** |
|||
* |
|||
** function : Q_Previous |
|||
* |
|||
** purpose : Opposite of Q_Next. Move to next element closer to the |
|||
* head of the queue. |
|||
* |
|||
** parameters : pointer to queue |
|||
* |
|||
** returns : pointer to data of new element else NULL if queue IsEmpty |
|||
* |
|||
** comments : Makes cursor move towards the head of the queue. |
|||
* |
|||
***/ |
|||
|
|||
void *Q_Previous(queue *q) |
|||
{ |
|||
if(!q) |
|||
return NULL; |
|||
|
|||
if(q->cursor->prev == NULL) |
|||
return NULL; |
|||
|
|||
q->cursor = (node *)q->cursor->prev; |
|||
|
|||
return q->cursor->data; |
|||
} |
|||
|
|||
|
|||
void *Q_Iter_Del(queue *q, q_iter iter) |
|||
{ |
|||
void *d; |
|||
datanode *n, *p; |
|||
|
|||
if(!q) |
|||
return NULL; |
|||
|
|||
if(iter == NULL) |
|||
return NULL; |
|||
|
|||
if(iter == (q_iter)q->head) |
|||
return Q_PopHead(q); |
|||
|
|||
if(iter == (q_iter)q->tail) |
|||
return Q_PopTail(q); |
|||
|
|||
n = ((node*)iter)->next; |
|||
p = ((node*)iter)->prev; |
|||
d = ((node*)iter)->data; |
|||
|
|||
efree(iter); |
|||
|
|||
if(p) { |
|||
p->next = n; |
|||
} |
|||
if (q->cursor == (node*)iter) { |
|||
if (p) { |
|||
q->cursor = p; |
|||
} else { |
|||
q->cursor = n; |
|||
} |
|||
} |
|||
|
|||
|
|||
if (n != NULL) { |
|||
n->prev = p; |
|||
} |
|||
|
|||
q->size--; |
|||
|
|||
q->sorted = False_; |
|||
|
|||
return d; |
|||
} |
|||
|
|||
|
|||
|
|||
/*** |
|||
* |
|||
** function : Q_DelCur |
|||
* |
|||
** purpose : Delete the current queue element as pointed to by |
|||
* the cursor. |
|||
* |
|||
** parameters : queue pointer |
|||
* |
|||
** returns : pointer to data element. |
|||
* |
|||
** comments : WARNING! It is the responsibility of the caller to |
|||
* free any memory. Queue cannot distinguish between |
|||
* pointers to literals and malloced memory. |
|||
* |
|||
***/ |
|||
|
|||
void *Q_DelCur(queue* q) { |
|||
if(q) { |
|||
return Q_Iter_Del(q, (q_iter)q->cursor); |
|||
} |
|||
return 0; |
|||
} |
|||
|
|||
|
|||
/*** |
|||
* |
|||
** function : Q_Destroy |
|||
* |
|||
** purpose : Free all queue resources |
|||
* |
|||
** parameters : queue pointer |
|||
* |
|||
** returns : null. |
|||
* |
|||
** comments : WARNING! It is the responsibility of the caller to |
|||
* free any memory. Queue cannot distinguish between |
|||
* pointers to literals and malloced memory. |
|||
* |
|||
***/ |
|||
|
|||
void Q_Destroy(queue *q) |
|||
{ |
|||
while(!Q_IsEmpty(q)) { |
|||
Q_PopHead(q); |
|||
} |
|||
} |
|||
|
|||
|
|||
/*** |
|||
* |
|||
** function : Q_Get |
|||
* |
|||
** purpose : get the pointer to the data at the cursor location |
|||
* |
|||
** parameters : queue pointer |
|||
* |
|||
** returns : data element pointer |
|||
* |
|||
** comments : |
|||
* |
|||
***/ |
|||
|
|||
void *Q_Get(queue *q) |
|||
{ |
|||
if(!q) |
|||
return NULL; |
|||
|
|||
if(q->cursor == NULL) |
|||
return NULL; |
|||
return q->cursor->data; |
|||
} |
|||
|
|||
|
|||
|
|||
/*** |
|||
* |
|||
** function : Q_Put |
|||
* |
|||
** purpose : replace pointer to data with new pointer to data. |
|||
* |
|||
** parameters : queue pointer, data pointer |
|||
* |
|||
** returns : boolean- True_ if successful, False_ if cursor at NULL |
|||
* |
|||
** comments : |
|||
* |
|||
***/ |
|||
|
|||
int Q_Put(queue *q, void *data) |
|||
{ |
|||
if(q && data) { |
|||
if(q->cursor == NULL) |
|||
return False_; |
|||
|
|||
q->cursor->data = data; |
|||
return True_; |
|||
} |
|||
return False_; |
|||
} |
|||
|
|||
|
|||
/*** |
|||
* |
|||
** function : Q_Find |
|||
* |
|||
** purpose : Linear search of queue for match with key in *data |
|||
* |
|||
** parameters : queue pointer q, data pointer with data containing key |
|||
* comparison function here called Comp. |
|||
* |
|||
** returns : True_ if found , False_ if not in queue. |
|||
* |
|||
** comments : Useful for small queues that are constantly changing |
|||
* and would otherwise need constant sorting with the |
|||
* Q_Seek function. |
|||
* For description of Comp see Q_Sort. |
|||
* Queue cursor left on position found item else at end. |
|||
* |
|||
***/ |
|||
|
|||
int Q_Find(queue *q, void *data, |
|||
int (*Comp)(const void *, const void *)) |
|||
{ |
|||
void *d; |
|||
|
|||
if (q == NULL) { |
|||
return False_; |
|||
} |
|||
|
|||
d = Q_Head(q); |
|||
do { |
|||
if(Comp(d, data) == 0) |
|||
return True_; |
|||
d = Q_Next(q); |
|||
} while(!Q_AtTail(q)); |
|||
|
|||
if(Comp(d, data) == 0) |
|||
return True_; |
|||
|
|||
return False_; |
|||
} |
|||
|
|||
/*======== Sorted Queue and Index functions ========= */ |
|||
|
|||
|
|||
static void QuickSort(void *list[], int low, int high, |
|||
int (*Comp)(const void *, const void *)) |
|||
{ |
|||
int flag = 1, i, j; |
|||
void *key, *temp; |
|||
|
|||
if(low < high) { |
|||
i = low; |
|||
j = high + 1; |
|||
|
|||
key = list[ low ]; |
|||
|
|||
while(flag) { |
|||
i++; |
|||
while(Comp(list[i], key) < 0) |
|||
i++; |
|||
|
|||
j--; |
|||
while(Comp(list[j], key) > 0) |
|||
j--; |
|||
|
|||
if(i < j) { |
|||
temp = list[i]; |
|||
list[i] = list[j]; |
|||
list[j] = temp; |
|||
} |
|||
else flag = 0; |
|||
} |
|||
|
|||
temp = list[low]; |
|||
list[low] = list[j]; |
|||
list[j] = temp; |
|||
|
|||
QuickSort(list, low, j-1, Comp); |
|||
QuickSort(list, j+1, high, Comp); |
|||
} |
|||
} |
|||
|
|||
|
|||
/*** |
|||
* |
|||
** function : Q_Sort |
|||
* |
|||
** purpose : sort the queue and allow index style access. |
|||
* |
|||
** parameters : queue pointer, comparison function compatible with |
|||
* with 'qsort'. |
|||
* |
|||
** returns : True_ if sort succeeded. False_ if error occurred. |
|||
* |
|||
** comments : Comp function supplied by caller must return |
|||
* -1 if data1 < data2 |
|||
* 0 if data1 == data2 |
|||
* +1 if data1 > data2 |
|||
* |
|||
* for Comp(data1, data2) |
|||
* |
|||
* If queue is already sorted it frees the memory of the |
|||
* old index and starts again. |
|||
* |
|||
***/ |
|||
|
|||
int Q_Sort(queue *q, int (*Comp)(const void *, const void *)) |
|||
{ |
|||
int i; |
|||
void *d; |
|||
datanode *dn; |
|||
|
|||
/* if already sorted free memory for tag array */ |
|||
|
|||
if(q->sorted) { |
|||
efree(queue_index); |
|||
efree(queue_posn_index); |
|||
q->sorted = False_; |
|||
} |
|||
|
|||
/* Now allocate memory of array, array of pointers */ |
|||
|
|||
queue_index = emalloc(q->size * sizeof(q->cursor->data)); |
|||
if(queue_index == NULL) |
|||
return False_; |
|||
|
|||
queue_posn_index = emalloc(q->size * sizeof(q->cursor)); |
|||
if(queue_posn_index == NULL) { |
|||
efree(queue_index); |
|||
return False_; |
|||
} |
|||
|
|||
/* Walk queue putting pointers into array */ |
|||
|
|||
d = Q_Head(q); |
|||
for(i=0; i < q->size; i++) { |
|||
queue_index[i] = d; |
|||
queue_posn_index[i] = q->cursor; |
|||
d = Q_Next(q); |
|||
} |
|||
|
|||
/* Now sort the index */ |
|||
|
|||
QuickSort(queue_index, 0, q->size - 1, Comp); |
|||
|
|||
/* Rearrange the actual queue into correct order */ |
|||
|
|||
dn = q->head; |
|||
i = 0; |
|||
while(dn != NULL) { |
|||
dn->data = queue_index[i++]; |
|||
dn = dn->next; |
|||
} |
|||
|
|||
/* Re-position to original element */ |
|||
|
|||
if(d != NULL) |
|||
Q_Find(q, d, Comp); |
|||
else Q_Head(q); |
|||
|
|||
q->sorted = True_; |
|||
|
|||
return True_; |
|||
} |
|||
|
|||
|
|||
/*** |
|||
* |
|||
** function : Q_BSearch |
|||
* |
|||
** purpose : binary search of queue index for node containing key |
|||
* |
|||
** parameters : queue pointer 'q', data pointer of key 'key', |
|||
* Comp comparison function. |
|||
* |
|||
** returns : integer index into array of node pointers, |
|||
* or -1 if not found. |
|||
* |
|||
** comments : see Q_Sort for description of 'Comp' function. |
|||
* |
|||
***/ |
|||
|
|||
static int Q_BSearch( queue *q, void *key, |
|||
int (*Comp)(const void *, const void*)) |
|||
{ |
|||
int low, mid, hi, val; |
|||
|
|||
low = 0; |
|||
hi = q->size - 1; |
|||
|
|||
while(low <= hi) { |
|||
mid = (low + hi) / 2; |
|||
val = Comp(key, queue_index[ mid ]); |
|||
|
|||
if(val < 0) |
|||
hi = mid - 1; |
|||
|
|||
else if(val > 0) |
|||
low = mid + 1; |
|||
|
|||
else /* Success */ |
|||
return mid; |
|||
} |
|||
|
|||
/* Not Found */ |
|||
|
|||
return -1; |
|||
} |
|||
|
|||
|
|||
/*** |
|||
* |
|||
** function : Q_Seek |
|||
* |
|||
** purpose : use index to locate data according to key in 'data' |
|||
* |
|||
** parameters : queue pointer 'q', data pointer 'data', Comp comparison |
|||
* function. |
|||
* |
|||
** returns : pointer to data or NULL if could not find it or could |
|||
* not sort queue. |
|||
* |
|||
** comments : see Q_Sort for description of 'Comp' function. |
|||
* |
|||
***/ |
|||
|
|||
void *Q_Seek(queue *q, void *data, int (*Comp)(const void *, const void *)) |
|||
{ |
|||
int idx; |
|||
|
|||
if (q == NULL) { |
|||
return NULL; |
|||
} |
|||
|
|||
if(!q->sorted) { |
|||
if(!Q_Sort(q, Comp)) |
|||
return NULL; |
|||
} |
|||
|
|||
idx = Q_BSearch(q, data, Comp); |
|||
|
|||
if(idx < 0) |
|||
return NULL; |
|||
|
|||
q->cursor = queue_posn_index[idx]; |
|||
|
|||
return queue_index[idx]; |
|||
} |
|||
|
|||
|
|||
|
|||
/*** |
|||
* |
|||
** function : Q_Insert |
|||
* |
|||
** purpose : Insert an element into an indexed queue |
|||
* |
|||
** parameters : queue pointer 'q', data pointer 'data', Comp comparison |
|||
* function. |
|||
* |
|||
** returns : pointer to data or NULL if could not find it or could |
|||
* not sort queue. |
|||
* |
|||
** comments : see Q_Sort for description of 'Comp' function. |
|||
* WARNING! This code can be very slow since each new |
|||
* element means a new Q_Sort. Should only be used for |
|||
* the insertion of the odd element ,not the piecemeal |
|||
* building of an entire queue. |
|||
***/ |
|||
|
|||
int Q_Insert(queue *q, void *data, int (*Comp)(const void *, const void *)) |
|||
{ |
|||
if (q == NULL) { |
|||
return False_; |
|||
} |
|||
|
|||
Q_PushHead(q, data); |
|||
|
|||
if(!Q_Sort(q, Comp)) |
|||
return False_; |
|||
|
|||
return True_; |
|||
} |
|||
|
|||
/* read only funcs for iterating through queue. above funcs modify queue */ |
|||
q_iter Q_Iter_Head(queue *q) { |
|||
return q ? (q_iter)q->head : NULL; |
|||
} |
|||
|
|||
q_iter Q_Iter_Tail(queue *q) { |
|||
return q ? (q_iter)q->tail : NULL; |
|||
} |
|||
|
|||
q_iter Q_Iter_Next(q_iter qi) { |
|||
return qi ? (q_iter)((node*)qi)->next : NULL; |
|||
} |
|||
|
|||
q_iter Q_Iter_Prev(q_iter qi) { |
|||
return qi ? (q_iter)((node*)qi)->prev : NULL; |
|||
} |
|||
|
|||
void * Q_Iter_Get(q_iter qi) { |
|||
return qi ? ((node*)qi)->data : NULL; |
|||
} |
|||
|
|||
int Q_Iter_Put(q_iter qi, void* data) { |
|||
if(qi) { |
|||
((node*)qi)->data = data; |
|||
return True_; |
|||
} |
|||
return False_; |
|||
} |
|||
@ -1,89 +0,0 @@ |
|||
/* |
|||
* Date last modified: Jan 2001 |
|||
* Modifications by Dan Libby (dan@libby.com), including: |
|||
* - various fixes, null checks, etc |
|||
* - addition of Q_Iter funcs, macros |
|||
*/ |
|||
|
|||
/* |
|||
* File : q.h |
|||
* |
|||
* Peter Yard 02 Jan 1993. |
|||
* |
|||
* Disclaimer: This code is released to the public domain. |
|||
*/ |
|||
|
|||
#ifndef Q__H |
|||
#define Q__H |
|||
|
|||
#ifndef False_ |
|||
#define False_ 0 |
|||
#endif |
|||
|
|||
#ifndef True_ |
|||
#define True_ 1 |
|||
#endif |
|||
|
|||
typedef struct nodeptr datanode; |
|||
|
|||
typedef struct nodeptr { |
|||
void *data ; |
|||
datanode *prev, *next ; |
|||
} node ; |
|||
|
|||
/* For external use with Q_Iter* funcs */ |
|||
typedef struct nodeptr* q_iter; |
|||
|
|||
typedef struct { |
|||
node *head, *tail, *cursor; |
|||
int size, sorted, item_deleted; |
|||
} queue; |
|||
|
|||
typedef struct { |
|||
void *dataptr; |
|||
node *loc ; |
|||
} index_elt ; |
|||
|
|||
|
|||
int Q_Init(queue *q); |
|||
void Q_Destroy(queue *q); |
|||
int Q_IsEmpty(queue *q); |
|||
int Q_Size(queue *q); |
|||
int Q_AtHead(queue *q); |
|||
int Q_AtTail(queue *q); |
|||
int Q_PushHead(queue *q, void *d); |
|||
int Q_PushTail(queue *q, void *d); |
|||
void *Q_Head(queue *q); |
|||
void *Q_Tail(queue *q); |
|||
void *Q_PopHead(queue *q); |
|||
void *Q_PopTail(queue *q); |
|||
void *Q_Next(queue *q); |
|||
void *Q_Previous(queue *q); |
|||
void *Q_DelCur(queue *q); |
|||
void *Q_Get(queue *q); |
|||
int Q_Put(queue *q, void *data); |
|||
int Q_Sort(queue *q, int (*Comp)(const void *, const void *)); |
|||
int Q_Find(queue *q, void *data, |
|||
int (*Comp)(const void *, const void *)); |
|||
void *Q_Seek(queue *q, void *data, |
|||
int (*Comp)(const void *, const void *)); |
|||
int Q_Insert(queue *q, void *data, |
|||
int (*Comp)(const void *, const void *)); |
|||
|
|||
/* read only funcs for iterating through queue. above funcs modify queue */ |
|||
q_iter Q_Iter_Head(queue *q); |
|||
q_iter Q_Iter_Tail(queue *q); |
|||
q_iter Q_Iter_Next(q_iter qi); |
|||
q_iter Q_Iter_Prev(q_iter qi); |
|||
void* Q_Iter_Get(q_iter qi); |
|||
int Q_Iter_Put(q_iter qi, void* data); /* not read only! here for completeness. */ |
|||
void* Q_Iter_Del(queue *q, q_iter iter); /* not read only! here for completeness. */ |
|||
|
|||
/* Fast (macro'd) versions of above */ |
|||
#define Q_Iter_Head_F(q) (q ? (q_iter)((queue*)q)->head : NULL) |
|||
#define Q_Iter_Tail_F(q) (q ? (q_iter)((queue*)q)->tail : NULL) |
|||
#define Q_Iter_Next_F(qi) (qi ? (q_iter)((node*)qi)->next : NULL) |
|||
#define Q_Iter_Prev_F(qi) (qi ? (q_iter)((node*)qi)->prev : NULL) |
|||
#define Q_Iter_Get_F(qi) (qi ? ((node*)qi)->data : NULL) |
|||
|
|||
#endif /* Q__H */ |
|||
@ -1,264 +0,0 @@ |
|||
/* |
|||
This file is part of libXMLRPC - a C library for xml-encoded function calls. |
|||
|
|||
Author: Dan Libby (dan@libby.com) |
|||
Epinions.com may be contacted at feedback@epinions-inc.com |
|||
*/ |
|||
|
|||
/* |
|||
Copyright 2000 Epinions, Inc. |
|||
|
|||
Subject to the following 3 conditions, Epinions, Inc. permits you, free |
|||
of charge, to (a) use, copy, distribute, modify, perform and display this |
|||
software and associated documentation files (the "Software"), and (b) |
|||
permit others to whom the Software is furnished to do so as well. |
|||
|
|||
1) The above copyright notice and this permission notice shall be included |
|||
without modification in all copies or substantial portions of the |
|||
Software. |
|||
|
|||
2) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTY OR CONDITION OF |
|||
ANY KIND, EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION ANY |
|||
IMPLIED WARRANTIES OF ACCURACY, MERCHANTABILITY, FITNESS FOR A PARTICULAR |
|||
PURPOSE OR NONINFRINGEMENT. |
|||
|
|||
3) IN NO EVENT SHALL EPINIONS, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, |
|||
SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT |
|||
OF OR IN CONNECTION WITH THE SOFTWARE (HOWEVER ARISING, INCLUDING |
|||
NEGLIGENCE), EVEN IF EPINIONS, INC. IS AWARE OF THE POSSIBILITY OF SUCH |
|||
DAMAGES. |
|||
|
|||
*/ |
|||
|
|||
#include <php.h> |
|||
|
|||
|
|||
#define SIMPLESTRING_INCR 32 |
|||
|
|||
/****h* ABOUT/simplestring |
|||
* NAME |
|||
* simplestring |
|||
* AUTHOR |
|||
* Dan Libby, aka danda (dan@libby.com) |
|||
* CREATION DATE |
|||
* 06/2000 |
|||
* HISTORY |
|||
* $Log$ |
|||
* Revision 1.3 2002/08/22 01:25:50 sniper |
|||
* kill some compile warnings |
|||
* |
|||
* Revision 1.2 2002/07/05 04:43:53 danda |
|||
* merged in updates from SF project. bring php repository up to date with xmlrpc-epi version 0.51 |
|||
* |
|||
* Revision 1.4 2002/02/13 20:58:50 danda |
|||
* patch to make source more windows friendly, contributed by Jeff Lawson |
|||
* |
|||
* Revision 1.3 2001/09/29 21:58:05 danda |
|||
* adding cvs log to history section |
|||
* |
|||
* 10/15/2000 -- danda -- adding robodoc documentation |
|||
* PORTABILITY |
|||
* Coded on RedHat Linux 6.2. Builds on Solaris x86. Should build on just |
|||
* about anything with minor mods. |
|||
* NOTES |
|||
* This code was written primarily for xmlrpc, but has found some other uses. |
|||
* |
|||
* simplestring is, as the name implies, a simple API for dealing with C strings. |
|||
* Why would I write yet another string API? Because I couldn't find any that were |
|||
* a) free / GPL, b) simple/lightweight, c) fast, not doing unnecessary strlens all |
|||
* over the place. So. It is simple, and it seems to work, and it is pretty fast. |
|||
* |
|||
* Oh, and it is also binary safe, ie it can handle strings with embedded NULLs, |
|||
* so long as the real length is passed in. |
|||
* |
|||
* And the masses rejoiced. |
|||
* |
|||
* BUGS |
|||
* there must be some. |
|||
******/ |
|||
|
|||
#include <stdlib.h> |
|||
#include <string.h> |
|||
#include <limits.h> |
|||
#include "simplestring.h" |
|||
|
|||
#define my_free(thing) if(thing) {efree(thing); thing = 0;} |
|||
|
|||
/*----------------------** |
|||
* Begin String Functions * |
|||
*-----------------------*/ |
|||
|
|||
/****f* FUNC/simplestring_init |
|||
* NAME |
|||
* simplestring_init |
|||
* SYNOPSIS |
|||
* void simplestring_init(simplestring* string) |
|||
* FUNCTION |
|||
* initialize string |
|||
* INPUTS |
|||
* string - pointer to a simplestring struct that will be initialized |
|||
* RESULT |
|||
* void |
|||
* NOTES |
|||
* SEE ALSO |
|||
* simplestring_free () |
|||
* simplestring_clear () |
|||
* SOURCE |
|||
*/ |
|||
void simplestring_init(simplestring* string) { |
|||
memset(string, 0, sizeof(simplestring)); |
|||
} |
|||
/******/ |
|||
|
|||
static void simplestring_init_str(simplestring* string) { |
|||
string->str = (char*)emalloc(SIMPLESTRING_INCR); |
|||
if(string->str) { |
|||
string->str[0] = 0; |
|||
string->len = 0; |
|||
string->size = SIMPLESTRING_INCR; |
|||
} |
|||
else { |
|||
string->size = 0; |
|||
} |
|||
} |
|||
|
|||
/****f* FUNC/simplestring_clear |
|||
* NAME |
|||
* simplestring_clear |
|||
* SYNOPSIS |
|||
* void simplestring_clear(simplestring* string) |
|||
* FUNCTION |
|||
* clears contents of a string |
|||
* INPUTS |
|||
* string - the string value to clear |
|||
* RESULT |
|||
* void |
|||
* NOTES |
|||
* This function is very fast as it does not de-allocate any memory. |
|||
* SEE ALSO |
|||
* |
|||
* SOURCE |
|||
*/ |
|||
void simplestring_clear(simplestring* string) { |
|||
if(string->str) { |
|||
string->str[0] = 0; |
|||
} |
|||
string->len = 0; |
|||
} |
|||
/******/ |
|||
|
|||
/****f* FUNC/simplestring_free |
|||
* NAME |
|||
* simplestring_free |
|||
* SYNOPSIS |
|||
* void simplestring_free(simplestring* string) |
|||
* FUNCTION |
|||
* frees contents of a string, if any. Does *not* free the simplestring struct itself. |
|||
* INPUTS |
|||
* string - value containing string to be free'd |
|||
* RESULT |
|||
* void |
|||
* NOTES |
|||
* caller is responsible for allocating and freeing simplestring* struct itself. |
|||
* SEE ALSO |
|||
* simplestring_init () |
|||
* SOURCE |
|||
*/ |
|||
void simplestring_free(simplestring* string) { |
|||
if(string && string->str) { |
|||
my_free(string->str); |
|||
string->len = 0; |
|||
} |
|||
} |
|||
/******/ |
|||
|
|||
#ifndef SIZE_MAX |
|||
#define SIZE_MAX ((size_t)-1) |
|||
#endif |
|||
/****f* FUNC/simplestring_addn |
|||
* NAME |
|||
* simplestring_addn |
|||
* SYNOPSIS |
|||
* void simplestring_addn(simplestring* string, const char* add, int add_len) |
|||
* FUNCTION |
|||
* copies n characters from source to target string |
|||
* INPUTS |
|||
* target - target string |
|||
* source - source string |
|||
* add_len - number of characters to copy |
|||
* RESULT |
|||
* void |
|||
* NOTES |
|||
* SEE ALSO |
|||
* simplestring_add () |
|||
* SOURCE |
|||
*/ |
|||
void simplestring_addn(simplestring* target, const char* source, size_t add_len) { |
|||
size_t newsize = target->size, incr = 0; |
|||
if(target && source) { |
|||
if(!target->str) { |
|||
simplestring_init_str(target); |
|||
} |
|||
|
|||
if((SIZE_MAX - add_len) < target->len || (SIZE_MAX - add_len - 1) < target->len) { |
|||
/* check for overflows, if there's a potential overflow do nothing */ |
|||
return; |
|||
} |
|||
|
|||
if(target->len + add_len + 1 > target->size) { |
|||
/* newsize is current length + new length */ |
|||
newsize = target->len + add_len + 1; |
|||
incr = target->size * 2; |
|||
|
|||
/* align to SIMPLESTRING_INCR increments */ |
|||
if (incr) { |
|||
newsize = newsize - (newsize % incr) + incr; |
|||
} |
|||
if(newsize < (target->len + add_len + 1)) { |
|||
/* some kind of overflow happened */ |
|||
return; |
|||
} |
|||
target->str = (char*)erealloc(target->str, newsize); |
|||
|
|||
target->size = target->str ? newsize : 0; |
|||
} |
|||
|
|||
if(target->str) { |
|||
if(add_len) { |
|||
memcpy(target->str + target->len, source, add_len); |
|||
} |
|||
target->len += add_len; |
|||
target->str[target->len] = 0; /* null terminate */ |
|||
} |
|||
} |
|||
} |
|||
/******/ |
|||
|
|||
/****f* FUNC/simplestring_add |
|||
* NAME |
|||
* simplestring_add |
|||
* SYNOPSIS |
|||
* void simplestring_add(simplestring* string, const char* add) |
|||
* FUNCTION |
|||
* appends a string of unknown length from source to target |
|||
* INPUTS |
|||
* target - the target string to append to |
|||
* source - the source string of unknown length |
|||
* RESULT |
|||
* void |
|||
* NOTES |
|||
* SEE ALSO |
|||
* simplestring_addn () |
|||
* SOURCE |
|||
*/ |
|||
void simplestring_add(simplestring* target, const char* source) { |
|||
if(target && source) { |
|||
simplestring_addn(target, source, strlen(source)); |
|||
} |
|||
} |
|||
/******/ |
|||
|
|||
|
|||
/*---------------------- |
|||
* End String Functions * |
|||
*--------------------**/ |
|||
@ -1,76 +0,0 @@ |
|||
/* |
|||
This file is part of libXMLRPC - a C library for xml-encoded function calls. |
|||
|
|||
Author: Dan Libby (dan@libby.com) |
|||
Epinions.com may be contacted at feedback@epinions-inc.com |
|||
*/ |
|||
|
|||
/* |
|||
Copyright 2000 Epinions, Inc. |
|||
|
|||
Subject to the following 3 conditions, Epinions, Inc. permits you, free |
|||
of charge, to (a) use, copy, distribute, modify, perform and display this |
|||
software and associated documentation files (the "Software"), and (b) |
|||
permit others to whom the Software is furnished to do so as well. |
|||
|
|||
1) The above copyright notice and this permission notice shall be included |
|||
without modification in all copies or substantial portions of the |
|||
Software. |
|||
|
|||
2) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTY OR CONDITION OF |
|||
ANY KIND, EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION ANY |
|||
IMPLIED WARRANTIES OF ACCURACY, MERCHANTABILITY, FITNESS FOR A PARTICULAR |
|||
PURPOSE OR NONINFRINGEMENT. |
|||
|
|||
3) IN NO EVENT SHALL EPINIONS, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, |
|||
SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT |
|||
OF OR IN CONNECTION WITH THE SOFTWARE (HOWEVER ARISING, INCLUDING |
|||
NEGLIGENCE), EVEN IF EPINIONS, INC. IS AWARE OF THE POSSIBILITY OF SUCH |
|||
DAMAGES. |
|||
|
|||
*/ |
|||
|
|||
#ifndef __SIMPLESTRING_H__ |
|||
#define __SIMPLESTRING_H__ |
|||
|
|||
/*-******************************** |
|||
* begin simplestring header stuff * |
|||
**********************************/ |
|||
|
|||
#ifdef __cplusplus |
|||
extern "C" { |
|||
#endif |
|||
|
|||
/****s* struct/simplestring |
|||
* NAME |
|||
* simplestring |
|||
* NOTES |
|||
* represents a string efficiently for fast appending, etc. |
|||
* SOURCE |
|||
*/ |
|||
typedef struct _simplestring { |
|||
char* str; /* string buf */ |
|||
size_t len; /* length of string/buf */ |
|||
size_t size; /* size of allocated buffer */ |
|||
} simplestring; |
|||
/******/ |
|||
|
|||
#ifndef NULL |
|||
#define NULL 0 |
|||
#endif |
|||
|
|||
void simplestring_init(simplestring* string); |
|||
void simplestring_clear(simplestring* string); |
|||
void simplestring_free(simplestring* string); |
|||
void simplestring_add(simplestring* string, const char* add); |
|||
void simplestring_addn(simplestring* string, const char* add, size_t add_len); |
|||
|
|||
#ifdef __cplusplus |
|||
} |
|||
#endif |
|||
|
|||
/*-****************************** |
|||
* end simplestring header stuff * |
|||
********************************/ |
|||
|
|||
#endif /* __SIMPLESTRING_H__ */ |
|||
@ -1,372 +0,0 @@ |
|||
/* |
|||
This file is part of libXMLRPC - a C library for xml-encoded function calls. |
|||
|
|||
Author: Dan Libby (dan@libby.com) |
|||
Epinions.com may be contacted at feedback@epinions-inc.com |
|||
*/ |
|||
|
|||
/* |
|||
Copyright 2001 Epinions, Inc. |
|||
|
|||
Subject to the following 3 conditions, Epinions, Inc. permits you, free |
|||
of charge, to (a) use, copy, distribute, modify, perform and display this |
|||
software and associated documentation files (the "Software"), and (b) |
|||
permit others to whom the Software is furnished to do so as well. |
|||
|
|||
1) The above copyright notice and this permission notice shall be included |
|||
without modification in all copies or substantial portions of the |
|||
Software. |
|||
|
|||
2) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTY OR CONDITION OF |
|||
ANY KIND, EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION ANY |
|||
IMPLIED WARRANTIES OF ACCURACY, MERCHANTABILITY, FITNESS FOR A PARTICULAR |
|||
PURPOSE OR NONINFRINGEMENT. |
|||
|
|||
3) IN NO EVENT SHALL EPINIONS, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, |
|||
SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT |
|||
OF OR IN CONNECTION WITH THE SOFTWARE (HOWEVER ARISING, INCLUDING |
|||
NEGLIGENCE), EVEN IF EPINIONS, INC. IS AWARE OF THE POSSIBILITY OF SUCH |
|||
DAMAGES. |
|||
|
|||
*/ |
|||
|
|||
|
|||
/****h* ABOUT/system_methods |
|||
* AUTHOR |
|||
* Dan Libby, aka danda (dan@libby.com) |
|||
* HISTORY |
|||
* $Log$ |
|||
* Revision 1.7 2001/09/29 21:58:05 danda |
|||
* adding cvs log to history section |
|||
* |
|||
* 4/28/2001 -- danda -- adding system.multicall and separating out system methods. |
|||
* TODO |
|||
* NOTES |
|||
*******/ |
|||
|
|||
|
|||
#include "queue.h" |
|||
#include "xmlrpc.h" |
|||
#include "xmlrpc_private.h" |
|||
#include "xmlrpc_introspection_private.h" |
|||
#include "system_methods_private.h" |
|||
#include <string.h> |
|||
#include <stdlib.h> |
|||
#include <stdarg.h> |
|||
|
|||
|
|||
static const char* xsm_introspection_xml = |
|||
"<?xml version='1.0' ?>" |
|||
|
|||
"<introspection version='1.0'>" |
|||
"<typeList>" |
|||
|
|||
"<typeDescription name='system.value' basetype='struct' desc='description of a value'>" |
|||
"<value type='string' name='name' optional='yes'>value identifier</value>" |
|||
"<value type='string' name='type'>value's xmlrpc or user-defined type</value>" |
|||
"<value type='string' name='description'>value's textual description</value> " |
|||
"<value type='boolean' name='optional'>true if value is optional, else it is required</value> " |
|||
"<value type='any' name='member' optional='yes'>a child of this element. n/a for scalar types</value> " |
|||
"</typeDescription>" |
|||
|
|||
"<typeDescription name='system.valueList' basetype='array' desc='list of value descriptions'>" |
|||
"<value type='system.value'/>" |
|||
"</typeDescription>" |
|||
|
|||
"<typeDescription name='system.stringList' basetype='array' desc='list of strings'>" |
|||
"<value type='string'/>" |
|||
"</typeDescription>" |
|||
|
|||
|
|||
"</typeList>" |
|||
|
|||
"<methodList>" |
|||
|
|||
"<!-- system.describeMethods -->" |
|||
"<methodDescription name='system.describeMethods'>" |
|||
"<author>Dan Libby</author>" |
|||
"<purpose>fully describes the methods and types implemented by this XML-RPC server.</purpose>" |
|||
"<version>1.1</version>" |
|||
"<signatures>" |
|||
"<signature>" |
|||
"<params>" |
|||
"<value type='array' name='methodList' optional='yes' desc='a list of methods to be described. if omitted, all are described.'>" |
|||
"<value type='string'>a valid method name</value>" |
|||
"</value>" |
|||
"</params>" |
|||
"<returns>" |
|||
"<value type='struct' desc='contains methods list and types list'>" |
|||
"<value type='array' name='methodList' desc='a list of methods'>" |
|||
"<value type='struct' desc='representation of a single method'>" |
|||
"<value type='string' name='name'>method name</value>" |
|||
"<value type='string' name='version' optional='yes'>method version</value>" |
|||
"<value type='string' name='author' optional='yes'>method author</value>" |
|||
"<value type='string' name='purpose' optional='yes'>method purpose</value>" |
|||
"<value type='array' name='signatures' desc='list of method signatures'>" |
|||
"<value type='struct' desc='representation of a single signature'>" |
|||
"<value type='system.valueList' name='params' optional='yes'>parameter list</value>" |
|||
"<value type='system.valueList' name='returns' optional='yes'>return value list</value>" |
|||
"</value>" |
|||
"</value>" |
|||
"<value type='system.stringList' name='bugs' optional='yes'>list of known bugs</value>" |
|||
"<value type='system.stringList' name='errors' optional='yes'>list of possible errors and error codes</value>" |
|||
"<value type='system.stringList' name='examples' optional='yes'>list of examples</value>" |
|||
"<value type='system.stringList' name='history' optional='yes'>list of modifications</value>" |
|||
"<value type='system.stringList' name='notes' optional='yes'>list of notes</value>" |
|||
"<value type='system.stringList' name='see' optional='yes'>see also. list of related methods</value>" |
|||
"<value type='system.stringList' name='todo' optional='yes'>list of unimplemented features</value>" |
|||
"</value>" |
|||
"</value>" |
|||
"<value type='array' name='typeList' desc='a list of type descriptions. Typically used for referencing complex types'>" |
|||
"<value type='system.value'>a type description</value>" |
|||
"</value>" |
|||
"</value>" |
|||
"</returns>" |
|||
"</signature>" |
|||
"</signatures>" |
|||
"<see>" |
|||
"<item name='system.listMethods' />" |
|||
"<item name='system.methodSignature' />" |
|||
"<item name='system.methodHelp' />" |
|||
"</see>" |
|||
"<example/>" |
|||
"<error/>" |
|||
"<note/>" |
|||
"<bug/>" |
|||
"<todo/>" |
|||
"</methodDescription>" |
|||
|
|||
"<!-- system.listMethods -->" |
|||
"<methodDescription name='system.listMethods'>" |
|||
"<author>Dan Libby</author>" |
|||
"<purpose>enumerates the methods implemented by this XML-RPC server.</purpose>" |
|||
"<version>1.0</version>" |
|||
"<signatures>" |
|||
"<signature>" |
|||
"<returns>" |
|||
"<value type='array' desc='an array of strings'>" |
|||
"<value type='string'>name of a method implemented by the server.</value>" |
|||
"</value>" |
|||
"</returns>" |
|||
"</signature>" |
|||
"</signatures>" |
|||
"<see>" |
|||
"<item name='system.describeMethods' />" |
|||
"<item name='system.methodSignature' />" |
|||
"<item name='system.methodHelp' />" |
|||
"</see>" |
|||
"<example/>" |
|||
"<error/>" |
|||
"<note/>" |
|||
"<bug/>" |
|||
"<todo/>" |
|||
"</methodDescription>" |
|||
|
|||
"<!-- system.methodHelp -->" |
|||
"<methodDescription name='system.methodHelp'>" |
|||
"<author>Dan Libby</author>" |
|||
"<purpose>provides documentation string for a single method</purpose>" |
|||
"<version>1.0</version>" |
|||
"<signatures>" |
|||
"<signature>" |
|||
"<params>" |
|||
"<value type='string' name='methodName'>name of the method for which documentation is desired</value>" |
|||
"</params>" |
|||
"<returns>" |
|||
"<value type='string'>help text if defined for the method passed, otherwise an empty string</value>" |
|||
"</returns>" |
|||
"</signature>" |
|||
"</signatures>" |
|||
"<see>" |
|||
"<item name='system.listMethods' />" |
|||
"<item name='system.methodSignature' />" |
|||
"<item name='system.methodHelp' />" |
|||
"</see>" |
|||
"<example/>" |
|||
"<error/>" |
|||
"<note/>" |
|||
"<bug/>" |
|||
"<todo/>" |
|||
"</methodDescription>" |
|||
|
|||
"<!-- system.methodSignature -->" |
|||
"<methodDescription name='system.methodSignature'>" |
|||
"<author>Dan Libby</author>" |
|||
"<purpose>provides 1 or more signatures for a single method</purpose>" |
|||
"<version>1.0</version>" |
|||
"<signatures>" |
|||
"<signature>" |
|||
"<params>" |
|||
"<value type='string' name='methodName'>name of the method for which documentation is desired</value>" |
|||
"</params>" |
|||
"<returns>" |
|||
"<value type='array' desc='a list of arrays, each representing a signature'>" |
|||
"<value type='array' desc='a list of strings. the first element represents the method return value. subsequent elements represent parameters.'>" |
|||
"<value type='string'>a string indicating the xmlrpc type of a value. one of: string, int, double, base64, datetime, array, struct</value>" |
|||
"</value>" |
|||
"</value>" |
|||
"</returns>" |
|||
"</signature>" |
|||
"</signatures>" |
|||
"<see>" |
|||
"<item name='system.listMethods' />" |
|||
"<item name='system.methodHelp' />" |
|||
"<item name='system.describeMethods' />" |
|||
"</see>" |
|||
"<example/>" |
|||
"<error/>" |
|||
"<note/>" |
|||
"<bug/>" |
|||
"<todo/>" |
|||
"</methodDescription>" |
|||
|
|||
"<!-- system.multiCall -->" |
|||
"<methodDescription name='system.multiCall'>" |
|||
"<author>Dan Libby</author>" |
|||
"<purpose>executes multiple methods in sequence and returns the results</purpose>" |
|||
"<version>1.0</version>" |
|||
"<signatures>" |
|||
"<signature>" |
|||
"<params>" |
|||
"<value type='array' name='methodList' desc='an array of method call structs'>" |
|||
"<value type='struct' desc='a struct representing a single method call'>" |
|||
"<value type='string' name='methodName' desc='name of the method to be executed'/>" |
|||
"<value type='array' name='params' desc='an array representing the params to a method. sub-elements should match method signature'/>" |
|||
"</value>" |
|||
"</value>" |
|||
"</params>" |
|||
"<returns>" |
|||
"<value type='array' desc='an array of method responses'>" |
|||
"<value type='array' desc='an array containing a single value, which is the method's response'/>" |
|||
"</value>" |
|||
"</returns>" |
|||
"</signature>" |
|||
"</signatures>" |
|||
"<see>" |
|||
"<item name='system.listMethods' />" |
|||
"<item name='system.methodHelp' />" |
|||
"<item name='system.describeMethods' />" |
|||
"</see>" |
|||
"<example/>" |
|||
"<error/>" |
|||
"<note/>" |
|||
"<bug/>" |
|||
"<todo/>" |
|||
"</methodDescription>" |
|||
|
|||
"<!-- system.getCapabilities -->" |
|||
"<methodDescription name='system.getCapabilities'>" |
|||
"<author>Dan Libby</author>" |
|||
"<purpose>returns a list of capabilities supported by this server</purpose>" |
|||
"<version>1.0</version>" |
|||
"<notes><item>spec url: http://groups.yahoo.com/group/xml-rpc/message/2897</item></notes>" |
|||
"<signatures>" |
|||
"<signature>" |
|||
"<returns>" |
|||
"<value type='struct' desc='list of capabilities, each with a unique key defined by the capability's spec'>" |
|||
"<value type='struct' desc='definition of a single capability'>" |
|||
"<value type='string' name='specURL'>www address of the specification defining this capability</value>" |
|||
"<value type='int' name='specVersion'>version of the spec that this server's implementation conforms to</value>" |
|||
"</value>" |
|||
"</value>" |
|||
"</returns>" |
|||
"</signature>" |
|||
"</signatures>" |
|||
"<see>" |
|||
"<item name='system.listMethods' />" |
|||
"<item name='system.methodHelp' />" |
|||
"<item name='system.describeMethods' />" |
|||
"</see>" |
|||
"<example/>" |
|||
"<error/>" |
|||
"<note/>" |
|||
"<bug/>" |
|||
"<todo/>" |
|||
"</methodDescription>" |
|||
|
|||
"</methodList>" |
|||
"</introspection>"; |
|||
|
|||
|
|||
/* forward declarations for static (non public, non api) funcs */ |
|||
static XMLRPC_VALUE xsm_system_multicall_cb(XMLRPC_SERVER server, XMLRPC_REQUEST input, void* userData); |
|||
static XMLRPC_VALUE xsm_system_get_capabilities_cb(XMLRPC_SERVER server, XMLRPC_REQUEST input, void* userData); |
|||
|
|||
/*-******************* |
|||
* System Methods API * |
|||
*********************/ |
|||
|
|||
static void xsm_lazy_doc_methods_cb(XMLRPC_SERVER server, void* userData) { |
|||
XMLRPC_VALUE xDesc = XMLRPC_IntrospectionCreateDescription(xsm_introspection_xml, NULL); |
|||
XMLRPC_ServerAddIntrospectionData(server, xDesc); |
|||
XMLRPC_CleanupValue(xDesc); |
|||
} |
|||
|
|||
void xsm_register(XMLRPC_SERVER server) { |
|||
xi_register_system_methods(server); |
|||
|
|||
XMLRPC_ServerRegisterMethod(server, xsm_token_system_multicall, xsm_system_multicall_cb); |
|||
XMLRPC_ServerRegisterMethod(server, xsm_token_system_get_capabilities, xsm_system_get_capabilities_cb); |
|||
|
|||
/* callback for documentation generation should it be requested */ |
|||
XMLRPC_ServerRegisterIntrospectionCallback(server, xsm_lazy_doc_methods_cb); |
|||
} |
|||
|
|||
XMLRPC_VALUE xsm_system_multicall_cb(XMLRPC_SERVER server, XMLRPC_REQUEST input, void* userData) { |
|||
XMLRPC_VALUE xArray = XMLRPC_VectorRewind(XMLRPC_RequestGetData(input)); |
|||
XMLRPC_VALUE xReturn = XMLRPC_CreateVector(0, xmlrpc_vector_array); |
|||
|
|||
if (xArray) { |
|||
XMLRPC_VALUE xMethodIter = XMLRPC_VectorRewind(xArray); |
|||
|
|||
while (xMethodIter) { |
|||
XMLRPC_REQUEST request = XMLRPC_RequestNew(); |
|||
if(request) { |
|||
const char* methodName = XMLRPC_VectorGetStringWithID(xMethodIter, "methodName"); |
|||
XMLRPC_VALUE params = XMLRPC_VectorGetValueWithID(xMethodIter, "params"); |
|||
|
|||
if(methodName && params) { |
|||
XMLRPC_VALUE xRandomArray = XMLRPC_CreateVector(0, xmlrpc_vector_array); |
|||
XMLRPC_RequestSetMethodName(request, methodName); |
|||
XMLRPC_RequestSetData(request, params); |
|||
XMLRPC_RequestSetRequestType(request, xmlrpc_request_call); |
|||
|
|||
XMLRPC_AddValueToVector(xRandomArray, |
|||
XMLRPC_ServerCallMethod(server, request, userData)); |
|||
|
|||
XMLRPC_AddValueToVector(xReturn, xRandomArray); |
|||
} |
|||
XMLRPC_RequestFree(request, 1); |
|||
} |
|||
xMethodIter = XMLRPC_VectorNext(xArray); |
|||
} |
|||
} |
|||
return xReturn; |
|||
} |
|||
|
|||
|
|||
XMLRPC_VALUE xsm_system_get_capabilities_cb(XMLRPC_SERVER server, XMLRPC_REQUEST input, void* userData) { |
|||
XMLRPC_VALUE xReturn = XMLRPC_CreateVector(0, xmlrpc_vector_struct); |
|||
XMLRPC_VALUE xFaults = XMLRPC_CreateVector("faults_interop", xmlrpc_vector_struct); |
|||
XMLRPC_VALUE xIntro = XMLRPC_CreateVector("introspection", xmlrpc_vector_struct); |
|||
|
|||
/* support for fault spec */ |
|||
XMLRPC_VectorAppendString(xFaults, "specURL", "http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php", 0); |
|||
XMLRPC_VectorAppendInt(xFaults, "specVersion", 20010516); |
|||
|
|||
/* support for introspection spec */ |
|||
XMLRPC_VectorAppendString(xIntro, "specURL", "http://xmlrpc-epi.sourceforge.net/specs/rfc.introspection.php", 0); |
|||
XMLRPC_VectorAppendInt(xIntro, "specVersion", 20010516); |
|||
|
|||
XMLRPC_AddValuesToVector(xReturn, |
|||
xFaults, |
|||
xIntro, |
|||
NULL); |
|||
|
|||
return xReturn; |
|||
|
|||
} |
|||
|
|||
/*-*********************** |
|||
* End System Methods API * |
|||
*************************/ |
|||
@ -1,87 +0,0 @@ |
|||
/* |
|||
This file is part of libXMLRPC - a C library for xml-encoded function calls. |
|||
|
|||
Author: Dan Libby (dan@libby.com) |
|||
Epinions.com may be contacted at feedback@epinions-inc.com |
|||
*/ |
|||
|
|||
/* |
|||
Copyright 2001 Dan Libby, Epinions, Inc. |
|||
|
|||
Subject to the following 3 conditions, Epinions, Inc. permits you, free |
|||
of charge, to (a) use, copy, distribute, modify, perform and display this |
|||
software and associated documentation files (the "Software"), and (b) |
|||
permit others to whom the Software is furnished to do so as well. |
|||
|
|||
1) The above copyright notice and this permission notice shall be included |
|||
without modification in all copies or substantial portions of the |
|||
Software. |
|||
|
|||
2) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTY OR CONDITION OF |
|||
ANY KIND, EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION ANY |
|||
IMPLIED WARRANTIES OF ACCURACY, MERCHANTABILITY, FITNESS FOR A PARTICULAR |
|||
PURPOSE OR NONINFRINGEMENT. |
|||
|
|||
3) IN NO EVENT SHALL EPINIONS, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, |
|||
SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT |
|||
OF OR IN CONNECTION WITH THE SOFTWARE (HOWEVER ARISING, INCLUDING |
|||
NEGLIGENCE), EVEN IF EPINIONS, INC. IS AWARE OF THE POSSIBILITY OF SUCH |
|||
DAMAGES. |
|||
|
|||
*/ |
|||
|
|||
/* IMPORTANT! |
|||
* |
|||
* only non-public things should be in this file. It is fine for any .c file |
|||
* in xmlrpc/src to include it, but users of the public API should never |
|||
* include it, and thus *.h files that are part of the public API should |
|||
* never include it, or they would break if this file is not present. |
|||
*/ |
|||
|
|||
|
|||
#ifndef __SYSTEM_METHODS_PRIVATE_H |
|||
/* |
|||
* Avoid include redundancy. |
|||
*/ |
|||
#define __SYSTEM_METHODS_PRIVATE_H |
|||
|
|||
/*---------------------------------------------------------------------------- |
|||
* system_methods_private.h |
|||
* |
|||
* Purpose: |
|||
* define non-public system.* methods |
|||
* Comments: |
|||
* xsm = xmlrpc system methods |
|||
*/ |
|||
|
|||
/*---------------------------------------------------------------------------- |
|||
* Constants |
|||
*/ |
|||
#define xsm_token_system_multicall "system.multiCall" |
|||
#define xsm_token_system_get_capabilities "system.getCapabilities" |
|||
|
|||
|
|||
/*---------------------------------------------------------------------------- |
|||
* Includes |
|||
*/ |
|||
|
|||
/*---------------------------------------------------------------------------- |
|||
* Structures |
|||
*/ |
|||
|
|||
/*---------------------------------------------------------------------------- |
|||
* Globals |
|||
*/ |
|||
|
|||
/*---------------------------------------------------------------------------- |
|||
* Functions |
|||
*/ |
|||
void xsm_register(XMLRPC_SERVER server); |
|||
int xsm_is_system_method(XMLRPC_Callback cb); |
|||
|
|||
/*---------------------------------------------------------------------------- |
|||
* Macros |
|||
*/ |
|||
|
|||
|
|||
#endif /* __SYSTEM_METHODS_PRIVATE_H */ |
|||
@ -1,763 +0,0 @@ |
|||
/* |
|||
This file is part of libXMLRPC - a C library for xml-encoded function calls. |
|||
|
|||
Author: Dan Libby (dan@libby.com) |
|||
Epinions.com may be contacted at feedback@epinions-inc.com |
|||
*/ |
|||
|
|||
/* |
|||
Copyright 2000 Epinions, Inc. |
|||
|
|||
Subject to the following 3 conditions, Epinions, Inc. permits you, free |
|||
of charge, to (a) use, copy, distribute, modify, perform and display this |
|||
software and associated documentation files (the "Software"), and (b) |
|||
permit others to whom the Software is furnished to do so as well. |
|||
|
|||
1) The above copyright notice and this permission notice shall be included |
|||
without modification in all copies or substantial portions of the |
|||
Software. |
|||
|
|||
2) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTY OR CONDITION OF |
|||
ANY KIND, EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION ANY |
|||
IMPLIED WARRANTIES OF ACCURACY, MERCHANTABILITY, FITNESS FOR A PARTICULAR |
|||
PURPOSE OR NONINFRINGEMENT. |
|||
|
|||
3) IN NO EVENT SHALL EPINIONS, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, |
|||
SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT |
|||
OF OR IN CONNECTION WITH THE SOFTWARE (HOWEVER ARISING, INCLUDING |
|||
NEGLIGENCE), EVEN IF EPINIONS, INC. IS AWARE OF THE POSSIBILITY OF SUCH |
|||
DAMAGES. |
|||
|
|||
*/ |
|||
|
|||
|
|||
/****h* ABOUT/xml_element |
|||
* NAME |
|||
* xml_element |
|||
* AUTHOR |
|||
* Dan Libby, aka danda (dan@libby.com) |
|||
* CREATION DATE |
|||
* 06/2000 |
|||
* HISTORY |
|||
* $Log$ |
|||
* Revision 1.9.4.1.2.1 2008/12/09 17:22:12 iliaa |
|||
* |
|||
* MFH: Fixed bug #46746 (xmlrpc_decode_request outputs non-suppressable error |
|||
* when given bad data). |
|||
* |
|||
* Revision 1.9.4.1 2006/07/30 11:34:02 tony2001 |
|||
* MFH: fix compile warnings (#38257) |
|||
* |
|||
* Revision 1.9 2005/04/22 11:06:53 jorton |
|||
* Fixed bug #32797 (invalid C code in xmlrpc extension). |
|||
* |
|||
* Revision 1.8 2005/03/28 00:07:24 edink |
|||
* Reshufle includes to make it compile on windows |
|||
* |
|||
* Revision 1.7 2005/03/26 03:13:58 sniper |
|||
* - Made it possible to build ext/xmlrpc with libxml2 |
|||
* |
|||
* Revision 1.6 2004/06/01 20:16:06 iliaa |
|||
* Fixed bug #28597 (xmlrpc_encode_request() incorrectly encodes chars in |
|||
* 200-210 range). |
|||
* Patch by: fernando dot nemec at folha dot com dot br |
|||
* |
|||
* Revision 1.5 2003/12/16 21:00:21 sniper |
|||
* Fix some compile warnings (patch by Joe Orton) |
|||
* |
|||
* Revision 1.4 2002/11/26 23:01:16 fmk |
|||
* removing unused variables |
|||
* |
|||
* Revision 1.3 2002/07/05 04:43:53 danda |
|||
* merged in updates from SF project. bring php repository up to date with xmlrpc-epi version 0.51 |
|||
* |
|||
* Revision 1.9 2002/07/03 20:54:30 danda |
|||
* root element should not have a parent. patch from anon SF user |
|||
* |
|||
* Revision 1.8 2002/05/23 17:46:51 danda |
|||
* patch from mukund - fix non utf-8 encoding conversions |
|||
* |
|||
* Revision 1.7 2002/02/13 20:58:50 danda |
|||
* patch to make source more windows friendly, contributed by Jeff Lawson |
|||
* |
|||
* Revision 1.6 2002/01/08 01:06:55 danda |
|||
* enable <?xml version="1.0"?> format for parsers that are very picky. |
|||
* |
|||
* Revision 1.5 2001/09/29 21:58:05 danda |
|||
* adding cvs log to history section |
|||
* |
|||
* 10/15/2000 -- danda -- adding robodoc documentation |
|||
* TODO |
|||
* Nicer external API. Get rid of macros. Make opaque types, etc. |
|||
* PORTABILITY |
|||
* Coded on RedHat Linux 6.2. Builds on Solaris x86. Should build on just |
|||
* about anything with minor mods. |
|||
* NOTES |
|||
* This code incorporates ideas from expat-ensor from http://xml.ensor.org. |
|||
* |
|||
* It was coded primarily to act as a go-between for expat and xmlrpc. To this |
|||
* end, it stores xml elements, their sub-elements, and their attributes in an |
|||
* in-memory tree. When expat is done parsing, the tree can be walked, thus |
|||
* retrieving the values. The code can also be used to build a tree via API then |
|||
* write out the tree to a buffer, thus "serializing" the xml. |
|||
* |
|||
* It turns out this is useful for other purposes, such as parsing config files. |
|||
* YMMV. |
|||
* |
|||
* Some Features: |
|||
* - output option for xml escaping data. Choices include no escaping, entity escaping, |
|||
* or CDATA sections. |
|||
* - output option for character encoding. Defaults to (none) utf-8. |
|||
* - output option for verbosity/readability. ultra-compact, newlines, pretty/level indented. |
|||
* |
|||
* BUGS |
|||
* there must be some. |
|||
******/ |
|||
|
|||
#include "ext/xml/expat_compat.h" |
|||
#include <stdlib.h> |
|||
#include <string.h> |
|||
#include <ctype.h> |
|||
|
|||
#include "xml_element.h" |
|||
#include "queue.h" |
|||
#include "encodings.h" |
|||
|
|||
#define my_free(thing) if(thing) {efree(thing); thing = NULL;} |
|||
|
|||
#define XML_DECL_START "<?xml" |
|||
#define XML_DECL_START_LEN sizeof(XML_DECL_START) - 1 |
|||
#define XML_DECL_VERSION "version=\"1.0\"" |
|||
#define XML_DECL_VERSION_LEN sizeof(XML_DECL_VERSION) - 1 |
|||
#define XML_DECL_ENCODING_ATTR "encoding" |
|||
#define XML_DECL_ENCODING_ATTR_LEN sizeof(XML_DECL_ENCODING_ATTR) - 1 |
|||
#define XML_DECL_ENCODING_DEFAULT "utf-8" |
|||
#define XML_DECL_ENCODING_DEFAULT_LEN sizeof(XML_DECL_ENCODING_DEFAULT) - 1 |
|||
#define XML_DECL_END "?>" |
|||
#define XML_DECL_END_LEN sizeof(XML_DECL_END) - 1 |
|||
#define START_TOKEN_BEGIN "<" |
|||
#define START_TOKEN_BEGIN_LEN sizeof(START_TOKEN_BEGIN) - 1 |
|||
#define START_TOKEN_END ">" |
|||
#define START_TOKEN_END_LEN sizeof(START_TOKEN_END) - 1 |
|||
#define EMPTY_START_TOKEN_END "/>" |
|||
#define EMPTY_START_TOKEN_END_LEN sizeof(EMPTY_START_TOKEN_END) - 1 |
|||
#define END_TOKEN_BEGIN "</" |
|||
#define END_TOKEN_BEGIN_LEN sizeof(END_TOKEN_BEGIN) - 1 |
|||
#define END_TOKEN_END ">" |
|||
#define END_TOKEN_END_LEN sizeof(END_TOKEN_END) - 1 |
|||
#define ATTR_DELIMITER "\"" |
|||
#define ATTR_DELIMITER_LEN sizeof(ATTR_DELIMITER) - 1 |
|||
#define CDATA_BEGIN "<![CDATA[" |
|||
#define CDATA_BEGIN_LEN sizeof(CDATA_BEGIN) - 1 |
|||
#define CDATA_END "]]>" |
|||
#define CDATA_END_LEN sizeof(CDATA_END) - 1 |
|||
#define EQUALS "=" |
|||
#define EQUALS_LEN sizeof(EQUALS) - 1 |
|||
#define WHITESPACE " " |
|||
#define WHITESPACE_LEN sizeof(WHITESPACE) - 1 |
|||
#define NEWLINE "\n" |
|||
#define NEWLINE_LEN sizeof(NEWLINE) - 1 |
|||
#define MAX_VAL_BUF 144 |
|||
#define SCALAR_STR "SCALAR" |
|||
#define SCALAR_STR_LEN sizeof(SCALAR_STR) - 1 |
|||
#define VECTOR_STR "VECTOR" |
|||
#define VECTOR_STR_LEN sizeof(VECTOR_STR) - 1 |
|||
#define RESPONSE_STR "RESPONSE" |
|||
#define RESPONSE_STR_LEN sizeof(RESPONSE_STR) - 1 |
|||
|
|||
|
|||
/*----------------------------- |
|||
- Begin xml_element Functions - |
|||
-----------------------------*/ |
|||
|
|||
/****f* xml_element/xml_elem_free_non_recurse |
|||
* NAME |
|||
* xml_elem_free_non_recurse |
|||
* SYNOPSIS |
|||
* void xml_elem_free_non_recurse(xml_element* root) |
|||
* FUNCTION |
|||
* free a single xml element. child elements will not be freed. |
|||
* INPUTS |
|||
* root - the element to free |
|||
* RESULT |
|||
* void |
|||
* NOTES |
|||
* SEE ALSO |
|||
* xml_elem_free () |
|||
* xml_elem_new () |
|||
* SOURCE |
|||
*/ |
|||
void xml_elem_free_non_recurse(xml_element* root) { |
|||
if(root) { |
|||
xml_element_attr* attrs = Q_Head(&root->attrs); |
|||
while(attrs) { |
|||
my_free(attrs->key); |
|||
my_free(attrs->val); |
|||
my_free(attrs); |
|||
attrs = Q_Next(&root->attrs); |
|||
} |
|||
|
|||
Q_Destroy(&root->children); |
|||
Q_Destroy(&root->attrs); |
|||
if(root->name) { |
|||
efree((char *)root->name); |
|||
root->name = NULL; |
|||
} |
|||
simplestring_free(&root->text); |
|||
my_free(root); |
|||
} |
|||
} |
|||
/******/ |
|||
|
|||
/****f* xml_element/xml_elem_free |
|||
* NAME |
|||
* xml_elem_free |
|||
* SYNOPSIS |
|||
* void xml_elem_free(xml_element* root) |
|||
* FUNCTION |
|||
* free an xml element and all of its child elements |
|||
* INPUTS |
|||
* root - the root of an xml tree you would like to free |
|||
* RESULT |
|||
* void |
|||
* NOTES |
|||
* SEE ALSO |
|||
* xml_elem_free_non_recurse () |
|||
* xml_elem_new () |
|||
* SOURCE |
|||
*/ |
|||
void xml_elem_free(xml_element* root) { |
|||
if(root) { |
|||
xml_element* kids = Q_Head(&root->children); |
|||
while(kids) { |
|||
xml_elem_free(kids); |
|||
kids = Q_Next(&root->children); |
|||
} |
|||
xml_elem_free_non_recurse(root); |
|||
} |
|||
} |
|||
/******/ |
|||
|
|||
/****f* xml_element/xml_elem_new |
|||
* NAME |
|||
* xml_elem_new |
|||
* SYNOPSIS |
|||
* xml_element* xml_elem_new() |
|||
* FUNCTION |
|||
* allocates and initializes a new xml_element |
|||
* INPUTS |
|||
* none |
|||
* RESULT |
|||
* xml_element* or NULL. NULL indicates an out-of-memory condition. |
|||
* NOTES |
|||
* SEE ALSO |
|||
* xml_elem_free () |
|||
* xml_elem_free_non_recurse () |
|||
* SOURCE |
|||
*/ |
|||
xml_element* xml_elem_new() { |
|||
xml_element* elem = ecalloc(1, sizeof(xml_element)); |
|||
if(elem) { |
|||
Q_Init(&elem->children); |
|||
Q_Init(&elem->attrs); |
|||
simplestring_init(&elem->text); |
|||
|
|||
/* init empty string in case we don't find any char data */ |
|||
simplestring_addn(&elem->text, "", 0); |
|||
} |
|||
return elem; |
|||
} |
|||
/******/ |
|||
|
|||
static int xml_elem_writefunc(int (*fptr)(void *data, const char *text, int size), const char *text, void *data, int len) |
|||
{ |
|||
return fptr && text ? fptr(data, text, len ? len : strlen(text)) : 0; |
|||
} |
|||
|
|||
|
|||
|
|||
static int create_xml_escape(char *pString, unsigned char c) |
|||
{ |
|||
int counter = 0; |
|||
|
|||
pString[counter++] = '&'; |
|||
pString[counter++] = '#'; |
|||
if(c >= 100) { |
|||
pString[counter++] = c / 100 + '0'; |
|||
c = c % 100; |
|||
} |
|||
pString[counter++] = c / 10 + '0'; |
|||
c = c % 10; |
|||
|
|||
pString[counter++] = c + '0'; |
|||
pString[counter++] = ';'; |
|||
return counter; |
|||
} |
|||
|
|||
#define non_ascii(c) (c > 127) |
|||
#define non_print(c) (!isprint(c)) |
|||
#define markup(c) (c == '&' || c == '\"' || c == '>' || c == '<') |
|||
#define entity_length(c) ( (c >= 100) ? 3 : ((c >= 10) ? 2 : 1) ) + 3; /* "&#" + c + ";" */ |
|||
|
|||
/* |
|||
* xml_elem_entity_escape |
|||
* |
|||
* Purpose: |
|||
* escape reserved xml chars and non utf-8 chars as xml entities |
|||
* Comments: |
|||
* The return value may be a new string, or null if no |
|||
* conversion was performed. In the latter case, *newlen will |
|||
* be 0. |
|||
* Flags (to escape) |
|||
* xml_elem_no_escaping = 0x000, |
|||
* xml_elem_entity_escaping = 0x002, // escape xml special chars as entities |
|||
* xml_elem_non_ascii_escaping = 0x008, // escape chars above 127 |
|||
* xml_elem_cdata_escaping = 0x010, // wrap in cdata |
|||
*/ |
|||
static char* xml_elem_entity_escape(const char* buf, int old_len, int *newlen, XML_ELEM_ESCAPING flags) { |
|||
char *pRetval = 0; |
|||
int iNewBufLen=0; |
|||
|
|||
#define should_escape(c, flag) ( ((flag & xml_elem_markup_escaping) && markup(c)) || \ |
|||
((flag & xml_elem_non_ascii_escaping) && non_ascii(c)) || \ |
|||
((flag & xml_elem_non_print_escaping) && non_print(c)) ) |
|||
|
|||
if(buf && *buf) { |
|||
const unsigned char *bufcopy; |
|||
char *NewBuffer; |
|||
int ToBeXmlEscaped=0; |
|||
int iLength; |
|||
bufcopy = (const unsigned char *) buf; |
|||
iLength= old_len ? old_len : strlen(buf); |
|||
while(*bufcopy) { |
|||
if( should_escape(*bufcopy, flags) ) { |
|||
/* the length will increase by length of xml escape - the character length */ |
|||
iLength += entity_length(*bufcopy); |
|||
ToBeXmlEscaped=1; |
|||
} |
|||
bufcopy++; |
|||
} |
|||
|
|||
if(ToBeXmlEscaped) { |
|||
|
|||
NewBuffer= emalloc(iLength+1); |
|||
if(NewBuffer) { |
|||
bufcopy = (const unsigned char *) buf; |
|||
while(*bufcopy) { |
|||
if(should_escape(*bufcopy, flags)) { |
|||
iNewBufLen += create_xml_escape(NewBuffer+iNewBufLen,*bufcopy); |
|||
} |
|||
else { |
|||
NewBuffer[iNewBufLen++]=*bufcopy; |
|||
} |
|||
bufcopy++; |
|||
} |
|||
NewBuffer[iNewBufLen] = 0; |
|||
pRetval = NewBuffer; |
|||
} |
|||
} |
|||
} |
|||
|
|||
if(newlen) { |
|||
*newlen = iNewBufLen; |
|||
} |
|||
|
|||
return pRetval; |
|||
} |
|||
|
|||
|
|||
static void xml_element_serialize(xml_element *el, int (*fptr)(void *data, const char *text, int size), void *data, XML_ELEM_OUTPUT_OPTIONS options, int depth) |
|||
{ |
|||
int i; |
|||
static STRUCT_XML_ELEM_OUTPUT_OPTIONS default_opts = {xml_elem_pretty, xml_elem_markup_escaping | xml_elem_non_print_escaping, XML_DECL_ENCODING_DEFAULT}; |
|||
static char whitespace[] = " " |
|||
" " |
|||
" "; |
|||
depth++; |
|||
|
|||
if(!el) { |
|||
/* fprintf(stderr, "Nothing to write\n"); */ |
|||
return; |
|||
} |
|||
if(!options) { |
|||
options = &default_opts; |
|||
} |
|||
|
|||
/* print xml declaration if at root level */ |
|||
if(depth == 1) { |
|||
xml_elem_writefunc(fptr, XML_DECL_START, data, XML_DECL_START_LEN); |
|||
xml_elem_writefunc(fptr, WHITESPACE, data, WHITESPACE_LEN); |
|||
xml_elem_writefunc(fptr, XML_DECL_VERSION, data, XML_DECL_VERSION_LEN); |
|||
if(options->encoding && *options->encoding) { |
|||
xml_elem_writefunc(fptr, WHITESPACE, data, WHITESPACE_LEN); |
|||
xml_elem_writefunc(fptr, XML_DECL_ENCODING_ATTR, data, XML_DECL_ENCODING_ATTR_LEN); |
|||
xml_elem_writefunc(fptr, EQUALS, data, EQUALS_LEN); |
|||
xml_elem_writefunc(fptr, ATTR_DELIMITER, data, ATTR_DELIMITER_LEN); |
|||
xml_elem_writefunc(fptr, options->encoding, data, 0); |
|||
xml_elem_writefunc(fptr, ATTR_DELIMITER, data, ATTR_DELIMITER_LEN); |
|||
} |
|||
xml_elem_writefunc(fptr, XML_DECL_END, data, XML_DECL_END_LEN); |
|||
if(options->verbosity != xml_elem_no_white_space) { |
|||
xml_elem_writefunc(fptr, NEWLINE, data, NEWLINE_LEN); |
|||
} |
|||
} |
|||
|
|||
if(options->verbosity == xml_elem_pretty && depth > 2) { |
|||
xml_elem_writefunc(fptr, whitespace, data, depth - 2); |
|||
} |
|||
/* begin element */ |
|||
xml_elem_writefunc(fptr,START_TOKEN_BEGIN, data, START_TOKEN_BEGIN_LEN); |
|||
if(el->name) { |
|||
xml_elem_writefunc(fptr, el->name, data, 0); |
|||
|
|||
/* write attrs, if any */ |
|||
if(Q_Size(&el->attrs)) { |
|||
xml_element_attr* iter = Q_Head(&el->attrs); |
|||
while( iter ) { |
|||
xml_elem_writefunc(fptr, WHITESPACE, data, WHITESPACE_LEN); |
|||
xml_elem_writefunc(fptr, iter->key, data, 0); |
|||
xml_elem_writefunc(fptr, EQUALS, data, EQUALS_LEN); |
|||
xml_elem_writefunc(fptr, ATTR_DELIMITER, data, ATTR_DELIMITER_LEN); |
|||
xml_elem_writefunc(fptr, iter->val, data, 0); |
|||
xml_elem_writefunc(fptr, ATTR_DELIMITER, data, ATTR_DELIMITER_LEN); |
|||
|
|||
iter = Q_Next(&el->attrs); |
|||
} |
|||
} |
|||
} |
|||
else { |
|||
xml_elem_writefunc(fptr, "None", data, 0); |
|||
} |
|||
/* if no text and no children, use abbreviated form, eg: <foo/> */ |
|||
if(!el->text.len && !Q_Size(&el->children)) { |
|||
xml_elem_writefunc(fptr, EMPTY_START_TOKEN_END, data, EMPTY_START_TOKEN_END_LEN); |
|||
} |
|||
/* otherwise, print element contents */ |
|||
else { |
|||
xml_elem_writefunc(fptr, START_TOKEN_END, data, START_TOKEN_END_LEN); |
|||
|
|||
/* print text, if any */ |
|||
if(el->text.len) { |
|||
char* escaped_str = el->text.str; |
|||
int buflen = el->text.len; |
|||
|
|||
if(options->escaping && options->escaping != xml_elem_cdata_escaping) { |
|||
escaped_str = xml_elem_entity_escape(el->text.str, buflen, &buflen, options->escaping ); |
|||
if(!escaped_str) { |
|||
escaped_str = el->text.str; |
|||
} |
|||
} |
|||
|
|||
if(options->escaping & xml_elem_cdata_escaping) { |
|||
xml_elem_writefunc(fptr, CDATA_BEGIN, data, CDATA_BEGIN_LEN); |
|||
} |
|||
|
|||
xml_elem_writefunc(fptr, escaped_str, data, buflen); |
|||
|
|||
if(escaped_str != el->text.str) { |
|||
my_free(escaped_str); |
|||
} |
|||
|
|||
if(options->escaping & xml_elem_cdata_escaping) { |
|||
xml_elem_writefunc(fptr, CDATA_END, data, CDATA_END_LEN); |
|||
} |
|||
} |
|||
/* no text, so print child elems */ |
|||
else { |
|||
xml_element *kids = Q_Head(&el->children); |
|||
i = 0; |
|||
while( kids ) { |
|||
if(i++ == 0) { |
|||
if(options->verbosity != xml_elem_no_white_space) { |
|||
xml_elem_writefunc(fptr, NEWLINE, data, NEWLINE_LEN); |
|||
} |
|||
} |
|||
xml_element_serialize(kids, fptr, data, options, depth); |
|||
kids = Q_Next(&el->children); |
|||
} |
|||
if(i) { |
|||
if(options->verbosity == xml_elem_pretty && depth > 2) { |
|||
xml_elem_writefunc(fptr, whitespace, data, depth - 2); |
|||
} |
|||
} |
|||
} |
|||
|
|||
xml_elem_writefunc(fptr, END_TOKEN_BEGIN, data, END_TOKEN_BEGIN_LEN); |
|||
xml_elem_writefunc(fptr,el->name ? el->name : "None", data, 0); |
|||
xml_elem_writefunc(fptr, END_TOKEN_END, data, END_TOKEN_END_LEN); |
|||
} |
|||
if(options->verbosity != xml_elem_no_white_space) { |
|||
xml_elem_writefunc(fptr, NEWLINE, data, NEWLINE_LEN); |
|||
} |
|||
} |
|||
|
|||
/* print buf to file */ |
|||
static int file_out_fptr(void *f, const char *text, int size) |
|||
{ |
|||
fputs(text, (FILE *)f); |
|||
return 0; |
|||
} |
|||
|
|||
/* print buf to simplestring */ |
|||
static int simplestring_out_fptr(void *f, const char *text, int size) |
|||
{ |
|||
simplestring* buf = (simplestring*)f; |
|||
if(buf) { |
|||
simplestring_addn(buf, text, size); |
|||
} |
|||
return 0; |
|||
} |
|||
|
|||
/****f* xml_element/xml_elem_serialize_to_string |
|||
* NAME |
|||
* xml_elem_serialize_to_string |
|||
* SYNOPSIS |
|||
* void xml_element_serialize_to_string(xml_element *el, XML_ELEM_OUTPUT_OPTIONS options, int *buf_len) |
|||
* FUNCTION |
|||
* writes element tree as XML into a newly allocated buffer |
|||
* INPUTS |
|||
* el - root element of tree |
|||
* options - options determining how output is written. see XML_ELEM_OUTPUT_OPTIONS |
|||
* buf_len - length of returned buffer, if not null. |
|||
* RESULT |
|||
* char* or NULL. Must be free'd by caller. |
|||
* NOTES |
|||
* SEE ALSO |
|||
* xml_elem_serialize_to_stream () |
|||
* xml_elem_parse_buf () |
|||
* SOURCE |
|||
*/ |
|||
char* xml_elem_serialize_to_string(xml_element *el, XML_ELEM_OUTPUT_OPTIONS options, int *buf_len) |
|||
{ |
|||
simplestring buf; |
|||
simplestring_init(&buf); |
|||
|
|||
xml_element_serialize(el, simplestring_out_fptr, (void *)&buf, options, 0); |
|||
|
|||
if(buf_len) { |
|||
*buf_len = buf.len; |
|||
} |
|||
|
|||
return buf.str; |
|||
} |
|||
/******/ |
|||
|
|||
/****f* xml_element/xml_elem_serialize_to_stream |
|||
* NAME |
|||
* xml_elem_serialize_to_stream |
|||
* SYNOPSIS |
|||
* void xml_elem_serialize_to_stream(xml_element *el, FILE *output, XML_ELEM_OUTPUT_OPTIONS options) |
|||
* FUNCTION |
|||
* writes element tree as XML into a stream (typically an opened file) |
|||
* INPUTS |
|||
* el - root element of tree |
|||
* output - stream handle |
|||
* options - options determining how output is written. see XML_ELEM_OUTPUT_OPTIONS |
|||
* RESULT |
|||
* void |
|||
* NOTES |
|||
* SEE ALSO |
|||
* xml_elem_serialize_to_string () |
|||
* xml_elem_parse_buf () |
|||
* SOURCE |
|||
*/ |
|||
void xml_elem_serialize_to_stream(xml_element *el, FILE *output, XML_ELEM_OUTPUT_OPTIONS options) |
|||
{ |
|||
xml_element_serialize(el, file_out_fptr, (void *)output, options, 0); |
|||
} |
|||
/******/ |
|||
|
|||
/*--------------------------* |
|||
* End xml_element Functions * |
|||
*--------------------------*/ |
|||
|
|||
|
|||
/*---------------------- |
|||
* Begin Expat Handlers * |
|||
*---------------------*/ |
|||
|
|||
typedef struct _xml_elem_data { |
|||
xml_element* root; |
|||
xml_element* current; |
|||
XML_ELEM_INPUT_OPTIONS input_options; |
|||
int needs_enc_conversion; |
|||
} xml_elem_data; |
|||
|
|||
|
|||
/* expat start of element handler */ |
|||
static void _xmlrpc_startElement(void *userData, const char *name, const char **attrs) |
|||
{ |
|||
xml_element *c; |
|||
xml_elem_data* mydata = (xml_elem_data*)userData; |
|||
const char** p = attrs; |
|||
|
|||
if(mydata) { |
|||
c = mydata->current; |
|||
|
|||
mydata->current = xml_elem_new(); |
|||
mydata->current->name = (char*)estrdup(name); |
|||
mydata->current->parent = c; |
|||
|
|||
/* init attrs */ |
|||
while(p && *p) { |
|||
xml_element_attr* attr = emalloc(sizeof(xml_element_attr)); |
|||
if(attr) { |
|||
attr->key = estrdup(*p); |
|||
attr->val = estrdup(*(p+1)); |
|||
Q_PushTail(&mydata->current->attrs, attr); |
|||
|
|||
p += 2; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
/* expat end of element handler */ |
|||
static void _xmlrpc_endElement(void *userData, const char *name) |
|||
{ |
|||
xml_elem_data* mydata = (xml_elem_data*)userData; |
|||
|
|||
if(mydata && mydata->current && mydata->current->parent) { |
|||
Q_PushTail(&mydata->current->parent->children, mydata->current); |
|||
|
|||
mydata->current = mydata->current->parent; |
|||
} |
|||
} |
|||
|
|||
/* expat char data handler */ |
|||
static void _xmlrpc_charHandler(void *userData, |
|||
const char *s, |
|||
int len) |
|||
{ |
|||
xml_elem_data* mydata = (xml_elem_data*)userData; |
|||
if(mydata && mydata->current) { |
|||
|
|||
/* Check if we need to decode utf-8 parser output to another encoding */ |
|||
if(mydata->needs_enc_conversion && mydata->input_options->encoding) { |
|||
int new_len = 0; |
|||
char* add_text = utf8_decode(s, len, &new_len, mydata->input_options->encoding); |
|||
if(add_text) { |
|||
len = new_len; |
|||
simplestring_addn(&mydata->current->text, add_text, len); |
|||
efree(add_text); |
|||
return; |
|||
} |
|||
} |
|||
simplestring_addn(&mydata->current->text, s, len); |
|||
} |
|||
} |
|||
/******/ |
|||
|
|||
/*-------------------* |
|||
* End Expat Handlers * |
|||
*-------------------*/ |
|||
|
|||
/*-------------------* |
|||
* xml_elem_parse_buf * |
|||
*-------------------*/ |
|||
|
|||
/****f* xml_element/xml_elem_parse_buf |
|||
* NAME |
|||
* xml_elem_parse_buf |
|||
* SYNOPSIS |
|||
* xml_element* xml_elem_parse_buf(const char* in_buf, int len, XML_ELEM_INPUT_OPTIONS options, XML_ELEM_ERROR error) |
|||
* FUNCTION |
|||
* parse a buffer containing XML into an xml_element in-memory tree |
|||
* INPUTS |
|||
* in_buf - buffer containing XML document |
|||
* len - length of buffer |
|||
* options - input options. optional |
|||
* error - error result data. optional. check if result is null. |
|||
* RESULT |
|||
* void |
|||
* NOTES |
|||
* The returned data must be free'd by caller |
|||
* SEE ALSO |
|||
* xml_elem_serialize_to_string () |
|||
* xml_elem_free () |
|||
* SOURCE |
|||
*/ |
|||
xml_element* xml_elem_parse_buf(const char* in_buf, int len, XML_ELEM_INPUT_OPTIONS options, XML_ELEM_ERROR error) |
|||
{ |
|||
xml_element* xReturn = NULL; |
|||
char buf[100] = ""; |
|||
static STRUCT_XML_ELEM_INPUT_OPTIONS default_opts = {encoding_utf_8}; |
|||
|
|||
if(!options) { |
|||
options = &default_opts; |
|||
} |
|||
|
|||
if(in_buf) { |
|||
XML_Parser parser; |
|||
xml_elem_data mydata = {0}; |
|||
|
|||
parser = XML_ParserCreate(NULL); |
|||
|
|||
mydata.root = xml_elem_new(); |
|||
mydata.current = mydata.root; |
|||
mydata.input_options = options; |
|||
mydata.needs_enc_conversion = options->encoding && strcmp(options->encoding, encoding_utf_8); |
|||
|
|||
XML_SetElementHandler(parser, (XML_StartElementHandler)_xmlrpc_startElement, (XML_EndElementHandler)_xmlrpc_endElement); |
|||
XML_SetCharacterDataHandler(parser, (XML_CharacterDataHandler)_xmlrpc_charHandler); |
|||
|
|||
/* pass the xml_elem_data struct along */ |
|||
XML_SetUserData(parser, (void*)&mydata); |
|||
|
|||
if(!len) { |
|||
len = strlen(in_buf); |
|||
} |
|||
|
|||
/* parse the XML */ |
|||
if(XML_Parse(parser, (const unsigned char *) in_buf, len, 1) == 0) { |
|||
enum XML_Error err_code = XML_GetErrorCode(parser); |
|||
int line_num = XML_GetCurrentLineNumber(parser); |
|||
int col_num = XML_GetCurrentColumnNumber(parser); |
|||
long byte_idx = XML_GetCurrentByteIndex(parser); |
|||
/* int byte_total = XML_GetCurrentByteCount(parser); */ |
|||
const char * error_str = (const char *) XML_ErrorString(err_code); |
|||
if(byte_idx > len) { |
|||
byte_idx = len; |
|||
} |
|||
if(byte_idx >= 0) { |
|||
snprintf(buf, |
|||
sizeof(buf), |
|||
"\n\tdata beginning %ld before byte index: %s\n", |
|||
byte_idx > 10 ? 10 : byte_idx, |
|||
in_buf + (byte_idx > 10 ? byte_idx - 10 : byte_idx)); |
|||
} |
|||
/* |
|||
fprintf(stderr, "expat reports error code %i\n" |
|||
"\tdescription: %s\n" |
|||
"\tline: %i\n" |
|||
"\tcolumn: %i\n" |
|||
"\tbyte index: %ld\n" |
|||
"\ttotal bytes: %i\n%s ", |
|||
err_code, error_str, line_num, |
|||
col_num, byte_idx, byte_total, buf); |
|||
*/ |
|||
|
|||
/* error condition */ |
|||
if(error) { |
|||
error->parser_code = (long)err_code; |
|||
error->line = line_num; |
|||
error->column = col_num; |
|||
error->byte_index = byte_idx; |
|||
error->parser_error = error_str; |
|||
} |
|||
} |
|||
else { |
|||
xReturn = (xml_element*)Q_Head(&mydata.root->children); |
|||
xReturn->parent = NULL; |
|||
} |
|||
|
|||
XML_ParserFree(parser); |
|||
|
|||
|
|||
xml_elem_free_non_recurse(mydata.root); |
|||
} |
|||
|
|||
return xReturn; |
|||
} |
|||
|
|||
/******/ |
|||
@ -1,202 +0,0 @@ |
|||
/* |
|||
This file is part of libXMLRPC - a C library for xml-encoded function calls. |
|||
|
|||
Author: Dan Libby (dan@libby.com) |
|||
Epinions.com may be contacted at feedback@epinions-inc.com |
|||
*/ |
|||
|
|||
/* |
|||
Copyright 2000 Epinions, Inc. |
|||
|
|||
Subject to the following 3 conditions, Epinions, Inc. permits you, free |
|||
of charge, to (a) use, copy, distribute, modify, perform and display this |
|||
software and associated documentation files (the "Software"), and (b) |
|||
permit others to whom the Software is furnished to do so as well. |
|||
|
|||
1) The above copyright notice and this permission notice shall be included |
|||
without modification in all copies or substantial portions of the |
|||
Software. |
|||
|
|||
2) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTY OR CONDITION OF |
|||
ANY KIND, EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION ANY |
|||
IMPLIED WARRANTIES OF ACCURACY, MERCHANTABILITY, FITNESS FOR A PARTICULAR |
|||
PURPOSE OR NONINFRINGEMENT. |
|||
|
|||
3) IN NO EVENT SHALL EPINIONS, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, |
|||
SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT |
|||
OF OR IN CONNECTION WITH THE SOFTWARE (HOWEVER ARISING, INCLUDING |
|||
NEGLIGENCE), EVEN IF EPINIONS, INC. IS AWARE OF THE POSSIBILITY OF SUCH |
|||
DAMAGES. |
|||
|
|||
*/ |
|||
|
|||
#ifndef __XML_ELEMENT_H__ |
|||
#define __XML_ELEMENT_H__ |
|||
|
|||
/* includes */ |
|||
#include <stdio.h> |
|||
#include "queue.h" |
|||
#include "simplestring.h" |
|||
#include "encodings.h" |
|||
|
|||
#ifdef __cplusplus |
|||
extern "C" { |
|||
#endif |
|||
|
|||
/****d* enum/XML_ELEM_VERBOSITY |
|||
* NAME |
|||
* XML_ELEM_VERBOSITY |
|||
* NOTES |
|||
* verbosity/readability options for generated xml |
|||
* SEE ALSO |
|||
* XML_ELEM_OUTPUT_OPTIONS |
|||
* SOURCE |
|||
*/ |
|||
typedef enum _xml_elem_verbosity { |
|||
xml_elem_no_white_space, /* compact xml with no white space */ |
|||
xml_elem_newlines_only, /* add newlines for enhanced readability */ |
|||
xml_elem_pretty /* add newlines and indent accordind to depth */ |
|||
} XML_ELEM_VERBOSITY; |
|||
/******/ |
|||
|
|||
|
|||
/****d* enum/XML_ELEM_ESCAPING |
|||
* NAME |
|||
* XML_ELEM_ESCAPING |
|||
* NOTES |
|||
* xml escaping options for generated xml |
|||
* SEE ALSO |
|||
* XML_ELEM_OUTPUT_OPTIONS |
|||
* SOURCE |
|||
*/ |
|||
typedef enum _xml_elem_escaping { |
|||
xml_elem_no_escaping = 0x000, |
|||
xml_elem_markup_escaping = 0x002, /* entity escape xml special chars */ |
|||
xml_elem_non_ascii_escaping = 0x008, /* entity escape chars above 127 */ |
|||
xml_elem_non_print_escaping = 0x010, /* entity escape non print (illegal) chars */ |
|||
xml_elem_cdata_escaping = 0x020, /* wrap in cdata section */ |
|||
} XML_ELEM_ESCAPING; |
|||
/******/ |
|||
|
|||
|
|||
/****s* struct/XML_ELEM_OUTPUT_OPTIONS |
|||
* NAME |
|||
* XML_ELEM_OUTPUT_OPTIONS |
|||
* NOTES |
|||
* defines various output options |
|||
* SOURCE |
|||
*/ |
|||
typedef struct _xml_output_options { |
|||
XML_ELEM_VERBOSITY verbosity; /* length/verbosity of xml */ |
|||
XML_ELEM_ESCAPING escaping; /* how to escape special chars */ |
|||
const char* encoding; /* <?xml encoding="<encoding>" ?> */ |
|||
} STRUCT_XML_ELEM_OUTPUT_OPTIONS, *XML_ELEM_OUTPUT_OPTIONS; |
|||
/******/ |
|||
|
|||
/****s* struct/XML_ELEM_INPUT_OPTIONS |
|||
* NAME |
|||
* XML_ELEM_INPUT_OPTIONS |
|||
* NOTES |
|||
* defines various input options |
|||
* SOURCE |
|||
*/ |
|||
typedef struct _xml_input_options { |
|||
ENCODING_ID encoding; /* which encoding to use. */ |
|||
} STRUCT_XML_ELEM_INPUT_OPTIONS, *XML_ELEM_INPUT_OPTIONS; |
|||
/******/ |
|||
|
|||
/****s* struct/XML_ELEM_ERROR |
|||
* NAME |
|||
* XML_ELEM_ERROR |
|||
* NOTES |
|||
* defines an xml parser error |
|||
* SOURCE |
|||
*/ |
|||
typedef struct _xml_elem_error { |
|||
int parser_code; |
|||
const char* parser_error; |
|||
long line; |
|||
long column; |
|||
long byte_index; |
|||
} STRUCT_XML_ELEM_ERROR, *XML_ELEM_ERROR; |
|||
/******/ |
|||
|
|||
|
|||
/*-************************ |
|||
* begin xml element stuff * |
|||
**************************/ |
|||
|
|||
/****s* struct/xml_elem_attr |
|||
* NAME |
|||
* xml_elem_attr |
|||
* NOTES |
|||
* representation of an xml attribute, foo="bar" |
|||
* SOURCE |
|||
*/ |
|||
typedef struct _xml_element_attr { |
|||
char* key; /* attribute key */ |
|||
char* val; /* attribute value */ |
|||
} xml_element_attr; |
|||
/******/ |
|||
|
|||
/****s* struct/xml_elem_attr |
|||
* NAME |
|||
* xml_elem_attr |
|||
* NOTES |
|||
* representation of an xml element, eg <candidate name="Harry Browne" party="Libertarian"/> |
|||
* SOURCE |
|||
*/ |
|||
typedef struct _xml_element { |
|||
const char* name; /* element identifier */ |
|||
simplestring text; /* text contained between element begin/end pairs */ |
|||
struct _xml_element* parent; /* element's parent */ |
|||
|
|||
queue attrs; /* attribute list */ |
|||
queue children; /* child element list */ |
|||
} xml_element; |
|||
/******/ |
|||
|
|||
void xml_elem_free(xml_element* root); |
|||
void xml_elem_free_non_recurse(xml_element* root); |
|||
xml_element* xml_elem_new(void); |
|||
char* xml_elem_serialize_to_string(xml_element *el, XML_ELEM_OUTPUT_OPTIONS options, int *buf_len); |
|||
void xml_elem_serialize_to_stream(xml_element *el, FILE *output, XML_ELEM_OUTPUT_OPTIONS options); |
|||
xml_element* xml_elem_parse_buf(const char* in_buf, int len, XML_ELEM_INPUT_OPTIONS options, XML_ELEM_ERROR error); |
|||
|
|||
/*-********************** |
|||
* end xml element stuff * |
|||
************************/ |
|||
|
|||
/*-********************** |
|||
* Begin xml_element API * |
|||
************************/ |
|||
|
|||
/****d* VALUE/XMLRPC_MACROS |
|||
* NAME |
|||
* Some Helpful Macros |
|||
* NOTES |
|||
* Some macros for making life easier. Should be self-explanatory. |
|||
* SEE ALSO |
|||
* XMLRPC_AddValueToVector () |
|||
* XMLRPC_VectorGetValueWithID_Case () |
|||
* XMLRPC_VALUE |
|||
* SOURCE |
|||
*/ |
|||
#define xml_elem_next_element(el) ((el) ? (xml_element *)Q_Next(&el->children) : NULL) |
|||
#define xml_elem_head_element(el) ((el) ? (xml_element *)Q_Head(&el->children) : NULL) |
|||
#define xml_elem_next_attr(el) ((el) ? (xml_element_attr *)Q_Next(&el->attrs) : NULL) |
|||
#define xml_elem_head_attr(el) ((el) ? (xml_element_attr *)Q_Head(&el->attrs) : NULL) |
|||
#define xml_elem_get_name(el) (char *)((el) ? el->name : NULL) |
|||
#define xml_elem_get_val(el) (char *)((el) ? el->text.str : NULL) |
|||
/******/ |
|||
|
|||
|
|||
/*-******************** |
|||
* End xml_element API * |
|||
**********************/ |
|||
|
|||
#ifdef __cplusplus |
|||
} |
|||
#endif |
|||
|
|||
#endif /* __XML_ELEMENT_H__ */ |
|||
@ -1,315 +0,0 @@ |
|||
/* |
|||
This file is part of libXMLRPC - a C library for xml-encoded function calls. |
|||
|
|||
Author: Dan Libby (dan@libby.com) |
|||
Epinions.com may be contacted at feedback@epinions-inc.com |
|||
*/ |
|||
|
|||
/* |
|||
Copyright 2000 Epinions, Inc. |
|||
|
|||
Subject to the following 3 conditions, Epinions, Inc. permits you, free |
|||
of charge, to (a) use, copy, distribute, modify, perform and display this |
|||
software and associated documentation files (the "Software"), and (b) |
|||
permit others to whom the Software is furnished to do so as well. |
|||
|
|||
1) The above copyright notice and this permission notice shall be included |
|||
without modification in all copies or substantial portions of the |
|||
Software. |
|||
|
|||
2) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTY OR CONDITION OF |
|||
ANY KIND, EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION ANY |
|||
IMPLIED WARRANTIES OF ACCURACY, MERCHANTABILITY, FITNESS FOR A PARTICULAR |
|||
PURPOSE OR NONINFRINGEMENT. |
|||
|
|||
3) IN NO EVENT SHALL EPINIONS, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, |
|||
SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT |
|||
OF OR IN CONNECTION WITH THE SOFTWARE (HOWEVER ARISING, INCLUDING |
|||
NEGLIGENCE), EVEN IF EPINIONS, INC. IS AWARE OF THE POSSIBILITY OF SUCH |
|||
DAMAGES. |
|||
|
|||
*/ |
|||
|
|||
#include <string.h> |
|||
#include <stdlib.h> |
|||
#include "xml_to_dandarpc.h" |
|||
#include "base64.h" |
|||
|
|||
/* list of tokens used in vocab */ |
|||
#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 : emalloc(sizeof(xml_element_attr)); |
|||
|
|||
if(attr_type) { |
|||
attr_type->key = estrdup(ATTR_TYPE); |
|||
attr_type->val = 0; |
|||
Q_PushTail(&elem_val->attrs, attr_type); |
|||
} |
|||
|
|||
elem_val->name = (type == xmlrpc_vector) ? estrdup(ATTR_VECTOR) : estrdup(ATTR_SCALAR); |
|||
|
|||
if(id && *id) { |
|||
xml_element_attr* attr_id = emalloc(sizeof(xml_element_attr)); |
|||
if(attr_id) { |
|||
attr_id->key = estrdup(ATTR_ID); |
|||
attr_id->val = estrdup(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; |
|||
} |
|||
|
|||
/* recurse through sub-elements */ |
|||
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 = estrdup(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 = emalloc(sizeof(xml_element_attr)); |
|||
version->key = estrdup(ATTR_VERSION); |
|||
version->val = estrdup(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 = estrdup(pStr); |
|||
} |
|||
|
|||
root = xml_elem_new(); |
|||
root->name = estrdup(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 = estrdup(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; |
|||
} |
|||
@ -1,44 +0,0 @@ |
|||
/* |
|||
This file is part of libXMLRPC - a C library for xml-encoded function calls. |
|||
|
|||
Author: Dan Libby (dan@libby.com) |
|||
Epinions.com may be contacted at feedback@epinions-inc.com |
|||
*/ |
|||
|
|||
/* |
|||
Copyright 2000 Epinions, Inc. |
|||
|
|||
Subject to the following 3 conditions, Epinions, Inc. permits you, free |
|||
of charge, to (a) use, copy, distribute, modify, perform and display this |
|||
software and associated documentation files (the "Software"), and (b) |
|||
permit others to whom the Software is furnished to do so as well. |
|||
|
|||
1) The above copyright notice and this permission notice shall be included |
|||
without modification in all copies or substantial portions of the |
|||
Software. |
|||
|
|||
2) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTY OR CONDITION OF |
|||
ANY KIND, EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION ANY |
|||
IMPLIED WARRANTIES OF ACCURACY, MERCHANTABILITY, FITNESS FOR A PARTICULAR |
|||
PURPOSE OR NONINFRINGEMENT. |
|||
|
|||
3) IN NO EVENT SHALL EPINIONS, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, |
|||
SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT |
|||
OF OR IN CONNECTION WITH THE SOFTWARE (HOWEVER ARISING, INCLUDING |
|||
NEGLIGENCE), EVEN IF EPINIONS, INC. IS AWARE OF THE POSSIBILITY OF SUCH |
|||
DAMAGES. |
|||
|
|||
*/ |
|||
|
|||
#ifndef XML_TO_DANDARPC_H |
|||
#define XML_TO_DANDARPC_H |
|||
|
|||
#include "time.h" |
|||
#include "xmlrpc.h" |
|||
|
|||
XMLRPC_VALUE xml_element_to_DANDARPC_VALUE(xml_element* el); |
|||
XMLRPC_VALUE xml_element_to_DANDARPC_REQUEST(XMLRPC_REQUEST request, xml_element* el); |
|||
xml_element* DANDARPC_VALUE_to_xml_element(XMLRPC_VALUE node); |
|||
xml_element* DANDARPC_REQUEST_to_xml_element(XMLRPC_REQUEST request); |
|||
|
|||
#endif /* XML_TO_DANDARPC_H */ |
|||
@ -1,664 +0,0 @@ |
|||
/* |
|||
This file is part of libXMLRPC - a C library for xml-encoded function calls. |
|||
|
|||
Author: Dan Libby (dan@libby.com) |
|||
*/ |
|||
|
|||
|
|||
/*-********************************************************************** |
|||
* TODO: * |
|||
* - [SOAP-ENC:position] read sparse arrays (and write?) * |
|||
* - [SOAP-ENC:offset] read partially transmitted arrays (and write?) * |
|||
* - read "flattened" multi-dimensional arrays. (don't bother writing) * |
|||
* * |
|||
* BUGS: * |
|||
* - does not read schema. thus only knows soap pre-defined types. * |
|||
* - references (probably) do not work. untested. * |
|||
* - does not expose SOAP-ENV:Header to application at all. * |
|||
* - does not use namespaces correctly, thus: * |
|||
* - namespaces are hard-coded in comparison tokens * |
|||
* - if a sender uses another namespace identifer, it will break * |
|||
************************************************************************/ |
|||
|
|||
|
|||
#include <string.h> |
|||
#include <stdlib.h> |
|||
#include "xml_to_soap.h" |
|||
#include "base64.h" |
|||
|
|||
/* list of tokens used in vocab */ |
|||
#define TOKEN_ANY "xsd:ur-type" |
|||
#define TOKEN_ARRAY "SOAP-ENC:Array" |
|||
#define TOKEN_ARRAY_TYPE "SOAP-ENC:arrayType" |
|||
#define TOKEN_BASE64 "SOAP-ENC:base64" |
|||
#define TOKEN_BOOLEAN "xsd:boolean" |
|||
#define TOKEN_DATETIME "xsd:timeInstant" |
|||
#define TOKEN_DOUBLE "xsd:double" |
|||
#define TOKEN_FLOAT "xsd:float" |
|||
#define TOKEN_ID "id" |
|||
#define TOKEN_INT "xsd:int" |
|||
#define TOKEN_NULL "xsi:null" |
|||
#define TOKEN_STRING "xsd:string" |
|||
#define TOKEN_STRUCT "xsd:struct" |
|||
#define TOKEN_TYPE "xsi:type" |
|||
#define TOKEN_FAULT "SOAP-ENV:Fault" |
|||
#define TOKEN_MUSTUNDERSTAND "SOAP-ENV:mustUnderstand" |
|||
#define TOKEN_ACTOR "SOAP-ENV:actor" |
|||
#define TOKEN_ACTOR_NEXT "http://schemas.xmlsoap.org/soap/actor/next" |
|||
|
|||
#define TOKEN_XMLRPC_FAULTCODE "faultCode" |
|||
#define TOKEN_XMLRPC_FAULTSTRING "faultString" |
|||
#define TOKEN_SOAP_FAULTCODE "faultcode" |
|||
#define TOKEN_SOAP_FAULTSTRING "faultstring" |
|||
#define TOKEN_SOAP_FAULTDETAILS "details" |
|||
#define TOKEN_SOAP_FAULTACTOR "actor" |
|||
|
|||
|
|||
/* determine if a string represents a soap type, as used in element names */ |
|||
static inline int is_soap_type(const char* soap_type) { |
|||
return(strstr(soap_type, "SOAP-ENC:") || strstr(soap_type, "xsd:")) ? 1 : 0; |
|||
} |
|||
|
|||
/* utility func to generate a new attribute. possibly should be in xml_element.c?? */ |
|||
static xml_element_attr* new_attr(const char* key, const char* val) { |
|||
xml_element_attr* attr = emalloc(sizeof(xml_element_attr)); |
|||
if (attr) { |
|||
attr->key = key ? estrdup(key) : NULL; |
|||
attr->val = val ? estrdup(val) : NULL; |
|||
} |
|||
return attr; |
|||
} |
|||
|
|||
struct array_info { |
|||
char kids_type[128]; |
|||
unsigned long size; |
|||
/* ... ? */ |
|||
}; |
|||
|
|||
|
|||
/* parses soap arrayType attribute to generate an array_info structure. |
|||
* TODO: should deal with sparse, flattened, & multi-dimensional arrays |
|||
*/ |
|||
static struct array_info* parse_array_type_info(const char* array_type) { |
|||
struct array_info* ai = NULL; |
|||
if (array_type) { |
|||
ai = (struct array_info*)ecalloc(1, sizeof(struct array_info)); |
|||
if (ai) { |
|||
char buf[128], *p; |
|||
snprintf(buf, sizeof(buf), "%s", array_type); |
|||
p = strchr(buf, '['); |
|||
if (p) { |
|||
*p = 0; |
|||
} |
|||
strcpy(ai->kids_type, buf); |
|||
} |
|||
} |
|||
return ai; |
|||
} |
|||
|
|||
/* performs heuristics on an xmlrpc_vector_array to determine |
|||
* appropriate soap arrayType string. |
|||
*/ |
|||
static const char* get_array_soap_type(XMLRPC_VALUE node) { |
|||
XMLRPC_VALUE_TYPE_EASY type = xmlrpc_type_none; |
|||
|
|||
XMLRPC_VALUE xIter = XMLRPC_VectorRewind(node); |
|||
int loopCount = 0; |
|||
const char* soapType = TOKEN_ANY; |
|||
|
|||
type = XMLRPC_GetValueTypeEasy(xIter); |
|||
xIter = XMLRPC_VectorNext(node); |
|||
|
|||
while (xIter) { |
|||
/* 50 seems like a decent # of loops. That will likely |
|||
* cover most cases. Any more and we start to sacrifice |
|||
* performance. |
|||
*/ |
|||
if ( (XMLRPC_GetValueTypeEasy(xIter) != type) || loopCount >= 50) { |
|||
type = xmlrpc_type_none; |
|||
break; |
|||
} |
|||
loopCount ++; |
|||
|
|||
xIter = XMLRPC_VectorNext(node); |
|||
} |
|||
switch (type) { |
|||
case xmlrpc_type_none: |
|||
soapType = TOKEN_ANY; |
|||
break; |
|||
case xmlrpc_type_empty: |
|||
soapType = TOKEN_NULL; |
|||
break; |
|||
case xmlrpc_type_int: |
|||
soapType = TOKEN_INT; |
|||
break; |
|||
case xmlrpc_type_double: |
|||
soapType = TOKEN_DOUBLE; |
|||
break; |
|||
case xmlrpc_type_boolean: |
|||
soapType = TOKEN_BOOLEAN; |
|||
break; |
|||
case xmlrpc_type_string: |
|||
soapType = TOKEN_STRING; |
|||
break; |
|||
case xmlrpc_type_base64: |
|||
soapType = TOKEN_BASE64; |
|||
break; |
|||
case xmlrpc_type_datetime: |
|||
soapType = TOKEN_DATETIME; |
|||
break; |
|||
case xmlrpc_type_struct: |
|||
soapType = TOKEN_STRUCT; |
|||
break; |
|||
case xmlrpc_type_array: |
|||
soapType = TOKEN_ARRAY; |
|||
break; |
|||
case xmlrpc_type_mixed: |
|||
soapType = TOKEN_STRUCT; |
|||
break; |
|||
} |
|||
return soapType; |
|||
} |
|||
|
|||
/* determines whether a node is a fault or not, and of which type: |
|||
* 0 = not a fault, |
|||
* 1 = xmlrpc style fault |
|||
* 2 = soap style fault. |
|||
*/ |
|||
static inline int get_fault_type(XMLRPC_VALUE node) { |
|||
if (XMLRPC_VectorGetValueWithID(node, TOKEN_XMLRPC_FAULTCODE) && |
|||
XMLRPC_VectorGetValueWithID(node, TOKEN_XMLRPC_FAULTSTRING)) { |
|||
return 1; |
|||
} |
|||
else if (XMLRPC_VectorGetValueWithID(node, TOKEN_SOAP_FAULTCODE) && |
|||
XMLRPC_VectorGetValueWithID(node, TOKEN_SOAP_FAULTSTRING)) { |
|||
return 2; |
|||
} |
|||
return 0; |
|||
} |
|||
|
|||
/* input: an XMLRPC_VALUE representing a fault struct in xml-rpc style. |
|||
* output: an XMLRPC_VALUE representing a fault struct in soap style, |
|||
* with xmlrpc codes mapped to soap codes, and all other values preserved. |
|||
* note that the returned value is a completely new value, and must be freed. |
|||
* the input value is untouched. |
|||
*/ |
|||
static XMLRPC_VALUE gen_fault_xmlrpc(XMLRPC_VALUE node, xml_element* el_target) { |
|||
XMLRPC_VALUE xDup = XMLRPC_DupValueNew(node); |
|||
XMLRPC_VALUE xCode = XMLRPC_VectorGetValueWithID(xDup, TOKEN_XMLRPC_FAULTCODE); |
|||
XMLRPC_VALUE xStr = XMLRPC_VectorGetValueWithID(xDup, TOKEN_XMLRPC_FAULTSTRING); |
|||
|
|||
XMLRPC_SetValueID(xCode, TOKEN_SOAP_FAULTCODE, 0); |
|||
XMLRPC_SetValueID(xStr, TOKEN_SOAP_FAULTSTRING, 0); |
|||
|
|||
/* rough mapping of xmlrpc fault codes to soap codes */ |
|||
switch (XMLRPC_GetValueInt(xCode)) { |
|||
case -32700: /* "parse error. not well formed", */ |
|||
case -32701: /* "parse error. unsupported encoding" */ |
|||
case -32702: /* "parse error. invalid character for encoding" */ |
|||
case -32600: /* "server error. invalid xml-rpc. not conforming to spec." */ |
|||
case -32601: /* "server error. requested method not found" */ |
|||
case -32602: /* "server error. invalid method parameters" */ |
|||
XMLRPC_SetValueString(xCode, "SOAP-ENV:Client", 0); |
|||
break; |
|||
case -32603: /* "server error. internal xml-rpc error" */ |
|||
case -32500: /* "application error" */ |
|||
case -32400: /* "system error" */ |
|||
case -32300: /* "transport error */ |
|||
XMLRPC_SetValueString(xCode, "SOAP-ENV:Server", 0); |
|||
break; |
|||
} |
|||
return xDup; |
|||
} |
|||
|
|||
/* returns a new XMLRPC_VALUE representing a soap fault, comprised of a struct with four keys. */ |
|||
static XMLRPC_VALUE gen_soap_fault(const char* fault_code, const char* fault_string, |
|||
const char* actor, const char* details) { |
|||
XMLRPC_VALUE xReturn = XMLRPC_CreateVector(TOKEN_FAULT, xmlrpc_vector_struct); |
|||
XMLRPC_AddValuesToVector(xReturn, |
|||
XMLRPC_CreateValueString(TOKEN_SOAP_FAULTCODE, fault_code, 0), |
|||
XMLRPC_CreateValueString(TOKEN_SOAP_FAULTSTRING, fault_string, 0), |
|||
XMLRPC_CreateValueString(TOKEN_SOAP_FAULTACTOR, actor, 0), |
|||
XMLRPC_CreateValueString(TOKEN_SOAP_FAULTDETAILS, details, 0), |
|||
NULL); |
|||
return xReturn; |
|||
} |
|||
|
|||
/* translates xml soap dom to native data structures. recursive. */ |
|||
XMLRPC_VALUE xml_element_to_SOAP_REQUEST_worker(XMLRPC_REQUEST request, |
|||
XMLRPC_VALUE xParent, |
|||
struct array_info* parent_array, |
|||
XMLRPC_VALUE xCurrent, |
|||
xml_element* el, |
|||
int depth) { |
|||
XMLRPC_REQUEST_TYPE rtype = xmlrpc_request_none; |
|||
|
|||
/* no current element on first call */ |
|||
if (!xCurrent) { |
|||
xCurrent = XMLRPC_CreateValueEmpty(); |
|||
} |
|||
|
|||
/* increment recursion depth gauge */ |
|||
depth ++; |
|||
|
|||
/* safety first. must have a valid element */ |
|||
if (el && el->name) { |
|||
const char* id = NULL; |
|||
const char* type = NULL, *arrayType=NULL, *actor = NULL; |
|||
xml_element_attr* attr_iter = Q_Head(&el->attrs); |
|||
int b_must_understand = 0; |
|||
|
|||
/* in soap, types may be specified in either element name -or- with xsi:type attribute. */ |
|||
if (is_soap_type(el->name)) { |
|||
type = el->name; |
|||
} |
|||
/* if our parent node, by definition a vector, is not an array, then |
|||
our element name must be our key identifier. */ |
|||
else if (XMLRPC_GetVectorType(xParent) != xmlrpc_vector_array) { |
|||
id = el->name; |
|||
if(!strcmp(id, "item")) { |
|||
} |
|||
} |
|||
|
|||
/* iterate through element attributes, pick out useful stuff. */ |
|||
while (attr_iter) { |
|||
/* element's type */ |
|||
if (!strcmp(attr_iter->key, TOKEN_TYPE)) { |
|||
type = attr_iter->val; |
|||
} |
|||
/* array type */ |
|||
else if (!strcmp(attr_iter->key, TOKEN_ARRAY_TYPE)) { |
|||
arrayType = attr_iter->val; |
|||
} |
|||
/* must understand, sometimes present in headers. */ |
|||
else if (!strcmp(attr_iter->key, TOKEN_MUSTUNDERSTAND)) { |
|||
b_must_understand = strchr(attr_iter->val, '1') ? 1 : 0; |
|||
} |
|||
/* actor, used in conjunction with must understand. */ |
|||
else if (!strcmp(attr_iter->key, TOKEN_ACTOR)) { |
|||
actor = attr_iter->val; |
|||
} |
|||
attr_iter = Q_Next(&el->attrs); |
|||
} |
|||
|
|||
/* check if caller says we must understand something in a header. */ |
|||
if (b_must_understand) { |
|||
/* is must understand actually indended for us? |
|||
BUG: spec says we should also determine if actor is our URL, but |
|||
we do not have that information. */ |
|||
if (!actor || !strcmp(actor, TOKEN_ACTOR_NEXT)) { |
|||
/* TODO: implement callbacks or other mechanism for applications |
|||
to "understand" these headers. For now, we just bail if we |
|||
get a mustUnderstand header intended for us. */ |
|||
XMLRPC_RequestSetError(request, |
|||
gen_soap_fault("SOAP-ENV:MustUnderstand", |
|||
"SOAP Must Understand Error", |
|||
"", "")); |
|||
return xCurrent; |
|||
} |
|||
} |
|||
|
|||
/* set id (key) if one was found. */ |
|||
if (id) { |
|||
XMLRPC_SetValueID_Case(xCurrent, id, 0, xmlrpc_case_exact); |
|||
} |
|||
|
|||
/* according to soap spec, |
|||
depth 1 = Envelope, 2 = Header, Body & Fault, 3 = methodcall or response. */ |
|||
if (depth == 3) { |
|||
const char* methodname = el->name; |
|||
char* p = NULL; |
|||
|
|||
/* BUG: we determine request or response type using presence of "Response" in element name. |
|||
According to spec, this is only recommended, not required. Apparently, implementations |
|||
are supposed to know the type of action based on state, which strikes me as a bit lame. |
|||
Anyway, we don't have that state info, thus we use Response as a heuristic. */ |
|||
rtype = |
|||
#ifdef strcasestr |
|||
strcasestr(el->name, "response") ? xmlrpc_request_response : xmlrpc_request_call; |
|||
#else |
|||
strstr(el->name, "esponse") ? xmlrpc_request_response : xmlrpc_request_call; |
|||
#endif |
|||
XMLRPC_RequestSetRequestType(request, rtype); |
|||
|
|||
/* Get methodname. strip xml namespace crap. */ |
|||
p = strchr(el->name, ':'); |
|||
if (p) { |
|||
methodname = p + 1; |
|||
} |
|||
if (rtype == xmlrpc_request_call) { |
|||
XMLRPC_RequestSetMethodName(request, methodname); |
|||
} |
|||
} |
|||
|
|||
|
|||
/* Next, we begin to convert actual values. if no children, then must be a scalar value. */ |
|||
if (!Q_Size(&el->children)) { |
|||
if (!type && parent_array && parent_array->kids_type[0]) { |
|||
type = parent_array->kids_type; |
|||
} |
|||
if (!type || !strcmp(type, TOKEN_STRING)) { |
|||
XMLRPC_SetValueString(xCurrent, el->text.str, el->text.len); |
|||
} |
|||
else if (!strcmp(type, TOKEN_INT)) { |
|||
XMLRPC_SetValueInt(xCurrent, atoi(el->text.str)); |
|||
} |
|||
else if (!strcmp(type, TOKEN_BOOLEAN)) { |
|||
XMLRPC_SetValueBoolean(xCurrent, atoi(el->text.str)); |
|||
} |
|||
else if (!strcmp(type, TOKEN_DOUBLE) || |
|||
!strcmp(type, TOKEN_FLOAT)) { |
|||
XMLRPC_SetValueDouble(xCurrent, atof(el->text.str)); |
|||
} |
|||
else if (!strcmp(type, TOKEN_NULL)) { |
|||
/* already an empty val. do nothing. */ |
|||
} |
|||
else if (!strcmp(type, TOKEN_DATETIME)) { |
|||
XMLRPC_SetValueDateTime_ISO8601(xCurrent, el->text.str); |
|||
} |
|||
else if (!strcmp(type, TOKEN_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); |
|||
} |
|||
} |
|||
/* Element has children, thus a vector, or "compound type" in soap-speak. */ |
|||
else { |
|||
struct array_info* ai = NULL; |
|||
xml_element* iter = (xml_element*)Q_Head(&el->children); |
|||
|
|||
if (!type || !strcmp(type, TOKEN_STRUCT)) { |
|||
XMLRPC_SetIsVector(xCurrent, xmlrpc_vector_struct); |
|||
} |
|||
else if (!strcmp(type, TOKEN_ARRAY) || arrayType != NULL) { |
|||
/* determine magic associated with soap array type. |
|||
this is passed down as we recurse, so our children have access to the info. */ |
|||
ai = parse_array_type_info(arrayType); /* alloc'ed ai free'd below. */ |
|||
XMLRPC_SetIsVector(xCurrent, xmlrpc_vector_array); |
|||
} |
|||
else { |
|||
/* mixed is probably closest thing we have to compound type. */ |
|||
XMLRPC_SetIsVector(xCurrent, xmlrpc_vector_mixed); |
|||
} |
|||
/* Recurse, adding values as we go. Check for error during recursion |
|||
and if found, bail. this short-circuits us out of the recursion. */ |
|||
while ( iter && !XMLRPC_RequestGetError(request) ) { |
|||
XMLRPC_VALUE xNext = NULL; |
|||
/* top level elements don't actually represent values, so we just pass the |
|||
current value along until we are deep enough. */ |
|||
if ( depth <= 2 || |
|||
(rtype == xmlrpc_request_response && depth <= 3) ) { |
|||
xml_element_to_SOAP_REQUEST_worker(request, NULL, ai, xCurrent, iter, depth); |
|||
} |
|||
/* ready to do some actual de-serialization. create a new empty value and |
|||
pass that along to be init'd, then add it to our current vector. */ |
|||
else { |
|||
xNext = XMLRPC_CreateValueEmpty(); |
|||
xml_element_to_SOAP_REQUEST_worker(request, xCurrent, ai, xNext, iter, depth); |
|||
XMLRPC_AddValueToVector(xCurrent, xNext); |
|||
} |
|||
iter = (xml_element*)Q_Next(&el->children); |
|||
} |
|||
/* cleanup */ |
|||
if (ai) { |
|||
efree(ai); |
|||
} |
|||
} |
|||
} |
|||
return xCurrent; |
|||
} |
|||
|
|||
/* Convert soap xml dom to XMLRPC_VALUE, sans request info. untested. */ |
|||
XMLRPC_VALUE xml_element_to_SOAP_VALUE(xml_element* el) |
|||
{ |
|||
return xml_element_to_SOAP_REQUEST_worker(NULL, NULL, NULL, NULL, el, 0); |
|||
} |
|||
|
|||
/* Convert soap xml dom to XMLRPC_REQUEST */ |
|||
XMLRPC_VALUE xml_element_to_SOAP_REQUEST(XMLRPC_REQUEST request, xml_element* el) |
|||
{ |
|||
if (request) { |
|||
return XMLRPC_RequestSetData(request, xml_element_to_SOAP_REQUEST_worker(request, NULL, NULL, NULL, el, 0)); |
|||
} |
|||
return NULL; |
|||
} |
|||
|
|||
|
|||
/* translates data structures to soap/xml. recursive */ |
|||
xml_element* SOAP_to_xml_element_worker(XMLRPC_REQUEST request, XMLRPC_VALUE node) { |
|||
#define BUF_SIZE 128 |
|||
xml_element* elem_val = NULL; |
|||
if (node) { |
|||
int bFreeNode = 0; /* sometimes we may need to free 'node' variable */ |
|||
char buf[BUF_SIZE]; |
|||
XMLRPC_VALUE_TYPE_EASY type = XMLRPC_GetValueTypeEasy(node); |
|||
char* pName = NULL, *pAttrType = NULL; |
|||
|
|||
/* create our return value element */ |
|||
elem_val = xml_elem_new(); |
|||
|
|||
switch (type) { |
|||
case xmlrpc_type_struct: |
|||
case xmlrpc_type_mixed: |
|||
case xmlrpc_type_array: |
|||
if (type == xmlrpc_type_array) { |
|||
/* array's are _very_ special in soap. |
|||
TODO: Should handle sparse/partial arrays here. */ |
|||
|
|||
/* determine soap array type. */ |
|||
const char* type = get_array_soap_type(node); |
|||
xml_element_attr* attr_array_type = NULL; |
|||
|
|||
/* specify array kids type and array size. */ |
|||
snprintf(buf, sizeof(buf), "%s[%i]", type, XMLRPC_VectorSize(node)); |
|||
attr_array_type = new_attr(TOKEN_ARRAY_TYPE, buf); |
|||
|
|||
Q_PushTail(&elem_val->attrs, attr_array_type); |
|||
|
|||
pAttrType = TOKEN_ARRAY; |
|||
} |
|||
/* check for fault, which is a rather special case. |
|||
(can't these people design anything consistent/simple/elegant?) */ |
|||
else if (type == xmlrpc_type_struct) { |
|||
int fault_type = get_fault_type(node); |
|||
if (fault_type) { |
|||
if (fault_type == 1) { |
|||
/* gen fault from xmlrpc style fault codes |
|||
notice that we get a new node, which must be freed herein. */ |
|||
node = gen_fault_xmlrpc(node, elem_val); |
|||
bFreeNode = 1; |
|||
} |
|||
pName = TOKEN_FAULT; |
|||
} |
|||
} |
|||
|
|||
{ |
|||
/* recurse through sub-elements */ |
|||
XMLRPC_VALUE xIter = XMLRPC_VectorRewind(node); |
|||
while ( xIter ) { |
|||
xml_element* next_el = SOAP_to_xml_element_worker(request, xIter); |
|||
if (next_el) { |
|||
Q_PushTail(&elem_val->children, next_el); |
|||
} |
|||
xIter = XMLRPC_VectorNext(node); |
|||
} |
|||
} |
|||
|
|||
break; |
|||
|
|||
/* handle scalar types */ |
|||
case xmlrpc_type_empty: |
|||
pAttrType = TOKEN_NULL; |
|||
break; |
|||
case xmlrpc_type_string: |
|||
pAttrType = TOKEN_STRING; |
|||
simplestring_addn(&elem_val->text, XMLRPC_GetValueString(node), XMLRPC_GetValueStringLen(node)); |
|||
break; |
|||
case xmlrpc_type_int: |
|||
pAttrType = TOKEN_INT; |
|||
snprintf(buf, BUF_SIZE, "%i", XMLRPC_GetValueInt(node)); |
|||
simplestring_add(&elem_val->text, buf); |
|||
break; |
|||
case xmlrpc_type_boolean: |
|||
pAttrType = TOKEN_BOOLEAN; |
|||
snprintf(buf, BUF_SIZE, "%i", XMLRPC_GetValueBoolean(node)); |
|||
simplestring_add(&elem_val->text, buf); |
|||
break; |
|||
case xmlrpc_type_double: |
|||
pAttrType = TOKEN_DOUBLE; |
|||
snprintf(buf, BUF_SIZE, "%f", XMLRPC_GetValueDouble(node)); |
|||
simplestring_add(&elem_val->text, buf); |
|||
break; |
|||
case xmlrpc_type_datetime: |
|||
{ |
|||
time_t tt = XMLRPC_GetValueDateTime(node); |
|||
struct tm *tm = localtime (&tt); |
|||
pAttrType = TOKEN_DATETIME; |
|||
if(strftime (buf, BUF_SIZE, "%Y-%m-%dT%H:%M:%SZ", tm)) { |
|||
simplestring_add(&elem_val->text, buf); |
|||
} |
|||
} |
|||
break; |
|||
case xmlrpc_type_base64: |
|||
{ |
|||
struct buffer_st buf; |
|||
pAttrType = TOKEN_BASE64; |
|||
base64_encode_xmlrpc(&buf, XMLRPC_GetValueBase64(node), XMLRPC_GetValueStringLen(node)); |
|||
simplestring_addn(&elem_val->text, buf.data, buf.offset ); |
|||
buffer_delete(&buf); |
|||
} |
|||
break; |
|||
break; |
|||
default: |
|||
break; |
|||
} |
|||
|
|||
/* determining element's name is a bit tricky, due to soap semantics. */ |
|||
if (!pName) { |
|||
/* if the value's type is known... */ |
|||
if (pAttrType) { |
|||
/* see if it has an id (key). If so, use that as name, and type as an attribute. */ |
|||
pName = (char*)XMLRPC_GetValueID(node); |
|||
if (pName) { |
|||
Q_PushTail(&elem_val->attrs, new_attr(TOKEN_TYPE, pAttrType)); |
|||
} |
|||
|
|||
/* otherwise, use the type as the name. */ |
|||
else { |
|||
pName = pAttrType; |
|||
} |
|||
} |
|||
/* if the value's type is not known... (a rare case?) */ |
|||
else { |
|||
/* see if it has an id (key). otherwise, default to generic "item" */ |
|||
pName = (char*)XMLRPC_GetValueID(node); |
|||
if (!pName) { |
|||
pName = "item"; |
|||
} |
|||
} |
|||
} |
|||
elem_val->name = estrdup(pName); |
|||
|
|||
/* cleanup */ |
|||
if (bFreeNode) { |
|||
XMLRPC_CleanupValue(node); |
|||
} |
|||
} |
|||
return elem_val; |
|||
} |
|||
|
|||
/* convert XMLRPC_VALUE to soap xml dom. untested. */ |
|||
xml_element* SOAP_VALUE_to_xml_element(XMLRPC_VALUE node) { |
|||
return SOAP_to_xml_element_worker(NULL, node); |
|||
} |
|||
|
|||
/* convert XMLRPC_REQUEST to soap xml dom. */ |
|||
xml_element* SOAP_REQUEST_to_xml_element(XMLRPC_REQUEST request) { |
|||
xml_element* root = xml_elem_new(); |
|||
|
|||
/* safety first. */ |
|||
if (root) { |
|||
xml_element* body = xml_elem_new(); |
|||
root->name = estrdup("SOAP-ENV:Envelope"); |
|||
|
|||
/* silly namespace stuff */ |
|||
Q_PushTail(&root->attrs, new_attr("xmlns:SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/")); |
|||
Q_PushTail(&root->attrs, new_attr("xmlns:xsi", "http://www.w3.org/1999/XMLSchema-instance")); |
|||
Q_PushTail(&root->attrs, new_attr("xmlns:xsd", "http://www.w3.org/1999/XMLSchema")); |
|||
Q_PushTail(&root->attrs, new_attr("xmlns:SOAP-ENC", "http://schemas.xmlsoap.org/soap/encoding/")); |
|||
Q_PushTail(&root->attrs, new_attr("xmlns:si", "http://soapinterop.org/xsd")); |
|||
Q_PushTail(&root->attrs, new_attr("xmlns:ns6", "http://testuri.org")); |
|||
Q_PushTail(&root->attrs, new_attr("SOAP-ENV:encodingStyle", "http://schemas.xmlsoap.org/soap/encoding/")); |
|||
|
|||
/* Q_PushHead(&root->attrs, new_attr("xmlns:ks", "http://kitchen.sink.org/soap/everything/under/sun")); |
|||
JUST KIDDING!! :-) ----> ------------------------------------------------- */ |
|||
|
|||
if (body) { |
|||
/* go ahead and serialize first... */ |
|||
xml_element* el_serialized = |
|||
SOAP_to_xml_element_worker(request, |
|||
XMLRPC_RequestGetData(request)); |
|||
|
|||
/* check for fault, in which case, there is no intermediate element */ |
|||
if (el_serialized && !strcmp(el_serialized->name, TOKEN_FAULT)) { |
|||
Q_PushTail(&body->children, el_serialized); |
|||
} |
|||
/* usual case: not a fault. Add Response element in between. */ |
|||
else { |
|||
xml_element* rpc = xml_elem_new(); |
|||
|
|||
if (rpc) { |
|||
const char* methodname = XMLRPC_RequestGetMethodName(request); |
|||
XMLRPC_REQUEST_TYPE rtype = XMLRPC_RequestGetRequestType(request); |
|||
|
|||
/* if we are making a request, we want to use the methodname as is. */ |
|||
if (rtype == xmlrpc_request_call) { |
|||
if (methodname) { |
|||
rpc->name = estrdup(methodname); |
|||
} |
|||
} |
|||
/* if it's a response, we append "Response". Also, given xmlrpc-epi |
|||
API/architecture, it's likely that we don't have a methodname for |
|||
the response, so we have to check that. */ |
|||
else { |
|||
char buf[128]; |
|||
snprintf(buf, sizeof(buf), "%s%s", |
|||
methodname ? methodname : "", |
|||
"Response"); |
|||
|
|||
rpc->name = estrdup(buf); |
|||
} |
|||
|
|||
/* add serialized data to method call/response. |
|||
add method call/response to body element */ |
|||
if (rpc->name) { |
|||
if(el_serialized) { |
|||
if(Q_Size(&el_serialized->children) && rtype == xmlrpc_request_call) { |
|||
xml_element* iter = (xml_element*)Q_Head(&el_serialized->children); |
|||
while(iter) { |
|||
Q_PushTail(&rpc->children, iter); |
|||
iter = (xml_element*)Q_Next(&el_serialized->children); |
|||
} |
|||
xml_elem_free_non_recurse(el_serialized); |
|||
} |
|||
else { |
|||
Q_PushTail(&rpc->children, el_serialized); |
|||
} |
|||
} |
|||
|
|||
Q_PushTail(&body->children, rpc); |
|||
} |
|||
else { |
|||
/* no method name?! |
|||
TODO: fault here...? */ |
|||
} |
|||
} |
|||
} |
|||
body->name = estrdup("SOAP-ENV:Body"); |
|||
Q_PushTail(&root->children, body); |
|||
} |
|||
} |
|||
|
|||
return root; |
|||
} |
|||
@ -1,44 +0,0 @@ |
|||
/* |
|||
This file is part of libXMLRPC - a C library for xml-encoded function calls. |
|||
|
|||
Author: Dan Libby (dan@libby.com) |
|||
Epinions.com may be contacted at feedback@epinions-inc.com |
|||
*/ |
|||
|
|||
/* |
|||
Copyright 2000 Epinions, Inc. |
|||
|
|||
Subject to the following 3 conditions, Epinions, Inc. permits you, free |
|||
of charge, to (a) use, copy, distribute, modify, perform and display this |
|||
software and associated documentation files (the "Software"), and (b) |
|||
permit others to whom the Software is furnished to do so as well. |
|||
|
|||
1) The above copyright notice and this permission notice shall be included |
|||
without modification in all copies or substantial portions of the |
|||
Software. |
|||
|
|||
2) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTY OR CONDITION OF |
|||
ANY KIND, EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION ANY |
|||
IMPLIED WARRANTIES OF ACCURACY, MERCHANTABILITY, FITNESS FOR A PARTICULAR |
|||
PURPOSE OR NONINFRINGEMENT. |
|||
|
|||
3) IN NO EVENT SHALL EPINIONS, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, |
|||
SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT |
|||
OF OR IN CONNECTION WITH THE SOFTWARE (HOWEVER ARISING, INCLUDING |
|||
NEGLIGENCE), EVEN IF EPINIONS, INC. IS AWARE OF THE POSSIBILITY OF SUCH |
|||
DAMAGES. |
|||
|
|||
*/ |
|||
|
|||
|
|||
#ifndef XML_TO_SOAP_H |
|||
#define XML_TO_SOAP_H |
|||
|
|||
#include "xmlrpc.h" |
|||
|
|||
XMLRPC_VALUE xml_element_to_SOAP_VALUE(xml_element* el); |
|||
XMLRPC_VALUE xml_element_to_SOAP_REQUEST(XMLRPC_REQUEST request, xml_element* el); |
|||
xml_element* SOAP_VALUE_to_xml_element(XMLRPC_VALUE node); |
|||
xml_element* SOAP_REQUEST_to_xml_element(XMLRPC_REQUEST request); |
|||
|
|||
#endif /* XML_TO_XMLRPC_H */ |
|||
@ -1,407 +0,0 @@ |
|||
/* |
|||
This file is part of libXMLRPC - a C library for xml-encoded function calls. |
|||
|
|||
Author: Dan Libby (dan@libby.com) |
|||
Epinions.com may be contacted at feedback@epinions-inc.com |
|||
*/ |
|||
|
|||
/* |
|||
Copyright 2000 Epinions, Inc. |
|||
|
|||
Subject to the following 3 conditions, Epinions, Inc. permits you, free |
|||
of charge, to (a) use, copy, distribute, modify, perform and display this |
|||
software and associated documentation files (the "Software"), and (b) |
|||
permit others to whom the Software is furnished to do so as well. |
|||
|
|||
1) The above copyright notice and this permission notice shall be included |
|||
without modification in all copies or substantial portions of the |
|||
Software. |
|||
|
|||
2) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTY OR CONDITION OF |
|||
ANY KIND, EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION ANY |
|||
IMPLIED WARRANTIES OF ACCURACY, MERCHANTABILITY, FITNESS FOR A PARTICULAR |
|||
PURPOSE OR NONINFRINGEMENT. |
|||
|
|||
3) IN NO EVENT SHALL EPINIONS, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, |
|||
SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT |
|||
OF OR IN CONNECTION WITH THE SOFTWARE (HOWEVER ARISING, INCLUDING |
|||
NEGLIGENCE), EVEN IF EPINIONS, INC. IS AWARE OF THE POSSIBILITY OF SUCH |
|||
DAMAGES. |
|||
|
|||
*/ |
|||
|
|||
|
|||
#include "php.h" |
|||
#include "main/snprintf.h" |
|||
#include <string.h> |
|||
#include <stdlib.h> |
|||
#include "xml_to_xmlrpc.h" |
|||
#include "base64.h" |
|||
|
|||
/* list of tokens used in vocab */ |
|||
#define ELEM_ARRAY "array" |
|||
#define ELEM_BASE64 "base64" |
|||
#define ELEM_BOOLEAN "boolean" |
|||
#define ELEM_DATA "data" |
|||
#define ELEM_DATETIME "dateTime.iso8601" |
|||
#define ELEM_DOUBLE "double" |
|||
#define ELEM_FAULT "fault" |
|||
#define ELEM_FAULTCODE "faultCode" |
|||
#define ELEM_FAULTSTRING "faultString" |
|||
#define ELEM_I4 "i4" |
|||
#define ELEM_INT "int" |
|||
#define ELEM_MEMBER "member" |
|||
#define ELEM_METHODCALL "methodCall" |
|||
#define ELEM_METHODNAME "methodName" |
|||
#define ELEM_METHODRESPONSE "methodResponse" |
|||
#define ELEM_NAME "name" |
|||
#define ELEM_PARAM "param" |
|||
#define ELEM_PARAMS "params" |
|||
#define ELEM_STRING "string" |
|||
#define ELEM_STRUCT "struct" |
|||
#define ELEM_VALUE "value" |
|||
|
|||
|
|||
XMLRPC_VALUE xml_element_to_XMLRPC_REQUEST_worker(XMLRPC_REQUEST request, XMLRPC_VALUE parent_vector, XMLRPC_VALUE current_val, xml_element* el) { |
|||
if (!current_val) { |
|||
/* This should only be the case for the first element */ |
|||
current_val = XMLRPC_CreateValueEmpty(); |
|||
} |
|||
|
|||
if (el->name) { |
|||
|
|||
/* first, deal with the crazy/stupid fault format */ |
|||
if (!strcmp(el->name, ELEM_FAULT)) { |
|||
xml_element* fault_value = (xml_element*)Q_Head(&el->children); |
|||
XMLRPC_SetIsVector(current_val, xmlrpc_vector_struct); |
|||
|
|||
if(fault_value) { |
|||
xml_element* fault_struct = (xml_element*)Q_Head(&fault_value->children); |
|||
if(fault_struct) { |
|||
xml_element* iter = (xml_element*)Q_Head(&fault_struct->children); |
|||
|
|||
while (iter) { |
|||
XMLRPC_VALUE xNextVal = XMLRPC_CreateValueEmpty(); |
|||
xml_element_to_XMLRPC_REQUEST_worker(request, current_val, xNextVal, iter); |
|||
XMLRPC_AddValueToVector(current_val, xNextVal); |
|||
iter = (xml_element*)Q_Next(&fault_struct->children); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
else if (!strcmp(el->name, ELEM_DATA) /* should be ELEM_ARRAY, but there is an extra level. weird */ |
|||
|| (!strcmp(el->name, ELEM_PARAMS) && |
|||
(XMLRPC_RequestGetRequestType(request) == xmlrpc_request_call)) ) { /* this "PARAMS" concept is silly. dave?! */ |
|||
xml_element* iter = (xml_element*)Q_Head(&el->children); |
|||
XMLRPC_SetIsVector(current_val, xmlrpc_vector_array); |
|||
|
|||
while (iter) { |
|||
XMLRPC_VALUE xNextVal = XMLRPC_CreateValueEmpty(); |
|||
xml_element_to_XMLRPC_REQUEST_worker(request, current_val, xNextVal, iter); |
|||
XMLRPC_AddValueToVector(current_val, xNextVal); |
|||
iter = (xml_element*)Q_Next(&el->children); |
|||
} |
|||
} |
|||
else if (!strcmp(el->name, ELEM_STRUCT)) { |
|||
xml_element* iter = (xml_element*)Q_Head(&el->children); |
|||
XMLRPC_SetIsVector(current_val, xmlrpc_vector_struct); |
|||
|
|||
while ( iter ) { |
|||
XMLRPC_VALUE xNextVal = XMLRPC_CreateValueEmpty(); |
|||
xml_element_to_XMLRPC_REQUEST_worker(request, current_val, xNextVal, iter); |
|||
XMLRPC_AddValueToVector(current_val, xNextVal); |
|||
iter = (xml_element*)Q_Next(&el->children); |
|||
} |
|||
} |
|||
else if (!strcmp(el->name, ELEM_STRING) || |
|||
(!strcmp(el->name, ELEM_VALUE) && Q_Size(&el->children) == 0)) { |
|||
XMLRPC_SetValueString(current_val, el->text.str, el->text.len); |
|||
} |
|||
else if (!strcmp(el->name, ELEM_NAME)) { |
|||
XMLRPC_SetValueID_Case(current_val, el->text.str, 0, xmlrpc_case_exact); |
|||
} |
|||
else if (!strcmp(el->name, ELEM_INT) || !strcmp(el->name, ELEM_I4)) { |
|||
XMLRPC_SetValueInt(current_val, atoi(el->text.str)); |
|||
} |
|||
else if (!strcmp(el->name, ELEM_BOOLEAN)) { |
|||
XMLRPC_SetValueBoolean(current_val, atoi(el->text.str)); |
|||
} |
|||
else if (!strcmp(el->name, ELEM_DOUBLE)) { |
|||
XMLRPC_SetValueDouble(current_val, atof(el->text.str)); |
|||
} |
|||
else if (!strcmp(el->name, ELEM_DATETIME)) { |
|||
XMLRPC_SetValueDateTime_ISO8601(current_val, el->text.str); |
|||
} |
|||
else if (!strcmp(el->name, ELEM_BASE64)) { |
|||
struct buffer_st buf; |
|||
base64_decode_xmlrpc(&buf, el->text.str, el->text.len); |
|||
XMLRPC_SetValueBase64(current_val, buf.data, buf.offset); |
|||
buffer_delete(&buf); |
|||
} |
|||
else { |
|||
xml_element* iter; |
|||
|
|||
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); |
|||
} |
|||
} |
|||
|
|||
iter = (xml_element*)Q_Head(&el->children); |
|||
while ( iter ) { |
|||
xml_element_to_XMLRPC_REQUEST_worker(request, parent_vector, |
|||
current_val, iter); |
|||
iter = (xml_element*)Q_Next(&el->children); |
|||
} |
|||
} |
|||
} |
|||
return current_val; |
|||
} |
|||
|
|||
XMLRPC_VALUE xml_element_to_XMLRPC_VALUE(xml_element* el) |
|||
{ |
|||
return xml_element_to_XMLRPC_REQUEST_worker(NULL, NULL, NULL, el); |
|||
} |
|||
|
|||
XMLRPC_VALUE xml_element_to_XMLRPC_REQUEST(XMLRPC_REQUEST request, xml_element* el) |
|||
{ |
|||
if (request) { |
|||
return XMLRPC_RequestSetData(request, xml_element_to_XMLRPC_REQUEST_worker(request, NULL, NULL, el)); |
|||
} |
|||
return NULL; |
|||
} |
|||
|
|||
xml_element* XMLRPC_to_xml_element_worker(XMLRPC_VALUE current_vector, XMLRPC_VALUE node, |
|||
XMLRPC_REQUEST_TYPE request_type, int depth) { |
|||
#define BUF_SIZE 512 |
|||
xml_element* root = NULL; |
|||
if (node) { |
|||
char buf[BUF_SIZE]; |
|||
XMLRPC_VALUE_TYPE type = XMLRPC_GetValueType(node); |
|||
XMLRPC_VECTOR_TYPE vtype = XMLRPC_GetVectorType(node); |
|||
xml_element* elem_val = xml_elem_new(); |
|||
|
|||
/* special case for when root element is not an array */ |
|||
if (depth == 0 && |
|||
!(type == xmlrpc_vector && |
|||
vtype == xmlrpc_vector_array && |
|||
request_type == xmlrpc_request_call) ) { |
|||
int bIsFault = (vtype == xmlrpc_vector_struct && XMLRPC_VectorGetValueWithID(node, ELEM_FAULTCODE)); |
|||
|
|||
xml_element* next_el = XMLRPC_to_xml_element_worker(NULL, node, request_type, depth + 1); |
|||
if (next_el) { |
|||
Q_PushTail(&elem_val->children, next_el); |
|||
} |
|||
elem_val->name = estrdup(bIsFault ? ELEM_FAULT : ELEM_PARAMS); |
|||
} |
|||
else { |
|||
switch (type) { |
|||
case xmlrpc_empty: /* treat null value as empty string in xmlrpc. */ |
|||
case xmlrpc_string: |
|||
elem_val->name = estrdup(ELEM_STRING); |
|||
simplestring_addn(&elem_val->text, XMLRPC_GetValueString(node), XMLRPC_GetValueStringLen(node)); |
|||
break; |
|||
case xmlrpc_int: |
|||
elem_val->name = estrdup(ELEM_INT); |
|||
snprintf(buf, BUF_SIZE, "%i", XMLRPC_GetValueInt(node)); |
|||
simplestring_add(&elem_val->text, buf); |
|||
break; |
|||
case xmlrpc_boolean: |
|||
elem_val->name = estrdup(ELEM_BOOLEAN); |
|||
snprintf(buf, BUF_SIZE, "%i", XMLRPC_GetValueBoolean(node)); |
|||
simplestring_add(&elem_val->text, buf); |
|||
break; |
|||
case xmlrpc_double: |
|||
{ |
|||
elem_val->name = estrdup(ELEM_DOUBLE); |
|||
ap_php_snprintf(buf, BUF_SIZE, "%.*G", (int) EG(precision), XMLRPC_GetValueDouble(node)); |
|||
simplestring_add(&elem_val->text, buf); |
|||
} |
|||
break; |
|||
case xmlrpc_datetime: |
|||
elem_val->name = estrdup(ELEM_DATETIME); |
|||
simplestring_add(&elem_val->text, XMLRPC_GetValueDateTime_ISO8601(node)); |
|||
break; |
|||
case xmlrpc_base64: |
|||
{ |
|||
struct buffer_st buf; |
|||
elem_val->name = estrdup(ELEM_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); |
|||
xml_element* root_vector_elem = elem_val; |
|||
|
|||
switch (my_type) { |
|||
case xmlrpc_vector_array: |
|||
{ |
|||
if(depth == 0) { |
|||
elem_val->name = estrdup(ELEM_PARAMS); |
|||
} |
|||
else { |
|||
/* Hi my name is Dave and I like to make things as confusing |
|||
* as possible, thus I will throw in this 'data' element |
|||
* where it absolutely does not belong just so that people |
|||
* cannot code arrays and structs in a similar and straight |
|||
* forward manner. Have a good day. |
|||
* |
|||
* GRRRRRRRRR! |
|||
*/ |
|||
xml_element* data = xml_elem_new(); |
|||
data->name = estrdup(ELEM_DATA); |
|||
|
|||
elem_val->name = estrdup(ELEM_ARRAY); |
|||
Q_PushTail(&elem_val->children, data); |
|||
root_vector_elem = data; |
|||
} |
|||
} |
|||
break; |
|||
case xmlrpc_vector_mixed: /* not officially supported */ |
|||
case xmlrpc_vector_struct: |
|||
elem_val->name = estrdup(ELEM_STRUCT); |
|||
break; |
|||
default: |
|||
break; |
|||
} |
|||
|
|||
/* recurse through sub-elements */ |
|||
while ( xIter ) { |
|||
xml_element* next_el = XMLRPC_to_xml_element_worker(node, xIter, request_type, depth + 1); |
|||
if (next_el) { |
|||
Q_PushTail(&root_vector_elem->children, next_el); |
|||
} |
|||
xIter = XMLRPC_VectorNext(node); |
|||
} |
|||
} |
|||
break; |
|||
default: |
|||
break; |
|||
} |
|||
} |
|||
|
|||
{ |
|||
XMLRPC_VECTOR_TYPE vtype = XMLRPC_GetVectorType(current_vector); |
|||
|
|||
if (depth == 1) { |
|||
xml_element* value = xml_elem_new(); |
|||
value->name = estrdup(ELEM_VALUE); |
|||
|
|||
/* yet another hack for the "fault" crap */ |
|||
if (XMLRPC_VectorGetValueWithID(node, ELEM_FAULTCODE)) { |
|||
root = value; |
|||
} |
|||
else { |
|||
xml_element* param = xml_elem_new(); |
|||
param->name = estrdup(ELEM_PARAM); |
|||
|
|||
Q_PushTail(¶m->children, value); |
|||
|
|||
root = param; |
|||
} |
|||
Q_PushTail(&value->children, elem_val); |
|||
} |
|||
else if (vtype == xmlrpc_vector_struct || vtype == xmlrpc_vector_mixed) { |
|||
xml_element* member = xml_elem_new(); |
|||
xml_element* name = xml_elem_new(); |
|||
xml_element* value = xml_elem_new(); |
|||
|
|||
member->name = estrdup(ELEM_MEMBER); |
|||
name->name = estrdup(ELEM_NAME); |
|||
value->name = estrdup(ELEM_VALUE); |
|||
|
|||
simplestring_add(&name->text, XMLRPC_GetValueID(node)); |
|||
|
|||
Q_PushTail(&member->children, name); |
|||
Q_PushTail(&member->children, value); |
|||
Q_PushTail(&value->children, elem_val); |
|||
|
|||
root = member; |
|||
} |
|||
else if (vtype == xmlrpc_vector_array) { |
|||
xml_element* value = xml_elem_new(); |
|||
|
|||
value->name = estrdup(ELEM_VALUE); |
|||
|
|||
Q_PushTail(&value->children, elem_val); |
|||
|
|||
root = value; |
|||
} |
|||
else if (vtype == xmlrpc_vector_none) { |
|||
/* no parent. non-op */ |
|||
root = elem_val; |
|||
} |
|||
else { |
|||
xml_element* value = xml_elem_new(); |
|||
|
|||
value->name = estrdup(ELEM_VALUE); |
|||
|
|||
Q_PushTail(&value->children, elem_val); |
|||
|
|||
root = value; |
|||
} |
|||
} |
|||
} |
|||
return root; |
|||
} |
|||
|
|||
xml_element* XMLRPC_VALUE_to_xml_element(XMLRPC_VALUE node) { |
|||
return XMLRPC_to_xml_element_worker(NULL, node, xmlrpc_request_none, 0); |
|||
} |
|||
|
|||
xml_element* XMLRPC_REQUEST_to_xml_element(XMLRPC_REQUEST request) { |
|||
xml_element* wrapper = NULL; |
|||
if (request) { |
|||
const char* pStr = NULL; |
|||
XMLRPC_REQUEST_TYPE request_type = XMLRPC_RequestGetRequestType(request); |
|||
XMLRPC_VALUE xParams = XMLRPC_RequestGetData(request); |
|||
|
|||
wrapper = xml_elem_new(); |
|||
|
|||
if (request_type == xmlrpc_request_call) { |
|||
pStr = ELEM_METHODCALL; |
|||
} |
|||
else if (request_type == xmlrpc_request_response) { |
|||
pStr = ELEM_METHODRESPONSE; |
|||
} |
|||
if (pStr) { |
|||
wrapper->name = estrdup(pStr); |
|||
} |
|||
|
|||
if(request_type == xmlrpc_request_call) { |
|||
pStr = XMLRPC_RequestGetMethodName(request); |
|||
|
|||
if (pStr) { |
|||
xml_element* method = xml_elem_new(); |
|||
method->name = estrdup(ELEM_METHODNAME); |
|||
simplestring_add(&method->text, pStr); |
|||
Q_PushTail(&wrapper->children, method); |
|||
} |
|||
} |
|||
if (xParams) { |
|||
Q_PushTail(&wrapper->children, |
|||
XMLRPC_to_xml_element_worker(NULL, XMLRPC_RequestGetData(request), XMLRPC_RequestGetRequestType(request), 0)); |
|||
} |
|||
else { |
|||
/* Despite the spec, the xml-rpc list folk want me to send an empty params element */ |
|||
xml_element* params = xml_elem_new(); |
|||
params->name = estrdup(ELEM_PARAMS); |
|||
Q_PushTail(&wrapper->children, params); |
|||
} |
|||
} |
|||
return wrapper; |
|||
} |
|||
@ -1,45 +0,0 @@ |
|||
/* |
|||
This file is part of libXMLRPC - a C library for xml-encoded function calls. |
|||
|
|||
Author: Dan Libby (dan@libby.com) |
|||
Epinions.com may be contacted at feedback@epinions-inc.com |
|||
*/ |
|||
|
|||
/* |
|||
Copyright 2000 Epinions, Inc. |
|||
|
|||
Subject to the following 3 conditions, Epinions, Inc. permits you, free |
|||
of charge, to (a) use, copy, distribute, modify, perform and display this |
|||
software and associated documentation files (the "Software"), and (b) |
|||
permit others to whom the Software is furnished to do so as well. |
|||
|
|||
1) The above copyright notice and this permission notice shall be included |
|||
without modification in all copies or substantial portions of the |
|||
Software. |
|||
|
|||
2) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTY OR CONDITION OF |
|||
ANY KIND, EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION ANY |
|||
IMPLIED WARRANTIES OF ACCURACY, MERCHANTABILITY, FITNESS FOR A PARTICULAR |
|||
PURPOSE OR NONINFRINGEMENT. |
|||
|
|||
3) IN NO EVENT SHALL EPINIONS, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, |
|||
SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT |
|||
OF OR IN CONNECTION WITH THE SOFTWARE (HOWEVER ARISING, INCLUDING |
|||
NEGLIGENCE), EVEN IF EPINIONS, INC. IS AWARE OF THE POSSIBILITY OF SUCH |
|||
DAMAGES. |
|||
|
|||
*/ |
|||
|
|||
|
|||
#ifndef XML_TO_XMLRPC_H |
|||
#define XML_TO_XMLRPC_H |
|||
|
|||
#include "time.h" |
|||
#include "xmlrpc.h" |
|||
|
|||
XMLRPC_VALUE xml_element_to_XMLRPC_VALUE(xml_element* el); |
|||
XMLRPC_VALUE xml_element_to_XMLRPC_REQUEST(XMLRPC_REQUEST request, xml_element* el); |
|||
xml_element* XMLRPC_VALUE_to_xml_element(XMLRPC_VALUE node); |
|||
xml_element* XMLRPC_REQUEST_to_xml_element(XMLRPC_REQUEST request); |
|||
|
|||
#endif /* XML_TO_XMLRPC_H */ |
|||
3005
ext/xmlrpc/libxmlrpc/xmlrpc.c
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -1,452 +0,0 @@ |
|||
/* |
|||
This file is part of libXMLRPC - a C library for xml-encoded function calls. |
|||
|
|||
Author: Dan Libby (dan@libby.com) |
|||
Epinions.com may be contacted at feedback@epinions-inc.com |
|||
*/ |
|||
|
|||
/* |
|||
Copyright 2000 Epinions, Inc. |
|||
|
|||
Subject to the following 3 conditions, Epinions, Inc. permits you, free |
|||
of charge, to (a) use, copy, distribute, modify, perform and display this |
|||
software and associated documentation files (the "Software"), and (b) |
|||
permit others to whom the Software is furnished to do so as well. |
|||
|
|||
1) The above copyright notice and this permission notice shall be included |
|||
without modification in all copies or substantial portions of the |
|||
Software. |
|||
|
|||
2) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTY OR CONDITION OF |
|||
ANY KIND, EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION ANY |
|||
IMPLIED WARRANTIES OF ACCURACY, MERCHANTABILITY, FITNESS FOR A PARTICULAR |
|||
PURPOSE OR NONINFRINGEMENT. |
|||
|
|||
3) IN NO EVENT SHALL EPINIONS, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, |
|||
SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT |
|||
OF OR IN CONNECTION WITH THE SOFTWARE (HOWEVER ARISING, INCLUDING |
|||
NEGLIGENCE), EVEN IF EPINIONS, INC. IS AWARE OF THE POSSIBILITY OF SUCH |
|||
DAMAGES. |
|||
|
|||
*/ |
|||
|
|||
#ifndef XMLRPC_ALREADY_INCLUDED |
|||
#define XMLRPC_ALREADY_INCLUDED 1 |
|||
|
|||
/* includes */ |
|||
#include "xml_element.h" |
|||
#include <time.h> /* for time_t */ |
|||
#include <php.h> |
|||
|
|||
#ifdef __cplusplus |
|||
extern "C" { |
|||
#endif |
|||
|
|||
/* allow version to be specified via compile line define */ |
|||
#ifndef XMLRPC_LIB_VERSION |
|||
#define XMLRPC_LIB_VERSION "0.51" |
|||
#endif |
|||
|
|||
/* this number, representing the date, must be increased each time the API changes */ |
|||
#define XMLRPC_API_NO 20020623 |
|||
|
|||
/* this string should be changed with each packaged release */ |
|||
#define XMLRPC_VERSION_STR "xmlrpc-epi v. " XMLRPC_LIB_VERSION |
|||
|
|||
/* where to find more info. shouldn't need to change much */ |
|||
#define XMLRPC_HOME_PAGE_STR "http://xmlprc-epi.sourceforge.net/" |
|||
|
|||
|
|||
/****d* VALUE/XMLRPC_VALUE_TYPE |
|||
* NAME |
|||
* XMLRPC_VALUE_TYPE |
|||
* NOTES |
|||
* Defines data types for XMLRPC_VALUE |
|||
* Deprecated for public use. See XMLRPC_VALUE_TYPE_EASY |
|||
* SEE ALSO |
|||
* XMLRPC_VECTOR_TYPE |
|||
* XMLRPC_REQUEST_TYPE |
|||
* SOURCE |
|||
*/ |
|||
typedef enum _XMLRPC_VALUE_TYPE { |
|||
xmlrpc_none, /* not a value */ |
|||
xmlrpc_empty, /* empty value, eg NULL */ |
|||
xmlrpc_base64, /* base64 value, eg binary data */ |
|||
xmlrpc_boolean, /* boolean [0 | 1] */ |
|||
xmlrpc_datetime, /* datetime [ISO8601 | time_t] */ |
|||
xmlrpc_double, /* double / floating point */ |
|||
xmlrpc_int, /* integer */ |
|||
xmlrpc_string, /* string */ |
|||
xmlrpc_vector /* vector, aka list, array */ |
|||
} XMLRPC_VALUE_TYPE; |
|||
/*******/ |
|||
|
|||
/****d* VALUE/XMLRPC_VECTOR_TYPE |
|||
* NAME |
|||
* XMLRPC_VECTOR_TYPE |
|||
* NOTES |
|||
* Defines data types for XMLRPC_VECTOR. |
|||
* Deprecated for public use. See XMLRPC_VALUE_TYPE_EASY |
|||
* SEE ALSO |
|||
* XMLRPC_VALUE_TYPE |
|||
* XMLRPC_REQUEST_TYPE |
|||
* SOURCE |
|||
*/ |
|||
typedef enum _XMLRPC_VECTOR_TYPE { |
|||
xmlrpc_vector_none, /* not an array */ |
|||
xmlrpc_vector_array, /* no values may have key names */ |
|||
xmlrpc_vector_mixed, /* some values may have key names */ |
|||
xmlrpc_vector_struct /* all values must have key names */ |
|||
} XMLRPC_VECTOR_TYPE; |
|||
/*******/ |
|||
|
|||
/****d* VALUE/XMLRPC_VALUE_TYPE_EASY |
|||
* NAME |
|||
* XMLRPC_VALUE_TYPE_EASY |
|||
* NOTES |
|||
* Defines data types for XMLRPC_VALUE, including vector types. |
|||
* SEE ALSO |
|||
* XMLRPC_VECTOR_TYPE |
|||
* XMLRPC_REQUEST_TYPE |
|||
* SOURCE |
|||
*/ |
|||
typedef enum _XMLRPC_VALUE_TYPE_EASY { |
|||
xmlrpc_type_none, /* not a value */ |
|||
xmlrpc_type_empty, /* empty value, eg NULL */ |
|||
xmlrpc_type_base64, /* base64 value, eg binary data */ |
|||
xmlrpc_type_boolean, /* boolean [0 | 1] */ |
|||
xmlrpc_type_datetime, /* datetime [ISO8601 | time_t] */ |
|||
xmlrpc_type_double, /* double / floating point */ |
|||
xmlrpc_type_int, /* integer */ |
|||
xmlrpc_type_string, /* string */ |
|||
/* -- IMPORTANT: identical to XMLRPC_VALUE_TYPE to this point. -- */ |
|||
xmlrpc_type_array, /* vector array */ |
|||
xmlrpc_type_mixed, /* vector mixed */ |
|||
xmlrpc_type_struct /* vector struct */ |
|||
} XMLRPC_VALUE_TYPE_EASY; |
|||
/*******/ |
|||
|
|||
|
|||
/****d* VALUE/XMLRPC_REQUEST_TYPE |
|||
* NAME |
|||
* XMLRPC_REQUEST_TYPE |
|||
* NOTES |
|||
* Defines data types for XMLRPC_REQUEST |
|||
* SEE ALSO |
|||
* XMLRPC_VALUE_TYPE |
|||
* XMLRPC_VECTOR_TYPE |
|||
* SOURCE |
|||
*/ |
|||
typedef enum _xmlrpc_request_type { |
|||
xmlrpc_request_none, /* not a valid request */ |
|||
xmlrpc_request_call, /* calling/invoking a method */ |
|||
xmlrpc_request_response, /* responding to a method call */ |
|||
} XMLRPC_REQUEST_TYPE; |
|||
/*******/ |
|||
|
|||
/****d* VALUE/XMLRPC_ERROR_CODE |
|||
* NAME |
|||
* XMLRPC_ERROR_CODE |
|||
* NOTES |
|||
* All existing error codes |
|||
* SEE ALSO |
|||
* XMLRPC_REQUEST_ERROR |
|||
* SOURCE |
|||
*/ |
|||
typedef enum _xmlrpc_error_code { |
|||
xmlrpc_error_none = 0, /* not an error */ |
|||
xmlrpc_error_parse_xml_syntax = -32700, |
|||
xmlrpc_error_parse_unknown_encoding = -32701, |
|||
xmlrpc_error_parse_bad_encoding = -32702, |
|||
xmlrpc_error_invalid_xmlrpc = -32600, |
|||
xmlrpc_error_unknown_method = -32601, |
|||
xmlrpc_error_invalid_params = -32602, |
|||
xmlrpc_error_internal_server = -32603, |
|||
xmlrpc_error_application = -32500, |
|||
xmlrpc_error_system = -32400, |
|||
xmlrpc_error_transport = -32300 |
|||
} XMLRPC_ERROR_CODE; |
|||
/******/ |
|||
|
|||
#define xmlrpc_error_parse_xml_syntax_str "parse error. not well formed." |
|||
#define xmlrpc_error_parse_unknown_encoding_str "parse error. unknown encoding" |
|||
#define xmlrpc_error_parse_bad_encoding_str "parse error. invalid character for encoding" |
|||
#define xmlrpc_error_invalid_xmlrpc_str "server error. xml-rpc not conforming to spec" |
|||
#define xmlrpc_error_unknown_method_str "server error. method not found." |
|||
#define xmlrpc_error_invalid_params_str "server error. invalid method parameters" |
|||
#define xmlrpc_error_internal_server_str "server error. internal xmlrpc library error" |
|||
#define xmlrpc_error_application_str "application error." |
|||
#define xmlrpc_error_system_str "system error." |
|||
#define xmlrpc_error_transport_str "transport error." |
|||
|
|||
|
|||
|
|||
/****d* VALUE/XMLRPC_VERSION |
|||
* NAME |
|||
* XMLRPC_VERSION |
|||
* NOTES |
|||
* Defines xml vocabulary used for generated xml |
|||
* SEE ALSO |
|||
* XMLRPC_REQUEST_OUTPUT_OPTIONS |
|||
* XMLRPC_REQUEST_To_XML () |
|||
* SOURCE |
|||
*/ |
|||
typedef enum _xmlrpc_version { |
|||
xmlrpc_version_none = 0, /* not a recognized vocabulary */ |
|||
xmlrpc_version_1_0 = 1, /* xmlrpc 1.0 standard vocab */ |
|||
xmlrpc_version_simple = 2, /* alt more readable vocab */ |
|||
xmlrpc_version_danda = 2, /* same as simple. legacy */ |
|||
xmlrpc_version_soap_1_1 = 3 /* SOAP. version 1.1 */ |
|||
} XMLRPC_VERSION; |
|||
/******/ |
|||
|
|||
/****s* VALUE/XMLRPC_REQUEST_OUTPUT_OPTIONS |
|||
* NAME |
|||
* XMLRPC_REQUEST_OUTPUT_OPTIONS |
|||
* NOTES |
|||
* Defines output options for generated xml |
|||
* SEE ALSO |
|||
* XMLRPC_VERSION |
|||
* XML_ELEM_OUTPUT_OPTIONS |
|||
* XMLRPC_REQUEST_To_XML () |
|||
* SOURCE |
|||
*/ |
|||
typedef struct _xmlrpc_request_output_options { |
|||
STRUCT_XML_ELEM_OUTPUT_OPTIONS xml_elem_opts; /* xml_element specific output options */ |
|||
XMLRPC_VERSION version; /* xml vocabulary to use */ |
|||
} STRUCT_XMLRPC_REQUEST_OUTPUT_OPTIONS, *XMLRPC_REQUEST_OUTPUT_OPTIONS; |
|||
/******/ |
|||
|
|||
/****s* VALUE/XMLRPC_REQUEST_INPUT_OPTIONS |
|||
* NAME |
|||
* XMLRPC_REQUEST_INPUT_OPTIONS |
|||
* NOTES |
|||
* Defines options for reading in xml data |
|||
* SEE ALSO |
|||
* XMLRPC_VERSION |
|||
* XML_ELEM_INPUT_OPTIONS |
|||
* XMLRPC_REQUEST_From_XML () |
|||
* SOURCE |
|||
*/ |
|||
typedef struct _xmlrpc_request_input_options { |
|||
STRUCT_XML_ELEM_INPUT_OPTIONS xml_elem_opts; /* xml_element specific output options */ |
|||
} STRUCT_XMLRPC_REQUEST_INPUT_OPTIONS, *XMLRPC_REQUEST_INPUT_OPTIONS; |
|||
/******/ |
|||
|
|||
/****s* VALUE/XMLRPC_ERROR |
|||
* NAME |
|||
* XMLRPC_ERROR |
|||
* NOTES |
|||
* For the reporting and handling of errors |
|||
* SOURCE |
|||
*/ |
|||
typedef struct _xmlrpc_error { |
|||
XMLRPC_ERROR_CODE code; |
|||
STRUCT_XML_ELEM_ERROR xml_elem_error; /* xml_element errors (parser errors) */ |
|||
} STRUCT_XMLRPC_ERROR, *XMLRPC_ERROR; |
|||
/******/ |
|||
|
|||
|
|||
/****d* VALUE/XMLRPC_CASE_COMPARISON |
|||
* NAME |
|||
* XMLRPC_CASE_COMPARISON |
|||
* NOTES |
|||
* Defines case comparison options for XMLRPC_VALUE/VECTOR API's |
|||
* SEE ALSO |
|||
* XMLRPC_CASE |
|||
* XMLRPC_VALUE |
|||
* SOURCE |
|||
*/ |
|||
typedef enum _xmlrpc_case_comparison { |
|||
xmlrpc_case_insensitive, /* use case-insensitive compare */ |
|||
xmlrpc_case_sensitive /* use case-sensitive compare */ |
|||
} XMLRPC_CASE_COMPARISON; |
|||
/******/ |
|||
|
|||
/****d* VALUE/XMLRPC_CASE |
|||
* NAME |
|||
* XMLRPC_CASE |
|||
* NOTES |
|||
* Defines case behavior when setting IDs in XMLRPC_VALUE API's |
|||
* SEE ALSO |
|||
* XMLRPC_CASE_COMPARISON |
|||
* XMLRPC_VALUE |
|||
* SOURCE |
|||
*/ |
|||
typedef enum _xmlrpc_case { |
|||
xmlrpc_case_exact, /* leave case alone */ |
|||
xmlrpc_case_lower, /* lower-case id */ |
|||
xmlrpc_case_upper /* upper-case id */ |
|||
} XMLRPC_CASE; |
|||
/******/ |
|||
|
|||
/* if you don't like these defaults, you can set them with XMLRPC_SetDefaultIdCase*() */ |
|||
#define XMLRPC_DEFAULT_ID_CASE XMLRPC_GetDefaultIdCase() |
|||
#define XMLRPC_DEFAULT_ID_CASE_SENSITIVITY XMLRPC_GetDefaultIdCaseComparison() |
|||
|
|||
/* opaque (non-public) types. defined locally in xmlrpc.c */ |
|||
typedef struct _xmlrpc_request* XMLRPC_REQUEST; |
|||
typedef struct _xmlrpc_server* XMLRPC_SERVER; |
|||
typedef struct _xmlrpc_value* XMLRPC_VALUE; |
|||
|
|||
/****d* VALUE/XMLRPC_Callback |
|||
* NAME |
|||
* XMLRPC_Callback |
|||
* NOTES |
|||
* Function prototype for user defined method handlers (callbacks). |
|||
* SEE ALSO |
|||
* XMLRPC_ServerRegisterMethod () |
|||
* XMLRPC_ServerCallMethod () |
|||
* XMLRPC_REQUEST |
|||
* XMLRPC_VALUE |
|||
* SOURCE |
|||
*/ |
|||
typedef XMLRPC_VALUE (*XMLRPC_Callback)(XMLRPC_SERVER server, XMLRPC_REQUEST input, void* userData); |
|||
/******/ |
|||
|
|||
/* ID Case Defaults */ |
|||
XMLRPC_CASE XMLRPC_GetDefaultIdCase(void); |
|||
XMLRPC_CASE XMLRPC_SetDefaultIdCase(XMLRPC_CASE id_case); |
|||
XMLRPC_CASE_COMPARISON XMLRPC_GetDefaultIdCaseComparison(void); |
|||
XMLRPC_CASE_COMPARISON XMLRPC_SetDefaultIdCaseComparison(XMLRPC_CASE_COMPARISON id_case); |
|||
|
|||
/* Vector manipulation */ |
|||
int XMLRPC_VectorSize(XMLRPC_VALUE value); |
|||
XMLRPC_VALUE XMLRPC_VectorRewind(XMLRPC_VALUE value); |
|||
XMLRPC_VALUE XMLRPC_VectorNext(XMLRPC_VALUE value); |
|||
int XMLRPC_SetIsVector(XMLRPC_VALUE value, XMLRPC_VECTOR_TYPE type); |
|||
int XMLRPC_AddValueToVector(XMLRPC_VALUE target, XMLRPC_VALUE source); |
|||
int XMLRPC_AddValuesToVector(XMLRPC_VALUE target, ...); |
|||
int XMLRPC_VectorRemoveValue(XMLRPC_VALUE vector, XMLRPC_VALUE value); |
|||
XMLRPC_VALUE XMLRPC_VectorGetValueWithID_Case(XMLRPC_VALUE vector, const char* id, XMLRPC_CASE_COMPARISON id_case); |
|||
|
|||
|
|||
/* Create values */ |
|||
XMLRPC_VALUE XMLRPC_CreateValueBoolean(const char* id, int truth); |
|||
XMLRPC_VALUE XMLRPC_CreateValueBase64(const char* id, const char* s, int len); |
|||
XMLRPC_VALUE XMLRPC_CreateValueDateTime(const char* id, time_t time); |
|||
XMLRPC_VALUE XMLRPC_CreateValueDateTime_ISO8601(const char* id, const char *s); |
|||
XMLRPC_VALUE XMLRPC_CreateValueDouble(const char* id, double f); |
|||
XMLRPC_VALUE XMLRPC_CreateValueInt(const char* id, int i); |
|||
XMLRPC_VALUE XMLRPC_CreateValueString(const char* id, const char* s, int len); |
|||
XMLRPC_VALUE XMLRPC_CreateValueEmpty(void); |
|||
XMLRPC_VALUE XMLRPC_CreateVector(const char* id, XMLRPC_VECTOR_TYPE type); |
|||
|
|||
/* Cleanup values */ |
|||
void XMLRPC_CleanupValue(XMLRPC_VALUE value); |
|||
|
|||
/* Request error */ |
|||
XMLRPC_VALUE XMLRPC_RequestSetError (XMLRPC_REQUEST request, XMLRPC_VALUE error); |
|||
XMLRPC_VALUE XMLRPC_RequestGetError (XMLRPC_REQUEST request); |
|||
|
|||
/* Copy values */ |
|||
XMLRPC_VALUE XMLRPC_CopyValue(XMLRPC_VALUE value); |
|||
XMLRPC_VALUE XMLRPC_DupValueNew(XMLRPC_VALUE xSource); |
|||
|
|||
/* Set Values */ |
|||
void XMLRPC_SetValueDateTime(XMLRPC_VALUE value, time_t time); |
|||
void XMLRPC_SetValueDateTime_ISO8601(XMLRPC_VALUE value, const char* s); |
|||
void XMLRPC_SetValueDouble(XMLRPC_VALUE value, double val); |
|||
void XMLRPC_SetValueInt(XMLRPC_VALUE value, int val); |
|||
void XMLRPC_SetValueBoolean(XMLRPC_VALUE value, int val); |
|||
const char *XMLRPC_SetValueString(XMLRPC_VALUE value, const char* s, int len); |
|||
void XMLRPC_SetValueBase64(XMLRPC_VALUE value, const char* s, int len); |
|||
const char *XMLRPC_SetValueID_Case(XMLRPC_VALUE value, const char* id, int len, XMLRPC_CASE id_case); |
|||
#define XMLRPC_SetValueID(value, id, len) XMLRPC_SetValueID_Case(value, id, len, XMLRPC_DEFAULT_ID_CASE) |
|||
|
|||
/* Get Values */ |
|||
const char* XMLRPC_GetValueString(XMLRPC_VALUE value); |
|||
int XMLRPC_GetValueStringLen(XMLRPC_VALUE value); |
|||
int XMLRPC_GetValueInt(XMLRPC_VALUE value); |
|||
int XMLRPC_GetValueBoolean(XMLRPC_VALUE value); |
|||
double XMLRPC_GetValueDouble(XMLRPC_VALUE value); |
|||
const char* XMLRPC_GetValueBase64(XMLRPC_VALUE value); |
|||
time_t XMLRPC_GetValueDateTime(XMLRPC_VALUE value); |
|||
const char* XMLRPC_GetValueDateTime_ISO8601(XMLRPC_VALUE value); |
|||
const char* XMLRPC_GetValueID(XMLRPC_VALUE value); |
|||
|
|||
/* Type introspection */ |
|||
XMLRPC_VALUE_TYPE XMLRPC_GetValueType(XMLRPC_VALUE v); |
|||
XMLRPC_VALUE_TYPE_EASY XMLRPC_GetValueTypeEasy(XMLRPC_VALUE v); |
|||
XMLRPC_VECTOR_TYPE XMLRPC_GetVectorType(XMLRPC_VALUE v); |
|||
|
|||
/* Parsing and Creating XML */ |
|||
XMLRPC_REQUEST XMLRPC_REQUEST_FromXML(const char* in_buf, int len, XMLRPC_REQUEST_INPUT_OPTIONS in_options); |
|||
XMLRPC_VALUE XMLRPC_VALUE_FromXML(const char* in_buf, int len, XMLRPC_REQUEST_INPUT_OPTIONS in_options); |
|||
char* XMLRPC_REQUEST_ToXML(XMLRPC_REQUEST request, int *buf_len); |
|||
char* XMLRPC_VALUE_ToXML(XMLRPC_VALUE val, int* buf_len); |
|||
|
|||
/* Request manipulation funcs */ |
|||
const char* XMLRPC_RequestSetMethodName(XMLRPC_REQUEST request, const char* methodName); |
|||
const char* XMLRPC_RequestGetMethodName(XMLRPC_REQUEST request); |
|||
XMLRPC_REQUEST XMLRPC_RequestNew(void); |
|||
void XMLRPC_RequestFree(XMLRPC_REQUEST request, int bFreeIO); |
|||
XMLRPC_REQUEST_OUTPUT_OPTIONS XMLRPC_RequestSetOutputOptions(XMLRPC_REQUEST request, XMLRPC_REQUEST_OUTPUT_OPTIONS output); |
|||
XMLRPC_REQUEST_OUTPUT_OPTIONS XMLRPC_RequestGetOutputOptions(XMLRPC_REQUEST request); |
|||
XMLRPC_VALUE XMLRPC_RequestSetData(XMLRPC_REQUEST request, XMLRPC_VALUE data); |
|||
XMLRPC_VALUE XMLRPC_RequestGetData(XMLRPC_REQUEST request); |
|||
XMLRPC_REQUEST_TYPE XMLRPC_RequestSetRequestType(XMLRPC_REQUEST request, XMLRPC_REQUEST_TYPE type); |
|||
XMLRPC_REQUEST_TYPE XMLRPC_RequestGetRequestType(XMLRPC_REQUEST request); |
|||
|
|||
/* Server Creation/Destruction; Method Registration and Invocation */ |
|||
XMLRPC_SERVER XMLRPC_ServerCreate(void); |
|||
XMLRPC_SERVER XMLRPC_GetGlobalServer(void); /* better to use XMLRPC_ServerCreate if you can */ |
|||
void XMLRPC_ServerDestroy(XMLRPC_SERVER server); |
|||
int XMLRPC_ServerRegisterMethod(XMLRPC_SERVER server, const char *name, XMLRPC_Callback cb); |
|||
XMLRPC_Callback XMLRPC_ServerFindMethod(XMLRPC_SERVER server, const char* callName); |
|||
XMLRPC_VALUE XMLRPC_ServerCallMethod(XMLRPC_SERVER server, XMLRPC_REQUEST request, void* userData); |
|||
|
|||
#include "xmlrpc_introspection.h" |
|||
|
|||
/* Fault interrogation funcs */ |
|||
int XMLRPC_ValueIsFault (XMLRPC_VALUE value); |
|||
int XMLRPC_ResponseIsFault(XMLRPC_REQUEST response); |
|||
int XMLRPC_GetValueFaultCode (XMLRPC_VALUE value); |
|||
int XMLRPC_GetResponseFaultCode(XMLRPC_REQUEST response); |
|||
const char* XMLRPC_GetValueFaultString (XMLRPC_VALUE value); |
|||
const char* XMLRPC_GetResponseFaultString (XMLRPC_REQUEST response); |
|||
|
|||
|
|||
/* Public Utility funcs */ |
|||
XMLRPC_VALUE XMLRPC_UtilityCreateFault(int fault_code, const char* fault_string); |
|||
void XMLRPC_Free(void* mem); |
|||
const char* XMLRPC_GetVersionString(void); |
|||
|
|||
/****d* VALUE/XMLRPC_MACROS |
|||
* NAME |
|||
* Some Helpful Macros |
|||
* NOTES |
|||
* Some macros for making life easier. Should be self-explanatory. |
|||
* SEE ALSO |
|||
* XMLRPC_AddValueToVector () |
|||
* XMLRPC_VectorGetValueWithID_Case () |
|||
* XMLRPC_VALUE |
|||
* SOURCE |
|||
*/ |
|||
|
|||
/* Append values to vector */ |
|||
#define XMLRPC_VectorAppendString(vector, id, s, len) XMLRPC_AddValueToVector(vector, XMLRPC_CreateValueString(id, s, len)) |
|||
#define XMLRPC_VectorAppendBase64(vector, id, s, len) XMLRPC_AddValueToVector(vector, XMLRPC_CreateValueBase64(id, s, len)) |
|||
#define XMLRPC_VectorAppendDateTime(vector, id, time) XMLRPC_AddValueToVector(vector, XMLRPC_CreateValueDateTime(id, time)) |
|||
#define XMLRPC_VectorAppendDateTime_ISO8601(vector, id, s) XMLRPC_AddValueToVector(vector, XMLRPC_CreateValueDateTime_ISO8601(id, s)) |
|||
#define XMLRPC_VectorAppendDouble(vector, id, f) XMLRPC_AddValueToVector(vector, XMLRPC_CreateValueDouble(id, f)) |
|||
#define XMLRPC_VectorAppendInt(vector, id, i) XMLRPC_AddValueToVector(vector, XMLRPC_CreateValueInt(id, i)) |
|||
#define XMLRPC_VectorAppendBoolean(vector, id, i) XMLRPC_AddValueToVector(vector, XMLRPC_CreateValueBoolean(id, i)) |
|||
|
|||
/* Get named values from vector */ |
|||
#define XMLRPC_VectorGetValueWithID(vector, id) XMLRPC_VectorGetValueWithID_Case(vector, id, XMLRPC_DEFAULT_ID_CASE_SENSITIVITY) |
|||
#define XMLRPC_VectorGetStringWithID(vector, id) XMLRPC_GetValueString(XMLRPC_VectorGetValueWithID(vector, id)) |
|||
#define XMLRPC_VectorGetBase64WithID(vector, id) XMLRPC_GetValueBase64(XMLRPC_VectorGetValueWithID(vector, id)) |
|||
#define XMLRPC_VectorGetDateTimeWithID(vector, id) XMLRPC_GetValueDateTime(XMLRPC_VectorGetValueWithID(vector, id)) |
|||
#define XMLRPC_VectorGetDoubleWithID(vector, id) XMLRPC_GetValueDouble(XMLRPC_VectorGetValueWithID(vector, id)) |
|||
#define XMLRPC_VectorGetIntWithID(vector, id) XMLRPC_GetValueInt(XMLRPC_VectorGetValueWithID(vector, id)) |
|||
#define XMLRPC_VectorGetBooleanWithID(vector, id) XMLRPC_GetValueBoolean(XMLRPC_VectorGetValueWithID(vector, id)) |
|||
|
|||
/******/ |
|||
|
|||
|
|||
#ifdef __cplusplus |
|||
} |
|||
#endif |
|||
|
|||
#endif /* not XMLRPC_ALREADY_INCLUDED */ |
|||
@ -1,598 +0,0 @@ |
|||
/* |
|||
This file is part of libXMLRPC - a C library for xml-encoded function calls. |
|||
|
|||
Author: Dan Libby (dan@libby.com) |
|||
Epinions.com may be contacted at feedback@epinions-inc.com |
|||
*/ |
|||
|
|||
/* |
|||
Copyright 2001 Epinions, Inc. |
|||
|
|||
Subject to the following 3 conditions, Epinions, Inc. permits you, free |
|||
of charge, to (a) use, copy, distribute, modify, perform and display this |
|||
software and associated documentation files (the "Software"), and (b) |
|||
permit others to whom the Software is furnished to do so as well. |
|||
|
|||
1) The above copyright notice and this permission notice shall be included |
|||
without modification in all copies or substantial portions of the |
|||
Software. |
|||
|
|||
2) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTY OR CONDITION OF |
|||
ANY KIND, EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION ANY |
|||
IMPLIED WARRANTIES OF ACCURACY, MERCHANTABILITY, FITNESS FOR A PARTICULAR |
|||
PURPOSE OR NONINFRINGEMENT. |
|||
|
|||
3) IN NO EVENT SHALL EPINIONS, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, |
|||
SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT |
|||
OF OR IN CONNECTION WITH THE SOFTWARE (HOWEVER ARISING, INCLUDING |
|||
NEGLIGENCE), EVEN IF EPINIONS, INC. IS AWARE OF THE POSSIBILITY OF SUCH |
|||
DAMAGES. |
|||
|
|||
*/ |
|||
|
|||
|
|||
/****h* ABOUT/xmlrpc_introspection |
|||
* AUTHOR |
|||
* Dan Libby, aka danda (dan@libby.com) |
|||
* HISTORY |
|||
* $Log$ |
|||
* Revision 1.4 2003/12/16 21:00:21 sniper |
|||
* Fix some compile warnings (patch by Joe Orton) |
|||
* |
|||
* Revision 1.3 2002/07/05 04:43:53 danda |
|||
* merged in updates from SF project. bring php repository up to date with xmlrpc-epi version 0.51 |
|||
* |
|||
* Revision 1.9 2001/09/29 21:58:05 danda |
|||
* adding cvs log to history section |
|||
* |
|||
* 4/10/2001 -- danda -- initial introspection support |
|||
* TODO |
|||
* NOTES |
|||
*******/ |
|||
|
|||
|
|||
#include "queue.h" |
|||
#include "xmlrpc.h" |
|||
#include "xmlrpc_private.h" |
|||
#include "xmlrpc_introspection_private.h" |
|||
#include <string.h> |
|||
#include <stdlib.h> |
|||
#include <stdarg.h> |
|||
|
|||
|
|||
/* forward declarations for static (non public, non api) funcs */ |
|||
static XMLRPC_VALUE xi_system_describe_methods_cb(XMLRPC_SERVER server, XMLRPC_REQUEST input, void* userData); |
|||
static XMLRPC_VALUE xi_system_list_methods_cb(XMLRPC_SERVER server, XMLRPC_REQUEST input, void* userData); |
|||
static XMLRPC_VALUE xi_system_method_signature_cb(XMLRPC_SERVER server, XMLRPC_REQUEST input, void* userData); |
|||
static XMLRPC_VALUE xi_system_method_help_cb(XMLRPC_SERVER server, XMLRPC_REQUEST input, void* userData); |
|||
|
|||
|
|||
/*-********************************** |
|||
* Introspection Callbacks (methods) * |
|||
************************************/ |
|||
|
|||
/* iterates through a list of structs and finds the one with key "name" matching |
|||
* needle. slow, would benefit from a struct key hash. |
|||
*/ |
|||
static inline XMLRPC_VALUE find_named_value(XMLRPC_VALUE list, const char* needle) { |
|||
XMLRPC_VALUE xIter = XMLRPC_VectorRewind(list); |
|||
while(xIter) { |
|||
const char* name = XMLRPC_VectorGetStringWithID(xIter, xi_token_name); |
|||
if(name && !strcmp(name, needle)) { |
|||
return xIter; |
|||
} |
|||
xIter = XMLRPC_VectorNext(list); |
|||
} |
|||
return NULL; |
|||
} |
|||
|
|||
|
|||
/* iterates through docs callbacks and calls any that have not yet been called */ |
|||
static void check_docs_loaded(XMLRPC_SERVER server, void* userData) { |
|||
if(server) { |
|||
q_iter qi = Q_Iter_Head_F(&server->docslist); |
|||
while( qi ) { |
|||
doc_method* dm = Q_Iter_Get_F(qi); |
|||
if(dm && !dm->b_called) { |
|||
dm->method(server, userData); |
|||
dm->b_called = 1; |
|||
} |
|||
qi = Q_Iter_Next_F(qi); |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
/* utility function for xi_system_describe_methods_cb */ |
|||
static inline void describe_method(XMLRPC_SERVER server, XMLRPC_VALUE vector, const char* method) { |
|||
if(method) { |
|||
server_method* sm = find_method(server, method); |
|||
if(sm) { |
|||
XMLRPC_AddValueToVector(vector, sm->desc); |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
|
|||
/* system.describeMethods() callback */ |
|||
static XMLRPC_VALUE xi_system_describe_methods_cb(XMLRPC_SERVER server, XMLRPC_REQUEST input, void* userData) { |
|||
XMLRPC_VALUE xParams = XMLRPC_VectorRewind(XMLRPC_RequestGetData(input)); |
|||
XMLRPC_VALUE xResponse = XMLRPC_CreateVector(NULL, xmlrpc_vector_struct); |
|||
XMLRPC_VALUE xMethodList = XMLRPC_CreateVector("methodList", xmlrpc_vector_array); |
|||
XMLRPC_VALUE xTypeList = NULL; |
|||
int bAll = 1; |
|||
|
|||
/* lazy loading of introspection data */ |
|||
check_docs_loaded(server, userData); |
|||
|
|||
xTypeList = XMLRPC_VectorGetValueWithID(server->xIntrospection, "typeList"); |
|||
|
|||
XMLRPC_AddValueToVector(xResponse, xTypeList); |
|||
XMLRPC_AddValueToVector(xResponse, xMethodList); |
|||
|
|||
/* check if we have any param */ |
|||
if(xParams) { |
|||
/* check if string or vector (1 or n) */ |
|||
XMLRPC_VALUE_TYPE type = XMLRPC_GetValueType(xParams); |
|||
if(type == xmlrpc_string) { |
|||
/* just one. spit it out. */ |
|||
describe_method(server, xMethodList, XMLRPC_GetValueString(xParams)); |
|||
bAll = 0; |
|||
} |
|||
else if(type == xmlrpc_vector) { |
|||
/* multiple. spit all out */ |
|||
XMLRPC_VALUE xIter = XMLRPC_VectorRewind(xParams); |
|||
while(xIter) { |
|||
describe_method(server, xMethodList, XMLRPC_GetValueString(xIter)); |
|||
xIter = XMLRPC_VectorNext(xParams); |
|||
} |
|||
bAll = 0; |
|||
} |
|||
} |
|||
|
|||
/* otherwise, default to sending all methods */ |
|||
if(bAll) { |
|||
q_iter qi = Q_Iter_Head_F(&server->methodlist); |
|||
while( qi ) { |
|||
server_method* sm = Q_Iter_Get_F(qi); |
|||
if(sm) { |
|||
XMLRPC_AddValueToVector(xMethodList, sm->desc); |
|||
} |
|||
qi = Q_Iter_Next_F(qi); |
|||
} |
|||
} |
|||
|
|||
return xResponse; |
|||
} |
|||
|
|||
/* this complies with system.listMethods as defined at http://xmlrpc.usefulinc.com/doc/reserved.html */ |
|||
static XMLRPC_VALUE xi_system_list_methods_cb(XMLRPC_SERVER server, XMLRPC_REQUEST input, void* userData) { |
|||
XMLRPC_VALUE xResponse = XMLRPC_CreateVector(NULL, xmlrpc_vector_array); |
|||
|
|||
q_iter qi = Q_Iter_Head_F(&server->methodlist); |
|||
while( qi ) { |
|||
server_method* sm = Q_Iter_Get_F(qi); |
|||
if(sm) { |
|||
XMLRPC_VectorAppendString(xResponse, 0, sm->name, 0); |
|||
} |
|||
qi = Q_Iter_Next_F(qi); |
|||
} |
|||
return xResponse; |
|||
} |
|||
|
|||
/* this complies with system.methodSignature as defined at |
|||
* http://xmlrpc.usefulinc.com/doc/sysmethodsig.html |
|||
*/ |
|||
static XMLRPC_VALUE xi_system_method_signature_cb(XMLRPC_SERVER server, XMLRPC_REQUEST input, void* userData) { |
|||
const char* method = XMLRPC_GetValueString(XMLRPC_VectorRewind(XMLRPC_RequestGetData(input))); |
|||
XMLRPC_VALUE xResponse = NULL; |
|||
|
|||
/* lazy loading of introspection data */ |
|||
check_docs_loaded(server, userData); |
|||
|
|||
if(method) { |
|||
server_method* sm = find_method(server, method); |
|||
if(sm && sm->desc) { |
|||
XMLRPC_VALUE xTypesArray = XMLRPC_CreateVector(NULL, xmlrpc_vector_array); |
|||
XMLRPC_VALUE xIter, xParams, xSig, xSigIter; |
|||
const char* type; |
|||
|
|||
/* array of possible signatures. */ |
|||
xResponse = XMLRPC_CreateVector(NULL, xmlrpc_vector_array); |
|||
|
|||
/* find first signature */ |
|||
xSig = XMLRPC_VectorGetValueWithID(sm->desc, xi_token_signatures); |
|||
xSigIter = XMLRPC_VectorRewind( xSig ); |
|||
|
|||
/* iterate through sigs */ |
|||
while(xSigIter) { |
|||
/* first type is the return value */ |
|||
type = XMLRPC_VectorGetStringWithID(XMLRPC_VectorRewind( |
|||
XMLRPC_VectorGetValueWithID(xSigIter, xi_token_returns)), |
|||
xi_token_type); |
|||
XMLRPC_AddValueToVector(xTypesArray, |
|||
XMLRPC_CreateValueString(NULL, |
|||
type ? type : type_to_str(xmlrpc_none, 0), |
|||
0)); |
|||
|
|||
/* the rest are parameters */ |
|||
xParams = XMLRPC_VectorGetValueWithID(xSigIter, xi_token_params); |
|||
xIter = XMLRPC_VectorRewind(xParams); |
|||
|
|||
/* iter through params, adding to types array */ |
|||
while(xIter) { |
|||
XMLRPC_AddValueToVector(xTypesArray, |
|||
XMLRPC_CreateValueString(NULL, |
|||
XMLRPC_VectorGetStringWithID(xIter, xi_token_type), |
|||
0)); |
|||
xIter = XMLRPC_VectorNext(xParams); |
|||
} |
|||
|
|||
/* add types for this signature */ |
|||
XMLRPC_AddValueToVector(xResponse, xTypesArray); |
|||
|
|||
xSigIter = XMLRPC_VectorNext( xSig ); |
|||
} |
|||
} |
|||
} |
|||
|
|||
return xResponse; |
|||
} |
|||
|
|||
/* this complies with system.methodHelp as defined at |
|||
* http://xmlrpc.usefulinc.com/doc/sysmethhelp.html |
|||
*/ |
|||
static XMLRPC_VALUE xi_system_method_help_cb(XMLRPC_SERVER server, XMLRPC_REQUEST input, void* userData) { |
|||
const char* method = XMLRPC_GetValueString(XMLRPC_VectorRewind(XMLRPC_RequestGetData(input))); |
|||
XMLRPC_VALUE xResponse = NULL; |
|||
|
|||
/* lazy loading of introspection data */ |
|||
check_docs_loaded(server, userData); |
|||
|
|||
if(method) { |
|||
server_method* sm = find_method(server, method); |
|||
if(sm && sm->desc) { |
|||
const char* help = XMLRPC_VectorGetStringWithID(sm->desc, xi_token_purpose); |
|||
|
|||
/* returns a documentation string, or empty string */ |
|||
xResponse = XMLRPC_CreateValueString(NULL, help ? help : xi_token_empty, 0); |
|||
} |
|||
} |
|||
|
|||
return xResponse; |
|||
} |
|||
|
|||
/*-************************************** |
|||
* End Introspection Callbacks (methods) * |
|||
****************************************/ |
|||
|
|||
|
|||
/*-************************ |
|||
* Introspection Utilities * |
|||
**************************/ |
|||
|
|||
/* performs registration of introspection methods */ |
|||
void xi_register_system_methods(XMLRPC_SERVER server) { |
|||
XMLRPC_ServerRegisterMethod(server, xi_token_system_list_methods, xi_system_list_methods_cb); |
|||
XMLRPC_ServerRegisterMethod(server, xi_token_system_method_help, xi_system_method_help_cb); |
|||
XMLRPC_ServerRegisterMethod(server, xi_token_system_method_signature, xi_system_method_signature_cb); |
|||
XMLRPC_ServerRegisterMethod(server, xi_token_system_describe_methods, xi_system_describe_methods_cb); |
|||
} |
|||
|
|||
/* describe a value (param, return, type) */ |
|||
static XMLRPC_VALUE describeValue_worker(const char* type, const char* id, const char* desc, int optional, const char* default_val, XMLRPC_VALUE sub_params) { |
|||
XMLRPC_VALUE xParam = NULL; |
|||
if(id || desc) { |
|||
xParam = XMLRPC_CreateVector(NULL, xmlrpc_vector_struct); |
|||
XMLRPC_VectorAppendString(xParam, xi_token_name, id, 0); |
|||
XMLRPC_VectorAppendString(xParam, xi_token_type, type, 0); |
|||
XMLRPC_VectorAppendString(xParam, xi_token_description, desc, 0); |
|||
if(optional != 2) { |
|||
XMLRPC_VectorAppendInt(xParam, xi_token_optional, optional); |
|||
} |
|||
if(optional == 1 && default_val) { |
|||
XMLRPC_VectorAppendString(xParam, xi_token_default, default_val, 0); |
|||
} |
|||
XMLRPC_AddValueToVector(xParam, sub_params); |
|||
} |
|||
return xParam; |
|||
} |
|||
|
|||
|
|||
/* convert an xml tree conforming to spec <url tbd> to XMLRPC_VALUE |
|||
* suitable for use with XMLRPC_ServerAddIntrospectionData |
|||
*/ |
|||
XMLRPC_VALUE xml_element_to_method_description(xml_element* el, XMLRPC_ERROR err) { |
|||
XMLRPC_VALUE xReturn = NULL; |
|||
|
|||
if(el->name) { |
|||
const char* name = NULL; |
|||
const char* type = NULL; |
|||
const char* basetype = NULL; |
|||
const char* desc = NULL; |
|||
const char* def = NULL; |
|||
int optional = 0; |
|||
xml_element_attr* attr_iter = Q_Head(&el->attrs); |
|||
|
|||
/* grab element attributes up front to save redundant while loops */ |
|||
while(attr_iter) { |
|||
if(!strcmp(attr_iter->key, "name")) { |
|||
name = attr_iter->val; |
|||
} |
|||
else if(!strcmp(attr_iter->key, "type")) { |
|||
type = attr_iter->val; |
|||
} |
|||
else if(!strcmp(attr_iter->key, "basetype")) { |
|||
basetype = attr_iter->val; |
|||
} |
|||
else if(!strcmp(attr_iter->key, "desc")) { |
|||
desc = attr_iter->val; |
|||
} |
|||
else if(!strcmp(attr_iter->key, "optional")) { |
|||
if(attr_iter->val && !strcmp(attr_iter->val, "yes")) { |
|||
optional = 1; |
|||
} |
|||
} |
|||
else if(!strcmp(attr_iter->key, "default")) { |
|||
def = attr_iter->val; |
|||
} |
|||
attr_iter = Q_Next(&el->attrs); |
|||
} |
|||
|
|||
/* value and typeDescription behave about the same */ |
|||
if(!strcmp(el->name, "value") || !strcmp(el->name, "typeDescription")) { |
|||
XMLRPC_VALUE xSubList = NULL; |
|||
const char* ptype = !strcmp(el->name, "value") ? type : basetype; |
|||
if(ptype) { |
|||
if(Q_Size(&el->children) && |
|||
(!strcmp(ptype, "array") || !strcmp(ptype, "struct") || !strcmp(ptype, "mixed"))) { |
|||
xSubList = XMLRPC_CreateVector("member", xmlrpc_vector_array); |
|||
|
|||
if(xSubList) { |
|||
xml_element* elem_iter = Q_Head(&el->children); |
|||
while(elem_iter) { |
|||
XMLRPC_AddValueToVector(xSubList, |
|||
xml_element_to_method_description(elem_iter, err)); |
|||
elem_iter = Q_Next(&el->children); |
|||
} |
|||
} |
|||
} |
|||
xReturn = describeValue_worker(ptype, name, (desc ? desc : (xSubList ? NULL : el->text.str)), optional, def, xSubList); |
|||
} |
|||
} |
|||
|
|||
/* these three kids are about equivalent */ |
|||
else if(!strcmp(el->name, "params") || |
|||
!strcmp(el->name, "returns") || |
|||
!strcmp(el->name, "signature")) { |
|||
if(Q_Size(&el->children)) { |
|||
xml_element* elem_iter = Q_Head(&el->children); |
|||
xReturn = XMLRPC_CreateVector(!strcmp(el->name, "signature") ? NULL : el->name, xmlrpc_vector_struct); |
|||
|
|||
|
|||
while(elem_iter) { |
|||
XMLRPC_AddValueToVector(xReturn, |
|||
xml_element_to_method_description(elem_iter, err)); |
|||
elem_iter = Q_Next(&el->children); |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
else if(!strcmp(el->name, "methodDescription")) { |
|||
xml_element* elem_iter = Q_Head(&el->children); |
|||
xReturn = XMLRPC_CreateVector(NULL, xmlrpc_vector_struct); |
|||
|
|||
XMLRPC_VectorAppendString(xReturn, xi_token_name, name, 0); |
|||
|
|||
while(elem_iter) { |
|||
XMLRPC_AddValueToVector(xReturn, |
|||
xml_element_to_method_description(elem_iter, err)); |
|||
elem_iter = Q_Next(&el->children); |
|||
} |
|||
} |
|||
|
|||
/* items are slightly special */ |
|||
else if(!strcmp(el->name, "item")) { |
|||
xReturn = XMLRPC_CreateValueString(name, el->text.str, el->text.len); |
|||
} |
|||
|
|||
/* sure. we'll let any ol element with children through */ |
|||
else if(Q_Size(&el->children)) { |
|||
xml_element* elem_iter = Q_Head(&el->children); |
|||
xReturn = XMLRPC_CreateVector(el->name, xmlrpc_vector_mixed); |
|||
|
|||
while(elem_iter) { |
|||
XMLRPC_AddValueToVector(xReturn, |
|||
xml_element_to_method_description(elem_iter, err)); |
|||
elem_iter = Q_Next(&el->children); |
|||
} |
|||
} |
|||
|
|||
/* or anything at all really, so long as its got some text. |
|||
* no reason being all snotty about a spec, right? |
|||
*/ |
|||
else if(el->name && el->text.len) { |
|||
xReturn = XMLRPC_CreateValueString(el->name, el->text.str, el->text.len); |
|||
} |
|||
} |
|||
|
|||
return xReturn; |
|||
} |
|||
|
|||
/*-**************************** |
|||
* End Introspection Utilities * |
|||
******************************/ |
|||
|
|||
|
|||
|
|||
/*-****************** |
|||
* Introspection API * |
|||
********************/ |
|||
|
|||
|
|||
/****f* VALUE/XMLRPC_IntrospectionCreateDescription |
|||
* NAME |
|||
* XMLRPC_IntrospectionCreateDescription |
|||
* SYNOPSIS |
|||
* XMLRPC_VALUE XMLRPC_IntrospectionCreateDescription(const char* xml, XMLRPC_ERROR err) |
|||
* FUNCTION |
|||
* converts raw xml describing types and methods into an |
|||
* XMLRPC_VALUE suitable for use with XMLRPC_ServerAddIntrospectionData() |
|||
* INPUTS |
|||
* xml - xml data conforming to introspection spec at <url tbd> |
|||
* err - optional pointer to error struct. filled in if error occurs and not NULL. |
|||
* RESULT |
|||
* XMLRPC_VALUE - newly created value, or NULL if fatal error. |
|||
* BUGS |
|||
* Currently does little or no validation of xml. |
|||
* Only parse errors are currently reported in err, not structural errors. |
|||
* SEE ALSO |
|||
* XMLRPC_ServerAddIntrospectionData () |
|||
* SOURCE |
|||
*/ |
|||
XMLRPC_VALUE XMLRPC_IntrospectionCreateDescription(const char* xml, XMLRPC_ERROR err) { |
|||
XMLRPC_VALUE xReturn = NULL; |
|||
xml_element* root = xml_elem_parse_buf(xml, 0, 0, err ? &err->xml_elem_error : NULL); |
|||
|
|||
if(root) { |
|||
xReturn = xml_element_to_method_description(root, err); |
|||
|
|||
xml_elem_free(root); |
|||
} |
|||
|
|||
return xReturn; |
|||
|
|||
} |
|||
/*******/ |
|||
|
|||
|
|||
/****f* SERVER/XMLRPC_ServerAddIntrospectionData |
|||
* NAME |
|||
* XMLRPC_ServerAddIntrospectionData |
|||
* SYNOPSIS |
|||
* int XMLRPC_ServerAddIntrospectionData(XMLRPC_SERVER server, XMLRPC_VALUE desc) |
|||
* FUNCTION |
|||
* updates server with additional introspection data |
|||
* INPUTS |
|||
* server - target server |
|||
* desc - introspection data, should be a struct generated by |
|||
* XMLRPC_IntrospectionCreateDescription () |
|||
* RESULT |
|||
* int - 1 if success, else 0 |
|||
* NOTES |
|||
* - function will fail if neither typeList nor methodList key is present in struct. |
|||
* - if method or type already exists, it will be replaced. |
|||
* - desc is never freed by the server. caller is responsible for cleanup. |
|||
* BUGS |
|||
* - horribly slow lookups. prime candidate for hash improvements. |
|||
* - uglier and more complex than I like to see for API functions. |
|||
* SEE ALSO |
|||
* XMLRPC_ServerAddIntrospectionData () |
|||
* XMLRPC_ServerRegisterIntrospectionCallback () |
|||
* XMLRPC_CleanupValue () |
|||
* SOURCE |
|||
*/ |
|||
int XMLRPC_ServerAddIntrospectionData(XMLRPC_SERVER server, XMLRPC_VALUE desc) { |
|||
int bSuccess = 0; |
|||
if(server && desc) { |
|||
XMLRPC_VALUE xNewTypes = XMLRPC_VectorGetValueWithID(desc, "typeList"); |
|||
XMLRPC_VALUE xNewMethods = XMLRPC_VectorGetValueWithID(desc, "methodList"); |
|||
XMLRPC_VALUE xServerTypes = XMLRPC_VectorGetValueWithID(server->xIntrospection, "typeList"); |
|||
|
|||
if(xNewMethods) { |
|||
XMLRPC_VALUE xMethod = XMLRPC_VectorRewind(xNewMethods); |
|||
|
|||
while(xMethod) { |
|||
const char* name = XMLRPC_VectorGetStringWithID(xMethod, xi_token_name); |
|||
server_method* sm = find_method(server, name); |
|||
|
|||
if(sm) { |
|||
if(sm->desc) { |
|||
XMLRPC_CleanupValue(sm->desc); |
|||
} |
|||
sm->desc = XMLRPC_CopyValue(xMethod); |
|||
bSuccess = 1; |
|||
} |
|||
|
|||
xMethod = XMLRPC_VectorNext(xNewMethods); |
|||
} |
|||
} |
|||
if(xNewTypes) { |
|||
if(!xServerTypes) { |
|||
if(!server->xIntrospection) { |
|||
server->xIntrospection = XMLRPC_CreateVector(NULL, xmlrpc_vector_struct); |
|||
} |
|||
|
|||
XMLRPC_AddValueToVector(server->xIntrospection, xNewTypes); |
|||
bSuccess = 1; |
|||
} |
|||
else { |
|||
XMLRPC_VALUE xIter = XMLRPC_VectorRewind(xNewTypes); |
|||
while(xIter) { |
|||
/* get rid of old values */ |
|||
XMLRPC_VALUE xPrev = find_named_value(xServerTypes, XMLRPC_VectorGetStringWithID(xIter, xi_token_name)); |
|||
if(xPrev) { |
|||
XMLRPC_VectorRemoveValue(xServerTypes, xPrev); |
|||
} |
|||
XMLRPC_AddValueToVector(xServerTypes, xIter); |
|||
bSuccess = 1; |
|||
xIter = XMLRPC_VectorNext(xNewTypes); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
return bSuccess; |
|||
} |
|||
/*******/ |
|||
|
|||
|
|||
/****f* SERVER/XMLRPC_ServerRegisterIntrospectionCallback |
|||
* NAME |
|||
* XMLRPC_ServerRegisterIntrospectionCallback |
|||
* SYNOPSIS |
|||
* int XMLRPC_ServerRegisterIntrospectionCallback(XMLRPC_SERVER server, XMLRPC_IntrospectionCallback cb) |
|||
* FUNCTION |
|||
* registers a callback for lazy generation of introspection data |
|||
* INPUTS |
|||
* server - target server |
|||
* cb - callback that will generate introspection data |
|||
* RESULT |
|||
* int - 1 if success, else 0 |
|||
* NOTES |
|||
* parsing xml and generating introspection data is fairly expensive, thus a |
|||
* server may wish to wait until this data is actually requested before generating |
|||
* it. Any number of callbacks may be registered at any time. A given callback |
|||
* will only ever be called once, the first time an introspection request is |
|||
* processed after the time of callback registration. |
|||
* SEE ALSO |
|||
* XMLRPC_ServerAddIntrospectionData () |
|||
* XMLRPC_IntrospectionCreateDescription () |
|||
* SOURCE |
|||
*/ |
|||
int XMLRPC_ServerRegisterIntrospectionCallback(XMLRPC_SERVER server, XMLRPC_IntrospectionCallback cb) { |
|||
int bSuccess = 0; |
|||
if(server && cb) { |
|||
|
|||
doc_method* dm = ecalloc(1, sizeof(doc_method)); |
|||
|
|||
if(dm) { |
|||
dm->method = cb; |
|||
dm->b_called = 0; |
|||
|
|||
if(Q_PushTail(&server->docslist, dm)) { |
|||
bSuccess = 1; |
|||
} |
|||
else { |
|||
my_free(dm); |
|||
} |
|||
} |
|||
} |
|||
return bSuccess; |
|||
} |
|||
/*******/ |
|||
|
|||
/*-********************** |
|||
* End Introspection API * |
|||
************************/ |
|||
@ -1,98 +0,0 @@ |
|||
/* |
|||
This file is part of libXMLRPC - a C library for xml-encoded function calls. |
|||
|
|||
Author: Dan Libby (dan@libby.com) |
|||
Epinions.com may be contacted at feedback@epinions-inc.com |
|||
*/ |
|||
|
|||
/* |
|||
Copyright 2000 Epinions, Inc. |
|||
|
|||
Subject to the following 3 conditions, Epinions, Inc. permits you, free |
|||
of charge, to (a) use, copy, distribute, modify, perform and display this |
|||
software and associated documentation files (the "Software"), and (b) |
|||
permit others to whom the Software is furnished to do so as well. |
|||
|
|||
1) The above copyright notice and this permission notice shall be included |
|||
without modification in all copies or substantial portions of the |
|||
Software. |
|||
|
|||
2) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTY OR CONDITION OF |
|||
ANY KIND, EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION ANY |
|||
IMPLIED WARRANTIES OF ACCURACY, MERCHANTABILITY, FITNESS FOR A PARTICULAR |
|||
PURPOSE OR NONINFRINGEMENT. |
|||
|
|||
3) IN NO EVENT SHALL EPINIONS, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, |
|||
SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT |
|||
OF OR IN CONNECTION WITH THE SOFTWARE (HOWEVER ARISING, INCLUDING |
|||
NEGLIGENCE), EVEN IF EPINIONS, INC. IS AWARE OF THE POSSIBILITY OF SUCH |
|||
DAMAGES. |
|||
|
|||
*/ |
|||
|
|||
/* IMPORTANT! |
|||
* |
|||
* only public (official API) things should be in this file. Anything else |
|||
* should go in <group>_private.h, or in the appropriate .c file. |
|||
*/ |
|||
|
|||
|
|||
#ifndef __XI_INTROSPECTION_H |
|||
/* |
|||
* Avoid include redundancy. |
|||
*/ |
|||
#define __XI_INTROSPECTION_H |
|||
|
|||
/*---------------------------------------------------------------------------- |
|||
* xmlrpc_introspection.h |
|||
* |
|||
* Purpose: |
|||
* define public introspection API |
|||
* Comments: |
|||
*/ |
|||
|
|||
/*---------------------------------------------------------------------------- |
|||
* Constants |
|||
*/ |
|||
#define xi_token_params "params" |
|||
#define xi_token_returns "returns" |
|||
#define xi_token_related "related" |
|||
#define xi_token_sub "sub" |
|||
|
|||
|
|||
/*---------------------------------------------------------------------------- |
|||
* Includes |
|||
*/ |
|||
|
|||
/*---------------------------------------------------------------------------- |
|||
* Structures |
|||
*/ |
|||
|
|||
/****d* VALUE/XMLRPC_IntrospectionCallback |
|||
* NAME |
|||
* XMLRPC_IntrospectionCallback |
|||
* NOTES |
|||
* Function prototype for lazy documentation generation (not generated until requested). |
|||
* SOURCE |
|||
*/ |
|||
typedef void (*XMLRPC_IntrospectionCallback)(XMLRPC_SERVER server, void* userData); |
|||
/******/ |
|||
|
|||
|
|||
/*---------------------------------------------------------------------------- |
|||
* Globals |
|||
*/ |
|||
|
|||
/*---------------------------------------------------------------------------- |
|||
* Functions |
|||
*/ |
|||
XMLRPC_VALUE XMLRPC_IntrospectionCreateDescription(const char* xml, XMLRPC_ERROR error); |
|||
int XMLRPC_ServerAddIntrospectionData(XMLRPC_SERVER server, XMLRPC_VALUE desc); |
|||
int XMLRPC_ServerRegisterIntrospectionCallback(XMLRPC_SERVER server, XMLRPC_IntrospectionCallback cb); |
|||
|
|||
/*---------------------------------------------------------------------------- |
|||
* Macros |
|||
*/ |
|||
|
|||
|
|||
#endif /* __XI_INTROSPECTION_H */ |
|||
@ -1,102 +0,0 @@ |
|||
/* |
|||
This file is part of libXMLRPC - a C library for xml-encoded function calls. |
|||
|
|||
Author: Dan Libby (dan@libby.com) |
|||
Epinions.com may be contacted at feedback@epinions-inc.com |
|||
*/ |
|||
|
|||
/* |
|||
Copyright 2001 Dan Libby, Epinions, Inc. |
|||
|
|||
Subject to the following 3 conditions, Epinions, Inc. permits you, free |
|||
of charge, to (a) use, copy, distribute, modify, perform and display this |
|||
software and associated documentation files (the "Software"), and (b) |
|||
permit others to whom the Software is furnished to do so as well. |
|||
|
|||
1) The above copyright notice and this permission notice shall be included |
|||
without modification in all copies or substantial portions of the |
|||
Software. |
|||
|
|||
2) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTY OR CONDITION OF |
|||
ANY KIND, EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION ANY |
|||
IMPLIED WARRANTIES OF ACCURACY, MERCHANTABILITY, FITNESS FOR A PARTICULAR |
|||
PURPOSE OR NONINFRINGEMENT. |
|||
|
|||
3) IN NO EVENT SHALL EPINIONS, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, |
|||
SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT |
|||
OF OR IN CONNECTION WITH THE SOFTWARE (HOWEVER ARISING, INCLUDING |
|||
NEGLIGENCE), EVEN IF EPINIONS, INC. IS AWARE OF THE POSSIBILITY OF SUCH |
|||
DAMAGES. |
|||
|
|||
*/ |
|||
|
|||
/* IMPORTANT! |
|||
* |
|||
* only non-public things should be in this file. It is fine for any .c file |
|||
* in xmlrpc/src to include it, but users of the public API should never |
|||
* include it, and thus *.h files that are part of the public API should |
|||
* never include it, or they would break if this file is not present. |
|||
*/ |
|||
|
|||
|
|||
#ifndef __XI_INTROSPECTION_PRIVATE_H |
|||
/* |
|||
* Avoid include redundancy. |
|||
*/ |
|||
#define __XI_INTROSPECTION_PRIVATE_H |
|||
|
|||
/*---------------------------------------------------------------------------- |
|||
* xmlrpc_introspection_private.h |
|||
* |
|||
* Purpose: |
|||
* define non-public introspection routines |
|||
* Comments: |
|||
*/ |
|||
|
|||
/*---------------------------------------------------------------------------- |
|||
* Constants |
|||
*/ |
|||
#define xi_token_default "default" |
|||
#define xi_token_description "description" |
|||
#define xi_token_name "name" |
|||
#define xi_token_optional "optional" |
|||
#define xi_token_params "params" |
|||
#define xi_token_purpose "purpose" |
|||
#define xi_token_returns "returns" |
|||
#define xi_token_signatures "signatures" |
|||
#define xi_token_type "type" |
|||
#define xi_token_version "version" |
|||
#define xi_token_empty "" |
|||
#define xi_token_system_describe_methods "system.describeMethods" |
|||
#define xi_token_system_list_methods "system.listMethods" |
|||
#define xi_token_system_method_help "system.methodHelp" |
|||
#define xi_token_system_method_signature "system.methodSignature" |
|||
|
|||
|
|||
/*---------------------------------------------------------------------------- |
|||
* Includes |
|||
*/ |
|||
|
|||
/*---------------------------------------------------------------------------- |
|||
* Structures |
|||
*/ |
|||
typedef struct _doc_method { |
|||
XMLRPC_IntrospectionCallback method; |
|||
int b_called; |
|||
} doc_method; |
|||
|
|||
/*---------------------------------------------------------------------------- |
|||
* Globals |
|||
*/ |
|||
|
|||
/*---------------------------------------------------------------------------- |
|||
* Functions |
|||
*/ |
|||
void xi_register_system_methods(XMLRPC_SERVER server); |
|||
|
|||
/*---------------------------------------------------------------------------- |
|||
* Macros |
|||
*/ |
|||
|
|||
|
|||
#endif /* __XI_INTROSPECTION_PRIVATE_H */ |
|||
@ -1,177 +0,0 @@ |
|||
/* |
|||
This file is part of libXMLRPC - a C library for xml-encoded function calls. |
|||
|
|||
Author: Dan Libby (dan@libby.com) |
|||
Epinions.com may be contacted at feedback@epinions-inc.com |
|||
*/ |
|||
|
|||
/* |
|||
Copyright 2000 Epinions, Inc. |
|||
|
|||
Subject to the following 3 conditions, Epinions, Inc. permits you, free |
|||
of charge, to (a) use, copy, distribute, modify, perform and display this |
|||
software and associated documentation files (the "Software"), and (b) |
|||
permit others to whom the Software is furnished to do so as well. |
|||
|
|||
1) The above copyright notice and this permission notice shall be included |
|||
without modification in all copies or substantial portions of the |
|||
Software. |
|||
|
|||
2) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTY OR CONDITION OF |
|||
ANY KIND, EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION ANY |
|||
IMPLIED WARRANTIES OF ACCURACY, MERCHANTABILITY, FITNESS FOR A PARTICULAR |
|||
PURPOSE OR NONINFRINGEMENT. |
|||
|
|||
3) IN NO EVENT SHALL EPINIONS, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, |
|||
SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT |
|||
OF OR IN CONNECTION WITH THE SOFTWARE (HOWEVER ARISING, INCLUDING |
|||
NEGLIGENCE), EVEN IF EPINIONS, INC. IS AWARE OF THE POSSIBILITY OF SUCH |
|||
DAMAGES. |
|||
|
|||
*/ |
|||
|
|||
/* only non-public things should be in this file. It is fine for any .c file |
|||
* in xmlrpc/src to include it, but users of the public API should never |
|||
* include it, and thus *.h files that are part of the public API should |
|||
* never include it, or they would break if this file is not present. |
|||
*/ |
|||
|
|||
#ifndef XMLRPC_PRIVATE_ALREADY_INCLUDED |
|||
/* |
|||
* Avoid include redundancy. |
|||
*/ |
|||
#define XMLRPC_PRIVATE_ALREADY_INCLUDED |
|||
|
|||
#ifdef __cplusplus |
|||
extern "C" { |
|||
#endif |
|||
|
|||
|
|||
/*---------------------------------------------------------------------------- |
|||
* xmlrpc_private.h |
|||
* |
|||
* Purpose: |
|||
* define non-public intra-library routines & data |
|||
* Comments: |
|||
*/ |
|||
|
|||
/*---------------------------------------------------------------------------- |
|||
* Constants |
|||
*/ |
|||
|
|||
|
|||
/*---------------------------------------------------------------------------- |
|||
* Includes |
|||
*/ |
|||
|
|||
/*---------------------------------------------------------------------------- |
|||
* Structures |
|||
*/ |
|||
|
|||
/* Some of these are typedef'd in xmlrpc.h for public use */ |
|||
|
|||
typedef struct _xmlrpc_vector* XMLRPC_VECTOR; |
|||
|
|||
/****s* VALUE/XMLRPC_VALUE |
|||
* NAME |
|||
* XMLRPC_VALUE |
|||
* NOTES |
|||
* A value of variable data type. The most important object in this API. :) |
|||
* |
|||
* This struct is opaque to callers and should be accessed only via accessor functions. |
|||
* SEE ALSO |
|||
* XMLRPC_REQUEST |
|||
* XMLRPC_CreateValueEmpty () |
|||
* XMLRPC_CleanupValue () |
|||
* SOURCE |
|||
*/ |
|||
typedef struct _xmlrpc_value { |
|||
XMLRPC_VALUE_TYPE type; /* data type of this value */ |
|||
XMLRPC_VECTOR v; /* vector type specific info */ |
|||
simplestring str; /* string value buffer */ |
|||
simplestring id; /* id of this value. possibly empty. */ |
|||
int i; /* integer value. */ |
|||
double d; /* double value */ |
|||
int iRefCount; /* So we know when we can delete the value . */ |
|||
} STRUCT_XMLRPC_VALUE; |
|||
/******/ |
|||
|
|||
/****s* VALUE/XMLRPC_REQUEST |
|||
* NAME |
|||
* XMLRPC_REQUEST |
|||
* NOTES |
|||
* Internal representation of an XML request. |
|||
* |
|||
* This struct is opaque to callers and should be accessed only via accessor functions. |
|||
* |
|||
* SEE ALSO |
|||
* XMLRPC_VALUE |
|||
* XMLRPC_RequestNew () |
|||
* XMLRPC_RequestFree () |
|||
* SOURCE |
|||
*/ |
|||
typedef struct _xmlrpc_request { |
|||
XMLRPC_VALUE io; /* data associated with this request */ |
|||
simplestring methodName; /* name of method being called */ |
|||
XMLRPC_REQUEST_TYPE request_type; /* type of request */ |
|||
STRUCT_XMLRPC_REQUEST_OUTPUT_OPTIONS output; /* xml output options */ |
|||
XMLRPC_VALUE error; /* error codes */ |
|||
} STRUCT_XMLRPC_REQUEST; |
|||
/******/ |
|||
|
|||
/* Vector type. Used by XMLRPC_VALUE. Never visible to users of the API. */ |
|||
typedef struct _xmlrpc_vector { |
|||
XMLRPC_VECTOR_TYPE type; /* vector type */ |
|||
queue *q; /* list of child values */ |
|||
} STRUCT_XMLRPC_VECTOR; |
|||
/******/ |
|||
|
|||
/****s* VALUE/XMLRPC_SERVER |
|||
* NAME |
|||
* XMLRPC_SERVER |
|||
* NOTES |
|||
* internal representation of an xmlrpc server |
|||
* |
|||
* This struct is opaque to callers and should be accessed only via accessor functions. |
|||
* |
|||
* SEE ALSO |
|||
* XMLRPC_ServerCreate () |
|||
* XMLRPC_ServerDestroy () |
|||
* SOURCE |
|||
*/ |
|||
typedef struct _xmlrpc_server { |
|||
queue methodlist; /* list of callback methods */ |
|||
queue docslist; /* list of introspection callbacks */ |
|||
XMLRPC_VALUE xIntrospection; |
|||
} STRUCT_XMLRPC_SERVER; |
|||
/******/ |
|||
|
|||
typedef struct _server_method { |
|||
char* name; |
|||
XMLRPC_VALUE desc; |
|||
XMLRPC_Callback method; |
|||
} server_method; |
|||
|
|||
|
|||
/*---------------------------------------------------------------------------- |
|||
* Globals |
|||
*/ |
|||
|
|||
/*---------------------------------------------------------------------------- |
|||
* Functions |
|||
*/ |
|||
server_method* find_method(XMLRPC_SERVER server, const char* name); |
|||
const char* type_to_str(XMLRPC_VALUE_TYPE type, XMLRPC_VECTOR_TYPE vtype); |
|||
|
|||
/*---------------------------------------------------------------------------- |
|||
* Macros |
|||
*/ |
|||
#define my_free(thing) if(thing) {efree(thing); thing = 0;} |
|||
|
|||
|
|||
#ifdef __cplusplus |
|||
} |
|||
#endif |
|||
|
|||
|
|||
#endif /* XMLRPC_PRIVATE_ALREADY_INCLUDED */ |
|||
@ -1,72 +0,0 @@ |
|||
/* |
|||
This file is part of, or distributed with, libXMLRPC - a C library for |
|||
xml-encoded function calls. |
|||
|
|||
Author: Dan Libby (dan@libby.com) |
|||
Epinions.com may be contacted at feedback@epinions-inc.com |
|||
*/ |
|||
|
|||
/* |
|||
Copyright 2001 Epinions, Inc. |
|||
|
|||
Subject to the following 3 conditions, Epinions, Inc. permits you, free |
|||
of charge, to (a) use, copy, distribute, modify, perform and display this |
|||
software and associated documentation files (the "Software"), and (b) |
|||
permit others to whom the Software is furnished to do so as well. |
|||
|
|||
1) The above copyright notice and this permission notice shall be included |
|||
without modification in all copies or substantial portions of the |
|||
Software. |
|||
|
|||
2) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTY OR CONDITION OF |
|||
ANY KIND, EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION ANY |
|||
IMPLIED WARRANTIES OF ACCURACY, MERCHANTABILITY, FITNESS FOR A PARTICULAR |
|||
PURPOSE OR NONINFRINGEMENT. |
|||
|
|||
3) IN NO EVENT SHALL EPINIONS, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, |
|||
SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT |
|||
OF OR IN CONNECTION WITH THE SOFTWARE (HOWEVER ARISING, INCLUDING |
|||
NEGLIGENCE), EVEN IF EPINIONS, INC. IS AWARE OF THE POSSIBILITY OF SUCH |
|||
DAMAGES. |
|||
|
|||
*/ |
|||
|
|||
/* auto-generated portions of this file are also subject to the php license */ |
|||
|
|||
/* |
|||
+----------------------------------------------------------------------+ |
|||
| Copyright (c) The PHP Group | |
|||
+----------------------------------------------------------------------+ |
|||
| This source file is subject to version 3.01 of the PHP license, | |
|||
| that is bundled with this package in the file LICENSE, and is | |
|||
| available through the world-wide-web at the following url: | |
|||
| http://www.php.net/license/3_01.txt | |
|||
| If you did not receive a copy of the PHP license and are unable to | |
|||
| obtain it through the world-wide-web, please send a note to | |
|||
| license@php.net so we can mail you a copy immediately. | |
|||
+----------------------------------------------------------------------+ |
|||
| Author: Dan Libby | |
|||
+----------------------------------------------------------------------+ |
|||
*/ |
|||
|
|||
#ifndef _PHP_XMLRPC_H |
|||
#define _PHP_XMLRPC_H |
|||
|
|||
#if 1 /* HAVE_XMLRPC */ |
|||
|
|||
extern zend_module_entry xmlrpc_module_entry; |
|||
#define phpext_xmlrpc_ptr &xmlrpc_module_entry |
|||
|
|||
#include "php_version.h" |
|||
#define PHP_XMLRPC_VERSION PHP_VERSION |
|||
|
|||
PHP_MINIT_FUNCTION(xmlrpc); |
|||
PHP_MINFO_FUNCTION(xmlrpc); |
|||
|
|||
#else |
|||
|
|||
#define phpext_xmlrpc_ptr NULL |
|||
|
|||
#endif |
|||
|
|||
#endif /* _PHP_XMLRPC_H */ |
|||
@ -1,51 +0,0 @@ |
|||
--TEST-- |
|||
xmlrpc_encode_request() with wrong arguments |
|||
--SKIPIF-- |
|||
<?php if (!extension_loaded("xmlrpc")) print "skip"; ?> |
|||
--FILE-- |
|||
<?php |
|||
|
|||
var_dump(xmlrpc_encode_request(-1, 1)); |
|||
var_dump(xmlrpc_encode_request("", 1)); |
|||
var_dump(xmlrpc_encode_request(3.4, 1)); |
|||
|
|||
echo "Done\n"; |
|||
?> |
|||
--EXPECTF-- |
|||
string(174) "<?xml version="1.0" encoding="iso-8859-1"?> |
|||
<methodCall> |
|||
<methodName>-1</methodName> |
|||
<params> |
|||
<param> |
|||
<value> |
|||
<int>1</int> |
|||
</value> |
|||
</param> |
|||
</params> |
|||
</methodCall> |
|||
" |
|||
string(160) "<?xml version="1.0" encoding="iso-8859-1"?> |
|||
<methodCall> |
|||
<methodName/> |
|||
<params> |
|||
<param> |
|||
<value> |
|||
<int>1</int> |
|||
</value> |
|||
</param> |
|||
</params> |
|||
</methodCall> |
|||
" |
|||
string(175) "<?xml version="1.0" encoding="iso-8859-1"?> |
|||
<methodCall> |
|||
<methodName>3.4</methodName> |
|||
<params> |
|||
<param> |
|||
<value> |
|||
<int>1</int> |
|||
</value> |
|||
</param> |
|||
</params> |
|||
</methodCall> |
|||
" |
|||
Done |
|||
@ -1,45 +0,0 @@ |
|||
--TEST-- |
|||
xmlrpc_encode_request() and various arguments |
|||
--SKIPIF-- |
|||
<?php if (!extension_loaded("xmlrpc")) print "skip"; ?> |
|||
--FILE-- |
|||
<?php |
|||
|
|||
$r = xmlrpc_encode_request("method", array()); |
|||
var_dump(xmlrpc_decode_request($r, $method)); |
|||
var_dump($method); |
|||
|
|||
$r = xmlrpc_encode_request("method", 1); |
|||
var_dump(xmlrpc_decode_request($r, $method)); |
|||
var_dump($method); |
|||
|
|||
$r = xmlrpc_encode_request("method", 'param'); |
|||
var_dump(xmlrpc_decode_request($r, $method)); |
|||
var_dump($method); |
|||
|
|||
$r = xmlrpc_encode_request(-1, ""); |
|||
var_dump(xmlrpc_decode_request($r, $method)); |
|||
var_dump($method); |
|||
|
|||
echo "Done\n"; |
|||
?> |
|||
--EXPECTF-- |
|||
array(0) { |
|||
} |
|||
string(6) "method" |
|||
array(1) { |
|||
[0]=> |
|||
int(1) |
|||
} |
|||
string(6) "method" |
|||
array(1) { |
|||
[0]=> |
|||
string(5) "param" |
|||
} |
|||
string(6) "method" |
|||
array(1) { |
|||
[0]=> |
|||
string(0) "" |
|||
} |
|||
string(2) "-1" |
|||
Done |
|||
@ -1,108 +0,0 @@ |
|||
--TEST-- |
|||
xmlrpc_encode() Simple test encode array |
|||
--SKIPIF-- |
|||
<?php if (!extension_loaded("xmlrpc")) print "skip"; ?> |
|||
--FILE-- |
|||
<?php |
|||
|
|||
$params = array( |
|||
"one" => "red", |
|||
"two" => "blue", |
|||
"three" => "green" |
|||
); |
|||
|
|||
$response = xmlrpc_encode($params); |
|||
echo $response; |
|||
|
|||
$params = array( |
|||
"red", |
|||
"blue", |
|||
"green" |
|||
); |
|||
|
|||
$response = xmlrpc_encode($params); |
|||
echo $response; |
|||
|
|||
$params = array( |
|||
0 => "red", |
|||
1 => "blue", |
|||
3 => "green" |
|||
); |
|||
|
|||
$response = xmlrpc_encode($params); |
|||
echo $response; |
|||
--EXPECT-- |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<params> |
|||
<param> |
|||
<value> |
|||
<struct> |
|||
<member> |
|||
<name>one</name> |
|||
<value> |
|||
<string>red</string> |
|||
</value> |
|||
</member> |
|||
<member> |
|||
<name>two</name> |
|||
<value> |
|||
<string>blue</string> |
|||
</value> |
|||
</member> |
|||
<member> |
|||
<name>three</name> |
|||
<value> |
|||
<string>green</string> |
|||
</value> |
|||
</member> |
|||
</struct> |
|||
</value> |
|||
</param> |
|||
</params> |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<params> |
|||
<param> |
|||
<value> |
|||
<array> |
|||
<data> |
|||
<value> |
|||
<string>red</string> |
|||
</value> |
|||
<value> |
|||
<string>blue</string> |
|||
</value> |
|||
<value> |
|||
<string>green</string> |
|||
</value> |
|||
</data> |
|||
</array> |
|||
</value> |
|||
</param> |
|||
</params> |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<params> |
|||
<param> |
|||
<value> |
|||
<struct> |
|||
<member> |
|||
<name>0</name> |
|||
<value> |
|||
<string>red</string> |
|||
</value> |
|||
</member> |
|||
<member> |
|||
<name>1</name> |
|||
<value> |
|||
<string>blue</string> |
|||
</value> |
|||
</member> |
|||
<member> |
|||
<name>3</name> |
|||
<value> |
|||
<string>green</string> |
|||
</value> |
|||
</member> |
|||
</struct> |
|||
</value> |
|||
</param> |
|||
</params> |
|||
@ -1,18 +0,0 @@ |
|||
--TEST-- |
|||
xmlrpc_encode() Simple test encode int |
|||
--SKIPIF-- |
|||
<?php if (!extension_loaded("xmlrpc")) print "skip"; ?> |
|||
--FILE-- |
|||
<?php |
|||
|
|||
$response = xmlrpc_encode(1); |
|||
echo $response; |
|||
--EXPECT-- |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<params> |
|||
<param> |
|||
<value> |
|||
<int>1</int> |
|||
</value> |
|||
</param> |
|||
</params> |
|||
@ -1,43 +0,0 @@ |
|||
--TEST-- |
|||
xmlrpc_encode() Simple test encode type double and String |
|||
--CREDITS-- |
|||
Michel Araujo <araujo_michel@yahoo.com.br> |
|||
#PHPSP 2013-08-22 |
|||
--SKIPIF-- |
|||
<?php if (!extension_loaded("xmlrpc")) print "skip"; ?> |
|||
--FILE-- |
|||
<?php |
|||
|
|||
$response = xmlrpc_encode(3.24234); |
|||
echo $response; |
|||
|
|||
$response = xmlrpc_encode(-3.24234); |
|||
echo $response; |
|||
|
|||
$response = xmlrpc_encode('Is string'); |
|||
echo $response; |
|||
--EXPECT-- |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<params> |
|||
<param> |
|||
<value> |
|||
<double>3.24234</double> |
|||
</value> |
|||
</param> |
|||
</params> |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<params> |
|||
<param> |
|||
<value> |
|||
<double>-3.24234</double> |
|||
</value> |
|||
</param> |
|||
</params> |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<params> |
|||
<param> |
|||
<value> |
|||
<string>Is string</string> |
|||
</value> |
|||
</param> |
|||
</params> |
|||
@ -1,25 +0,0 @@ |
|||
--TEST-- |
|||
xmlrpc_decode() Simple test decode type string |
|||
--CREDITS-- |
|||
Michel Araujo <araujo_michel@yahoo.com.br> |
|||
#PHPSP 2013-08-22 |
|||
--SKIPIF-- |
|||
<?php if (!extension_loaded("xmlrpc")) print "skip"; ?> |
|||
--FILE-- |
|||
<?php |
|||
|
|||
$xml = <<<XML |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<params> |
|||
<param> |
|||
<value> |
|||
<string>Is string</string> |
|||
</value> |
|||
</param> |
|||
</params> |
|||
XML; |
|||
|
|||
$response = xmlrpc_decode($xml); |
|||
echo $response; |
|||
--EXPECT-- |
|||
Is string |
|||
@ -1,25 +0,0 @@ |
|||
--TEST-- |
|||
xmlrpc_decode() Simple test decode type int |
|||
--CREDITS-- |
|||
Michel Araujo <araujo_michel@yahoo.com.br> |
|||
#PHPSP 2013-08-22 |
|||
--SKIPIF-- |
|||
<?php if (!extension_loaded("xmlrpc")) print "skip"; ?> |
|||
--FILE-- |
|||
<?php |
|||
|
|||
$xml = <<<XML |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<params> |
|||
<param> |
|||
<value> |
|||
<int>1</int> |
|||
</value> |
|||
</param> |
|||
</params> |
|||
XML; |
|||
|
|||
$response = xmlrpc_decode($xml); |
|||
echo $response; |
|||
--EXPECT-- |
|||
1 |
|||
@ -1,23 +0,0 @@ |
|||
--TEST-- |
|||
Bug #18916 (xmlrpc_set_type() not working) |
|||
--SKIPIF-- |
|||
<?php if (!extension_loaded("xmlrpc")) print "skip"; ?> |
|||
--INI-- |
|||
date.timezone="America/Sao_Paulo" |
|||
--FILE-- |
|||
<?php |
|||
|
|||
$params = date("Ymd\TH:i:s", time()); |
|||
xmlrpc_set_type($params, 'datetime'); |
|||
echo xmlrpc_encode($params); |
|||
|
|||
?> |
|||
--EXPECTF-- |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<params> |
|||
<param> |
|||
<value> |
|||
<dateTime.iso8601>%dT%d:%d:%d</dateTime.iso8601> |
|||
</value> |
|||
</param> |
|||
</params> |
|||
@ -1,64 +0,0 @@ |
|||
--TEST-- |
|||
Bug #37057 (xmlrpc_decode() may produce arrays with numeric string keys which are unaccessible) |
|||
--SKIPIF-- |
|||
<?php if (!extension_loaded("xmlrpc")) print "skip"; ?> |
|||
--FILE-- |
|||
<?php |
|||
$response='<?xml version="1.0"?> |
|||
<methodResponse> |
|||
<params> |
|||
<param> |
|||
<value> |
|||
<struct> |
|||
<member> |
|||
<name>50</name> |
|||
<value><string>0.29</string></value> |
|||
</member> |
|||
</struct> |
|||
</value> |
|||
</param> |
|||
</params> |
|||
</methodResponse>'; |
|||
|
|||
$retval=xmlrpc_decode($response); |
|||
var_dump($retval); |
|||
var_dump($retval["50"]); |
|||
var_dump($retval[50]); |
|||
|
|||
$response='<?xml version="1.0"?> |
|||
<methodResponse> |
|||
<params> |
|||
<param> |
|||
<value> |
|||
<struct> |
|||
<member> |
|||
<name>0</name> |
|||
<value><string>0.29</string></value> |
|||
</member> |
|||
</struct> |
|||
</value> |
|||
</param> |
|||
</params> |
|||
</methodResponse>'; |
|||
|
|||
$retval=xmlrpc_decode($response); |
|||
var_dump($retval); |
|||
var_dump($retval["0"]); |
|||
var_dump($retval[0]); |
|||
|
|||
echo "Done\n"; |
|||
?> |
|||
--EXPECT-- |
|||
array(1) { |
|||
[50]=> |
|||
string(4) "0.29" |
|||
} |
|||
string(4) "0.29" |
|||
string(4) "0.29" |
|||
array(1) { |
|||
[0]=> |
|||
string(4) "0.29" |
|||
} |
|||
string(4) "0.29" |
|||
string(4) "0.29" |
|||
Done |
|||
@ -1,25 +0,0 @@ |
|||
--TEST-- |
|||
Bug #38431 (xmlrpc_get_type() crashes PHP on objects) |
|||
--SKIPIF-- |
|||
<?php if (!extension_loaded("xmlrpc")) print "skip"; ?> |
|||
--FILE-- |
|||
<?php |
|||
|
|||
var_dump(xmlrpc_get_type(new stdclass)); |
|||
var_dump(xmlrpc_get_type(array())); |
|||
$var = array(1,2,3); |
|||
var_dump(xmlrpc_get_type($var)); |
|||
$var = array("test"=>1,2,3); |
|||
var_dump(xmlrpc_get_type($var)); |
|||
$var = array("test"=>1,"test2"=>2); |
|||
var_dump(xmlrpc_get_type($var)); |
|||
|
|||
echo "Done\n"; |
|||
?> |
|||
--EXPECT-- |
|||
string(5) "array" |
|||
string(5) "array" |
|||
string(5) "array" |
|||
string(5) "mixed" |
|||
string(6) "struct" |
|||
Done |
|||
@ -1,77 +0,0 @@ |
|||
--TEST-- |
|||
Bug #40576 (double values are truncated to 6 decimal digits when encoding) |
|||
--SKIPIF-- |
|||
<?php |
|||
if (!extension_loaded("xmlrpc")) print "skip"; |
|||
if (PHP_INT_SIZE != 4) die("skip this test is for 32bit platform only"); |
|||
?> |
|||
--INI-- |
|||
precision=12 |
|||
--FILE-- |
|||
<?php |
|||
|
|||
var_dump(xmlrpc_encode(1.123456789)); |
|||
var_dump(xmlrpc_encode(11234567891010)); |
|||
var_dump(xmlrpc_encode(11234567)); |
|||
var_dump(xmlrpc_encode("")); |
|||
var_dump(xmlrpc_encode("test")); |
|||
var_dump(xmlrpc_encode("1.22222222222222222222222")); |
|||
|
|||
echo "Done\n"; |
|||
?> |
|||
--EXPECT-- |
|||
string(125) "<?xml version="1.0" encoding="utf-8"?> |
|||
<params> |
|||
<param> |
|||
<value> |
|||
<double>1.123456789</double> |
|||
</value> |
|||
</param> |
|||
</params> |
|||
" |
|||
string(130) "<?xml version="1.0" encoding="utf-8"?> |
|||
<params> |
|||
<param> |
|||
<value> |
|||
<double>1.1234567891E+13</double> |
|||
</value> |
|||
</param> |
|||
</params> |
|||
" |
|||
string(116) "<?xml version="1.0" encoding="utf-8"?> |
|||
<params> |
|||
<param> |
|||
<value> |
|||
<int>11234567</int> |
|||
</value> |
|||
</param> |
|||
</params> |
|||
" |
|||
string(106) "<?xml version="1.0" encoding="utf-8"?> |
|||
<params> |
|||
<param> |
|||
<value> |
|||
<string/> |
|||
</value> |
|||
</param> |
|||
</params> |
|||
" |
|||
string(118) "<?xml version="1.0" encoding="utf-8"?> |
|||
<params> |
|||
<param> |
|||
<value> |
|||
<string>test</string> |
|||
</value> |
|||
</param> |
|||
</params> |
|||
" |
|||
string(139) "<?xml version="1.0" encoding="utf-8"?> |
|||
<params> |
|||
<param> |
|||
<value> |
|||
<string>1.22222222222222222222222</string> |
|||
</value> |
|||
</param> |
|||
</params> |
|||
" |
|||
Done |
|||
@ -1,77 +0,0 @@ |
|||
--TEST-- |
|||
Bug #40576 (double values are truncated to 6 decimal digits when encoding) |
|||
--SKIPIF-- |
|||
<?php |
|||
if (!extension_loaded("xmlrpc")) print "skip"; |
|||
if (PHP_INT_SIZE != 8) die("skip this test is for 64bit platform only"); |
|||
?> |
|||
--INI-- |
|||
precision=12 |
|||
--FILE-- |
|||
<?php |
|||
|
|||
var_dump(xmlrpc_encode(1.123456789)); |
|||
var_dump(xmlrpc_encode(11234567891010)); |
|||
var_dump(xmlrpc_encode(11234567)); |
|||
var_dump(xmlrpc_encode("")); |
|||
var_dump(xmlrpc_encode("test")); |
|||
var_dump(xmlrpc_encode("1.22222222222222222222222")); |
|||
|
|||
echo "Done\n"; |
|||
?> |
|||
--EXPECT-- |
|||
string(125) "<?xml version="1.0" encoding="utf-8"?> |
|||
<params> |
|||
<param> |
|||
<value> |
|||
<double>1.123456789</double> |
|||
</value> |
|||
</param> |
|||
</params> |
|||
" |
|||
string(119) "<?xml version="1.0" encoding="utf-8"?> |
|||
<params> |
|||
<param> |
|||
<value> |
|||
<int>-1066555326</int> |
|||
</value> |
|||
</param> |
|||
</params> |
|||
" |
|||
string(116) "<?xml version="1.0" encoding="utf-8"?> |
|||
<params> |
|||
<param> |
|||
<value> |
|||
<int>11234567</int> |
|||
</value> |
|||
</param> |
|||
</params> |
|||
" |
|||
string(106) "<?xml version="1.0" encoding="utf-8"?> |
|||
<params> |
|||
<param> |
|||
<value> |
|||
<string/> |
|||
</value> |
|||
</param> |
|||
</params> |
|||
" |
|||
string(118) "<?xml version="1.0" encoding="utf-8"?> |
|||
<params> |
|||
<param> |
|||
<value> |
|||
<string>test</string> |
|||
</value> |
|||
</param> |
|||
</params> |
|||
" |
|||
string(139) "<?xml version="1.0" encoding="utf-8"?> |
|||
<params> |
|||
<param> |
|||
<value> |
|||
<string>1.22222222222222222222222</string> |
|||
</value> |
|||
</param> |
|||
</params> |
|||
" |
|||
Done |
|||
@ -1,15 +0,0 @@ |
|||
--TEST-- |
|||
Bug #42189 (xmlrpc_get_type() crashes PHP on invalid dates) |
|||
--SKIPIF-- |
|||
<?php if (!extension_loaded("xmlrpc")) print "skip"; ?> |
|||
--FILE-- |
|||
<?php |
|||
$a = '~~~~~~~~~~~~~~~~~~'; |
|||
$ok = xmlrpc_set_type($a, 'datetime'); |
|||
var_dump($ok); |
|||
|
|||
echo "Done\n"; |
|||
?> |
|||
--EXPECT-- |
|||
bool(false) |
|||
Done |
|||
@ -1,56 +0,0 @@ |
|||
--TEST-- |
|||
Bug #42736 (xmlrpc_server_call_method() crashes) |
|||
--SKIPIF-- |
|||
<?php if (!extension_loaded("xmlrpc")) print "skip"; ?> |
|||
--FILE-- |
|||
<?php |
|||
|
|||
class SOAP_Array { |
|||
public function get($id){ |
|||
return $this->add($id); |
|||
} |
|||
} |
|||
|
|||
$xml = xmlrpc_server_create(); |
|||
|
|||
$Myrequest = '<?xml version="1.0" encoding="UTF-8"?><methodCall><methodName>GetProducts</methodName><params><param><value><dateTime.iso8601>20060922T14:26:19</dateTime.iso8601></value></param></params></methodCall>'; |
|||
|
|||
class MyClass { |
|||
function GetProducts($dummy, $time){ |
|||
return array('faultString' => $time); |
|||
} |
|||
} |
|||
$myclass = new MyClass(); |
|||
xmlrpc_server_register_method($xml, 'GetProducts', array($myclass, 'GetProducts')); |
|||
$response = xmlrpc_server_call_method($xml, $Myrequest, null); |
|||
|
|||
var_dump($response); |
|||
|
|||
echo "Done\n"; |
|||
?> |
|||
--EXPECT-- |
|||
string(402) "<?xml version="1.0" encoding="iso-8859-1"?> |
|||
<methodResponse> |
|||
<params> |
|||
<param> |
|||
<value> |
|||
<struct> |
|||
<member> |
|||
<name>faultString</name> |
|||
<value> |
|||
<array> |
|||
<data> |
|||
<value> |
|||
<dateTime.iso8601>20060922T14:26:19</dateTime.iso8601> |
|||
</value> |
|||
</data> |
|||
</array> |
|||
</value> |
|||
</member> |
|||
</struct> |
|||
</value> |
|||
</param> |
|||
</params> |
|||
</methodResponse> |
|||
" |
|||
Done |
|||
@ -1,51 +0,0 @@ |
|||
--TEST-- |
|||
Bug #44996 (xmlrpc_decode() ignores time zone on iso8601.datetime) |
|||
--SKIPIF-- |
|||
<?php if (!extension_loaded("xmlrpc")) print "skip"; ?> |
|||
--FILE-- |
|||
<?php |
|||
|
|||
function DecodeDatetime($datetime) { |
|||
print "\nISO 8601 datetime $datetime\n"; |
|||
$obj = xmlrpc_decode("<?xml version=\"1.0\"?><methodResponse><params><param><value><dateTime.iso8601>$datetime</dateTime.iso8601></value></param></params></methodResponse>"); |
|||
print_r($obj); |
|||
} |
|||
|
|||
DecodeDatetime("20010909T01:46:40Z"); |
|||
DecodeDatetime("20010909T00:46:40-01"); |
|||
DecodeDatetime("2001-09-09T08:46:40+07:00"); |
|||
DecodeDatetime("2001-09-08T21:46:40-0400"); |
|||
|
|||
?> |
|||
--EXPECT-- |
|||
ISO 8601 datetime 20010909T01:46:40Z |
|||
stdClass Object |
|||
( |
|||
[scalar] => 20010909T01:46:40Z |
|||
[xmlrpc_type] => datetime |
|||
[timestamp] => 1000000000 |
|||
) |
|||
|
|||
ISO 8601 datetime 20010909T00:46:40-01 |
|||
stdClass Object |
|||
( |
|||
[scalar] => 20010909T00:46:40-01 |
|||
[xmlrpc_type] => datetime |
|||
[timestamp] => 1000000000 |
|||
) |
|||
|
|||
ISO 8601 datetime 2001-09-09T08:46:40+07:00 |
|||
stdClass Object |
|||
( |
|||
[scalar] => 2001-09-09T08:46:40+07:00 |
|||
[xmlrpc_type] => datetime |
|||
[timestamp] => 1000000000 |
|||
) |
|||
|
|||
ISO 8601 datetime 2001-09-08T21:46:40-0400 |
|||
stdClass Object |
|||
( |
|||
[scalar] => 2001-09-08T21:46:40-0400 |
|||
[xmlrpc_type] => datetime |
|||
[timestamp] => 1000000000 |
|||
) |
|||
@ -1,55 +0,0 @@ |
|||
--TEST-- |
|||
Bug #45226 (xmlrpc_set_type() segfaults with valid ISO8601 date string) |
|||
--INI-- |
|||
date.timezone="America/Sao_Paulo" |
|||
--SKIPIF-- |
|||
<?php if (!extension_loaded("xmlrpc")) print "skip"; ?> |
|||
--FILE-- |
|||
<?php |
|||
|
|||
$d = date(DATE_ISO8601); |
|||
xmlrpc_set_type($d, 'datetime'); |
|||
echo xmlrpc_encode_request('method.call', array('date' => $d)); |
|||
|
|||
$d = '2008-01-01 20:00:00'; |
|||
xmlrpc_set_type($d, 'datetime'); |
|||
echo xmlrpc_encode_request('method.call', array('date' => $d)); |
|||
|
|||
?> |
|||
--EXPECTF-- |
|||
<?xml version="1.0" encoding="iso-8859-1"?> |
|||
<methodCall> |
|||
<methodName>method.call</methodName> |
|||
<params> |
|||
<param> |
|||
<value> |
|||
<struct> |
|||
<member> |
|||
<name>date</name> |
|||
<value> |
|||
<dateTime.iso8601>%d-%d-%dT%d:%d:%d%s%d</dateTime.iso8601> |
|||
</value> |
|||
</member> |
|||
</struct> |
|||
</value> |
|||
</param> |
|||
</params> |
|||
</methodCall> |
|||
<?xml version="1.0" encoding="iso-8859-1"?> |
|||
<methodCall> |
|||
<methodName>method.call</methodName> |
|||
<params> |
|||
<param> |
|||
<value> |
|||
<struct> |
|||
<member> |
|||
<name>date</name> |
|||
<value> |
|||
<dateTime.iso8601>%d-%d-%d %d:%d:%d</dateTime.iso8601> |
|||
</value> |
|||
</member> |
|||
</struct> |
|||
</value> |
|||
</param> |
|||
</params> |
|||
</methodCall> |
|||
@ -1,22 +0,0 @@ |
|||
--TEST-- |
|||
Bug #45555 (Segfault with invalid non-string as register_introspection_callback) |
|||
--SKIPIF-- |
|||
<?php if (!extension_loaded("xmlrpc")) print "skip"; ?> |
|||
--FILE-- |
|||
<?php |
|||
|
|||
$options = array (); |
|||
$request = xmlrpc_encode_request ("system.describeMethods", $options); |
|||
$server = xmlrpc_server_create (); |
|||
|
|||
xmlrpc_server_register_introspection_callback($server, 1); |
|||
xmlrpc_server_register_introspection_callback($server, array('foo', 'bar')); |
|||
|
|||
$options = array ('output_type' => 'xml', 'version' => 'xmlrpc'); |
|||
xmlrpc_server_call_method ($server, $request, NULL, $options); |
|||
|
|||
?> |
|||
--EXPECTF-- |
|||
Warning: xmlrpc_server_call_method(): Invalid callback '1' passed in %s on line %d |
|||
|
|||
Warning: xmlrpc_server_call_method(): Invalid callback 'foo::bar' passed in %s on line %d |
|||
@ -1,34 +0,0 @@ |
|||
--TEST-- |
|||
Bug #45556 (Return value from callback isn't freed) |
|||
--SKIPIF-- |
|||
<?php if (!extension_loaded("xmlrpc")) print "skip"; ?> |
|||
--FILE-- |
|||
<?php |
|||
|
|||
$options = array (); |
|||
$request = xmlrpc_encode_request ("system.describeMethods", $options); |
|||
$server = xmlrpc_server_create (); |
|||
|
|||
|
|||
function foo() { return 11111; } |
|||
|
|||
class bar { |
|||
static public function test() { |
|||
return 'foo'; |
|||
} |
|||
} |
|||
|
|||
xmlrpc_server_register_introspection_callback($server, 'foobar'); |
|||
xmlrpc_server_register_introspection_callback($server, array('bar', 'test')); |
|||
xmlrpc_server_register_introspection_callback($server, array('foo', 'bar')); |
|||
|
|||
$options = array ('output_type' => 'xml', 'version' => 'xmlrpc'); |
|||
xmlrpc_server_call_method ($server, $request, NULL, $options); |
|||
|
|||
?> |
|||
--EXPECTF-- |
|||
Warning: xmlrpc_server_call_method(): Invalid callback 'foobar' passed in %s on line %d |
|||
|
|||
Warning: xmlrpc_server_call_method(): XML parse error: [line 1, column 1, message: Invalid document end] Unable to add introspection data returned from bar::test() in %s on line %d |
|||
|
|||
Warning: xmlrpc_server_call_method(): Invalid callback 'foo::bar' passed in %s on line %d |
|||
@ -1,41 +0,0 @@ |
|||
--TEST-- |
|||
Bug #47818 (Segfault due to bound callback param) |
|||
--SKIPIF-- |
|||
<?php if (!extension_loaded("xmlrpc")) print "skip"; ?> |
|||
--FILE-- |
|||
<?php |
|||
|
|||
class MyXmlRpc { |
|||
private $s; |
|||
private $method; |
|||
|
|||
function impl($method_name, $params, $user_data){ |
|||
$this->method = $method_name; |
|||
print "Inside impl(): {$this->method}\n"; |
|||
return array_sum($params); |
|||
} |
|||
|
|||
function __construct() { |
|||
$this->s = xmlrpc_server_create(); |
|||
xmlrpc_server_register_method($this->s, 'add', array($this, 'impl')); |
|||
} |
|||
|
|||
function call($req) { |
|||
return xmlrpc_server_call_method($this->s, $req, null); |
|||
} |
|||
|
|||
function getMethod() {return $this->method;} |
|||
|
|||
} |
|||
|
|||
$x = new MyXmlRpc; |
|||
$resp = $x->call(xmlrpc_encode_request('add', array(1, 2, 3))); |
|||
|
|||
$method = $x->getMethod(); |
|||
|
|||
print "Global scope: $method\n"; |
|||
|
|||
?> |
|||
--EXPECT-- |
|||
Inside impl(): add |
|||
Global scope: add |
|||
@ -1,43 +0,0 @@ |
|||
--TEST-- |
|||
Bug #50282 (xmlrpc_encode_request() changes object into array in calling function) |
|||
--SKIPIF-- |
|||
<?php if (!extension_loaded("xmlrpc")) print "skip"; ?> |
|||
--FILE-- |
|||
<?php |
|||
|
|||
class One { var $x = 10; } |
|||
|
|||
$o = new One(); |
|||
var_dump($o); |
|||
var_dump(xmlrpc_encode_request('test', $o)); |
|||
var_dump($o); |
|||
|
|||
?> |
|||
--EXPECTF-- |
|||
object(One)#%d (1) { |
|||
["x"]=> |
|||
int(10) |
|||
} |
|||
string(279) "<?xml version="1.0" encoding="iso-8859-1"?> |
|||
<methodCall> |
|||
<methodName>test</methodName> |
|||
<params> |
|||
<param> |
|||
<value> |
|||
<struct> |
|||
<member> |
|||
<name>x</name> |
|||
<value> |
|||
<int>10</int> |
|||
</value> |
|||
</member> |
|||
</struct> |
|||
</value> |
|||
</param> |
|||
</params> |
|||
</methodCall> |
|||
" |
|||
object(One)#%d (1) { |
|||
["x"]=> |
|||
int(10) |
|||
} |
|||
@ -1,117 +0,0 @@ |
|||
--TEST-- |
|||
Bug #50285 (xmlrpc does not preserve keys in encoded indexed arrays) |
|||
--SKIPIF-- |
|||
<?php if (!extension_loaded("xmlrpc")) print "skip"; ?> |
|||
--FILE-- |
|||
<?php |
|||
|
|||
function test1($func, $params) { |
|||
return array(1=>'One', 3=>'Three', 5=>'Five'); |
|||
} |
|||
|
|||
function test2($func, $params) { |
|||
return array('One', 'Three', 'Five', 5); |
|||
} |
|||
|
|||
function test3($func, $params) { |
|||
return array('One', 3 => 'Three', 'Five' => 5, 'Six'); |
|||
} |
|||
|
|||
function test4($func, $params) { |
|||
return array('One', 'Three', 'Five', 'Six' => 6); |
|||
} |
|||
|
|||
$server = xmlrpc_server_create(); |
|||
$result = xmlrpc_server_register_method($server, 'test1', 'test1'); |
|||
$HTTP_RAW_POST_DATA = <<<EOD |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<methodCall> |
|||
<methodName>test1</methodName> |
|||
<params /> |
|||
</methodCall> |
|||
EOD; |
|||
$response = xmlrpc_server_call_method($server, $HTTP_RAW_POST_DATA, null); |
|||
var_dump(xmlrpc_decode($response)); |
|||
|
|||
// ------------ |
|||
|
|||
$server = xmlrpc_server_create(); |
|||
$result = xmlrpc_server_register_method($server, 'test2', 'test2'); |
|||
$HTTP_RAW_POST_DATA = <<<EOD |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<methodCall> |
|||
<methodName>test2</methodName> |
|||
<params /> |
|||
</methodCall> |
|||
EOD; |
|||
$response = xmlrpc_server_call_method($server, $HTTP_RAW_POST_DATA, null); |
|||
var_dump(xmlrpc_decode($response)); |
|||
|
|||
// ------------ |
|||
|
|||
$server = xmlrpc_server_create(); |
|||
$result = xmlrpc_server_register_method($server, 'test3', 'test3'); |
|||
$HTTP_RAW_POST_DATA = <<<EOD |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<methodCall> |
|||
<methodName>test3</methodName> |
|||
<params /> |
|||
</methodCall> |
|||
EOD; |
|||
$response = xmlrpc_server_call_method($server, $HTTP_RAW_POST_DATA, null); |
|||
var_dump(xmlrpc_decode($response)); |
|||
|
|||
// ------------ |
|||
|
|||
$server = xmlrpc_server_create(); |
|||
$result = xmlrpc_server_register_method($server, 'test4', 'test4'); |
|||
$HTTP_RAW_POST_DATA = <<<EOD |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<methodCall> |
|||
<methodName>test4</methodName> |
|||
<params /> |
|||
</methodCall> |
|||
EOD; |
|||
$response = xmlrpc_server_call_method($server, $HTTP_RAW_POST_DATA, null); |
|||
var_dump(xmlrpc_decode($response)); |
|||
|
|||
?> |
|||
--EXPECT-- |
|||
array(3) { |
|||
[1]=> |
|||
string(3) "One" |
|||
[3]=> |
|||
string(5) "Three" |
|||
[5]=> |
|||
string(4) "Five" |
|||
} |
|||
array(4) { |
|||
[0]=> |
|||
string(3) "One" |
|||
[1]=> |
|||
string(5) "Three" |
|||
[2]=> |
|||
string(4) "Five" |
|||
[3]=> |
|||
int(5) |
|||
} |
|||
array(4) { |
|||
[0]=> |
|||
string(3) "One" |
|||
[3]=> |
|||
string(5) "Three" |
|||
["Five"]=> |
|||
int(5) |
|||
[4]=> |
|||
string(3) "Six" |
|||
} |
|||
array(4) { |
|||
[0]=> |
|||
string(3) "One" |
|||
[1]=> |
|||
string(5) "Three" |
|||
[2]=> |
|||
string(4) "Five" |
|||
["Six"]=> |
|||
int(6) |
|||
} |
|||
@ -1,64 +0,0 @@ |
|||
--TEST-- |
|||
Bug #50761 (system.multiCall crashes) |
|||
--SKIPIF-- |
|||
<?php if (!extension_loaded("xmlrpc")) print "skip"; ?> |
|||
--FILE-- |
|||
<?php |
|||
$req = '<?xml version="1.0"?> |
|||
<methodCall> |
|||
<methodName>system.multiCall</methodName> |
|||
<params><param><value><array><data> |
|||
<value><struct> |
|||
<member><name>methodName</name><value><string>testMethodA</string></value></member> |
|||
<member><name>params</name><value><array><data><value><string>A</string> |
|||
</value></data></array></value></member> |
|||
</struct></value> |
|||
<value><struct> |
|||
<member><name>methodName</name><value><string>testMethodB</string></value></member> |
|||
<member><name>params</name><value><array><data><value><string>B</string> |
|||
</value></data></array></value></member> |
|||
</struct></value> |
|||
</data></array></value></param></params> |
|||
</methodCall>'; |
|||
|
|||
function testA($methodName, $params, $var){ return "C"; } |
|||
function testB($methodName, $params, $var){ return "D"; } |
|||
|
|||
$server = xmlrpc_server_create(); |
|||
xmlrpc_server_register_method($server, 'testMethodA', 'testA'); |
|||
xmlrpc_server_register_method($server, 'testMethodB', 'testB'); |
|||
$res = xmlrpc_server_call_method($server, $req, null); |
|||
echo $res; |
|||
?> |
|||
--EXPECT-- |
|||
<?xml version="1.0" encoding="iso-8859-1"?> |
|||
<methodResponse> |
|||
<params> |
|||
<param> |
|||
<value> |
|||
<array> |
|||
<data> |
|||
<value> |
|||
<array> |
|||
<data> |
|||
<value> |
|||
<string>C</string> |
|||
</value> |
|||
</data> |
|||
</array> |
|||
</value> |
|||
<value> |
|||
<array> |
|||
<data> |
|||
<value> |
|||
<string>D</string> |
|||
</value> |
|||
</data> |
|||
</array> |
|||
</value> |
|||
</data> |
|||
</array> |
|||
</value> |
|||
</param> |
|||
</params> |
|||
</methodResponse> |
|||
@ -1,16 +0,0 @@ |
|||
--TEST-- |
|||
Bug #51288 (CVE-2010-0397, NULL pointer deref when no <methodName> in request) |
|||
--SKIPIF-- |
|||
<?php if (!extension_loaded("xmlrpc")) print "skip"; ?> |
|||
--FILE-- |
|||
<?php |
|||
$method = NULL; |
|||
$req = '<?xml version="1.0"?><methodCall></methodCall>'; |
|||
var_dump(xmlrpc_decode_request($req, $method)); |
|||
var_dump($method); |
|||
echo "Done\n"; |
|||
?> |
|||
--EXPECT-- |
|||
NULL |
|||
NULL |
|||
Done |
|||
@ -1,16 +0,0 @@ |
|||
--TEST-- |
|||
Bug #61097 (Memory leak in xmlrpc functions copying zvals) |
|||
--SKIPIF-- |
|||
<?php if (!extension_loaded("xmlrpc")) print "skip"; ?> |
|||
--FILE-- |
|||
<?php |
|||
$server = xmlrpc_server_create(); |
|||
|
|||
$method = 'abc'; |
|||
xmlrpc_server_register_introspection_callback($server, $method); |
|||
xmlrpc_server_register_method($server, 'abc', $method); |
|||
|
|||
echo 'Done'; |
|||
?> |
|||
--EXPECT-- |
|||
Done |
|||
@ -1,19 +0,0 @@ |
|||
--TEST-- |
|||
Bug #61264: xmlrpc_parse_method_descriptions leaks temporary variable |
|||
--SKIPIF-- |
|||
<?php if (!extension_loaded("xmlrpc")) print "skip"; ?> |
|||
--FILE-- |
|||
<?php |
|||
$xml = <<<XML |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<a> |
|||
<b>foo</b> |
|||
</a> |
|||
XML; |
|||
var_dump(xmlrpc_parse_method_descriptions($xml)); |
|||
?> |
|||
--EXPECT-- |
|||
array(1) { |
|||
["b"]=> |
|||
string(3) "foo" |
|||
} |
|||
@ -1,44 +0,0 @@ |
|||
--TEST-- |
|||
Bug #68027 (buffer overflow in mkgmtime() function) |
|||
--SKIPIF-- |
|||
<?php |
|||
if (!extension_loaded("xmlrpc")) print "skip"; |
|||
?> |
|||
--FILE-- |
|||
<?php |
|||
|
|||
$d = '6-01-01 20:00:00'; |
|||
xmlrpc_set_type($d, 'datetime'); |
|||
var_dump($d); |
|||
$datetime = "2001-0-08T21:46:40-0400"; |
|||
$obj = xmlrpc_decode("<?xml version=\"1.0\"?><methodResponse><params><param><value><dateTime.iso8601>$datetime</dateTime.iso8601></value></param></params></methodResponse>"); |
|||
print_r($obj); |
|||
|
|||
$datetime = "34770-0-08T21:46:40-0400"; |
|||
$obj = xmlrpc_decode("<?xml version=\"1.0\"?><methodResponse><params><param><value><dateTime.iso8601>$datetime</dateTime.iso8601></value></param></params></methodResponse>"); |
|||
print_r($obj); |
|||
|
|||
echo "Done\n"; |
|||
?> |
|||
--EXPECTF-- |
|||
object(stdClass)#1 (3) { |
|||
["scalar"]=> |
|||
string(16) "6-01-01 20:00:00" |
|||
["xmlrpc_type"]=> |
|||
string(8) "datetime" |
|||
["timestamp"]=> |
|||
int(%d) |
|||
} |
|||
stdClass Object |
|||
( |
|||
[scalar] => 2001-0-08T21:46:40-0400 |
|||
[xmlrpc_type] => datetime |
|||
[timestamp] => %s |
|||
) |
|||
stdClass Object |
|||
( |
|||
[scalar] => 34770-0-08T21:46:40-0400 |
|||
[xmlrpc_type] => datetime |
|||
[timestamp] => %d |
|||
) |
|||
Done |
|||
@ -1,14 +0,0 @@ |
|||
--TEST-- |
|||
Bug #70526 (xmlrpc_set_type returns false on success) |
|||
--SKIPIF-- |
|||
<?php |
|||
if (!extension_loaded("xmlrpc")) print "skip"; |
|||
?> |
|||
--FILE-- |
|||
<?php |
|||
$params = date("Ymd\TH:i:s", time()); |
|||
$rv = xmlrpc_set_type($params, 'datetime'); |
|||
var_dump($rv); |
|||
?> |
|||
--EXPECT-- |
|||
bool(true) |
|||
@ -1,31 +0,0 @@ |
|||
--TEST-- |
|||
Bug #70728 (Type Confusion Vulnerability in PHP_to_XMLRPC_worker) |
|||
--SKIPIF-- |
|||
<?php |
|||
if (!extension_loaded("xmlrpc")) print "skip"; |
|||
if (PHP_INT_SIZE != 4) die("skip this test is for 32bit platform only"); |
|||
?> |
|||
--FILE-- |
|||
<?php |
|||
$obj = new stdClass; |
|||
$obj->xmlrpc_type = 'base64'; |
|||
$obj->scalar = 0x1122334455; |
|||
var_dump(xmlrpc_encode($obj)); |
|||
var_dump($obj); |
|||
?> |
|||
--EXPECT-- |
|||
string(135) "<?xml version="1.0" encoding="utf-8"?> |
|||
<params> |
|||
<param> |
|||
<value> |
|||
<base64>NzM1ODgyMjkyMDU= </base64> |
|||
</value> |
|||
</param> |
|||
</params> |
|||
" |
|||
object(stdClass)#1 (2) { |
|||
["xmlrpc_type"]=> |
|||
string(6) "base64" |
|||
["scalar"]=> |
|||
float(73588229205) |
|||
} |
|||
@ -1,31 +0,0 @@ |
|||
--TEST-- |
|||
Bug #70728 (Type Confusion Vulnerability in PHP_to_XMLRPC_worker) |
|||
--SKIPIF-- |
|||
<?php |
|||
if (!extension_loaded("xmlrpc")) print "skip"; |
|||
if (PHP_INT_SIZE != 8) die("skip this test is for 64bit platform only"); |
|||
?> |
|||
--FILE-- |
|||
<?php |
|||
$obj = new stdClass; |
|||
$obj->xmlrpc_type = 'base64'; |
|||
$obj->scalar = 0x1122334455; |
|||
var_dump(xmlrpc_encode($obj)); |
|||
var_dump($obj); |
|||
?> |
|||
--EXPECT-- |
|||
string(135) "<?xml version="1.0" encoding="utf-8"?> |
|||
<params> |
|||
<param> |
|||
<value> |
|||
<base64>NzM1ODgyMjkyMDU= </base64> |
|||
</value> |
|||
</param> |
|||
</params> |
|||
" |
|||
object(stdClass)#1 (2) { |
|||
["xmlrpc_type"]=> |
|||
string(6) "base64" |
|||
["scalar"]=> |
|||
int(73588229205) |
|||
} |
|||
@ -1,23 +0,0 @@ |
|||
--TEST-- |
|||
Bug #71501 (xmlrpc_encode_request ignores encoding option) |
|||
--SKIPIF-- |
|||
<?php |
|||
if (!extension_loaded("xmlrpc")) print "skip"; |
|||
?> |
|||
--FILE-- |
|||
<?php |
|||
$params = 'Lê Trung Hiếu'; |
|||
echo xmlrpc_encode_request('foo', $params, ['encoding' => 'UTF-8', 'escaping' => 'markup']); |
|||
?> |
|||
--EXPECT-- |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<methodCall> |
|||
<methodName>foo</methodName> |
|||
<params> |
|||
<param> |
|||
<value> |
|||
<string>Lê Trung Hiếu</string> |
|||
</value> |
|||
</param> |
|||
</params> |
|||
</methodCall> |
|||
@ -1,27 +0,0 @@ |
|||
--TEST-- |
|||
Bug #72155 (use-after-free caused by get_zval_xmlrpc_type) |
|||
--SKIPIF-- |
|||
<?php |
|||
if (!extension_loaded("xmlrpc")) print "skip"; |
|||
?> |
|||
--FILE-- |
|||
<?php |
|||
if (false !== strpos(PHP_OS, "WIN")) { |
|||
$fl = "c:\\windows\\explorer.exe"; |
|||
} else { |
|||
$fl = "/etc/passwd"; |
|||
} |
|||
$var0 = fopen($fl,"r"); |
|||
$var1 = xmlrpc_encode($var0); |
|||
var_dump($var1); |
|||
?> |
|||
--EXPECT-- |
|||
string(109) "<?xml version="1.0" encoding="utf-8"?> |
|||
<params> |
|||
<param> |
|||
<value> |
|||
<int>5</int> |
|||
</value> |
|||
</param> |
|||
</params> |
|||
" |
|||
@ -1,36 +0,0 @@ |
|||
--TEST-- |
|||
Bug #72647 (xmlrpc_encode() unexpected output after referencing array elements) |
|||
--SKIPIF-- |
|||
<?php |
|||
if (!extension_loaded("xmlrpc")) print "skip"; |
|||
?> |
|||
--FILE-- |
|||
<?php |
|||
|
|||
$ar = array(4, "a", 7); |
|||
$v = &$ar[1]; |
|||
unset($v); |
|||
|
|||
echo xmlrpc_encode($ar); |
|||
?> |
|||
--EXPECT-- |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<params> |
|||
<param> |
|||
<value> |
|||
<array> |
|||
<data> |
|||
<value> |
|||
<int>4</int> |
|||
</value> |
|||
<value> |
|||
<string>a</string> |
|||
</value> |
|||
<value> |
|||
<int>7</int> |
|||
</value> |
|||
</data> |
|||
</array> |
|||
</value> |
|||
</param> |
|||
</params> |
|||
@ -1,56 +0,0 @@ |
|||
--TEST-- |
|||
Bug #74975 Different serialization for classes |
|||
--SKIPIF-- |
|||
<?php |
|||
if (!extension_loaded("xmlrpc")) print "skip"; |
|||
?> |
|||
--FILE-- |
|||
<?php |
|||
|
|||
class Foo { |
|||
|
|||
} |
|||
|
|||
class Bar { |
|||
|
|||
public $xmlrpc_type; |
|||
public $scalar; |
|||
|
|||
} |
|||
|
|||
$foo = new Foo(); |
|||
$foo->xmlrpc_type = 'base64'; |
|||
$foo->scalar = 'foobar'; |
|||
|
|||
$bar = new Bar(); |
|||
$bar->xmlrpc_type = 'base64'; |
|||
$bar->scalar = 'foobar'; |
|||
|
|||
echo xmlrpc_encode([ |
|||
'foo' => $foo, |
|||
'bar' => $bar |
|||
]); |
|||
|
|||
?> |
|||
--EXPECT-- |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<params> |
|||
<param> |
|||
<value> |
|||
<struct> |
|||
<member> |
|||
<name>foo</name> |
|||
<value> |
|||
<base64>Zm9vYmFy </base64> |
|||
</value> |
|||
</member> |
|||
<member> |
|||
<name>bar</name> |
|||
<value> |
|||
<base64>Zm9vYmFy </base64> |
|||
</value> |
|||
</member> |
|||
</struct> |
|||
</value> |
|||
</param> |
|||
</params> |
|||
@ -1,10 +0,0 @@ |
|||
--TEST-- |
|||
Bug #77242 (heap out of bounds read in xmlrpc_decode()) |
|||
--SKIPIF-- |
|||
<?php if (!extension_loaded("xmlrpc")) print "skip"; ?> |
|||
--FILE-- |
|||
<?php |
|||
var_dump(xmlrpc_decode(base64_decode("PD94bWwgdmVyc2lvbmVuY29kaW5nPSJJU084ODU5NyKkpKSkpKSkpKSkpKSkpKSkpKSkpKSk"))); |
|||
?> |
|||
--EXPECT-- |
|||
NULL |
|||
@ -1,17 +0,0 @@ |
|||
--TEST-- |
|||
Bug #77380 (Global out of bounds read in xmlrpc base64 code) |
|||
--SKIPIF-- |
|||
<?php |
|||
if (!extension_loaded("xmlrpc")) print "skip"; |
|||
?> |
|||
--FILE-- |
|||
<?php |
|||
var_dump(xmlrpc_decode(base64_decode("PGJhc2U2ND7CkzwvYmFzZTY0Pgo="))); |
|||
?> |
|||
--EXPECT-- |
|||
object(stdClass)#1 (2) { |
|||
["scalar"]=> |
|||
string(0) "" |
|||
["xmlrpc_type"]=> |
|||
string(6) "base64" |
|||
} |
|||
1377
ext/xmlrpc/xmlrpc-epi-php.c
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -1,35 +0,0 @@ |
|||
<?php |
|||
|
|||
/** @generate-function-entries */ |
|||
|
|||
final class XmlRpcServer |
|||
{ |
|||
} |
|||
|
|||
function xmlrpc_encode(mixed $value): ?string {} |
|||
|
|||
function xmlrpc_decode(string $xml, string $encoding = "iso-8859-1"): mixed {} |
|||
|
|||
function xmlrpc_decode_request(string $xml, &$method, string $encoding = "iso-8859-1"): mixed {} |
|||
|
|||
function xmlrpc_encode_request(?string $method, mixed $params, array $output_options = []): ?string {} |
|||
|
|||
function xmlrpc_get_type(mixed $value): string {} |
|||
|
|||
function xmlrpc_set_type(&$value, string $type): bool {} |
|||
|
|||
function xmlrpc_is_fault(array $arg): bool {} |
|||
|
|||
function xmlrpc_server_create(): XmlRpcServer {} |
|||
|
|||
function xmlrpc_server_destroy(XmlRpcServer $server): bool {} |
|||
|
|||
function xmlrpc_server_register_method(XmlRpcServer $server, string $method_name, $function): bool {} |
|||
|
|||
function xmlrpc_server_call_method(XmlRpcServer $server, string $xml, mixed $user_data, array $output_options = []): mixed {} |
|||
|
|||
function xmlrpc_parse_method_descriptions(string $xml): mixed {} |
|||
|
|||
function xmlrpc_server_add_introspection_data(XmlRpcServer $server, array $desc): int {} |
|||
|
|||
function xmlrpc_server_register_introspection_callback(XmlRpcServer $server, $function): bool {} |
|||
@ -1,109 +0,0 @@ |
|||
/* This is a generated file, edit the .stub.php file instead. */ |
|||
|
|||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_xmlrpc_encode, 0, 1, IS_STRING, 1) |
|||
ZEND_ARG_TYPE_INFO(0, value, IS_MIXED, 0) |
|||
ZEND_END_ARG_INFO() |
|||
|
|||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_xmlrpc_decode, 0, 1, IS_MIXED, 0) |
|||
ZEND_ARG_TYPE_INFO(0, xml, IS_STRING, 0) |
|||
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, encoding, IS_STRING, 0, "\"iso-8859-1\"") |
|||
ZEND_END_ARG_INFO() |
|||
|
|||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_xmlrpc_decode_request, 0, 2, IS_MIXED, 0) |
|||
ZEND_ARG_TYPE_INFO(0, xml, IS_STRING, 0) |
|||
ZEND_ARG_INFO(1, method) |
|||
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, encoding, IS_STRING, 0, "\"iso-8859-1\"") |
|||
ZEND_END_ARG_INFO() |
|||
|
|||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_xmlrpc_encode_request, 0, 2, IS_STRING, 1) |
|||
ZEND_ARG_TYPE_INFO(0, method, IS_STRING, 1) |
|||
ZEND_ARG_TYPE_INFO(0, params, IS_MIXED, 0) |
|||
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, output_options, IS_ARRAY, 0, "[]") |
|||
ZEND_END_ARG_INFO() |
|||
|
|||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_xmlrpc_get_type, 0, 1, IS_STRING, 0) |
|||
ZEND_ARG_TYPE_INFO(0, value, IS_MIXED, 0) |
|||
ZEND_END_ARG_INFO() |
|||
|
|||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_xmlrpc_set_type, 0, 2, _IS_BOOL, 0) |
|||
ZEND_ARG_INFO(1, value) |
|||
ZEND_ARG_TYPE_INFO(0, type, IS_STRING, 0) |
|||
ZEND_END_ARG_INFO() |
|||
|
|||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_xmlrpc_is_fault, 0, 1, _IS_BOOL, 0) |
|||
ZEND_ARG_TYPE_INFO(0, arg, IS_ARRAY, 0) |
|||
ZEND_END_ARG_INFO() |
|||
|
|||
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_xmlrpc_server_create, 0, 0, XmlRpcServer, 0) |
|||
ZEND_END_ARG_INFO() |
|||
|
|||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_xmlrpc_server_destroy, 0, 1, _IS_BOOL, 0) |
|||
ZEND_ARG_OBJ_INFO(0, server, XmlRpcServer, 0) |
|||
ZEND_END_ARG_INFO() |
|||
|
|||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_xmlrpc_server_register_method, 0, 3, _IS_BOOL, 0) |
|||
ZEND_ARG_OBJ_INFO(0, server, XmlRpcServer, 0) |
|||
ZEND_ARG_TYPE_INFO(0, method_name, IS_STRING, 0) |
|||
ZEND_ARG_INFO(0, function) |
|||
ZEND_END_ARG_INFO() |
|||
|
|||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_xmlrpc_server_call_method, 0, 3, IS_MIXED, 0) |
|||
ZEND_ARG_OBJ_INFO(0, server, XmlRpcServer, 0) |
|||
ZEND_ARG_TYPE_INFO(0, xml, IS_STRING, 0) |
|||
ZEND_ARG_TYPE_INFO(0, user_data, IS_MIXED, 0) |
|||
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, output_options, IS_ARRAY, 0, "[]") |
|||
ZEND_END_ARG_INFO() |
|||
|
|||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_xmlrpc_parse_method_descriptions, 0, 1, IS_MIXED, 0) |
|||
ZEND_ARG_TYPE_INFO(0, xml, IS_STRING, 0) |
|||
ZEND_END_ARG_INFO() |
|||
|
|||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_xmlrpc_server_add_introspection_data, 0, 2, IS_LONG, 0) |
|||
ZEND_ARG_OBJ_INFO(0, server, XmlRpcServer, 0) |
|||
ZEND_ARG_TYPE_INFO(0, desc, IS_ARRAY, 0) |
|||
ZEND_END_ARG_INFO() |
|||
|
|||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_xmlrpc_server_register_introspection_callback, 0, 2, _IS_BOOL, 0) |
|||
ZEND_ARG_OBJ_INFO(0, server, XmlRpcServer, 0) |
|||
ZEND_ARG_INFO(0, function) |
|||
ZEND_END_ARG_INFO() |
|||
|
|||
|
|||
ZEND_FUNCTION(xmlrpc_encode); |
|||
ZEND_FUNCTION(xmlrpc_decode); |
|||
ZEND_FUNCTION(xmlrpc_decode_request); |
|||
ZEND_FUNCTION(xmlrpc_encode_request); |
|||
ZEND_FUNCTION(xmlrpc_get_type); |
|||
ZEND_FUNCTION(xmlrpc_set_type); |
|||
ZEND_FUNCTION(xmlrpc_is_fault); |
|||
ZEND_FUNCTION(xmlrpc_server_create); |
|||
ZEND_FUNCTION(xmlrpc_server_destroy); |
|||
ZEND_FUNCTION(xmlrpc_server_register_method); |
|||
ZEND_FUNCTION(xmlrpc_server_call_method); |
|||
ZEND_FUNCTION(xmlrpc_parse_method_descriptions); |
|||
ZEND_FUNCTION(xmlrpc_server_add_introspection_data); |
|||
ZEND_FUNCTION(xmlrpc_server_register_introspection_callback); |
|||
|
|||
|
|||
static const zend_function_entry ext_functions[] = { |
|||
ZEND_FE(xmlrpc_encode, arginfo_xmlrpc_encode) |
|||
ZEND_FE(xmlrpc_decode, arginfo_xmlrpc_decode) |
|||
ZEND_FE(xmlrpc_decode_request, arginfo_xmlrpc_decode_request) |
|||
ZEND_FE(xmlrpc_encode_request, arginfo_xmlrpc_encode_request) |
|||
ZEND_FE(xmlrpc_get_type, arginfo_xmlrpc_get_type) |
|||
ZEND_FE(xmlrpc_set_type, arginfo_xmlrpc_set_type) |
|||
ZEND_FE(xmlrpc_is_fault, arginfo_xmlrpc_is_fault) |
|||
ZEND_FE(xmlrpc_server_create, arginfo_xmlrpc_server_create) |
|||
ZEND_FE(xmlrpc_server_destroy, arginfo_xmlrpc_server_destroy) |
|||
ZEND_FE(xmlrpc_server_register_method, arginfo_xmlrpc_server_register_method) |
|||
ZEND_FE(xmlrpc_server_call_method, arginfo_xmlrpc_server_call_method) |
|||
ZEND_FE(xmlrpc_parse_method_descriptions, arginfo_xmlrpc_parse_method_descriptions) |
|||
ZEND_FE(xmlrpc_server_add_introspection_data, arginfo_xmlrpc_server_add_introspection_data) |
|||
ZEND_FE(xmlrpc_server_register_introspection_callback, arginfo_xmlrpc_server_register_introspection_callback) |
|||
ZEND_FE_END |
|||
}; |
|||
|
|||
|
|||
static const zend_function_entry class_XmlRpcServer_methods[] = { |
|||
ZEND_FE_END |
|||
}; |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue