mirror of
https://github.com/php/php-src.git
synced 2026-03-24 00:02:20 +01:00
Unbundle ext/xmlrpc
According to <https://wiki.php.net/rfc/unbundle_xmlprc> we unbundle ext/xmlrpc.
This commit is contained in:
@@ -197,9 +197,6 @@ locations.
|
||||
└─ tokenizer/
|
||||
├─ tokenizer_data.c # Generated by `ext/tokenizer/tokenizer_data_gen.sh`
|
||||
└─ ...
|
||||
└─ xmlrpc/
|
||||
├─ libxmlrpc/ # Forked and maintained in php-src
|
||||
└─ ...
|
||||
└─ zend_test # For testing internal APIs. Not needed for regular builds.
|
||||
└─ ...
|
||||
└─ zip/ # Bundled https://github.com/pierrejoye/php_zip
|
||||
|
||||
@@ -214,11 +214,6 @@ PRIMARY MAINTAINER: Rob Richards <rrichards@php.net> (2004 - 2010)
|
||||
MAINTENANCE: Maintained
|
||||
STATUS: Working
|
||||
-------------------------------------------------------------------------------
|
||||
EXTENSION: xmlrpc
|
||||
PRIMARY MAINTAINER: Unknown
|
||||
MAINTENANCE: Orphaned
|
||||
STATUS: Experimental
|
||||
-------------------------------------------------------------------------------
|
||||
EXTENSION: xmlwriter
|
||||
PRIMARY MAINTAINER: Rob Richards <rrichards@php.net> (2004 - 2010)
|
||||
Pierre-Alain Joye <pajoye@php.net> (2005-2009)
|
||||
|
||||
@@ -7,15 +7,14 @@
|
||||
7. ext/standard/scanf
|
||||
8. ext/standard/strnatcmp.c
|
||||
9. ext/standard/uuencode
|
||||
10. libxmlrpc ext/xmlrpc
|
||||
11. main/snprintf.c
|
||||
12. main/strlcat
|
||||
13. main/strlcpy
|
||||
14. libgd (ext/gd)
|
||||
15. ext/phar portions of tar implementations
|
||||
16. ext/phar/zip.c portion extracted from libzip
|
||||
17. libbcmath (ext/bcmath) see ext/bcmath/libbcmath/LICENSE
|
||||
18. ext/mbstring/ucgendat portions based on the ucgendat.c from the OpenLDAP
|
||||
10. main/snprintf.c
|
||||
11. main/strlcat
|
||||
12. main/strlcpy
|
||||
13. libgd (ext/gd)
|
||||
14. ext/phar portions of tar implementations
|
||||
15. ext/phar/zip.c portion extracted from libzip
|
||||
16. libbcmath (ext/bcmath) see ext/bcmath/libbcmath/LICENSE
|
||||
17. ext/mbstring/ucgendat portions based on the ucgendat.c from the OpenLDAP
|
||||
|
||||
|
||||
3. pcre2lib (ext/pcre)
|
||||
@@ -355,32 +354,7 @@ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
|
||||
|
||||
10. libxmlrpc ext/xmlrpc
|
||||
|
||||
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.
|
||||
|
||||
|
||||
11. main/snprintf.c
|
||||
10. main/snprintf.c
|
||||
|
||||
Copyright (c) 2002, 2006 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
|
||||
@@ -455,8 +429,8 @@ SIO stdio-replacement strx_* functions by Panos Tsirigotis
|
||||
<panos@alumni.cs.colorado.edu> for xinetd.
|
||||
|
||||
|
||||
12. main/strlcat
|
||||
13. main/strlcpy
|
||||
11. main/strlcat
|
||||
12. main/strlcpy
|
||||
|
||||
Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
All rights reserved.
|
||||
@@ -484,7 +458,7 @@ OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
14. libgd (ext/gd)
|
||||
13. libgd (ext/gd)
|
||||
|
||||
* Portions copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
|
||||
2002, 2003, 2004 by Cold Spring Harbor Laboratory. Funded under
|
||||
@@ -554,7 +528,7 @@ Avenue Software Corporation for their prior contributions.
|
||||
END OF COPYRIGHT STATEMENT
|
||||
|
||||
|
||||
15. ext/phar portions of tar implementations
|
||||
14. ext/phar portions of tar implementations
|
||||
|
||||
portions of tar implementations in ext/phar - phar_tar_octal() are based on an
|
||||
implementation by Tim Kientzle from libarchive, licensed with this license:
|
||||
@@ -583,7 +557,7 @@ implementation by Tim Kientzle from libarchive, licensed with this license:
|
||||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
16. ext/phar/zip.c portion extracted from libzip
|
||||
15. ext/phar/zip.c portion extracted from libzip
|
||||
|
||||
zip_dirent.c -- read directory entry (local or central), clean dirent
|
||||
Copyright (C) 1999, 2003, 2004, 2005 Dieter Baron and Thomas Klausner
|
||||
@@ -617,7 +591,7 @@ OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
18. ext/mbstring/ucgendat portions based on the ucgendat.c from the OpenLDAP
|
||||
16. ext/mbstring/ucgendat portions based on the ucgendat.c from the OpenLDAP
|
||||
|
||||
The OpenLDAP Public License
|
||||
Version 2.8, 17 August 2003
|
||||
|
||||
@@ -29,7 +29,6 @@ steps:
|
||||
--enable-xmlreader \
|
||||
--with-xsl \
|
||||
--with-tidy \
|
||||
--with-xmlrpc \
|
||||
--enable-sysvsem \
|
||||
--enable-sysvshm \
|
||||
--enable-shmop \
|
||||
|
||||
@@ -39,7 +39,6 @@ jobs:
|
||||
--enable-xmlreader \
|
||||
--with-xsl \
|
||||
--with-tidy \
|
||||
--with-xmlrpc \
|
||||
--enable-sysvsem \
|
||||
--enable-sysvshm \
|
||||
--enable-shmop \
|
||||
|
||||
@@ -40,7 +40,6 @@ jobs:
|
||||
--enable-xmlreader \
|
||||
--with-xsl \
|
||||
--with-tidy=/usr/local/opt/tidyp \
|
||||
--with-xmlrpc \
|
||||
--with-libxml \
|
||||
--enable-sysvsem \
|
||||
--enable-sysvshm \
|
||||
|
||||
@@ -14,7 +14,6 @@ LCOV_EXCLUDES = \
|
||||
'$(top_srcdir)/ext/mbstring/libmbfl/*' \
|
||||
'$(top_srcdir)/ext/opcache/jit/libudis86/*' \
|
||||
'$(top_srcdir)/ext/pcre/pcre2lib/*' \
|
||||
'$(top_srcdir)/ext/xmlrpc/libxmlrpc/*' \
|
||||
'$(top_srcdir)/parse_date.re' \
|
||||
'$(top_srcdir)/parse_iso_intervals.re'
|
||||
|
||||
@@ -26,8 +25,7 @@ GCOVR_EXCLUDES = \
|
||||
'ext/hash/sha3/.*' \
|
||||
'ext/mbstring/libmbfl/.*' \
|
||||
'ext/opcache/jit/libudis86/.*' \
|
||||
'ext/pcre/pcre2lib/.*' \
|
||||
'ext/xmlrpc/libxmlrpc/.*'
|
||||
'ext/pcre/pcre2lib/.*'
|
||||
|
||||
lcov: lcov-html
|
||||
|
||||
|
||||
@@ -74,7 +74,6 @@ CREDIT_LINE("tidy", "John Coggeshall, Ilia Alshanetsky");
|
||||
CREDIT_LINE("tokenizer", "Andrei Zmievski, Johannes Schlueter");
|
||||
CREDIT_LINE("XML", "Stig Bakken, Thies C. Arntzen, Sterling Hughes");
|
||||
CREDIT_LINE("XMLReader", "Rob Richards");
|
||||
CREDIT_LINE("xmlrpc", "Dan Libby");
|
||||
CREDIT_LINE("XMLWriter", "Rob Richards, Pierre-Alain Joye");
|
||||
CREDIT_LINE("XSL", "Christian Stocker, Rob Richards");
|
||||
CREDIT_LINE("Zip", "Pierre-Alain Joye, Remi Collet");
|
||||
|
||||
@@ -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 */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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"
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
};
|
||||
@@ -931,7 +931,6 @@ default_socket_timeout = 60
|
||||
;extension=sodium
|
||||
;extension=sqlite3
|
||||
;extension=tidy
|
||||
;extension=xmlrpc
|
||||
;extension=xsl
|
||||
|
||||
;zend_extension=opcache
|
||||
|
||||
@@ -933,7 +933,6 @@ default_socket_timeout = 60
|
||||
;extension=sodium
|
||||
;extension=sqlite3
|
||||
;extension=tidy
|
||||
;extension=xmlrpc
|
||||
;extension=xsl
|
||||
|
||||
;zend_extension=opcache
|
||||
|
||||
@@ -27,7 +27,6 @@ $excludes = [
|
||||
'ext/opcache/jit/vtune',
|
||||
'ext/pcre/pcre2lib/',
|
||||
'ext/standard/html_tables/html_table_gen.php',
|
||||
'ext/xmlrpc/libxmlrpc/',
|
||||
'sapi/cli/php_http_parser.c',
|
||||
'sapi/cli/php_http_parser.h',
|
||||
'sapi/litespeed/',
|
||||
|
||||
@@ -45,7 +45,6 @@ $S390X_CONFIG \
|
||||
--enable-xmlreader \
|
||||
--with-xsl \
|
||||
--with-tidy \
|
||||
--with-xmlrpc \
|
||||
--enable-sysvsem \
|
||||
--enable-sysvshm \
|
||||
--enable-shmop \
|
||||
|
||||
Reference in New Issue
Block a user