mirror of
https://github.com/php/php-src.git
synced 2026-04-17 21:11:02 +02:00
moved to pecl by sascha. remove them from head.
discussed with harald, will remain in pecl till he has some more time to work on it.
This commit is contained in:
@@ -1,2 +0,0 @@
|
||||
Java
|
||||
Sam Ruby
|
||||
@@ -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,97 +0,0 @@
|
||||
what's this ?
|
||||
=============
|
||||
|
||||
This is an abstraction layer that eases the task of writing rpc
|
||||
extensions (e.g. java, com, corba, soap, srm, .net, xml-rpc, ..).
|
||||
it maps the quite complex ZendEngine2 oo api to a few simpler to
|
||||
handle callback functions declared in the 'rpc_object_handlers'
|
||||
struct.
|
||||
|
||||
so what happens behind my back ?
|
||||
================================
|
||||
|
||||
- the abstraction layer takes care of your underlaying data structure
|
||||
and passes it to you each time you have to handle an operation.
|
||||
- it does reference counting and tells you when you have to destruct
|
||||
your underlaying data structure.
|
||||
- it registers a class and four functions (xxx_load, xxx_call, xxx_get,
|
||||
xxx_set) for your rpc layer and checks if the parameters are valid (beside
|
||||
the ones that are optional for your rpc layer).
|
||||
- it silently creates proxies for references to members of your rpc
|
||||
objects.
|
||||
- it optionally does object pooling for objects that support it (has to
|
||||
be defined in the constructor)
|
||||
- it optionally requests hash values for method and property names and
|
||||
caches them. call / get and set requests will then receive the hash value
|
||||
instead of the original function- / propertyname.
|
||||
|
||||
how can i make use of it ?
|
||||
==========================
|
||||
|
||||
take ext/rpc/com/com.c as a starting point. you'll have to set up the following struct:
|
||||
|
||||
typedef struct _rpc_object_handlers {
|
||||
int (*rpc_hash)(char *name, zend_uint name_len, char **hash, zend_uint *hash_len, int type);
|
||||
int hash_type;
|
||||
int (*rpc_ctor)(char *class_name, zend_uint class_name_len, void **data, INTERNAL_FUNCTION_PARAMETERS);
|
||||
int (*rpc_dtor)(void **data);
|
||||
int (*rpc_call)(char *method_name, zend_uint method_name_len, void **data, INTERNAL_FUNCTION_PARAMETERS);
|
||||
int (*rpc_get)(char *property_name, zend_uint property_name_len, zval *return_value, void **data);
|
||||
int (*rpc_set)(char *property_name, zend_uint property_name_len, zval *value, zval *return_value, void **data);
|
||||
int (*rpc_compare)(void **data1, void **data2);
|
||||
int (*rpc_get_classname)(char **class_name, zend_uint *class_name_length, void **data);
|
||||
int (*rpc_has_property)(char *property_name, zend_uint property_name_length, void **data);
|
||||
int (*rpc_unset_property)(char *property_name, zend_uint property_name_length, void **data);
|
||||
int (*rpc_get_properties)(HashTable **properties, void **data);
|
||||
} rpc_object_handlers;
|
||||
|
||||
|
||||
rpc_hash:
|
||||
the hashing function for method and property names. returns a hash value
|
||||
for the string passed in 'name'. 'type' is either METHOD or PROPERTY.
|
||||
if you set 'hash_type' to HASH_AS_INT you can set '*hash' to NULL and pass
|
||||
the hash value as 'hash_len'.
|
||||
rpc_hash can be set to NULL if hashing of method and property names is not
|
||||
appreciated.
|
||||
|
||||
hash_type:
|
||||
either HASH_AS_INT, HASH_AS_STRING or DONT_HASH
|
||||
|
||||
rpc_ctor:
|
||||
the constructor
|
||||
|
||||
rpc_dtor:
|
||||
the destructor
|
||||
|
||||
rpc_call:
|
||||
the call handler
|
||||
|
||||
rpc_get:
|
||||
the get handler
|
||||
|
||||
rpc_set:
|
||||
the set handler
|
||||
|
||||
rpc_compare:
|
||||
the compare handler.
|
||||
rpc_compare can be set to NULL then objects will be treated the same if they
|
||||
belong to the same rpc layer.
|
||||
|
||||
rpc_get_classname:
|
||||
returns the classname.
|
||||
rpc_get_classname can be set to NULL then the name of the rpc layer will be
|
||||
used as classname.
|
||||
|
||||
rpc_has_property:
|
||||
check if a property exists.
|
||||
rpc_has_property can be set to NULL then true will be returned for every request.
|
||||
|
||||
rpc_unset_property:
|
||||
unset a property.
|
||||
rpc_unset_property can be set to NULL, a 'not supported' warning will then be
|
||||
issued.
|
||||
|
||||
rpc_get_properties:
|
||||
returns a HashTable with all the properties.
|
||||
rpc_get_properties can be set to NULL, then a list of the explicit declared
|
||||
properties will be returned.
|
||||
@@ -1,2 +0,0 @@
|
||||
Win32 COM
|
||||
Alan Brown, Wez Furlong, Harald Radi, Zeev Suraski
|
||||
@@ -1,28 +0,0 @@
|
||||
1) Multi-dimenstional array support
|
||||
4) Documentation (internal and user) and howtos
|
||||
5) IEnumVariant::All() which would be like IEnumVariant::Next(IDispatch::Count)
|
||||
7) Test component (goes with the docs)
|
||||
8) Test suite (Needs test component)
|
||||
10) lets try if we are able to call non IDispatch - only Typelib components
|
||||
|
||||
-- delayed till PHP5: 3) WithEvents
|
||||
-- delayed till PHP5: 9) reduce the need for VARIANT()
|
||||
|
||||
ad 6.) check vbsample.php (new VARIANT(*, *|VT_BYREF)) GPs
|
||||
|
||||
-- done 2) IErrorInfo
|
||||
-- done 6) Look for memory leaks and AdRef/Release problems - I KNOW there are some...
|
||||
-- done 11) IEnumVariant::Next() without parameter should only return an object, not an array with one element
|
||||
-- done 12) VARIANT->value as lvalue
|
||||
-- done 13) export VARIANT through the COM module
|
||||
-- done 14) trap exceptions and errors
|
||||
|
||||
-- donne ad 4.) faq (i've collected a few questions from various lists)
|
||||
variant attributes !!
|
||||
|
||||
to be discussed:
|
||||
|
||||
- mts support (getcontext)
|
||||
- adsi support (ads* functions)
|
||||
|
||||
-- delayed till PHP 5: try serialisation support (if component implements IPersist)
|
||||
1362
ext/rpc/com/com.c
1362
ext/rpc/com/com.c
File diff suppressed because it is too large
Load Diff
@@ -1,167 +0,0 @@
|
||||
# Microsoft Developer Studio Project File - Name="com" - Package Owner=<4>
|
||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
||||
# ** DO NOT EDIT **
|
||||
|
||||
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
|
||||
|
||||
CFG=com - Win32 Debug_TS
|
||||
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
||||
!MESSAGE use the Export Makefile command and run
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "com.mak".
|
||||
!MESSAGE
|
||||
!MESSAGE You can specify a configuration when running NMAKE
|
||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "com.mak" CFG="com - Win32 Debug_TS"
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE "com - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
|
||||
!MESSAGE "com - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
|
||||
!MESSAGE "com - Win32 Debug_TS" (based on "Win32 (x86) Dynamic-Link Library")
|
||||
!MESSAGE "com - Win32 Release_TS" (based on "Win32 (x86) Dynamic-Link Library")
|
||||
!MESSAGE
|
||||
|
||||
# Begin Project
|
||||
# PROP AllowPerConfigDependencies 0
|
||||
# PROP Scc_ProjName ""
|
||||
# PROP Scc_LocalPath ""
|
||||
CPP=cl.exe
|
||||
MTL=midl.exe
|
||||
RSC=rc.exe
|
||||
|
||||
!IF "$(CFG)" == "com - Win32 Release"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "..\..\Release"
|
||||
# PROP BASE Intermediate_Dir "Release"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "Release"
|
||||
# PROP Intermediate_Dir "Release"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "PHP_WIN32" /D "ZEND_WIN32" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /YX /FD /c
|
||||
# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\.." /I "..\..\main" /I "..\..\Zend" /I "..\..\..\bindlib_w32" /I "..\..\TSRM" /D "NDEBUG" /D ZEND_DEBUG=0 /D "PHP_WIN32" /D "ZEND_WIN32" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "COMPILE_DL_JAVA" /D HAVE_JAVA=1 /YX /FD /c
|
||||
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||
# ADD BASE RSC /l 0x40d /d "NDEBUG"
|
||||
# ADD RSC /l 0x40d /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"..\..\Release/php_rpc_com.dll" /libpath:"$(JAVA_HOME)\lib" /libpath:"..\..\Release"
|
||||
|
||||
!ELSEIF "$(CFG)" == "com - Win32 Debug"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 1
|
||||
# PROP BASE Output_Dir "..\..\Debug"
|
||||
# PROP BASE Intermediate_Dir "Debug"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 1
|
||||
# PROP Output_Dir "Debug"
|
||||
# PROP Intermediate_Dir "Debug"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "PHP_WIN32" /D "ZEND_WIN32" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /YX /FD /GZ /c
|
||||
# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\.." /I "..\..\main" /I "..\..\Zend" /I "..\..\..\bindlib_w32" /I "..\..\TSRM" /D "_DEBUG" /D ZEND_DEBUG=1 /D "PHP_WIN32" /D "ZEND_WIN32" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "COMPILE_DL_JAVA" /D HAVE_JAVA=1 /FR /YX /FD /GZ /c
|
||||
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||
# ADD BASE RSC /l 0x40d /d "_DEBUG"
|
||||
# ADD RSC /l 0x40d /d "_DEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"..\..\Debug/php_rpc_com.dll" /pdbtype:sept /libpath:"$(JAVA_HOME)\lib" /libpath:"..\..\Debug"
|
||||
|
||||
!ELSEIF "$(CFG)" == "com - Win32 Debug_TS"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 1
|
||||
# PROP BASE Output_Dir "..\..\Debug_TS"
|
||||
# PROP BASE Intermediate_Dir "Debug_TS"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 1
|
||||
# PROP Output_Dir "Debug_TS"
|
||||
# PROP Intermediate_Dir "Debug_TS"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\.." /I "..\..\..\Zend" /I "$(JAVA_HOME)\include\win32" /I "$(JAVA_HOME)\include" /I "..\..\..\bindlib_w32" /D "_DEBUG" /D "PHP_WIN32" /D "ZEND_WIN32" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "COMPILE_DL_JAVA" /FR /YX /FD /GZ /c
|
||||
# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\..\\" /I "..\..\main" /I "..\..\Zend" /I "..\..\..\bindlib_w32" /I "..\..\TSRM" /D "_DEBUG" /D ZEND_DEBUG=1 /D "ZTS" /D "PHP_WIN32" /D "ZEND_WIN32" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /FR /YX /FD /D /GZ /c
|
||||
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||
# ADD BASE RSC /l 0x40d /d "_DEBUG"
|
||||
# ADD RSC /l 0x40d /d "_DEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib php4ts_debug.lib /nologo /dll /debug /machine:I386 /out:"..\..\Debug_TS/php_rpc_com.dll" /pdbtype:sept /libpath:"..\..\Debug_TS"
|
||||
|
||||
!ELSEIF "$(CFG)" == "com - Win32 Release_TS"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "..\..\Release_TS"
|
||||
# PROP BASE Intermediate_Dir "Release_TS"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "Release_TS"
|
||||
# PROP Intermediate_Dir "Release_TS"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /MD /W3 /GX /O2 /I "..\.." /I "..\..\..\Zend" /I "$(JAVA_HOME)\include\win32" /I "$(JAVA_HOME)\include" /I "..\..\..\bindlib_w32" /D "NDEBUG" /D "PHP_WIN32" /D "ZEND_WIN32" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "COMPILE_DL_JAVA" /YX /FD /c
|
||||
# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\..\\" /I "..\..\main" /I "..\..\Zend" /I "..\..\..\bindlib_w32" /I "..\..\TSRM" /D "NDEBUG" /D ZEND_DEBUG=0 /D "ZTS" /D "PHP_WIN32" /D "ZEND_WIN32" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /YX /FD /c
|
||||
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||
# ADD BASE RSC /l 0x40d /d "NDEBUG"
|
||||
# ADD RSC /l 0x40d /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib php4ts.lib /nologo /dll /machine:I386 /out:"..\..\Release_TS/php_rpc_com.dll" /libpath:"..\..\Release_TS" /libpath:"..\..\Release_TS_Inline"
|
||||
|
||||
!ENDIF
|
||||
|
||||
# Begin Target
|
||||
|
||||
# Name "com - Win32 Release"
|
||||
# Name "com - Win32 Debug"
|
||||
# Name "com - Win32 Debug_TS"
|
||||
# Name "com - Win32 Release_TS"
|
||||
# Begin Group "Source Files"
|
||||
|
||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\com.cpp
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Header Files"
|
||||
|
||||
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\php_com.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\README
|
||||
# End Source File
|
||||
# End Target
|
||||
# End Project
|
||||
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 4 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2003 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.0 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_0.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: Harald Radi <h.radi@nme.at> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#ifndef COM_H
|
||||
#define COM_H
|
||||
|
||||
#include "../handler.h"
|
||||
#include "../php_rpc.h"
|
||||
|
||||
#ifndef PHP_COM_DONT_DECLARE_RPC_HANDLER
|
||||
RPC_DECLARE_HANDLER(com);
|
||||
#endif
|
||||
|
||||
ZEND_MINIT_FUNCTION(com);
|
||||
ZEND_MSHUTDOWN_FUNCTION(com);
|
||||
ZEND_MINFO_FUNCTION(com);
|
||||
|
||||
ZEND_FUNCTION(com_addref);
|
||||
ZEND_FUNCTION(com_release);
|
||||
ZEND_FUNCTION(com_isenum);
|
||||
ZEND_FUNCTION(com_next);
|
||||
ZEND_FUNCTION(com_all);
|
||||
ZEND_FUNCTION(com_reset);
|
||||
ZEND_FUNCTION(com_skip);
|
||||
ZEND_FUNCTION(com_event_sink);
|
||||
ZEND_FUNCTION(com_message_pump);
|
||||
ZEND_FUNCTION(com_load_typelib);
|
||||
ZEND_FUNCTION(com_print_typeinfo);
|
||||
|
||||
#endif
|
||||
@@ -1,930 +0,0 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 4 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2003 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.0 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_0.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: Zeev Suraski <zeev@zend.com> |
|
||||
| Harald Radi <h.radi@nme.at> |
|
||||
| Alan Brown <abrown@pobox.com> |
|
||||
| Wez Furlong <wez@thebrainroom.com> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
/* $Id$ */
|
||||
/*
|
||||
* This module implements support for COM components that support the IDispatch
|
||||
* interface. Both local (COM) and remote (DCOM) components can be accessed.
|
||||
*
|
||||
* Type libraries can be loaded (in order for PHP to recognize automation constants)
|
||||
* by specifying a typelib_file in the PHP .ini file. That file should contain
|
||||
* paths to type libraries, one in every line. By default, constants are registered
|
||||
* as case-sensitive. If you want them to be defined as case-insensitive, add
|
||||
* #case_insensitive or #cis at the end of the type library path.
|
||||
*
|
||||
* This is also the first module to demonstrate Zend's OO syntax overloading
|
||||
* capabilities. CORBA coders are invited to write a CORBA module as well!
|
||||
*
|
||||
* Zeev
|
||||
*/
|
||||
|
||||
/*
|
||||
* 28.12.2000
|
||||
* unicode conversion fixed by Harald Radi <h.radi@nme.at>
|
||||
*
|
||||
* now all these strange '?'s should be disapeared
|
||||
*/
|
||||
|
||||
/*
|
||||
* 28.1.2001
|
||||
* VARIANT datatype and pass_by_reference support
|
||||
*/
|
||||
|
||||
/*
|
||||
* 03.6.2001
|
||||
* Enhanced Typelib support to include a search by name
|
||||
*/
|
||||
|
||||
#ifdef PHP_WIN32
|
||||
|
||||
#define _WIN32_DCOM
|
||||
|
||||
#include "php.h"
|
||||
#include "php_ini.h"
|
||||
|
||||
#include <iostream.h>
|
||||
#include <math.h>
|
||||
#include <ocidl.h>
|
||||
|
||||
#include "../rpc.h"
|
||||
#include "../php_rpc.h"
|
||||
#include "../handler.h"
|
||||
|
||||
#include "com.h"
|
||||
#include "com_wrapper.h"
|
||||
#include "conversion.h"
|
||||
#include "variant.h"
|
||||
|
||||
#ifdef _DEBUG
|
||||
int resourcecounter = 1;
|
||||
#endif
|
||||
|
||||
ZEND_API HRESULT php_COM_invoke(comval *obj, DISPID dispIdMember, WORD wFlags,
|
||||
DISPPARAMS FAR* pDispParams, VARIANT FAR* pVarResult, char **ErrString)
|
||||
{
|
||||
HRESULT hr;
|
||||
int failed = FALSE;
|
||||
unsigned int ArgErr = 0;
|
||||
EXCEPINFO ExceptInfo;
|
||||
|
||||
*ErrString = NULL;
|
||||
/* @todo use DispInvoke here ? */
|
||||
if (C_HASTLIB(obj)) {
|
||||
hr = C_TYPEINFO_VT(obj)->Invoke(C_TYPEINFO(obj), C_DISPATCH(obj),
|
||||
dispIdMember, wFlags, pDispParams, pVarResult, &ExceptInfo, &ArgErr);
|
||||
if (FAILED(hr) && (hr != DISP_E_EXCEPTION)) {
|
||||
hr = C_DISPATCH_VT(obj)->Invoke(C_DISPATCH(obj), dispIdMember, &IID_NULL,
|
||||
LOCALE_SYSTEM_DEFAULT, wFlags, pDispParams, pVarResult, &ExceptInfo, &ArgErr);
|
||||
if (SUCCEEDED(hr)) {
|
||||
/*
|
||||
* ITypLib doesn't work
|
||||
* Release ITypeLib and fall back to IDispatch
|
||||
*/
|
||||
|
||||
C_TYPEINFO_VT(obj)->Release(C_TYPEINFO(obj));
|
||||
C_HASTLIB(obj) = FALSE;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
hr = C_DISPATCH_VT(obj)->Invoke(C_DISPATCH(obj), dispIdMember, &IID_NULL,
|
||||
LOCALE_SYSTEM_DEFAULT, wFlags, pDispParams, pVarResult, &ExceptInfo, &ArgErr);
|
||||
}
|
||||
|
||||
if (FAILED(hr)) {
|
||||
switch (hr) {
|
||||
case DISP_E_EXCEPTION: {
|
||||
|
||||
char *src=estrdup("Unavailable");
|
||||
int srclen=strlen(src);
|
||||
char *desc=estrdup("Unavailable");
|
||||
int desclen=strlen(desc);
|
||||
|
||||
if (ExceptInfo.bstrSource)
|
||||
{
|
||||
efree(src);
|
||||
src = php_OLECHAR_to_char(ExceptInfo.bstrSource, &srclen, C_CODEPAGE(obj), FALSE);
|
||||
SysFreeString(ExceptInfo.bstrSource);
|
||||
}
|
||||
if (ExceptInfo.bstrDescription)
|
||||
{
|
||||
efree(desc);
|
||||
desc = php_OLECHAR_to_char(ExceptInfo.bstrDescription, &desclen, C_CODEPAGE(obj), FALSE);
|
||||
SysFreeString(ExceptInfo.bstrDescription);
|
||||
}
|
||||
|
||||
spprintf(ErrString, 0, "<b>Source</b>: %s <b>Description</b>: %s", src, desc);
|
||||
efree(src);
|
||||
efree(desc);
|
||||
|
||||
if (ExceptInfo.bstrHelpFile)
|
||||
{
|
||||
SysFreeString(ExceptInfo.bstrHelpFile);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case DISP_E_PARAMNOTFOUND:
|
||||
case DISP_E_TYPEMISMATCH:
|
||||
spprintf(ErrString, 0, "<b>Argument</b>: %d", pDispParams->cArgs - ArgErr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pVarResult && (V_VT(pVarResult) == VT_EMPTY)) {
|
||||
V_VT(pVarResult) = VT_I4;
|
||||
V_I4(pVarResult) = hr;
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
ZEND_API HRESULT php_COM_get_ids_of_names(comval *obj, OLECHAR FAR* rgszNames, DISPID FAR* rgDispId)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
if (C_HASTLIB(obj)) {
|
||||
hr = C_TYPEINFO_VT(obj)->GetIDsOfNames(C_TYPEINFO(obj), &rgszNames, 1, rgDispId);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
hr = C_DISPATCH_VT(obj)->GetIDsOfNames(C_DISPATCH(obj), &IID_NULL, &rgszNames, 1, LOCALE_SYSTEM_DEFAULT, rgDispId);
|
||||
|
||||
if (SUCCEEDED(hr)) {
|
||||
/*
|
||||
* ITypLib doesn't work
|
||||
* Release ITypeLib and fall back to IDispatch
|
||||
*/
|
||||
|
||||
C_TYPEINFO_VT(obj)->Release(C_TYPEINFO(obj));
|
||||
C_HASTLIB(obj) = FALSE;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
hr = C_DISPATCH_VT(obj)->GetIDsOfNames(C_DISPATCH(obj), &IID_NULL, &rgszNames, 1, LOCALE_SYSTEM_DEFAULT, rgDispId);
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
ZEND_API HRESULT php_COM_release(comval *obj)
|
||||
{
|
||||
return C_DISPATCH_VT(obj)->Release(C_DISPATCH(obj));
|
||||
}
|
||||
|
||||
|
||||
ZEND_API HRESULT php_COM_addref(comval *obj)
|
||||
{
|
||||
return C_DISPATCH_VT(obj)->AddRef(C_DISPATCH(obj));
|
||||
}
|
||||
|
||||
|
||||
ZEND_API HRESULT php_COM_set(comval *obj, IDispatch FAR* FAR* ppDisp, int cleanup)
|
||||
{
|
||||
HRESULT hr = 1;
|
||||
DISPPARAMS dispparams;
|
||||
VARIANT *result;
|
||||
IDispatch FAR* pDisp;
|
||||
|
||||
pDisp = *ppDisp;
|
||||
if (cleanup) {
|
||||
*ppDisp = NULL;
|
||||
}
|
||||
|
||||
C_DISPATCH(obj) = pDisp;
|
||||
C_HASTLIB(obj) = SUCCEEDED(C_DISPATCH_VT(obj)->GetTypeInfo(C_DISPATCH(obj), 0, LANG_NEUTRAL, &C_TYPEINFO(obj)));
|
||||
|
||||
dispparams.rgvarg = NULL;
|
||||
dispparams.rgdispidNamedArgs = NULL;
|
||||
dispparams.cArgs = 0;
|
||||
dispparams.cNamedArgs = 0;
|
||||
|
||||
result = (VARIANT *) emalloc(sizeof(VARIANT));
|
||||
VariantInit(result);
|
||||
|
||||
if (C_HASENUM(obj) = SUCCEEDED(C_DISPATCH_VT(obj)->Invoke(C_DISPATCH(obj), DISPID_NEWENUM, &IID_NULL, LOCALE_SYSTEM_DEFAULT,
|
||||
DISPATCH_METHOD|DISPATCH_PROPERTYGET, &dispparams, result, NULL, NULL))) {
|
||||
if (V_VT(result) == VT_UNKNOWN) {
|
||||
V_UNKNOWN(result)->lpVtbl->AddRef(V_UNKNOWN(result));
|
||||
C_HASENUM(obj) = SUCCEEDED(V_UNKNOWN(result)->lpVtbl->QueryInterface(V_UNKNOWN(result), &IID_IEnumVARIANT,
|
||||
(void**)&C_ENUMVARIANT(obj)));
|
||||
} else if (V_VT(result) == VT_DISPATCH) {
|
||||
V_DISPATCH(result)->lpVtbl->AddRef(V_DISPATCH(result));
|
||||
C_HASENUM(obj) = SUCCEEDED(V_DISPATCH(result)->lpVtbl->QueryInterface(V_DISPATCH(result), &IID_IEnumVARIANT,
|
||||
(void**)&C_ENUMVARIANT(obj)));
|
||||
}
|
||||
}
|
||||
|
||||
efree(result);
|
||||
|
||||
if (!cleanup) {
|
||||
hr = C_DISPATCH_VT(obj)->AddRef(C_DISPATCH(obj));
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
obj->resourceindex = resourcecounter++;
|
||||
#endif
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
ZEND_API char *php_COM_error_message(HRESULT hr)
|
||||
{
|
||||
void *pMsgBuf = NULL;
|
||||
|
||||
if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL,
|
||||
hr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &pMsgBuf, 0, NULL)) {
|
||||
char error_string[] = "No description available";
|
||||
|
||||
pMsgBuf = LocalAlloc(LMEM_FIXED, sizeof(error_string));
|
||||
memcpy(pMsgBuf, error_string, sizeof(error_string));
|
||||
}
|
||||
|
||||
return pMsgBuf;
|
||||
}
|
||||
|
||||
|
||||
ZEND_API char *php_COM_string_from_CLSID(const CLSID *clsid)
|
||||
{
|
||||
LPOLESTR ole_clsid;
|
||||
char *clsid_str;
|
||||
|
||||
StringFromCLSID(clsid, &ole_clsid);
|
||||
clsid_str = php_OLECHAR_to_char(ole_clsid, NULL, CP_ACP, FALSE);
|
||||
CoTaskMemFree(ole_clsid);
|
||||
|
||||
return clsid_str;
|
||||
}
|
||||
|
||||
|
||||
ZEND_API HRESULT php_COM_destruct(comval *obj)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
php_COM_enable_events(obj, FALSE);
|
||||
if (obj->sinkdispatch)
|
||||
obj->sinkdispatch->lpVtbl->Release(obj->sinkdispatch);
|
||||
|
||||
if (C_HASTLIB(obj)) {
|
||||
C_TYPEINFO_VT(obj)->Release(C_TYPEINFO(obj));
|
||||
}
|
||||
if (C_HASENUM(obj)) {
|
||||
C_ENUMVARIANT_VT(obj)->Release(C_ENUMVARIANT(obj));
|
||||
}
|
||||
|
||||
if (C_DISPATCH(obj)) {
|
||||
hr = C_DISPATCH_VT(obj)->Release(C_DISPATCH(obj));
|
||||
}
|
||||
efree(obj);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* {{{ proto bool com_message_pump([int timeoutms])
|
||||
Process COM messages, sleeping for up to timeoutms milliseconds */
|
||||
PHP_FUNCTION(com_message_pump)
|
||||
{
|
||||
long timeoutms = 0;
|
||||
MSG msg;
|
||||
DWORD result;
|
||||
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &timeoutms) == FAILURE)
|
||||
RETURN_FALSE;
|
||||
|
||||
result = MsgWaitForMultipleObjects(0, NULL, FALSE, timeoutms, QS_ALLINPUT);
|
||||
|
||||
if (result == WAIT_OBJECT_0) {
|
||||
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
/* we processed messages */
|
||||
RETVAL_TRUE;
|
||||
} else {
|
||||
/* we did not process messages (timed out) */
|
||||
RETVAL_FALSE;
|
||||
}
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
ZEND_API HRESULT php_COM_enable_events(comval *obj, int enable)
|
||||
{
|
||||
if (obj->sinkdispatch) {
|
||||
IConnectionPointContainer *cont;
|
||||
IConnectionPoint *point;
|
||||
|
||||
if (SUCCEEDED(C_DISPATCH_VT(obj)->QueryInterface(C_DISPATCH(obj), &IID_IConnectionPointContainer, (void**)&cont))) {
|
||||
if (SUCCEEDED(cont->lpVtbl->FindConnectionPoint(cont, &obj->sinkid, &point))) {
|
||||
if (enable) {
|
||||
point->lpVtbl->Advise(point, (IUnknown*)obj->sinkdispatch, &obj->sinkcookie);
|
||||
} else {
|
||||
point->lpVtbl->Unadvise(point, obj->sinkcookie);
|
||||
}
|
||||
point->lpVtbl->Release(point);
|
||||
}
|
||||
cont->lpVtbl->Release(cont);
|
||||
}
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static const struct {
|
||||
VARTYPE vt;
|
||||
const char *name;
|
||||
} vt_names[] = {
|
||||
{ VT_NULL, "VT_NULL" },
|
||||
{ VT_EMPTY, "VT_EMPTY" },
|
||||
{ VT_UI1, "VT_UI1" },
|
||||
{ VT_I2, "VT_I2" },
|
||||
{ VT_I4, "VT_I4" },
|
||||
{ VT_R4, "VT_R4" },
|
||||
{ VT_R8, "VT_R8" },
|
||||
{ VT_BOOL, "VT_BOOL" },
|
||||
{ VT_ERROR, "VT_ERROR" },
|
||||
{ VT_CY, "VT_CY" },
|
||||
{ VT_DATE, "VT_DATE" },
|
||||
{ VT_BSTR, "VT_BSTR" },
|
||||
{ VT_DECIMAL, "VT_DECIMAL" },
|
||||
{ VT_UNKNOWN, "VT_UNKNOWN" },
|
||||
{ VT_DISPATCH, "VT_DISPATCH" },
|
||||
{ VT_VARIANT, "VT_VARIANT" },
|
||||
{ VT_I1, "VT_I1" },
|
||||
{ VT_UI2, "VT_UI2" },
|
||||
{ VT_UI4, "VT_UI4" },
|
||||
{ VT_INT, "VT_INT" },
|
||||
{ VT_UINT, "VT_UINT" },
|
||||
{ VT_ARRAY, "VT_ARRAY" },
|
||||
{ VT_BYREF, "VT_BYREF" },
|
||||
{ VT_VOID, "VT_VOID" },
|
||||
{ VT_PTR, "VT_PTR" },
|
||||
{ VT_HRESULT, "VT_HRESULT" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
static inline const char *vt_to_string(VARTYPE vt)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; vt_names[i].name != NULL; i++) {
|
||||
if (vt_names[i].vt == vt)
|
||||
return vt_names[i].name;
|
||||
}
|
||||
return "?";
|
||||
}
|
||||
|
||||
ZEND_API int php_COM_process_typeinfo(ITypeInfo *typeinfo, HashTable *id_to_name, int printdef, GUID *guid)
|
||||
{
|
||||
TYPEATTR *attr;
|
||||
FUNCDESC *func;
|
||||
int i;
|
||||
OLECHAR *olename;
|
||||
char *ansiname = NULL;
|
||||
unsigned int ansinamelen;
|
||||
int ret = 0;
|
||||
|
||||
if (FAILED(typeinfo->lpVtbl->GetTypeAttr(typeinfo, &attr)))
|
||||
return 0;
|
||||
|
||||
/* verify that it is suitable */
|
||||
if (id_to_name == NULL || attr->typekind == TKIND_DISPATCH) {
|
||||
|
||||
if (guid)
|
||||
memcpy(guid, &attr->guid, sizeof(GUID));
|
||||
|
||||
if (printdef) {
|
||||
char *guidstring;
|
||||
|
||||
typeinfo->lpVtbl->GetDocumentation(typeinfo, MEMBERID_NIL, &olename, NULL, NULL, NULL);
|
||||
ansiname = php_OLECHAR_to_char(olename, &ansinamelen, CP_ACP, FALSE);
|
||||
SysFreeString(olename);
|
||||
|
||||
guidstring = php_COM_string_from_CLSID(&attr->guid);
|
||||
php_printf("class %s { /* GUID=%s */\n", ansiname, guidstring);
|
||||
efree(guidstring);
|
||||
|
||||
efree(ansiname);
|
||||
}
|
||||
|
||||
if (id_to_name)
|
||||
zend_hash_init(id_to_name, 0, NULL, ZVAL_PTR_DTOR, 0);
|
||||
|
||||
/* So we've got the dispatch interface; lets list the event methods */
|
||||
for (i = 0; i < attr->cFuncs; i++) {
|
||||
zval *tmp;
|
||||
DISPID lastid = 0; /* for props */
|
||||
int isprop;
|
||||
|
||||
if (FAILED(typeinfo->lpVtbl->GetFuncDesc(typeinfo, i, &func)))
|
||||
break;
|
||||
|
||||
isprop = (func->invkind & DISPATCH_PROPERTYGET || func->invkind & DISPATCH_PROPERTYPUT);
|
||||
|
||||
if (!isprop || lastid != func->memid) {
|
||||
|
||||
lastid = func->memid;
|
||||
|
||||
typeinfo->lpVtbl->GetDocumentation(typeinfo, func->memid, &olename, NULL, NULL, NULL);
|
||||
ansiname = php_OLECHAR_to_char(olename, &ansinamelen, CP_ACP, FALSE);
|
||||
SysFreeString(olename);
|
||||
|
||||
if (printdef) {
|
||||
int j;
|
||||
char *funcdesc;
|
||||
unsigned int funcdesclen, cnames = 0;
|
||||
BSTR *names;
|
||||
|
||||
names = (BSTR*)emalloc((func->cParams + 1) * sizeof(BSTR));
|
||||
|
||||
typeinfo->lpVtbl->GetNames(typeinfo, func->memid, names, func->cParams + 1, &cnames);
|
||||
/* first element is the function name */
|
||||
SysFreeString(names[0]);
|
||||
|
||||
php_printf("\t/* DISPID=%d */\n", func->memid);
|
||||
|
||||
if (func->elemdescFunc.tdesc.vt != VT_VOID) {
|
||||
php_printf("\t/* %s [%d] */\n",
|
||||
vt_to_string(func->elemdescFunc.tdesc.vt),
|
||||
func->elemdescFunc.tdesc.vt
|
||||
);
|
||||
}
|
||||
|
||||
if (isprop) {
|
||||
|
||||
typeinfo->lpVtbl->GetDocumentation(typeinfo, func->memid, NULL, &olename, NULL, NULL);
|
||||
if (olename) {
|
||||
funcdesc = php_OLECHAR_to_char(olename, &funcdesclen, CP_ACP, FALSE);
|
||||
SysFreeString(olename);
|
||||
php_printf("\t/* %s */\n", funcdesc);
|
||||
efree(funcdesc);
|
||||
}
|
||||
|
||||
php_printf("\tvar $%s;\n\n", ansiname);
|
||||
|
||||
} else {
|
||||
/* a function */
|
||||
|
||||
php_printf("\tfunction %s(\n", ansiname);
|
||||
|
||||
for (j = 0; j < func->cParams; j++) {
|
||||
ELEMDESC *elem = &func->lprgelemdescParam[j];
|
||||
|
||||
php_printf("\t\t/* %s [%d] ", vt_to_string(elem->tdesc.vt), elem->tdesc.vt);
|
||||
|
||||
if (elem->paramdesc.wParamFlags & PARAMFLAG_FIN)
|
||||
php_printf("[in]");
|
||||
if (elem->paramdesc.wParamFlags & PARAMFLAG_FOUT)
|
||||
php_printf("[out]");
|
||||
|
||||
if (elem->tdesc.vt == VT_PTR) {
|
||||
/* what does it point to ? */
|
||||
php_printf(" --> %s [%d] ",
|
||||
vt_to_string(elem->tdesc.lptdesc->vt),
|
||||
elem->tdesc.lptdesc->vt
|
||||
);
|
||||
}
|
||||
|
||||
/* when we handle prop put and get, this will look nicer */
|
||||
if (j+1 < (int)cnames) {
|
||||
funcdesc = php_OLECHAR_to_char(names[j+1], &funcdesclen, CP_ACP, FALSE);
|
||||
SysFreeString(names[j+1]);
|
||||
} else {
|
||||
funcdesc = "???";
|
||||
}
|
||||
|
||||
php_printf(" */ %s%s%c\n",
|
||||
elem->tdesc.vt == VT_PTR ? "&$" : "$",
|
||||
funcdesc,
|
||||
j == func->cParams - 1 ? ' ' : ','
|
||||
);
|
||||
|
||||
if (j+1 < (int)cnames)
|
||||
efree(funcdesc);
|
||||
}
|
||||
|
||||
php_printf("\t\t)\n\t{\n");
|
||||
|
||||
typeinfo->lpVtbl->GetDocumentation(typeinfo, func->memid, NULL, &olename, NULL, NULL);
|
||||
if (olename) {
|
||||
funcdesc = php_OLECHAR_to_char(olename, &funcdesclen, CP_ACP, FALSE);
|
||||
SysFreeString(olename);
|
||||
php_printf("\t\t/* %s */\n", funcdesc);
|
||||
efree(funcdesc);
|
||||
}
|
||||
|
||||
php_printf("\t}\n");
|
||||
}
|
||||
|
||||
efree(names);
|
||||
}
|
||||
|
||||
if (id_to_name) {
|
||||
zend_str_tolower(ansiname, ansinamelen);
|
||||
MAKE_STD_ZVAL(tmp);
|
||||
ZVAL_STRINGL(tmp, ansiname, ansinamelen, 0);
|
||||
zend_hash_index_update(id_to_name, func->memid, (void*)&tmp, sizeof(zval *), NULL);
|
||||
}
|
||||
}
|
||||
typeinfo->lpVtbl->ReleaseFuncDesc(typeinfo, func);
|
||||
|
||||
}
|
||||
|
||||
if (printdef)
|
||||
php_printf("}\n");
|
||||
|
||||
ret = 1;
|
||||
} else {
|
||||
zend_error(E_WARNING, "That's not a dispatchable interface!! type kind = %08x", attr->typekind);
|
||||
}
|
||||
|
||||
typeinfo->lpVtbl->ReleaseTypeAttr(typeinfo, attr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
ZEND_API ITypeInfo *php_COM_locate_typeinfo(char *typelibname, comval *obj, char *dispname, int sink)
|
||||
{
|
||||
ITypeInfo *typeinfo = NULL;
|
||||
ITypeLib *typelib = NULL;
|
||||
int gotguid = 0;
|
||||
GUID iid;
|
||||
|
||||
if (obj) {
|
||||
if (dispname == NULL && sink) {
|
||||
IProvideClassInfo2 *pci2;
|
||||
IProvideClassInfo *pci;
|
||||
|
||||
if (SUCCEEDED(C_DISPATCH_VT(obj)->QueryInterface(C_DISPATCH(obj), &IID_IProvideClassInfo2, (void**)&pci2))) {
|
||||
gotguid = SUCCEEDED(pci2->lpVtbl->GetGUID(pci2, GUIDKIND_DEFAULT_SOURCE_DISP_IID, &iid));
|
||||
pci2->lpVtbl->Release(pci2);
|
||||
}
|
||||
if (!gotguid && SUCCEEDED(C_DISPATCH_VT(obj)->QueryInterface(C_DISPATCH(obj), &IID_IProvideClassInfo, (void**)&pci))) {
|
||||
/* examine the available interfaces */
|
||||
/* TODO: write some code here */
|
||||
pci->lpVtbl->Release(pci);
|
||||
}
|
||||
} else if (dispname && C_HASTLIB(obj)) {
|
||||
unsigned int idx;
|
||||
/* get the library from the object; the rest will be dealt with later */
|
||||
C_TYPEINFO_VT(obj)->GetContainingTypeLib(C_TYPEINFO(obj), &typelib, &idx);
|
||||
} else if (typelibname == NULL) {
|
||||
C_DISPATCH_VT(obj)->GetTypeInfo(C_DISPATCH(obj), 0, LANG_NEUTRAL, &typeinfo);
|
||||
}
|
||||
} else if (typelibname) {
|
||||
/* Fetch the typelibrary and use that to look things up */
|
||||
typelib = php_COM_find_typelib(typelibname, CONST_CS);
|
||||
}
|
||||
|
||||
if (!gotguid && dispname && typelib) {
|
||||
unsigned short cfound;
|
||||
MEMBERID memid;
|
||||
OLECHAR *olename = php_char_to_OLECHAR(dispname, strlen(dispname), CP_ACP, FALSE);
|
||||
|
||||
cfound = 1;
|
||||
if (FAILED(typelib->lpVtbl->FindName(typelib, olename, 0, &typeinfo, &memid, &cfound)) || cfound == 0) {
|
||||
CLSID coclass;
|
||||
ITypeInfo *coinfo;
|
||||
|
||||
/* assume that it might be a progid instead */
|
||||
if (SUCCEEDED(CLSIDFromProgID(olename, &coclass)) &&
|
||||
SUCCEEDED(typelib->lpVtbl->GetTypeInfoOfGuid(typelib, &coclass, &coinfo))) {
|
||||
|
||||
/* enumerate implemented interfaces and pick the one as indicated by sink */
|
||||
TYPEATTR *attr;
|
||||
int i;
|
||||
|
||||
coinfo->lpVtbl->GetTypeAttr(coinfo, &attr);
|
||||
|
||||
for (i = 0; i < attr->cImplTypes; i++) {
|
||||
HREFTYPE rt;
|
||||
int tf;
|
||||
|
||||
if (FAILED(coinfo->lpVtbl->GetImplTypeFlags(coinfo, i, &tf)))
|
||||
continue;
|
||||
|
||||
if ((sink && tf == (IMPLTYPEFLAG_FSOURCE|IMPLTYPEFLAG_FDEFAULT)) ||
|
||||
(!sink && (tf & IMPLTYPEFLAG_FSOURCE) == 0)) {
|
||||
|
||||
/* flags match what we are looking for */
|
||||
|
||||
if (SUCCEEDED(coinfo->lpVtbl->GetRefTypeOfImplType(coinfo, i, &rt)))
|
||||
if (SUCCEEDED(coinfo->lpVtbl->GetRefTypeInfo(coinfo, rt, &typeinfo)))
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
coinfo->lpVtbl->ReleaseTypeAttr(coinfo, attr);
|
||||
coinfo->lpVtbl->Release(coinfo);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
efree(olename);
|
||||
} else if (gotguid) {
|
||||
typelib->lpVtbl->GetTypeInfoOfGuid(typelib, &iid, &typeinfo);
|
||||
}
|
||||
|
||||
if (typelib)
|
||||
typelib->lpVtbl->Release(typelib);
|
||||
|
||||
return typeinfo;
|
||||
}
|
||||
|
||||
static ITypeLib *php_COM_find_typelib(char *search_string, int mode)
|
||||
{
|
||||
ITypeLib *TypeLib = NULL;
|
||||
char *strtok_buf, *major, *minor;
|
||||
CLSID clsid;
|
||||
OLECHAR *p;
|
||||
|
||||
/* Type Libraries:
|
||||
* The string we have is either:
|
||||
* a) a file name
|
||||
* b) a CLSID, major, minor e.g. "{00000200-0000-0010-8000-00AA006D2EA4},2,0"
|
||||
* c) a Type Library name e.g. "Microsoft OLE DB ActiveX Data Objects 1.0 Library"
|
||||
* Searching for the name will be more expensive that the
|
||||
* other two, so we will do that when both other attempts
|
||||
* fail.
|
||||
*/
|
||||
|
||||
search_string = php_strtok_r(search_string, ",", &strtok_buf);
|
||||
|
||||
if (search_string == NULL)
|
||||
return NULL;
|
||||
|
||||
major = php_strtok_r(NULL, ",", &strtok_buf);
|
||||
minor = php_strtok_r(NULL, ",", &strtok_buf);
|
||||
|
||||
p = php_char_to_OLECHAR(search_string, strlen(search_string), CP_ACP, FALSE);
|
||||
/* Is the string a GUID ? */
|
||||
|
||||
if (!FAILED(CLSIDFromString(p, &clsid))) {
|
||||
HRESULT hr;
|
||||
WORD major_i = 1;
|
||||
WORD minor_i = 0;
|
||||
|
||||
/* We have a valid GUID, check to see if a major/minor */
|
||||
/* version was specified otherwise assume 1,0 */
|
||||
if ((major != NULL) && (minor != NULL)) {
|
||||
major_i = (WORD) atoi(major);
|
||||
minor_i = (WORD) atoi(minor);
|
||||
}
|
||||
|
||||
/* The GUID will either be a typelibrary or a CLSID */
|
||||
hr = LoadRegTypeLib((REFGUID) &clsid, major_i, minor_i, LANG_NEUTRAL, &TypeLib);
|
||||
|
||||
/* If the LoadRegTypeLib fails, let's try to instantiate */
|
||||
/* the class itself and then QI for the TypeInfo and */
|
||||
/* retrieve the type info from that interface */
|
||||
if (FAILED(hr) && (!major || !minor)) {
|
||||
IDispatch *Dispatch;
|
||||
ITypeInfo *TypeInfo;
|
||||
int idx;
|
||||
|
||||
if (FAILED(CoCreateInstance(&clsid, NULL, CLSCTX_SERVER, &IID_IDispatch, (LPVOID *) &Dispatch))) {
|
||||
efree(p);
|
||||
return NULL;
|
||||
}
|
||||
if (FAILED(Dispatch->lpVtbl->GetTypeInfo(Dispatch, 0, LANG_NEUTRAL, &TypeInfo))) {
|
||||
Dispatch->lpVtbl->Release(Dispatch);
|
||||
efree(p);
|
||||
return NULL;
|
||||
}
|
||||
Dispatch->lpVtbl->Release(Dispatch);
|
||||
if (FAILED(TypeInfo->lpVtbl->GetContainingTypeLib(TypeInfo, &TypeLib, &idx))) {
|
||||
TypeInfo->lpVtbl->Release(TypeInfo);
|
||||
efree(p);
|
||||
return NULL;
|
||||
}
|
||||
TypeInfo->lpVtbl->Release(TypeInfo);
|
||||
}
|
||||
} else {
|
||||
if (FAILED(LoadTypeLib(p, &TypeLib))) {
|
||||
/* Walk HKCR/TypeLib looking for the string */
|
||||
/* If that succeeds, call ourself recursively */
|
||||
/* using the CLSID found, else give up and bail */
|
||||
HKEY hkey, hsubkey;
|
||||
DWORD SubKeys, MaxSubKeyLength;
|
||||
char *keyname;
|
||||
register unsigned int ii, jj;
|
||||
DWORD VersionCount;
|
||||
char version[20]; /* All the version keys are 1.0, 4.6, ... */
|
||||
char *libname;
|
||||
DWORD libnamelen;
|
||||
|
||||
/* No Need for Unicode version any more */
|
||||
efree(p);
|
||||
|
||||
/* Starting at HKEY_CLASSES_ROOT/TypeLib */
|
||||
/* Walk all subkeys (Typelib GUIDs) looking */
|
||||
/* at each version for a string match to the */
|
||||
/* supplied argument */
|
||||
|
||||
if (ERROR_SUCCESS != RegOpenKey(HKEY_CLASSES_ROOT, "TypeLib",&hkey)) {
|
||||
/* This is pretty bad - better bail */
|
||||
return NULL;
|
||||
}
|
||||
if (ERROR_SUCCESS != RegQueryInfoKey(hkey, NULL, NULL, NULL, &SubKeys, &MaxSubKeyLength, NULL, NULL, NULL, NULL, NULL, NULL)) {
|
||||
RegCloseKey(hkey);
|
||||
return NULL;
|
||||
}
|
||||
MaxSubKeyLength++; /* \0 is not counted */
|
||||
keyname = emalloc(MaxSubKeyLength);
|
||||
libname = emalloc(strlen(search_string)+1);
|
||||
for (ii=0;ii<SubKeys;ii++) {
|
||||
if (ERROR_SUCCESS != RegEnumKey(hkey, ii, keyname, MaxSubKeyLength)) {
|
||||
/* Failed - who cares */
|
||||
continue;
|
||||
}
|
||||
if (ERROR_SUCCESS != RegOpenKey(hkey, keyname, &hsubkey)) {
|
||||
/* Failed - who cares */
|
||||
continue;
|
||||
}
|
||||
if (ERROR_SUCCESS != RegQueryInfoKey(hsubkey, NULL, NULL, NULL, &VersionCount, NULL, NULL, NULL, NULL, NULL, NULL, NULL)) {
|
||||
/* Failed - who cares */
|
||||
RegCloseKey(hsubkey);
|
||||
continue;
|
||||
}
|
||||
for (jj=0;jj<VersionCount;jj++) {
|
||||
if (ERROR_SUCCESS != RegEnumKey(hsubkey, jj, version, sizeof(version))) {
|
||||
/* Failed - who cares */
|
||||
continue;
|
||||
}
|
||||
/* OK we just need to retrieve the default */
|
||||
/* value for this key and see if it matches */
|
||||
libnamelen = strlen(search_string)+1;
|
||||
if (ERROR_SUCCESS == RegQueryValue(hsubkey, version, libname, &libnamelen)) {
|
||||
if ((mode & CONST_CS) ? (strcmp(libname, search_string) == 0) : (stricmp(libname, search_string) == 0)) {
|
||||
char *str;
|
||||
int major, minor;
|
||||
|
||||
/* Found it */
|
||||
RegCloseKey(hkey);
|
||||
RegCloseKey(hsubkey);
|
||||
|
||||
efree(libname);
|
||||
/* We can either open up the "win32" key and find the DLL name */
|
||||
/* Or just parse the version string and pass that in */
|
||||
/* The version string seems like a more portable solution */
|
||||
/* Given that there is a COM on Unix */
|
||||
if (2 != sscanf(version, "%d.%d", &major, &minor)) {
|
||||
major = 1;
|
||||
minor = 0;
|
||||
}
|
||||
str = emalloc(strlen(keyname)+strlen(version)+20); /* 18 == safety, 2 == extra comma and \0 */
|
||||
sprintf(str, "%s,%d,%d", keyname, major, minor);
|
||||
efree(keyname);
|
||||
TypeLib = php_COM_find_typelib(str, mode);
|
||||
efree(str);
|
||||
/* This is probbaly much harder to read and follow */
|
||||
/* But it is MUCH more effiecient than trying to */
|
||||
/* test for errors and leave through a single "return" */
|
||||
return TypeLib;
|
||||
}
|
||||
} else {
|
||||
/* Failed - perhaps too small abuffer */
|
||||
/* But if too small, then the name does not match */
|
||||
}
|
||||
}
|
||||
RegCloseKey(hsubkey);
|
||||
}
|
||||
efree(keyname);
|
||||
efree(libname);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
efree(p);
|
||||
return TypeLib;
|
||||
}
|
||||
|
||||
|
||||
ZEND_API int php_COM_load_typelib(ITypeLib *TypeLib, int mode)
|
||||
{
|
||||
ITypeComp *TypeComp;
|
||||
int i;
|
||||
int interfaces;
|
||||
TSRMLS_FETCH();
|
||||
|
||||
if (NULL == TypeLib) {
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
interfaces = TypeLib->lpVtbl->GetTypeInfoCount(TypeLib);
|
||||
|
||||
TypeLib->lpVtbl->GetTypeComp(TypeLib, &TypeComp);
|
||||
for (i=0; i<interfaces; i++) {
|
||||
TYPEKIND pTKind;
|
||||
|
||||
TypeLib->lpVtbl->GetTypeInfoType(TypeLib, i, &pTKind);
|
||||
if (pTKind==TKIND_ENUM) {
|
||||
ITypeInfo *TypeInfo;
|
||||
VARDESC *pVarDesc;
|
||||
UINT NameCount;
|
||||
int j;
|
||||
BSTR bstr_EnumId;
|
||||
char *EnumId;
|
||||
|
||||
TypeLib->lpVtbl->GetDocumentation(TypeLib, i, &bstr_EnumId, NULL, NULL, NULL);
|
||||
EnumId = php_OLECHAR_to_char(bstr_EnumId, NULL, CP_ACP, FALSE);
|
||||
printf("Enumeration %d - %s:\n", i, EnumId);
|
||||
efree(EnumId);
|
||||
|
||||
TypeLib->lpVtbl->GetTypeInfo(TypeLib, i, &TypeInfo);
|
||||
|
||||
j=0;
|
||||
while (SUCCEEDED(TypeInfo->lpVtbl->GetVarDesc(TypeInfo, j, &pVarDesc))) {
|
||||
BSTR bstr_ids;
|
||||
zend_constant c;
|
||||
zval exists, results, value;
|
||||
char *const_name;
|
||||
|
||||
TypeInfo->lpVtbl->GetNames(TypeInfo, pVarDesc->memid, &bstr_ids, 1, &NameCount);
|
||||
if (NameCount!=1) {
|
||||
j++;
|
||||
continue;
|
||||
}
|
||||
const_name = php_OLECHAR_to_char(bstr_ids, &c.name_len, CP_ACP, FALSE);
|
||||
c.name = zend_strndup(const_name, c.name_len);
|
||||
efree(const_name);
|
||||
c.name_len++; /* length should include the NULL */
|
||||
SysFreeString(bstr_ids);
|
||||
|
||||
/* Before registering the contsnt, let's see if we can find it */
|
||||
if (zend_get_constant(c.name, c.name_len-1, &exists TSRMLS_CC)) {
|
||||
/* Oops, it already exists. No problem if it is defined as the same value */
|
||||
/* Check to see if they are the same */
|
||||
if (!compare_function(&results, &c.value, &exists TSRMLS_CC) && INI_INT("com.autoregister_verbose")) {
|
||||
rpc_error(E_WARNING, "Type library value %s is already defined and has a different value", c.name);
|
||||
}
|
||||
free(c.name);
|
||||
j++;
|
||||
continue;
|
||||
}
|
||||
|
||||
php_variant_to_zval(pVarDesc->lpvarValue, &value, CP_ACP);
|
||||
/* we only import enumerations (=int) */
|
||||
if (Z_TYPE(value) == IS_LONG) {
|
||||
c.flags = mode;
|
||||
c.value.type = IS_LONG;
|
||||
c.value.value.lval = Z_LVAL(value);
|
||||
c.module_number = 0; /* the module number is not available here */
|
||||
|
||||
zend_register_constant(&c TSRMLS_CC);
|
||||
}
|
||||
|
||||
j++;
|
||||
}
|
||||
TypeInfo->lpVtbl->Release(TypeInfo);
|
||||
}
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/* create an overloaded COM object from a dispatch pointer */
|
||||
PHPAPI zval *php_COM_object_from_dispatch(IDispatch *disp)
|
||||
{
|
||||
comval *obj;
|
||||
|
||||
ALLOC_COM(obj);
|
||||
php_COM_set(obj, &disp, FALSE);
|
||||
|
||||
return rpc_object_from_data(com, obj);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* tab-width: 4
|
||||
* c-basic-offset: 4
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,107 +0,0 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 4 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2003 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.0 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_0.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: Zeev Suraski <zeev@zend.com> |
|
||||
| Harald Radi <h.radi@nme.at> |
|
||||
| Alan Brown <abrown@pobox.com> |
|
||||
| Wez Furlong <wez@thebrainroom.com> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#ifndef COM_WRAPPER_H
|
||||
#define COM_WRAPPER_H
|
||||
|
||||
#if PHP_WIN32
|
||||
|
||||
BEGIN_EXTERN_C()
|
||||
|
||||
typedef struct comval_ {
|
||||
BOOL typelib;
|
||||
BOOL enumeration;
|
||||
int refcount;
|
||||
int codepage;
|
||||
struct {
|
||||
IDispatch *dispatch;
|
||||
ITypeInfo *typeinfo;
|
||||
IEnumVARIANT *enumvariant;
|
||||
} i;
|
||||
|
||||
#if 1
|
||||
IDispatch *sinkdispatch;
|
||||
GUID sinkid;
|
||||
DWORD sinkcookie;
|
||||
#endif
|
||||
|
||||
#ifdef _DEBUG
|
||||
int resourceindex;
|
||||
#endif
|
||||
|
||||
} comval;
|
||||
|
||||
ZEND_API HRESULT php_COM_invoke(comval *obj, DISPID dispIdMember, WORD wFlags, DISPPARAMS FAR* pDispParams, VARIANT FAR* pVarResult, char **ErrString);
|
||||
ZEND_API HRESULT php_COM_get_ids_of_names(comval *obj, OLECHAR FAR* rgszNames, DISPID FAR* rgDispId);
|
||||
ZEND_API HRESULT php_COM_release(comval *obj);
|
||||
ZEND_API HRESULT php_COM_addref(comval *obj);
|
||||
ZEND_API HRESULT php_COM_destruct(comval *obj);
|
||||
ZEND_API HRESULT php_COM_set(comval *obj, IDispatch FAR* FAR* pDisp, int cleanup);
|
||||
ZEND_API HRESULT php_COM_enable_events(comval *obj, int enable);
|
||||
|
||||
ZEND_API char* php_COM_string_from_CLSID(const CLSID *clsid);
|
||||
ZEND_API char* php_COM_error_message(HRESULT hr);
|
||||
ZEND_API int php_COM_load_typelib(ITypeLib *TypeLib, int mode);
|
||||
ZEND_API int php_COM_process_typeinfo(ITypeInfo *typeinfo, HashTable *id_to_name, int printdef, GUID *guid);
|
||||
ZEND_API ITypeInfo* php_COM_locate_typeinfo(char *typelibname, comval *obj, char *dispname, int sink);
|
||||
ZEND_API ITypeLib* php_COM_find_typelib(char *search_string, int mode);
|
||||
|
||||
ZEND_API IDispatch* php_COM_export_as_sink(zval *val, GUID *sinkid, HashTable *id_to_name);
|
||||
ZEND_API IDispatch* php_COM_export_object(zval *val);
|
||||
ZEND_API zval* php_COM_object_from_dispatch(IDispatch *disp);
|
||||
|
||||
END_EXTERN_C()
|
||||
|
||||
#define ZVAL_COM(z,o) { \
|
||||
rpc_internal *intern; \
|
||||
Z_TYPE_P(z) = IS_OBJECT; \
|
||||
(z)->value.obj = rpc_objects_new(com_class_entry TSRMLS_CC); \
|
||||
if (GET_INTERNAL_EX(intern, (z)) != SUCCESS) { \
|
||||
/* TODO: exception */ \
|
||||
} \
|
||||
intern->data = (o); \
|
||||
}
|
||||
|
||||
#define RETVAL_COM(o) ZVAL_COM(&return_value, o);
|
||||
#define RETURN_COM(o) RETVAL_COM(o) \
|
||||
return;
|
||||
|
||||
#define ALLOC_COM(z) (z) = (comval *) ecalloc(1, sizeof(comval)); \
|
||||
C_CODEPAGE(z) = CP_ACP;
|
||||
|
||||
#define FREE_COM(z) php_COM_destruct(z);
|
||||
|
||||
#define C_CODEPAGE(x) ((x)->codepage)
|
||||
|
||||
#define C_HASTLIB(x) ((x)->typelib)
|
||||
#define C_HASENUM(x) ((x)->enumeration)
|
||||
|
||||
#define C_DISPATCH(x) ((x)->i.dispatch)
|
||||
#define C_TYPEINFO(x) ((x)->i.typeinfo)
|
||||
#define C_ENUMVARIANT(x) ((x)->i.enumvariant)
|
||||
|
||||
#define C_DISPATCH_VT(x) (C_DISPATCH(x)->lpVtbl)
|
||||
#define C_TYPEINFO_VT(x) (C_TYPEINFO(x)->lpVtbl)
|
||||
#define C_ENUMVARIANT_VT(x) (C_ENUMVARIANT(x)->lpVtbl)
|
||||
|
||||
#endif /* PHP_WIN32 */
|
||||
|
||||
#endif /* COM_H */
|
||||
@@ -1,855 +0,0 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 4 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2003 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.0 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_0.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: Harald Radi <h.radi@nme.at> |
|
||||
| Alan Brown <abrown@pobox.com> |
|
||||
| Paul Shortis <pshortis@dataworx.com.au> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
/*
|
||||
* 03.6.2001
|
||||
* Added SafeArray ==> Hash support
|
||||
*/
|
||||
|
||||
/*
|
||||
* Paul Shortis June 7, 2001 <pshortis@dataworx.com.au> - Added code to support SafeArray passing
|
||||
* to COM objects. Support includes passing arrays of variants as well
|
||||
* as typed arrays.
|
||||
*/
|
||||
|
||||
#ifdef PHP_WIN32
|
||||
|
||||
#define ZEND_INCLUDE_FULL_WINDOWS_HEADERS
|
||||
|
||||
#include "php.h"
|
||||
|
||||
#include "../rpc.h"
|
||||
#include "../handler.h"
|
||||
|
||||
#include "com.h"
|
||||
#include "com_wrapper.h"
|
||||
#include "conversion.h"
|
||||
#include "variant.h"
|
||||
|
||||
/* prototypes */
|
||||
|
||||
static int comval_to_variant(zval *zval_arg, VARIANT *var_arg);
|
||||
|
||||
/* implementations */
|
||||
PHPAPI void php_zval_to_variant(zval *zval_arg, VARIANT *var_arg, int codepage TSRMLS_DC)
|
||||
{
|
||||
int type = VT_EMPTY; /* default variant type */
|
||||
|
||||
switch (Z_TYPE_P(zval_arg)) {
|
||||
case IS_NULL:
|
||||
type = VT_NULL;
|
||||
break;
|
||||
|
||||
case IS_BOOL:
|
||||
type = VT_BOOL;
|
||||
break;
|
||||
|
||||
case IS_OBJECT:
|
||||
if (!strcmp(Z_OBJCE_P(zval_arg)->name, "VARIANT")) {
|
||||
type = VT_VARIANT|VT_BYREF;
|
||||
} else {
|
||||
type = VT_DISPATCH;
|
||||
}
|
||||
break;
|
||||
|
||||
case IS_ARRAY:
|
||||
type = VT_ARRAY;
|
||||
break;
|
||||
|
||||
case IS_RESOURCE:
|
||||
case IS_CONSTANT:
|
||||
case IS_CONSTANT_ARRAY:
|
||||
/* ?? */
|
||||
break;
|
||||
|
||||
case IS_LONG:
|
||||
type = VT_I4; /* assuming 32-bit platform */
|
||||
break;
|
||||
|
||||
case IS_DOUBLE:
|
||||
type = VT_R8; /* assuming 64-bit double precision */
|
||||
break;
|
||||
|
||||
case IS_STRING:
|
||||
type = VT_BSTR;
|
||||
break;
|
||||
}
|
||||
|
||||
php_zval_to_variant_ex(zval_arg, var_arg, type, codepage TSRMLS_CC);
|
||||
}
|
||||
|
||||
|
||||
PHPAPI void php_zval_to_variant_ex(zval *zval_arg, VARIANT *var_arg, int type, int codepage TSRMLS_DC)
|
||||
{
|
||||
OLECHAR *unicode_str = NULL;
|
||||
|
||||
VariantInit(var_arg);
|
||||
V_VT(var_arg) = type;
|
||||
|
||||
if (V_VT(var_arg) & VT_ARRAY) {
|
||||
/* For now we'll just handle single dimension arrays, we'll use the data type of the first element for the
|
||||
output data type */
|
||||
HashTable *ht = Z_ARRVAL(*zval_arg);
|
||||
int numberOfElements = zend_hash_num_elements(ht);
|
||||
SAFEARRAY *safeArray;
|
||||
SAFEARRAYBOUND bounds[1];
|
||||
VARIANT *v;
|
||||
zval **entry; /* An entry in the input array */
|
||||
|
||||
type &= ~VT_ARRAY;
|
||||
|
||||
if (V_VT(var_arg) == (VT_ARRAY|VT_BYREF)) { /* == is intended, because VT_*|VT_BYREF|VT_ARRAY means something diffrent */
|
||||
type &= ~VT_BYREF;
|
||||
V_VARIANTREF(var_arg) = (VARIANT *) emalloc(sizeof(VARIANT));
|
||||
var_arg = V_VARIANTREF(var_arg); /* put the array in that VARIANT */
|
||||
}
|
||||
|
||||
bounds[0].lLbound = 0;
|
||||
bounds[0].cElements = numberOfElements;
|
||||
safeArray = SafeArrayCreate(VT_VARIANT, 1, bounds);
|
||||
|
||||
if (NULL == safeArray) {
|
||||
rpc_error(E_WARNING, "Unable to convert php array to VARIANT array - %s", numberOfElements ? "" : "(Empty input array)");
|
||||
ZVAL_FALSE(zval_arg);
|
||||
} else {
|
||||
V_ARRAY(var_arg) = safeArray;
|
||||
V_VT(var_arg) = VT_ARRAY|VT_VARIANT; /* Now have a valid safe array allocated */
|
||||
if (SUCCEEDED(SafeArrayLock(safeArray))) {
|
||||
ulong i;
|
||||
|
||||
zend_hash_internal_pointer_reset(ht);
|
||||
for (i = 0; i < (ulong)numberOfElements; ++i) {
|
||||
if ((zend_hash_get_current_data(ht, (void **)&entry) == SUCCESS) && (entry != NULL)) { /* Get a pointer to the php array element */
|
||||
/* Add another value to the safe array */
|
||||
if (SUCCEEDED(SafeArrayPtrOfIndex( safeArray, &i, &v))) { /* Pointer to output element entry retrieved successfully */
|
||||
if (type) { /* explicit type */
|
||||
php_zval_to_variant_ex(*entry, v, type, codepage TSRMLS_CC); /* Do the required conversion */
|
||||
} else {
|
||||
php_zval_to_variant(*entry, v, codepage TSRMLS_CC); /* Do the required conversion */
|
||||
}
|
||||
} else {
|
||||
rpc_error(E_WARNING, "phpArrayToSafeArray() - Unable to retrieve pointer to output element number (%d)", i);
|
||||
}
|
||||
}
|
||||
zend_hash_move_forward(ht);
|
||||
}
|
||||
SafeArrayUnlock( safeArray);
|
||||
} else {
|
||||
rpc_error(E_WARNING, "phpArrayToSafeArray() - Unable to lock safeArray");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
switch (V_VT(var_arg)) {
|
||||
|
||||
case VT_NULL:
|
||||
case VT_VOID:
|
||||
ZVAL_NULL(zval_arg);
|
||||
break;
|
||||
|
||||
case VT_UI1:
|
||||
convert_to_long_ex(&zval_arg);
|
||||
V_UI1(var_arg) = (unsigned char) Z_LVAL_P(zval_arg);
|
||||
break;
|
||||
|
||||
case VT_I2:
|
||||
convert_to_long_ex(&zval_arg);
|
||||
V_I2(var_arg) = (short) Z_LVAL_P(zval_arg);
|
||||
break;
|
||||
|
||||
case VT_I4:
|
||||
convert_to_long_ex(&zval_arg);
|
||||
V_I4(var_arg) = Z_LVAL_P(zval_arg);
|
||||
break;
|
||||
|
||||
case VT_R4:
|
||||
convert_to_double_ex(&zval_arg);
|
||||
V_R4(var_arg) = (float) Z_DVAL_P(zval_arg);
|
||||
break;
|
||||
|
||||
case VT_R8:
|
||||
convert_to_double_ex(&zval_arg);
|
||||
V_R8(var_arg) = Z_DVAL_P(zval_arg);
|
||||
break;
|
||||
|
||||
case VT_BOOL:
|
||||
convert_to_boolean_ex(&zval_arg);
|
||||
if (Z_LVAL_P(zval_arg)) {
|
||||
V_BOOL(var_arg) = VT_TRUE;
|
||||
} else {
|
||||
V_BOOL(var_arg) = VT_FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
case VT_ERROR:
|
||||
convert_to_long_ex(&zval_arg);
|
||||
V_ERROR(var_arg) = Z_LVAL_P(zval_arg);
|
||||
break;
|
||||
|
||||
case VT_CY:
|
||||
convert_to_double_ex(&zval_arg);
|
||||
VarCyFromR8(Z_DVAL_P(zval_arg), &V_CY(var_arg));
|
||||
break;
|
||||
|
||||
case VT_DATE: {
|
||||
SYSTEMTIME wintime;
|
||||
struct tm *phptime;
|
||||
|
||||
switch (Z_TYPE_P(zval_arg)) {
|
||||
case IS_DOUBLE:
|
||||
/* already a VariantTime value */
|
||||
V_DATE(var_arg) = Z_DVAL_P(zval_arg);
|
||||
break;
|
||||
|
||||
/** @todo
|
||||
case IS_STRING:
|
||||
*/
|
||||
/* string representation of a time value */
|
||||
|
||||
default:
|
||||
/* a PHP time value ? */
|
||||
convert_to_long_ex(&zval_arg);
|
||||
phptime = gmtime(&(Z_LVAL_P(zval_arg)));
|
||||
memset(&wintime, 0, sizeof(wintime));
|
||||
|
||||
wintime.wYear = phptime->tm_year + 1900;
|
||||
wintime.wMonth = phptime->tm_mon + 1;
|
||||
wintime.wDay = phptime->tm_mday;
|
||||
wintime.wHour = phptime->tm_hour;
|
||||
wintime.wMinute = phptime->tm_min;
|
||||
wintime.wSecond = phptime->tm_sec;
|
||||
|
||||
SystemTimeToVariantTime(&wintime, &V_DATE(var_arg));
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case VT_BSTR:
|
||||
convert_to_string_ex(&zval_arg);
|
||||
unicode_str = php_char_to_OLECHAR(Z_STRVAL_P(zval_arg), Z_STRLEN_P(zval_arg), codepage, FALSE);
|
||||
V_BSTR(var_arg) = SysAllocStringByteLen((char *) unicode_str, Z_STRLEN_P(zval_arg) * sizeof(OLECHAR));
|
||||
break;
|
||||
|
||||
case VT_DECIMAL:
|
||||
convert_to_string_ex(&zval_arg);
|
||||
unicode_str = php_char_to_OLECHAR(Z_STRVAL_P(zval_arg), Z_STRLEN_P(zval_arg), codepage, FALSE);
|
||||
VarDecFromStr(unicode_str, LOCALE_SYSTEM_DEFAULT, 0, &V_DECIMAL(var_arg));
|
||||
break;
|
||||
|
||||
case VT_DECIMAL|VT_BYREF:
|
||||
convert_to_string_ex(&zval_arg);
|
||||
unicode_str = php_char_to_OLECHAR(Z_STRVAL_P(zval_arg), Z_STRLEN_P(zval_arg), codepage, FALSE);
|
||||
VarDecFromStr(unicode_str, LOCALE_SYSTEM_DEFAULT, 0, V_DECIMALREF(var_arg));
|
||||
break;
|
||||
|
||||
case VT_UNKNOWN:
|
||||
if (comval_to_variant(zval_arg, var_arg) == SUCCESS) {
|
||||
V_VT(var_arg) = VT_UNKNOWN;
|
||||
V_UNKNOWN(var_arg) = (IUnknown *) V_DISPATCH(var_arg);
|
||||
}
|
||||
break;
|
||||
|
||||
case VT_DISPATCH:
|
||||
if (Z_OBJCE_P(zval_arg) == com_class_entry) {
|
||||
comval_to_variant(zval_arg, var_arg);
|
||||
} else {
|
||||
V_DISPATCH(var_arg) = php_COM_export_object(zval_arg);
|
||||
|
||||
if (V_DISPATCH(var_arg)) {
|
||||
V_VT(var_arg) = VT_DISPATCH;
|
||||
}
|
||||
}
|
||||
if (V_VT(var_arg) != VT_DISPATCH) {
|
||||
VariantInit(var_arg);
|
||||
}
|
||||
break;
|
||||
|
||||
case VT_UI1|VT_BYREF:
|
||||
convert_to_long(zval_arg);
|
||||
V_UI1REF(var_arg) = (unsigned char FAR*) &Z_LVAL_P(zval_arg);
|
||||
break;
|
||||
|
||||
case VT_I2|VT_BYREF:
|
||||
convert_to_long(zval_arg);
|
||||
V_I2REF(var_arg) = (short FAR*) &Z_LVAL_P(zval_arg);
|
||||
break;
|
||||
|
||||
case VT_I4|VT_BYREF:
|
||||
convert_to_long(zval_arg);
|
||||
V_I4REF(var_arg) = (long FAR*) &Z_LVAL_P(zval_arg);
|
||||
break;
|
||||
|
||||
case VT_R4|VT_BYREF:
|
||||
convert_to_double(zval_arg);
|
||||
V_R4REF(var_arg) = (float FAR*) &Z_LVAL_P(zval_arg);
|
||||
break;
|
||||
|
||||
case VT_R8|VT_BYREF:
|
||||
convert_to_double(zval_arg);
|
||||
V_R8REF(var_arg) = (double FAR*) &Z_LVAL_P(zval_arg);
|
||||
break;
|
||||
|
||||
case VT_BOOL|VT_BYREF:
|
||||
convert_to_boolean(zval_arg);
|
||||
/* emalloc or malloc ? */
|
||||
V_BOOLREF(var_arg) = (short FAR*) pemalloc(sizeof(short), 1);
|
||||
if (Z_LVAL_P(zval_arg)) {
|
||||
*V_BOOLREF(var_arg) = VT_TRUE;
|
||||
} else {
|
||||
*V_BOOLREF(var_arg) = VT_FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
case VT_ERROR|VT_BYREF:
|
||||
convert_to_long(zval_arg);
|
||||
V_ERRORREF(var_arg) = (long FAR*) &Z_LVAL_P(zval_arg);
|
||||
break;
|
||||
|
||||
case VT_CY|VT_BYREF:
|
||||
convert_to_double_ex(&zval_arg);
|
||||
VarCyFromR8(Z_DVAL_P(zval_arg), var_arg->pcyVal);
|
||||
break;
|
||||
|
||||
case VT_DATE|VT_BYREF: {
|
||||
SYSTEMTIME wintime;
|
||||
struct tm *phptime;
|
||||
|
||||
phptime = gmtime(&(Z_LVAL_P(zval_arg)));
|
||||
memset(&wintime, 0, sizeof(wintime));
|
||||
|
||||
wintime.wYear = phptime->tm_year + 1900;
|
||||
wintime.wMonth = phptime->tm_mon + 1;
|
||||
wintime.wDay = phptime->tm_mday;
|
||||
wintime.wHour = phptime->tm_hour;
|
||||
wintime.wMinute = phptime->tm_min;
|
||||
wintime.wSecond = phptime->tm_sec;
|
||||
|
||||
SystemTimeToVariantTime(&wintime, var_arg->pdate);
|
||||
}
|
||||
break;
|
||||
|
||||
case VT_BSTR|VT_BYREF:
|
||||
convert_to_string(zval_arg);
|
||||
V_BSTRREF(var_arg) = (BSTR FAR*) emalloc(sizeof(BSTR FAR*));
|
||||
unicode_str = php_char_to_OLECHAR(Z_STRVAL_P(zval_arg), Z_STRLEN_P(zval_arg), codepage, FALSE);
|
||||
*V_BSTRREF(var_arg) = SysAllocString(unicode_str);
|
||||
break;
|
||||
|
||||
case VT_UNKNOWN|VT_BYREF:
|
||||
if (comval_to_variant(zval_arg, var_arg) == SUCCESS) {
|
||||
V_VT(var_arg) = VT_UNKNOWN|VT_BYREF;
|
||||
V_UNKNOWNREF(var_arg) = (IUnknown **) &V_DISPATCH(var_arg);
|
||||
}
|
||||
break;
|
||||
|
||||
case VT_DISPATCH|VT_BYREF:
|
||||
if (comval_to_variant(zval_arg, var_arg) == SUCCESS) {
|
||||
V_VT(var_arg) = VT_DISPATCH|VT_BYREF;
|
||||
V_DISPATCHREF(var_arg) = &V_DISPATCH(var_arg);
|
||||
}
|
||||
break;
|
||||
|
||||
case VT_VARIANT:
|
||||
rpc_error(E_WARNING, "VT_VARIANT is invalid. Use VT_VARIANT|VT_BYREF instead.");
|
||||
/* break missing intentionally */
|
||||
case VT_VARIANT|VT_BYREF: {
|
||||
variantval *var;
|
||||
TSRMLS_FETCH();
|
||||
|
||||
if ((var = zend_object_store_get_object(zval_arg TSRMLS_CC)) == NULL) {
|
||||
/* TODO exception */
|
||||
}
|
||||
|
||||
V_VARIANTREF(var_arg) = var->var;
|
||||
}
|
||||
break;
|
||||
|
||||
case VT_I1:
|
||||
convert_to_long_ex(&zval_arg);
|
||||
V_I1(var_arg) = (char)Z_LVAL_P(zval_arg);
|
||||
break;
|
||||
|
||||
case VT_UI2:
|
||||
convert_to_long_ex(&zval_arg);
|
||||
V_UI2(var_arg) = (unsigned short)Z_LVAL_P(zval_arg);
|
||||
break;
|
||||
|
||||
case VT_UI4:
|
||||
convert_to_long_ex(&zval_arg);
|
||||
V_UI4(var_arg) = (unsigned long)Z_LVAL_P(zval_arg);
|
||||
break;
|
||||
|
||||
case VT_INT:
|
||||
convert_to_long_ex(&zval_arg);
|
||||
V_INT(var_arg) = (int)Z_LVAL_P(zval_arg);
|
||||
break;
|
||||
|
||||
case VT_UINT:
|
||||
convert_to_long_ex(&zval_arg);
|
||||
V_UINT(var_arg) = (unsigned int)Z_LVAL_P(zval_arg);
|
||||
break;
|
||||
|
||||
case VT_I1|VT_BYREF:
|
||||
convert_to_long(zval_arg);
|
||||
V_I1REF(var_arg) = (char FAR*) &Z_LVAL_P(zval_arg);
|
||||
break;
|
||||
|
||||
case VT_UI2|VT_BYREF:
|
||||
convert_to_long(zval_arg);
|
||||
V_UI2REF(var_arg) = (unsigned short FAR*) &Z_LVAL_P(zval_arg);
|
||||
break;
|
||||
|
||||
case VT_UI4|VT_BYREF:
|
||||
convert_to_long(zval_arg);
|
||||
V_UI4REF(var_arg) = (unsigned long FAR*) &Z_LVAL_P(zval_arg);
|
||||
break;
|
||||
|
||||
case VT_INT|VT_BYREF:
|
||||
convert_to_long(zval_arg);
|
||||
V_INTREF(var_arg) = (int FAR*) &Z_LVAL_P(zval_arg);
|
||||
break;
|
||||
|
||||
case VT_UINT|VT_BYREF:
|
||||
convert_to_long(zval_arg);
|
||||
V_UINTREF(var_arg) = (unsigned int FAR*) &Z_LVAL_P(zval_arg);
|
||||
break;
|
||||
|
||||
default:
|
||||
rpc_error(E_WARNING, "Unsupported variant type: %d (0x%X)", V_VT(var_arg), V_VT(var_arg));
|
||||
}
|
||||
|
||||
if (unicode_str != NULL) {
|
||||
efree(unicode_str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PHPAPI int php_variant_to_zval(VARIANT *var_arg, zval *zval_arg, int codepage)
|
||||
{
|
||||
/* Changed the function to return a value for recursive error testing */
|
||||
/* Existing calls will be unaffected by the change - so it */
|
||||
/* seemed like the smallest impact on unfamiliar code */
|
||||
int ret = SUCCESS;
|
||||
|
||||
INIT_PZVAL(zval_arg);
|
||||
|
||||
/* Add SafeArray support */
|
||||
if (V_ISARRAY(var_arg)) {
|
||||
SAFEARRAY *array = V_ARRAY(var_arg);
|
||||
LONG indices[1];
|
||||
LONG lbound=0, ubound;
|
||||
VARTYPE vartype;
|
||||
register int ii;
|
||||
UINT Dims;
|
||||
VARIANT vv;
|
||||
zval *element;
|
||||
HRESULT hr;
|
||||
|
||||
/* TODO: Add support for multi-dimensional SafeArrays */
|
||||
/* For now just validate that the SafeArray has one dimension */
|
||||
if (1 != (Dims = SafeArrayGetDim(array))) {
|
||||
rpc_error(E_WARNING, "Unsupported: multi-dimensional (%d) SafeArrays", Dims);
|
||||
ZVAL_NULL(zval_arg);
|
||||
return FAILURE;
|
||||
}
|
||||
SafeArrayLock(array);
|
||||
|
||||
/* This call has failed for everything I have tried */
|
||||
/* But best leave it to be on the safe side */
|
||||
if (FAILED(SafeArrayGetVartype(array, &vartype)) || (vartype == VT_EMPTY)) {
|
||||
/* Fall back to what we do know */
|
||||
/* Mask off the array bit and assume */
|
||||
/* what is left is the type of the array */
|
||||
/* elements */
|
||||
vartype = V_VT(var_arg) & ~VT_ARRAY;
|
||||
}
|
||||
SafeArrayGetUBound(array, 1, &ubound);
|
||||
SafeArrayGetLBound(array, 1, &lbound);
|
||||
|
||||
/* Since COM returned an array we set up the php */
|
||||
/* return value to be an array */
|
||||
array_init(zval_arg);
|
||||
|
||||
/* Walk the safe array */
|
||||
for (ii=lbound;ii<=ubound;ii++) {
|
||||
indices[0] = ii;
|
||||
VariantInit(&vv); /* Docs say this just set the vt field, but you never know */
|
||||
/* Set up a variant to pass to a recursive call */
|
||||
/* So that we do not need to have two copies */
|
||||
/* of the code */
|
||||
if (VT_VARIANT == vartype) {
|
||||
hr = SafeArrayGetElement(array, indices, (VOID *) &(vv));
|
||||
} else {
|
||||
V_VT(&vv) = vartype;
|
||||
hr = SafeArrayGetElement(array, indices, (VOID *) &(vv.lVal));
|
||||
}
|
||||
if (FAILED(hr)) {
|
||||
/* Failure to retieve an element probably means the array is sparse */
|
||||
/* So leave the php array sparse too */
|
||||
continue;
|
||||
}
|
||||
/* Create an element to be added to the array */
|
||||
ALLOC_ZVAL(element);
|
||||
/* Call ourself again to handle the base type conversion */
|
||||
/* If SafeArrayGetElement proclaims to allocate */
|
||||
/* memory for a BSTR, so the recursive call frees */
|
||||
/* the string correctly */
|
||||
if (FAILURE == php_variant_to_zval(&vv, element, codepage)) {
|
||||
/* Error occurred setting up array element */
|
||||
/* Error was displayed by the recursive call */
|
||||
FREE_ZVAL(element);
|
||||
/* TODO: Do we stop here, or go on and */
|
||||
/* try to make sense of the rest of the array */
|
||||
/* Going on leads to multiple errors displayed */
|
||||
/* for the same conversion. For large arrays that */
|
||||
/* could be very annoying */
|
||||
/* And if we don't go on - what to do about */
|
||||
/* the parts of the array that are OK? */
|
||||
/* break; */
|
||||
} else {
|
||||
/* Just insert the element into our return array */
|
||||
add_index_zval(zval_arg, ii, element);
|
||||
}
|
||||
}
|
||||
SafeArrayUnlock(array);
|
||||
} else switch (var_arg->vt & ~VT_BYREF) {
|
||||
case VT_EMPTY:
|
||||
ZVAL_NULL(zval_arg);
|
||||
break;
|
||||
|
||||
case VT_UI1:
|
||||
if (V_ISBYREF(var_arg)) {
|
||||
ZVAL_LONG(zval_arg, (long)*V_UI1REF(var_arg));
|
||||
} else {
|
||||
ZVAL_LONG(zval_arg, (long)V_UI1(var_arg));
|
||||
}
|
||||
break;
|
||||
|
||||
case VT_I2:
|
||||
if (V_ISBYREF(var_arg)) {
|
||||
ZVAL_LONG(zval_arg, (long )*V_I2REF(var_arg));
|
||||
} else {
|
||||
ZVAL_LONG(zval_arg, (long)V_I2(var_arg));
|
||||
}
|
||||
break;
|
||||
|
||||
case VT_I4:
|
||||
if (V_ISBYREF(var_arg)) {
|
||||
ZVAL_LONG(zval_arg, *V_I4REF(var_arg));
|
||||
} else {
|
||||
ZVAL_LONG(zval_arg, V_I4(var_arg));
|
||||
}
|
||||
break;
|
||||
|
||||
case VT_R4:
|
||||
if (V_ISBYREF(var_arg)) {
|
||||
ZVAL_DOUBLE(zval_arg, (double)*V_R4REF(var_arg));
|
||||
} else {
|
||||
ZVAL_DOUBLE(zval_arg, (double)V_R4(var_arg));
|
||||
}
|
||||
break;
|
||||
|
||||
case VT_R8:
|
||||
if (V_ISBYREF(var_arg)) {
|
||||
ZVAL_DOUBLE(zval_arg, *V_R8REF(var_arg));
|
||||
} else {
|
||||
ZVAL_DOUBLE(zval_arg, V_R8(var_arg));
|
||||
}
|
||||
break;
|
||||
|
||||
/* 96bit uint */
|
||||
case VT_DECIMAL: {
|
||||
OLECHAR *unicode_str;
|
||||
switch (VarBstrFromDec(&V_DECIMAL(var_arg), LOCALE_SYSTEM_DEFAULT, 0, &unicode_str)) {
|
||||
case S_OK:
|
||||
Z_STRVAL_P(zval_arg) = php_OLECHAR_to_char(unicode_str, &Z_STRLEN_P(zval_arg), codepage, FALSE);
|
||||
Z_TYPE_P(zval_arg) = IS_STRING;
|
||||
break;
|
||||
|
||||
default:
|
||||
ZVAL_NULL(zval_arg);
|
||||
ret = FAILURE;
|
||||
rpc_error(E_WARNING, "Error converting DECIMAL value to PHP string");
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
/* Currency */
|
||||
case VT_CY:
|
||||
if (V_ISBYREF(var_arg)) {
|
||||
VarR8FromCy(*V_CYREF(var_arg), &Z_DVAL_P(zval_arg));
|
||||
} else {
|
||||
VarR8FromCy(V_CY(var_arg), &Z_DVAL_P(zval_arg));
|
||||
}
|
||||
Z_TYPE_P(zval_arg) = IS_DOUBLE;
|
||||
break;
|
||||
|
||||
case VT_BOOL:
|
||||
if (V_ISBYREF(var_arg)) {
|
||||
if (*V_BOOLREF(var_arg)) {
|
||||
ZVAL_BOOL(zval_arg, Z_TRUE);
|
||||
} else {
|
||||
ZVAL_BOOL(zval_arg, Z_FALSE);
|
||||
}
|
||||
} else {
|
||||
if (V_BOOL(var_arg)) {
|
||||
ZVAL_BOOL(zval_arg, Z_TRUE);
|
||||
} else {
|
||||
ZVAL_BOOL(zval_arg, Z_FALSE);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case VT_NULL:
|
||||
case VT_VOID:
|
||||
ZVAL_NULL(zval_arg);
|
||||
break;
|
||||
|
||||
case VT_VARIANT:
|
||||
php_variant_to_zval(V_VARIANTREF(var_arg), zval_arg, codepage);
|
||||
break;
|
||||
|
||||
case VT_BSTR:
|
||||
Z_TYPE_P(zval_arg) = IS_STRING;
|
||||
|
||||
if (V_ISBYREF(var_arg)) {
|
||||
if (*V_BSTR(var_arg)) {
|
||||
Z_STRVAL_P(zval_arg) = php_OLECHAR_to_char(*V_BSTRREF(var_arg), &Z_STRLEN_P(zval_arg), codepage, FALSE);
|
||||
} else {
|
||||
ZVAL_NULL(zval_arg);
|
||||
}
|
||||
efree(V_BSTRREF(var_arg));
|
||||
} else {
|
||||
if (V_BSTR(var_arg)) {
|
||||
Z_STRVAL_P(zval_arg) = php_OLECHAR_to_char(V_BSTR(var_arg), &Z_STRLEN_P(zval_arg), codepage, FALSE);
|
||||
} else {
|
||||
ZVAL_NULL(zval_arg);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case VT_DATE: {
|
||||
BOOL success;
|
||||
SYSTEMTIME wintime;
|
||||
struct tm phptime;
|
||||
|
||||
if (V_ISBYREF(var_arg)) {
|
||||
success = VariantTimeToSystemTime(*V_DATEREF(var_arg), &wintime);
|
||||
} else {
|
||||
success = VariantTimeToSystemTime(V_DATE(var_arg), &wintime);
|
||||
}
|
||||
|
||||
if (success) {
|
||||
memset(&phptime, 0, sizeof(phptime));
|
||||
|
||||
phptime.tm_year = wintime.wYear - 1900;
|
||||
phptime.tm_mon = wintime.wMonth - 1;
|
||||
phptime.tm_mday = wintime.wDay;
|
||||
phptime.tm_hour = wintime.wHour;
|
||||
phptime.tm_min = wintime.wMinute;
|
||||
phptime.tm_sec = wintime.wSecond;
|
||||
phptime.tm_isdst = -1;
|
||||
|
||||
tzset();
|
||||
ZVAL_LONG(zval_arg, mktime(&phptime));
|
||||
} else {
|
||||
ret = FAILURE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case VT_UNKNOWN:
|
||||
if (V_UNKNOWN(var_arg) == NULL) {
|
||||
V_DISPATCH(var_arg) = NULL;
|
||||
} else {
|
||||
HRESULT hr;
|
||||
|
||||
hr = V_UNKNOWN(var_arg)->lpVtbl->QueryInterface(var_arg->punkVal, &IID_IDispatch, &V_DISPATCH(var_arg));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
char *error_message;
|
||||
|
||||
error_message = php_COM_error_message(hr);
|
||||
rpc_error(E_WARNING, "Unable to obtain IDispatch interface: %s", error_message);
|
||||
LocalFree(error_message);
|
||||
|
||||
V_DISPATCH(var_arg) = NULL;
|
||||
}
|
||||
}
|
||||
/* break missing intentionaly */
|
||||
case VT_DISPATCH: {
|
||||
comval *obj;
|
||||
|
||||
if (V_DISPATCH(var_arg) == NULL) {
|
||||
ret = FAILURE;
|
||||
ZVAL_NULL(zval_arg);
|
||||
} else {
|
||||
TSRMLS_FETCH();
|
||||
|
||||
ALLOC_COM(obj);
|
||||
php_COM_set(obj, &V_DISPATCH(var_arg), FALSE);
|
||||
|
||||
ZVAL_COM(zval_arg, obj);
|
||||
VariantInit(var_arg); /* to protect C_DISPATCH(obj) from being freed when var_result is destructed */
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case VT_I1:
|
||||
if (V_ISBYREF(var_arg)) {
|
||||
ZVAL_LONG(zval_arg, (long)*V_I1REF(var_arg));
|
||||
} else {
|
||||
ZVAL_LONG(zval_arg, (long)V_I1(var_arg));
|
||||
}
|
||||
break;
|
||||
|
||||
case VT_UI2:
|
||||
if (V_ISBYREF(var_arg)) {
|
||||
ZVAL_LONG(zval_arg, (long)*V_UI2REF(var_arg));
|
||||
} else {
|
||||
ZVAL_LONG(zval_arg, (long)V_UI2(var_arg));
|
||||
}
|
||||
break;
|
||||
|
||||
case VT_UI4:
|
||||
if (V_ISBYREF(var_arg)) {
|
||||
ZVAL_LONG(zval_arg, (long)*V_UI4REF(var_arg));
|
||||
} else {
|
||||
ZVAL_LONG(zval_arg, (long)V_UI4(var_arg));
|
||||
}
|
||||
break;
|
||||
|
||||
case VT_INT:
|
||||
if (V_ISBYREF(var_arg)) {
|
||||
ZVAL_LONG(zval_arg, (long)*V_INTREF(var_arg));
|
||||
} else {
|
||||
ZVAL_LONG(zval_arg, (long)V_INT(var_arg));
|
||||
}
|
||||
break;
|
||||
|
||||
case VT_UINT:
|
||||
if (V_ISBYREF(var_arg)) {
|
||||
ZVAL_LONG(zval_arg, (long)*V_UINTREF(var_arg));
|
||||
} else {
|
||||
ZVAL_LONG(zval_arg, (long)V_UINT(var_arg));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
rpc_error(E_WARNING, "Unsupported variant type: %d (0x%X)", V_VT(var_arg), V_VT(var_arg));
|
||||
ZVAL_NULL(zval_arg);
|
||||
ret = FAILURE;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PHPAPI OLECHAR *php_char_to_OLECHAR(char *C_str, uint strlen, int codepage, int persist)
|
||||
{
|
||||
BOOL error = FALSE;
|
||||
OLECHAR *unicode_str;
|
||||
|
||||
if (strlen == -1) {
|
||||
/* request needed buffersize */
|
||||
strlen = MultiByteToWideChar(codepage, (codepage == CP_UTF8 ? 0 : MB_PRECOMPOSED | MB_ERR_INVALID_CHARS), C_str, -1, NULL, 0);
|
||||
} else {
|
||||
/* \0 terminator */
|
||||
strlen++;
|
||||
}
|
||||
|
||||
if (strlen >= 0) {
|
||||
unicode_str = (OLECHAR *) pemalloc(sizeof(OLECHAR) * strlen, persist);
|
||||
|
||||
/* convert string */
|
||||
error = !MultiByteToWideChar(codepage, (codepage == CP_UTF8 ? 0 : MB_PRECOMPOSED | MB_ERR_INVALID_CHARS), C_str, strlen, unicode_str, strlen);
|
||||
} else {
|
||||
/* return a zero-length string */
|
||||
unicode_str = (OLECHAR *) pemalloc(sizeof(OLECHAR), persist);
|
||||
*unicode_str = 0;
|
||||
|
||||
error = TRUE;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
switch (GetLastError()) {
|
||||
case ERROR_NO_UNICODE_TRANSLATION:
|
||||
rpc_error(E_WARNING, "No unicode translation available for the specified string");
|
||||
break;
|
||||
case ERROR_INSUFFICIENT_BUFFER:
|
||||
rpc_error(E_WARNING, "Internal Error: Insufficient Buffer");
|
||||
break;
|
||||
default:
|
||||
rpc_error(E_WARNING, "Unknown error in php_char_to_OLECHAR()");
|
||||
}
|
||||
}
|
||||
|
||||
return unicode_str;
|
||||
}
|
||||
|
||||
|
||||
PHPAPI char *php_OLECHAR_to_char(OLECHAR *unicode_str, uint *out_length, int codepage, int persist)
|
||||
{
|
||||
char *C_str;
|
||||
uint length = 0;
|
||||
|
||||
/* request needed buffersize */
|
||||
uint reqSize = WideCharToMultiByte(codepage, codepage == CP_UTF8 ? 0 : WC_COMPOSITECHECK, unicode_str, -1, NULL, 0, NULL, NULL);
|
||||
|
||||
if (reqSize) {
|
||||
C_str = (char *) pemalloc(sizeof(char) * reqSize, persist);
|
||||
|
||||
/* convert string */
|
||||
length = WideCharToMultiByte(codepage, codepage == CP_UTF8 ? 0 : WC_COMPOSITECHECK, unicode_str, -1, C_str, reqSize, NULL, NULL) - 1;
|
||||
} else {
|
||||
C_str = (char *) pemalloc(sizeof(char), persist);
|
||||
*C_str = 0;
|
||||
|
||||
rpc_error(E_WARNING, "Error in php_OLECHAR_to_char()");
|
||||
}
|
||||
|
||||
if (out_length) {
|
||||
*out_length = length;
|
||||
}
|
||||
|
||||
return C_str;
|
||||
}
|
||||
|
||||
static int comval_to_variant(zval *object, VARIANT *var_arg)
|
||||
{
|
||||
rpc_internal *intern;
|
||||
TSRMLS_FETCH();
|
||||
|
||||
if (GET_INTERNAL_EX(intern, object) != SUCCESS) {
|
||||
/* TODO exception */
|
||||
VariantInit(var_arg);
|
||||
|
||||
return FAILURE;
|
||||
} else {
|
||||
V_VT(var_arg) = VT_DISPATCH;
|
||||
V_DISPATCH(var_arg) = C_DISPATCH((comval *) intern->data);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* PHP_WIN32 */
|
||||
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 4 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2003 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.0 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_0.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: Harald Radi <h.radi@nme.at> |
|
||||
| Alan Brown <abrown@pobox.com> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#ifndef CONVERSION_H
|
||||
#define CONVERSION_H
|
||||
|
||||
/* isn't this defined somewhere else ? */
|
||||
|
||||
#define Z_TRUE 1
|
||||
#define Z_FALSE 0
|
||||
|
||||
#define VT_TRUE -1
|
||||
#define VT_FALSE 0
|
||||
|
||||
BEGIN_EXTERN_C()
|
||||
|
||||
ZEND_API void php_zval_to_variant(zval *zval_arg, VARIANT *var_arg, int codepage TSRMLS_DC);
|
||||
ZEND_API void php_zval_to_variant_ex(zval *zval_arg, VARIANT *var_arg, int type, int codepage TSRMLS_DC);
|
||||
ZEND_API int php_variant_to_zval(VARIANT *var_arg, zval *zval_arg, int codepage);
|
||||
|
||||
ZEND_API OLECHAR *php_char_to_OLECHAR(char *C_str, uint strlen, int codepage, int persist);
|
||||
ZEND_API char *php_OLECHAR_to_char(OLECHAR *unicode_str, uint *out_length, int codepage, int persist);
|
||||
|
||||
END_EXTERN_C()
|
||||
|
||||
#endif
|
||||
@@ -1,641 +0,0 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 4 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2003 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.0 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_0.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: Wez Furlong <wez@thebrainroom.com> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* This module is used to export PHP objects to COM and DOTNET by exposing
|
||||
* them as objects implementing IDispatch.
|
||||
* */
|
||||
|
||||
#define ZEND_INCLUDE_FULL_WINDOWS_HEADERS
|
||||
|
||||
#include "../rpc.h"
|
||||
|
||||
#include "php.h"
|
||||
#include "com.h"
|
||||
#include "com_wrapper.h"
|
||||
#include "conversion.h"
|
||||
#include "variant.h"
|
||||
|
||||
#define COBJMACROS
|
||||
#include <unknwn.h> /* IDispatch */
|
||||
#include <dispex.h> /* IDispatchEx */
|
||||
|
||||
|
||||
typedef struct {
|
||||
/* This first part MUST match the declaration
|
||||
* of interface IDispatchEx */
|
||||
CONST_VTBL struct IDispatchExVtbl *lpVtbl;
|
||||
|
||||
/* now the PHP stuff */
|
||||
|
||||
THREAD_T engine_thread; /* for sanity checking */
|
||||
zval *object; /* the object exported */
|
||||
LONG refcount; /* COM reference count */
|
||||
|
||||
HashTable *dispid_to_name; /* keep track of dispid -> name mappings */
|
||||
HashTable *name_to_dispid; /* keep track of name -> dispid mappings */
|
||||
|
||||
GUID sinkid; /* iid that we "implement" for event sinking */
|
||||
|
||||
int id;
|
||||
} php_dispatchex;
|
||||
|
||||
static void disp_destructor(php_dispatchex *disp);
|
||||
|
||||
static void dispatch_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
|
||||
{
|
||||
php_dispatchex *disp = (php_dispatchex *)rsrc->ptr;
|
||||
disp_destructor(disp);
|
||||
}
|
||||
|
||||
static int le_dispatch;
|
||||
int php_COM_dispatch_init(int module_number TSRMLS_DC)
|
||||
{
|
||||
le_dispatch = zend_register_list_destructors_ex(dispatch_dtor, NULL, "COM:Dispatch", module_number);
|
||||
return le_dispatch;
|
||||
}
|
||||
|
||||
|
||||
/* {{{ trace */
|
||||
static inline void trace(char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char buf[4096];
|
||||
|
||||
sprintf(buf, "T=%08x ", tsrm_thread_id());
|
||||
OutputDebugString(buf);
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(buf, sizeof(buf), fmt, ap);
|
||||
|
||||
OutputDebugString(buf);
|
||||
|
||||
va_end(ap);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
#define FETCH_DISP(methname) \
|
||||
php_dispatchex *disp = (php_dispatchex*)This; \
|
||||
trace(" PHP:%s %s\n", Z_OBJCE_P(disp->object)->name, methname); \
|
||||
if (tsrm_thread_id() != disp->engine_thread) \
|
||||
return E_UNEXPECTED;
|
||||
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE disp_queryinterface(
|
||||
IDispatchEx *This,
|
||||
/* [in] */ REFIID riid,
|
||||
/* [iid_is][out] */ void **ppvObject)
|
||||
{
|
||||
TSRMLS_FETCH();
|
||||
FETCH_DISP("QueryInterface");
|
||||
|
||||
if (IsEqualGUID(&IID_IUnknown, riid) ||
|
||||
IsEqualGUID(&IID_IDispatch, riid) ||
|
||||
IsEqualGUID(&IID_IDispatchEx, riid) ||
|
||||
IsEqualGUID(&disp->sinkid, riid)) {
|
||||
*ppvObject = This;
|
||||
InterlockedIncrement(&disp->refcount);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
*ppvObject = NULL;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
static ULONG STDMETHODCALLTYPE disp_addref(IDispatchEx *This)
|
||||
{
|
||||
TSRMLS_FETCH();
|
||||
FETCH_DISP("AddRef");
|
||||
|
||||
return InterlockedIncrement(&disp->refcount);
|
||||
}
|
||||
|
||||
static ULONG STDMETHODCALLTYPE disp_release(IDispatchEx *This)
|
||||
{
|
||||
ULONG ret;
|
||||
TSRMLS_FETCH();
|
||||
FETCH_DISP("Release");
|
||||
|
||||
ret = InterlockedDecrement(&disp->refcount);
|
||||
trace("-- refcount now %d\n", ret);
|
||||
if (ret == 0) {
|
||||
/* destroy it */
|
||||
if (disp->id)
|
||||
zend_list_delete(disp->id);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE disp_gettypeinfocount(
|
||||
IDispatchEx *This,
|
||||
/* [out] */ UINT *pctinfo)
|
||||
{
|
||||
TSRMLS_FETCH();
|
||||
FETCH_DISP("GetTypeInfoCount");
|
||||
|
||||
*pctinfo = 0;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE disp_gettypeinfo(
|
||||
IDispatchEx *This,
|
||||
/* [in] */ UINT iTInfo,
|
||||
/* [in] */ LCID lcid,
|
||||
/* [out] */ ITypeInfo **ppTInfo)
|
||||
{
|
||||
TSRMLS_FETCH();
|
||||
FETCH_DISP("GetTypeInfo");
|
||||
|
||||
*ppTInfo = NULL;
|
||||
return DISP_E_BADINDEX;
|
||||
}
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE disp_getidsofnames(
|
||||
IDispatchEx *This,
|
||||
/* [in] */ REFIID riid,
|
||||
/* [size_is][in] */ LPOLESTR *rgszNames,
|
||||
/* [in] */ UINT cNames,
|
||||
/* [in] */ LCID lcid,
|
||||
/* [size_is][out] */ DISPID *rgDispId)
|
||||
{
|
||||
UINT i;
|
||||
HRESULT ret = S_OK;
|
||||
TSRMLS_FETCH();
|
||||
FETCH_DISP("GetIDsOfNames");
|
||||
|
||||
for (i = 0; i < cNames; i++) {
|
||||
char *name;
|
||||
unsigned int namelen;
|
||||
zval **tmp;
|
||||
|
||||
name = php_OLECHAR_to_char(rgszNames[i], &namelen, CP_ACP, FALSE);
|
||||
|
||||
/* Lookup the name in the hash */
|
||||
if (zend_hash_find(disp->name_to_dispid, name, namelen+1, (void**)&tmp) == FAILURE) {
|
||||
ret = DISP_E_UNKNOWNNAME;
|
||||
rgDispId[i] = 0;
|
||||
} else {
|
||||
rgDispId[i] = Z_LVAL_PP(tmp);
|
||||
}
|
||||
|
||||
efree(name);
|
||||
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE disp_invoke(
|
||||
IDispatchEx *This,
|
||||
/* [in] */ DISPID dispIdMember,
|
||||
/* [in] */ REFIID riid,
|
||||
/* [in] */ LCID lcid,
|
||||
/* [in] */ WORD wFlags,
|
||||
/* [out][in] */ DISPPARAMS *pDispParams,
|
||||
/* [out] */ VARIANT *pVarResult,
|
||||
/* [out] */ EXCEPINFO *pExcepInfo,
|
||||
/* [out] */ UINT *puArgErr)
|
||||
{
|
||||
return This->lpVtbl->InvokeEx(This, dispIdMember,
|
||||
lcid, wFlags, pDispParams,
|
||||
pVarResult, pExcepInfo, NULL);
|
||||
}
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE disp_getdispid(
|
||||
IDispatchEx *This,
|
||||
/* [in] */ BSTR bstrName,
|
||||
/* [in] */ DWORD grfdex,
|
||||
/* [out] */ DISPID *pid)
|
||||
{
|
||||
HRESULT ret = DISP_E_UNKNOWNNAME;
|
||||
char *name;
|
||||
unsigned int namelen;
|
||||
zval **tmp;
|
||||
TSRMLS_FETCH();
|
||||
FETCH_DISP("GetDispID");
|
||||
|
||||
name = php_OLECHAR_to_char(bstrName, &namelen, CP_ACP, FALSE);
|
||||
|
||||
/* Lookup the name in the hash */
|
||||
if (zend_hash_find(disp->name_to_dispid, name, namelen+1, (void**)&tmp) == SUCCESS) {
|
||||
*pid = Z_LVAL_PP(tmp);
|
||||
ret = S_OK;
|
||||
}
|
||||
|
||||
efree(name);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE disp_invokeex(
|
||||
IDispatchEx *This,
|
||||
/* [in] */ DISPID id,
|
||||
/* [in] */ LCID lcid,
|
||||
/* [in] */ WORD wFlags,
|
||||
/* [in] */ DISPPARAMS *pdp,
|
||||
/* [out] */ VARIANT *pvarRes,
|
||||
/* [out] */ EXCEPINFO *pei,
|
||||
/* [unique][in] */ IServiceProvider *pspCaller)
|
||||
{
|
||||
zval **name;
|
||||
UINT i;
|
||||
int codepage = CP_ACP;
|
||||
zval *retval = NULL;
|
||||
zval ***params = NULL;
|
||||
HRESULT ret = DISP_E_MEMBERNOTFOUND;
|
||||
TSRMLS_FETCH();
|
||||
FETCH_DISP("InvokeEx");
|
||||
|
||||
if (SUCCESS == zend_hash_index_find(disp->dispid_to_name, id, (void**)&name)) {
|
||||
/* TODO: add support for overloaded objects */
|
||||
|
||||
trace("-- Invoke: %d %20s flags=%08x args=%d\n", id, Z_STRVAL_PP(name), wFlags, pdp->cArgs);
|
||||
|
||||
/* convert args into zvals.
|
||||
* Args are in reverse order */
|
||||
params = (zval ***)emalloc(sizeof(zval **) * pdp->cArgs);
|
||||
for (i = 0; i < pdp->cArgs; i++) {
|
||||
VARIANT *arg;
|
||||
zval *zarg;
|
||||
|
||||
arg = &pdp->rgvarg[ pdp->cArgs - 1 - i];
|
||||
|
||||
trace("alloc zval for arg %d VT=%08x\n", i, V_VT(arg));
|
||||
|
||||
ALLOC_INIT_ZVAL(zarg);
|
||||
|
||||
if (V_VT(arg) == VT_DISPATCH) {
|
||||
trace("arg %d is dispatchable\n", i);
|
||||
if ((zarg = php_COM_object_from_dispatch(V_DISPATCH(arg))) == NULL) {
|
||||
trace("failed to convert arg %d to zval\n", i);
|
||||
ZVAL_NULL(zarg);
|
||||
}
|
||||
} else {
|
||||
/* arg can't be an idispatch, so we don't care for the implicit AddRef() call here */
|
||||
if (FAILURE == php_variant_to_zval(arg, zarg, codepage)) {
|
||||
trace("failed to convert arg %d to zval\n", i);
|
||||
ZVAL_NULL(zarg);
|
||||
}
|
||||
}
|
||||
|
||||
params[i] = &zarg;
|
||||
}
|
||||
|
||||
trace("arguments processed, prepare to do some work\n");
|
||||
|
||||
if (wFlags & DISPATCH_PROPERTYGET) {
|
||||
trace("trying to get a property\n");
|
||||
zend_hash_find(Z_OBJPROP_P(disp->object), Z_STRVAL_PP(name), Z_STRLEN_PP(name)+1, (void**)&retval);
|
||||
} else if (wFlags & DISPATCH_PROPERTYPUT) {
|
||||
trace("trying to set a property\n");
|
||||
add_property_zval(disp->object, Z_STRVAL_PP(name), *params[0]);
|
||||
} else if (wFlags & DISPATCH_METHOD) {
|
||||
trace("Trying to call user function\n");
|
||||
if (SUCCESS == call_user_function_ex(EG(function_table), &disp->object, *name,
|
||||
&retval, pdp->cArgs, params, 1, NULL TSRMLS_CC)) {
|
||||
ret = S_OK;
|
||||
} else {
|
||||
ret = DISP_E_EXCEPTION;
|
||||
}
|
||||
} else {
|
||||
trace("Don't know how to handle this invocation %08x\n", wFlags);
|
||||
}
|
||||
|
||||
/* release arguments */
|
||||
for (i = 0; i < pdp->cArgs; i++)
|
||||
zval_ptr_dtor(params[i]);
|
||||
efree(params);
|
||||
|
||||
/* return value */
|
||||
if (retval) {
|
||||
if (pvarRes) {
|
||||
if (Z_TYPE_P(retval) == IS_OBJECT) {
|
||||
/* export the object using a dispatch like ourselves */
|
||||
VariantInit(pvarRes);
|
||||
V_VT(pvarRes) = VT_DISPATCH;
|
||||
V_DISPATCH(pvarRes) = php_COM_export_object(retval);
|
||||
} else {
|
||||
php_zval_to_variant(retval, pvarRes, codepage TSRMLS_CC);
|
||||
}
|
||||
}
|
||||
zval_ptr_dtor(&retval);
|
||||
} else if (pvarRes) {
|
||||
VariantInit(pvarRes);
|
||||
}
|
||||
|
||||
} else {
|
||||
trace("InvokeEx: I don't support DISPID=%d\n", id);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE disp_deletememberbyname(
|
||||
IDispatchEx *This,
|
||||
/* [in] */ BSTR bstrName,
|
||||
/* [in] */ DWORD grfdex)
|
||||
{
|
||||
TSRMLS_FETCH();
|
||||
FETCH_DISP("DeleteMemberByName");
|
||||
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE disp_deletememberbydispid(
|
||||
IDispatchEx *This,
|
||||
/* [in] */ DISPID id)
|
||||
{
|
||||
TSRMLS_FETCH();
|
||||
FETCH_DISP("DeleteMemberByDispID");
|
||||
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE disp_getmemberproperties(
|
||||
IDispatchEx *This,
|
||||
/* [in] */ DISPID id,
|
||||
/* [in] */ DWORD grfdexFetch,
|
||||
/* [out] */ DWORD *pgrfdex)
|
||||
{
|
||||
TSRMLS_FETCH();
|
||||
FETCH_DISP("GetMemberProperties");
|
||||
|
||||
return DISP_E_UNKNOWNNAME;
|
||||
}
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE disp_getmembername(
|
||||
IDispatchEx *This,
|
||||
/* [in] */ DISPID id,
|
||||
/* [out] */ BSTR *pbstrName)
|
||||
{
|
||||
zval *name;
|
||||
TSRMLS_FETCH();
|
||||
FETCH_DISP("GetMemberName");
|
||||
|
||||
if (SUCCESS == zend_hash_index_find(disp->dispid_to_name, id, (void**)&name)) {
|
||||
OLECHAR *olestr = php_char_to_OLECHAR(Z_STRVAL_P(name), Z_STRLEN_P(name), CP_ACP, FALSE);
|
||||
*pbstrName = SysAllocString(olestr);
|
||||
efree(olestr);
|
||||
return S_OK;
|
||||
} else {
|
||||
return DISP_E_UNKNOWNNAME;
|
||||
}
|
||||
}
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE disp_getnextdispid(
|
||||
IDispatchEx *This,
|
||||
/* [in] */ DWORD grfdex,
|
||||
/* [in] */ DISPID id,
|
||||
/* [out] */ DISPID *pid)
|
||||
{
|
||||
ulong next = id+1;
|
||||
TSRMLS_FETCH();
|
||||
FETCH_DISP("GetNextDispID");
|
||||
|
||||
while(!zend_hash_index_exists(disp->dispid_to_name, next))
|
||||
next++;
|
||||
|
||||
if (zend_hash_index_exists(disp->dispid_to_name, next)) {
|
||||
*pid = next;
|
||||
return S_OK;
|
||||
}
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE disp_getnamespaceparent(
|
||||
IDispatchEx *This,
|
||||
/* [out] */ IUnknown **ppunk)
|
||||
{
|
||||
TSRMLS_FETCH();
|
||||
FETCH_DISP("GetNameSpaceParent");
|
||||
|
||||
*ppunk = NULL;
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
static struct IDispatchExVtbl php_dispatch_vtbl = {
|
||||
disp_queryinterface,
|
||||
disp_addref,
|
||||
disp_release,
|
||||
disp_gettypeinfocount,
|
||||
disp_gettypeinfo,
|
||||
disp_getidsofnames,
|
||||
disp_invoke,
|
||||
disp_getdispid,
|
||||
disp_invokeex,
|
||||
disp_deletememberbyname,
|
||||
disp_deletememberbydispid,
|
||||
disp_getmemberproperties,
|
||||
disp_getmembername,
|
||||
disp_getnextdispid,
|
||||
disp_getnamespaceparent
|
||||
};
|
||||
|
||||
|
||||
/* enumerate functions and properties of the object and assign
|
||||
* dispatch ids */
|
||||
static void generate_dispids(php_dispatchex *disp TSRMLS_DC)
|
||||
{
|
||||
HashPosition pos;
|
||||
char *name = NULL;
|
||||
zval *tmp;
|
||||
int namelen;
|
||||
int keytype;
|
||||
ulong pid;
|
||||
|
||||
if (disp->dispid_to_name == NULL) {
|
||||
ALLOC_HASHTABLE(disp->dispid_to_name);
|
||||
ALLOC_HASHTABLE(disp->name_to_dispid);
|
||||
zend_hash_init(disp->name_to_dispid, 0, NULL, ZVAL_PTR_DTOR, 0);
|
||||
zend_hash_init(disp->dispid_to_name, 0, NULL, ZVAL_PTR_DTOR, 0);
|
||||
}
|
||||
|
||||
/* properties */
|
||||
zend_hash_internal_pointer_reset_ex(Z_OBJPROP_PP(&disp->object), &pos);
|
||||
while (HASH_KEY_NON_EXISTANT != (keytype =
|
||||
zend_hash_get_current_key_ex(Z_OBJPROP_PP(&disp->object), &name, &namelen, &pid, 0, &pos))) {
|
||||
char namebuf[32];
|
||||
if (keytype == HASH_KEY_IS_LONG) {
|
||||
sprintf(namebuf, "%d", pid);
|
||||
name = namebuf;
|
||||
namelen = strlen(namebuf);
|
||||
}
|
||||
|
||||
zend_hash_move_forward_ex(Z_OBJPROP_PP(&disp->object), &pos);
|
||||
|
||||
/* Find the existing id */
|
||||
if (zend_hash_find(disp->name_to_dispid, name, namelen+1, (void**)&tmp) == SUCCESS)
|
||||
continue;
|
||||
|
||||
/* add the mappings */
|
||||
MAKE_STD_ZVAL(tmp);
|
||||
ZVAL_STRINGL(tmp, name, namelen, 1);
|
||||
zend_hash_index_update(disp->dispid_to_name, pid, (void*)&tmp, sizeof(zval *), NULL);
|
||||
|
||||
MAKE_STD_ZVAL(tmp);
|
||||
ZVAL_LONG(tmp, pid);
|
||||
zend_hash_update(disp->name_to_dispid, name, namelen+1, (void*)&tmp, sizeof(zval *), NULL);
|
||||
|
||||
}
|
||||
|
||||
/* functions */
|
||||
zend_hash_internal_pointer_reset_ex(&Z_OBJCE_PP(&disp->object)->function_table, &pos);
|
||||
while (HASH_KEY_NON_EXISTANT != (keytype =
|
||||
zend_hash_get_current_key_ex(&Z_OBJCE_PP(&disp->object)->function_table, &name, &namelen, &pid, 0, &pos))) {
|
||||
|
||||
char namebuf[32];
|
||||
if (keytype == HASH_KEY_IS_LONG) {
|
||||
sprintf(namebuf, "%d", pid);
|
||||
name = namebuf;
|
||||
namelen = strlen(namebuf);
|
||||
}
|
||||
|
||||
zend_hash_move_forward_ex(Z_OBJPROP_PP(&disp->object), &pos);
|
||||
|
||||
/* Find the existing id */
|
||||
if (zend_hash_find(disp->name_to_dispid, name, namelen+1, (void**)&tmp) == SUCCESS)
|
||||
continue;
|
||||
|
||||
/* add the mappings */
|
||||
MAKE_STD_ZVAL(tmp);
|
||||
ZVAL_STRINGL(tmp, name, namelen, 1);
|
||||
zend_hash_index_update(disp->dispid_to_name, pid, (void*)&tmp, sizeof(zval *), NULL);
|
||||
|
||||
MAKE_STD_ZVAL(tmp);
|
||||
ZVAL_LONG(tmp, pid);
|
||||
zend_hash_update(disp->name_to_dispid, name, namelen+1, (void*)&tmp, sizeof(zval *), NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static php_dispatchex *disp_constructor(zval *object)
|
||||
{
|
||||
php_dispatchex *disp = (php_dispatchex*)CoTaskMemAlloc(sizeof(php_dispatchex));
|
||||
|
||||
trace("constructing a COM proxy\n");
|
||||
|
||||
if (disp == NULL)
|
||||
return NULL;
|
||||
|
||||
memset(disp, 0, sizeof(php_dispatchex));
|
||||
|
||||
disp->engine_thread = tsrm_thread_id();
|
||||
disp->lpVtbl = &php_dispatch_vtbl;
|
||||
disp->refcount = 1;
|
||||
|
||||
|
||||
if (object)
|
||||
ZVAL_ADDREF(object);
|
||||
disp->object = object;
|
||||
|
||||
disp->id = zend_list_insert(disp, le_dispatch);
|
||||
|
||||
return disp;
|
||||
}
|
||||
|
||||
static void disp_destructor(php_dispatchex *disp)
|
||||
{
|
||||
TSRMLS_FETCH();
|
||||
|
||||
trace("destroying COM wrapper for PHP object %s\n", Z_OBJCE_P(disp->object)->name);
|
||||
|
||||
disp->id = 0;
|
||||
|
||||
if (disp->refcount > 0)
|
||||
CoDisconnectObject((IUnknown*)disp, 0);
|
||||
|
||||
zend_hash_destroy(disp->dispid_to_name);
|
||||
zend_hash_destroy(disp->name_to_dispid);
|
||||
FREE_HASHTABLE(disp->dispid_to_name);
|
||||
FREE_HASHTABLE(disp->name_to_dispid);
|
||||
|
||||
if (disp->object)
|
||||
zval_ptr_dtor(&disp->object);
|
||||
|
||||
|
||||
CoTaskMemFree(disp);
|
||||
}
|
||||
|
||||
PHPAPI IDispatch *php_COM_export_as_sink(zval *val, GUID *sinkid, HashTable *id_to_name)
|
||||
{
|
||||
php_dispatchex *disp = disp_constructor(val);
|
||||
HashPosition pos;
|
||||
char *name = NULL;
|
||||
zval *tmp, **ntmp;
|
||||
int namelen;
|
||||
int keytype;
|
||||
ulong pid;
|
||||
|
||||
disp->dispid_to_name = id_to_name;
|
||||
|
||||
memcpy(&disp->sinkid, sinkid, sizeof(disp->sinkid));
|
||||
|
||||
/* build up the reverse mapping */
|
||||
ALLOC_HASHTABLE(disp->name_to_dispid);
|
||||
zend_hash_init(disp->name_to_dispid, 0, NULL, ZVAL_PTR_DTOR, 0);
|
||||
|
||||
zend_hash_internal_pointer_reset_ex(id_to_name, &pos);
|
||||
while (HASH_KEY_NON_EXISTANT != (keytype =
|
||||
zend_hash_get_current_key_ex(id_to_name, &name, &namelen, &pid, 0, &pos))) {
|
||||
|
||||
if (keytype == HASH_KEY_IS_LONG) {
|
||||
|
||||
zend_hash_get_current_data_ex(id_to_name, (void**)&ntmp, &pos);
|
||||
|
||||
MAKE_STD_ZVAL(tmp);
|
||||
ZVAL_LONG(tmp, pid);
|
||||
zend_hash_update(disp->name_to_dispid, Z_STRVAL_PP(ntmp), Z_STRLEN_PP(ntmp)+1, (void*)&tmp, sizeof(zval *), NULL);
|
||||
}
|
||||
|
||||
zend_hash_move_forward_ex(id_to_name, &pos);
|
||||
}
|
||||
|
||||
return (IDispatch*)disp;
|
||||
}
|
||||
|
||||
PHPAPI IDispatch *php_COM_export_object(zval *val)
|
||||
{
|
||||
php_dispatchex *disp = NULL;
|
||||
TSRMLS_FETCH();
|
||||
|
||||
if (Z_TYPE_P(val) != IS_OBJECT)
|
||||
return NULL;
|
||||
|
||||
if (Z_OBJCE_P(val) == com_class_entry) {
|
||||
/* pass back it's IDispatch directly */
|
||||
comval *obj;
|
||||
rpc_internal *intern;
|
||||
|
||||
if (GET_INTERNAL_EX(intern, val) != SUCCESS) {
|
||||
/* TODO: exception */
|
||||
}
|
||||
|
||||
obj = (comval *) intern->data;
|
||||
|
||||
C_DISPATCH(obj)->lpVtbl->AddRef(C_DISPATCH(obj));
|
||||
return C_DISPATCH(obj);
|
||||
}
|
||||
|
||||
disp = disp_constructor(val);
|
||||
generate_dispids(disp TSRMLS_CC);
|
||||
|
||||
return (IDispatch*)disp;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 4 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2003 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.0 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_0.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: Harald Radi <h.radi@nme.at> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#ifndef PHP_COM_H
|
||||
#define PHP_COM_H
|
||||
|
||||
extern zend_module_entry com_module_entry;
|
||||
#define phpext_com_ptr &com_module_entry
|
||||
|
||||
#endif /* PHP_COM_H */
|
||||
@@ -1,324 +0,0 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 4 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2003 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.0 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_0.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: Harald Radi <h.radi@nme.at> |
|
||||
| Alan Brown <abrown@pobox.com> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This module maps the VARIANT datastructure into PHP so that it can be used to
|
||||
* pass values to COM and DOTNET Objects by reference and not only by value.
|
||||
*
|
||||
* harald
|
||||
*/
|
||||
|
||||
#ifdef PHP_WIN32
|
||||
|
||||
#define ZEND_INCLUDE_FULL_WINDOWS_HEADERS
|
||||
|
||||
#include "php.h"
|
||||
#include "php_ini.h"
|
||||
#include "ext/standard/info.h"
|
||||
#include "conversion.h"
|
||||
#include "variant.h"
|
||||
|
||||
#include "../php_rpc.h"
|
||||
|
||||
#include <unknwn.h>
|
||||
|
||||
static zend_object_value variant_objects_new(zend_class_entry * TSRMLS_DC);
|
||||
static void variant_objects_delete(void *, zend_object_handle TSRMLS_DC);
|
||||
|
||||
/* object handler */
|
||||
static zval* variant_read(zval *, zval * TSRMLS_DC);
|
||||
static void variant_write(zval *, zval *, zval * TSRMLS_DC);
|
||||
static union _zend_function* variant_get_constructor(zval * TSRMLS_DC);
|
||||
static zend_class_entry* variant_get_class_entry(zval * TSRMLS_DC);
|
||||
/**/
|
||||
|
||||
static HashTable types;
|
||||
static zend_class_entry *variant_class_entry;
|
||||
static zend_function *variant_ctor;
|
||||
static zend_object_handlers variant_handlers = {
|
||||
ZEND_OBJECTS_STORE_HANDLERS,
|
||||
|
||||
variant_read,
|
||||
variant_write,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
variant_get_constructor,
|
||||
variant_get_class_entry,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
/**/
|
||||
void php_variant_init(int module_number TSRMLS_DC)
|
||||
{
|
||||
zend_internal_function *zif;
|
||||
zend_class_entry ce;
|
||||
int type;
|
||||
|
||||
/* variant datatypes */
|
||||
REGISTER_LONG_CONSTANT("VT_NULL", VT_NULL, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("VT_EMPTY", VT_EMPTY, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("VT_UI1", VT_UI1, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("VT_I2", VT_I2, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("VT_I4", VT_I4, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("VT_R4", VT_R4, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("VT_R8", VT_R8, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("VT_BOOL", VT_BOOL, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("VT_ERROR", VT_ERROR, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("VT_CY", VT_CY, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("VT_DATE", VT_DATE, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("VT_BSTR", VT_BSTR, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("VT_DECIMAL", VT_DECIMAL, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("VT_UNKNOWN", VT_UNKNOWN, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("VT_DISPATCH", VT_DISPATCH, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("VT_VARIANT", VT_VARIANT, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("VT_I1", VT_I1, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("VT_UI2", VT_UI2, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("VT_UI4", VT_UI4, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("VT_INT", VT_INT, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("VT_UINT", VT_UINT, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("VT_ARRAY", VT_ARRAY, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("VT_BYREF", VT_BYREF, CONST_CS | CONST_PERSISTENT);
|
||||
|
||||
/* codepages */
|
||||
REGISTER_LONG_CONSTANT("CP_ACP", CP_ACP, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("CP_MACCP", CP_MACCP, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("CP_OEMCP", CP_OEMCP, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("CP_UTF7", CP_UTF7, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("CP_UTF8", CP_UTF8, CONST_CS | CONST_PERSISTENT);
|
||||
|
||||
#ifdef CP_SYMBOL
|
||||
REGISTER_LONG_CONSTANT("CP_SYMBOL", CP_SYMBOL, CONST_CS | CONST_PERSISTENT);
|
||||
#else
|
||||
#error "CP_SYMBOL undefined"
|
||||
#endif
|
||||
#ifdef CP_THREAD_ACP
|
||||
REGISTER_LONG_CONSTANT("CP_THREAD_ACP", CP_THREAD_ACP, CONST_CS | CONST_PERSISTENT);
|
||||
#else
|
||||
#error "CP_THREAD_ACP undefined"
|
||||
#endif
|
||||
|
||||
INIT_CLASS_ENTRY(ce, "variant", NULL);
|
||||
ce.create_object = variant_objects_new;
|
||||
variant_class_entry = zend_register_internal_class(&ce TSRMLS_CC);
|
||||
|
||||
zif = (zend_internal_function *) emalloc(sizeof(zend_internal_function));
|
||||
|
||||
zif->type = ZEND_INTERNAL_FUNCTION;
|
||||
zif->function_name = variant_class_entry->name;
|
||||
zif->scope = variant_class_entry;
|
||||
zif->arg_types = NULL;
|
||||
zif->handler = ZEND_FN(variant_load);
|
||||
|
||||
/* add new constructor to the method table */
|
||||
zend_hash_add(&(variant_class_entry->function_table), variant_class_entry->name,
|
||||
variant_class_entry->name_length + 1, zif, sizeof(zend_function), &variant_ctor);
|
||||
efree(zif);
|
||||
|
||||
zend_hash_init(&types, 0, NULL, NULL, TRUE);
|
||||
|
||||
type = VT_UI1;
|
||||
zend_hash_add(&types, "bVal", 5, (void *) &type, sizeof(int), NULL);
|
||||
type = VT_UI2;
|
||||
zend_hash_add(&types, "uiVal", 6, (void *) &type, sizeof(int), NULL);
|
||||
type = VT_UI4;
|
||||
zend_hash_add(&types, "ulVal", 6, (void *) &type, sizeof(int), NULL);
|
||||
type = VT_UINT;
|
||||
zend_hash_add(&types, "uintVal", 8, (void *) &type, sizeof(int), NULL);
|
||||
type = VT_I1;
|
||||
zend_hash_add(&types, "cVal", 5, (void *) &type, sizeof(int), NULL);
|
||||
type = VT_I2;
|
||||
zend_hash_add(&types, "iVal", 5, (void *) &type, sizeof(int), NULL);
|
||||
type = VT_I4;
|
||||
zend_hash_add(&types, "lVal", 5, (void *) &type, sizeof(int), NULL);
|
||||
type = VT_INT;
|
||||
zend_hash_add(&types, "intVal", 7, (void *) &type, sizeof(int), NULL);
|
||||
type = VT_R4;
|
||||
zend_hash_add(&types, "fltVal", 7, (void *) &type, sizeof(int), NULL);
|
||||
type = VT_R8;
|
||||
zend_hash_add(&types, "dblVal", 7, (void *) &type, sizeof(int), NULL);
|
||||
type = VT_BOOL;
|
||||
zend_hash_add(&types, "boolVal", 8, (void *) &type, sizeof(int), NULL);
|
||||
type = VT_ERROR;
|
||||
zend_hash_add(&types, "scode", 6, (void *) &type, sizeof(int), NULL);
|
||||
type = VT_CY;
|
||||
zend_hash_add(&types, "cyVal", 6, (void *) &type, sizeof(int), NULL);
|
||||
type = VT_DATE;
|
||||
zend_hash_add(&types, "date", 5, (void *) &type, sizeof(int), NULL);
|
||||
type = VT_BSTR;
|
||||
zend_hash_add(&types, "bstrVal", 8, (void *) &type, sizeof(int), NULL);
|
||||
type = VT_UNKNOWN;
|
||||
zend_hash_add(&types, "punkVal", 8, (void *) &type, sizeof(int), NULL);
|
||||
type = VT_DISPATCH;
|
||||
zend_hash_add(&types, "pdispVal", 9, (void *) &type, sizeof(int), NULL);
|
||||
type = VT_ARRAY;
|
||||
zend_hash_add(&types, "parray", 7, (void *) &type, sizeof(int), NULL);
|
||||
type = VT_BYREF;
|
||||
zend_hash_add(&types, "byref", 6, (void *) &type, sizeof(int), NULL);
|
||||
type = VT_BYREF|VT_UI1;
|
||||
zend_hash_add(&types, "pbVal", 6, (void *) &type, sizeof(int), NULL);
|
||||
type = VT_BYREF|VT_UI2;
|
||||
zend_hash_add(&types, "puiVal", 7, (void *) &type, sizeof(int), NULL);
|
||||
type = VT_BYREF|VT_UI4;
|
||||
zend_hash_add(&types, "pulVal", 7, (void *) &type, sizeof(int), NULL);
|
||||
type = VT_BYREF|VT_UINT;
|
||||
zend_hash_add(&types, "puintVal", 9, (void *) &type, sizeof(int), NULL);
|
||||
type = VT_BYREF|VT_I1;
|
||||
zend_hash_add(&types, "pcVal", 6, (void *) &type, sizeof(int), NULL);
|
||||
type = VT_BYREF|VT_I2;
|
||||
zend_hash_add(&types, "piVal", 6, (void *) &type, sizeof(int), NULL);
|
||||
type = VT_BYREF|VT_I4;
|
||||
zend_hash_add(&types, "plVal", 6, (void *) &type, sizeof(int), NULL);
|
||||
type = VT_BYREF|VT_INT;
|
||||
zend_hash_add(&types, "pintVal", 8, (void *) &type, sizeof(int), NULL);
|
||||
type = VT_BYREF|VT_R4;
|
||||
zend_hash_add(&types, "pfltVal", 8, (void *) &type, sizeof(int), NULL);
|
||||
type = VT_BYREF|VT_R8;
|
||||
zend_hash_add(&types, "pdblVal", 8, (void *) &type, sizeof(int), NULL);
|
||||
type = VT_BYREF|VT_BOOL;
|
||||
zend_hash_add(&types, "pboolVal", 9, (void *) &type, sizeof(int), NULL);
|
||||
type = VT_BYREF|VT_ERROR;
|
||||
zend_hash_add(&types, "pscode", 7, (void *) &type, sizeof(int), NULL);
|
||||
type = VT_BYREF|VT_CY;
|
||||
zend_hash_add(&types, "pcyVal", 7, (void *) &type, sizeof(int), NULL);
|
||||
type = VT_BYREF|VT_DATE;
|
||||
zend_hash_add(&types, "pdate", 6, (void *) &type, sizeof(int), NULL);
|
||||
type = VT_BYREF|VT_BSTR;
|
||||
zend_hash_add(&types, "pbstrVal", 9, (void *) &type, sizeof(int), NULL);
|
||||
type = VT_BYREF|VT_DECIMAL;
|
||||
zend_hash_add(&types, "pdecVal", 8, (void *) &type, sizeof(int), NULL);
|
||||
type = VT_BYREF|VT_UNKNOWN;
|
||||
zend_hash_add(&types, "ppunkVal", 9, (void *) &type, sizeof(int), NULL);
|
||||
type = VT_BYREF|VT_DISPATCH;
|
||||
zend_hash_add(&types, "ppdispVal", 10, (void *) &type, sizeof(int), NULL);
|
||||
type = VT_BYREF|VT_ARRAY;
|
||||
zend_hash_add(&types, "pparray", 8, (void *) &type, sizeof(int), NULL);
|
||||
type = VT_BYREF|VT_VARIANT;
|
||||
zend_hash_add(&types, "pvarVal", 8, (void *) &type, sizeof(int), NULL);
|
||||
}
|
||||
|
||||
void php_variant_shutdown(TSRMLS_D)
|
||||
{
|
||||
zend_hash_destroy(&types);
|
||||
}
|
||||
|
||||
static zend_object_value variant_objects_new(zend_class_entry *ce TSRMLS_DC)
|
||||
{
|
||||
zend_object_value *zov;
|
||||
variantval *var;
|
||||
|
||||
ALLOC_VARIANT(var);
|
||||
|
||||
/* set up the object value struct */
|
||||
zov = (zend_object_value*) emalloc(sizeof(zend_object_value));
|
||||
zov->handlers = &variant_handlers;
|
||||
zov->handle = zend_objects_store_put(var, variant_objects_delete, NULL TSRMLS_CC);
|
||||
|
||||
return *zov;
|
||||
}
|
||||
|
||||
static void variant_objects_delete(void *object, zend_object_handle handle TSRMLS_DC)
|
||||
{
|
||||
FREE_VARIANT((variantval *)object);
|
||||
}
|
||||
|
||||
static zval* variant_read(zval *object, zval *member TSRMLS_DC)
|
||||
{
|
||||
variantval *var;
|
||||
zval *result;
|
||||
|
||||
ALLOC_ZVAL(result);
|
||||
|
||||
if ((var = zend_object_store_get_object(object TSRMLS_CC)) == NULL) {
|
||||
/* exception */
|
||||
}
|
||||
|
||||
if (!strcmp(Z_STRVAL_P(member), "value")) {
|
||||
/* var_arg can't be an idispatch, so we don't care for the implicit AddRef() call here */
|
||||
php_variant_to_zval(var->var, result, var->codepage);
|
||||
} else if (!strcmp(Z_STRVAL_P(member), "type")) {
|
||||
ZVAL_LONG(result, V_VT(var->var));
|
||||
} else {
|
||||
ZVAL_FALSE(result);
|
||||
rpc_error(E_WARNING, "Unknown member.");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void variant_write(zval *object, zval *member, zval *value TSRMLS_DC)
|
||||
{
|
||||
int *type;
|
||||
variantval *var;
|
||||
|
||||
if ((var = zend_object_store_get_object(object TSRMLS_CC)) == NULL) {
|
||||
/* exception */
|
||||
}
|
||||
|
||||
if (!strcmp(Z_STRVAL_P(member), "value")) {
|
||||
php_zval_to_variant(value, var->var, var->codepage TSRMLS_CC);
|
||||
} else if (zend_hash_find(&types, Z_STRVAL_P(member), Z_STRLEN_P(member) + 1, (void **) &type) == SUCCESS) {
|
||||
php_zval_to_variant_ex(value, var->var, *type, var->codepage TSRMLS_CC);
|
||||
} else {
|
||||
rpc_error(E_WARNING, "Unknown member.");
|
||||
}
|
||||
}
|
||||
|
||||
static union _zend_function* variant_get_constructor(zval *object TSRMLS_DC)
|
||||
{
|
||||
return variant_ctor;
|
||||
}
|
||||
|
||||
static zend_class_entry* variant_get_class_entry(zval *object TSRMLS_DC)
|
||||
{
|
||||
return variant_class_entry;
|
||||
}
|
||||
|
||||
/**/
|
||||
/* constructor */
|
||||
ZEND_FUNCTION(variant_load)
|
||||
{
|
||||
zval *value = NULL, *object = getThis();
|
||||
variantval *var;
|
||||
long type = 0;
|
||||
|
||||
if (!object || ((var = zend_object_store_get_object(object TSRMLS_CC)) == NULL)) {
|
||||
/*TODO exception */
|
||||
}
|
||||
|
||||
zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|zll", &value, &type, &(var->codepage));
|
||||
|
||||
if (value) {
|
||||
if (type) {
|
||||
php_zval_to_variant_ex(value, var->var, type, var->codepage TSRMLS_CC);
|
||||
} else {
|
||||
php_zval_to_variant(value, var->var, var->codepage TSRMLS_CC);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* PHP_WIN32 */
|
||||
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 4 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2003 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.0 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_0.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: Harald Radi <h.radi@nme.at> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
|
||||
#ifndef VARIANT_H
|
||||
#define VARIANT_H
|
||||
|
||||
#if PHP_WIN32
|
||||
|
||||
#define ALLOC_VARIANT(v) (v) = (variantval *) emalloc(sizeof(variantval)); \
|
||||
(v)->var = (VARIANT *) emalloc(sizeof(VARIANT)); \
|
||||
(v)->codepage = CP_ACP; \
|
||||
VariantInit((v)->var);
|
||||
|
||||
#define FREE_VARIANT(v) VariantClear((v)->var); \
|
||||
efree((v)->var); \
|
||||
efree((v));
|
||||
|
||||
#define ZVAL_VARIANT(z, v, cp) \
|
||||
if (V_VT(v) == VT_DISPATCH && V_DISPATCH(v) == NULL) { \
|
||||
V_VT(v) = VT_NULL; \
|
||||
} \
|
||||
if (V_VT(v) == VT_DISPATCH) { \
|
||||
comval *obj; \
|
||||
ALLOC_COM(obj); \
|
||||
php_COM_set(obj, &V_DISPATCH(v), TRUE); \
|
||||
rpc_object_from_data_ex(z, com, obj, NULL); \
|
||||
} else { \
|
||||
php_variant_to_zval((v), (z), cp); \
|
||||
VariantClear(v); \
|
||||
}
|
||||
|
||||
#define RETVAL_VARIANT(v, cp) ZVAL_VARIANT(return_value, v, cp)
|
||||
#define RETURN_VARIANT(v, cp) RETVAL_VARIANT(v, cp) \
|
||||
return;
|
||||
|
||||
typedef struct variantval_ {
|
||||
VARIANT* var;
|
||||
long codepage;
|
||||
} variantval;
|
||||
|
||||
void php_variant_init(int module_number TSRMLS_DC);
|
||||
void php_variant_shutdown(TSRMLS_D);
|
||||
|
||||
ZEND_FUNCTION(variant_load);
|
||||
|
||||
#endif /* PHP_WIN32 */
|
||||
|
||||
#endif /* VARIANT_H */
|
||||
@@ -1,2 +0,0 @@
|
||||
dotnet
|
||||
Sam Ruby
|
||||
@@ -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,32 +0,0 @@
|
||||
Warning
|
||||
=======
|
||||
|
||||
This support is EXPERIMENTAL. In fact, it integrates code that
|
||||
Microsoft labels as pre-beta. Use at your own risk.
|
||||
|
||||
Build instructions
|
||||
==================
|
||||
|
||||
Download and install the .NET Framework SDK Technology Preview from
|
||||
http://msdn.microsoft.com/net/#sdk. Once installed, copy Mscoree.h
|
||||
(typically found in C:\Program Files\NGWSSDK\Include to ext\dotnet).
|
||||
Do not simply add the NGWSSDK\Include directory to the include path
|
||||
as this will cause compilation failures.
|
||||
|
||||
Download and unzip the source to the dm.net COM Moniker from
|
||||
http://staff.develop.com/jasonw/clr/readme.htm. Copy mscorlib.h
|
||||
to ext\dotnet. There is no need to register the clrmonsrv.dll as
|
||||
it is not used.
|
||||
|
||||
At this point, the dotnet project can be built like any other
|
||||
project, from either VisualStudio 6's GUI or from the command line.
|
||||
Example command line invocation:
|
||||
|
||||
msdev dotnet.dsp /MAKE "dotnet - Win32 Debug_TS"
|
||||
|
||||
Execution instructions:
|
||||
=======================
|
||||
|
||||
Add "extension=php_dotnet.dll" into php.ini.
|
||||
|
||||
Sample program can be found at dotnet.php
|
||||
@@ -1,237 +0,0 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 4 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2002 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.0 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_0.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: Sam Ruby <rubys@us.ibm.com> |
|
||||
| Harald Radi <h.radi@nme.at> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
/*
|
||||
* This module implements support for Microsoft .Net components.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 28.1.2001
|
||||
* use external unicode conversion functions
|
||||
*
|
||||
* harald radi <h.radi@nme.at>
|
||||
*/
|
||||
|
||||
#ifdef PHP_WIN32
|
||||
|
||||
#include <iostream>
|
||||
#include <math.h>
|
||||
#include <comdef.h>
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "php.h"
|
||||
#include "ext/standard/info.h"
|
||||
}
|
||||
|
||||
#include "ext/com/conversion.h"
|
||||
#include "ext/com/php_COM.h"
|
||||
|
||||
#include "Mscoree.h"
|
||||
#include "mscorlib.h"
|
||||
|
||||
using namespace mscorlib;
|
||||
|
||||
static ICorRuntimeHost *pHost;
|
||||
static mscorlib::_AppDomain *pDomain;
|
||||
|
||||
static zend_class_entry dotnet_class_entry;
|
||||
static int codepage;
|
||||
|
||||
HRESULT dotnet_init() {
|
||||
HRESULT hr;
|
||||
|
||||
hr = CoCreateInstance(CLSID_CorRuntimeHost, NULL, CLSCTX_ALL,
|
||||
IID_ICorRuntimeHost, (void **)&pHost);
|
||||
if (FAILED(hr)) return hr;
|
||||
|
||||
hr = pHost->Start();
|
||||
if (FAILED(hr)) return hr;
|
||||
|
||||
IUnknown *uDomain;
|
||||
hr = pHost->GetDefaultDomain(&uDomain);
|
||||
if (FAILED(hr)) return hr;
|
||||
|
||||
hr = uDomain->QueryInterface(__uuidof(_AppDomain), (void**) &pDomain);
|
||||
if (FAILED(hr)) return -1;
|
||||
|
||||
uDomain->Release();
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
HRESULT dotnet_create(OLECHAR *assembly, OLECHAR *datatype, comval *obj TSRMLS_DC) {
|
||||
HRESULT hr;
|
||||
|
||||
_ObjectHandle *pHandle;
|
||||
hr = pDomain->CreateInstance(_bstr_t(assembly), _bstr_t(datatype), &pHandle);
|
||||
if (FAILED(hr)) return hr;
|
||||
if (!pHandle) return hr;
|
||||
|
||||
_variant_t unwrapped;
|
||||
hr = pHandle->Unwrap(&unwrapped);
|
||||
pHandle->Release();
|
||||
if (FAILED(hr)) return hr;
|
||||
|
||||
php_COM_set(obj, &unwrapped.pdispVal, TRUE TSRMLS_CC);
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
void dotnet_term() {
|
||||
if (pHost) pHost->Stop();
|
||||
if (pHost) pHost->Release();
|
||||
if (pDomain) pDomain->Release();
|
||||
|
||||
pHost = 0;
|
||||
pDomain = 0;
|
||||
}
|
||||
|
||||
/* {{{ proto int dotnet_load(string assembly_name [, string datatype_name, int codepage])
|
||||
Loads a DOTNET module */
|
||||
PHP_FUNCTION(dotnet_load)
|
||||
{
|
||||
HRESULT hr;
|
||||
zval **assembly_name, **datatype_name, **code_page;
|
||||
OLECHAR *assembly, *datatype;
|
||||
comval *obj;
|
||||
|
||||
switch(ZEND_NUM_ARGS())
|
||||
{
|
||||
case 2:
|
||||
zend_get_parameters_ex(2, &assembly_name, &datatype_name);
|
||||
codepage = CP_ACP;
|
||||
break;
|
||||
case 3:
|
||||
zend_get_parameters_ex(3, &assembly_name, &datatype_name, &code_page);
|
||||
|
||||
convert_to_long_ex(code_page);
|
||||
codepage = Z_LVAL_PP(code_page);
|
||||
break;
|
||||
default:
|
||||
WRONG_PARAM_COUNT;
|
||||
break;
|
||||
}
|
||||
|
||||
convert_to_string_ex(assembly_name);
|
||||
assembly = php_char_to_OLECHAR(Z_STRVAL_PP(assembly_name), Z_STRLEN_PP(assembly_name), codepage TSRMLS_CC);
|
||||
|
||||
convert_to_string_ex(datatype_name);
|
||||
datatype = php_char_to_OLECHAR(Z_STRVAL_PP(datatype_name), Z_STRLEN_PP(datatype_name), codepage TSRMLS_CC);
|
||||
|
||||
ALLOC_COM(obj);
|
||||
|
||||
/* obtain IDispatch */
|
||||
hr = dotnet_create(assembly, datatype, obj TSRMLS_CC);
|
||||
efree(assembly);
|
||||
efree(datatype);
|
||||
if (FAILED(hr)) {
|
||||
char *error_message;
|
||||
error_message = php_COM_error_message(hr TSRMLS_CC);
|
||||
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error obtaining .Net class for %s in assembly %s: %s", datatype_name->value.str.val, assembly_name->value.str.val, error_message);
|
||||
LocalFree(error_message);
|
||||
efree(obj);
|
||||
RETURN_FALSE;
|
||||
}
|
||||
if (C_DISPATCH(obj) == NULL) {
|
||||
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to locate %s in assembly %s", datatype_name->value.str.val, assembly_name->value.str.val);
|
||||
efree(obj);
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
RETURN_LONG(zend_list_insert(obj, IS_COM));
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
|
||||
void php_DOTNET_call_function_handler(INTERNAL_FUNCTION_PARAMETERS, zend_property_reference *property_reference)
|
||||
{
|
||||
pval *object = property_reference->object;
|
||||
zend_overloaded_element *function_name = (zend_overloaded_element *) property_reference->elements_list->tail->data;
|
||||
|
||||
if (zend_llist_count(property_reference->elements_list)==1
|
||||
&& !strcmp(Z_STRVAL(function_name->element), "dotnet")) { /* constructor */
|
||||
pval *object_handle;
|
||||
|
||||
PHP_FN(dotnet_load)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
|
||||
if (!Z_LVAL_P(return_value)) {
|
||||
ZVAL_FALSE(object);
|
||||
return;
|
||||
}
|
||||
ALLOC_ZVAL(object_handle);
|
||||
*object_handle = *return_value;
|
||||
pval_copy_constructor(object_handle);
|
||||
INIT_PZVAL(object_handle);
|
||||
zend_hash_index_update(Z_OBJPROP_P(object), 0, &object_handle, sizeof(pval *), NULL);
|
||||
pval_destructor(&function_name->element);
|
||||
} else {
|
||||
php_COM_call_function_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, property_reference);
|
||||
}
|
||||
}
|
||||
|
||||
void php_register_DOTNET_class(TSRMLS_D)
|
||||
{
|
||||
INIT_OVERLOADED_CLASS_ENTRY(dotnet_class_entry, "DOTNET", NULL,
|
||||
php_DOTNET_call_function_handler,
|
||||
php_COM_get_property_handler,
|
||||
php_COM_set_property_handler);
|
||||
|
||||
zend_register_internal_class(&dotnet_class_entry TSRMLS_CC);
|
||||
}
|
||||
|
||||
function_entry DOTNET_functions[] = {
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
static PHP_MINFO_FUNCTION(DOTNET)
|
||||
{
|
||||
php_info_print_table_start();
|
||||
php_info_print_table_row(2, ".NET support", "enabled");
|
||||
php_info_print_table_end();
|
||||
}
|
||||
|
||||
PHP_MINIT_FUNCTION(DOTNET)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
if (FAILED(hr = dotnet_init())) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
php_register_DOTNET_class(TSRMLS_C);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
PHP_MSHUTDOWN_FUNCTION(DOTNET)
|
||||
{
|
||||
dotnet_term();
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
zend_module_entry dotnet_module_entry = {
|
||||
STANDARD_MODULE_HEADER,
|
||||
"dotnet", DOTNET_functions, PHP_MINIT(DOTNET), PHP_MSHUTDOWN(DOTNET), NULL, NULL, PHP_MINFO(DOTNET), NO_VERSION_YET, STANDARD_MODULE_PROPERTIES
|
||||
};
|
||||
|
||||
BEGIN_EXTERN_C()
|
||||
ZEND_GET_MODULE(dotnet)
|
||||
END_EXTERN_C()
|
||||
|
||||
#endif
|
||||
@@ -1,167 +0,0 @@
|
||||
# Microsoft Developer Studio Project File - Name="dotnet" - Package Owner=<4>
|
||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
||||
# ** DO NOT EDIT **
|
||||
|
||||
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
|
||||
|
||||
CFG=dotnet - Win32 Debug_TS
|
||||
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
||||
!MESSAGE use the Export Makefile command and run
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "dotnet.mak".
|
||||
!MESSAGE
|
||||
!MESSAGE You can specify a configuration when running NMAKE
|
||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "dotnet.mak" CFG="dotnet - Win32 Debug_TS"
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE "dotnet - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
|
||||
!MESSAGE "dotnet - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
|
||||
!MESSAGE "dotnet - Win32 Debug_TS" (based on "Win32 (x86) Dynamic-Link Library")
|
||||
!MESSAGE "dotnet - Win32 Release_TS" (based on "Win32 (x86) Dynamic-Link Library")
|
||||
!MESSAGE
|
||||
|
||||
# Begin Project
|
||||
# PROP AllowPerConfigDependencies 0
|
||||
# PROP Scc_ProjName ""
|
||||
# PROP Scc_LocalPath ""
|
||||
CPP=cl.exe
|
||||
MTL=midl.exe
|
||||
RSC=rc.exe
|
||||
|
||||
!IF "$(CFG)" == "dotnet - Win32 Release"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "..\..\Release"
|
||||
# PROP BASE Intermediate_Dir "Release"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "Release"
|
||||
# PROP Intermediate_Dir "Release"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "PHP_WIN32" /D "ZEND_WIN32" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /YX /FD /c
|
||||
# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\.." /I "..\..\main" /I "..\..\Zend" /I "..\..\..\bindlib_w32" /I "..\..\TSRM" /D "NDEBUG" /D ZEND_DEBUG=0 /D "PHP_WIN32" /D "ZEND_WIN32" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "COMPILE_DL_JAVA" /D HAVE_JAVA=1 /YX /FD /c
|
||||
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||
# ADD BASE RSC /l 0x40d /d "NDEBUG"
|
||||
# ADD RSC /l 0x40d /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"..\..\Release/php_dotnet.dll" /libpath:"$(JAVA_HOME)\lib" /libpath:"..\..\Release"
|
||||
|
||||
!ELSEIF "$(CFG)" == "dotnet - Win32 Debug"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 1
|
||||
# PROP BASE Output_Dir "..\..\Debug"
|
||||
# PROP BASE Intermediate_Dir "Debug"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 1
|
||||
# PROP Output_Dir "Debug"
|
||||
# PROP Intermediate_Dir "Debug"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "PHP_WIN32" /D "ZEND_WIN32" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /YX /FD /GZ /c
|
||||
# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\.." /I "..\..\main" /I "..\..\Zend" /I "..\..\..\bindlib_w32" /I "..\..\TSRM" /D "_DEBUG" /D ZEND_DEBUG=1 /D "PHP_WIN32" /D "ZEND_WIN32" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "COMPILE_DL_JAVA" /D HAVE_JAVA=1 /FR /YX /FD /GZ /c
|
||||
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||
# ADD BASE RSC /l 0x40d /d "_DEBUG"
|
||||
# ADD RSC /l 0x40d /d "_DEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"..\..\Debug/php_dotnet.dll" /pdbtype:sept /libpath:"$(JAVA_HOME)\lib" /libpath:"..\..\Debug"
|
||||
|
||||
!ELSEIF "$(CFG)" == "dotnet - Win32 Debug_TS"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 1
|
||||
# PROP BASE Output_Dir "..\..\Debug_TS"
|
||||
# PROP BASE Intermediate_Dir "Debug_TS"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 1
|
||||
# PROP Output_Dir "Debug_TS"
|
||||
# PROP Intermediate_Dir "Debug_TS"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\.." /I "..\..\..\Zend" /I "$(JAVA_HOME)\include\win32" /I "$(JAVA_HOME)\include" /I "..\..\..\bindlib_w32" /D "_DEBUG" /D "PHP_WIN32" /D "ZEND_WIN32" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "COMPILE_DL_JAVA" /FR /YX /FD /GZ /c
|
||||
# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\..\\" /I "..\..\main" /I "..\..\Zend" /I "..\..\..\bindlib_w32" /I "..\..\TSRM" /D "_DEBUG" /D ZEND_DEBUG=1 /D "ZTS" /D "PHP_WIN32" /D "ZEND_WIN32" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /FR /YX /FD /D /GZ /c
|
||||
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||
# ADD BASE RSC /l 0x40d /d "_DEBUG"
|
||||
# ADD RSC /l 0x40d /d "_DEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib php4ts_debug.lib /nologo /dll /debug /machine:I386 /out:"..\..\Debug_TS/php_dotnet.dll" /pdbtype:sept /libpath:"..\..\Debug_TS"
|
||||
|
||||
!ELSEIF "$(CFG)" == "dotnet - Win32 Release_TS"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "..\..\Release_TS"
|
||||
# PROP BASE Intermediate_Dir "Release_TS"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "Release_TS"
|
||||
# PROP Intermediate_Dir "Release_TS"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /MD /W3 /GX /O2 /I "..\.." /I "..\..\..\Zend" /I "$(JAVA_HOME)\include\win32" /I "$(JAVA_HOME)\include" /I "..\..\..\bindlib_w32" /D "NDEBUG" /D "PHP_WIN32" /D "ZEND_WIN32" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "COMPILE_DL_JAVA" /YX /FD /c
|
||||
# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\..\\" /I "..\..\main" /I "..\..\Zend" /I "..\..\..\bindlib_w32" /I "..\..\TSRM" /D "NDEBUG" /D ZEND_DEBUG=0 /D "ZTS" /D "PHP_WIN32" /D "ZEND_WIN32" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /YX /FD /c
|
||||
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||
# ADD BASE RSC /l 0x40d /d "NDEBUG"
|
||||
# ADD RSC /l 0x40d /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib php4ts.lib /nologo /dll /machine:I386 /out:"..\..\Release_TS/php_dotnet.dll" /libpath:"..\..\Release_TS" /libpath:"..\..\Release_TS_Inline"
|
||||
|
||||
!ENDIF
|
||||
|
||||
# Begin Target
|
||||
|
||||
# Name "dotnet - Win32 Release"
|
||||
# Name "dotnet - Win32 Debug"
|
||||
# Name "dotnet - Win32 Debug_TS"
|
||||
# Name "dotnet - Win32 Release_TS"
|
||||
# Begin Group "Source Files"
|
||||
|
||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\dotnet.cpp
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Header Files"
|
||||
|
||||
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\php_dotnet.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\README
|
||||
# End Source File
|
||||
# End Target
|
||||
# End Project
|
||||
@@ -1,8 +0,0 @@
|
||||
<?
|
||||
$stack = new DOTNET("mscorlib","System.Collections.Stack");
|
||||
|
||||
$stack->Push(".Net");
|
||||
$stack->Push("Hello ");
|
||||
|
||||
echo $stack->Pop() . $stack->Pop();
|
||||
?>
|
||||
@@ -1,21 +0,0 @@
|
||||
#ifndef PHP_DOTNET_H
|
||||
#define PHP_DOTNET_H
|
||||
|
||||
#ifdef PHP_WIN32
|
||||
|
||||
PHP_MINIT_FUNCTION(DOTNET);
|
||||
PHP_MSHUTDOWN_FUNCTION(DOTNET);
|
||||
PHP_FUNCTION(DOTNET_load);
|
||||
|
||||
extern zend_module_entry DOTNET_module_entry;
|
||||
#define DOTNET_module_ptr &DOTNET_module_entry
|
||||
|
||||
#else
|
||||
|
||||
#define DOTNET_module_ptr NULL
|
||||
|
||||
#endif /* PHP_WIN32 */
|
||||
|
||||
#define phpext_DOTNET_ptr DOTNET_module_ptr
|
||||
|
||||
#endif /* PHP_DOTNET_H */
|
||||
@@ -1,144 +0,0 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 4 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2003 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.0 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_0.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: Harald Radi <h.radi@nme.at> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#ifndef HANDLER_H
|
||||
#define HANDLER_H
|
||||
|
||||
#include "php.h"
|
||||
#include "php_ini.h"
|
||||
|
||||
#define RPC_REGISTER_LAYER(layer) rpc_register_layer(&layer##_handler_entry TSRMLS_CC);
|
||||
#define RPC_DECLARE_HANDLER(layer) rpc_object_handlers layer##_object_handlers; \
|
||||
zend_class_entry *layer##_class_entry; \
|
||||
function_entry layer##_function_entry[]; \
|
||||
function_entry layer##_method_entry[]; \
|
||||
static rpc_handler_entry layer##_handler_entry = \
|
||||
{#layer, &layer##_object_handlers, &layer##_class_entry,\
|
||||
layer##_function_entry, layer##_method_entry}
|
||||
|
||||
#define RPC_REGISTER_HANDLERS_BEGIN(layer) zend_class_entry *layer##_class_entry; \
|
||||
rpc_object_handlers layer##_object_handlers = {
|
||||
|
||||
#define RPC_REGISTER_HANDLERS_END() };
|
||||
|
||||
#define RPC_FUNCTION_ENTRY(layer) layer##_function_entry
|
||||
#define RPC_FUNCTION_ENTRY_BEGIN(layer) function_entry layer##_function_entry[] = { \
|
||||
ZEND_FALIAS(layer##_load, rpc_load, NULL) \
|
||||
ZEND_FALIAS(layer##_call, rpc_call, NULL) \
|
||||
ZEND_FALIAS(layer##_get, rpc_get, NULL) \
|
||||
ZEND_FALIAS(layer##_set, rpc_get, NULL) \
|
||||
ZEND_FALIAS(layer##_singleton, rpc_singleton, NULL) \
|
||||
ZEND_FALIAS(layer##_poolable, rpc_poolable, NULL)
|
||||
|
||||
#define RPC_FUNCTION_ENTRY_END() {NULL, NULL, NULL} \
|
||||
};
|
||||
|
||||
#define RPC_METHOD_ENTRY_BEGIN(layer) function_entry layer##_method_entry[] = {
|
||||
|
||||
#define RPC_METHOD_ENTRY_END() {NULL, NULL, NULL} \
|
||||
};
|
||||
|
||||
#define DONT_HASH 0
|
||||
#define HASH_AS_INT 1
|
||||
#define HASH_AS_STRING 2
|
||||
#define HASH_WITH_SIGNATURE 4
|
||||
#define HASH_AS_INT_WITH_SIGNATURE (HASH_AS_INT & HASH_WITH_SIGNATURE)
|
||||
#define HASH_AS_STRING_WITH_SIGNATURE (HASH_AS_STRING & HASH_WITH_SIGNATURE)
|
||||
|
||||
#define CLASS 0
|
||||
#define METHOD 1
|
||||
#define PROPERTY 2
|
||||
|
||||
|
||||
/* string */
|
||||
typedef struct _rpc_string {
|
||||
char *str;
|
||||
zend_uint len;
|
||||
} rpc_string;
|
||||
|
||||
/* rpc handler that have to be implemented by a
|
||||
* specific rpc layer
|
||||
*/
|
||||
typedef struct _rpc_object_handlers {
|
||||
const zend_bool poolable;
|
||||
const zend_uint hash_type;
|
||||
int (*rpc_hash)(rpc_string name, rpc_string *hash, void *data, int num_args, char *arg_types, int type);
|
||||
int (*rpc_name)(rpc_string hash, rpc_string *name, void *data, int type);
|
||||
int (*rpc_ctor)(rpc_string class_name, void **data, int num_args, zval **args[]);
|
||||
int (*rpc_dtor)(void *data);
|
||||
int (*rpc_describe)(rpc_string method_name, void *data, char **arg_types, unsigned char **ref_types);
|
||||
int (*rpc_call)(rpc_string method_name, void *data, zval *return_value, int num_args, zval **args[]);
|
||||
int (*rpc_get)(rpc_string property_name, zval *return_value, void *data);
|
||||
int (*rpc_set)(rpc_string property_name, zval *value, void *data);
|
||||
int (*rpc_compare)(void *data1, void *data2);
|
||||
int (*rpc_has_property)(rpc_string property_name, void *data);
|
||||
int (*rpc_unset_property)(rpc_string property_name, void *data);
|
||||
int (*rpc_get_properties)(HashTable **properties, void *data);
|
||||
} rpc_object_handlers;
|
||||
|
||||
/* handler entry */
|
||||
typedef struct _rpc_handler_entry {
|
||||
char *name;
|
||||
rpc_object_handlers *handlers;
|
||||
zend_class_entry **ce;
|
||||
function_entry *functions;
|
||||
function_entry *methods;
|
||||
} rpc_handler_entry;
|
||||
|
||||
/* class/method/function hash */
|
||||
typedef struct _rpc_class_hash {
|
||||
rpc_string name; /* must be first entry */
|
||||
zend_bool poolable;
|
||||
zend_bool singleton;
|
||||
TsHashTable methods;
|
||||
TsHashTable properties;
|
||||
rpc_object_handlers **handlers;
|
||||
zend_class_entry *ce;
|
||||
void *data;
|
||||
} rpc_class_hash;
|
||||
|
||||
/* internal data */
|
||||
typedef struct _rpc_internal {
|
||||
MUTEX_T mx_handler;
|
||||
TsHashTable function_table;
|
||||
zend_bool free_function_table;
|
||||
rpc_object_handlers **handlers;
|
||||
rpc_class_hash *hash;
|
||||
zend_class_entry *ce;
|
||||
void *data;
|
||||
} rpc_internal;
|
||||
|
||||
/* proxy data */
|
||||
typedef struct _rpc_proxy {
|
||||
zend_uint dummy;
|
||||
} rpc_proxy;
|
||||
|
||||
|
||||
ZEND_API ZEND_FUNCTION(rpc_load);
|
||||
ZEND_API ZEND_FUNCTION(rpc_call);
|
||||
ZEND_API ZEND_FUNCTION(rpc_set);
|
||||
ZEND_API ZEND_FUNCTION(rpc_get);
|
||||
ZEND_API ZEND_FUNCTION(rpc_singleton);
|
||||
ZEND_API ZEND_FUNCTION(rpc_poolable);
|
||||
|
||||
ZEND_API rpc_register_layer(rpc_handler_entry *entry TSRMLS_DC);
|
||||
ZEND_API zval* _rpc_object_from_data(zval *z, rpc_handler_entry *handler, void *data, rpc_class_hash *class_hash);
|
||||
#define rpc_object_from_data(layer, data) rpc_object_from_data_ex(NULL, layer, data, NULL)
|
||||
#define rpc_object_from_data_ex(z, layer, data, class_hash) _rpc_object_from_data((z), &layer##_handler_entry, (data), (class_hash))
|
||||
|
||||
#endif /* HANDLER_H */
|
||||
@@ -1,74 +0,0 @@
|
||||
#ifndef HASH_H
|
||||
#define HASH_H
|
||||
|
||||
static int zend_ts_hash_remove_key_or_index(TsHashTable *ht, char *arKey, uint nKeyLength, void **pData);
|
||||
|
||||
static int zend_ts_hash_remove_key_or_index(TsHashTable *ht, char *arKey, uint nKeyLength, void **pData)
|
||||
{
|
||||
uint nIndex;
|
||||
uint h = nKeyLength;
|
||||
uint result;
|
||||
void **ppData;
|
||||
Bucket *p;
|
||||
|
||||
tsrm_mutex_lock(ht->mx_writer);
|
||||
|
||||
if (arKey) {
|
||||
result = zend_hash_find(TS_HASH(ht), arKey, nKeyLength, (void **) &ppData);
|
||||
} else {
|
||||
result = zend_hash_index_find(TS_HASH(ht), h, (void **) &ppData);
|
||||
}
|
||||
|
||||
if (result == SUCCESS) {
|
||||
*pData = *ppData;
|
||||
|
||||
if (arKey) {
|
||||
h = zend_inline_hash_func(arKey, nKeyLength);
|
||||
}
|
||||
|
||||
nIndex = h & TS_HASH(ht)->nTableMask;
|
||||
|
||||
p = TS_HASH(ht)->arBuckets[nIndex];
|
||||
while (p != NULL) {
|
||||
if ((p->h == h) && ((p->nKeyLength == 0) || /* Numeric index */
|
||||
((p->nKeyLength == nKeyLength) && (!memcmp(p->arKey, arKey, nKeyLength))))) {
|
||||
HANDLE_BLOCK_INTERRUPTIONS();
|
||||
if (p == TS_HASH(ht)->arBuckets[nIndex]) {
|
||||
TS_HASH(ht)->arBuckets[nIndex] = p->pNext;
|
||||
} else {
|
||||
p->pLast->pNext = p->pNext;
|
||||
}
|
||||
if (p->pNext) {
|
||||
p->pNext->pLast = p->pLast;
|
||||
}
|
||||
if (p->pListLast != NULL) {
|
||||
p->pListLast->pListNext = p->pListNext;
|
||||
} else {
|
||||
/* Deleting the head of the list */
|
||||
TS_HASH(ht)->pListHead = p->pListNext;
|
||||
}
|
||||
if (p->pListNext != NULL) {
|
||||
p->pListNext->pListLast = p->pListLast;
|
||||
} else {
|
||||
TS_HASH(ht)->pListTail = p->pListLast;
|
||||
}
|
||||
if (TS_HASH(ht)->pInternalPointer == p) {
|
||||
TS_HASH(ht)->pInternalPointer = p->pListNext;
|
||||
}
|
||||
if (!p->pDataPtr) {
|
||||
pefree(p->pData, TS_HASH(ht)->persistent);
|
||||
}
|
||||
pefree(p, TS_HASH(ht)->persistent);
|
||||
HANDLE_UNBLOCK_INTERRUPTIONS();
|
||||
TS_HASH(ht)->nNumOfElements--;
|
||||
return SUCCESS;
|
||||
}
|
||||
p = p->pNext;
|
||||
}
|
||||
}
|
||||
tsrm_mutex_unlock(ht->mx_writer);
|
||||
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
#endif /* HASH_H */
|
||||
@@ -1,2 +0,0 @@
|
||||
Java
|
||||
Sam Ruby
|
||||
@@ -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,13 +0,0 @@
|
||||
|
||||
$(srcdir)/java.c : $(srcdir)/php_java.jar
|
||||
|
||||
$(srcdir)/php_java.jar : $(srcdir)/reflect.java
|
||||
@$(mkinstalldirs) $(srcdir)/net/php
|
||||
@cp $(srcdir)/reflect.java $(srcdir)/net/php
|
||||
@echo library=php_java > $(srcdir)/net/php/reflect.properties
|
||||
@$(JAVA_C) $(srcdir)/net/php/reflect.java
|
||||
@test ! -f reflect.class || mv reflect.class $(srcdir)/net/php # bug in KJC javac
|
||||
@$(JAVA_JAR) $(srcdir)/php_java.jar -C $(srcdir) net/php/reflect.class -C $(srcdir) net/php/reflect.properties
|
||||
@rm $(srcdir)/net/php/reflect.*
|
||||
@rmdir $(srcdir)/net/php
|
||||
@rmdir $(srcdir)/net
|
||||
@@ -1,247 +0,0 @@
|
||||
What is PHP4 ext/java?
|
||||
|
||||
PHP4 ext/java provides a simple and effective means for creating and
|
||||
invoking methods on Java objects from PHP. The JVM is created using JNI,
|
||||
and everything runs in-process.
|
||||
|
||||
Two examples are provided, jver and jawt, to illustrate usage of this
|
||||
extension. A few things to note:
|
||||
|
||||
1) new Java() will create an instance of a class if a suitable constructor
|
||||
is available. If no parameters are passed and the default constructor
|
||||
is useful as it provides access to classes like "java.lang.System"
|
||||
which expose most of their functionallity through static methods.
|
||||
|
||||
2) Accessing a member of an instance will first look for bean properties
|
||||
then public fields. In other words, "print $date.time" will first
|
||||
attempt to be resolved as "$date.getTime()", then as "$date.time";
|
||||
|
||||
3) Both static and instance members can be accessed on an object with
|
||||
the same syntax. Furthermore, if the java object is of type
|
||||
"java.lang.Class", then static members of the class (fields and
|
||||
methods) can be accessed.
|
||||
|
||||
4) Exceptions raised result in PHP warnings, and null results. The
|
||||
warnings may be eliminated by prefixing the method call with an
|
||||
"@" sign. The following APIs may be used to retrieve and reset
|
||||
the last error:
|
||||
|
||||
java_last_exception_get()
|
||||
java_last_exception_clear()
|
||||
|
||||
5) Overload resolution is in general a hard problem given the
|
||||
differences in types between the two languages. The PHP Java
|
||||
extension employs a simple, but fairly effective, metric for
|
||||
determining which overload is the best match.
|
||||
|
||||
Additionally, method names in PHP are not case sensitive, potentially
|
||||
increasing the number of overloads to select from.
|
||||
|
||||
Once a method is selected, the parameters are cooerced if necessary,
|
||||
possibly with a loss of data (example: double precision floating point
|
||||
numbers will be converted to boolean).
|
||||
|
||||
6) In the tradition of PHP, arrays and hashtables may pretty much
|
||||
be used interchangably. Note that hashtables in PHP may only be
|
||||
indexed by integers or strings; and that arrays of primitive types
|
||||
in Java can not be sparse. Also note that these constructs are
|
||||
passed by value, so may be expensive in terms of memory and time.
|
||||
|
||||
Build and execution instructions:
|
||||
|
||||
Given the number of platforms and providers of JVMs, no single set of
|
||||
instructions will be able to cover all cases. So in place of hard and
|
||||
fast instructions, below are a working examples for a number of free and
|
||||
commercial implementations and platforms. Please adjust the paths to
|
||||
suit your installation. Also, if you happen to get this to work on
|
||||
another JVM/platform combination, please let me know, particularly if
|
||||
a unique build or execution setup was required.
|
||||
|
||||
Note for Windows users: semi-colons (";") mark the beginning of
|
||||
comments in php.ini files, so if you wish to add to the classpath,
|
||||
make sure that the entire string is in quotes. See the JDK 1.1.8
|
||||
instructions below for an example.
|
||||
|
||||
This function has been tested in both CGI and Apache (apxs) modes. As
|
||||
the current design requires shared libraries, this support can not be
|
||||
linked statically into Apache.
|
||||
|
||||
With ext/java, no Java Virtual Machines are created until the first
|
||||
Java call is made. This not only eliminates unnecessary overhead if
|
||||
the extension is never used, it also provides error messages directly
|
||||
back to the user instead of being burried in a log some place.
|
||||
|
||||
For people interested in robustness, performance, and more complete
|
||||
integration with Java, consider using the sapi/servlet interface which
|
||||
is built upon the Java extension. Running PHP as a servlet enables PHP
|
||||
to utilize the existing JVM and threads from the servlet engine, and
|
||||
provides direct access to the servlet request and response objects.
|
||||
|
||||
Finally, the bottom of this readme contains some guidance for how to
|
||||
approach situations in which these instructions don't work on your
|
||||
machine.
|
||||
|
||||
========================================================================
|
||||
=== JVM=Kaffe 1.0.4 (as delivered with OS), OS=Redhat Linux 6.1 ===
|
||||
========================================================================
|
||||
|
||||
build instructions:
|
||||
|
||||
./configure --with-java
|
||||
|
||||
php.ini:
|
||||
|
||||
[java]
|
||||
java.library.path=/usr/lib/kaffe:/home/rubys/php4/modules
|
||||
java.class.path=/usr/share/kaffe/Klasses.jar:/home/rubys/php4/modules/php_java.jar
|
||||
extension_dir=/home/rubys/php4/modules
|
||||
extension=java.so
|
||||
|
||||
========================================================================
|
||||
=== JVM=Kaffe 1.0.5 (built from source), OS=Redhat Linux 6.1 ===
|
||||
========================================================================
|
||||
|
||||
build instructions:
|
||||
|
||||
./configure --with-java
|
||||
|
||||
php.ini:
|
||||
|
||||
[java]
|
||||
java.library.path=/usr/local/lib/kaffe:/home/rubys/php4/modules
|
||||
java.class.path=/usr/local/share/kaffe/Klasses.jar:/home/rubys/php4/modules/php_java.jar
|
||||
extension_dir=/home/rubys/php4/modules
|
||||
extension=java.so
|
||||
|
||||
========================================================================
|
||||
=== JVM=IBM 1.1.8, OS=Redhat Linux 6.1 ===
|
||||
========================================================================
|
||||
|
||||
build instructions:
|
||||
|
||||
./configure --with-java
|
||||
|
||||
php.ini:
|
||||
|
||||
[java]
|
||||
java.class.path=/home/jdk118/lib/classes.zip:/home/rubys/php4/modules/php_java.jar
|
||||
extension_dir=/home/rubys/php4/modules
|
||||
extension=java.so
|
||||
|
||||
========================================================================
|
||||
=== JVM=Blackdown 1.2.2 RC4, OS=Redhat Linux 6.1 ===
|
||||
========================================================================
|
||||
|
||||
build instructions:
|
||||
|
||||
./configure --with-java
|
||||
|
||||
php.ini:
|
||||
|
||||
[java]
|
||||
java.class.path=/home/rubys/php4/lib/php_java.jar
|
||||
extension_dir=/home/rubys/php4/modules
|
||||
extension=java.so
|
||||
|
||||
========================================================================
|
||||
=== JVM=Sun JDK 1.2.2, OS=Linux ===
|
||||
========================================================================
|
||||
|
||||
build instructions:
|
||||
|
||||
./configure --with-java
|
||||
|
||||
php.ini:
|
||||
|
||||
[java]
|
||||
java.class.path=/home/rubys/php4/lib/php_java.jar
|
||||
java.library.path=/home/rubys/php4/modules
|
||||
extension_dir=/home/rubys/php4/modules
|
||||
extension=java.so
|
||||
|
||||
========================================================================
|
||||
=== JVM=Sun JDK 1.1.8, OS=Windows NT 4 ===
|
||||
========================================================================
|
||||
|
||||
build instructions:
|
||||
|
||||
SET JAVA_HOME=D:\jdk1.1.8
|
||||
msdev ext\java\java.dsp /MAKE "java - Win32 Debug_TS"
|
||||
|
||||
php.ini:
|
||||
|
||||
[java]
|
||||
java.class.path="D:\jdk1.1.8\lib\classes.zip;F:\PHP4\Debug_TS\php_java.jar"
|
||||
extension=php_java.dll
|
||||
|
||||
========================================================================
|
||||
=== JVM=Sun JDK 1.2.2, OS=Windows NT 4 ===
|
||||
========================================================================
|
||||
|
||||
build instructions:
|
||||
|
||||
SET JAVA_HOME=D:\jdk1.2.2
|
||||
msdev ext\java\java.dsp /MAKE "java - Win32 Debug_TS"
|
||||
|
||||
php.ini:
|
||||
|
||||
[java]
|
||||
java.class.path=F:\PHP4\Debug_TS\php_java.jar
|
||||
extension=php_java.dll
|
||||
|
||||
=========================================================================
|
||||
|
||||
Guidance for when these instructions don't work.
|
||||
|
||||
JDK vendors don't typically document their internal workings, and are
|
||||
typically very reliant on code inside of the JAVA main program and the
|
||||
installation directory structure. For this reason, running PHP as a
|
||||
servlet is typically much easier to get working. But if for some reason
|
||||
this is not appropriate for you, and the instructions above don't work,
|
||||
then read on.
|
||||
|
||||
The first thing to realize is that the directory structure of the JDK is
|
||||
very important. Some users (particularly on Windows) get a message about
|
||||
a DLL or shared library not being available and proceed to find that file
|
||||
and copy it into a system directory. This typically just gets you to the
|
||||
next problem - for example, it appears that many JDKs attempt to locate
|
||||
the runtime Java classes (rt.jar) in a directory relative to these system
|
||||
libraries. So unless you are inclined to copy your entire Java
|
||||
installation, you are much better adjusting your PATHs.
|
||||
|
||||
Not documented above, but useful for many JDK's is ability to specify the
|
||||
library path via java.library.path in the php.ini. On many Unix machines,
|
||||
determining the initial value for this can be done by changing directory
|
||||
to where you find a shared library that can't be loaded (example:
|
||||
libjava.so), and executing "ld libjava.so". If you see some modules
|
||||
listed as "not found", add the necessary directories to LD_LIBRARY_PATH
|
||||
and repeat until successful. On my system, I require the following
|
||||
two directories.
|
||||
|
||||
/home/jdk1.2.2/jre/lib/i386/native_threads
|
||||
/home/jdk1.2.2/jre/lib/i386/classic
|
||||
|
||||
Note: this only determines the statically loaded libraries. Additional
|
||||
libraries (such as libzip.so) may be loaded dynamically. On my system,
|
||||
libzip.so is located in
|
||||
|
||||
/home/jdk1.2.2/jre/lib/i386
|
||||
|
||||
Another php.ini variable which may be helpful is java.home.
|
||||
|
||||
If java.library.path doesn't work for you (it won't on any JDK 1.1
|
||||
implementations, for example), then try setting the system PATH or the
|
||||
LD_LIBRARY_PATH before starting your web server. For Apache on Linux
|
||||
systems, this can be accomplished by editing the Root's .bashrc and
|
||||
adding the necessary export LD_LIBRARY_PATH statement.
|
||||
|
||||
If that doesn't work, try dividing an (hopefully) conquering by temporarily
|
||||
eliminating items such as Apache from the process by adjusting the
|
||||
arguments passed to the ./configure command (i.e., removing --with-apxs).
|
||||
|
||||
If all else fails, "man dlopen" on Unix systems will give more insight on
|
||||
what the system is trying to do internally.
|
||||
|
||||
There have been some issues where users need to create a symbolic link
|
||||
from java.so to libphp_java.so. If you notice a large number of unexplained
|
||||
crashes in your webserver log file, try doing this.
|
||||
@@ -1,190 +0,0 @@
|
||||
dnl
|
||||
dnl $Id$
|
||||
dnl
|
||||
AC_DEFUN(JAVA_FIND_JAR, [
|
||||
AC_MSG_CHECKING([Java Jar location])
|
||||
if test "$PHP_JAVA" = "yes"; then
|
||||
if JAVA_JAR=`which jar 2>/dev/null`; then
|
||||
JAVA_JAR="$JAVA_JAR cf"
|
||||
else
|
||||
JAVA_JAR=
|
||||
fi
|
||||
PHP_JAVA=`cd \`dirname \\\`which javac\\\`\`/..;pwd`
|
||||
|
||||
dnl
|
||||
dnl substitue zip for systems which don't have jar
|
||||
dnl
|
||||
if test -z "$JAVA_JAR"; then
|
||||
JAVA_JAR='zip -q0'
|
||||
fi
|
||||
else
|
||||
dnl
|
||||
dnl we have a custom path defined so use it
|
||||
dnl
|
||||
if test -x $PHP_JAVA/bin/jar; then
|
||||
JAVA_JAR="$PHP_JAVA/bin/jar cf"
|
||||
else
|
||||
AC_MSG_ERROR([Unable to locate $PHP_JAVA/bin])
|
||||
fi
|
||||
fi
|
||||
PHP_SUBST(JAVA_JAR)
|
||||
AC_MSG_RESULT([$JAVA_JAR])
|
||||
])
|
||||
|
||||
AC_DEFUN(JAVA_FIND_C, [
|
||||
AC_MSG_CHECKING([Java C location])
|
||||
if test "$PHP_JAVA" = "yes"; then
|
||||
JAVA_C=`which javac`
|
||||
else
|
||||
dnl
|
||||
dnl We've been given a path to use, so use it
|
||||
dnl
|
||||
if test -x $PHP_JAVA/bin/javac; then
|
||||
JAVA_C=$PHP_JAVA/bin/javac
|
||||
else
|
||||
AC_MSG_ERROR([Unable to locate $PHP_JAVA/bin])
|
||||
fi
|
||||
fi
|
||||
if test -z "$JAVA_C"; then
|
||||
AC_MSG_ERROR([Unable to locate the javac binary in your system path
|
||||
Either adjust your Java installation or provide the Java installation path,
|
||||
e.g. --with-java=/java expecting /java/bin/ to contain the binaries])
|
||||
fi
|
||||
|
||||
PHP_SUBST(JAVA_C)
|
||||
AC_MSG_RESULT([$JAVA_C])
|
||||
])
|
||||
|
||||
AC_DEFUN(JAVA_CHECK_LIB, [
|
||||
AC_MSG_CHECKING([Checking for libjava])
|
||||
if test -d $PHP_JAVA/lib/kaffe; then
|
||||
PHP_ADD_LIBPATH($PHP_JAVA/lib)
|
||||
JAVA_CFLAGS=-DKAFFE
|
||||
JAVA_INCLUDE=-I$PHP_JAVA/include/kaffe
|
||||
JAVA_CLASSPATH=$PHP_JAVA/share/kaffe/Klasses.jar
|
||||
JAVA_LIB=kaffevm
|
||||
JAVA_LIBPATH=$PHP_JAVA/lib/kaffe
|
||||
java_libext=kaffevm
|
||||
|
||||
test -f $PHP_JAVA/lib/$JAVA_LIB && JAVA_LIBPATH=$PHP_JAVA/lib
|
||||
test -f $PHP_JAVA/lib/kaffe/$JAVA_LIB && JAVA_LIBPATH=$PHP_JAVA/lib/kaffe
|
||||
|
||||
dnl
|
||||
dnl accomodate old versions of kaffe which don't support jar
|
||||
dnl
|
||||
if kaffe -version 2>&1 | grep 1.0b > /dev/null; then
|
||||
JAVA_JAR='zip -q0'
|
||||
fi
|
||||
elif test -f $PHP_JAVA/lib/$java_libext; then
|
||||
JAVA_LIB=java
|
||||
JAVA_LIBPATH=$PHP_JAVA/lib
|
||||
JAVA_INCLUDE=-I$PHP_JAVA/include
|
||||
|
||||
test -f $PHP_JAVA/lib/classes.zip && JAVA_CFLAGS=-DJNI_11
|
||||
test -f $PHP_JAVA/lib/jvm.jar && JAVA_CFLAGS=-DJNI_12
|
||||
test -f $PHP_JAVA/lib/classes.zip && JAVA_CLASSPATH=$PHP_JAVA/lib/classes.zip
|
||||
test -f $PHP_JAVA/lib/jvm.jar && JAVA_CLASSPATH=$PHP_JAVA/lib/jvm.jar
|
||||
|
||||
for i in $PHP_JAVA/include/*; do
|
||||
test -f $i/jni_md.h && JAVA_INCLUDE="$JAVA_INCLUDE $i"
|
||||
done
|
||||
dnl
|
||||
dnl sample JDK v 1.4 path
|
||||
dnl /usr/java/j2sdk1.4.0_01/jre/lib/i386/libjava.so
|
||||
dnl
|
||||
else
|
||||
dnl
|
||||
dnl We have to find everything
|
||||
dnl
|
||||
for i in `find $PHP_JAVA/include -type d`; do
|
||||
test -f $i/jni.h && JAVA_INCLUDE="$JAVA_INCLUDE -I$i"
|
||||
test -f $i/jni_md.h && JAVA_INCLUDE="$JAVA_INCLUDE -I$i"
|
||||
done
|
||||
|
||||
for i in `find $PHP_JAVA/ -type d`; do
|
||||
test -f $i/classes.zip && JAVA_CFLAGS=-DJNI_11
|
||||
test -f $i/rt.jar && JAVA_CFLAGS=-DJNI_12
|
||||
test -f $i/classes.zip && JAVA_CLASSPATH=$i/classes.zip
|
||||
test -f $i/rt.jar && JAVA_CLASSPATH=$i/rt.jar
|
||||
|
||||
if test -f $i/$java_libext; then
|
||||
JAVA_LIB=java
|
||||
JAVA_LIBPATH=$i
|
||||
|
||||
test -d $i/hotspot && PHP_ADD_LIBPATH($i/hotspot)
|
||||
test -d $i/classic && PHP_ADD_LIBPATH($i/classic)
|
||||
test -d $i/server && PHP_ADD_LIBPATH($i/server)
|
||||
test -d $i/native_threads && PHP_ADD_LIBPATH($i/native_threads)
|
||||
fi
|
||||
done
|
||||
|
||||
if test -z "$JAVA_INCLUDE"; then
|
||||
AC_MSG_RESULT(no)
|
||||
AC_MSG_ERROR(unable to find Java VM includes)
|
||||
fi
|
||||
|
||||
JAVA_CFLAGS="$JAVA_CFLAGS -D_REENTRANT"
|
||||
fi
|
||||
|
||||
AC_MSG_RESULT([$JAVA_LIBPATH])
|
||||
])
|
||||
|
||||
|
||||
PHP_ARG_WITH(java, for Java support,
|
||||
[ --with-java[=DIR] Include Java support. DIR is the JDK base install directory.
|
||||
This extension is always built as shared.])
|
||||
|
||||
if test "$PHP_JAVA" != "no"; then
|
||||
platform=`uname -s 2>/dev/null`
|
||||
java_libext=libjava.so
|
||||
case $platform in
|
||||
AIX) java_libext=libjava.a ;;
|
||||
HP-UX) java_libext=libjava.sl ;;
|
||||
Darwin) java_libext=libjava.jnilib ;;
|
||||
esac
|
||||
JAVA_FIND_JAR()
|
||||
JAVA_FIND_C()
|
||||
|
||||
if test "$platform" = "Darwin"; then
|
||||
AC_CHECK_HEADERS([JavaVM/JavaVM.h])
|
||||
AC_CHECK_HEADERS([JavaVM/jni.h])
|
||||
dnl JAVA_CLASSPATH=/System/Library/Frameworks/JavaVM.framework/Classes/classes.jar
|
||||
PHP_CHECK_FRAMEWORK("JavaVM", JNI_CreateJavaVM,[AC_DEFINE(HAVE_JAVA,1,[ ])])
|
||||
PHP_ADD_FRAMEWORK("JavaVM")
|
||||
JAVA_CFLAGS="-x objective-c"
|
||||
else
|
||||
JAVA_CHECK_LIB()
|
||||
AC_DEFINE(HAVE_JAVA,1,[ ])
|
||||
|
||||
if test -z "$JAVA_LIBPATH"; then
|
||||
AC_MSG_ERROR([unable to find Java VM libraries in $PHP_JAVA])
|
||||
fi
|
||||
|
||||
PHP_ADD_LIBPATH($JAVA_LIBPATH)
|
||||
JAVA_CFLAGS="$JAVA_CFLAGS '-DJAVALIB=\"$JAVA_LIBPATH/$java_libext\"'"
|
||||
fi
|
||||
|
||||
if test "$PHP_SAPI" != "servlet"; then
|
||||
PHP_NEW_EXTENSION(java, java.c, shared,, $JAVA_CFLAGS $JAVA_INCLUDE)
|
||||
|
||||
if test "$PHP_SAPI" = "cgi"; then
|
||||
if test "$platform" != "Darwin"; then
|
||||
PHP_ADD_LIBRARY($JAVA_LIB)
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -n "$INSTALL_IT"; then
|
||||
INSTALL_IT="$INSTALL_IT ;"
|
||||
fi
|
||||
|
||||
INSTALL_IT="$INSTALL_IT \$(srcdir)/build/shtool mkdir -p -f -m 0755 \$(INSTALL_ROOT)\$(libdir)"
|
||||
INSTALL_IT="$INSTALL_IT ; \$(INSTALL) -m 0755 \$(srcdir)/ext/java/php_java.jar \$(INSTALL_ROOT)\$(libdir)"
|
||||
fi
|
||||
|
||||
PHP_SUBST(JAVA_CLASSPATH)
|
||||
PHP_SUBST(JAVA_INCLUDE)
|
||||
PHP_SUBST(JAVA_CFLAGS)
|
||||
|
||||
PHP_ADD_MAKEFILE_FRAGMENT
|
||||
fi
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
<?
|
||||
$stack=new Java("java.util.Stack");
|
||||
$stack->push(1);
|
||||
|
||||
#
|
||||
# Should succeed and print out "1"
|
||||
#
|
||||
$result = $stack->pop();
|
||||
$ex = java_last_exception_get();
|
||||
if (!$ex) print "$result\n";
|
||||
|
||||
#
|
||||
# Should fail - note the "@" eliminates the warning
|
||||
#
|
||||
$result=@$stack->pop();
|
||||
$ex=java_last_exception_get();
|
||||
if ($ex) print $ex->toString();
|
||||
|
||||
#
|
||||
# Reset last exception
|
||||
#
|
||||
java_last_exception_clear();
|
||||
?>
|
||||
@@ -1,862 +0,0 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 4 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2003 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.0 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_0.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: Sam Ruby (rubys@us.ibm.com) |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* This module implements Zend OO syntax overloading support for Java
|
||||
* components using JNI and reflection.
|
||||
*/
|
||||
|
||||
#include "php.h"
|
||||
#include "zend_compile.h"
|
||||
#include "php_ini.h"
|
||||
#include "php_globals.h"
|
||||
|
||||
#if HAVE_JAVAVM_JAVAVM_H
|
||||
#include <JavaVM/JavaVM.h>
|
||||
#include <JavaVM/jni.h>
|
||||
#define JNI_12
|
||||
#else
|
||||
#include <jni.h>
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef PHP_WIN32
|
||||
#include "win32/winutil.h"
|
||||
#define DL_ERROR php_win_err
|
||||
#endif
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define IS_EXCEPTION 86
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
#ifndef KAFFE
|
||||
#ifndef JNI_11
|
||||
#ifndef JNI_12
|
||||
|
||||
#ifdef JNI_VERSION_1_2
|
||||
#define JNI_12
|
||||
#else
|
||||
#define JNI_11
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef PHP_WIN32
|
||||
#ifdef JNI_12
|
||||
#define JAVALIB "jvm.dll"
|
||||
#else
|
||||
#define JAVALIB "javai.dll"
|
||||
#endif
|
||||
#else
|
||||
#endif
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
static int le_jobject = 0;
|
||||
|
||||
static char *classpath = 0;
|
||||
static char *libpath = 0;
|
||||
static char *javahome = 0;
|
||||
static char *javalib = 0;
|
||||
|
||||
static void *dl_handle = 0;
|
||||
|
||||
/* {{{ ZEND_BEGIN_MODULE_GLOBALS
|
||||
*/
|
||||
ZEND_BEGIN_MODULE_GLOBALS(java)
|
||||
JavaVM *jvm;
|
||||
JNIEnv *jenv;
|
||||
jobject php_reflect;
|
||||
jclass reflect_class;
|
||||
ZEND_END_MODULE_GLOBALS(java)
|
||||
/* }}} */
|
||||
|
||||
#ifdef ZTS
|
||||
# define JG(v) TSRMG(java_globals_id, zend_java_globals *, v)
|
||||
#else
|
||||
# define JG(v) (java_globals.v)
|
||||
#endif
|
||||
|
||||
ZEND_DECLARE_MODULE_GLOBALS(java)
|
||||
|
||||
static zend_class_entry java_class_entry;
|
||||
|
||||
static PHP_INI_MH(OnIniUpdate)
|
||||
{
|
||||
if (new_value) *(char**)mh_arg1 = new_value;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/* {{{ PHP_INI_BEGIN
|
||||
*/
|
||||
PHP_INI_BEGIN()
|
||||
PHP_INI_ENTRY1("java.class.path", NULL, PHP_INI_SYSTEM, OnIniUpdate, &classpath)
|
||||
#ifndef JNI_11
|
||||
PHP_INI_ENTRY1("java.home", NULL, PHP_INI_SYSTEM, OnIniUpdate, &javahome)
|
||||
PHP_INI_ENTRY1("java.library.path", NULL, PHP_INI_SYSTEM,OnIniUpdate, &libpath)
|
||||
#endif
|
||||
#ifdef JAVALIB
|
||||
PHP_INI_ENTRY1("java.library", JAVALIB, PHP_INI_SYSTEM, OnIniUpdate, &javalib)
|
||||
#else
|
||||
PHP_INI_ENTRY1("java.library", NULL, PHP_INI_SYSTEM, OnIniUpdate, &javalib)
|
||||
#endif
|
||||
PHP_INI_END()
|
||||
/* }}} */
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
/* {{{ jvm_destroy
|
||||
*/
|
||||
/*
|
||||
* Destroy a Java Virtual Machine.
|
||||
*/
|
||||
void jvm_destroy(TSRMLS_D)
|
||||
{
|
||||
if (JG(php_reflect)) (*JG(jenv))->DeleteGlobalRef(JG(jenv), JG(php_reflect));
|
||||
JG(php_reflect) = 0;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ addJVMOption
|
||||
*/
|
||||
/*
|
||||
* Create a Java Virtual Machine.
|
||||
* - class.path, home, and library.path are read out of the INI file
|
||||
* - appropriate (pre 1.1, JDK 1.1, and JDK 1.2) initialization is performed
|
||||
* - net.php.reflect class file is located
|
||||
*/
|
||||
|
||||
#ifdef JNI_12
|
||||
static void addJVMOption(JavaVMInitArgs *vm_args, char *name, char *value)
|
||||
{
|
||||
char *option = (char*) malloc(strlen(name) + strlen(value) + 1);
|
||||
strcpy(option, name);
|
||||
strcat(option, value);
|
||||
vm_args->options[vm_args->nOptions++].optionString = option;
|
||||
}
|
||||
#endif
|
||||
/* }}} */
|
||||
|
||||
/* {{{ jvm_create
|
||||
*/
|
||||
static int jvm_create(TSRMLS_D)
|
||||
{
|
||||
int rc;
|
||||
jobject local_php_reflect;
|
||||
jthrowable error;
|
||||
|
||||
jint (JNICALL *JNI_CreateVM)(const void*, const void*, void*);
|
||||
#ifndef JNI_12
|
||||
jint (JNICALL *JNI_DefaultArgs)(void*);
|
||||
#endif
|
||||
|
||||
#ifdef JNI_11
|
||||
JDK1_1InitArgs vm_args;
|
||||
#else
|
||||
JavaVMInitArgs vm_args;
|
||||
#ifdef JNI_12
|
||||
JavaVMOption options[3];
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
if (javalib) {
|
||||
dl_handle = DL_LOAD(javalib);
|
||||
|
||||
if (!dl_handle) {
|
||||
php_error_docref(NULL TSRMLS_CC, E_ERROR, "Unable to load Java Library %s, error: %s", javalib, DL_ERROR());
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef JAVALIB
|
||||
if (!dl_handle)
|
||||
JNI_CreateVM = &JNI_CreateJavaVM;
|
||||
else
|
||||
#endif
|
||||
|
||||
JNI_CreateVM = (jint (JNICALL *)(const void*, const void*, void*))
|
||||
DL_FETCH_SYMBOL(dl_handle, "JNI_CreateJavaVM");
|
||||
|
||||
if (!JNI_CreateVM) {
|
||||
php_error_docref(NULL TSRMLS_CC, E_ERROR, "Unable to locate CreateJavaVM function");
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef JNI_12
|
||||
|
||||
vm_args.version = JNI_VERSION_1_2;
|
||||
vm_args.ignoreUnrecognized = JNI_FALSE;
|
||||
vm_args.options = options;
|
||||
vm_args.nOptions = 0;
|
||||
|
||||
if (classpath) addJVMOption(&vm_args, "-Djava.class.path=", classpath);
|
||||
if (javahome) addJVMOption(&vm_args, "-Djava.home=", javahome);
|
||||
if (libpath) addJVMOption(&vm_args, "-Djava.library.path=", libpath);
|
||||
|
||||
#else
|
||||
|
||||
#ifndef JAVALIB
|
||||
if (!dl_handle)
|
||||
JNI_DefaultArgs = &JNI_GetDefaultJavaVMInitArgs;
|
||||
else
|
||||
#endif
|
||||
|
||||
JNI_DefaultArgs = (jint (JNICALL *)(void*))
|
||||
DL_FETCH_SYMBOL(dl_handle, "JNI_GetDefaultJavaVMInitArgs");
|
||||
|
||||
if (!JNI_DefaultArgs) {
|
||||
php_error_docref(NULL TSRMLS_CC, E_ERROR, "Unable to locate GetDefaultJavaVMInitArgs function");
|
||||
return -1;
|
||||
}
|
||||
|
||||
vm_args.version=0x00010001;
|
||||
(*JNI_DefaultArgs)(&vm_args);
|
||||
|
||||
if (!classpath) classpath = "";
|
||||
vm_args.classpath = classpath;
|
||||
#ifdef KAFFE
|
||||
vm_args.classhome = javahome;
|
||||
vm_args.libraryhome = libpath;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
rc = (*JNI_CreateVM)(&JG(jvm), &JG(jenv), &vm_args);
|
||||
|
||||
if (rc) {
|
||||
php_error_docref(NULL TSRMLS_CC, E_ERROR, "Unable to create Java Virtual Machine");
|
||||
return rc;
|
||||
}
|
||||
|
||||
JG(reflect_class) = (*JG(jenv))->FindClass(JG(jenv), "net/php/reflect");
|
||||
error = (*JG(jenv))->ExceptionOccurred(JG(jenv));
|
||||
if (error) {
|
||||
jclass errClass;
|
||||
jmethodID toString;
|
||||
jobject errString;
|
||||
const char *errAsUTF;
|
||||
jboolean isCopy;
|
||||
JNIEnv *jenv = JG(jenv);
|
||||
(*jenv)->ExceptionClear(jenv);
|
||||
errClass = (*jenv)->GetObjectClass(jenv, error);
|
||||
toString = (*jenv)->GetMethodID(jenv, errClass, "toString",
|
||||
"()Ljava/lang/String;");
|
||||
errString = (*jenv)->CallObjectMethod(jenv, error, toString);
|
||||
errAsUTF = (*jenv)->GetStringUTFChars(jenv, errString, &isCopy);
|
||||
php_error_docref(NULL TSRMLS_CC, E_ERROR, "%s", errAsUTF);
|
||||
if (isCopy) (*jenv)->ReleaseStringUTFChars(jenv, error, errAsUTF);
|
||||
jvm_destroy(TSRMLS_C);
|
||||
return -1;
|
||||
}
|
||||
|
||||
local_php_reflect = (*JG(jenv))->AllocObject(JG(jenv), JG(reflect_class));
|
||||
JG(php_reflect) = (*JG(jenv))->NewGlobalRef(JG(jenv), local_php_reflect);
|
||||
return rc;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
/* {{{ _java_makeObject
|
||||
*/
|
||||
static jobject _java_makeObject(pval* arg TSRMLS_DC)
|
||||
{
|
||||
JNIEnv *jenv = JG(jenv);
|
||||
jobject result;
|
||||
pval **handle;
|
||||
int type;
|
||||
jmethodID makeArg;
|
||||
jclass hashClass;
|
||||
|
||||
switch (Z_TYPE_P(arg)) {
|
||||
case IS_STRING:
|
||||
result=(*jenv)->NewByteArray(jenv, Z_STRLEN_P(arg));
|
||||
(*jenv)->SetByteArrayRegion(jenv, (jbyteArray)result, 0,
|
||||
Z_STRLEN_P(arg), Z_STRVAL_P(arg));
|
||||
break;
|
||||
|
||||
case IS_OBJECT:
|
||||
zend_hash_index_find(Z_OBJPROP_P(arg), 0, (void*)&handle);
|
||||
result = zend_list_find(Z_LVAL_PP(handle), &type);
|
||||
break;
|
||||
|
||||
case IS_BOOL:
|
||||
makeArg = (*jenv)->GetMethodID(jenv, JG(reflect_class), "MakeArg",
|
||||
"(Z)Ljava/lang/Object;");
|
||||
result = (*jenv)->CallObjectMethod(jenv, JG(php_reflect), makeArg,
|
||||
(jboolean)(Z_LVAL_P(arg)));
|
||||
break;
|
||||
|
||||
case IS_LONG:
|
||||
makeArg = (*jenv)->GetMethodID(jenv, JG(reflect_class), "MakeArg",
|
||||
"(J)Ljava/lang/Object;");
|
||||
result = (*jenv)->CallObjectMethod(jenv, JG(php_reflect), makeArg,
|
||||
(jlong)(Z_LVAL_P(arg)));
|
||||
break;
|
||||
|
||||
case IS_DOUBLE:
|
||||
makeArg = (*jenv)->GetMethodID(jenv, JG(reflect_class), "MakeArg",
|
||||
"(D)Ljava/lang/Object;");
|
||||
result = (*jenv)->CallObjectMethod(jenv, JG(php_reflect), makeArg,
|
||||
(jdouble)(Z_DVAL_P(arg)));
|
||||
break;
|
||||
|
||||
case IS_ARRAY:
|
||||
{
|
||||
jobject jkey, jval;
|
||||
zval **value;
|
||||
zval key;
|
||||
char *string_key;
|
||||
ulong num_key;
|
||||
jobject jold;
|
||||
jmethodID put, init;
|
||||
|
||||
hashClass = (*jenv)->FindClass(jenv, "java/util/Hashtable");
|
||||
init = (*jenv)->GetMethodID(jenv, hashClass, "<init>", "()V");
|
||||
result = (*jenv)->NewObject(jenv, hashClass, init);
|
||||
|
||||
put = (*jenv)->GetMethodID(jenv, hashClass, "put",
|
||||
"(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
|
||||
|
||||
/* Iterate through hash */
|
||||
zend_hash_internal_pointer_reset(Z_ARRVAL_P(arg));
|
||||
while(zend_hash_get_current_data(Z_ARRVAL_P(arg), (void**)&value) == SUCCESS) {
|
||||
jval = _java_makeObject(*value TSRMLS_CC);
|
||||
|
||||
switch (zend_hash_get_current_key(Z_ARRVAL_P(arg), &string_key, &num_key, 0)) {
|
||||
case HASH_KEY_IS_STRING:
|
||||
Z_TYPE(key) = IS_STRING;
|
||||
Z_STRVAL(key) = string_key;
|
||||
Z_STRLEN(key) = strlen(string_key);
|
||||
jkey = _java_makeObject(&key TSRMLS_CC);
|
||||
break;
|
||||
case HASH_KEY_IS_LONG:
|
||||
Z_TYPE(key) = IS_LONG;
|
||||
Z_LVAL(key) = num_key;
|
||||
jkey = _java_makeObject(&key TSRMLS_CC);
|
||||
break;
|
||||
default: /* HASH_KEY_NON_EXISTANT */
|
||||
jkey = 0;
|
||||
}
|
||||
jold = (*jenv)->CallObjectMethod(jenv, result, put, jkey, jval);
|
||||
if (Z_TYPE_PP(value) != IS_OBJECT) (*jenv)->DeleteLocalRef(jenv, jval);
|
||||
zend_hash_move_forward(Z_ARRVAL_P(arg));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
result=0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
/* {{{ _java_makeArray
|
||||
*/
|
||||
static jobjectArray _java_makeArray(int argc, pval** argv TSRMLS_DC)
|
||||
{
|
||||
JNIEnv *jenv = JG(jenv);
|
||||
|
||||
jclass objectClass = (*jenv)->FindClass(jenv, "java/lang/Object");
|
||||
jobjectArray result = (*jenv)->NewObjectArray(jenv, argc, objectClass, 0);
|
||||
jobject arg;
|
||||
int i;
|
||||
|
||||
for (i=0; i<argc; i++) {
|
||||
arg = _java_makeObject(argv[i] TSRMLS_CC);
|
||||
(*jenv)->SetObjectArrayElement(jenv, result, i, arg);
|
||||
if (Z_TYPE_P(argv[i]) != IS_OBJECT) (*jenv)->DeleteLocalRef(jenv, arg);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ checkError
|
||||
*/
|
||||
static int checkError(pval *value TSRMLS_DC)
|
||||
{
|
||||
if (Z_TYPE_P(value) == IS_EXCEPTION) {
|
||||
php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", Z_STRVAL_P(value));
|
||||
efree(Z_STRVAL_P(value));
|
||||
ZVAL_FALSE(value);
|
||||
return 1;
|
||||
};
|
||||
return 0;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
/* {{{ java_call_function_handler
|
||||
*/
|
||||
/*
|
||||
* Invoke a method on an object. If method name is "java", create a new
|
||||
* object instead.
|
||||
*/
|
||||
void java_call_function_handler(INTERNAL_FUNCTION_PARAMETERS, zend_property_reference *property_reference)
|
||||
{
|
||||
JNIEnv *jenv;
|
||||
|
||||
pval *object = property_reference->object;
|
||||
zend_overloaded_element *function_name = (zend_overloaded_element *)
|
||||
property_reference->elements_list->tail->data;
|
||||
|
||||
int arg_count = ZEND_NUM_ARGS();
|
||||
jlong result = 0;
|
||||
zval ***arguments = (zval ***) emalloc(sizeof(zval *)*arg_count);
|
||||
|
||||
zend_get_parameters_array_ex(arg_count, arguments);
|
||||
|
||||
if (!JG(jenv)) jvm_create(TSRMLS_C);
|
||||
if (!JG(jenv)) return;
|
||||
jenv = JG(jenv);
|
||||
|
||||
if (!strcmp("java", Z_STRVAL(function_name->element))) {
|
||||
|
||||
/* construct a Java object:
|
||||
First argument is the class name. Any additional arguments will
|
||||
be treated as constructor parameters. */
|
||||
|
||||
jmethodID co = (*jenv)->GetMethodID(jenv, JG(reflect_class), "CreateObject",
|
||||
"(Ljava/lang/String;[Ljava/lang/Object;J)V");
|
||||
jstring className;
|
||||
result = (jlong)(long)object;
|
||||
|
||||
if (ZEND_NUM_ARGS() < 1) {
|
||||
php_error_docref(NULL TSRMLS_CC, E_ERROR, "Missing classname in new Java() call");
|
||||
return;
|
||||
}
|
||||
|
||||
className=(*jenv)->NewStringUTF(jenv, Z_STRVAL_PP(arguments[0]));
|
||||
(*jenv)->CallVoidMethod(jenv, JG(php_reflect), co,
|
||||
className, _java_makeArray(arg_count-1, *(arguments+1) TSRMLS_CC), result);
|
||||
|
||||
(*jenv)->DeleteLocalRef(jenv, className);
|
||||
|
||||
} else {
|
||||
|
||||
pval **handle;
|
||||
int type;
|
||||
jobject obj;
|
||||
jstring method;
|
||||
|
||||
/* invoke a method on the given object */
|
||||
|
||||
jmethodID invoke = (*jenv)->GetMethodID(jenv, JG(reflect_class), "Invoke",
|
||||
"(Ljava/lang/Object;Ljava/lang/String;[Ljava/lang/Object;J)V");
|
||||
zend_hash_index_find(Z_OBJPROP_P(object), 0, (void**) &handle);
|
||||
obj = zend_list_find(Z_LVAL_PP(handle), &type);
|
||||
method = (*jenv)->NewStringUTF(jenv, Z_STRVAL(function_name->element));
|
||||
result = (jlong)(long)return_value;
|
||||
|
||||
(*jenv)->CallVoidMethod(jenv, JG(php_reflect), invoke,
|
||||
obj, method, _java_makeArray(arg_count, *arguments TSRMLS_CC), result);
|
||||
|
||||
(*jenv)->DeleteLocalRef(jenv, method);
|
||||
|
||||
}
|
||||
|
||||
efree(arguments);
|
||||
pval_destructor(&function_name->element);
|
||||
|
||||
checkError((pval*)(long)result TSRMLS_CC);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
/* {{{ proto object java_last_exception_get(void)
|
||||
Get last Java exception */
|
||||
PHP_FUNCTION(java_last_exception_get)
|
||||
{
|
||||
jlong result = 0;
|
||||
jmethodID lastEx;
|
||||
|
||||
if (ZEND_NUM_ARGS()!=0) WRONG_PARAM_COUNT;
|
||||
|
||||
result = (jlong)(long)return_value;
|
||||
|
||||
lastEx = (*JG(jenv))->GetMethodID(JG(jenv), JG(reflect_class),
|
||||
"lastException", "(J)V");
|
||||
|
||||
(*JG(jenv))->CallVoidMethod(JG(jenv), JG(php_reflect), lastEx, result);
|
||||
}
|
||||
|
||||
/* }}} */
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
/* {{{ proto void java_last_exception_clear(void)
|
||||
Clear last java extension */
|
||||
PHP_FUNCTION(java_last_exception_clear)
|
||||
{
|
||||
jlong result = 0;
|
||||
jmethodID clearEx;
|
||||
|
||||
if (ZEND_NUM_ARGS()!=0) WRONG_PARAM_COUNT;
|
||||
|
||||
result = (jlong)(long)return_value;
|
||||
|
||||
clearEx = (*JG(jenv))->GetMethodID(JG(jenv), JG(reflect_class),
|
||||
"clearException", "()V");
|
||||
|
||||
(*JG(jenv))->CallVoidMethod(JG(jenv), JG(php_reflect), clearEx);
|
||||
}
|
||||
|
||||
/* }}} */
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
/* {{{ _java_getset_property
|
||||
*/
|
||||
static pval _java_getset_property
|
||||
(zend_property_reference *property_reference, jobjectArray value TSRMLS_DC)
|
||||
{
|
||||
pval presult;
|
||||
jlong result = 0;
|
||||
pval **pobject;
|
||||
jobject obj;
|
||||
int type;
|
||||
|
||||
/* get the property name */
|
||||
zend_llist_element *element = property_reference->elements_list->head;
|
||||
zend_overloaded_element *property=(zend_overloaded_element *)element->data;
|
||||
jstring propName;
|
||||
|
||||
JNIEnv *jenv;
|
||||
jenv = JG(jenv);
|
||||
|
||||
propName = (*jenv)->NewStringUTF(jenv, Z_STRVAL(property->element));
|
||||
|
||||
/* get the object */
|
||||
zend_hash_index_find(Z_OBJPROP_P(property_reference->object),
|
||||
0, (void **) &pobject);
|
||||
obj = zend_list_find(Z_LVAL_PP(pobject), &type);
|
||||
result = (jlong)(long) &presult;
|
||||
Z_TYPE(presult) = IS_NULL;
|
||||
|
||||
if (!obj || (type!=le_jobject)) {
|
||||
php_error_docref(NULL TSRMLS_CC, E_ERROR, "Attempt to access a Java property on a non-Java object");
|
||||
} else {
|
||||
/* invoke the method */
|
||||
jmethodID gsp = (*jenv)->GetMethodID(jenv, JG(reflect_class), "GetSetProp",
|
||||
"(Ljava/lang/Object;Ljava/lang/String;[Ljava/lang/Object;J)V");
|
||||
(*jenv)->CallVoidMethod
|
||||
(jenv, JG(php_reflect), gsp, obj, propName, value, result);
|
||||
}
|
||||
|
||||
(*jenv)->DeleteLocalRef(jenv, propName);
|
||||
pval_destructor(&property->element);
|
||||
return presult;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ java_get_property_handler
|
||||
*/
|
||||
pval java_get_property_handler(zend_property_reference *property_reference)
|
||||
{
|
||||
pval presult;
|
||||
TSRMLS_FETCH();
|
||||
|
||||
presult = _java_getset_property(property_reference, 0 TSRMLS_CC);
|
||||
checkError(&presult TSRMLS_CC);
|
||||
return presult;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ java_set_property_handler
|
||||
*/
|
||||
int java_set_property_handler(zend_property_reference *property_reference, pval *value)
|
||||
{
|
||||
pval presult;
|
||||
TSRMLS_FETCH();
|
||||
|
||||
presult = _java_getset_property(property_reference, _java_makeArray(1, &value TSRMLS_CC) TSRMLS_CC);
|
||||
return checkError(&presult TSRMLS_CC) ? FAILURE : SUCCESS;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
/* {{{ _php_java_destructor
|
||||
*/
|
||||
static void _php_java_destructor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
|
||||
{
|
||||
void *jobject = (void *)rsrc->ptr;
|
||||
|
||||
if (JG(jenv)) (*JG(jenv))->DeleteGlobalRef(JG(jenv), jobject);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ alloc_java_globals_ctor
|
||||
*/
|
||||
static void alloc_java_globals_ctor(zend_java_globals *java_globals TSRMLS_DC)
|
||||
{
|
||||
memset(java_globals, 0, sizeof(zend_java_globals));
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ PHP_MINIT_FUNCTION
|
||||
*/
|
||||
PHP_MINIT_FUNCTION(java)
|
||||
{
|
||||
INIT_OVERLOADED_CLASS_ENTRY(java_class_entry, "java", NULL,
|
||||
java_call_function_handler,
|
||||
java_get_property_handler,
|
||||
java_set_property_handler);
|
||||
|
||||
zend_register_internal_class(&java_class_entry TSRMLS_CC);
|
||||
|
||||
le_jobject = zend_register_list_destructors_ex(_php_java_destructor, NULL, "java", module_number);
|
||||
|
||||
REGISTER_INI_ENTRIES();
|
||||
|
||||
if (!classpath) classpath = getenv("CLASSPATH");
|
||||
|
||||
if (!libpath) {
|
||||
libpath=PG(extension_dir);
|
||||
}
|
||||
|
||||
ZEND_INIT_MODULE_GLOBALS(java, alloc_java_globals_ctor, NULL);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ PHP_MSHUTDOWN_FUNCTION
|
||||
*/
|
||||
PHP_MSHUTDOWN_FUNCTION(java)
|
||||
{
|
||||
UNREGISTER_INI_ENTRIES();
|
||||
if (JG(jvm)) jvm_destroy(TSRMLS_C);
|
||||
return SUCCESS;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
function_entry java_functions[] = {
|
||||
PHP_FE(java_last_exception_get, NULL)
|
||||
PHP_FE(java_last_exception_clear, NULL)
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
|
||||
static PHP_MINFO_FUNCTION(java) {
|
||||
DISPLAY_INI_ENTRIES();
|
||||
}
|
||||
|
||||
zend_module_entry java_module_entry = {
|
||||
STANDARD_MODULE_HEADER,
|
||||
"java",
|
||||
java_functions,
|
||||
PHP_MINIT(java),
|
||||
PHP_MSHUTDOWN(java),
|
||||
NULL,
|
||||
NULL,
|
||||
PHP_MINFO(java),
|
||||
NO_VERSION_YET,
|
||||
STANDARD_MODULE_PROPERTIES
|
||||
};
|
||||
|
||||
ZEND_GET_MODULE(java)
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
/* {{{ Java_net_php_reflect_setResultFromString
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_net_php_reflect_setResultFromString
|
||||
(JNIEnv *jenv, jclass self, jlong result, jbyteArray jvalue)
|
||||
{
|
||||
jboolean isCopy;
|
||||
jbyte *value = (*jenv)->GetByteArrayElements(jenv, jvalue, &isCopy);
|
||||
pval *presult = (pval*)(long)result;
|
||||
Z_TYPE_P(presult)=IS_STRING;
|
||||
Z_STRLEN_P(presult)=(*jenv)->GetArrayLength(jenv, jvalue);
|
||||
Z_STRVAL_P(presult)=emalloc(Z_STRLEN_P(presult)+1);
|
||||
memcpy(Z_STRVAL_P(presult), value, Z_STRLEN_P(presult));
|
||||
Z_STRVAL_P(presult)[Z_STRLEN_P(presult)]=0;
|
||||
if (isCopy) (*jenv)->ReleaseByteArrayElements(jenv, jvalue, value, 0);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ Java_net_php_reflect_setResultFromLong
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_net_php_reflect_setResultFromLong
|
||||
(JNIEnv *jenv, jclass self, jlong result, jlong value)
|
||||
{
|
||||
pval *presult = (pval*)(long)result;
|
||||
Z_TYPE_P(presult)=IS_LONG;
|
||||
Z_LVAL_P(presult)=(long)value;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ Java_net_php_reflect_setResultFromDouble
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_net_php_reflect_setResultFromDouble
|
||||
(JNIEnv *jenv, jclass self, jlong result, jdouble value)
|
||||
{
|
||||
pval *presult = (pval*)(long)result;
|
||||
Z_TYPE_P(presult)=IS_DOUBLE;
|
||||
Z_DVAL_P(presult)=value;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ Java_net_php_reflect_setResultFromBoolean
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_net_php_reflect_setResultFromBoolean
|
||||
(JNIEnv *jenv, jclass self, jlong result, jboolean value)
|
||||
{
|
||||
pval *presult = (pval*)(long)result;
|
||||
Z_TYPE_P(presult)=IS_BOOL;
|
||||
Z_LVAL_P(presult)=value;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ Java_net_php_reflect_setResultFromObject
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_net_php_reflect_setResultFromObject
|
||||
(JNIEnv *jenv, jclass self, jlong result, jobject value)
|
||||
{
|
||||
/* wrapper the java object in a pval object */
|
||||
pval *presult = (pval*)(long)result;
|
||||
pval *handle;
|
||||
TSRMLS_FETCH();
|
||||
|
||||
if (Z_TYPE_P(presult) != IS_OBJECT) {
|
||||
object_init_ex(presult, &java_class_entry);
|
||||
presult->is_ref=1;
|
||||
presult->refcount=1;
|
||||
}
|
||||
|
||||
ALLOC_ZVAL(handle);
|
||||
Z_TYPE_P(handle) = IS_LONG;
|
||||
Z_LVAL_P(handle) =
|
||||
zend_list_insert((*jenv)->NewGlobalRef(jenv, value), le_jobject);
|
||||
pval_copy_constructor(handle);
|
||||
INIT_PZVAL(handle);
|
||||
zend_hash_index_update(Z_OBJPROP_P(presult), 0, &handle, sizeof(pval *), NULL);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ Java_net_php_reflect_setResultFromArray
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_net_php_reflect_setResultFromArray
|
||||
(JNIEnv *jenv, jclass self, jlong result)
|
||||
{
|
||||
array_init( (pval*)(long)result );
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ Java_net_php_reflect_nextElement
|
||||
*/
|
||||
JNIEXPORT jlong JNICALL Java_net_php_reflect_nextElement
|
||||
(JNIEnv *jenv, jclass self, jlong array)
|
||||
{
|
||||
pval *result;
|
||||
pval *handle = (pval*)(long)array;
|
||||
ALLOC_ZVAL(result);
|
||||
zend_hash_next_index_insert(Z_ARRVAL_P(handle), &result, sizeof(zval *), NULL);
|
||||
return (jlong)(long)result;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ Java_net_php_reflect_hashIndexUpdate
|
||||
*/
|
||||
JNIEXPORT jlong JNICALL Java_net_php_reflect_hashIndexUpdate
|
||||
(JNIEnv *jenv, jclass self, jlong array, jlong key)
|
||||
{
|
||||
pval *result;
|
||||
pval *handle = (pval*)(long)array;
|
||||
ALLOC_ZVAL(result);
|
||||
zend_hash_index_update(Z_ARRVAL_P(handle), (unsigned long)key,
|
||||
&result, sizeof(zval *), NULL);
|
||||
return (jlong)(long)result;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ Java_net_php_reflect_hashUpdate
|
||||
*/
|
||||
JNIEXPORT jlong JNICALL Java_net_php_reflect_hashUpdate
|
||||
(JNIEnv *jenv, jclass self, jlong array, jbyteArray key)
|
||||
{
|
||||
pval *result;
|
||||
pval pkey;
|
||||
pval *handle = (pval*)(long)array;
|
||||
ALLOC_ZVAL(result);
|
||||
Java_net_php_reflect_setResultFromString(jenv, self, (jlong)(long)&pkey, key);
|
||||
zend_hash_update(Z_ARRVAL_P(handle), Z_STRVAL(pkey), Z_STRLEN(pkey)+1,
|
||||
&result, sizeof(zval *), NULL);
|
||||
return (jlong)(long)result;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ Java_net_php_reflect_setException
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_net_php_reflect_setException
|
||||
(JNIEnv *jenv, jclass self, jlong result, jbyteArray value)
|
||||
{
|
||||
pval *presult = (pval*)(long)result;
|
||||
Java_net_php_reflect_setResultFromString(jenv, self, result, value);
|
||||
Z_TYPE_P(presult)=IS_EXCEPTION;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ Java_net_php_reflect_setEnv
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_net_php_reflect_setEnv
|
||||
(JNIEnv *newJenv, jclass self TSRMLS_DC)
|
||||
{
|
||||
jobject local_php_reflect;
|
||||
|
||||
JG(jenv)=newJenv;
|
||||
|
||||
if (!self) self = (*JG(jenv))->FindClass(JG(jenv), "net/php/reflect");
|
||||
JG(reflect_class) = self;
|
||||
|
||||
if (JG(php_reflect)) (*JG(jenv))->DeleteGlobalRef(JG(jenv), JG(php_reflect));
|
||||
local_php_reflect = (*JG(jenv))->AllocObject(JG(jenv), JG(reflect_class));
|
||||
JG(php_reflect) = (*JG(jenv))->NewGlobalRef(JG(jenv), local_php_reflect);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* tab-width: 4
|
||||
* c-basic-offset: 4
|
||||
* End:
|
||||
* vim600: sw=4 ts=4 fdm=marker
|
||||
* vim<600: sw=4 ts=4
|
||||
*/
|
||||
@@ -1,254 +0,0 @@
|
||||
# Microsoft Developer Studio Project File - Name="java" - Package Owner=<4>
|
||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
||||
# ** DO NOT EDIT **
|
||||
|
||||
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
|
||||
|
||||
CFG=java - Win32 Debug_TS
|
||||
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
||||
!MESSAGE use the Export Makefile command and run
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "java.mak".
|
||||
!MESSAGE
|
||||
!MESSAGE You can specify a configuration when running NMAKE
|
||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "java.mak" CFG="java - Win32 Debug_TS"
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE "java - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
|
||||
!MESSAGE "java - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
|
||||
!MESSAGE "java - Win32 Debug_TS" (based on "Win32 (x86) Dynamic-Link Library")
|
||||
!MESSAGE "java - Win32 Release_TS" (based on "Win32 (x86) Dynamic-Link Library")
|
||||
!MESSAGE
|
||||
|
||||
# Begin Project
|
||||
# PROP AllowPerConfigDependencies 0
|
||||
# PROP Scc_ProjName ""
|
||||
# PROP Scc_LocalPath ""
|
||||
CPP=cl.exe
|
||||
MTL=midl.exe
|
||||
RSC=rc.exe
|
||||
|
||||
!IF "$(CFG)" == "java - Win32 Release"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "..\..\..\Release"
|
||||
# PROP BASE Intermediate_Dir "..\..\..\Release"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "..\..\..\Release"
|
||||
# PROP Intermediate_Dir "..\..\..\Release"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "PHP_WIN32" /D "ZEND_WIN32" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /YX /FD /c
|
||||
# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\..\.." /I "..\..\..\Zend" /I "$(JAVA_HOME)\include\win32" /I "$(JAVA_HOME)\include" /I "..\..\..\..\bindlib_w32" /D "NDEBUG" /D ZEND_DEBUG=0 /D "PHP_WIN32" /D "ZEND_WIN32" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "COMPILE_DL_JAVA" /D HAVE_JAVA=1 /YX /FD /c
|
||||
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||
# ADD BASE RSC /l 0x40d /d "NDEBUG"
|
||||
# ADD RSC /l 0x40d /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"..\..\..\Release/php_rpc_java.dll" /libpath:"$(JAVA_HOME)\lib" /libpath:"..\..\..\Release"
|
||||
|
||||
!ELSEIF "$(CFG)" == "java - Win32 Debug"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 1
|
||||
# PROP BASE Output_Dir "..\..\..\Debug"
|
||||
# PROP BASE Intermediate_Dir "..\..\..\Debug"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 1
|
||||
# PROP Output_Dir "..\..\..\Debug"
|
||||
# PROP Intermediate_Dir "..\..\..\Debug"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "PHP_WIN32" /D "ZEND_WIN32" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /YX /FD /GZ /c
|
||||
# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\..\.." /I "..\..\..\Zend" /I "$(JAVA_HOME)\include\win32" /I "$(JAVA_HOME)\include" /I "..\..\..\..\bindlib_w32" /D "_DEBUG" /D ZEND_DEBUG=1 /D "PHP_WIN32" /D "ZEND_WIN32" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "COMPILE_DL_JAVA" /D HAVE_JAVA=1 /FR /YX /FD /GZ /c
|
||||
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||
# ADD BASE RSC /l 0x40d /d "_DEBUG"
|
||||
# ADD RSC /l 0x40d /d "_DEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"..\..\..\Debug/php_rpc_java.dll" /pdbtype:sept /libpath:"$(JAVA_HOME)\lib" /libpath:"..\..\..\Debug"
|
||||
|
||||
!ELSEIF "$(CFG)" == "java - Win32 Debug_TS"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 1
|
||||
# PROP BASE Output_Dir "..\..\..\Debug_TS"
|
||||
# PROP BASE Intermediate_Dir "..\..\..\Debug_TS"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 1
|
||||
# PROP Output_Dir "..\..\..\Debug_TS"
|
||||
# PROP Intermediate_Dir "..\..\..\Debug_TS"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\..\.." /I "..\..\..\..\Zend" /I "$(JAVA_HOME)\include\win32" /I "$(JAVA_HOME)\include" /I "..\..\..\..\bindlib_w32" /D "_DEBUG" /D "PHP_WIN32" /D "ZEND_WIN32" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "COMPILE_DL_JAVA" /FR /YX /FD /GZ /c
|
||||
# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\..\..\\" /I "..\..\..\main" /I "..\..\..\TSRM" /I "..\..\..\Zend" /I "$(JAVA_HOME)\include\win32" /I "$(JAVA_HOME)\include" /I "..\..\..\..\bindlib_w32" /D "_DEBUG" /D ZEND_DEBUG=1 /D "ZTS" /D "PHP_WIN32" /D "ZEND_WIN32" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "COMPILE_DL_JAVA" /D HAVE_JAVA=1 /FR /YX /FD /GZ /c
|
||||
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||
# ADD BASE RSC /l 0x40d /d "_DEBUG"
|
||||
# ADD RSC /l 0x40d /d "_DEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib php4ts_debug.lib /nologo /dll /debug /machine:I386 /out:"..\..\..\Debug_TS/php_rpc_java.dll" /pdbtype:sept /libpath:"$(JAVA_HOME)\lib" /libpath:"..\..\..\Debug_TS"
|
||||
|
||||
!ELSEIF "$(CFG)" == "java - Win32 Release_TS"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "..\..\..\Release_TS"
|
||||
# PROP BASE Intermediate_Dir "..\..\..\Release_TS"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "..\..\..\Release_TS"
|
||||
# PROP Intermediate_Dir "..\..\..\Release_TS"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /MD /W3 /GX /O2 /I "..\..\.." /I "..\..\..\..\Zend" /I "$(JAVA_HOME)\include\win32" /I "$(JAVA_HOME)\include" /I "..\..\..\..\bindlib_w32" /D "NDEBUG" /D "PHP_WIN32" /D "ZEND_WIN32" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "COMPILE_DL_JAVA" /YX /FD /c
|
||||
# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\..\..\\" /I "..\..\..\main" /I "..\..\..\TSRM" /I "..\..\..\Zend" /I "$(JAVA_HOME)\include\win32" /I "$(JAVA_HOME)\include" /I "..\..\..\..\bindlib_w32" /D "NDEBUG" /D ZEND_DEBUG=0 /D "ZTS" /D "PHP_WIN32" /D "ZEND_WIN32" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "COMPILE_DL_JAVA" /D HAVE_JAVA=1 /YX /FD /c
|
||||
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||
# ADD BASE RSC /l 0x40d /d "NDEBUG"
|
||||
# ADD RSC /l 0x40d /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib php4ts.lib /nologo /dll /machine:I386 /out:"..\..\..\Release_TS/php_rpc_java.dll" /libpath:"$(JAVA_HOME)\lib" /libpath:"..\..\..\Release_TS" /libpath:"..\..\..\Release_TS_Inline"
|
||||
|
||||
!ENDIF
|
||||
|
||||
# Begin Target
|
||||
|
||||
# Name "java - Win32 Release"
|
||||
# Name "java - Win32 Debug"
|
||||
# Name "java - Win32 Debug_TS"
|
||||
# Name "java - Win32 Release_TS"
|
||||
# Begin Group "Source Files"
|
||||
|
||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\java.c
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Header Files"
|
||||
|
||||
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\php_java.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Java Files"
|
||||
|
||||
# PROP Default_Filter "java"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\reflect.java
|
||||
|
||||
!IF "$(CFG)" == "java - Win32 Release"
|
||||
|
||||
# Begin Custom Build
|
||||
OutDir=.\..\..\..\Release
|
||||
InputPath=.\reflect.java
|
||||
|
||||
"$(OutDir)\php_java.jar" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
|
||||
if not exist net mkdir net
|
||||
if not exist net\php mkdir net\php
|
||||
copy $(InputPath) net\php > nul
|
||||
echo library=php_java>net\php\reflect.properties
|
||||
$(JAVA_HOME)\bin\javac net\php\reflect.java
|
||||
$(JAVA_HOME)\bin\jar c0f $(OutDir)\php_java.jar net\php\*.class net\php\*.properties
|
||||
erase net\php\reflect.*
|
||||
rmdir net\php
|
||||
rmdir net
|
||||
|
||||
# End Custom Build
|
||||
|
||||
!ELSEIF "$(CFG)" == "java - Win32 Debug"
|
||||
|
||||
# Begin Custom Build
|
||||
OutDir=.\..\..\..\Debug
|
||||
InputPath=.\reflect.java
|
||||
|
||||
"$(OutDir)\php_java.jar" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
|
||||
if not exist net mkdir net
|
||||
if not exist net\php mkdir net\php
|
||||
copy $(InputPath) net\php > nul
|
||||
echo library=php_java>net\php\reflect.properties
|
||||
$(JAVA_HOME)\bin\javac -g net\php\reflect.java
|
||||
$(JAVA_HOME)\bin\jar c0f $(OutDir)\php_java.jar net\php\*.class net\php\*.properties
|
||||
erase net\php\reflect.*
|
||||
rmdir net\php
|
||||
rmdir net
|
||||
|
||||
# End Custom Build
|
||||
|
||||
!ELSEIF "$(CFG)" == "java - Win32 Debug_TS"
|
||||
|
||||
# Begin Custom Build
|
||||
OutDir=.\..\..\..\Debug_TS
|
||||
InputPath=.\reflect.java
|
||||
|
||||
"$(OutDir)\php_java.jar" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
|
||||
if not exist net mkdir net
|
||||
if not exist net\php mkdir net\php
|
||||
copy $(InputPath) net\php > nul
|
||||
echo library=php_java>net\php\reflect.properties
|
||||
$(JAVA_HOME)\bin\javac -g net\php\reflect.java
|
||||
$(JAVA_HOME)\bin\jar c0f $(OutDir)\php_java.jar net\php\*.class net\php\*.properties
|
||||
erase net\php\reflect.*
|
||||
rmdir net\php
|
||||
rmdir net
|
||||
|
||||
# End Custom Build
|
||||
|
||||
!ELSEIF "$(CFG)" == "java - Win32 Release_TS"
|
||||
|
||||
# Begin Custom Build
|
||||
OutDir=.\..\..\..\Release_TS
|
||||
InputPath=.\reflect.java
|
||||
|
||||
"$(OutDir)\php_java.jar" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
|
||||
if not exist net mkdir net
|
||||
if not exist net\php mkdir net\php
|
||||
copy $(InputPath) net\php > nul
|
||||
echo library=php_java>net\php\reflect.properties
|
||||
$(JAVA_HOME)\bin\javac net\php\reflect.java
|
||||
$(JAVA_HOME)\bin\jar c0f $(OutDir)\php_java.jar net\php\*.class net\php\*.properties
|
||||
erase net\php\reflect.*
|
||||
rmdir net\php
|
||||
rmdir net
|
||||
|
||||
# End Custom Build
|
||||
|
||||
!ENDIF
|
||||
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\jtest.php
|
||||
# End Source File
|
||||
# End Target
|
||||
# End Project
|
||||
@@ -1,27 +0,0 @@
|
||||
<?
|
||||
|
||||
// This example is only intented to be run as a CGI.
|
||||
|
||||
$frame = new Java("java.awt.Frame", "Zend");
|
||||
$button = new Java("java.awt.Button", "Hello Java world!");
|
||||
$frame->add("North", $button);
|
||||
$frame->validate();
|
||||
$frame->pack();
|
||||
$frame->visible = True;
|
||||
|
||||
$thread = new Java("java.lang.Thread");
|
||||
$thread->sleep(10000);
|
||||
|
||||
$frame->dispose();
|
||||
|
||||
// Odd behavior noted with Sun JVMs:
|
||||
//
|
||||
// 1) $thread->destroy() will fail with a NoSuchMethodError exception.
|
||||
// 2) The call to (*jvm)->DestroyJVM(jvm) made when PHP terminates
|
||||
// will hang, unless _BOTH_ the calls to pack and setVisible above
|
||||
// are removed.
|
||||
//
|
||||
// Even more odd: both effects are seen with a 100% Java implementation
|
||||
// of the above!
|
||||
|
||||
?>
|
||||
@@ -1,17 +0,0 @@
|
||||
<html>
|
||||
<?
|
||||
|
||||
$system = new Java("java.lang.System");
|
||||
print "Java version=".$system->getProperty("java.version")." <br>\n";
|
||||
print "Java vendor=".$system->getProperty("java.vendor")." <p>\n\n";
|
||||
print "OS=".$system->getProperty("os.name")." ".
|
||||
$system->getProperty("os.version")." on ".
|
||||
$system->getProperty("os.arch")." <br>\n";
|
||||
|
||||
$formatter = new Java("java.text.SimpleDateFormat",
|
||||
"EEEE, MMMM dd, yyyy 'at' h:mm:ss a zzzz");
|
||||
|
||||
print $formatter->format(new Java("java.util.Date"))."\n";
|
||||
|
||||
?>
|
||||
</html>
|
||||
@@ -1,419 +0,0 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 4 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2002 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.0 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_0.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: Sam Ruby (rubys@us.ibm.com) |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
package net.php;
|
||||
|
||||
import java.lang.reflect.*;
|
||||
import java.util.*;
|
||||
import java.beans.*;
|
||||
|
||||
public class reflect {
|
||||
|
||||
static { loadLibrary("reflect"); }
|
||||
|
||||
protected static void loadLibrary(String property) {
|
||||
try {
|
||||
ResourceBundle bundle = ResourceBundle.getBundle("net.php."+property);
|
||||
System.loadLibrary(bundle.getString("library"));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Native methods
|
||||
//
|
||||
private static native void setResultFromString(long result, byte value[]);
|
||||
private static native void setResultFromLong(long result, long value);
|
||||
private static native void setResultFromDouble(long result, double value);
|
||||
private static native void setResultFromBoolean(long result, boolean value);
|
||||
private static native void setResultFromObject(long result, Object value);
|
||||
private static native void setResultFromArray(long result);
|
||||
private static native long nextElement(long array);
|
||||
private static native long hashUpdate(long array, byte key[]);
|
||||
private static native long hashIndexUpdate(long array, long key);
|
||||
private static native void setException(long result, byte value[]);
|
||||
public static native void setEnv();
|
||||
|
||||
//
|
||||
// Helper routines which encapsulate the native methods
|
||||
//
|
||||
public static void setResult(long result, Object value) {
|
||||
if (value == null) return;
|
||||
|
||||
if (value instanceof java.lang.String) {
|
||||
|
||||
setResultFromString(result, ((String)value).getBytes());
|
||||
|
||||
} else if (value instanceof java.lang.Number) {
|
||||
|
||||
if (value instanceof java.lang.Integer ||
|
||||
value instanceof java.lang.Short ||
|
||||
value instanceof java.lang.Byte) {
|
||||
setResultFromLong(result, ((Number)value).longValue());
|
||||
} else {
|
||||
/* Float, Double, BigDecimal, BigInteger, Double, Long, ... */
|
||||
setResultFromDouble(result, ((Number)value).doubleValue());
|
||||
}
|
||||
|
||||
} else if (value instanceof java.lang.Boolean) {
|
||||
|
||||
setResultFromBoolean(result, ((Boolean)value).booleanValue());
|
||||
|
||||
} else if (value.getClass().isArray()) {
|
||||
|
||||
long length = Array.getLength(value);
|
||||
setResultFromArray(result);
|
||||
for (int i=0; i<length; i++) {
|
||||
setResult(nextElement(result), Array.get(value, i));
|
||||
}
|
||||
|
||||
} else if (value instanceof java.util.Hashtable) {
|
||||
|
||||
Hashtable ht = (Hashtable) value;
|
||||
setResultFromArray(result);
|
||||
for (Enumeration e = ht.keys(); e.hasMoreElements(); ) {
|
||||
Object key = e.nextElement();
|
||||
long slot;
|
||||
if (key instanceof Number &&
|
||||
!(key instanceof Double || key instanceof Float))
|
||||
slot = hashIndexUpdate(result, ((Number)key).longValue());
|
||||
else
|
||||
slot = hashUpdate(result, key.toString().getBytes());
|
||||
setResult(slot, ht.get(key));
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
setResultFromObject(result, value);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Throwable lastException = null;
|
||||
|
||||
void lastException(long result) {
|
||||
setResult(result, lastException);
|
||||
}
|
||||
|
||||
void clearException() {
|
||||
lastException = null;
|
||||
}
|
||||
|
||||
void setException(long result, Throwable e) {
|
||||
if (e instanceof InvocationTargetException) {
|
||||
Throwable t = ((InvocationTargetException)e).getTargetException();
|
||||
if (t!=null) e=t;
|
||||
}
|
||||
|
||||
lastException = e;
|
||||
setException(result, e.toString().getBytes());
|
||||
}
|
||||
|
||||
//
|
||||
// Create an new instance of a given class
|
||||
//
|
||||
public void CreateObject(String name, Object args[], long result) {
|
||||
try {
|
||||
Vector matches = new Vector();
|
||||
|
||||
Constructor cons[] = Class.forName(name).getConstructors();
|
||||
for (int i=0; i<cons.length; i++) {
|
||||
if (cons[i].getParameterTypes().length == args.length) {
|
||||
matches.addElement(cons[i]);
|
||||
}
|
||||
}
|
||||
|
||||
Constructor selected = (Constructor)select(matches, args);
|
||||
|
||||
if (selected == null) {
|
||||
if (args.length > 0) {
|
||||
throw new InstantiationException("No matching constructor found");
|
||||
} else {
|
||||
// for classes which have no visible constructor, return the class
|
||||
// useful for classes like java.lang.System and java.util.Calendar.
|
||||
setResult(result, Class.forName(name));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Object coercedArgs[] = coerce(selected.getParameterTypes(), args);
|
||||
setResultFromObject(result, selected.newInstance(coercedArgs));
|
||||
|
||||
} catch (Exception e) {
|
||||
setException(result, e);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Select the best match from a list of methods
|
||||
//
|
||||
private static Object select(Vector methods, Object args[]) {
|
||||
if (methods.size() == 1) return methods.firstElement();
|
||||
|
||||
Object selected = null;
|
||||
int best = Integer.MAX_VALUE;
|
||||
|
||||
for (Enumeration e = methods.elements(); e.hasMoreElements(); ) {
|
||||
Object element = e.nextElement();
|
||||
int weight=0;
|
||||
|
||||
Class parms[] = (element instanceof Method) ?
|
||||
((Method)element).getParameterTypes() :
|
||||
((Constructor)element).getParameterTypes();
|
||||
|
||||
for (int i=0; i<parms.length; i++) {
|
||||
if (parms[i].isInstance(args[i])) {
|
||||
for (Class c=parms[i]; (c=c.getSuperclass()) != null; ) {
|
||||
if (!c.isInstance(args[i])) break;
|
||||
weight++;
|
||||
}
|
||||
} else if (parms[i].isAssignableFrom(java.lang.String.class)) {
|
||||
if (!(args[i] instanceof byte[]) && !(args[i] instanceof String))
|
||||
weight+=9999;
|
||||
} else if (parms[i].isArray()) {
|
||||
if (args[i] instanceof java.util.Hashtable)
|
||||
weight+=256;
|
||||
else
|
||||
weight+=9999;
|
||||
} else if (parms[i].isPrimitive()) {
|
||||
Class c=parms[i];
|
||||
if (args[i] instanceof Number) {
|
||||
if (c==Boolean.TYPE) weight+=5;
|
||||
if (c==Character.TYPE) weight+=4;
|
||||
if (c==Byte.TYPE) weight+=3;
|
||||
if (c==Short.TYPE) weight+=2;
|
||||
if (c==Integer.TYPE) weight++;
|
||||
if (c==Float.TYPE) weight++;
|
||||
} else if (args[i] instanceof Boolean) {
|
||||
if (c!=Boolean.TYPE) weight+=9999;
|
||||
} else if (args[i] instanceof String) {
|
||||
if (c== Character.TYPE || ((String)args[i]).length()>0)
|
||||
weight+=((String)args[i]).length();
|
||||
else
|
||||
weight+=64;
|
||||
} else {
|
||||
weight+=9999;
|
||||
}
|
||||
} else {
|
||||
weight+=9999;
|
||||
}
|
||||
}
|
||||
|
||||
if (weight < best) {
|
||||
if (weight == 0) return element;
|
||||
best = weight;
|
||||
selected = element;
|
||||
}
|
||||
}
|
||||
|
||||
return selected;
|
||||
}
|
||||
|
||||
//
|
||||
// Coerce arguments when possible to conform to the argument list.
|
||||
// Java's reflection will automatically do widening conversions,
|
||||
// unfortunately PHP only supports wide formats, so to be practical
|
||||
// some (possibly lossy) conversions are required.
|
||||
//
|
||||
private static Object[] coerce(Class parms[], Object args[]) {
|
||||
Object result[] = args;
|
||||
for (int i=0; i<args.length; i++) {
|
||||
if (args[i] instanceof byte[] && !parms[i].isArray()) {
|
||||
Class c = parms[i];
|
||||
String s = new String((byte[])args[i]);
|
||||
result[i] = s;
|
||||
try {
|
||||
if (c == Boolean.TYPE) result[i]=new Boolean(s);
|
||||
if (c == Byte.TYPE) result[i]=new Byte(s);
|
||||
if (c == Short.TYPE) result[i]=new Short(s);
|
||||
if (c == Integer.TYPE) result[i]=new Integer(s);
|
||||
if (c == Float.TYPE) result[i]=new Float(s);
|
||||
if (c == Long.TYPE) result[i]=new Long(s);
|
||||
if (c == Character.TYPE && s.length()>0)
|
||||
result[i]=new Character(s.charAt(0));
|
||||
} catch (NumberFormatException n) {
|
||||
// oh well, we tried!
|
||||
}
|
||||
} else if (args[i] instanceof Number && parms[i].isPrimitive()) {
|
||||
if (result==args) result=(Object[])result.clone();
|
||||
Class c = parms[i];
|
||||
Number n = (Number)args[i];
|
||||
if (c == Boolean.TYPE) result[i]=new Boolean(0.0!=n.floatValue());
|
||||
if (c == Byte.TYPE) result[i]=new Byte(n.byteValue());
|
||||
if (c == Short.TYPE) result[i]=new Short(n.shortValue());
|
||||
if (c == Integer.TYPE) result[i]=new Integer(n.intValue());
|
||||
if (c == Float.TYPE) result[i]=new Float(n.floatValue());
|
||||
if (c == Long.TYPE && !(n instanceof Long))
|
||||
result[i]=new Long(n.longValue());
|
||||
} else if (args[i] instanceof Hashtable && parms[i].isArray()) {
|
||||
try {
|
||||
Hashtable ht = (Hashtable)args[i];
|
||||
int size = ht.size();
|
||||
|
||||
// Verify that the keys are Long, and determine maximum
|
||||
for (Enumeration e = ht.keys(); e.hasMoreElements(); ) {
|
||||
int index = ((Long)e.nextElement()).intValue();
|
||||
if (index >= size) size = index+1;
|
||||
}
|
||||
|
||||
Object tempArray[] = new Object[size];
|
||||
Class tempTarget[] = new Class[size];
|
||||
Class targetType = parms[i].getComponentType();
|
||||
|
||||
// flatten the hash table into an array
|
||||
for (int j=0; j<size; j++) {
|
||||
tempArray[j] = ht.get(new Long(j));
|
||||
if (tempArray[j] == null && targetType.isPrimitive())
|
||||
throw new Exception("bail");
|
||||
tempTarget[j] = targetType;
|
||||
}
|
||||
|
||||
// coerce individual elements into the target type
|
||||
Object coercedArray[] = coerce(tempTarget, tempArray);
|
||||
|
||||
// copy the results into the desired array type
|
||||
Object array = Array.newInstance(targetType,size);
|
||||
for (int j=0; j<size; j++) {
|
||||
Array.set(array, j, coercedArray[j]);
|
||||
}
|
||||
|
||||
result[i]=array;
|
||||
} catch (Exception e) {
|
||||
// leave result[i] alone...
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//
|
||||
// Invoke a method on a given object
|
||||
//
|
||||
public void Invoke
|
||||
(Object object, String method, Object args[], long result)
|
||||
{
|
||||
try {
|
||||
Vector matches = new Vector();
|
||||
|
||||
// gather
|
||||
for (Class jclass = object.getClass();;jclass=(Class)object) {
|
||||
while (!Modifier.isPublic(jclass.getModifiers())) {
|
||||
// OK, some joker gave us an instance of a non-public class
|
||||
// This often occurs in the case of enumerators
|
||||
// Substitute the first public interface in its place,
|
||||
// and barring that, try the superclass
|
||||
Class interfaces[] = jclass.getInterfaces();
|
||||
jclass=jclass.getSuperclass();
|
||||
for (int i=interfaces.length; i-->0;) {
|
||||
if (Modifier.isPublic(interfaces[i].getModifiers())) {
|
||||
jclass=interfaces[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
Method methods[] = jclass.getMethods();
|
||||
for (int i=0; i<methods.length; i++) {
|
||||
if (methods[i].getName().equalsIgnoreCase(method) &&
|
||||
methods[i].getParameterTypes().length == args.length) {
|
||||
matches.addElement(methods[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// try a second time with the object itself, if it is of type Class
|
||||
if (!(object instanceof Class) || (jclass==object)) break;
|
||||
}
|
||||
|
||||
Method selected = (Method)select(matches, args);
|
||||
if (selected == null) throw new NoSuchMethodException(method);
|
||||
|
||||
Object coercedArgs[] = coerce(selected.getParameterTypes(), args);
|
||||
setResult(result, selected.invoke(object, coercedArgs));
|
||||
|
||||
} catch (Exception e) {
|
||||
setException(result, e);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Get or Set a property
|
||||
//
|
||||
public void GetSetProp
|
||||
(Object object, String prop, Object args[], long result)
|
||||
{
|
||||
try {
|
||||
|
||||
for (Class jclass = object.getClass();;jclass=(Class)object) {
|
||||
while (!Modifier.isPublic(jclass.getModifiers())) {
|
||||
// OK, some joker gave us an instance of a non-public class
|
||||
// Substitute the first public interface in its place,
|
||||
// and barring that, try the superclass
|
||||
Class interfaces[] = jclass.getInterfaces();
|
||||
jclass=jclass.getSuperclass();
|
||||
for (int i=interfaces.length; i-->0;) {
|
||||
if (Modifier.isPublic(interfaces[i].getModifiers())) {
|
||||
jclass=interfaces[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
BeanInfo beanInfo = Introspector.getBeanInfo(jclass);
|
||||
PropertyDescriptor props[] = beanInfo.getPropertyDescriptors();
|
||||
for (int i=0; i<props.length; i++) {
|
||||
if (props[i].getName().equalsIgnoreCase(prop)) {
|
||||
Method method;
|
||||
if (args!=null && args.length>0) {
|
||||
method=props[i].getWriteMethod();
|
||||
args = coerce(method.getParameterTypes(), args);
|
||||
} else {
|
||||
method=props[i].getReadMethod();
|
||||
}
|
||||
setResult(result, method.invoke(object, args));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Field jfields[] = jclass.getFields();
|
||||
for (int i=0; i<jfields.length; i++) {
|
||||
if (jfields[i].getName().equalsIgnoreCase(prop)) {
|
||||
if (args!=null && args.length>0) {
|
||||
args = coerce(new Class[] {jfields[i].getType()}, args);
|
||||
jfields[i].set(object, args[0]);
|
||||
} else {
|
||||
setResult(result, jfields[i].get(object));
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// try a second time with the object itself, if it is of type Class
|
||||
if (!(object instanceof Class) || (jclass==object)) break;
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
setException(result, e);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Helper routines for the C implementation
|
||||
//
|
||||
public Object MakeArg(boolean b) { return new Boolean(b); }
|
||||
public Object MakeArg(long l) { return new Long(l); }
|
||||
public Object MakeArg(double d) { return new Double(d); }
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 4 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2003 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.0 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_0.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: Harald Radi <h.radi@nme.at> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#ifndef PHP_RPC_H
|
||||
#define PHP_RPC_H
|
||||
|
||||
#include "zend.h"
|
||||
|
||||
extern zend_module_entry rpc_module_entry;
|
||||
#define phpext_rpc_ptr &rpc_module_entry
|
||||
|
||||
#ifdef ZTS
|
||||
#include "TSRM.h"
|
||||
#endif
|
||||
|
||||
ZEND_MINIT_FUNCTION(rpc);
|
||||
ZEND_MSHUTDOWN_FUNCTION(rpc);
|
||||
ZEND_RINIT_FUNCTION(rpc);
|
||||
ZEND_RSHUTDOWN_FUNCTION(rpc);
|
||||
ZEND_MINFO_FUNCTION(rpc);
|
||||
|
||||
ZEND_API void rpc_error(int type, const char *format, ...);
|
||||
ZEND_API zend_object_value rpc_objects_new(zend_class_entry * TSRMLS_DC);
|
||||
|
||||
#endif /* PHP_RPC_H */
|
||||
936
ext/rpc/rpc.c
936
ext/rpc/rpc.c
@@ -1,936 +0,0 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 4 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2003 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.0 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_0.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: Harald Radi <h.radi@nme.at> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "php.h"
|
||||
#include "php_ini.h"
|
||||
#include "ext/standard/info.h"
|
||||
|
||||
#include "php_rpc.h"
|
||||
#include "rpc.h"
|
||||
#include "hash.h"
|
||||
#include "handler.h"
|
||||
|
||||
static void rpc_instance_dtor(void *);
|
||||
static void rpc_class_dtor(void *);
|
||||
static void rpc_string_dtor(void *);
|
||||
|
||||
static void rpc_objects_delete(void *, zend_object_handle TSRMLS_DC);
|
||||
static void rpc_ini_cb(void *arg TSRMLS_DC);
|
||||
|
||||
static rpc_class_hash *rpc_class_hash_find(rpc_string *name);
|
||||
|
||||
/* object handler */
|
||||
static zval* rpc_read(zval *, zval * TSRMLS_DC);
|
||||
static void rpc_write(zval *, zval *, zval * TSRMLS_DC);
|
||||
static zval** rpc_get_property(zval *, zval * TSRMLS_DC);
|
||||
static zval* rpc_get(zval * TSRMLS_DC);
|
||||
static void rpc_set(zval **, zval * TSRMLS_DC);
|
||||
static int rpc_has_property(zval *, zval *, int TSRMLS_DC);
|
||||
static void rpc_unset_property(zval *, zval * TSRMLS_DC);
|
||||
static HashTable* rpc_get_properties(zval * TSRMLS_DC);
|
||||
static union _zend_function* rpc_get_method(zval *, char *, int TSRMLS_DC);
|
||||
static union _zend_function* rpc_get_constructor(zval * TSRMLS_DC);
|
||||
static zend_class_entry* rpc_get_class_entry(zval * TSRMLS_DC);
|
||||
static int rpc_get_class_name(zval *object, char **class_name, zend_uint *class_name_len, int parent TSRMLS_DC);
|
||||
static int rpc_compare(zval *, zval * TSRMLS_DC);
|
||||
/**/
|
||||
|
||||
/* pseudo handler */
|
||||
static void rpc_internal_get(rpc_internal *, char *, zend_uint, zval *);
|
||||
static void rpc_internal_set(rpc_internal *, char *, zend_uint, zval *);
|
||||
/**/
|
||||
|
||||
extern zend_object_handlers rpc_proxy_handlers;
|
||||
|
||||
static zend_object_handlers rpc_handlers = {
|
||||
ZEND_OBJECTS_STORE_HANDLERS,
|
||||
|
||||
rpc_read,
|
||||
rpc_write,
|
||||
rpc_get_property,
|
||||
NULL,
|
||||
rpc_get,
|
||||
rpc_set,
|
||||
rpc_has_property,
|
||||
rpc_unset_property,
|
||||
rpc_get_properties,
|
||||
rpc_get_method,
|
||||
NULL,
|
||||
rpc_get_constructor,
|
||||
rpc_get_class_entry,
|
||||
rpc_get_class_name,
|
||||
rpc_compare
|
||||
};
|
||||
|
||||
/* {{{ rpc_functions[]
|
||||
*/
|
||||
function_entry rpc_functions[] = {
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
/* }}} */
|
||||
|
||||
/* {{{ rpc_module_entry
|
||||
*/
|
||||
zend_module_entry rpc_module_entry = {
|
||||
STANDARD_MODULE_HEADER,
|
||||
"rpc",
|
||||
rpc_functions,
|
||||
ZEND_MINIT(rpc),
|
||||
ZEND_MSHUTDOWN(rpc),
|
||||
NULL,
|
||||
NULL,
|
||||
ZEND_MINFO(rpc),
|
||||
"0.1a",
|
||||
STANDARD_MODULE_PROPERTIES
|
||||
};
|
||||
/* }}} */
|
||||
|
||||
zend_class_entry rpc_class_entry;
|
||||
|
||||
static zend_class_entry *rpc_entry;
|
||||
static zend_function *rpc_ctor;
|
||||
static HashTable handlers;
|
||||
static TsHashTable pool;
|
||||
static TsHashTable classes;
|
||||
static zend_llist classes_list;
|
||||
static zend_llist layers;
|
||||
|
||||
#ifdef COMPILE_DL_RPC
|
||||
ZEND_GET_MODULE(rpc);
|
||||
#endif
|
||||
|
||||
/* {{{ ZEND_MINIT_FUNCTION
|
||||
*/
|
||||
ZEND_MINIT_FUNCTION(rpc)
|
||||
{
|
||||
zend_internal_function *zif;
|
||||
|
||||
/* rpc base class entry */
|
||||
INIT_CLASS_ENTRY(rpc_class_entry, "rpc", NULL);
|
||||
rpc_entry = zend_register_internal_class(&rpc_class_entry TSRMLS_CC);
|
||||
|
||||
zend_hash_init(&handlers, 0, NULL, NULL, TRUE);
|
||||
zend_ts_hash_init(&pool, sizeof(rpc_internal **), NULL, rpc_instance_dtor, TRUE);
|
||||
zend_ts_hash_init(&classes, 0, NULL, NULL, TRUE);
|
||||
zend_llist_init(&classes_list, sizeof(rpc_class_hash **), rpc_class_dtor, TRUE);
|
||||
zend_llist_init(&layers, sizeof(char *), NULL, TRUE);
|
||||
|
||||
zif = (zend_internal_function *) emalloc(sizeof(zend_internal_function));
|
||||
|
||||
zif->type = ZEND_INTERNAL_FUNCTION;
|
||||
zif->function_name = rpc_entry->name;
|
||||
zif->scope = rpc_entry;
|
||||
zif->arg_types = NULL;
|
||||
zif->handler = ZEND_FN(rpc_load);
|
||||
|
||||
/* add new constructor to the method table */
|
||||
zend_hash_add(&(rpc_entry->function_table), rpc_entry->name, rpc_entry->name_length + 1, zif, sizeof(zend_function), &rpc_ctor);
|
||||
efree(zif);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ ZEND_MSHUTDOWN_FUNCTION
|
||||
*/
|
||||
ZEND_MSHUTDOWN_FUNCTION(rpc)
|
||||
{
|
||||
/* destroy instances first */
|
||||
zend_ts_hash_destroy(&pool);
|
||||
|
||||
zend_ts_hash_destroy(&classes);
|
||||
zend_llist_destroy(&classes_list);
|
||||
zend_llist_destroy(&layers);
|
||||
zend_hash_destroy(&handlers);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ ZEND_MINFO_FUNCTION
|
||||
*/
|
||||
ZEND_MINFO_FUNCTION(rpc)
|
||||
{
|
||||
php_info_print_table_start();
|
||||
zend_llist_apply(&layers, rpc_ini_cb TSRMLS_CC);
|
||||
php_info_print_table_end();
|
||||
|
||||
DISPLAY_INI_ENTRIES();
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
ZEND_API rpc_register_layer(rpc_handler_entry *entry TSRMLS_DC)
|
||||
{
|
||||
zend_class_entry ce;
|
||||
|
||||
INIT_CLASS_ENTRY(ce, entry->name, entry->methods);
|
||||
|
||||
ce.create_object = rpc_objects_new;
|
||||
|
||||
/* load all available rpc handler into a hash */
|
||||
zend_hash_add(&handlers, entry->name, strlen(entry->name) + 1, &(entry->handlers), sizeof(rpc_object_handlers *), NULL);
|
||||
zend_llist_add_element(&layers, &(entry->name));
|
||||
|
||||
/* register classes */
|
||||
*(entry->ce) = zend_register_internal_class_ex(&ce, rpc_entry, NULL TSRMLS_CC);
|
||||
}
|
||||
|
||||
static void rpc_class_dtor(void *pDest)
|
||||
{
|
||||
rpc_class_hash **hash;
|
||||
|
||||
hash = (rpc_class_hash **) pDest;
|
||||
|
||||
if ((*hash)->singleton) {
|
||||
RPC_HT(*hash)->rpc_dtor((*hash)->data);
|
||||
}
|
||||
|
||||
zend_ts_hash_destroy(&((*hash)->methods));
|
||||
zend_ts_hash_destroy(&((*hash)->properties));
|
||||
|
||||
free((*hash)->name.str);
|
||||
pefree((*hash), TRUE);
|
||||
}
|
||||
|
||||
static void rpc_string_dtor(void *pDest)
|
||||
{
|
||||
rpc_string **string;
|
||||
|
||||
string = (rpc_string **) pDest;
|
||||
|
||||
free((*string)->str);
|
||||
pefree(*string, TRUE);
|
||||
}
|
||||
|
||||
static void rpc_instance_dtor(void *pDest)
|
||||
{
|
||||
rpc_internal **intern;
|
||||
|
||||
intern = (rpc_internal **) pDest;
|
||||
|
||||
RPC_HT(*intern)->rpc_dtor((*intern)->data);
|
||||
|
||||
tsrm_mutex_free((*intern)->mx_handler);
|
||||
if ((*intern)->free_function_table) {
|
||||
zend_ts_hash_destroy(&((*intern)->function_table));
|
||||
}
|
||||
|
||||
pefree(*intern, TRUE);
|
||||
}
|
||||
|
||||
static void rpc_ini_cb(void *arg TSRMLS_DC)
|
||||
{
|
||||
char *name = *((char **) arg);
|
||||
php_info_print_table_header(2, name, "loaded");
|
||||
}
|
||||
|
||||
static zend_object_value rpc_create_proxy(TSRMLS_D)
|
||||
{
|
||||
zend_object_value *zov;
|
||||
rpc_proxy *proxy_intern;
|
||||
|
||||
/* set up the object value struct */
|
||||
zov = (zend_object_value*) pemalloc(sizeof(zend_object_value), TRUE);
|
||||
zov->handlers = &rpc_proxy_handlers;
|
||||
|
||||
/* set up the internal representation of the proxy */
|
||||
proxy_intern = (rpc_proxy *) pemalloc(sizeof(rpc_proxy), TRUE);
|
||||
|
||||
/* store the instance in a hash and set the key as handle, thus
|
||||
* we can find it later easily
|
||||
*/
|
||||
/* tsrm_mutex_lock(proxy->mx_writer);
|
||||
{
|
||||
zov->handle = zend_hash_next_free_element(TS_HASH(proxy));
|
||||
zend_ts_hash_next_index_insert(proxy, &proxy_intern, sizeof(rpc_proxy *), NULL);
|
||||
}
|
||||
tsrm_mutex_unlock(proxy->mx_writer);
|
||||
*/
|
||||
return *zov;
|
||||
}
|
||||
|
||||
/* object handler */
|
||||
|
||||
static void rpc_objects_delete(void *object, zend_object_handle handle TSRMLS_DC)
|
||||
{
|
||||
rpc_internal *intern = (rpc_internal *) object;
|
||||
|
||||
if (RPC_CLASS(intern) && RPC_CLASS(intern)->singleton) {
|
||||
pefree(intern, TRUE);
|
||||
} else if (RPC_CLASS(intern) && RPC_CLASS(intern)->poolable) {
|
||||
if (RPC_CLASS(intern)->name.str) {
|
||||
zend_ts_hash_add(&pool, RPC_CLASS(intern)->name.str, RPC_CLASS(intern)->name.len + 1, &intern, sizeof(rpc_internal *), NULL);
|
||||
} else {
|
||||
zend_ts_hash_index_update(&pool, RPC_CLASS(intern)->name.len + 1, &intern, sizeof(rpc_internal *), NULL);
|
||||
}
|
||||
} else {
|
||||
if (intern->data != NULL) {
|
||||
RPC_HT(intern)->rpc_dtor(intern->data);
|
||||
}
|
||||
pefree(intern, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
static zval* rpc_read(zval *object, zval *member TSRMLS_DC)
|
||||
{
|
||||
zval *return_value;
|
||||
GET_INTERNAL(intern);
|
||||
|
||||
/* seting up the return value and decrease the refcounter as we don't
|
||||
* keep a reference to this zval.
|
||||
*/
|
||||
MAKE_STD_ZVAL(return_value);
|
||||
ZVAL_DELREF(return_value);
|
||||
ZVAL_NULL(return_value);
|
||||
|
||||
if (intern->hash && Z_TYPE_P(member) == IS_LONG) {
|
||||
rpc_internal_get(intern, NULL, Z_LVAL_P(member), return_value);
|
||||
} else if (Z_TYPE_P(member) == IS_STRING) {
|
||||
rpc_internal_get(intern, Z_STRVAL_P(member), Z_STRLEN_P(member), return_value);
|
||||
} else {
|
||||
/* TODO: exception here */
|
||||
}
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
static void rpc_write(zval *object, zval *member, zval *value TSRMLS_DC)
|
||||
{
|
||||
GET_INTERNAL(intern);
|
||||
|
||||
if (intern->hash && Z_TYPE_P(member) == IS_LONG) {
|
||||
rpc_internal_set(intern, NULL, Z_LVAL_P(member), value);
|
||||
} else if (Z_TYPE_P(member) == IS_STRING) {
|
||||
rpc_internal_set(intern, Z_STRVAL_P(member), Z_STRLEN_P(member), value);
|
||||
} else {
|
||||
/* TODO: exception here */
|
||||
}
|
||||
}
|
||||
|
||||
static zval** rpc_get_property(zval *object, zval *member TSRMLS_DC)
|
||||
{
|
||||
zval **return_value;
|
||||
GET_INTERNAL(intern);
|
||||
|
||||
return_value = emalloc(sizeof(zval *));
|
||||
MAKE_STD_ZVAL(*return_value);
|
||||
Z_TYPE_P(object) = IS_OBJECT;
|
||||
(*return_value)->value.obj = rpc_create_proxy(TSRMLS_C);
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
static zval* rpc_get(zval *property TSRMLS_DC)
|
||||
{
|
||||
/* not yet implemented */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void rpc_set(zval **property, zval *value TSRMLS_DC)
|
||||
{
|
||||
/* not yet implemented */
|
||||
}
|
||||
|
||||
static int rpc_has_property(zval *object, zval *member, int check_empty TSRMLS_DC)
|
||||
{
|
||||
// GET_INTERNAL(intern);
|
||||
/* FIXME */
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
static void rpc_unset_property(zval *object, zval *member TSRMLS_DC)
|
||||
{
|
||||
// GET_INTERNAL(intern);
|
||||
/* FIXME */
|
||||
}
|
||||
|
||||
static HashTable* rpc_get_properties(zval *object TSRMLS_DC)
|
||||
{
|
||||
// GET_INTERNAL(intern);
|
||||
/* FIXME */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static union _zend_function* rpc_get_method(zval *object, char *method, int method_len TSRMLS_DC)
|
||||
{
|
||||
zend_function *function;
|
||||
unsigned char *ref_types = NULL;
|
||||
GET_INTERNAL(intern);
|
||||
|
||||
if (zend_ts_hash_find(&intern->function_table, method, method_len + 1, &function) != SUCCESS) {
|
||||
zend_internal_function *zif;
|
||||
|
||||
/* get reftypes */
|
||||
if (RPC_HT(intern)->rpc_describe) {
|
||||
char *arg_types;
|
||||
rpc_string method_name;
|
||||
|
||||
method_name.str = method;
|
||||
method_name.len = method_len;
|
||||
|
||||
RPC_HT(intern)->rpc_describe(method_name, intern->data, &arg_types, &ref_types);
|
||||
}
|
||||
|
||||
zif = (zend_internal_function *) emalloc(sizeof(zend_internal_function));
|
||||
zif->arg_types = ref_types;
|
||||
zif->function_name = method;
|
||||
zif->handler = ZEND_FN(rpc_call);
|
||||
zif->scope = intern->ce;
|
||||
zif->type = ZEND_INTERNAL_FUNCTION;
|
||||
zif->fn_flags = ZEND_ACC_PUBLIC;
|
||||
|
||||
/* add new method to the method table */
|
||||
zend_ts_hash_add(&intern->function_table, method, method_len + 1, zif, sizeof(zend_function), &function);
|
||||
efree(zif);
|
||||
}
|
||||
|
||||
return function;
|
||||
}
|
||||
|
||||
static union _zend_function* rpc_get_constructor(zval *object TSRMLS_DC)
|
||||
{
|
||||
return rpc_ctor;
|
||||
}
|
||||
|
||||
static zend_class_entry* rpc_get_class_entry(zval *object TSRMLS_DC)
|
||||
{
|
||||
GET_INTERNAL(intern);
|
||||
|
||||
return intern->ce;
|
||||
}
|
||||
|
||||
static int rpc_get_class_name(zval *object, char **class_name, zend_uint *class_name_len, int parent TSRMLS_DC)
|
||||
{
|
||||
GET_INTERNAL(intern);
|
||||
|
||||
if (parent) {
|
||||
return FAILURE;
|
||||
} else {
|
||||
*class_name = intern->ce->name;
|
||||
*class_name_len = intern->ce->name_length;
|
||||
return SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
static int rpc_compare(zval *object1, zval *object2 TSRMLS_DC)
|
||||
{
|
||||
/* FIXME */
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
/**/
|
||||
|
||||
/* constructor */
|
||||
ZEND_API ZEND_FUNCTION(rpc_load)
|
||||
{
|
||||
zval *object = getThis();
|
||||
zval ***args, ***args_free;
|
||||
zend_uint num_args = ZEND_NUM_ARGS();
|
||||
rpc_class_hash *class_hash;
|
||||
rpc_internal *intern;
|
||||
rpc_string hash_val, class_val;
|
||||
int retval, append = 0;
|
||||
char *arg_types;
|
||||
|
||||
/* check if we were called as a constructor or as a function */
|
||||
if (!object) {
|
||||
/* we were called as a function so we have to figure out which rpc layer was requested
|
||||
* and then we have to set up a zval containing the object
|
||||
*/
|
||||
|
||||
/* get class entry */
|
||||
GET_CLASS(ce);
|
||||
|
||||
/* set up a new zval container */
|
||||
object = return_value;
|
||||
|
||||
Z_TYPE_P(object) = IS_OBJECT;
|
||||
|
||||
/* create a new object */
|
||||
object->value.obj = rpc_objects_new(*ce TSRMLS_CC);
|
||||
|
||||
/* now everything is set up the same way as if we were called as a constructor */
|
||||
}
|
||||
|
||||
if (GET_INTERNAL_EX(intern, object) != SUCCESS) {
|
||||
/* TODO: exception */
|
||||
}
|
||||
|
||||
/* fetch further parameters */
|
||||
GET_ARGS_EX(num_args, args, args_free, 1);
|
||||
|
||||
/* if classname != integer */
|
||||
if ((zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, 1 TSRMLS_CC, "l", &class_val.len) != SUCCESS) ||
|
||||
/* or we have no hash function */
|
||||
!(RPC_HT(intern)->rpc_hash) ||
|
||||
/* or integer hashing is not allowed */
|
||||
!(RPC_HT(intern)->hash_type & HASH_AS_INT)) {
|
||||
|
||||
/* else check for string - classname */
|
||||
if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, 1 TSRMLS_CC, "s", &class_val.str, &class_val.len) != SUCCESS) {
|
||||
/* none of the two possibilities */
|
||||
/* TODO: exception */
|
||||
rpc_error(E_WARNING, "wrong arguments for %s()", get_active_function_name(TSRMLS_C));
|
||||
ZVAL_NULL(object);
|
||||
return;
|
||||
} else {
|
||||
/* hash classname if hashing function exists */
|
||||
if (RPC_HT(intern)->rpc_hash) {
|
||||
|
||||
GET_SIGNATURE(intern, class_val.str, class_val.len, hash_val, num_args, arg_types);
|
||||
|
||||
/* check if already hashed */
|
||||
if ((class_hash = rpc_class_hash_find(&hash_val)) == NULL) {
|
||||
ALLOC_CLASS_HASH(class_hash, intern->handlers);
|
||||
|
||||
/* do hashing */
|
||||
if (RPC_HT(intern)->rpc_hash(class_val, (rpc_string *) class_hash, NULL, num_args, arg_types, CLASS) != SUCCESS) {
|
||||
/* TODO: exception */
|
||||
ZVAL_NULL(object);
|
||||
return;
|
||||
}
|
||||
|
||||
/* overload class entry */
|
||||
RPC_HT(intern)->rpc_name(class_val, &class_val, NULL, CLASS);
|
||||
OVERLOAD_RPC_CLASS(class_val, intern, class_hash);
|
||||
|
||||
/* register with non-hashed key
|
||||
* also track all instaces in a llist for destruction later on, because there might be duplicate entries in
|
||||
* the hashtable and we can't determine if a pointer references to an already freed element
|
||||
*/
|
||||
REGISTER_RPC_CLASS(class_val, class_hash);
|
||||
} else {
|
||||
INIT_RPC_OBJECT(intern, class_hash);
|
||||
}
|
||||
|
||||
FREE_SIGNATURE(hash_val, arg_types);
|
||||
} else {
|
||||
/* Copy the function table hash for this object, so that it is separated
|
||||
* from the "global" table */
|
||||
SEPARATE_RPC_CLASS(intern);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* integer classname (hashcode) */
|
||||
if ((class_hash = rpc_class_hash_find(&hash_val)) == NULL) {
|
||||
ALLOC_CLASS_HASH(class_hash, intern->handlers);
|
||||
|
||||
class_val.str = NULL;
|
||||
class_hash->name.str = NULL;
|
||||
class_hash->name.len = class_val.len;
|
||||
|
||||
/* overload class entry */
|
||||
RPC_HT(intern)->rpc_name(class_val, &class_val, NULL, CLASS);
|
||||
OVERLOAD_RPC_CLASS(class_val, intern, class_hash);
|
||||
|
||||
/* register int hashcode, we don't know more */
|
||||
REGISTER_RPC_CLASS(class_val, class_hash);
|
||||
} else {
|
||||
INIT_RPC_OBJECT(intern, class_hash);
|
||||
}
|
||||
}
|
||||
|
||||
/* if hash function available */
|
||||
if (RPC_HT(intern)->rpc_hash) {
|
||||
rpc_internal *pool_intern;
|
||||
|
||||
/* assign cache structure */
|
||||
RPC_CLASS(intern) = class_hash;
|
||||
|
||||
if (zend_ts_hash_remove_key_or_index(&pool, RPC_CLASS(intern)->name.str, RPC_CLASS(intern)->name.len + 1, (void **) &pool_intern) == SUCCESS) {
|
||||
intern->data = pool_intern->data;
|
||||
|
||||
pefree(pool_intern, TRUE);
|
||||
retval = SUCCESS;
|
||||
} else if (RPC_CLASS(intern)->singleton) {
|
||||
/* singleton */
|
||||
intern->data = RPC_CLASS(intern)->data;
|
||||
retval = SUCCESS;
|
||||
} else {
|
||||
/* call the rpc ctor */
|
||||
retval = RPC_HT(intern)->rpc_ctor(class_hash->name, &(intern->data), num_args, args);
|
||||
}
|
||||
} else {
|
||||
/* disable caching from now on */
|
||||
intern->hash = NULL;
|
||||
|
||||
/* call the rpc ctor */
|
||||
retval = RPC_HT(intern)->rpc_ctor(class_val, &(intern->data), num_args, args);
|
||||
}
|
||||
|
||||
efree(args_free);
|
||||
|
||||
if (retval != SUCCESS) {
|
||||
/* TODO: exception */
|
||||
RETURN_NULL();
|
||||
}
|
||||
}
|
||||
|
||||
ZEND_API ZEND_FUNCTION(rpc_call)
|
||||
{
|
||||
zval *object = getThis();
|
||||
zval ***args, ***args_free;
|
||||
zend_uint num_args = ZEND_NUM_ARGS();
|
||||
char *hash = NULL, *arg_types;
|
||||
int hash_len, retval, strip = 0;
|
||||
|
||||
/* check if we were called as a method or as a function */
|
||||
if (!object) {
|
||||
/* we were called as a function so we have to figure out which rpc layer was requested */
|
||||
|
||||
/* get class entry */
|
||||
GET_CLASS(ce);
|
||||
|
||||
if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, 2 TSRMLS_CC, "Ol", &object, *ce, &hash_len) != SUCCESS) {
|
||||
if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, 2 TSRMLS_CC, "Os", &object, *ce, &hash, &hash_len) != SUCCESS) {
|
||||
/* none of the two possibilities */
|
||||
/* TODO: exception */
|
||||
rpc_error(E_WARNING, "wrong arguments for %s()", get_active_function_name(TSRMLS_C));
|
||||
}
|
||||
}
|
||||
|
||||
strip = 2;
|
||||
} else {
|
||||
hash = get_active_function_name(TSRMLS_C);
|
||||
hash_len = strlen(hash);
|
||||
}
|
||||
|
||||
GET_ARGS_EX(num_args, args, args_free, strip);
|
||||
|
||||
/* scope for internal data */
|
||||
{
|
||||
rpc_string hash_val, *method_hash, **method_hash_find;
|
||||
GET_INTERNAL(intern);
|
||||
|
||||
method_hash = (rpc_string *) pemalloc(sizeof(rpc_string), TRUE);
|
||||
method_hash->str = hash;
|
||||
method_hash->len = hash_len;
|
||||
|
||||
if (intern->hash) {
|
||||
/* cache method table lookups */
|
||||
|
||||
if (!hash && !(RPC_HT(intern)->hash_type & HASH_AS_INT)) {
|
||||
/* TODO: exception */
|
||||
} else if(hash) {
|
||||
/* string passed */
|
||||
GET_METHOD_SIGNATURE(intern, method_hash, hash_val, num_args, arg_types);
|
||||
|
||||
/* check if already hashed */
|
||||
if (zend_ts_hash_find(&(intern->hash->methods), hash_val.str, hash_val.len + 1, (void **) &method_hash_find) != SUCCESS) {
|
||||
if (RPC_HT(intern)->rpc_hash(*method_hash, method_hash, intern->data, num_args, arg_types, METHOD) != SUCCESS) {
|
||||
/* TODO: exception */
|
||||
RETURN_NULL();
|
||||
}
|
||||
|
||||
/* register with non-hashed key */
|
||||
zend_ts_hash_add(&(intern->hash->methods), hash_val.str, hash_val.len + 1, &method_hash, sizeof(rpc_string *), NULL);
|
||||
} else {
|
||||
pefree(method_hash, TRUE);
|
||||
method_hash = *method_hash_find;
|
||||
}
|
||||
|
||||
FREE_SIGNATURE(hash_val, arg_types);
|
||||
}
|
||||
}
|
||||
|
||||
/* actually this should not be neccesary, but who knows :)
|
||||
* considering possible thread implementations in future php versions
|
||||
* and srm it is better to do concurrency checks
|
||||
* DEPRECATE THIS !
|
||||
*/
|
||||
tsrm_mutex_lock(intern->mx_handler);
|
||||
retval = RPC_HT(intern)->rpc_call(*method_hash, intern->data, return_value, num_args, args);
|
||||
tsrm_mutex_unlock(intern->mx_handler);
|
||||
}
|
||||
|
||||
efree(args_free);
|
||||
|
||||
if (retval != SUCCESS) {
|
||||
/* TODO: exception here */
|
||||
}
|
||||
}
|
||||
|
||||
ZEND_API ZEND_FUNCTION(rpc_set)
|
||||
{
|
||||
zval *object, *value;
|
||||
char *property = NULL;
|
||||
int property_len;
|
||||
rpc_internal *intern;
|
||||
/* get class entry */
|
||||
GET_CLASS(ce);
|
||||
|
||||
if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, 3 TSRMLS_CC, "Olz", &object, *ce, &property_len, &value) != SUCCESS) {
|
||||
if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, 3 TSRMLS_CC, "Osz", &object, *ce, &property, &property_len, &value) != SUCCESS) {
|
||||
/* none of the two possibilities */
|
||||
/* TODO: exception */
|
||||
rpc_error(E_WARNING, "wrong arguments for %s()", get_active_function_name(TSRMLS_C));
|
||||
}
|
||||
}
|
||||
|
||||
GET_INTERNAL_EX(intern, object);
|
||||
if (!property && !intern->hash) {
|
||||
/* TODO: exception here */
|
||||
} else {
|
||||
rpc_internal_set(intern, property, property_len, value);
|
||||
}
|
||||
}
|
||||
|
||||
ZEND_API ZEND_FUNCTION(rpc_get)
|
||||
{
|
||||
zval *object;
|
||||
char *property = NULL;
|
||||
int property_len;
|
||||
rpc_internal *intern;
|
||||
/* get class entry */
|
||||
GET_CLASS(ce);
|
||||
|
||||
if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, 2 TSRMLS_CC, "Ol", &object, *ce, &property_len) != SUCCESS) {
|
||||
if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, 2 TSRMLS_CC, "Os", &object, *ce, &property, &property_len) != SUCCESS) {
|
||||
/* none of the two possibilities */
|
||||
/* TODO: exception */
|
||||
rpc_error(E_WARNING, "wrong arguments for %s()", get_active_function_name(TSRMLS_C));
|
||||
}
|
||||
}
|
||||
|
||||
GET_INTERNAL_EX(intern, object);
|
||||
if (!property && !intern->hash) {
|
||||
/* TODO: exception here */
|
||||
} else {
|
||||
rpc_internal_get(intern, property, property_len, return_value);
|
||||
}
|
||||
}
|
||||
|
||||
ZEND_API ZEND_FUNCTION(rpc_singleton)
|
||||
{
|
||||
zval *object;
|
||||
rpc_internal *intern;
|
||||
/* get class entry */
|
||||
GET_CLASS(ce);
|
||||
|
||||
zend_parse_parameters(1 TSRMLS_CC, "O", &object, *ce);
|
||||
|
||||
GET_INTERNAL_EX(intern, object);
|
||||
|
||||
if (!RPC_CLASS(intern)) {
|
||||
/* TODO: exception here, no hashing */
|
||||
} else if (!RPC_CLASS(intern)->singleton) {
|
||||
RPC_CLASS(intern)->singleton = TRUE;
|
||||
RPC_CLASS(intern)->data = intern->data;
|
||||
}
|
||||
}
|
||||
|
||||
ZEND_API ZEND_FUNCTION(rpc_poolable)
|
||||
{
|
||||
zval *object;
|
||||
rpc_internal *intern;
|
||||
/* get class entry */
|
||||
GET_CLASS(ce);
|
||||
|
||||
zend_parse_parameters(1 TSRMLS_CC, "O", &object, *ce);
|
||||
|
||||
GET_INTERNAL_EX(intern, object);
|
||||
|
||||
if (RPC_HT(intern)->poolable && RPC_CLASS(intern) && (RPC_HT(intern)->poolable == TRUE)) {
|
||||
RPC_CLASS(intern)->poolable = TRUE;
|
||||
} else {
|
||||
/* TODO: exception here, no hashing */
|
||||
}
|
||||
}
|
||||
|
||||
ZEND_API void rpc_error(int type, const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
TSRMLS_FETCH();
|
||||
|
||||
va_start(args, format);
|
||||
zend_error_cb(type, zend_get_executed_filename(TSRMLS_C), zend_get_executed_lineno(TSRMLS_C), format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
ZEND_API zend_object_value rpc_objects_new(zend_class_entry *class_type TSRMLS_DC)
|
||||
{
|
||||
zend_object_value zov;
|
||||
rpc_internal *intern;
|
||||
|
||||
/* set up the object value struct */
|
||||
zov.handlers = &rpc_handlers;
|
||||
|
||||
/* set up the internal representation of our rpc instance */
|
||||
intern = (rpc_internal *) pecalloc(1, sizeof(rpc_internal), TRUE);
|
||||
|
||||
intern->ce = class_type;
|
||||
intern->data = NULL;
|
||||
intern->free_function_table = 0;
|
||||
intern->function_table.reader = 0;
|
||||
intern->function_table.mx_reader = tsrm_mutex_alloc();
|
||||
intern->function_table.mx_writer = tsrm_mutex_alloc();
|
||||
intern->mx_handler = tsrm_mutex_alloc();
|
||||
|
||||
if (zend_hash_find(&handlers, class_type->name, class_type->name_length + 1, (void **) &(intern->handlers)) != SUCCESS) {
|
||||
/* TODO: exception */
|
||||
}
|
||||
|
||||
zov.handle = zend_objects_store_put(intern, rpc_objects_delete, NULL TSRMLS_CC);
|
||||
|
||||
return zov;
|
||||
}
|
||||
|
||||
/*******************/
|
||||
|
||||
static void rpc_internal_get(rpc_internal *intern, char *property, zend_uint property_len, zval *return_value)
|
||||
{
|
||||
int retval;
|
||||
rpc_string *property_hash, **property_hash_find;
|
||||
|
||||
Z_TYPE_P(return_value) = IS_NULL;
|
||||
|
||||
property_hash = (rpc_string *) pemalloc(sizeof(rpc_string), TRUE);
|
||||
property_hash->str = property;
|
||||
property_hash->len = property_len;
|
||||
|
||||
if (intern->hash) {
|
||||
/* cache method table lookups */
|
||||
|
||||
if (!property && !(RPC_HT(intern)->hash_type & HASH_AS_INT)) {
|
||||
/* TODO: exception */
|
||||
} else if(property) {
|
||||
/* check if already hashed */
|
||||
if (zend_ts_hash_find(&(intern->hash->properties), property, property_len + 1, (void **) &property_hash_find) != SUCCESS) {
|
||||
if (RPC_HT(intern)->rpc_hash(*property_hash, property_hash, intern->data, 0, NULL, PROPERTY) != SUCCESS) {
|
||||
/* TODO: exception */
|
||||
RETURN_NULL();
|
||||
}
|
||||
|
||||
/* register with non-hashed key */
|
||||
zend_ts_hash_add(&(intern->hash->properties), property, property_len + 1, &property_hash, sizeof(rpc_string *), NULL);
|
||||
} else {
|
||||
pefree(property_hash, TRUE);
|
||||
property_hash = *property_hash_find;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
tsrm_mutex_lock(intern->mx_handler);
|
||||
retval = RPC_HT(intern)->rpc_get(*property_hash, return_value, intern->data);
|
||||
tsrm_mutex_unlock(intern->mx_handler);
|
||||
|
||||
if (retval != SUCCESS) {
|
||||
/* TODO: exception here */
|
||||
}
|
||||
}
|
||||
|
||||
static void rpc_internal_set(rpc_internal *intern, char *property, zend_uint property_len, zval *value)
|
||||
{
|
||||
int retval;
|
||||
rpc_string property_name;
|
||||
|
||||
property_name.str = property;
|
||||
property_name.len = property_len;
|
||||
|
||||
tsrm_mutex_lock(intern->mx_handler);
|
||||
retval = RPC_HT(intern)->rpc_set(property_name, value, intern->data);
|
||||
tsrm_mutex_unlock(intern->mx_handler);
|
||||
|
||||
if (retval != SUCCESS) {
|
||||
/* TODO: exception here */
|
||||
}
|
||||
}
|
||||
|
||||
static rpc_class_hash *rpc_class_hash_find(rpc_string *name)
|
||||
{
|
||||
rpc_class_hash **class_hash_find = NULL;
|
||||
|
||||
if (name->str == NULL) {
|
||||
/* int value */
|
||||
if (zend_ts_hash_index_find(&classes, name->len, (void**) &class_hash_find) != SUCCESS) {
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
/* string value */
|
||||
if (zend_ts_hash_find(&classes, name->str, name->len + 1, (void **) &class_hash_find) != SUCCESS) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return *class_hash_find;
|
||||
}
|
||||
|
||||
ZEND_API zval* _rpc_object_from_data(zval *z, rpc_handler_entry *handler, void *data, rpc_class_hash *class_hash)
|
||||
{
|
||||
rpc_internal *intern;
|
||||
rpc_string hash, name = {NULL, 0};
|
||||
TSRMLS_FETCH();
|
||||
|
||||
if (z == NULL) {
|
||||
ALLOC_ZVAL(z);
|
||||
}
|
||||
|
||||
Z_TYPE_P(z) = IS_OBJECT;
|
||||
z->value.obj = rpc_objects_new(*(handler->ce) TSRMLS_CC);
|
||||
|
||||
if (GET_INTERNAL_EX(intern, z) != SUCCESS) {
|
||||
/* TODO: exception */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
intern->ce = *(handler->ce);
|
||||
intern->data = data;
|
||||
|
||||
if ((handler->handlers->rpc_hash) &&
|
||||
(handler->handlers->rpc_hash(name, &hash, data, 0, "", CLASS) == SUCCESS)) {
|
||||
/* We are hashing, try to find an appropriate hash or create a new one */
|
||||
if ((class_hash == NULL) &&
|
||||
((class_hash = rpc_class_hash_find(&hash)) == NULL)) {
|
||||
ALLOC_CLASS_HASH(class_hash, intern->handlers);
|
||||
|
||||
class_hash->name = hash;
|
||||
|
||||
if (handler->handlers->rpc_name(hash, &name, data, CLASS) != SUCCESS) {
|
||||
/* TODO exception */
|
||||
}
|
||||
|
||||
OVERLOAD_RPC_CLASS(name, intern, class_hash);
|
||||
REGISTER_RPC_CLASS(name, class_hash);
|
||||
} else {
|
||||
INIT_RPC_OBJECT(intern, class_hash);
|
||||
}
|
||||
|
||||
RPC_CLASS(intern) = class_hash;
|
||||
} else {
|
||||
/* Copy the function table hash for this object, so that it is separated
|
||||
* from the "global" table */
|
||||
SEPARATE_RPC_CLASS(intern);
|
||||
}
|
||||
|
||||
return z;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* tab-width: 4
|
||||
* c-basic-offset: 4
|
||||
* End:
|
||||
* vim600: noet sw=4 ts=4 fdm=marker
|
||||
* vim<600: noet sw=4 ts=4
|
||||
*/
|
||||
173
ext/rpc/rpc.h
173
ext/rpc/rpc.h
@@ -1,173 +0,0 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 4 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2003 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.0 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_0.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: Harald Radi <h.radi@nme.at> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#ifndef RPC_H
|
||||
#define RPC_H
|
||||
|
||||
#define RPC_HT(intern) (*((intern)->handlers))
|
||||
#define RPC_CLASS(intern) ((intern)->hash)
|
||||
|
||||
#define GET_INTERNAL(intern) rpc_internal *intern; \
|
||||
if (GET_INTERNAL_EX(intern, object) != SUCCESS) { \
|
||||
/* TODO: exception */ \
|
||||
}
|
||||
|
||||
#define GET_INTERNAL_EX(intern, object) (((intern = zend_object_store_get_object(object TSRMLS_CC)) == NULL) ? FAILURE : SUCCESS)
|
||||
|
||||
#define GET_CLASS(ce) char *key; \
|
||||
int key_len; \
|
||||
zend_class_entry **ce; \
|
||||
\
|
||||
/* the name of the rpc layer is prepended to '_load' so lets strip everything after \
|
||||
* the first '_' away from the function name \
|
||||
*/ \
|
||||
key = estrdup(get_active_function_name(TSRMLS_C)); \
|
||||
key_len = strchr(key, '_') - key; \
|
||||
key[key_len] = '\0'; \
|
||||
\
|
||||
/* get the class entry for the requested rpc layer */ \
|
||||
if (zend_hash_find(CG(class_table), key, key_len + 1, (void **) &ce) != SUCCESS) { \
|
||||
efree(key); \
|
||||
/* TODO: exception here */ \
|
||||
} else { \
|
||||
efree(key); \
|
||||
}
|
||||
|
||||
#define GET_ARGS_EX(num_args, args, args_free, strip) \
|
||||
GET_ARGS(num_args, args) \
|
||||
\
|
||||
args_free = args; \
|
||||
\
|
||||
/* strip away the first parameters */ \
|
||||
num_args -= strip; \
|
||||
args = (num_args > 0) ? &args[strip] : NULL;
|
||||
|
||||
#define GET_ARGS(num_args, args) \
|
||||
args = (zval ***) emalloc(sizeof(zval **) * num_args); \
|
||||
\
|
||||
if (zend_get_parameters_array_ex(num_args, args) != SUCCESS) { \
|
||||
efree(args); \
|
||||
/* TODO: exception */ \
|
||||
}
|
||||
|
||||
#define GET_METHOD_SIGNATURE(intern, method, hash_val, num_args, arg_types) \
|
||||
GET_SIGNATURE(intern, method->str, method->len, hash_val, num_args, arg_types)
|
||||
|
||||
#define GET_SIGNATURE(intern, name, name_len, hash_val, num_args, arg_types) \
|
||||
hash_val.len = name_len; \
|
||||
\
|
||||
if ((*intern->handlers)->hash_type & HASH_WITH_SIGNATURE) { \
|
||||
zend_uint _signature_counter; \
|
||||
\
|
||||
arg_types = (char *) emalloc(sizeof(char) * (num_args + 1)); \
|
||||
hash_val.len += num_args + 1; \
|
||||
\
|
||||
for (_signature_counter = 0; _signature_counter < num_args; _signature_counter++) { \
|
||||
switch (Z_TYPE_PP(args[_signature_counter])) { \
|
||||
case IS_NULL: \
|
||||
arg_types[_signature_counter] = 'n'; \
|
||||
break; \
|
||||
case IS_LONG: \
|
||||
arg_types[_signature_counter] = 'l'; \
|
||||
break; \
|
||||
case IS_DOUBLE: \
|
||||
arg_types[_signature_counter] = 'd'; \
|
||||
break; \
|
||||
case IS_STRING: \
|
||||
arg_types[_signature_counter] = 's'; \
|
||||
break; \
|
||||
case IS_ARRAY: \
|
||||
arg_types[_signature_counter] = 'a'; \
|
||||
break; \
|
||||
case IS_OBJECT: \
|
||||
arg_types[_signature_counter] = 'o'; \
|
||||
break; \
|
||||
case IS_BOOL: \
|
||||
arg_types[_signature_counter] = 'b'; \
|
||||
break; \
|
||||
case IS_RESOURCE: \
|
||||
arg_types[_signature_counter] = 'r'; \
|
||||
break; \
|
||||
default: \
|
||||
arg_types[_signature_counter] = 'u'; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
arg_types[_signature_counter] = '\0'; \
|
||||
} else { \
|
||||
arg_types = (char *) emalloc(sizeof(char)); \
|
||||
arg_types[0] = '\0'; \
|
||||
} \
|
||||
\
|
||||
hash_val.str = (char *) emalloc(sizeof(char) * (hash_val.len + 2)); \
|
||||
memcpy(hash_val.str, arg_types, num_args + 1); \
|
||||
memcpy(&hash_val.str[hash_val.len - name_len], \
|
||||
name, name_len + 1);
|
||||
|
||||
#define FREE_SIGNATURE(hash_val, arg_types) \
|
||||
efree(arg_types); \
|
||||
efree(hash_val.str);
|
||||
|
||||
#define ALLOC_CLASS_HASH(_class_hash, _handlers) \
|
||||
if (_class_hash = pemalloc(sizeof(rpc_class_hash), TRUE)) { \
|
||||
/* set up the cache */ \
|
||||
zend_ts_hash_init(&(_class_hash->methods), 0, NULL, rpc_string_dtor, TRUE); \
|
||||
zend_ts_hash_init(&(_class_hash->properties), 0, NULL, rpc_string_dtor, TRUE); \
|
||||
_class_hash->singleton = FALSE; \
|
||||
_class_hash->poolable = FALSE; \
|
||||
_class_hash->data = NULL; \
|
||||
_class_hash->handlers = _handlers; \
|
||||
}
|
||||
|
||||
#define INIT_RPC_OBJECT(__intern, __clh) \
|
||||
(__intern)->ce = (__clh)->ce; \
|
||||
(__intern)->function_table.hash = (__intern)->ce->function_table;
|
||||
|
||||
#define OVERLOAD_RPC_CLASS(__name, __intern, __clh) { \
|
||||
zend_class_entry overloaded_class_entry; \
|
||||
INIT_CLASS_ENTRY(overloaded_class_entry, NULL, NULL); \
|
||||
overloaded_class_entry.name = __name.str; \
|
||||
overloaded_class_entry.name_length = (__name.str != NULL) ? __name.len : 0; \
|
||||
(__clh)->ce = zend_register_internal_class_ex(&overloaded_class_entry, (__intern)->ce, NULL TSRMLS_CC); \
|
||||
INIT_RPC_OBJECT(__intern, __clh); \
|
||||
}
|
||||
|
||||
#define SEPARATE_RPC_CLASS(__intern) \
|
||||
(__intern)->free_function_table = 1; \
|
||||
zend_ts_hash_init(&((__intern)->function_table), 0, NULL, NULL, TRUE); \
|
||||
zend_hash_copy(&((__intern)->function_table.hash), &((__intern)->ce->function_table), NULL, NULL, 0);
|
||||
|
||||
#define REGISTER_RPC_CLASS(__name, __class_hash) { \
|
||||
rpc_class_hash **_tmp; \
|
||||
if ((__name).str != NULL) { \
|
||||
zend_ts_hash_add(&classes, (__name).str, (__name).len + 1, &(__class_hash), sizeof(rpc_class_hash *), (void **) &_tmp); \
|
||||
} \
|
||||
\
|
||||
tsrm_mutex_lock(classes.mx_writer); \
|
||||
zend_llist_add_element(&classes_list, _tmp); \
|
||||
tsrm_mutex_unlock(classes.mx_writer); \
|
||||
\
|
||||
if ((__class_hash)->name.str) { \
|
||||
zend_ts_hash_add(&classes, (__class_hash)->name.str, (__class_hash)->name.len + 1, &(__class_hash), sizeof(rpc_class_hash *), NULL); \
|
||||
} else { \
|
||||
zend_ts_hash_index_update(&classes, class_hash->name.len, &class_hash, sizeof(rpc_class_hash *), NULL); \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,154 +0,0 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 4 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2003 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.0 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_0.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: Harald Radi <h.radi@nme.at> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#include "php.h"
|
||||
|
||||
#include "rpc_proxy.h"
|
||||
#include "handler.h"
|
||||
|
||||
/* object handler */
|
||||
static void rpc_proxy_add_ref(zval * TSRMLS_DC);
|
||||
static void rpc_proxy_del_ref(zval * TSRMLS_DC);
|
||||
static void rpc_proxy_delete(zval * TSRMLS_DC);
|
||||
static zend_object_value rpc_proxy_clone(zval * TSRMLS_DC);
|
||||
static zval* rpc_proxy_read(zval *, zval * TSRMLS_DC);
|
||||
static void rpc_proxy_write(zval *, zval *, zval * TSRMLS_DC);
|
||||
static zval** rpc_proxy_get_property(zval *, zval * TSRMLS_DC);
|
||||
static zval* rpc_proxy_get(zval * TSRMLS_DC);
|
||||
static void rpc_proxy_set(zval **, zval * TSRMLS_DC);
|
||||
static int rpc_proxy_has_property(zval *, zval *, int TSRMLS_DC);
|
||||
static void rpc_proxy_unset_property(zval *, zval * TSRMLS_DC);
|
||||
static HashTable* rpc_proxy_get_properties(zval * TSRMLS_DC);
|
||||
static union _zend_function* rpc_proxy_get_method(zval *, char *, int TSRMLS_DC);
|
||||
static union _zend_function* rpc_proxy_get_constructor(zval * TSRMLS_DC);
|
||||
static zend_class_entry* rpc_proxy_get_class_entry(zval *object TSRMLS_DC);
|
||||
static int rpc_proxy_get_classname(zval *, char **, zend_uint *, int TSRMLS_DC);
|
||||
static int rpc_proxy_compare(zval *, zval * TSRMLS_DC);
|
||||
/**/
|
||||
|
||||
zend_object_handlers rpc_proxy_handlers = {
|
||||
rpc_proxy_add_ref,
|
||||
rpc_proxy_del_ref,
|
||||
rpc_proxy_delete,
|
||||
rpc_proxy_clone,
|
||||
rpc_proxy_read,
|
||||
rpc_proxy_write,
|
||||
rpc_proxy_get_property,
|
||||
NULL,
|
||||
rpc_proxy_get,
|
||||
rpc_proxy_set,
|
||||
rpc_proxy_has_property,
|
||||
rpc_proxy_unset_property,
|
||||
rpc_proxy_get_properties,
|
||||
rpc_proxy_get_method,
|
||||
NULL,
|
||||
rpc_proxy_get_constructor,
|
||||
rpc_proxy_get_class_entry,
|
||||
rpc_proxy_get_classname,
|
||||
rpc_proxy_compare
|
||||
};
|
||||
|
||||
|
||||
/* object handler */
|
||||
|
||||
static void rpc_proxy_add_ref(zval *object TSRMLS_DC)
|
||||
{
|
||||
}
|
||||
|
||||
static void rpc_proxy_del_ref(zval *object TSRMLS_DC)
|
||||
{
|
||||
}
|
||||
|
||||
static void rpc_proxy_delete(zval *object TSRMLS_DC)
|
||||
{
|
||||
}
|
||||
|
||||
static zend_object_value rpc_proxy_clone(zval *object TSRMLS_DC)
|
||||
{
|
||||
}
|
||||
|
||||
static zval* rpc_proxy_read(zval *object, zval *member TSRMLS_DC)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void rpc_proxy_write(zval *object, zval *member, zval *value TSRMLS_DC)
|
||||
{
|
||||
}
|
||||
|
||||
static zval** rpc_proxy_get_property(zval *object, zval *member TSRMLS_DC)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static zval* rpc_proxy_get(zval *property TSRMLS_DC)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void rpc_proxy_set(zval **property, zval *value TSRMLS_DC)
|
||||
{
|
||||
}
|
||||
|
||||
static int rpc_proxy_has_property(zval *object, zval *member, int check_empty TSRMLS_DC)
|
||||
{
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
static void rpc_proxy_unset_property(zval *object, zval *member TSRMLS_DC)
|
||||
{
|
||||
}
|
||||
|
||||
static HashTable* rpc_proxy_get_properties(zval *object TSRMLS_DC)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static union _zend_function* rpc_proxy_get_method(zval *object, char *method, int method_len TSRMLS_DC)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static union _zend_function* rpc_proxy_get_constructor(zval *object TSRMLS_DC)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static zend_class_entry* rpc_proxy_get_class_entry(zval *object TSRMLS_DC)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int rpc_proxy_get_classname(zval *object, char **class_name, zend_uint *class_name_len, int parent TSRMLS_DC)
|
||||
{
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
static int rpc_proxy_compare(zval *object1, zval *object2 TSRMLS_DC)
|
||||
{
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* tab-width: 4
|
||||
* c-basic-offset: 4
|
||||
* End:
|
||||
* vim600: noet sw=4 ts=4 fdm=marker
|
||||
* vim<600: noet sw=4 ts=4
|
||||
*/
|
||||
@@ -1,22 +0,0 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 4 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2003 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.0 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_0.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: Harald Radi <h.radi@nme.at> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#ifndef RPC_PROXY_H
|
||||
#define RPC_PROXY_H
|
||||
|
||||
#endif
|
||||
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 4 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2003 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.0 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_0.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: Harald Radi <h.radi@nme.at> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#ifndef PHP_SKELETON_H
|
||||
#define PHP_SKELETON_H
|
||||
|
||||
extern zend_module_entry skeleton_module_entry;
|
||||
#define phpext_skeleton_ptr &skeleton_module_entry
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-basic-offset: 4
|
||||
* tab-width: 4
|
||||
* End:
|
||||
* vim600: fdm=marker
|
||||
* vim: sw=4 ts=4 noet
|
||||
*/
|
||||
#endif /* PHP_SKELETON_H */
|
||||
@@ -1,269 +0,0 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 4 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2003 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.0 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_0.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: Harald Radi <h.radi@nme.at> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#include "../rpc.h"
|
||||
#include "../handler.h"
|
||||
|
||||
#include "skeleton.h"
|
||||
|
||||
/* protos */
|
||||
static int skeleton_hash(rpc_string, rpc_string *, void *, int, char *, int);
|
||||
static int skeleton_name(rpc_string, rpc_string *, void *, int);
|
||||
static int skeleton_ctor(rpc_string, void **, int , zval ***);
|
||||
static int skeleton_dtor(void *);
|
||||
static int skeleton_describe(rpc_string, void *, char **, unsigned char **);
|
||||
static int skeleton_call(rpc_string, void **, zval *, int, zval ***);
|
||||
static int skeleton_get(rpc_string, zval *, void **);
|
||||
static int skeleton_set(rpc_string, zval *, void **);
|
||||
static int skeleton_compare(void **, void **);
|
||||
static int skeleton_has_property(rpc_string, void **);
|
||||
static int skeleton_unset_property(rpc_string, void **);
|
||||
static int skeleton_get_properties(HashTable **, void **);
|
||||
|
||||
/* register rpc callback function */
|
||||
RPC_REGISTER_HANDLERS_BEGIN(skeleton)
|
||||
FALSE, /* poolable TRUE|FALSE*/
|
||||
DONT_HASH, /* hash function name lookups to avoid reflection of the object for each
|
||||
* method call. hashing is done either by mapping only the function name
|
||||
* to a coresponding method id or by taking the whole method signature into
|
||||
* account. possible values:
|
||||
* DONT_HASH|HASH_AS_INT|HASH_AS_STRING|
|
||||
* HASH_AS_INT_WITH_SIGNATURE|HASH_AS_STRING_WITH_SIGNATURE
|
||||
*/
|
||||
skeleton_hash, /* the hash function, can be NULL */
|
||||
skeleton_name, /* the reverse hash function, can be NULL */
|
||||
skeleton_ctor, /* constructor */
|
||||
skeleton_dtor, /* destructor */
|
||||
skeleton_describe, /* function to reflect methods to get information about parameter types.
|
||||
* parameters can be forced to be by reference this way. can be NULL.
|
||||
*/
|
||||
skeleton_call, /* method call handler */
|
||||
skeleton_get, /* property get handler */
|
||||
skeleton_set, /* property set handler */
|
||||
skeleton_compare, /* compare handler, can be NULL */
|
||||
skeleton_has_property, /* reflection functions */
|
||||
skeleton_unset_property, /* can be NULL */
|
||||
skeleton_get_properties
|
||||
RPC_REGISTER_HANDLERS_END()
|
||||
|
||||
/* register ini settings */
|
||||
PHP_INI_BEGIN()
|
||||
/* TODO: palce your ini entries here */
|
||||
PHP_INI_END()
|
||||
|
||||
/* register userspace functions */
|
||||
RPC_FUNCTION_ENTRY_BEGIN(skeleton)
|
||||
/* TODO: add your userspace functions here */
|
||||
ZEND_FE(skeleton_function, NULL)
|
||||
RPC_FUNCTION_ENTRY_END()
|
||||
|
||||
/* register class methods */
|
||||
RPC_METHOD_ENTRY_BEGIN(skeleton)
|
||||
/* TODO: add your class methods here */
|
||||
ZEND_FALIAS(method, skeleton_function, NULL)
|
||||
RPC_METHOD_ENTRY_END()
|
||||
|
||||
zend_module_entry skeleton_module_entry = {
|
||||
ZE2_STANDARD_MODULE_HEADER,
|
||||
"skeleton",
|
||||
RPC_FUNCTION_ENTRY(skeleton),
|
||||
ZEND_MINIT(skeleton),
|
||||
ZEND_MSHUTDOWN(skeleton),
|
||||
NULL,
|
||||
NULL,
|
||||
ZEND_MINFO(skeleton),
|
||||
"0.1a",
|
||||
STANDARD_MODULE_PROPERTIES
|
||||
};
|
||||
|
||||
ZEND_MINIT_FUNCTION(skeleton)
|
||||
{
|
||||
/* TODO: place your init stuff here */
|
||||
|
||||
RPC_REGISTER_LAYER(skeleton);
|
||||
REGISTER_INI_ENTRIES();
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
ZEND_MSHUTDOWN_FUNCTION(skeleton)
|
||||
{
|
||||
/* TODO: place your shutdown stuff here */
|
||||
|
||||
UNREGISTER_INI_ENTRIES();
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
ZEND_MINFO_FUNCTION(skeleton)
|
||||
{
|
||||
DISPLAY_INI_ENTRIES();
|
||||
}
|
||||
|
||||
#ifdef COMPILE_DL_SKELETON
|
||||
ZEND_GET_MODULE(skeleton);
|
||||
#endif
|
||||
|
||||
/* rpc handler functions */
|
||||
|
||||
/* {{{ skeleton_hash
|
||||
*/
|
||||
static int skeleton_hash(rpc_string name, rpc_string *hash, void *data, int num_args, char *arg_types, int type)
|
||||
{
|
||||
/* TODO: implement your hash function here. if you have specified any of the HASH_AS_INT constants, simply set
|
||||
* hash->str to NULL and set hash->len to the int hash value.
|
||||
* arg_types is a zend_parse_parameters() like string containing the types of the parameters passed enabling you
|
||||
* to find the best match if you want to hash WITH_SIGNATURE.
|
||||
* type is one of CLASS|METHOD|PROPERTY.
|
||||
*/
|
||||
hash->str = strdup(name.str);
|
||||
hash->len = name.len;
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ skeleton_name
|
||||
*/
|
||||
static int skeleton_name(rpc_string hash, rpc_string *name, void *data, int type)
|
||||
{
|
||||
/* TODO: do the opposite of what you did above */
|
||||
return FAILURE;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ skeleton_ctor
|
||||
*/
|
||||
static int skeleton_ctor(rpc_string class_name, void **data, int num_args, zval **args[])
|
||||
{
|
||||
/* TODO: use *data as a pointer to your internal data. if you want to enable your instances for
|
||||
* pooling or to be used as singletons then you have to use malloc() and free() instead of
|
||||
* emalloc() and efree() because emalloc()'ed memory will be efree()'ed on script shutdown.
|
||||
* ATTENTION: take care about possible memory holes when you use malloc()
|
||||
* calls to the handler functions are mutual exclusive per userspace instance, thus if you use
|
||||
* the same internal datastructure accross multiple userspace instances of php objects you have
|
||||
* to care for thread safety yourself (this again applies only if you want to make your instances
|
||||
* poolable/singleton-able), if you have an internal data structure per instance, then you don't
|
||||
* have to care for thread safety as the handler functions are locked by a mutex.
|
||||
*/
|
||||
return SUCCESS;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ skeleton_dtor
|
||||
*/
|
||||
static int skeleton_dtor(void *data)
|
||||
{
|
||||
/* TODO: free everything you alloc'ed above */
|
||||
return SUCCESS;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ skeleton_describe
|
||||
*/
|
||||
static int skeleton_describe(rpc_string method_name, void *data, char **arg_types, unsigned char **ref_types)
|
||||
{
|
||||
/* TODO: return a zend_parse_parameters() like string in arg_types to describe the
|
||||
* parameters taken by the specific function. if one of the parameters should be forced be reference then
|
||||
* you have to set ref_types to an array describing the function parameters as you would in the
|
||||
* ZEND_FE() macro as the last parameter.
|
||||
*/
|
||||
return SUCCESS;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ skeleton_call
|
||||
*/
|
||||
static int skeleton_call(rpc_string method_name, void **data, zval *return_value, int num_args, zval **args[])
|
||||
{
|
||||
/* TODO: implement call handler. if you passed back an arg_types string in the describe function the arguments
|
||||
* are already converted to the corresponding types, if there are too few or too much, a warning is already issued.
|
||||
* if arg_types was NULL you have to check for the right parameter count and types yourself.
|
||||
*/
|
||||
return SUCCESS;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ skeleton_get
|
||||
*/
|
||||
static int skeleton_get(rpc_string property_name, zval *return_value, void **data)
|
||||
{
|
||||
/* TODO: implement get handler */
|
||||
return SUCCESS;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ skeleton_set
|
||||
*/
|
||||
static int skeleton_set(rpc_string property_name, zval *value, void **data)
|
||||
{
|
||||
/* TODO: implement set handler */
|
||||
return SUCCESS;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ skeleton_compare
|
||||
*/
|
||||
static int skeleton_compare(void **data1, void **data2)
|
||||
{
|
||||
/* TODO: implement compare handler */
|
||||
return SUCCESS;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ skeleton_has_property
|
||||
*/
|
||||
static int skeleton_has_property(rpc_string property_name, void **data)
|
||||
{
|
||||
/* TODO: implement has property handler */
|
||||
return SUCCESS;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ skeleton_unset_property
|
||||
*/
|
||||
static int skeleton_unset_property(rpc_string property_name, void **data)
|
||||
{
|
||||
/* TODO: implement unset property handler */
|
||||
return SUCCESS;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ skeleton_get_properties
|
||||
*/
|
||||
static int skeleton_get_properties(HashTable **properties, void **data)
|
||||
{
|
||||
/* TODO: implement get properties handler */
|
||||
return SUCCESS;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
|
||||
/* custom functions */
|
||||
ZEND_FUNCTION(skeleton_function)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-basic-offset: 4
|
||||
* tab-width: 4
|
||||
* End:
|
||||
* vim600: fdm=marker
|
||||
* vim: sw=4 ts=4 noet
|
||||
*/
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 4 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2003 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.0 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_0.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: Harald Radi <h.radi@nme.at> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#ifndef SKELETON_H
|
||||
#define SKELETON_H
|
||||
|
||||
#include "../handler.h"
|
||||
#include "../php_rpc.h"
|
||||
|
||||
RPC_DECLARE_HANDLER(skeleton);
|
||||
|
||||
ZEND_MINIT_FUNCTION(skeleton);
|
||||
ZEND_MSHUTDOWN_FUNCTION(skeleton);
|
||||
ZEND_MINFO_FUNCTION(skeleton);
|
||||
|
||||
/* TODO: define your functions here */
|
||||
ZEND_FUNCTION(skeleton_function);
|
||||
/**/
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-basic-offset: 4
|
||||
* tab-width: 4
|
||||
* End:
|
||||
* vim600: fdm=marker
|
||||
* vim: sw=4 ts=4 noet
|
||||
*/
|
||||
#endif /* SKELETON_H */
|
||||
@@ -1,14 +0,0 @@
|
||||
<?php
|
||||
|
||||
$rpc = new com("class");
|
||||
|
||||
/* class hirarchy test */
|
||||
echo "is class .. " . (get_class($rpc) == "class" ? "passed" : "faiure");
|
||||
echo "\n";
|
||||
echo "is com .. " . (is_subclass_of($rpc, "com") ? "passed" : "failure");
|
||||
echo "\n";
|
||||
echo "is rpc .. " . (is_subclass_of($rpc, "rpc") ? "passed" : "failure");
|
||||
|
||||
/* uncloneable */
|
||||
//$rpc->__clone(); // issues a fatal
|
||||
?>
|
||||
@@ -1,20 +0,0 @@
|
||||
<?php
|
||||
|
||||
echo "hash test\n";
|
||||
|
||||
/* hash test */
|
||||
$rpc1 = new com("hash", true, 1);
|
||||
$rpc2 = new com("hash", false, 2);
|
||||
$rpc3 = new com("hash", true, 3);
|
||||
$rpc4 = com_load("hash", false, 4);
|
||||
$rpc5 = com_load("hash", true, 5);
|
||||
|
||||
$rpc1->{3} = "hh";
|
||||
com_set($rpc2, "hehe", 3);
|
||||
|
||||
$rpc1->call("blah");
|
||||
$rpc2->call("blah");
|
||||
$rpc3->call("blah");
|
||||
$rpc4->call("heh");
|
||||
$rpc5->call("blah");
|
||||
?>
|
||||
@@ -1,19 +0,0 @@
|
||||
<?php
|
||||
|
||||
echo "singleton test\n";
|
||||
|
||||
/* singleton test */
|
||||
$rpc1 = new com("singleton", true, 1);
|
||||
com_singleton($rpc1);
|
||||
|
||||
$rpc2 = new com("singleton", false, 2);
|
||||
$rpc3 = new com("singleton", true, 3);
|
||||
$rpc4 = new com("singleton", false, 4);
|
||||
$rpc5 = new com("singleton", true, 5);
|
||||
|
||||
delete $rpc1;
|
||||
delete $rpc2;
|
||||
delete $rpc3;
|
||||
delete $rpc4;
|
||||
delete $rpc5;
|
||||
?>
|
||||
@@ -1,18 +0,0 @@
|
||||
<?php
|
||||
|
||||
echo "pooling test\n";
|
||||
|
||||
/* pooling test */
|
||||
$rpc = new com("pooling", true, 1);
|
||||
com_poolable($rpc);
|
||||
delete $rpc;
|
||||
|
||||
$rpc = new com("pooling", true, 1);
|
||||
delete $rpc;
|
||||
|
||||
$rpc = new com("pooling", true, 1);
|
||||
delete $rpc;
|
||||
|
||||
$rpc = new com("pooling", true, 1);
|
||||
delete $rpc;
|
||||
?>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?php
|
||||
//include_once "test1.php";
|
||||
//include_once "test2.php";
|
||||
//include_once "test3.php";
|
||||
include_once "test4.php";
|
||||
?>
|
||||
@@ -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,93 +0,0 @@
|
||||
dnl
|
||||
dnl $Id$
|
||||
dnl
|
||||
|
||||
sinclude(ext/xmlrpc/libxmlrpc/acinclude.m4)
|
||||
sinclude(ext/xmlrpc/libxmlrpc/xmlrpc.m4)
|
||||
sinclude(libxmlrpc/acinclude.m4)
|
||||
sinclude(libxmlrpc/xmlrpc.m4)
|
||||
|
||||
PHP_ARG_WITH(xmlrpc, for XMLRPC-EPI support,
|
||||
[ --with-xmlrpc[=DIR] Include XMLRPC-EPI support.])
|
||||
|
||||
PHP_ARG_WITH(expat-dir, libexpat dir for XMLRPC-EPI,
|
||||
[ --with-expat-dir=DIR XMLRPC-EPI: libexpat dir for XMLRPC-EPI.],yes,no)
|
||||
|
||||
PHP_ARG_WITH(iconv-dir, iconv dir for XMLRPC-EPI,
|
||||
[ --with-iconv-dir=DIR XMLRPC-EPI: iconv dir for XMLRPC-EPI.],yes,no)
|
||||
|
||||
if test "$PHP_XMLRPC" != "no"; then
|
||||
|
||||
PHP_SUBST(XMLRPC_SHARED_LIBADD)
|
||||
AC_DEFINE(HAVE_XMLRPC,1,[ ])
|
||||
|
||||
testval=no
|
||||
for i in /usr /usr/local $PHP_EXPAT_DIR $XMLRPC_DIR; do
|
||||
if test -f $i/lib/libexpat.a -o -f $i/lib/libexpat.$SHLIB_SUFFIX_NAME; then
|
||||
AC_DEFINE(HAVE_LIBEXPAT2,1,[ ])
|
||||
PHP_ADD_LIBRARY_WITH_PATH(expat, $i/lib, XMLRPC_SHARED_LIBADD)
|
||||
PHP_ADD_INCLUDE($i/include)
|
||||
testval=yes
|
||||
fi
|
||||
done
|
||||
|
||||
if test "$testval" = "no"; then
|
||||
AC_MSG_ERROR(XML-RPC support requires libexpat. Use --with-expat-dir=<DIR>)
|
||||
fi
|
||||
|
||||
if test "$PHP_ICONV_DIR" != "no"; then
|
||||
PHP_ICONV=$PHP_ICONV_DIR
|
||||
fi
|
||||
|
||||
if 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
|
||||
|
||||
|
||||
if test "$PHP_XMLRPC" = "yes"; then
|
||||
XMLRPC_CHECKS
|
||||
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
|
||||
|
||||
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
|
||||
dnl queue.h or base64.h. Distributions have to create dir
|
||||
dnl for xmlrpc-epi because of 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)
|
||||
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/lib, XMLRPC_SHARED_LIBADD)
|
||||
|
||||
fi
|
||||
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
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,32 +0,0 @@
|
||||
# Local macros for automake & autoconf
|
||||
|
||||
AC_DEFUN(XMLRPC_FUNCTION_CHECKS,[
|
||||
|
||||
# Standard XMLRPC list
|
||||
AC_CHECK_FUNCS( \
|
||||
strtoul strtoull snprintf \
|
||||
strstr strpbrk strerror\
|
||||
memcpy memmove)
|
||||
|
||||
])
|
||||
|
||||
AC_DEFUN(XMLRPC_HEADER_CHECKS,[
|
||||
AC_HEADER_STDC
|
||||
AC_CHECK_HEADERS(xmlparse.h xmltok.h stdlib.h strings.h string.h)
|
||||
])
|
||||
|
||||
AC_DEFUN(XMLRPC_TYPE_CHECKS,[
|
||||
|
||||
AC_REQUIRE([AC_C_CONST])
|
||||
AC_REQUIRE([AC_C_INLINE])
|
||||
AC_CHECK_SIZEOF(char, 1)
|
||||
|
||||
AC_CHECK_SIZEOF(int, 4)
|
||||
AC_CHECK_SIZEOF(long, 4)
|
||||
AC_CHECK_SIZEOF(long long, 8)
|
||||
AC_TYPE_SIZE_T
|
||||
AC_HEADER_TIME
|
||||
AC_TYPE_UID_T
|
||||
|
||||
|
||||
])
|
||||
@@ -1,192 +0,0 @@
|
||||
static const char rcsid[] = "#(@) $Id$";
|
||||
|
||||
/*
|
||||
|
||||
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 "base64.h"
|
||||
|
||||
static unsigned char dtable[512];
|
||||
|
||||
void buffer_new(struct buffer_st *b)
|
||||
{
|
||||
b->length = 512;
|
||||
b->data = malloc(sizeof(char)*(b->length));
|
||||
b->data[0] = 0;
|
||||
b->ptr = b->data;
|
||||
b->offset = 0;
|
||||
}
|
||||
|
||||
void buffer_add(struct buffer_st *b, char c)
|
||||
{
|
||||
*(b->ptr++) = c;
|
||||
b->offset++;
|
||||
if (b->offset == b->length) {
|
||||
b->length += 512;
|
||||
b->data = realloc(b->data, b->length);
|
||||
b->ptr = b->data + b->offset;
|
||||
}
|
||||
}
|
||||
|
||||
void buffer_delete(struct buffer_st *b)
|
||||
{
|
||||
free(b->data);
|
||||
b->length = 0;
|
||||
b->offset = 0;
|
||||
b->ptr = NULL;
|
||||
b->data = NULL;
|
||||
}
|
||||
|
||||
void base64_encode(struct buffer_st *b, const char *source, int length)
|
||||
{
|
||||
int i, hiteof = 0;
|
||||
int offset = 0;
|
||||
int olen;
|
||||
|
||||
olen = 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) {
|
||||
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(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[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,38 +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(struct buffer_st *b, const char *source, int length);
|
||||
void base64_decode(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,119 +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.
|
||||
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifndef PHP_WIN32
|
||||
#include <php_config.h>
|
||||
#else
|
||||
#include <config.w32.h>
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
static const char rcsid[] = "#(@) $Id$";
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef HAVE_GICONV_H
|
||||
#include <giconv.h>
|
||||
#else
|
||||
#include <iconv.h>
|
||||
#endif
|
||||
|
||||
#include "encodings.h"
|
||||
|
||||
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) {
|
||||
int outlenleft = src_len;
|
||||
int outlen = src_len;
|
||||
int inlenleft = src_len;
|
||||
iconv_t ic = iconv_open(to_enc, from_enc);
|
||||
char* src_ptr = (char*)src;
|
||||
char* out_ptr = 0;
|
||||
|
||||
if(ic != (iconv_t)-1) {
|
||||
size_t st;
|
||||
outbuf = (char*)malloc(outlen + 1);
|
||||
|
||||
if(outbuf) {
|
||||
out_ptr = (char*)outbuf;
|
||||
while(inlenleft) {
|
||||
st = iconv(ic, &src_ptr, &inlenleft, &out_ptr, &outlenleft);
|
||||
if(st == -1) {
|
||||
if(errno == E2BIG) {
|
||||
int diff = out_ptr - outbuf;
|
||||
outlen += inlenleft;
|
||||
outlenleft += inlenleft;
|
||||
outbuf = (char*)realloc(outbuf, outlen + 1);
|
||||
if(!outbuf) {
|
||||
break;
|
||||
}
|
||||
out_ptr = outbuf + diff;
|
||||
}
|
||||
else {
|
||||
free(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,982 +0,0 @@
|
||||
static const char rcsid[] = "#(@) $Id$";
|
||||
|
||||
/*
|
||||
* 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/
|
||||
*
|
||||
*
|
||||
****************************************************************/
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "xmlrpc_win32.h"
|
||||
#endif
|
||||
#include <stdlib.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 **index;
|
||||
static datanode **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 = malloc(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 = malloc(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;
|
||||
free(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;
|
||||
free(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;
|
||||
|
||||
free(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) {
|
||||
free(index);
|
||||
free(posn_index);
|
||||
q->sorted = False_;
|
||||
}
|
||||
|
||||
/* Now allocate memory of array, array of pointers */
|
||||
|
||||
index = malloc(q->size * sizeof(q->cursor->data));
|
||||
if(index == NULL)
|
||||
return False_;
|
||||
|
||||
posn_index = malloc(q->size * sizeof(q->cursor));
|
||||
if(posn_index == NULL) {
|
||||
free(index);
|
||||
return False_;
|
||||
}
|
||||
|
||||
/* Walk queue putting pointers into array */
|
||||
|
||||
d = Q_Head(q);
|
||||
for(i=0; i < q->size; i++) {
|
||||
index[i] = d;
|
||||
posn_index[i] = q->cursor;
|
||||
d = Q_Next(q);
|
||||
}
|
||||
|
||||
/* Now sort the index */
|
||||
|
||||
QuickSort(index, 0, q->size - 1, Comp);
|
||||
|
||||
/* Rearrange the actual queue into correct order */
|
||||
|
||||
dn = q->head;
|
||||
i = 0;
|
||||
while(dn != NULL) {
|
||||
dn->data = 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, 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 = posn_index[idx];
|
||||
|
||||
return 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,244 +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.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
static const char rcsid[] = "#(@) $Id$";
|
||||
|
||||
|
||||
#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.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 unneccesary 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 "simplestring.h"
|
||||
|
||||
#define my_free(thing) if(thing) {free(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*)malloc(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;
|
||||
}
|
||||
}
|
||||
/******/
|
||||
|
||||
/****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, int add_len) {
|
||||
if(target && source) {
|
||||
if(!target->str) {
|
||||
simplestring_init_str(target);
|
||||
}
|
||||
if(target->len + add_len + 1 > target->size) {
|
||||
/* newsize is current length + new length */
|
||||
int newsize = target->len + add_len + 1;
|
||||
int incr = target->size * 2;
|
||||
|
||||
/* align to SIMPLESTRING_INCR increments */
|
||||
newsize = newsize - (newsize % incr) + incr;
|
||||
target->str = (char*)realloc(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 */
|
||||
int len; /* length of string/buf */
|
||||
int 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, int add_len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/*-******************************
|
||||
* end simplestring header stuff *
|
||||
********************************/
|
||||
|
||||
#endif /* __SIMPLESTRING_H__ */
|
||||
@@ -1,375 +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,91 +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,734 +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.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
static const char rcsid[] = "#(@) $Id$";
|
||||
|
||||
|
||||
|
||||
/****h* ABOUT/xml_element
|
||||
* NAME
|
||||
* xml_element
|
||||
* AUTHOR
|
||||
* Dan Libby, aka danda (dan@libby.com)
|
||||
* CREATION DATE
|
||||
* 06/2000
|
||||
* HISTORY
|
||||
* $Log$
|
||||
* 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.
|
||||
******/
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "xmlrpc_win32.h"
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "xml_element.h"
|
||||
#include "queue.h"
|
||||
#include "expat.h"
|
||||
#include "encodings.h"
|
||||
|
||||
#define my_free(thing) if(thing) {free(thing); thing = 0;}
|
||||
|
||||
#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);
|
||||
my_free((char*)root->name);
|
||||
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 = calloc(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;
|
||||
}
|
||||
if(c >= 10) {
|
||||
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 = 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= malloc(iLength+1);
|
||||
if(NewBuffer) {
|
||||
bufcopy=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 file_out_fptr(void *f, const char *text, int size)
|
||||
{
|
||||
fputs(text, (FILE *)f);
|
||||
}
|
||||
|
||||
/* print buf to simplestring */
|
||||
static simplestring_out_fptr(void *f, const char *text, int size)
|
||||
{
|
||||
simplestring* buf = (simplestring*)f;
|
||||
if(buf) {
|
||||
simplestring_addn(buf, text, size);
|
||||
}
|
||||
}
|
||||
|
||||
/****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 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*)strdup(name);
|
||||
mydata->current->parent = c;
|
||||
|
||||
/* init attrs */
|
||||
while(p && *p) {
|
||||
xml_element_attr* attr = malloc(sizeof(xml_element_attr));
|
||||
if(attr) {
|
||||
attr->key = strdup(*p);
|
||||
attr->val = strdup(*(p+1));
|
||||
Q_PushTail(&mydata->current->attrs, attr);
|
||||
|
||||
p += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* expat end of element handler */
|
||||
static void 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 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);
|
||||
free(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, startElement, endElement);
|
||||
XML_SetCharacterDataHandler(parser, 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, 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 = XML_ErrorString(err_code);
|
||||
if(byte_idx >= 0) {
|
||||
snprintf(buf,
|
||||
sizeof(buf),
|
||||
"\n\tdata beginning %i 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: %i\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 accordint 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,319 +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.
|
||||
|
||||
*/
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "xmlrpc_win32.h"
|
||||
#endif
|
||||
#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(&buf, el->text.str, el->text.len);
|
||||
XMLRPC_SetValueBase64(xCurrent, buf.data, buf.offset);
|
||||
buffer_delete(&buf);
|
||||
}
|
||||
}
|
||||
else if(!strcmp(el->name, ATTR_VECTOR)) {
|
||||
xml_element* iter = (xml_element*)Q_Head(&el->children);
|
||||
|
||||
if(!type || !strcmp(type, ATTR_MIXED)) {
|
||||
XMLRPC_SetIsVector(xCurrent, xmlrpc_vector_mixed);
|
||||
}
|
||||
else if(!strcmp(type, ATTR_ARRAY)) {
|
||||
XMLRPC_SetIsVector(xCurrent, xmlrpc_vector_array);
|
||||
}
|
||||
else if(!strcmp(type, ATTR_STRUCT)) {
|
||||
XMLRPC_SetIsVector(xCurrent, xmlrpc_vector_struct);
|
||||
}
|
||||
while( iter ) {
|
||||
XMLRPC_VALUE xNext = XMLRPC_CreateValueEmpty();
|
||||
xml_element_to_DANDARPC_REQUEST_worker(request, xNext, iter);
|
||||
XMLRPC_AddValueToVector(xCurrent, xNext);
|
||||
iter = (xml_element*)Q_Next(&el->children);
|
||||
}
|
||||
}
|
||||
else {
|
||||
xml_element* iter = (xml_element*)Q_Head(&el->children);
|
||||
while( iter ) {
|
||||
xml_element_to_DANDARPC_REQUEST_worker(request, xCurrent, iter);
|
||||
iter = (xml_element*)Q_Next(&el->children);
|
||||
}
|
||||
|
||||
if(!strcmp(el->name, ELEM_METHODCALL)) {
|
||||
if(request) {
|
||||
XMLRPC_RequestSetRequestType(request, xmlrpc_request_call);
|
||||
}
|
||||
}
|
||||
else if(!strcmp(el->name, ELEM_METHODRESPONSE)) {
|
||||
if(request) {
|
||||
XMLRPC_RequestSetRequestType(request, xmlrpc_request_response);
|
||||
}
|
||||
}
|
||||
else if(!strcmp(el->name, ELEM_METHODNAME)) {
|
||||
if(request) {
|
||||
XMLRPC_RequestSetMethodName(request, el->text.str);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return xCurrent;
|
||||
}
|
||||
|
||||
XMLRPC_VALUE xml_element_to_DANDARPC_VALUE(xml_element* el)
|
||||
{
|
||||
return xml_element_to_DANDARPC_REQUEST_worker(NULL, NULL, el);
|
||||
}
|
||||
|
||||
XMLRPC_VALUE xml_element_to_DANDARPC_REQUEST(XMLRPC_REQUEST request, xml_element* el)
|
||||
{
|
||||
if(request) {
|
||||
return XMLRPC_RequestSetData(request, xml_element_to_DANDARPC_REQUEST_worker(request, NULL, el));
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
xml_element* DANDARPC_to_xml_element_worker(XMLRPC_REQUEST request, XMLRPC_VALUE node) {
|
||||
#define BUF_SIZE 512
|
||||
xml_element* root = NULL;
|
||||
if(node) {
|
||||
char buf[BUF_SIZE];
|
||||
const char* id = XMLRPC_GetValueID(node);
|
||||
XMLRPC_VALUE_TYPE type = XMLRPC_GetValueType(node);
|
||||
XMLRPC_REQUEST_OUTPUT_OPTIONS output = XMLRPC_RequestGetOutputOptions(request);
|
||||
int bNoAddType = (type == xmlrpc_string && request && output && output->xml_elem_opts.verbosity == xml_elem_no_white_space);
|
||||
xml_element* elem_val = xml_elem_new();
|
||||
const char* pAttrType = NULL;
|
||||
|
||||
xml_element_attr* attr_type = bNoAddType ? NULL : malloc(sizeof(xml_element_attr));
|
||||
|
||||
if(attr_type) {
|
||||
attr_type->key = strdup(ATTR_TYPE);
|
||||
attr_type->val = 0;
|
||||
Q_PushTail(&elem_val->attrs, attr_type);
|
||||
}
|
||||
|
||||
elem_val->name = (type == xmlrpc_vector) ? strdup(ATTR_VECTOR) : strdup(ATTR_SCALAR);
|
||||
|
||||
if(id && *id) {
|
||||
xml_element_attr* attr_id = malloc(sizeof(xml_element_attr));
|
||||
if(attr_id) {
|
||||
attr_id->key = strdup(ATTR_ID);
|
||||
attr_id->val = strdup(id);
|
||||
Q_PushTail(&elem_val->attrs, attr_id);
|
||||
}
|
||||
}
|
||||
|
||||
switch(type) {
|
||||
case xmlrpc_string:
|
||||
pAttrType = ATTR_STRING;
|
||||
simplestring_addn(&elem_val->text, XMLRPC_GetValueString(node), XMLRPC_GetValueStringLen(node));
|
||||
break;
|
||||
case xmlrpc_int:
|
||||
pAttrType = ATTR_INT;
|
||||
snprintf(buf, BUF_SIZE, "%i", XMLRPC_GetValueInt(node));
|
||||
simplestring_add(&elem_val->text, buf);
|
||||
break;
|
||||
case xmlrpc_boolean:
|
||||
pAttrType = ATTR_BOOLEAN;
|
||||
snprintf(buf, BUF_SIZE, "%i", XMLRPC_GetValueBoolean(node));
|
||||
simplestring_add(&elem_val->text, buf);
|
||||
break;
|
||||
case xmlrpc_double:
|
||||
pAttrType = ATTR_DOUBLE;
|
||||
snprintf(buf, BUF_SIZE, "%f", XMLRPC_GetValueDouble(node));
|
||||
simplestring_add(&elem_val->text, buf);
|
||||
break;
|
||||
case xmlrpc_datetime:
|
||||
pAttrType = ATTR_DATETIME;
|
||||
simplestring_add(&elem_val->text, XMLRPC_GetValueDateTime_ISO8601(node));
|
||||
break;
|
||||
case xmlrpc_base64:
|
||||
{
|
||||
struct buffer_st buf;
|
||||
pAttrType = ATTR_BASE64;
|
||||
base64_encode(&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 = strdup(pAttrType);
|
||||
}
|
||||
root = elem_val;
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
||||
xml_element* DANDARPC_VALUE_to_xml_element(XMLRPC_VALUE node) {
|
||||
return DANDARPC_to_xml_element_worker(NULL, node);
|
||||
}
|
||||
|
||||
xml_element* DANDARPC_REQUEST_to_xml_element(XMLRPC_REQUEST request) {
|
||||
xml_element* wrapper = NULL;
|
||||
xml_element* root = NULL;
|
||||
if(request) {
|
||||
XMLRPC_REQUEST_TYPE request_type = XMLRPC_RequestGetRequestType(request);
|
||||
const char* pStr = NULL;
|
||||
xml_element_attr* version = malloc(sizeof(xml_element_attr));
|
||||
version->key = strdup(ATTR_VERSION);
|
||||
version->val = strdup(VAL_VERSION_0_9);
|
||||
|
||||
wrapper = xml_elem_new();
|
||||
|
||||
if(request_type == xmlrpc_request_response) {
|
||||
pStr = ELEM_METHODRESPONSE;
|
||||
}
|
||||
else if(request_type == xmlrpc_request_call) {
|
||||
pStr = ELEM_METHODCALL;
|
||||
}
|
||||
if(pStr) {
|
||||
wrapper->name = strdup(pStr);
|
||||
}
|
||||
|
||||
root = xml_elem_new();
|
||||
root->name = strdup(ELEM_ROOT);
|
||||
Q_PushTail(&root->attrs, version);
|
||||
Q_PushTail(&root->children, wrapper);
|
||||
|
||||
pStr = XMLRPC_RequestGetMethodName(request);
|
||||
|
||||
if(pStr) {
|
||||
xml_element* method = xml_elem_new();
|
||||
method->name = strdup(ELEM_METHODNAME);
|
||||
simplestring_add(&method->text, pStr);
|
||||
Q_PushTail(&wrapper->children, method);
|
||||
}
|
||||
Q_PushTail(&wrapper->children,
|
||||
DANDARPC_to_xml_element_worker(request, XMLRPC_RequestGetData(request)));
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
||||
@@ -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,673 +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 *
|
||||
************************************************************************/
|
||||
|
||||
|
||||
static const char rcsid[] = "#(@) $Id:";
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "xmlrpc_win32.h"
|
||||
#endif
|
||||
#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 = malloc(sizeof(xml_element_attr));
|
||||
if (attr) {
|
||||
attr->key = key ? strdup(key) : NULL;
|
||||
attr->val = val ? strdup(val) : NULL;
|
||||
}
|
||||
return attr;
|
||||
}
|
||||
|
||||
struct array_info {
|
||||
char kids_type[30];
|
||||
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*)calloc(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 wether 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 guage
|
||||
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 conjuction 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(&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) {
|
||||
free(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(&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 = strdup(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 = strdup("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 = strdup(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 = strdup(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 = strdup("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,409 +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.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
static const char rcsid[] = "#(@) $Id$";
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "xmlrpc_win32.h"
|
||||
#endif
|
||||
#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(&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 = strdup(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 = strdup(ELEM_STRING);
|
||||
simplestring_addn(&elem_val->text, XMLRPC_GetValueString(node), XMLRPC_GetValueStringLen(node));
|
||||
break;
|
||||
case xmlrpc_int:
|
||||
elem_val->name = strdup(ELEM_INT);
|
||||
snprintf(buf, BUF_SIZE, "%i", XMLRPC_GetValueInt(node));
|
||||
simplestring_add(&elem_val->text, buf);
|
||||
break;
|
||||
case xmlrpc_boolean:
|
||||
elem_val->name = strdup(ELEM_BOOLEAN);
|
||||
snprintf(buf, BUF_SIZE, "%i", XMLRPC_GetValueBoolean(node));
|
||||
simplestring_add(&elem_val->text, buf);
|
||||
break;
|
||||
case xmlrpc_double:
|
||||
elem_val->name = strdup(ELEM_DOUBLE);
|
||||
snprintf(buf, BUF_SIZE, "%f", XMLRPC_GetValueDouble(node));
|
||||
simplestring_add(&elem_val->text, buf);
|
||||
break;
|
||||
case xmlrpc_datetime:
|
||||
elem_val->name = strdup(ELEM_DATETIME);
|
||||
simplestring_add(&elem_val->text, XMLRPC_GetValueDateTime_ISO8601(node));
|
||||
break;
|
||||
case xmlrpc_base64:
|
||||
{
|
||||
struct buffer_st buf;
|
||||
elem_val->name = strdup(ELEM_BASE64);
|
||||
base64_encode(&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 = strdup(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 = strdup(ELEM_DATA);
|
||||
|
||||
elem_val->name = strdup(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 = strdup(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 = strdup(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 = strdup(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 = strdup(ELEM_MEMBER);
|
||||
name->name = strdup(ELEM_NAME);
|
||||
value->name = strdup(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 = strdup(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 = strdup(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 = strdup(pStr);
|
||||
}
|
||||
|
||||
if(request_type == xmlrpc_request_call) {
|
||||
pStr = XMLRPC_RequestGetMethodName(request);
|
||||
|
||||
if (pStr) {
|
||||
xml_element* method = xml_elem_new();
|
||||
method->name = strdup(ELEM_METHODNAME);
|
||||
simplestring_add(&method->text, pStr);
|
||||
Q_PushTail(&wrapper->children, method);
|
||||
}
|
||||
}
|
||||
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 = strdup(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,454 +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 */
|
||||
|
||||
#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,12 +0,0 @@
|
||||
AC_DEFUN(XMLRPC_CHECKS,[
|
||||
|
||||
AC_REQUIRE([AC_PROG_CC])
|
||||
AC_REQUIRE([AC_PROG_LN_S])
|
||||
AC_REQUIRE([AC_PROG_RANLIB])
|
||||
|
||||
AC_DEFINE(UNDEF_THREADS_HACK,,[ ])
|
||||
|
||||
XMLRPC_HEADER_CHECKS
|
||||
XMLRPC_TYPE_CHECKS
|
||||
XMLRPC_FUNCTION_CHECKS
|
||||
])
|
||||
@@ -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.9 2001/09/29 21:58:05 danda
|
||||
* adding cvs log to history section
|
||||
*
|
||||
* 4/10/2001 -- danda -- initial introspection support
|
||||
* TODO
|
||||
* NOTES
|
||||
*******/
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "xmlrpc_win32.h"
|
||||
#endif
|
||||
#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.
|
||||
*/
|
||||
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 */
|
||||
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 = calloc(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 0;
|
||||
}
|
||||
/*******/
|
||||
|
||||
/*-**********************
|
||||
* End Introspection API *
|
||||
************************/
|
||||
|
||||
|
||||
|
||||
@@ -1,101 +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,106 +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,178 +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) {free(thing); thing = 0;}
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* XMLRPC_PRIVATE_ALREADY_INCLUDED */
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
#ifndef _XMLRPC_WIN32_H
|
||||
#define _XMLRPC_WIN32_H
|
||||
/* just some things needed to compile win32 */
|
||||
#include <windows.h>
|
||||
#include <stdlib.h>
|
||||
#define inline __inline
|
||||
#define snprintf _snprintf
|
||||
#define strcasecmp(s1, s2) stricmp(s1, s2)
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,120 +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 */
|
||||
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 4 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2003 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.0 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_0.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
|
||||
|
||||
/* You should tweak config.m4 so this symbol (or some else suitable)
|
||||
gets defined.
|
||||
*/
|
||||
#if 1 /* HAVE_XMLRPC */
|
||||
|
||||
extern zend_module_entry xmlrpc_module_entry;
|
||||
#define phpext_xmlrpc_ptr &xmlrpc_module_entry
|
||||
|
||||
#ifdef PHP_WIN32
|
||||
#define PHP_XMLRPC_API __declspec(dllexport)
|
||||
#else
|
||||
#define PHP_XMLRPC_API
|
||||
#endif
|
||||
|
||||
PHP_MINIT_FUNCTION(xmlrpc);
|
||||
PHP_MSHUTDOWN_FUNCTION(xmlrpc);
|
||||
PHP_RINIT_FUNCTION(xmlrpc);
|
||||
PHP_RSHUTDOWN_FUNCTION(xmlrpc);
|
||||
PHP_MINFO_FUNCTION(xmlrpc);
|
||||
|
||||
PHP_FUNCTION(xmlrpc_encode);
|
||||
PHP_FUNCTION(xmlrpc_decode);
|
||||
PHP_FUNCTION(xmlrpc_decode_request);
|
||||
PHP_FUNCTION(xmlrpc_encode_request);
|
||||
PHP_FUNCTION(xmlrpc_get_type);
|
||||
PHP_FUNCTION(xmlrpc_set_type);
|
||||
PHP_FUNCTION(xmlrpc_is_fault);
|
||||
PHP_FUNCTION(xmlrpc_server_create);
|
||||
PHP_FUNCTION(xmlrpc_server_destroy);
|
||||
PHP_FUNCTION(xmlrpc_server_register_method);
|
||||
PHP_FUNCTION(xmlrpc_server_call_method);
|
||||
PHP_FUNCTION(xmlrpc_parse_method_descriptions);
|
||||
PHP_FUNCTION(xmlrpc_server_add_introspection_data);
|
||||
PHP_FUNCTION(xmlrpc_server_register_introspection_callback);
|
||||
|
||||
/* Fill in this structure and use entries in it
|
||||
for thread safety instead of using true globals.
|
||||
*/
|
||||
typedef struct {
|
||||
int x; /* fix error in msvc, cannot have empty structs */
|
||||
} zend_xmlrpc_globals;
|
||||
|
||||
/* In every function that needs to use variables in zend_xmlrpc_globals,
|
||||
do call XMLRPCLS_FETCH(); after declaring other variables used by
|
||||
that function, and always refer to them as XMLRPCG(variable).
|
||||
You are encouraged to rename these macros something shorter, see
|
||||
examples in any other php module directory.
|
||||
*/
|
||||
|
||||
#else
|
||||
|
||||
#define phpext_xmlrpc_ptr NULL
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* _PHP_XMLRPC_H */
|
||||
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* tab-width: 4
|
||||
* c-basic-offset: 4
|
||||
* End:
|
||||
*/
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,211 +0,0 @@
|
||||
# Microsoft Developer Studio Project File - Name="xmlrpc" - Package Owner=<4>
|
||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
||||
# ** DO NOT EDIT **
|
||||
|
||||
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
|
||||
|
||||
CFG=xmlrpc - Win32 Debug_TS
|
||||
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
||||
!MESSAGE use the Export Makefile command and run
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "xmlrpc.mak".
|
||||
!MESSAGE
|
||||
!MESSAGE You can specify a configuration when running NMAKE
|
||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "xmlrpc.mak" CFG="xmlrpc - Win32 Debug_TS"
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE "xmlrpc - Win32 Debug_TS" (based on "Win32 (x86) Dynamic-Link Library")
|
||||
!MESSAGE "xmlrpc - Win32 Release_TS" (based on "Win32 (x86) Dynamic-Link Library")
|
||||
!MESSAGE
|
||||
|
||||
# Begin Project
|
||||
# PROP AllowPerConfigDependencies 0
|
||||
# PROP Scc_ProjName ""
|
||||
# PROP Scc_LocalPath ""
|
||||
CPP=cl.exe
|
||||
MTL=midl.exe
|
||||
RSC=rc.exe
|
||||
|
||||
!IF "$(CFG)" == "xmlrpc - Win32 Debug_TS"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 1
|
||||
# PROP BASE Output_Dir "Debug_TS"
|
||||
# PROP BASE Intermediate_Dir "Debug_TS"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 1
|
||||
# PROP Output_Dir "Debug_TS"
|
||||
# PROP Intermediate_Dir "Debug_TS"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "XMLRPC_EXPORTS" /YX /FD /GZ /c
|
||||
# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\.." /I "..\..\main" /I "..\..\Zend" /I "..\..\TSRM" /I "libxmlrpc" /I "..\..\bundle\expat" /D HAVE_XMLRPC=1 /D "ZEND_WIN32" /D "PHP_WIN32" /D ZEND_DEBUG=1 /D ZTS=1 /D COMPILE_DL_XMLRPC=1 /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "XMLRPC_EXPORTS" /YX /FD /GZ /c
|
||||
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||
# ADD BASE RSC /l 0x1009 /d "_DEBUG"
|
||||
# ADD RSC /l 0x1009 /d "_DEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
|
||||
# ADD LINK32 iconv.lib php4ts_debug.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"..\..\Debug_TS/php_xmlrpc.dll" /pdbtype:sept /libpath:"..\..\Debug_TS"
|
||||
|
||||
!ELSEIF "$(CFG)" == "xmlrpc - Win32 Release_TS"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "Release_TS"
|
||||
# PROP BASE Intermediate_Dir "Release_TS"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "Release_TS"
|
||||
# PROP Intermediate_Dir "Release_TS"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "XMLRPC_EXPORTS" /YX /FD /c
|
||||
# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\.." /I "..\..\main" /I "..\..\Zend" /I "..\..\TSRM" /I "libxmlrpc" /I "..\..\bundle\expat" /D HAVE_XMLRPC=1 /D "ZEND_WIN32" /D ZEND_DEBUG=0 /D "PHP_WIN32" /D ZTS=1 /D COMPILE_DL_XMLRPC=1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "XMLRPC_EXPORTS" /YX /FD /c
|
||||
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||
# ADD BASE RSC /l 0x1009 /d "NDEBUG"
|
||||
# ADD RSC /l 0x1009 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
|
||||
# ADD LINK32 iconv.lib php4ts.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"..\..\Release_TS/php_xmlrpc.dll" /libpath:"..\..\Release_TS"
|
||||
|
||||
!ENDIF
|
||||
|
||||
# Begin Target
|
||||
|
||||
# Name "xmlrpc - Win32 Debug_TS"
|
||||
# Name "xmlrpc - Win32 Release_TS"
|
||||
# Begin Group "Source Files"
|
||||
|
||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=".\xmlrpc-epi-php.c"
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Header Files"
|
||||
|
||||
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\php_xmlrpc.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Resource Files"
|
||||
|
||||
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
|
||||
# End Group
|
||||
# Begin Group "libxmlrpc"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\libxmlrpc\base64.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\libxmlrpc\base64.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\libxmlrpc\encodings.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\libxmlrpc\encodings.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\libxmlrpc\queue.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\libxmlrpc\queue.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\libxmlrpc\simplestring.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\libxmlrpc\simplestring.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\libxmlrpc\system_methods.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\libxmlrpc\system_methods_private.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\libxmlrpc\xml_element.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\libxmlrpc\xml_element.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\libxmlrpc\xml_to_dandarpc.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\libxmlrpc\xml_to_dandarpc.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\libxmlrpc\xml_to_soap.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\libxmlrpc\xml_to_soap.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\libxmlrpc\xml_to_xmlrpc.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\libxmlrpc\xml_to_xmlrpc.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\libxmlrpc\xmlrpc.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\libxmlrpc\xmlrpc.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\libxmlrpc\xmlrpc_introspection.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\libxmlrpc\xmlrpc_introspection.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\libxmlrpc\xmlrpc_introspection_private.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\libxmlrpc\xmlrpc_private.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# End Target
|
||||
# End Project
|
||||
Reference in New Issue
Block a user