aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIOhannes m zmölnig <zmoelnig@users.sourceforge.net>2005-03-08 10:23:43 +0000
committerIOhannes m zmölnig <zmoelnig@users.sourceforge.net>2005-03-08 10:23:43 +0000
commit922cb5559b9f2f97279fa24cc9c5862c8b666495 (patch)
tree10b3616acd63f3d60689c1a26aa4ccadf6115511
This commit was generated by cvs2svn to compensate for changes in r2603,svn2git-root
which included commits to RCS files with non-trunk default branches. svn path=/trunk/externals/iem/iemxmlrpc/; revision=2604
-rw-r--r--LICENSE.txt504
-rw-r--r--Makefile100
-rw-r--r--README.txt29
-rw-r--r--main.cpp805
-rw-r--r--xmlrpc++/COPYING504
-rw-r--r--xmlrpc++/Makefile39
-rw-r--r--xmlrpc++/Makefile.win189
-rw-r--r--xmlrpc++/README.html109
-rw-r--r--xmlrpc++/src/Doxyfile1041
-rw-r--r--xmlrpc++/src/XmlRpc.h94
-rw-r--r--xmlrpc++/src/XmlRpcClient.cpp413
-rw-r--r--xmlrpc++/src/XmlRpcClient.h125
-rw-r--r--xmlrpc++/src/XmlRpcDispatch.cpp209
-rw-r--r--xmlrpc++/src/XmlRpcDispatch.h88
-rw-r--r--xmlrpc++/src/XmlRpcException.h42
-rw-r--r--xmlrpc++/src/XmlRpcServer.cpp284
-rw-r--r--xmlrpc++/src/XmlRpcServer.h104
-rw-r--r--xmlrpc++/src/XmlRpcServerConnection.cpp371
-rw-r--r--xmlrpc++/src/XmlRpcServerConnection.h102
-rw-r--r--xmlrpc++/src/XmlRpcServerMethod.cpp21
-rw-r--r--xmlrpc++/src/XmlRpcServerMethod.h47
-rw-r--r--xmlrpc++/src/XmlRpcSocket.cpp260
-rw-r--r--xmlrpc++/src/XmlRpcSocket.h69
-rw-r--r--xmlrpc++/src/XmlRpcSource.cpp35
-rw-r--r--xmlrpc++/src/XmlRpcSource.h55
-rw-r--r--xmlrpc++/src/XmlRpcUtil.cpp250
-rw-r--r--xmlrpc++/src/XmlRpcUtil.h61
-rw-r--r--xmlrpc++/src/XmlRpcValue.cpp611
-rw-r--r--xmlrpc++/src/XmlRpcValue.h189
-rw-r--r--xmlrpc++/src/base64.h379
-rw-r--r--xmlrpc-init.pd12
-rw-r--r--xmlrpc-test.pd31
-rw-r--r--xmlrpc-test.py75
-rw-r--r--xmlrpc.dsp96
-rw-r--r--xmlrpc.dsw29
-rw-r--r--xmlrpc.vcproj177
36 files changed, 7549 insertions, 0 deletions
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
index 0000000..b1e3f5a
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,504 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..4143a6f
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,100 @@
+# xmlrpc - XMLRPC external for PD
+#
+# Makefile for gcc @ linux
+#
+# usage:
+# to build run "make -f Makefile.linux"
+# to install (as root), do "make -f Makefile.linux install"
+#
+#* Author: Thomas Grill t.grill [at] gmx.net
+#
+# License LGPL see LICENSE.txt
+# IEM - Institute of Electronic Music and Acoustics, Graz
+# Inffeldgasse 10/3, 8010 Graz, Austria
+# http://iem.at
+#************************************************************/
+
+
+# Configuration: ##########################
+
+
+# where are the PD header files?
+# leave it blank if it is a system directory (like /usr/local/include),
+# since gcc 3.2 complains about it
+PDPATH=
+
+# where should flext libraries be built?
+TARGDIR=./pd-linux
+
+# where are the XMLRPC++ header files?
+XMLRPCPATH=xmlrpc++
+XMLRPCINC=$(XMLRPCPATH)/src/
+XMLRPCLIB=libXmlRpc.a
+
+# where should the external be installed?
+# (leave blank to omit installation)
+INSTPATH=/usr/local/lib/pd/extra
+
+# additional compiler flags
+# (check if they fit for your system!)
+# UFLAGS=-mcpu=pentiumpro # gcc 2.95
+UFLAGS=-mcpu=pentium3 -msse # gcc 3.2
+
+###########################################
+
+# compiler+linker stuff
+INCLUDES=$(PDPATH) $(XMLRPCINC)
+LIBPATH= ${XMLRPCPATH}
+
+FLAGS=-DPD ${U_FLAGS}
+CFLAGS=-O6
+#CFLAGS=-g
+LIBS=m util XmlRpc
+
+# ---------------------------------------------
+# the rest can stay untouched
+# ----------------------------------------------
+NAME=iemxmlrpc
+
+# all the source files from the package
+DIR=.
+SRCS=main.cpp
+
+MAKEFILE=Makefile
+
+TARGET=$(TARGDIR)/$(NAME).pd_linux
+
+# default target
+all: $(XMLRPCPATH)/$(XMLRPCLIB) $(TARGDIR) $(TARGET)
+
+$(XMLRPCPATH)/$(XMLRPCLIB): $(XMLRPCPATH)
+ make -C $(XMLRPCPATH)
+
+$(patsubst %,$(DIR)/%,$(SRCS)): $(patsubst %,$(DIR)/%,$(HDRS)) $(MAKEFILE)
+ touch $@
+
+$(TARGDIR):
+ mkdir -p $(TARGDIR)
+
+$(TARGDIR)/%.o : $(DIR)/%.cpp
+ $(CXX) -c $(CFLAGS) $(FLAGS) $(patsubst %,-I%,$(INCLUDES)) $< -o $@
+
+$(TARGET) : $(patsubst %.cpp,$(TARGDIR)/%.o,$(SRCS))
+ $(CXX) -shared $^ $(patsubst %,-L%,$(LIBPATH)) $(patsubst %,-l%,$(LIBS)) -o $@
+ chmod 755 $@
+
+$(INSTPATH):
+ mkdir $(INSTPATH)
+
+install:: $(INSTPATH)
+
+install:: $(TARGET)
+ cp $^ $(INSTPATH)
+ chown root.root $(patsubst %,$(INSTPATH)/%,$(notdir $^))
+ chmod 755 $(patsubst %,$(INSTPATH)/%,$(notdir $^))
+
+.PHONY: clean
+clean:
+ make -C $(XMLRPCPATH) clean
+ rm -f $(TARGDIR)/*.o $(TARGET)
+ -rm -f *~
diff --git a/README.txt b/README.txt
new file mode 100644
index 0000000..f01cfc9
--- /dev/null
+++ b/README.txt
@@ -0,0 +1,29 @@
+XMLRPC external for PD -- Version 0.1.3b
+
+Author: Thomas Grill t.grill [at] gmx.net
+Maintainer: w.ritsch (for this release)
+
+
+Docu:
+
+ For Howto look at pd helppatches and pythonexample.
+
+Requirements:
+
+ I included xmlprc++ as library to prevent additional dependencies
+ also this lib looks simple and clean not much to improve (w.ritsch)
+
+
+Licence:
+
+ LGPL see LICENSE.txt
+ IEM - Institute of Electronic Music and Acoustics, Graz
+ Inffeldgasse 10/3, 8010 Graz, Austria
+ http://iem.at
+
+CHANGES:
+
+ V 0.1.3b, LICENSES added, post error removed.
+
+
+
diff --git a/main.cpp b/main.cpp
new file mode 100644
index 0000000..2cc0a26
--- /dev/null
+++ b/main.cpp
@@ -0,0 +1,805 @@
+/*************************************************************
+ *
+ * XMLRPC external for PD
+ *
+ * File: main.cpp
+ *
+ * Description: This is it all
+ *
+ * Author: Thomas Grill t.grill [at] gmx.net
+ *
+# License LGPL see LICENSE.txt
+# IEM - Institute of Electronic Music and Acoustics, Graz
+# Inffeldgasse 10/3, 8010 Graz, Austria
+# http://iem.at
+#
+# CHANGES:
+# V 0.1.3b, LICENSES added, post error removed.
+#
+#************************************************************/
+
+//! Version number of this external
+#define __XMLRPC_VERSION "0.1.3b"
+
+// prevent MSVC "extern" warning
+#ifdef _MSC_VER
+#pragma warning( disable : 4091 )
+#endif
+
+// necessary for a Sleep command
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+// headers contained in the PD distribution
+#include <m_pd.h>
+#include <pthread.h>
+
+// we are using the xmlrpc++ project (see http://sf.net/projects/xmlrpcpp )
+#include <XmlRpc.h>
+
+// include STL map class
+#include <map>
+
+
+#ifdef PD_DEVEL_VERSION
+ // here, the sys_lock and sys_unlock functions are defined
+ #undef USECLOCK
+#else
+ #define USECLOCK
+#endif
+
+
+//! Convert XMLRPC values to PD atoms
+static bool Val2Atom(XmlRpc::XmlRpcValue &val,t_atom &atom)
+{
+ switch(val.getType()) {
+ case XmlRpc::XmlRpcValue::TypeBoolean: SETFLOAT(&atom,(int)val?0:1); break;
+ case XmlRpc::XmlRpcValue::TypeInt: SETFLOAT(&atom,(int)val); break;
+ case XmlRpc::XmlRpcValue::TypeDouble: SETFLOAT(&atom,(double)val); break;
+ case XmlRpc::XmlRpcValue::TypeString: SETSYMBOL(&atom,gensym((char *)((std::string &)val).c_str())); break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+//! Convert PD atoms to XMLRPC values
+static bool Atom2Val(const t_atom &atom,XmlRpc::XmlRpcValue &val)
+{
+ switch(atom.a_type) {
+ case A_FLOAT: val = (double)atom_getfloat((t_atom *)&atom); break;
+ case A_SYMBOL: val = (std::string)(atom_getsymbol((t_atom *)&atom)->s_name);
+ default: return false;
+ }
+ return true;
+}
+
+
+
+//! proxy class holder
+static t_class *px_class = NULL;
+
+
+/*! \brief This is the proxy class receiving messages to a symbol
+ \note No virtual table here!
+*/
+class bind_proxy {
+public:
+ //! Obligatory PD object structure
+ t_object obj;
+
+ //! this symbol
+ const t_symbol *sym;
+
+ //! mutex for value changes
+ pthread_mutex_t *mutex;
+
+ //! current value of bound sender
+ XmlRpc::XmlRpcValue value;
+
+ //! Initalize structure
+ void Init(const t_symbol *s,pthread_mutex_t *mtx)
+ {
+ sym = s; mutex = mtx;
+ value.clear();
+ }
+
+ /*! \brief PD method called when a bound symbol changes its value
+ \note This is called from PD system thread
+ */
+ static void px_method(bind_proxy *obj,const t_symbol *s,int argc,const t_atom *argv);
+};
+
+
+void bind_proxy::px_method(bind_proxy *obj,const t_symbol *s,int argc,const t_atom *argv)
+{
+ pthread_mutex_lock(obj->mutex);
+
+ obj->value.clear();
+
+ if(s == &s_float && argc == 1 && argv->a_type == A_FLOAT)
+ // float value
+ obj->value = (double)atom_getfloat((t_atom *)argv);
+ else if(argc == 0)
+ // symbol value
+ obj->value = (std::string)s->s_name;
+ else if(s == &s_symbol && argc == 1 && argv->a_type == A_SYMBOL)
+ // this is probably never called
+ obj->value = (std::string)atom_getsymbol((t_atom *)argv)->s_name;
+ else {
+ // anything or list
+
+ // look if header is "list" and don't propagate it to the atom list
+ int hdr = s == &s_list?0:1;
+
+ // set the parameters
+ obj->value.setSize(argc+hdr);
+
+ if(hdr) obj->value[0] = s->s_name;
+
+ for(int i = 0; i < argc; ++i) {
+ if(!Atom2Val(argv[i],obj->value[i+hdr]))
+#ifdef _DEBUG
+ error("XMLRPC: Internal error - version %s, file %s, line %i",__XMLRPC_VERSION,__FILE__,__LINE__);
+#else
+ {}
+#endif
+ }
+ }
+
+ pthread_mutex_unlock(obj->mutex);
+}
+
+
+//! Type to map a symbol name to the associated proxy class
+typedef std::map<std::string,bind_proxy *> ProxyMapper;
+
+
+//! Our XMLRPC server
+class RPCServer:
+ public XmlRpc::XmlRpcServer
+{
+public:
+ RPCServer(int port);
+ ~RPCServer();
+
+ void Work() { work(-1.0); }
+
+ class Message
+ {
+ public:
+ enum Msg { load,close,send,bind,unbind,query };
+
+ Message(Msg m,XmlRpc::XmlRpcValue &val,XmlRpc::XmlRpcValue &res,pthread_mutex_t &mtx):
+ msg(m),value(val),result(res),mutex(mtx)
+ {
+#ifdef USECLOCK
+ pthread_cond_init(&cond,NULL);
+#endif
+ }
+
+ ~Message()
+ {
+#ifdef USECLOCK
+ pthread_cond_destroy(&cond);
+#endif
+ }
+
+#ifdef USECLOCK
+ void Signal()
+ {
+ pthread_cond_signal(&cond);
+ }
+
+ void Wait()
+ {
+ pthread_mutex_lock(&mutex);
+ pthread_cond_wait(&cond,&mutex);
+ pthread_mutex_unlock(&mutex);
+ }
+
+ pthread_cond_t cond;
+#endif
+ pthread_mutex_t &mutex;
+
+ std::string err;
+ Msg msg;
+ XmlRpc::XmlRpcValue &value,&result;
+ };
+
+ std::list<Message *> msglist;
+ pthread_mutex_t qu_mutex,msg_mutex,px_mutex;
+
+ //! Add message to queue (thread-safe)
+ void MsgPush(Message *m);
+ //! Fetch message from queue (thread-safe)
+ Message *MsgPop();
+
+ //! loaded PD patch
+ t_pd *canvas;
+
+ //! bound symbols and their proxies
+ ProxyMapper objmap;
+
+#ifdef USECLOCK
+ /*! \brief trigger message worker
+ \remark thread-safe!
+ */
+ void Trigger() { clock_delay(clk,0); }
+
+ //! worker function
+ static void clk_worker(RPCServer *s) { s->MsgWorker(); }
+
+ //! worker function
+ void MsgWorker();
+
+ //! worker clock
+ t_clock *clk;
+#endif
+
+ //! process message
+ void MsgProcess(Message &m);
+
+ void Methods(Message::Msg msg,XmlRpc::XmlRpcValue &params, XmlRpc::XmlRpcValue &result);
+
+ void Method_Load(XmlRpc::XmlRpcValue &params, XmlRpc::XmlRpcValue &result);
+ void Method_Close(XmlRpc::XmlRpcValue &params, XmlRpc::XmlRpcValue &result);
+ void Method_Bind(XmlRpc::XmlRpcValue &params, XmlRpc::XmlRpcValue &result);
+ void Method_Unbind(XmlRpc::XmlRpcValue &params, XmlRpc::XmlRpcValue &result);
+ void Method_Send(XmlRpc::XmlRpcValue &params, XmlRpc::XmlRpcValue &result);
+ void Method_Query(XmlRpc::XmlRpcValue &params, XmlRpc::XmlRpcValue &result);
+};
+
+RPCServer::RPCServer(int port):
+ canvas(NULL)
+{
+ // Create the server socket on the specified port
+ bindAndListen(port);
+
+ // Enable introspection API
+ enableIntrospection(true);
+
+ // make mutex for message queue
+ pthread_mutex_init(&qu_mutex,NULL);
+ pthread_mutex_init(&msg_mutex,NULL);
+ pthread_mutex_init(&px_mutex,NULL);
+
+#ifdef USECLOCK
+ // create worker clock
+ clk = clock_new(this,(t_method)clk_worker);
+#endif
+}
+
+RPCServer::~RPCServer()
+{
+ // delete message queue mutex
+ pthread_mutex_destroy(&qu_mutex);
+ pthread_mutex_destroy(&msg_mutex);
+ pthread_mutex_destroy(&px_mutex);
+
+#ifdef USECLOCK
+ clock_free(clk);
+#endif
+}
+
+void RPCServer::MsgPush(Message *m)
+{
+ pthread_mutex_lock(&qu_mutex);
+ msglist.push_back(m);
+ pthread_mutex_unlock(&qu_mutex);
+}
+
+RPCServer::Message *RPCServer::MsgPop()
+{
+ Message *m = NULL;
+
+ pthread_mutex_lock(&qu_mutex);
+ if(!msglist.empty()) {
+ // fetch reference from queue
+ m = msglist.front();
+ msglist.pop_front();
+ }
+ pthread_mutex_unlock(&qu_mutex);
+
+ return m;
+}
+
+//! process message
+void RPCServer::MsgProcess(Message &m)
+{
+ try {
+ // choose function
+ switch(m.msg) {
+ case Message::load: Method_Load(m.value,m.result); break;
+ case Message::close: Method_Close(m.value,m.result); break;
+ case Message::bind: Method_Bind(m.value,m.result); break;
+ case Message::unbind: Method_Unbind(m.value,m.result); break;
+ case Message::send: Method_Send(m.value,m.result); break;
+ }
+ }
+
+ // catch all exceptions as they can't propagate across threads
+ catch(const char *txt) {
+ m.err = txt;
+ }
+ catch(const std::string &txt) {
+ m.err = txt;
+ }
+ catch(const XmlRpc::XmlRpcException &exc) {
+ m.err = std::string("XMLRPC++ error: ")+exc.getMessage();
+ }
+ catch(...) {
+ m.err = "Undefined method error";
+ }
+}
+
+#ifdef USECLOCK
+//! worker function
+void RPCServer::MsgWorker()
+{
+ for(;;) {
+ // fetch reference from queue
+ Message *m = MsgPop();
+ if(!m) break;
+
+ MsgProcess(*m);
+
+ // signal message to be finished
+ m->Signal();
+ }
+}
+#endif
+
+
+//! dispatcher function
+void RPCServer::Methods(Message::Msg msg,XmlRpc::XmlRpcValue &params, XmlRpc::XmlRpcValue &result)
+{
+ switch(msg) {
+ // these can execute in the XMLRPC thread
+ case Message::query:
+ Method_Query(params,result); break;
+
+ // all others need to be executed in the PD thread
+ default: {
+ // make new message
+ Message *m = new Message(msg,params,result,msg_mutex);
+
+#ifdef USECLOCK
+ // add to message queue
+ MsgPush(m);
+
+ // trigger PD clock
+ Trigger();
+
+ // wait for function to finish in PD system thread
+ m->Wait();
+#else
+ // lock PD
+ sys_lock();
+
+ // process message
+ MsgProcess(*m);
+
+ // unlock PD
+ sys_unlock();
+#endif
+
+ // save eventual error string
+ std::string err = m->err;
+
+ // delete message
+ delete m;
+
+ // if error string is non-null throw exception
+ if(err.length()) throw err;
+ }
+ }
+}
+
+
+/*! \brief "load" method
+ \param string-array XML data representing a PD patch
+
+ This method takes a string array containing the code of a PD patch to load.
+*/
+void RPCServer::Method_Load(XmlRpc::XmlRpcValue &params, XmlRpc::XmlRpcValue &result)
+{
+ XmlRpc::XmlRpcValue *parr;
+ if(params.getType() == XmlRpc::XmlRpcValue::TypeArray && params[0].getType() == XmlRpc::XmlRpcValue::TypeString)
+ parr = &params;
+ else if(params.size() == 1 && params[0].getType() == XmlRpc::XmlRpcValue::TypeArray)
+ parr = &params[0];
+ else
+ throw "Wrong syntax - should be 'load string-array'";
+
+#ifndef _DEBUG
+ // stop dsp while the numerous objects are created
+ int dspstate = canvas_suspend_dsp();
+#endif
+
+ // if there is already a canvas... trash it!
+ if(canvas) pd_free(canvas);
+
+ // a current directory must be set so that PD creates an environment for the new canvas
+ // see pd/src/g_canvas.c - function canvas_new "if (canvas_newdirectory->s_name[0])"
+ // if there would be no canvas environment PD would crash
+ glob_setfilename(NULL,gensym("IAEM"),gensym("."));
+
+ for(int i = 0; i < parr->size(); ++i) {
+ // here, an exception can happen if (*parr)[i] is not a string!
+ const std::string &str = (std::string &)(*parr)[i];
+
+ // allocate binbuf storage
+ t_binbuf *b = binbuf_new();
+
+ // create binbuf from the string
+ binbuf_text(b, (char *)str.c_str(), str.size());
+ // evaluate binbuf - create canvas, objects or whatever
+ binbuf_eval(b, 0, 0, 0);
+
+ // free storage
+ binbuf_free(b);
+
+ // here, it would be interesting if the object has been sucessfully created...
+ // we could use the following...
+#if (PD_MINOR_VERSION >= 37) || defined(PD_DEVEL_VERSION)
+ // This pd_newest is currently only defined with PD veriosn >= 0.37 or in the
+ // CVS devel_0_36 branch on http://sf.net/projects/pure-data
+ // It is needed for knowing whether an object could be created or not
+ // However, it doesn't work for messages or comments for which pd_newest is not reset...
+ // Since the first statement is object a canvas, which (on success) sets pd_newest
+ // to non-null this should not be a problem for following msgs or comments.
+ t_pd *x = pd_newest();
+ if(!x) throw "Could not create object";
+#endif
+ }
+
+ // clear current file and path
+ // this is done because it is done in g_canvas.c
+ glob_setfilename(NULL,&s_,&s_);
+
+ // now resume dsp
+#ifndef _DEBUG
+ canvas_resume_dsp(dspstate);
+#endif
+
+ // get the patch canvas
+ t_pd *x = s__X.s_thing;
+ if(x) {
+ // pop newly created canvas
+ pd_vmess(x, gensym("pop"), "i", 1);
+
+ // issue load bang
+ pd_vmess(x, gensym("loadbang"), "");
+
+ // save created canvas object
+ canvas = x;
+ }
+ else
+ throw "Canvas could not be created";
+}
+
+/*! \brief "close" method
+
+ The previously loaded PD patch (by "load method") is closed
+*/
+void RPCServer::Method_Close(XmlRpc::XmlRpcValue &params, XmlRpc::XmlRpcValue &result)
+{
+ if(params.valid() && params.size())
+ throw "Wrong syntax - method 'close' takes no parameters";
+
+ if(canvas) {
+ pd_free(canvas);
+ canvas = NULL;
+ }
+ else
+ throw "No open canvas";
+}
+
+/*! \brief "bind" method
+ \parameter symbol PD symbol to bind a callback to
+ \return Fault if symbol has already been bound
+
+ Registers a symbol for query or active feedback
+*/
+void RPCServer::Method_Bind(XmlRpc::XmlRpcValue &params, XmlRpc::XmlRpcValue &result)
+{
+ if(!params.valid() || params.size() != 1)
+ throw "Wrong syntax - should be 'bind symbol'";
+
+ // check type of params[0] before evaluating the rest
+ // this throws an exception if it's not a string
+ std::string &name = (std::string &)params[0];
+
+ // look for existing proxy object
+ ProxyMapper::iterator iter = objmap.find(name);
+
+ if(iter == objmap.end()) {
+ // new proxy object
+ bind_proxy *px = (bind_proxy *)pd_new(px_class);
+ px->Init(gensym((char *)name.c_str()),&px_mutex);
+
+ // bind symbol to object
+ pd_bind(&px->obj.ob_pd,(t_symbol *)px->sym);
+
+ // add to map
+ objmap[name] = px;
+ }
+ else
+ throw "The symbol is already bound";
+}
+
+/*! \brief "unbind" method
+ \parameter symbol Previously bound PD symbol
+ \return Fault if symbol is not found or has not been bound
+
+ Free a previously bound symbol from its callback
+*/
+void RPCServer::Method_Unbind(XmlRpc::XmlRpcValue &params, XmlRpc::XmlRpcValue &result)
+{
+ if(!params.valid() || params.size() != 1)
+ throw "Wrong syntax - should be 'unbind symbol'";
+
+ // check type of params[0] before evaluating the rest
+ // this throws an exception if it's not a string
+ std::string &name = (std::string &)params[0];
+
+ // look for existing proxy object
+ ProxyMapper::iterator iter = objmap.find(name);
+
+ if(iter != objmap.end()) {
+ // retrieve pointer to proxy from map
+ bind_proxy *px = iter->second;
+
+ // unbind and free proxy object
+ pd_unbind(&px->obj.ob_pd,gensym((char *)name.c_str()));
+ pd_free((t_pd *)&px->obj);
+
+ // remove from map
+ objmap.erase(iter);
+ }
+ else
+ throw "The symbol is not bound";
+}
+
+/*! \brief "send" method
+ \param symbol PD symbol to send data to
+ \param parameters Data values (translated to PD atoms)
+
+ Send data to a receiving symbol in PD
+*/
+void RPCServer::Method_Send(XmlRpc::XmlRpcValue &params, XmlRpc::XmlRpcValue &result)
+{
+ if(!params.valid() || params.size() < 2)
+ throw "Wrong syntax - should be 'send symbol parameters ...'";
+
+ // check type of params[0] before evaluating the rest
+ // this throws an exception if it's not a string
+ std::string &recv = (std::string &)params[0];
+
+ int offset = 1;
+ XmlRpc::XmlRpcValue *val = &params;
+
+ // parameter 1 can also be an array (but no other parameters may follow!)
+ if(params.size() == 2 && params[1].getType() == XmlRpc::XmlRpcValue::TypeArray) {
+ offset = 0;
+ val = &params[1];
+ }
+
+ t_symbol *sym = gensym((char *)recv.c_str());
+ int argc = val->size()-offset;
+ t_atom *args = new t_atom[argc];
+
+ // iterate through argument list
+ for(int i = offset; i < val->size(); ++i) {
+ if(!Val2Atom((*val)[i],args[i-offset]))
+ throw "Parameter type not handled";
+ }
+
+#ifdef WIN32
+ // this is not very nice but I have no clue why sometimes this
+ // function hangs under windows. seems to be related to the
+ // pd function called and some mutex/thread issues
+ // remove this windows hack if it reveals why it blocks
+ Sleep(3);
+#endif
+
+ // forward parameters to receiving symbol
+ if(sym && sym->s_thing)
+ pd_forwardmess(sym->s_thing,argc,args);
+ else
+ post("XMLRPC: receiver %s not found",recv.c_str());
+
+ delete[] args;
+}
+
+/*! \brief "query" method
+ \parameter symbol PD symbol to query
+ \return Value of sender symbol
+
+ Queries the current value of a PD symbol
+*/
+void RPCServer::Method_Query(XmlRpc::XmlRpcValue &params, XmlRpc::XmlRpcValue &result)
+{
+ if(!params.valid() || params.size() != 1)
+ throw "Wrong syntax - should be 'query symbol'";
+
+ // check type of params[0] before evaluating the rest
+ // this throws an exception if it's not a string
+ std::string &name = (std::string &)params[0];
+
+ // lock mutex to protect objmap
+ pthread_mutex_lock(&px_mutex);
+
+ // look for existing proxy object
+ ProxyMapper::iterator iter = objmap.find(name);
+
+ // initialize px to NULL (serves as a flag for error exception)
+ bind_proxy *px = NULL;
+
+ if(iter != objmap.end()) {
+ // retrieve pointer to proxy from map
+ px = iter->second;
+
+ // return current value stored in proxy
+ result = px->value;
+ }
+
+ pthread_mutex_unlock(&px_mutex);
+
+ // throw exception if px has not been set
+ if(!px) throw "Symbol not found";
+}
+
+
+//! Base class for all our XMLRPC methods
+class RPCMethod:
+ public XmlRpc::XmlRpcServerMethod
+{
+public:
+ RPCMethod(const char *name,RPCServer *s,RPCServer::Message::Msg msg,const char *help):
+ XmlRpc::XmlRpcServerMethod(name,s),
+ srvmsg(msg),helptext(help)
+ {}
+
+protected:
+ //! the actual worker function where all is done
+ virtual void worker(XmlRpc::XmlRpcValue& params, XmlRpc::XmlRpcValue& result)
+ {
+ getServer().Methods(srvmsg,params,result);
+ }
+
+ //! return help string
+ virtual std::string help() { return helptext; }
+
+ //! execute RPC method and handle exceptions
+ void execute(XmlRpc::XmlRpcValue& params, XmlRpc::XmlRpcValue& result)
+ {
+ try { worker(params,result); }
+
+ // the exceptions are mostly typed as strings
+ catch(const char *str) {
+ throw XmlRpc::XmlRpcException(str);
+ }
+ catch(const std::string &str) {
+ throw XmlRpc::XmlRpcException(str);
+ }
+ catch(const XmlRpc::XmlRpcException &exc) {
+ throw exc;
+ }
+
+ // treat others here generically and protect PD from crashing
+ catch(...) {
+ throw XmlRpc::XmlRpcException("Undefined error, please report");
+ }
+ }
+
+ //! get reference to RPC server
+ RPCServer &getServer() { return *(RPCServer *)_server; }
+
+ std::string helptext;
+ const RPCServer::Message::Msg srvmsg;
+};
+
+
+
+//! our XMLRPC server
+static RPCServer *xmlrpc_server = NULL;
+
+
+//! Thread function where our XMLRPC server runs
+static void *xmlrpc_worker(void *)
+{
+#ifdef _DEBUG
+ // In debug mode display some messages
+ XmlRpc::setVerbosity(1);
+
+ if(!xmlrpc_server)
+ error("XMLRPC: Internal error - version %s, file %s, line %i",__XMLRPC_VERSION,__FILE__,__LINE__);
+ else
+#endif
+ {
+ // Register all methods
+ RPCMethod meth_load("load",xmlrpc_server,RPCServer::Message::load,"Load a patch - Syntax: 'load string-array'");
+ RPCMethod meth_close("close",xmlrpc_server,RPCServer::Message::close,"Close the open patch");
+ RPCMethod meth_send("send",xmlrpc_server,RPCServer::Message::send,"Send a value to a symbol - Syntax:'send symbol parameters ...'");
+ RPCMethod meth_bind("bind",xmlrpc_server,RPCServer::Message::bind,"Bind a callback to a PD symbol - Syntax:'bind symbol'");
+ RPCMethod meth_unbind("unbind",xmlrpc_server,RPCServer::Message::unbind,"Unbind a callback from a PD symbol - Syntax:'unbind symbol'");
+ RPCMethod meth_query("query",xmlrpc_server,RPCServer::Message::query,"Query the value of PD symbol - Syntax:'query symbol'");
+
+ // Wait for requests indefinitely
+ xmlrpc_server->Work();
+ }
+
+ // This point is never reached
+ delete xmlrpc_server; xmlrpc_server = NULL;
+
+ return NULL;
+}
+
+
+//! xmlrpc class holder
+static t_class *xmlrpc_class = NULL;
+
+
+/*! \brief xmlrpc object creation function
+
+ This function launches the xmlrpc thread
+*/
+static t_object *xmlrpc_new(t_floatarg p)
+{
+ t_object *ret = NULL;
+
+ if(xmlrpc_server)
+ post("XMLRPC: server has already been launched");
+ else {
+ if(p <= 0)
+ post("XMLRPC: port must be > 0");
+ else {
+ int port = (int)p;
+
+ // Initialize server
+ xmlrpc_server = new RPCServer(port);
+
+ // launch worker function
+ pthread_t id;
+ if(pthread_create(&id,NULL,xmlrpc_worker,xmlrpc_server)) {
+ error("XMLRPC thread could not be launched");
+
+ delete xmlrpc_server; xmlrpc_server = NULL;
+ }
+ else {
+ // success -> create object
+ ret = (t_object *)pd_new(xmlrpc_class);
+
+ post("XMLRPC: server is listening at port %i",port);
+ }
+ }
+ }
+ return ret;
+}
+
+
+/*! \brief Library setup routine
+ \note Must be exported from shared library
+*/
+extern "C"
+#ifdef NT
+__declspec(dllexport)
+#endif
+void xmlrpc_setup()
+{
+ // post some message to the console
+ post("IEMXMLRPC, version " __XMLRPC_VERSION ", (C)2003 IEM Graz");
+ post("");
+
+ // register the proxy class for binding symbols
+ px_class = class_new(gensym("xmlrpc proxy"),NULL,NULL,sizeof(bind_proxy),CLASS_PD|CLASS_NOINLET, A_NULL);
+ // one method for all messages to proxy
+ class_addanything(px_class,bind_proxy::px_method);
+
+ // register the xmlrpc class
+ xmlrpc_class = class_new(gensym("xmlrpc"),(t_newmethod)xmlrpc_new,NULL,sizeof(t_object),CLASS_NOINLET, A_FLOAT,A_NULL);
+}
+
diff --git a/xmlrpc++/COPYING b/xmlrpc++/COPYING
new file mode 100644
index 0000000..b1e3f5a
--- /dev/null
+++ b/xmlrpc++/COPYING
@@ -0,0 +1,504 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/xmlrpc++/Makefile b/xmlrpc++/Makefile
new file mode 100644
index 0000000..1c67616
--- /dev/null
+++ b/xmlrpc++/Makefile
@@ -0,0 +1,39 @@
+# modified by Christopher Frauenberger [frauenberger@iem.at]
+# 25.8.2004
+# for the integration in iARS project
+
+# makefile written for gnu make
+CXX = g++
+SRC = ./src
+CPPFLAGS = -I$(SRC)
+DEBUG = -g
+OPTIMIZE = -O2
+GCCWARN = -Wall -Wstrict-prototypes
+CXXFLAGS = $(DEBUG) $(GCCWARN) $(OPTIMIZE) $(INCLUDES)
+
+LIB = ./libXmlRpc.a
+
+# Add your system-dependent network libs here. These are
+# only used to build the tests (your application will need them too).
+# Linux: none
+# Solaris: -lsocket -lnsl
+#SYSTEMLIBS = -lsocket -lnsl
+SYSTEMLIBS =
+LDLIBS = $(LIB) $(SYSTEMLIBS)
+
+OBJ = $(SRC)/XmlRpcClient.o $(SRC)/XmlRpcDispatch.o \
+ $(SRC)/XmlRpcServer.o $(SRC)/XmlRpcServerConnection.o \
+ $(SRC)/XmlRpcServerMethod.o $(SRC)/XmlRpcSocket.o $(SRC)/XmlRpcSource.o \
+ $(SRC)/XmlRpcUtil.o $(SRC)/XmlRpcValue.o
+
+all: $(LIB)
+
+$(LIB): $(OBJ)
+ $(AR) $(ARFLAGS) $(LIB) $(OBJ)
+
+
+clean:
+ rm -f $(SRC)/*.o
+ rm -f $(SRC)/*~
+ rm -f $(LIB)
+
diff --git a/xmlrpc++/Makefile.win b/xmlrpc++/Makefile.win
new file mode 100644
index 0000000..0b98398
--- /dev/null
+++ b/xmlrpc++/Makefile.win
@@ -0,0 +1,189 @@
+#
+#
+# Makefile.win
+#
+# Microsoft Developer Studio Generated NMAKE File, Based on xmlrpc.dsp
+# created 30.8.2004
+# modified by Christopher Frauenberger [frauenberger@iem.at]#
+#
+#
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+
+CPP=cl.exe
+RSC=rc.exe
+
+OUTDIR=.\obj
+INTDIR=.\obj
+
+ALL : ".\xmlrpc.lib" "$(OUTDIR)\xmlrpc.bsc"
+
+
+CLEAN :
+ -@erase "$(INTDIR)\vc60.idb"
+ -@erase "$(INTDIR)\XmlRpcClient.obj"
+ -@erase "$(INTDIR)\XmlRpcClient.sbr"
+ -@erase "$(INTDIR)\XmlRpcDispatch.obj"
+ -@erase "$(INTDIR)\XmlRpcDispatch.sbr"
+ -@erase "$(INTDIR)\XmlRpcServer.obj"
+ -@erase "$(INTDIR)\XmlRpcServer.sbr"
+ -@erase "$(INTDIR)\XmlRpcServerConnection.obj"
+ -@erase "$(INTDIR)\XmlRpcServerConnection.sbr"
+ -@erase "$(INTDIR)\XmlRpcServerMethod.obj"
+ -@erase "$(INTDIR)\XmlRpcServerMethod.sbr"
+ -@erase "$(INTDIR)\XmlRpcSocket.obj"
+ -@erase "$(INTDIR)\XmlRpcSocket.sbr"
+ -@erase "$(INTDIR)\XmlRpcSource.obj"
+ -@erase "$(INTDIR)\XmlRpcSource.sbr"
+ -@erase "$(INTDIR)\XmlRpcUtil.obj"
+ -@erase "$(INTDIR)\XmlRpcUtil.sbr"
+ -@erase "$(INTDIR)\XmlRpcValue.obj"
+ -@erase "$(INTDIR)\XmlRpcValue.sbr"
+ -@erase "$(OUTDIR)\xmlrpc.bsc"
+ -@erase ".\xmlrpc.lib"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+MTL=midl.exe
+CPP_PROJ=/nologo /MD /W3 /GX /Zd /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_LIB" /FR"$(INTDIR)\\" /Fp"$(INTDIR)\xmlrpc.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\xmlrpc.bsc"
+BSC32_SBRS= \
+ "$(INTDIR)\XmlRpcClient.sbr" \
+ "$(INTDIR)\XmlRpcDispatch.sbr" \
+ "$(INTDIR)\XmlRpcServer.sbr" \
+ "$(INTDIR)\XmlRpcServerConnection.sbr" \
+ "$(INTDIR)\XmlRpcServerMethod.sbr" \
+ "$(INTDIR)\XmlRpcSocket.sbr" \
+ "$(INTDIR)\XmlRpcSource.sbr" \
+ "$(INTDIR)\XmlRpcUtil.sbr" \
+ "$(INTDIR)\XmlRpcValue.sbr"
+
+"$(OUTDIR)\xmlrpc.bsc" : "$(OUTDIR)" $(BSC32_SBRS)
+ $(BSC32) @<<
+ $(BSC32_FLAGS) $(BSC32_SBRS)
+<<
+
+LIB32=link.exe -lib
+LIB32_FLAGS=/nologo /out:"xmlrpc.lib"
+LIB32_OBJS= \
+ "$(INTDIR)\XmlRpcClient.obj" \
+ "$(INTDIR)\XmlRpcDispatch.obj" \
+ "$(INTDIR)\XmlRpcServer.obj" \
+ "$(INTDIR)\XmlRpcServerConnection.obj" \
+ "$(INTDIR)\XmlRpcServerMethod.obj" \
+ "$(INTDIR)\XmlRpcSocket.obj" \
+ "$(INTDIR)\XmlRpcSource.obj" \
+ "$(INTDIR)\XmlRpcUtil.obj" \
+ "$(INTDIR)\XmlRpcValue.obj"
+
+".\xmlrpc.lib" : "$(OUTDIR)" $(DEF_FILE) $(LIB32_OBJS)
+ $(LIB32) @<<
+ $(LIB32_FLAGS) $(DEF_FLAGS) $(LIB32_OBJS)
+<<
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+
+!IF "$(NO_EXTERNAL_DEPS)" != "1"
+!IF EXISTS("xmlrpc.dep")
+!INCLUDE "xmlrpc.dep"
+!ELSE
+!MESSAGE Warning: cannot find "xmlrpc.dep"
+!ENDIF
+!ENDIF
+
+
+SOURCE=.\src\XmlRpcClient.cpp
+
+"$(INTDIR)\XmlRpcClient.obj" "$(INTDIR)\XmlRpcClient.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\XmlRpcDispatch.cpp
+
+"$(INTDIR)\XmlRpcDispatch.obj" "$(INTDIR)\XmlRpcDispatch.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\XmlRpcServer.cpp
+
+"$(INTDIR)\XmlRpcServer.obj" "$(INTDIR)\XmlRpcServer.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\XmlRpcServerConnection.cpp
+
+"$(INTDIR)\XmlRpcServerConnection.obj" "$(INTDIR)\XmlRpcServerConnection.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\XmlRpcServerMethod.cpp
+
+"$(INTDIR)\XmlRpcServerMethod.obj" "$(INTDIR)\XmlRpcServerMethod.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\XmlRpcSocket.cpp
+
+"$(INTDIR)\XmlRpcSocket.obj" "$(INTDIR)\XmlRpcSocket.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\XmlRpcSource.cpp
+
+"$(INTDIR)\XmlRpcSource.obj" "$(INTDIR)\XmlRpcSource.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\XmlRpcUtil.cpp
+
+"$(INTDIR)\XmlRpcUtil.obj" "$(INTDIR)\XmlRpcUtil.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\src\XmlRpcValue.cpp
+
+"$(INTDIR)\XmlRpcValue.obj" "$(INTDIR)\XmlRpcValue.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+
+
+
+
+
+
diff --git a/xmlrpc++/README.html b/xmlrpc++/README.html
new file mode 100644
index 0000000..fd8e7f8
--- /dev/null
+++ b/xmlrpc++/README.html
@@ -0,0 +1,109 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+ <title>XmlRpc++ Library</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <meta http-equiv="Content-language" content="en-US">
+ <meta name="author" content="Chris Morley">
+ <meta name="copyright" content="Copyright 2003 by Chris Morley">
+ </head>
+ <body>
+ <H3>XmlRpc++ Library</H3>
+ <P>This is version 0.7 of XmlRpc++, an implementation of the <A HREF="http://www.xmlrpc.org">
+ XmlRpc protocol</A> written in C++, based upon Shilad Sen's excellent <A HREF="http://py-xmlrpc.sourceforge.net">
+ py-xmlrpc library</A>. XmlRpc++ is designed to make it easy to incorporate
+ XmlRpc client and server support into C++ applications. Or use both client and
+ server objects in your app for easy peer-to-peer support.
+ </P>
+ <H3>Features</H3>
+ <UL>
+ <li>
+ <STRONG>Easy</STRONG> &nbsp; This library is easy to incorporate into C++
+ applications. No other libraries are required, other than your system's socket
+ libraries. Simple XML parsing and HTTP support are built in.<br>
+ <li>
+ <STRONG>Fast</STRONG> &nbsp; All IO is non-blocking, so a slow client or
+ network will not slow down the server.<br>
+ <li>
+ <STRONG>Portable</STRONG> Written in standard C++ to the POSIX and Windows
+ sockets APIs. You do need a fairly recent compiler (g++ 3.1 or MSVC++ .Net or
+ MSVC++ 6 with the <A href="http://www.dinkumware.com/vc_fixes.html">STL patches</A>.)
+ </li>
+ <li>
+ <STRONG>Free</STRONG> &nbsp; This library is released under the <a href="http://www.gnu.org/">
+ GNU</a> <a href="http://www.gnu.org/copyleft/lesser.html">LGPL</a>.<br>
+ <br>
+ </li>
+ </UL>
+ <P>&nbsp;</P>
+ <h3>Changes</h3>
+ <UL>
+ <li>
+ Better handling of fault responses: server methods can throw an
+ XmlRpcException to return a fault and XmlRpcClient has a new method to
+ test whether the last response was a fault.</li>
+ <li>
+ Support for system.listMethods and system.methodHelp from the introspection
+ API.</li>
+ <li>
+ Support for system.multicall to process multiple requests in a single transaction.</li>
+ <li>
+ Fixed a problem in the XmlRpcServer destructor (it should not have been deleting the methods).</li>
+ <li>
+ The server ensures a valid result value is returned even if the method does not
+ set the result. The default result is an empty string.</li>
+ <li>
+ Doxygen comments in header files and a doc target in the makefile.</li>
+ </UL>
+ <P>
+ <P>&nbsp;</P>
+ <h3>Installation</h3>
+ <P>
+ There are VC++ 6 and VC++ .Net project files building on Windows. If you are
+ using VC++ 6, you should apply SP3 and the fixes at <A href="http://www.dinkumware.com/vc_fixes.html">
+ http://www.dinkumware.com/vc_fixes.html</A>. Be sure to set the appropriate
+ code generation switches. In particular, ensure that the runtime library
+ (single/multi-threaded, static library/DLL) used is the same for the XmlRpc++
+ code and whatever application it will be linked to.</P>
+ <P>
+ For Linux, Solaris, and other Unix-like platforms there is a GNU Makefile which
+ can be edited to suit your system. Specify your C++ compiler, compiler flags,
+ and your system's socket libraries.
+ </P>
+ <p>In the test directory there are various test programs that are built by default.
+ To verify that the library built correctly, you can start the HelloServer
+ example:<br>
+ <pre>HelloServer 8000
+ </pre>
+ and the HelloClient example in another terminal window:<br>
+ <pre>HelloClient localhost 8000
+ </pre>
+ <P>
+ You should see two Hello messages and a sum displayed (amongst a bunch of debug
+ output). You can also try the XML server validator program (eg, "Validator 80")
+ and then attempt to connect to it from <A href="http://validator.xmlrpc.com">http://validator.xmlrpc.com</A>
+ (if you have access to the internet and are not behind a firewall etc).
+ </P>
+ <H3>Author</H3>
+ <P><A href="mailto:cmorley@users.sourceforge.net">Chris Morley</A>
+ </P>
+ <P>Although no code was re-used, the design and structure of the library is based
+ upon the py-xmlrpc library implementation.<BR>
+ The base64 decoder/encoder is by <A href="mailto:lostd@ukr.net">Konstantin
+ Pilipchuk</A>.</P>
+ <P></P>
+ <H3>License</H3>
+ <p>A full copy of the LGPL license is included in the file COPYING. The source code
+ is Copyright (c) 2002-2003 by Chris Morley. This library is free software; you
+ can redistribute it and/or modify it under the terms of the GNU Lesser General
+ Public License as published by the Free Software Foundation; either version 2.1
+ of the License, or (at your option) any later version. This library is
+ distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+ You should have received a copy of the GNU Lesser General Public License along
+ with this library; if not, write to the Free Software Foundation, Inc., 59
+ Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ </p>
+ </body>
+</html>
diff --git a/xmlrpc++/src/Doxyfile b/xmlrpc++/src/Doxyfile
new file mode 100644
index 0000000..2d8a346
--- /dev/null
+++ b/xmlrpc++/src/Doxyfile
@@ -0,0 +1,1041 @@
+# Doxyfile 1.3-rc3
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# General configuration options
+#---------------------------------------------------------------------------
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME = XmlRpc++
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER = 0.7
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = ../doc
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch,
+# Finnish, French, German, Greek, Hungarian, Italian, Japanese, Japanese-en
+# (Japanese with english messages), Korean, Norwegian, Polish, Portuguese,
+# Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish and Ukrainian.
+
+OUTPUT_LANGUAGE = English
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these class will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = YES
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS = NO
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited
+# members of a class in the documentation of that class as if those members were
+# ordinary class members. Constructors, destructors and assignment operators of
+# the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. It is allowed to use relative paths in the argument list.
+
+STRIP_FROM_PATH =
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower case letters. If set to YES upper case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# users are adviced to set this option to NO.
+
+CASE_SENSE_NAMES = YES
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like the Qt-style comments (thus requiring an
+# explict @brief command for a brief description.
+
+JAVADOC_AUTOBRIEF = YES
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member
+# documentation.
+
+DETAILS_AT_TOP = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# reimplements.
+
+INHERIT_DOCS = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 8
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES =
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consist of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C.
+# For instance some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources
+# only. Doxygen will then generate output that is more tailored for Java.
+# For instance namespaces will be presented as packages, qualified scopes
+# will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR = YES
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT =
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp
+# *.h++ *.idl *.odl
+
+FILE_PATTERNS =
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE = base64.h
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories
+# that are symbolic links (a Unix filesystem feature) are excluded from the input.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+
+EXCLUDE_PATTERNS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.
+
+INPUT_FILTER =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES (the default)
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES (the default)
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet
+
+HTML_STYLESHEET =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output dir.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non empty doxygen will try to run
+# the html help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the Html help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
+# generated containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla,
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are
+# probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 250
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimised for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assigments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_XML = NO
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader. This is useful
+# if you want to understand what is going on. On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_PREDEFINED tags.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse the
+# parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::addtions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tagfiles.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in Html, RTF and LaTeX) for classes with base or
+# super classes. Setting the tag to NO turns the diagrams off. Note that this
+# option is superceded by the HAVE_DOT option below. This is only a fallback. It is
+# recommended to install and use dot, since it yield more powerful graphs.
+
+CLASS_DIAGRAMS = YES
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = NO
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = YES
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found on the path.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
+# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than
+# this value, doxygen will try to truncate the graph, so that it fits within
+# the specified constraint. Beware that most browsers cannot cope with very
+# large images.
+
+MAX_DOT_GRAPH_WIDTH = 1024
+
+# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than
+# this value, doxygen will try to truncate the graph, so that it fits within
+# the specified constraint. Beware that most browsers cannot cope with very
+# large images.
+
+MAX_DOT_GRAPH_HEIGHT = 1024
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermedate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
+
+#---------------------------------------------------------------------------
+# Configuration::addtions related to the search engine
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE = NO
+
+# The CGI_NAME tag should be the name of the CGI script that
+# starts the search engine (doxysearch) with the correct parameters.
+# A script with this name will be generated by doxygen.
+
+CGI_NAME = search.cgi
+
+# The CGI_URL tag should be the absolute URL to the directory where the
+# cgi binaries are located. See the documentation of your http daemon for
+# details.
+
+CGI_URL =
+
+# The DOC_URL tag should be the absolute URL to the directory where the
+# documentation is located. If left blank the absolute path to the
+# documentation, with file:// prepended to it, will be used.
+
+DOC_URL =
+
+# The DOC_ABSPATH tag should be the absolute path to the directory where the
+# documentation is located. If left blank the directory on the local machine
+# will be used.
+
+DOC_ABSPATH =
+
+# The BIN_ABSPATH tag must point to the directory where the doxysearch binary
+# is installed.
+
+BIN_ABSPATH = /usr/local/bin/
+
+# The EXT_DOC_PATHS tag can be used to specify one or more paths to
+# documentation generated for other projects. This allows doxysearch to search
+# the documentation for these projects as well.
+
+EXT_DOC_PATHS =
diff --git a/xmlrpc++/src/XmlRpc.h b/xmlrpc++/src/XmlRpc.h
new file mode 100644
index 0000000..9611af7
--- /dev/null
+++ b/xmlrpc++/src/XmlRpc.h
@@ -0,0 +1,94 @@
+#ifndef _XMLRPC_H_
+#define _XMLRPC_H_
+//
+// XmlRpc++ Copyright (c) 2002-2003 by Chris Morley
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+//
+
+#if defined(_MSC_VER)
+# pragma warning(disable:4786) // identifier was truncated in debug info
+#endif
+
+#ifndef MAKEDEPEND
+# include <string>
+#endif
+
+#include "XmlRpcClient.h"
+#include "XmlRpcException.h"
+#include "XmlRpcServer.h"
+#include "XmlRpcServerMethod.h"
+#include "XmlRpcValue.h"
+#include "XmlRpcUtil.h"
+
+namespace XmlRpc {
+
+
+ //! An interface allowing custom handling of error message reporting.
+ class XmlRpcErrorHandler {
+ public:
+ //! Returns a pointer to the currently installed error handling object.
+ static XmlRpcErrorHandler* getErrorHandler()
+ { return _errorHandler; }
+
+ //! Specifies the error handler.
+ static void setErrorHandler(XmlRpcErrorHandler* eh)
+ { _errorHandler = eh; }
+
+ //! Report an error. Custom error handlers should define this method.
+ virtual void error(const char* msg) = 0;
+
+ protected:
+ static XmlRpcErrorHandler* _errorHandler;
+ };
+
+ //! An interface allowing custom handling of informational message reporting.
+ class XmlRpcLogHandler {
+ public:
+ //! Returns a pointer to the currently installed message reporting object.
+ static XmlRpcLogHandler* getLogHandler()
+ { return _logHandler; }
+
+ //! Specifies the message handler.
+ static void setLogHandler(XmlRpcLogHandler* lh)
+ { _logHandler = lh; }
+
+ //! Returns the level of verbosity of informational messages. 0 is no output, 5 is very verbose.
+ static int getVerbosity()
+ { return _verbosity; }
+
+ //! Specify the level of verbosity of informational messages. 0 is no output, 5 is very verbose.
+ static void setVerbosity(int v)
+ { _verbosity = v; }
+
+ //! Output a message. Custom error handlers should define this method.
+ virtual void log(int level, const char* msg) = 0;
+
+ protected:
+ static XmlRpcLogHandler* _logHandler;
+ static int _verbosity;
+ };
+
+ //! Returns log message verbosity. This is short for XmlRpcLogHandler::getVerbosity()
+ int getVerbosity();
+ //! Sets log message verbosity. This is short for XmlRpcLogHandler::setVerbosity(level)
+ void setVerbosity(int level);
+
+
+ //! Version identifier
+ extern const char XMLRPC_VERSION[];
+
+} // namespace XmlRpc
+
+#endif // _XMLRPC_H_
diff --git a/xmlrpc++/src/XmlRpcClient.cpp b/xmlrpc++/src/XmlRpcClient.cpp
new file mode 100644
index 0000000..e706d0a
--- /dev/null
+++ b/xmlrpc++/src/XmlRpcClient.cpp
@@ -0,0 +1,413 @@
+
+#include "XmlRpcClient.h"
+
+#include "XmlRpcSocket.h"
+#include "XmlRpc.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+
+using namespace XmlRpc;
+
+// Static data
+const char XmlRpcClient::REQUEST_BEGIN[] =
+ "<?xml version=\"1.0\"?>\r\n"
+ "<methodCall><methodName>";
+const char XmlRpcClient::REQUEST_END_METHODNAME[] = "</methodName>\r\n";
+const char XmlRpcClient::PARAMS_TAG[] = "<params>";
+const char XmlRpcClient::PARAMS_ETAG[] = "</params>";
+const char XmlRpcClient::PARAM_TAG[] = "<param>";
+const char XmlRpcClient::PARAM_ETAG[] = "</param>";
+const char XmlRpcClient::REQUEST_END[] = "</methodCall>\r\n";
+const char XmlRpcClient::METHODRESPONSE_TAG[] = "<methodResponse>";
+const char XmlRpcClient::FAULT_TAG[] = "<fault>";
+
+
+
+XmlRpcClient::XmlRpcClient(const char* host, int port, const char* uri/*=0*/)
+{
+ XmlRpcUtil::log(1, "XmlRpcClient new client: host %s, port %d.", host, port);
+
+ _host = host;
+ _port = port;
+ if (uri)
+ _uri = uri;
+ else
+ _uri = "/RPC2";
+ _connectionState = NO_CONNECTION;
+ _executing = false;
+ _eof = false;
+
+ // Default to keeping the connection open until an explicit close is done
+ setKeepOpen();
+}
+
+
+XmlRpcClient::~XmlRpcClient()
+{
+}
+
+// Close the owned fd
+void
+XmlRpcClient::close()
+{
+ XmlRpcUtil::log(4, "XmlRpcClient::close: fd %d.", getfd());
+ _connectionState = NO_CONNECTION;
+ _disp.exit();
+ _disp.removeSource(this);
+ XmlRpcSource::close();
+}
+
+
+// Clear the referenced flag even if exceptions or errors occur.
+struct ClearFlagOnExit {
+ ClearFlagOnExit(bool& flag) : _flag(flag) {}
+ ~ClearFlagOnExit() { _flag = false; }
+ bool& _flag;
+};
+
+// Execute the named procedure on the remote server.
+// Params should be an array of the arguments for the method.
+// Returns true if the request was sent and a result received (although the result
+// might be a fault).
+bool
+XmlRpcClient::execute(const char* method, XmlRpcValue const& params, XmlRpcValue& result)
+{
+ XmlRpcUtil::log(1, "XmlRpcClient::execute: method %s (_connectionState %d).", method, _connectionState);
+
+ // This is not a thread-safe operation, if you want to do multithreading, use separate
+ // clients for each thread. If you want to protect yourself from multiple threads
+ // accessing the same client, replace this code with a real mutex.
+ if (_executing)
+ return false;
+
+ _executing = true;
+ ClearFlagOnExit cf(_executing);
+
+ _sendAttempts = 0;
+ _isFault = false;
+
+ if ( ! setupConnection())
+ return false;
+
+ if ( ! generateRequest(method, params))
+ return false;
+
+ result.clear();
+ double msTime = -1.0; // Process until exit is called
+ _disp.work(msTime);
+
+ if (_connectionState != IDLE || ! parseResponse(result))
+ return false;
+
+ XmlRpcUtil::log(1, "XmlRpcClient::execute: method %s completed.", method);
+ _response = "";
+ return true;
+}
+
+// XmlRpcSource interface implementation
+// Handle server responses. Called by the event dispatcher during execute.
+unsigned
+XmlRpcClient::handleEvent(unsigned eventType)
+{
+ if (eventType == XmlRpcDispatch::Exception)
+ {
+ if (_connectionState == WRITE_REQUEST && _bytesWritten == 0)
+ XmlRpcUtil::error("Error in XmlRpcClient::handleEvent: could not connect to server (%s).",
+ XmlRpcSocket::getErrorMsg().c_str());
+ else
+ XmlRpcUtil::error("Error in XmlRpcClient::handleEvent (state %d): %s.",
+ _connectionState, XmlRpcSocket::getErrorMsg().c_str());
+ return 0;
+ }
+
+ if (_connectionState == WRITE_REQUEST)
+ if ( ! writeRequest()) return 0;
+
+ if (_connectionState == READ_HEADER)
+ if ( ! readHeader()) return 0;
+
+ if (_connectionState == READ_RESPONSE)
+ if ( ! readResponse()) return 0;
+
+ // This should probably always ask for Exception events too
+ return (_connectionState == WRITE_REQUEST)
+ ? XmlRpcDispatch::WritableEvent : XmlRpcDispatch::ReadableEvent;
+}
+
+
+// Create the socket connection to the server if necessary
+bool
+XmlRpcClient::setupConnection()
+{
+ // If an error occurred last time through, or if the server closed the connection, close our end
+ if ((_connectionState != NO_CONNECTION && _connectionState != IDLE) || _eof)
+ close();
+
+ _eof = false;
+ if (_connectionState == NO_CONNECTION)
+ if (! doConnect())
+ return false;
+
+ // Prepare to write the request
+ _connectionState = WRITE_REQUEST;
+ _bytesWritten = 0;
+
+ // Notify the dispatcher to listen on this source (calls handleEvent when the socket is writable)
+ _disp.removeSource(this); // Make sure nothing is left over
+ _disp.addSource(this, XmlRpcDispatch::WritableEvent | XmlRpcDispatch::Exception);
+
+ return true;
+}
+
+
+// Connect to the xmlrpc server
+bool
+XmlRpcClient::doConnect()
+{
+ int fd = XmlRpcSocket::socket();
+ if (fd < 0)
+ {
+ XmlRpcUtil::error("Error in XmlRpcClient::doConnect: Could not create socket (%s).", XmlRpcSocket::getErrorMsg().c_str());
+ return false;
+ }
+
+ XmlRpcUtil::log(3, "XmlRpcClient::doConnect: fd %d.", fd);
+ this->setfd(fd);
+
+ // Don't block on connect/reads/writes
+ if ( ! XmlRpcSocket::setNonBlocking(fd))
+ {
+ this->close();
+ XmlRpcUtil::error("Error in XmlRpcClient::doConnect: Could not set socket to non-blocking IO mode (%s).", XmlRpcSocket::getErrorMsg().c_str());
+ return false;
+ }
+
+ if ( ! XmlRpcSocket::connect(fd, _host, _port))
+ {
+ this->close();
+ XmlRpcUtil::error("Error in XmlRpcClient::doConnect: Could not connect to server (%s).", XmlRpcSocket::getErrorMsg().c_str());
+ return false;
+ }
+
+ return true;
+}
+
+// Encode the request to call the specified method with the specified parameters into xml
+bool
+XmlRpcClient::generateRequest(const char* methodName, XmlRpcValue const& params)
+{
+ std::string body = REQUEST_BEGIN;
+ body += methodName;
+ body += REQUEST_END_METHODNAME;
+
+ // If params is an array, each element is a separate parameter
+ if (params.valid()) {
+ body += PARAMS_TAG;
+ if (params.getType() == XmlRpcValue::TypeArray)
+ {
+ for (int i=0; i<params.size(); ++i) {
+ body += PARAM_TAG;
+ body += params[i].toXml();
+ body += PARAM_ETAG;
+ }
+ }
+ else
+ {
+ body += PARAM_TAG;
+ body += params.toXml();
+ body += PARAM_ETAG;
+ }
+
+ body += PARAMS_ETAG;
+ }
+ body += REQUEST_END;
+
+ std::string header = generateHeader(body);
+ XmlRpcUtil::log(4, "XmlRpcClient::generateRequest: header is %d bytes, content-length is %d.",
+ header.length(), body.length());
+
+ _request = header + body;
+ return true;
+}
+
+// Prepend http headers
+std::string
+XmlRpcClient::generateHeader(std::string const& body)
+{
+ std::string header =
+ "POST " + _uri + " HTTP/1.1\r\n"
+ "User-Agent: ";
+ header += XMLRPC_VERSION;
+ header += "\r\nHost: ";
+ header += _host;
+
+ char buff[40];
+ sprintf(buff,":%d\r\n", _port);
+
+ header += buff;
+ header += "Content-Type: text/xml\r\nContent-length: ";
+
+ sprintf(buff,"%d\r\n\r\n", body.size());
+
+ return header + buff;
+}
+
+bool
+XmlRpcClient::writeRequest()
+{
+ if (_bytesWritten == 0)
+ XmlRpcUtil::log(5, "XmlRpcClient::writeRequest (attempt %d):\n%s\n", _sendAttempts+1, _request.c_str());
+
+ // Try to write the request
+ if ( ! XmlRpcSocket::nbWrite(this->getfd(), _request, &_bytesWritten)) {
+ XmlRpcUtil::error("Error in XmlRpcClient::writeRequest: write error (%s).",XmlRpcSocket::getErrorMsg().c_str());
+ return false;
+ }
+
+ XmlRpcUtil::log(3, "XmlRpcClient::writeRequest: wrote %d of %d bytes.", _bytesWritten, _request.length());
+
+ // Wait for the result
+ if (_bytesWritten == int(_request.length())) {
+ _header = "";
+ _response = "";
+ _connectionState = READ_HEADER;
+ }
+ return true;
+}
+
+
+// Read the header from the response
+bool
+XmlRpcClient::readHeader()
+{
+ // Read available data
+ if ( ! XmlRpcSocket::nbRead(this->getfd(), _header, &_eof) ||
+ (_eof && _header.length() == 0)) {
+
+ // If we haven't read any data yet and this is a keep-alive connection, the server may
+ // have timed out, so we try one more time.
+ if (getKeepOpen() && _header.length() == 0 && _sendAttempts++ == 0) {
+ XmlRpcUtil::log(4, "XmlRpcClient::readHeader: re-trying connection");
+ XmlRpcSource::close();
+ _connectionState = NO_CONNECTION;
+ _eof = false;
+ return setupConnection();
+ }
+
+ XmlRpcUtil::error("Error in XmlRpcClient::readHeader: error while reading header (%s) on fd %d.",
+ XmlRpcSocket::getErrorMsg().c_str(), getfd());
+ return false;
+ }
+
+ XmlRpcUtil::log(4, "XmlRpcClient::readHeader: client has read %d bytes", _header.length());
+
+ char *hp = (char*)_header.c_str(); // Start of header
+ char *ep = hp + _header.length(); // End of string
+ char *bp = 0; // Start of body
+ char *lp = 0; // Start of content-length value
+
+ for (char *cp = hp; (bp == 0) && (cp < ep); ++cp) {
+ if ((ep - cp > 16) && (strncasecmp(cp, "Content-length: ", 16) == 0))
+ lp = cp + 16;
+ else if ((ep - cp > 4) && (strncmp(cp, "\r\n\r\n", 4) == 0))
+ bp = cp + 4;
+ else if ((ep - cp > 2) && (strncmp(cp, "\n\n", 2) == 0))
+ bp = cp + 2;
+ }
+
+ // If we haven't gotten the entire header yet, return (keep reading)
+ if (bp == 0) {
+ if (_eof) // EOF in the middle of a response is an error
+ {
+ XmlRpcUtil::error("Error in XmlRpcClient::readHeader: EOF while reading header");
+ return false; // Close the connection
+ }
+
+ return true; // Keep reading
+ }
+
+ // Decode content length
+ if (lp == 0) {
+ XmlRpcUtil::error("Error XmlRpcClient::readHeader: No Content-length specified");
+ return false; // We could try to figure it out by parsing as we read, but for now...
+ }
+
+ _contentLength = atoi(lp);
+ if (_contentLength <= 0) {
+ XmlRpcUtil::error("Error in XmlRpcClient::readHeader: Invalid Content-length specified (%d).", _contentLength);
+ return false;
+ }
+
+ XmlRpcUtil::log(4, "client read content length: %d", _contentLength);
+
+ // Otherwise copy non-header data to response buffer and set state to read response.
+ _response = bp;
+ _header = ""; // should parse out any interesting bits from the header (connection, etc)...
+ _connectionState = READ_RESPONSE;
+ return true; // Continue monitoring this source
+}
+
+
+bool
+XmlRpcClient::readResponse()
+{
+ // If we dont have the entire response yet, read available data
+ if (int(_response.length()) < _contentLength) {
+ if ( ! XmlRpcSocket::nbRead(this->getfd(), _response, &_eof)) {
+ XmlRpcUtil::error("Error in XmlRpcClient::readResponse: read error (%s).",XmlRpcSocket::getErrorMsg().c_str());
+ return false;
+ }
+
+ // If we haven't gotten the entire _response yet, return (keep reading)
+ if (int(_response.length()) < _contentLength) {
+ if (_eof) {
+ XmlRpcUtil::error("Error in XmlRpcClient::readResponse: EOF while reading response");
+ return false;
+ }
+ return true;
+ }
+ }
+
+ // Otherwise, parse and return the result
+ XmlRpcUtil::log(3, "XmlRpcClient::readResponse (read %d bytes)", _response.length());
+ XmlRpcUtil::log(5, "response:\n%s", _response.c_str());
+
+ _connectionState = IDLE;
+
+ return false; // Stop monitoring this source (causes return from work)
+}
+
+
+// Convert the response xml into a result value
+bool
+XmlRpcClient::parseResponse(XmlRpcValue& result)
+{
+ // Parse response xml into result
+ int offset = 0;
+ if ( ! XmlRpcUtil::findTag(METHODRESPONSE_TAG,_response,&offset)) {
+ XmlRpcUtil::error("Error in XmlRpcClient::parseResponse: Invalid response - no methodResponse. Response:\n%s", _response.c_str());
+ return false;
+ }
+
+ // Expect either <params><param>... or <fault>...
+ if ((XmlRpcUtil::nextTagIs(PARAMS_TAG,_response,&offset) &&
+ XmlRpcUtil::nextTagIs(PARAM_TAG,_response,&offset)) ||
+ XmlRpcUtil::nextTagIs(FAULT_TAG,_response,&offset) && (_isFault = true))
+ {
+ if ( ! result.fromXml(_response, &offset)) {
+ XmlRpcUtil::error("Error in XmlRpcClient::parseResponse: Invalid response value. Response:\n%s", _response.c_str());
+ _response = "";
+ return false;
+ }
+ } else {
+ XmlRpcUtil::error("Error in XmlRpcClient::parseResponse: Invalid response - no param or fault tag. Response:\n%s", _response.c_str());
+ _response = "";
+ return false;
+ }
+
+ _response = "";
+ return result.valid();
+}
+
diff --git a/xmlrpc++/src/XmlRpcClient.h b/xmlrpc++/src/XmlRpcClient.h
new file mode 100644
index 0000000..ecf5811
--- /dev/null
+++ b/xmlrpc++/src/XmlRpcClient.h
@@ -0,0 +1,125 @@
+
+#ifndef _XMLRPCCLIENT_H_
+#define _XMLRPCCLIENT_H_
+//
+// XmlRpc++ Copyright (c) 2002-2003 by Chris Morley
+//
+#if defined(_MSC_VER)
+# pragma warning(disable:4786) // identifier was truncated in debug info
+#endif
+
+
+#ifndef MAKEDEPEND
+# include <string>
+#endif
+
+#include "XmlRpcDispatch.h"
+#include "XmlRpcSource.h"
+
+namespace XmlRpc {
+
+ // Arguments and results are represented by XmlRpcValues
+ class XmlRpcValue;
+
+ //! A class to send XML RPC requests to a server and return the results.
+ class XmlRpcClient : public XmlRpcSource {
+ public:
+ // Static data
+ static const char REQUEST_BEGIN[];
+ static const char REQUEST_END_METHODNAME[];
+ static const char PARAMS_TAG[];
+ static const char PARAMS_ETAG[];
+ static const char PARAM_TAG[];
+ static const char PARAM_ETAG[];
+ static const char REQUEST_END[];
+ // Result tags
+ static const char METHODRESPONSE_TAG[];
+ static const char FAULT_TAG[];
+
+ //! Construct a client to connect to the server at the specified host:port address
+ //! @param host The name of the remote machine hosting the server
+ //! @param port The port on the remote machine where the server is listening
+ //! @param uri An optional string to be sent as the URI in the HTTP GET header
+ XmlRpcClient(const char* host, int port, const char* uri=0);
+
+ //! Destructor
+ virtual ~XmlRpcClient();
+
+ //! Execute the named procedure on the remote server.
+ //! @param method The name of the remote procedure to execute
+ //! @param params An array of the arguments for the method
+ //! @param result The result value to be returned to the client
+ //! @return true if the request was sent and a result received
+ //! (although the result might be a fault).
+ //!
+ //! Currently this is a synchronous (blocking) implementation (execute
+ //! does not return until it receives a response or an error). Use isFault()
+ //! to determine whether the result is a fault response.
+ bool execute(const char* method, XmlRpcValue const& params, XmlRpcValue& result);
+
+ //! Returns true if the result of the last execute() was a fault response.
+ bool isFault() const { return _isFault; }
+
+
+ // XmlRpcSource interface implementation
+ //! Close the connection
+ virtual void close();
+
+ //! Handle server responses. Called by the event dispatcher during execute.
+ //! @param eventType The type of event that occurred.
+ //! @see XmlRpcDispatch::EventType
+ virtual unsigned handleEvent(unsigned eventType);
+
+ protected:
+ // Execution processing helpers
+ virtual bool doConnect();
+ virtual bool setupConnection();
+
+ virtual bool generateRequest(const char* method, XmlRpcValue const& params);
+ virtual std::string generateHeader(std::string const& body);
+ virtual bool writeRequest();
+ virtual bool readHeader();
+ virtual bool readResponse();
+ virtual bool parseResponse(XmlRpcValue& result);
+
+ // Possible IO states for the connection
+ enum ClientConnectionState { NO_CONNECTION, CONNECTING, WRITE_REQUEST, READ_HEADER, READ_RESPONSE, IDLE };
+ ClientConnectionState _connectionState;
+
+ // Server location
+ std::string _host;
+ std::string _uri;
+ int _port;
+
+ // The xml-encoded request, http header of response, and response xml
+ std::string _request;
+ std::string _header;
+ std::string _response;
+
+ // Number of times the client has attempted to send the request
+ int _sendAttempts;
+
+ // Number of bytes of the request that have been written to the socket so far
+ int _bytesWritten;
+
+ // True if we are currently executing a request. If you want to multithread,
+ // each thread should have its own client.
+ bool _executing;
+
+ // True if the server closed the connection
+ bool _eof;
+
+ // True if a fault response was returned by the server
+ bool _isFault;
+
+ // Number of bytes expected in the response body (parsed from response header)
+ int _contentLength;
+
+ // Event dispatcher
+ XmlRpcDispatch _disp;
+
+ }; // class XmlRpcClient
+
+} // namespace XmlRpc
+
+#endif // _XMLRPCCLIENT_H_
diff --git a/xmlrpc++/src/XmlRpcDispatch.cpp b/xmlrpc++/src/XmlRpcDispatch.cpp
new file mode 100644
index 0000000..3bbca40
--- /dev/null
+++ b/xmlrpc++/src/XmlRpcDispatch.cpp
@@ -0,0 +1,209 @@
+
+#include "XmlRpcDispatch.h"
+#include "XmlRpcSource.h"
+#include "XmlRpcUtil.h"
+
+#include <math.h>
+#include <sys/timeb.h>
+
+#if defined(_WINDOWS)
+# include <winsock2.h>
+
+# define USE_FTIME
+# if defined(_MSC_VER)
+# define timeb _timeb
+# define ftime _ftime
+# endif
+#else
+# include <sys/time.h>
+#endif // _WINDOWS
+
+
+using namespace XmlRpc;
+
+
+XmlRpcDispatch::XmlRpcDispatch()
+{
+ _endTime = -1.0;
+ _doClear = false;
+ _inWork = false;
+}
+
+
+XmlRpcDispatch::~XmlRpcDispatch()
+{
+}
+
+// Monitor this source for the specified events and call its event handler
+// when the event occurs
+void
+XmlRpcDispatch::addSource(XmlRpcSource* source, unsigned mask)
+{
+ _sources.push_back(MonitoredSource(source, mask));
+}
+
+// Stop monitoring this source. Does not close the source.
+void
+XmlRpcDispatch::removeSource(XmlRpcSource* source)
+{
+ for (SourceList::iterator it=_sources.begin(); it!=_sources.end(); ++it)
+ if (it->getSource() == source)
+ {
+ _sources.erase(it);
+ break;
+ }
+}
+
+
+// Modify the types of events to watch for on this source
+void
+XmlRpcDispatch::setSourceEvents(XmlRpcSource* source, unsigned eventMask)
+{
+ for (SourceList::iterator it=_sources.begin(); it!=_sources.end(); ++it)
+ if (it->getSource() == source)
+ {
+ it->getMask() = eventMask;
+ break;
+ }
+}
+
+
+
+// Watch current set of sources and process events
+void
+XmlRpcDispatch::work(double timeout)
+{
+ // Compute end time
+ _endTime = (timeout < 0.0) ? -1.0 : (getTime() + timeout);
+ _doClear = false;
+ _inWork = true;
+
+ // Only work while there is something to monitor
+ while (_sources.size() > 0) {
+
+ // Construct the sets of descriptors we are interested in
+ fd_set inFd, outFd, excFd;
+ FD_ZERO(&inFd);
+ FD_ZERO(&outFd);
+ FD_ZERO(&excFd);
+
+ int maxFd = -1; // Not used on windows
+ SourceList::iterator it;
+ for (it=_sources.begin(); it!=_sources.end(); ++it) {
+ int fd = it->getSource()->getfd();
+ if (it->getMask() & ReadableEvent) FD_SET(fd, &inFd);
+ if (it->getMask() & WritableEvent) FD_SET(fd, &outFd);
+ if (it->getMask() & Exception) FD_SET(fd, &excFd);
+ if (it->getMask() && fd > maxFd) maxFd = fd;
+ }
+
+ // Check for events
+ int nEvents;
+ if (timeout < 0.0)
+ nEvents = select(maxFd+1, &inFd, &outFd, &excFd, NULL);
+ else
+ {
+ struct timeval tv;
+ tv.tv_sec = (int)floor(timeout);
+ tv.tv_usec = ((int)floor(1000000.0 * (timeout-floor(timeout)))) % 1000000;
+ nEvents = select(maxFd+1, &inFd, &outFd, &excFd, &tv);
+ }
+
+ if (nEvents < 0)
+ {
+ XmlRpcUtil::error("Error in XmlRpcDispatch::work: error in select (%d).", nEvents);
+ _inWork = false;
+ return;
+ }
+
+ // Process events
+ for (it=_sources.begin(); it != _sources.end(); )
+ {
+ SourceList::iterator thisIt = it++;
+ XmlRpcSource* src = thisIt->getSource();
+ int fd = src->getfd();
+ unsigned newMask = (unsigned) -1;
+ if (fd <= maxFd) {
+ // If you select on multiple event types this could be ambiguous
+ if (FD_ISSET(fd, &inFd))
+ newMask &= src->handleEvent(ReadableEvent);
+ if (FD_ISSET(fd, &outFd))
+ newMask &= src->handleEvent(WritableEvent);
+ if (FD_ISSET(fd, &excFd))
+ newMask &= src->handleEvent(Exception);
+
+ if ( ! newMask) {
+ _sources.erase(thisIt); // Stop monitoring this one
+ if ( ! src->getKeepOpen())
+ src->close();
+ } else if (newMask != (unsigned) -1) {
+ thisIt->getMask() = newMask;
+ }
+ }
+ }
+
+ // Check whether to clear all sources
+ if (_doClear)
+ {
+ SourceList closeList = _sources;
+ _sources.clear();
+ for (SourceList::iterator it=closeList.begin(); it!=closeList.end(); ++it) {
+ XmlRpcSource *src = it->getSource();
+ src->close();
+ }
+
+ _doClear = false;
+ }
+
+ // Check whether end time has passed
+ if (0 <= _endTime && getTime() > _endTime)
+ break;
+ }
+
+ _inWork = false;
+}
+
+
+// Exit from work routine. Presumably this will be called from
+// one of the source event handlers.
+void
+XmlRpcDispatch::exit()
+{
+ _endTime = 0.0; // Return from work asap
+}
+
+// Clear all sources from the monitored sources list
+void
+XmlRpcDispatch::clear()
+{
+ if (_inWork)
+ _doClear = true; // Finish reporting current events before clearing
+ else
+ {
+ SourceList closeList = _sources;
+ _sources.clear();
+ for (SourceList::iterator it=closeList.begin(); it!=closeList.end(); ++it)
+ it->getSource()->close();
+ }
+}
+
+
+double
+XmlRpcDispatch::getTime()
+{
+#ifdef USE_FTIME
+ struct timeb tbuff;
+
+ ftime(&tbuff);
+ return ((double) tbuff.time + ((double)tbuff.millitm / 1000.0) +
+ ((double) tbuff.timezone * 60));
+#else
+ struct timeval tv;
+ struct timezone tz;
+
+ gettimeofday(&tv, &tz);
+ return (tv.tv_sec + tv.tv_usec / 1000000.0);
+#endif /* USE_FTIME */
+}
+
+
diff --git a/xmlrpc++/src/XmlRpcDispatch.h b/xmlrpc++/src/XmlRpcDispatch.h
new file mode 100644
index 0000000..b3c4ec0
--- /dev/null
+++ b/xmlrpc++/src/XmlRpcDispatch.h
@@ -0,0 +1,88 @@
+
+#ifndef _XMLRPCDISPATCH_H_
+#define _XMLRPCDISPATCH_H_
+//
+// XmlRpc++ Copyright (c) 2002-2003 by Chris Morley
+//
+#if defined(_MSC_VER)
+# pragma warning(disable:4786) // identifier was truncated in debug info
+#endif
+
+#ifndef MAKEDEPEND
+# include <list>
+#endif
+
+namespace XmlRpc {
+
+ // An RPC source represents a file descriptor to monitor
+ class XmlRpcSource;
+
+ //! An object which monitors file descriptors for events and performs
+ //! callbacks when interesting events happen.
+ class XmlRpcDispatch {
+ public:
+ //! Constructor
+ XmlRpcDispatch();
+ ~XmlRpcDispatch();
+
+ //! Values indicating the type of events a source is interested in
+ enum EventType {
+ ReadableEvent = 1, //!< data available to read
+ WritableEvent = 2, //!< connected/data can be written without blocking
+ Exception = 4 //!< uh oh
+ };
+
+ //! Monitor this source for the event types specified by the event mask
+ //! and call its event handler when any of the events occur.
+ //! @param source The source to monitor
+ //! @param eventMask Which event types to watch for. \see EventType
+ void addSource(XmlRpcSource* source, unsigned eventMask);
+
+ //! Stop monitoring this source.
+ //! @param source The source to stop monitoring
+ void removeSource(XmlRpcSource* source);
+
+ //! Modify the types of events to watch for on this source
+ void setSourceEvents(XmlRpcSource* source, unsigned eventMask);
+
+
+ //! Watch current set of sources and process events for the specified
+ //! duration (in ms, -1 implies wait forever, or until exit is called)
+ void work(double msTime);
+
+ //! Exit from work routine
+ void exit();
+
+ //! Clear all sources from the monitored sources list. Sources are closed.
+ void clear();
+
+ protected:
+
+ // helper
+ double getTime();
+
+ // A source to monitor and what to monitor it for
+ struct MonitoredSource {
+ MonitoredSource(XmlRpcSource* src, unsigned mask) : _src(src), _mask(mask) {}
+ XmlRpcSource* getSource() const { return _src; }
+ unsigned& getMask() { return _mask; }
+ XmlRpcSource* _src;
+ unsigned _mask;
+ };
+
+ // A list of sources to monitor
+ typedef std::list< MonitoredSource > SourceList;
+
+ // Sources being monitored
+ SourceList _sources;
+
+ // When work should stop (-1 implies wait forever, or until exit is called)
+ double _endTime;
+
+ bool _doClear;
+ bool _inWork;
+
+ };
+} // namespace XmlRpc
+
+#endif // _XMLRPCDISPATCH_H_
diff --git a/xmlrpc++/src/XmlRpcException.h b/xmlrpc++/src/XmlRpcException.h
new file mode 100644
index 0000000..6090450
--- /dev/null
+++ b/xmlrpc++/src/XmlRpcException.h
@@ -0,0 +1,42 @@
+
+#ifndef _XMLRPCEXCEPTION_H_
+#define _XMLRPCEXCEPTION_H_
+//
+// XmlRpc++ Copyright (c) 2002-2003 by Chris Morley
+//
+#if defined(_MSC_VER)
+# pragma warning(disable:4786) // identifier was truncated in debug info
+#endif
+
+#ifndef MAKEDEPEND
+# include <string>
+#endif
+
+
+namespace XmlRpc {
+
+ //! A class representing an error.
+ //! If server methods throw this exception, a fault response is returned
+ //! to the client.
+ class XmlRpcException {
+ public:
+ //! Constructor
+ //! @param message A descriptive error message
+ //! @param code An integer error code
+ XmlRpcException(const std::string& message, int code=-1) :
+ _message(message), _code(code) {}
+
+ //! Return the error message.
+ const std::string& getMessage() const { return _message; }
+
+ //! Return the error code.
+ int getCode() const { return _code; }
+
+ private:
+ std::string _message;
+ int _code;
+ };
+
+}
+
+#endif // _XMLRPCEXCEPTION_H_
diff --git a/xmlrpc++/src/XmlRpcServer.cpp b/xmlrpc++/src/XmlRpcServer.cpp
new file mode 100644
index 0000000..f6b4aa5
--- /dev/null
+++ b/xmlrpc++/src/XmlRpcServer.cpp
@@ -0,0 +1,284 @@
+
+#include "XmlRpcServer.h"
+#include "XmlRpcServerConnection.h"
+#include "XmlRpcServerMethod.h"
+#include "XmlRpcSocket.h"
+#include "XmlRpcUtil.h"
+#include "XmlRpcException.h"
+
+
+using namespace XmlRpc;
+
+
+XmlRpcServer::XmlRpcServer()
+{
+ _introspectionEnabled = false;
+ _listMethods = 0;
+ _methodHelp = 0;
+}
+
+
+XmlRpcServer::~XmlRpcServer()
+{
+ this->shutdown();
+ _methods.clear();
+ delete _listMethods;
+ delete _methodHelp;
+}
+
+
+// Add a command to the RPC server
+void
+XmlRpcServer::addMethod(XmlRpcServerMethod* method)
+{
+ _methods[method->name()] = method;
+}
+
+// Remove a command from the RPC server
+void
+XmlRpcServer::removeMethod(XmlRpcServerMethod* method)
+{
+ MethodMap::iterator i = _methods.find(method->name());
+ if (i != _methods.end())
+ _methods.erase(i);
+}
+
+// Remove a command from the RPC server by name
+void
+XmlRpcServer::removeMethod(const std::string& methodName)
+{
+ MethodMap::iterator i = _methods.find(methodName);
+ if (i != _methods.end())
+ _methods.erase(i);
+}
+
+
+// Look up a method by name
+XmlRpcServerMethod*
+XmlRpcServer::findMethod(const std::string& name) const
+{
+ MethodMap::const_iterator i = _methods.find(name);
+ if (i == _methods.end())
+ return 0;
+ return i->second;
+}
+
+
+// Create a socket, bind to the specified port, and
+// set it in listen mode to make it available for clients.
+bool
+XmlRpcServer::bindAndListen(int port, int backlog /*= 5*/)
+{
+ int fd = XmlRpcSocket::socket();
+ if (fd < 0)
+ {
+ XmlRpcUtil::error("XmlRpcServer::bindAndListen: Could not create socket (%s).", XmlRpcSocket::getErrorMsg().c_str());
+ return false;
+ }
+
+ this->setfd(fd);
+
+ // Don't block on reads/writes
+ if ( ! XmlRpcSocket::setNonBlocking(fd))
+ {
+ this->close();
+ XmlRpcUtil::error("XmlRpcServer::bindAndListen: Could not set socket to non-blocking input mode (%s).", XmlRpcSocket::getErrorMsg().c_str());
+ return false;
+ }
+
+ // Allow this port to be re-bound immediately so server re-starts are not delayed
+ if ( ! XmlRpcSocket::setReuseAddr(fd))
+ {
+ this->close();
+ XmlRpcUtil::error("XmlRpcServer::bindAndListen: Could not set SO_REUSEADDR socket option (%s).", XmlRpcSocket::getErrorMsg().c_str());
+ return false;
+ }
+
+ // Bind to the specified port on the default interface
+ if ( ! XmlRpcSocket::bind(fd, port))
+ {
+ this->close();
+ XmlRpcUtil::error("XmlRpcServer::bindAndListen: Could not bind to specified port (%s).", XmlRpcSocket::getErrorMsg().c_str());
+ return false;
+ }
+
+ // Set in listening mode
+ if ( ! XmlRpcSocket::listen(fd, backlog))
+ {
+ this->close();
+ XmlRpcUtil::error("XmlRpcServer::bindAndListen: Could not set socket in listening mode (%s).", XmlRpcSocket::getErrorMsg().c_str());
+ return false;
+ }
+
+ XmlRpcUtil::log(2, "XmlRpcServer::bindAndListen: server listening on port %d fd %d", port, fd);
+
+ // Notify the dispatcher to listen on this source when we are in work()
+ _disp.addSource(this, XmlRpcDispatch::ReadableEvent);
+
+ return true;
+}
+
+
+// Process client requests for the specified time
+void
+XmlRpcServer::work(double msTime)
+{
+ XmlRpcUtil::log(2, "XmlRpcServer::work: waiting for a connection");
+ _disp.work(msTime);
+}
+
+
+
+// Handle input on the server socket by accepting the connection
+// and reading the rpc request.
+unsigned
+XmlRpcServer::handleEvent(unsigned mask)
+{
+ acceptConnection();
+ return XmlRpcDispatch::ReadableEvent; // Continue to monitor this fd
+}
+
+
+// Accept a client connection request and create a connection to
+// handle method calls from the client.
+void
+XmlRpcServer::acceptConnection()
+{
+ int s = XmlRpcSocket::accept(this->getfd());
+ XmlRpcUtil::log(2, "XmlRpcServer::acceptConnection: socket %d", s);
+ if (s < 0)
+ {
+ //this->close();
+ XmlRpcUtil::error("XmlRpcServer::acceptConnection: Could not accept connection (%s).", XmlRpcSocket::getErrorMsg().c_str());
+ }
+ else if ( ! XmlRpcSocket::setNonBlocking(s))
+ {
+ XmlRpcSocket::close(s);
+ XmlRpcUtil::error("XmlRpcServer::acceptConnection: Could not set socket to non-blocking input mode (%s).", XmlRpcSocket::getErrorMsg().c_str());
+ }
+ else // Notify the dispatcher to listen for input on this source when we are in work()
+ {
+ XmlRpcUtil::log(2, "XmlRpcServer::acceptConnection: creating a connection");
+ _disp.addSource(this->createConnection(s), XmlRpcDispatch::ReadableEvent);
+ }
+}
+
+
+// Create a new connection object for processing requests from a specific client.
+XmlRpcServerConnection*
+XmlRpcServer::createConnection(int s)
+{
+ // Specify that the connection object be deleted when it is closed
+ return new XmlRpcServerConnection(s, this, true);
+}
+
+
+void
+XmlRpcServer::removeConnection(XmlRpcServerConnection* sc)
+{
+ _disp.removeSource(sc);
+}
+
+
+// Stop processing client requests
+void
+XmlRpcServer::exit()
+{
+ _disp.exit();
+}
+
+
+// Close the server socket file descriptor and stop monitoring connections
+void
+XmlRpcServer::shutdown()
+{
+ // This closes and destroys all connections as well as closing this socket
+ _disp.clear();
+}
+
+
+// Introspection support
+static const std::string LIST_METHODS("system.listMethods");
+static const std::string METHOD_HELP("system.methodHelp");
+static const std::string MULTICALL("system.multicall");
+
+
+// List all methods available on a server
+class ListMethods : public XmlRpcServerMethod
+{
+public:
+ ListMethods(XmlRpcServer* s) : XmlRpcServerMethod(LIST_METHODS, s) {}
+
+ void execute(XmlRpcValue& params, XmlRpcValue& result)
+ {
+ _server->listMethods(result);
+ }
+
+ std::string help() { return std::string("List all methods available on a server as an array of strings"); }
+};
+
+
+// Retrieve the help string for a named method
+class MethodHelp : public XmlRpcServerMethod
+{
+public:
+ MethodHelp(XmlRpcServer* s) : XmlRpcServerMethod(METHOD_HELP, s) {}
+
+ void execute(XmlRpcValue& params, XmlRpcValue& result)
+ {
+ if (params[0].getType() != XmlRpcValue::TypeString)
+ throw XmlRpcException(METHOD_HELP + ": Invalid argument type");
+
+ XmlRpcServerMethod* m = _server->findMethod(params[0]);
+ if ( ! m)
+ throw XmlRpcException(METHOD_HELP + ": Unknown method name");
+
+ result = m->help();
+ }
+
+ std::string help() { return std::string("Retrieve the help string for a named method"); }
+};
+
+
+// Specify whether introspection is enabled or not. Default is enabled.
+void
+XmlRpcServer::enableIntrospection(bool enabled)
+{
+ if (_introspectionEnabled == enabled)
+ return;
+
+ _introspectionEnabled = enabled;
+
+ if (enabled)
+ {
+ if ( ! _listMethods)
+ {
+ _listMethods = new ListMethods(this);
+ _methodHelp = new MethodHelp(this);
+ } else {
+ addMethod(_listMethods);
+ addMethod(_methodHelp);
+ }
+ }
+ else
+ {
+ removeMethod(LIST_METHODS);
+ removeMethod(METHOD_HELP);
+ }
+}
+
+
+void
+XmlRpcServer::listMethods(XmlRpcValue& result)
+{
+ int i = 0;
+ result.setSize(_methods.size()+1);
+ for (MethodMap::iterator it=_methods.begin(); it != _methods.end(); ++it)
+ result[i++] = it->first;
+
+ // Multicall support is built into XmlRpcServerConnection
+ result[i] = MULTICALL;
+}
+
+
+
diff --git a/xmlrpc++/src/XmlRpcServer.h b/xmlrpc++/src/XmlRpcServer.h
new file mode 100644
index 0000000..8172733
--- /dev/null
+++ b/xmlrpc++/src/XmlRpcServer.h
@@ -0,0 +1,104 @@
+
+#ifndef _XMLRPCSERVER_H_
+#define _XMLRPCSERVER_H_
+//
+// XmlRpc++ Copyright (c) 2002-2003 by Chris Morley
+//
+#if defined(_MSC_VER)
+# pragma warning(disable:4786) // identifier was truncated in debug info
+#endif
+
+#ifndef MAKEDEPEND
+# include <map>
+# include <string>
+#endif
+
+#include "XmlRpcDispatch.h"
+#include "XmlRpcSource.h"
+
+namespace XmlRpc {
+
+
+ // An abstract class supporting XML RPC methods
+ class XmlRpcServerMethod;
+
+ // Class representing connections to specific clients
+ class XmlRpcServerConnection;
+
+ // Class representing argument and result values
+ class XmlRpcValue;
+
+
+ //! A class to handle XML RPC requests
+ class XmlRpcServer : public XmlRpcSource {
+ public:
+ //! Create a server object.
+ XmlRpcServer();
+ //! Destructor.
+ virtual ~XmlRpcServer();
+
+ //! Specify whether introspection is enabled or not. Default is not enabled.
+ void enableIntrospection(bool enabled=true);
+
+ //! Add a command to the RPC server
+ void addMethod(XmlRpcServerMethod* method);
+
+ //! Remove a command from the RPC server
+ void removeMethod(XmlRpcServerMethod* method);
+
+ //! Remove a command from the RPC server by name
+ void removeMethod(const std::string& methodName);
+
+ //! Look up a method by name
+ XmlRpcServerMethod* findMethod(const std::string& name) const;
+
+ //! Create a socket, bind to the specified port, and
+ //! set it in listen mode to make it available for clients.
+ bool bindAndListen(int port, int backlog = 5);
+
+ //! Process client requests for the specified time
+ void work(double msTime);
+
+ //! Temporarily stop processing client requests and exit the work() method.
+ void exit();
+
+ //! Close all connections with clients and the socket file descriptor
+ void shutdown();
+
+ //! Introspection support
+ void listMethods(XmlRpcValue& result);
+
+ // XmlRpcSource interface implementation
+
+ //! Handle client connection requests
+ virtual unsigned handleEvent(unsigned eventType);
+
+ //! Remove a connection from the dispatcher
+ virtual void removeConnection(XmlRpcServerConnection*);
+
+ protected:
+
+ //! Accept a client connection request
+ virtual void acceptConnection();
+
+ //! Create a new connection object for processing requests from a specific client.
+ virtual XmlRpcServerConnection* createConnection(int socket);
+
+ // Whether the introspection API is supported by this server
+ bool _introspectionEnabled;
+
+ // Event dispatcher
+ XmlRpcDispatch _disp;
+
+ // Collection of methods. This could be a set keyed on method name if we wanted...
+ typedef std::map< std::string, XmlRpcServerMethod* > MethodMap;
+ MethodMap _methods;
+
+ // system methods
+ XmlRpcServerMethod* _listMethods;
+ XmlRpcServerMethod* _methodHelp;
+
+ };
+} // namespace XmlRpc
+
+#endif //_XMLRPCSERVER_H_
diff --git a/xmlrpc++/src/XmlRpcServerConnection.cpp b/xmlrpc++/src/XmlRpcServerConnection.cpp
new file mode 100644
index 0000000..b9d6def
--- /dev/null
+++ b/xmlrpc++/src/XmlRpcServerConnection.cpp
@@ -0,0 +1,371 @@
+
+#include "XmlRpcServerConnection.h"
+
+#include "XmlRpcSocket.h"
+#include "XmlRpc.h"
+#ifndef MAKEDEPEND
+# include <stdio.h>
+# include <stdlib.h>
+#endif
+
+using namespace XmlRpc;
+
+// Static data
+const char XmlRpcServerConnection::METHODNAME_TAG[] = "<methodName>";
+const char XmlRpcServerConnection::PARAMS_TAG[] = "<params>";
+const char XmlRpcServerConnection::PARAMS_ETAG[] = "</params>";
+const char XmlRpcServerConnection::PARAM_TAG[] = "<param>";
+const char XmlRpcServerConnection::PARAM_ETAG[] = "</param>";
+
+const std::string XmlRpcServerConnection::SYSTEM_MULTICALL = "system.multicall";
+const std::string XmlRpcServerConnection::METHODNAME = "methodName";
+const std::string XmlRpcServerConnection::PARAMS = "params";
+
+const std::string XmlRpcServerConnection::FAULTCODE = "faultCode";
+const std::string XmlRpcServerConnection::FAULTSTRING = "faultString";
+
+
+
+// The server delegates handling client requests to a serverConnection object.
+XmlRpcServerConnection::XmlRpcServerConnection(int fd, XmlRpcServer* server, bool deleteOnClose /*= false*/) :
+ XmlRpcSource(fd, deleteOnClose)
+{
+ XmlRpcUtil::log(2,"XmlRpcServerConnection: new socket %d.", fd);
+ _server = server;
+ _connectionState = READ_HEADER;
+ _keepAlive = true;
+}
+
+
+XmlRpcServerConnection::~XmlRpcServerConnection()
+{
+ XmlRpcUtil::log(4,"XmlRpcServerConnection dtor.");
+ _server->removeConnection(this);
+}
+
+
+// Handle input on the server socket by accepting the connection
+// and reading the rpc request. Return true to continue to monitor
+// the socket for events, false to remove it from the dispatcher.
+unsigned
+XmlRpcServerConnection::handleEvent(unsigned /*eventType*/)
+{
+ if (_connectionState == READ_HEADER)
+ if ( ! readHeader()) return 0;
+
+ if (_connectionState == READ_REQUEST)
+ if ( ! readRequest()) return 0;
+
+ if (_connectionState == WRITE_RESPONSE)
+ if ( ! writeResponse()) return 0;
+
+ return (_connectionState == WRITE_RESPONSE)
+ ? XmlRpcDispatch::WritableEvent : XmlRpcDispatch::ReadableEvent;
+}
+
+
+bool
+XmlRpcServerConnection::readHeader()
+{
+ // Read available data
+ bool eof;
+ if ( ! XmlRpcSocket::nbRead(this->getfd(), _header, &eof)) {
+ // Its only an error if we already have read some data
+ if (_header.length() > 0)
+ XmlRpcUtil::error("XmlRpcServerConnection::readHeader: error while reading header (%s).",XmlRpcSocket::getErrorMsg().c_str());
+ return false;
+ }
+
+ XmlRpcUtil::log(4, "XmlRpcServerConnection::readHeader: read %d bytes.", _header.length());
+ char *hp = (char*)_header.c_str(); // Start of header
+ char *ep = hp + _header.length(); // End of string
+ char *bp = 0; // Start of body
+ char *lp = 0; // Start of content-length value
+ char *kp = 0; // Start of connection value
+
+ for (char *cp = hp; (bp == 0) && (cp < ep); ++cp) {
+ if ((ep - cp > 16) && (strncasecmp(cp, "Content-length: ", 16) == 0))
+ lp = cp + 16;
+ else if ((ep - cp > 12) && (strncasecmp(cp, "Connection: ", 12) == 0))
+ kp = cp + 12;
+ else if ((ep - cp > 4) && (strncmp(cp, "\r\n\r\n", 4) == 0))
+ bp = cp + 4;
+ else if ((ep - cp > 2) && (strncmp(cp, "\n\n", 2) == 0))
+ bp = cp + 2;
+ }
+
+ // If we haven't gotten the entire header yet, return (keep reading)
+ if (bp == 0) {
+ // EOF in the middle of a request is an error, otherwise its ok
+ if (eof) {
+ XmlRpcUtil::log(4, "XmlRpcServerConnection::readHeader: EOF");
+ if (_header.length() > 0)
+ XmlRpcUtil::error("XmlRpcServerConnection::readHeader: EOF while reading header");
+ return false; // Either way we close the connection
+ }
+
+ return true; // Keep reading
+ }
+
+ // Decode content length
+ if (lp == 0) {
+ XmlRpcUtil::error("XmlRpcServerConnection::readHeader: No Content-length specified");
+ return false; // We could try to figure it out by parsing as we read, but for now...
+ }
+
+ _contentLength = atoi(lp);
+ if (_contentLength <= 0) {
+ XmlRpcUtil::error("XmlRpcServerConnection::readHeader: Invalid Content-length specified (%d).", _contentLength);
+ return false;
+ }
+
+ XmlRpcUtil::log(3, "XmlRpcServerConnection::readHeader: specified content length is %d.", _contentLength);
+
+ // Otherwise copy non-header data to request buffer and set state to read request.
+ _request = bp;
+
+ // Parse out any interesting bits from the header (HTTP version, connection)
+ _keepAlive = true;
+ if (_header.find("HTTP/1.0") != std::string::npos) {
+ if (kp == 0 || strncasecmp(kp, "keep-alive", 10) != 0)
+ _keepAlive = false; // Default for HTTP 1.0 is to close the connection
+ } else {
+ if (kp != 0 && strncasecmp(kp, "close", 5) == 0)
+ _keepAlive = false;
+ }
+ XmlRpcUtil::log(3, "KeepAlive: %d", _keepAlive);
+
+
+ _header = "";
+ _connectionState = READ_REQUEST;
+ return true; // Continue monitoring this source
+}
+
+bool
+XmlRpcServerConnection::readRequest()
+{
+ // If we dont have the entire request yet, read available data
+ if (int(_request.length()) < _contentLength) {
+ bool eof;
+ if ( ! XmlRpcSocket::nbRead(this->getfd(), _request, &eof)) {
+ XmlRpcUtil::error("XmlRpcServerConnection::readRequest: read error (%s).",XmlRpcSocket::getErrorMsg().c_str());
+ return false;
+ }
+
+ // If we haven't gotten the entire request yet, return (keep reading)
+ if (int(_request.length()) < _contentLength) {
+ if (eof) {
+ XmlRpcUtil::error("XmlRpcServerConnection::readRequest: EOF while reading request");
+ return false; // Either way we close the connection
+ }
+ return true;
+ }
+ }
+
+ // Otherwise, parse and dispatch the request
+ XmlRpcUtil::log(3, "XmlRpcServerConnection::readRequest read %d bytes.", _request.length());
+ //XmlRpcUtil::log(5, "XmlRpcServerConnection::readRequest:\n%s\n", _request.c_str());
+
+ _connectionState = WRITE_RESPONSE;
+
+ return true; // Continue monitoring this source
+}
+
+
+bool
+XmlRpcServerConnection::writeResponse()
+{
+ if (_response.length() == 0) {
+ executeRequest();
+ _bytesWritten = 0;
+ if (_response.length() == 0) {
+ XmlRpcUtil::error("XmlRpcServerConnection::writeResponse: empty response.");
+ return false;
+ }
+ }
+
+ // Try to write the response
+ if ( ! XmlRpcSocket::nbWrite(this->getfd(), _response, &_bytesWritten)) {
+ XmlRpcUtil::error("XmlRpcServerConnection::writeResponse: write error (%s).",XmlRpcSocket::getErrorMsg().c_str());
+ return false;
+ }
+ XmlRpcUtil::log(3, "XmlRpcServerConnection::writeResponse: wrote %d of %d bytes.", _bytesWritten, _response.length());
+
+ // Prepare to read the next request
+ if (_bytesWritten == int(_response.length())) {
+ _header = "";
+ _request = "";
+ _response = "";
+ _connectionState = READ_HEADER;
+ }
+
+ return _keepAlive; // Continue monitoring this source if true
+}
+
+// Run the method, generate _response string
+void
+XmlRpcServerConnection::executeRequest()
+{
+ XmlRpcValue params, resultValue;
+ std::string methodName = parseRequest(params);
+ XmlRpcUtil::log(2, "XmlRpcServerConnection::executeRequest: server calling method '%s'",
+ methodName.c_str());
+
+ try {
+
+ if ( ! executeMethod(methodName, params, resultValue) &&
+ ! executeMulticall(methodName, params, resultValue))
+ generateFaultResponse(methodName + ": unknown method name");
+ else
+ generateResponse(resultValue.toXml());
+
+ } catch (const XmlRpcException& fault) {
+ XmlRpcUtil::log(2, "XmlRpcServerConnection::executeRequest: fault %s.",
+ fault.getMessage().c_str());
+ generateFaultResponse(fault.getMessage(), fault.getCode());
+ }
+}
+
+// Parse the method name and the argument values from the request.
+std::string
+XmlRpcServerConnection::parseRequest(XmlRpcValue& params)
+{
+ int offset = 0; // Number of chars parsed from the request
+
+ std::string methodName = XmlRpcUtil::parseTag(METHODNAME_TAG, _request, &offset);
+
+ if (methodName.size() > 0 && XmlRpcUtil::findTag(PARAMS_TAG, _request, &offset))
+ {
+ int nArgs = 0;
+ while (XmlRpcUtil::nextTagIs(PARAM_TAG, _request, &offset)) {
+ params[nArgs++] = XmlRpcValue(_request, &offset);
+ (void) XmlRpcUtil::nextTagIs(PARAM_ETAG, _request, &offset);
+ }
+
+ (void) XmlRpcUtil::nextTagIs(PARAMS_ETAG, _request, &offset);
+ }
+
+ return methodName;
+}
+
+// Execute a named method with the specified params.
+bool
+XmlRpcServerConnection::executeMethod(const std::string& methodName,
+ XmlRpcValue& params, XmlRpcValue& result)
+{
+ XmlRpcServerMethod* method = _server->findMethod(methodName);
+
+ if ( ! method) return false;
+
+ method->execute(params, result);
+
+ // Ensure a valid result value
+ if ( ! result.valid())
+ result = std::string();
+
+ return true;
+}
+
+// Execute multiple calls and return the results in an array.
+bool
+XmlRpcServerConnection::executeMulticall(const std::string& methodName,
+ XmlRpcValue& params, XmlRpcValue& result)
+{
+ if (methodName != SYSTEM_MULTICALL) return false;
+
+ // There ought to be 1 parameter, an array of structs
+ if (params.size() != 1 || params[0].getType() != XmlRpcValue::TypeArray)
+ throw XmlRpcException(SYSTEM_MULTICALL + ": Invalid argument (expected an array)");
+
+ int nc = params[0].size();
+ result.setSize(nc);
+
+ for (int i=0; i<nc; ++i) {
+
+ if ( ! params[0][i].hasMember(METHODNAME) ||
+ ! params[0][i].hasMember(PARAMS)) {
+ result[i][FAULTCODE] = -1;
+ result[i][FAULTSTRING] = SYSTEM_MULTICALL +
+ ": Invalid argument (expected a struct with members methodName and params)";
+ continue;
+ }
+
+ const std::string& methodName = params[0][i][METHODNAME];
+ XmlRpcValue& methodParams = params[0][i][PARAMS];
+
+ XmlRpcValue resultValue;
+ resultValue.setSize(1);
+ try {
+ if ( ! executeMethod(methodName, methodParams, resultValue[0]) &&
+ ! executeMulticall(methodName, params, resultValue[0]))
+ {
+ result[i][FAULTCODE] = -1;
+ result[i][FAULTSTRING] = methodName + ": unknown method name";
+ }
+ else
+ result[i] = resultValue;
+
+ } catch (const XmlRpcException& fault) {
+ result[i][FAULTCODE] = fault.getCode();
+ result[i][FAULTSTRING] = fault.getMessage();
+ }
+ }
+
+ return true;
+}
+
+
+// Create a response from results xml
+void
+XmlRpcServerConnection::generateResponse(std::string const& resultXml)
+{
+ const char RESPONSE_1[] =
+ "<?xml version=\"1.0\"?>\r\n"
+ "<methodResponse><params><param>\r\n\t";
+ const char RESPONSE_2[] =
+ "\r\n</param></params></methodResponse>\r\n";
+
+ std::string body = RESPONSE_1 + resultXml + RESPONSE_2;
+ std::string header = generateHeader(body);
+
+ _response = header + body;
+ XmlRpcUtil::log(5, "XmlRpcServerConnection::generateResponse:\n%s\n", _response.c_str());
+}
+
+// Prepend http headers
+std::string
+XmlRpcServerConnection::generateHeader(std::string const& body)
+{
+ std::string header =
+ "HTTP/1.1 200 OK\r\n"
+ "Server: ";
+ header += XMLRPC_VERSION;
+ header += "\r\n"
+ "Content-Type: text/xml\r\n"
+ "Content-length: ";
+
+ char buffLen[40];
+ sprintf(buffLen,"%d\r\n\r\n", body.size());
+
+ return header + buffLen;
+}
+
+
+void
+XmlRpcServerConnection::generateFaultResponse(std::string const& errorMsg, int errorCode)
+{
+ const char RESPONSE_1[] =
+ "<?xml version=\"1.0\"?>\r\n"
+ "<methodResponse><fault>\r\n\t";
+ const char RESPONSE_2[] =
+ "\r\n</fault></methodResponse>\r\n";
+
+ XmlRpcValue faultStruct;
+ faultStruct[FAULTCODE] = errorCode;
+ faultStruct[FAULTSTRING] = errorMsg;
+ std::string body = RESPONSE_1 + faultStruct.toXml() + RESPONSE_2;
+ std::string header = generateHeader(body);
+
+ _response = header + body;
+}
+
diff --git a/xmlrpc++/src/XmlRpcServerConnection.h b/xmlrpc++/src/XmlRpcServerConnection.h
new file mode 100644
index 0000000..9efbbaf
--- /dev/null
+++ b/xmlrpc++/src/XmlRpcServerConnection.h
@@ -0,0 +1,102 @@
+#ifndef _XMLRPCSERVERCONNECTION_H_
+#define _XMLRPCSERVERCONNECTION_H_
+//
+// XmlRpc++ Copyright (c) 2002-2003 by Chris Morley
+//
+#if defined(_MSC_VER)
+# pragma warning(disable:4786) // identifier was truncated in debug info
+#endif
+
+#ifndef MAKEDEPEND
+# include <string>
+#endif
+
+#include "XmlRpcValue.h"
+#include "XmlRpcSource.h"
+
+namespace XmlRpc {
+
+
+ // The server waits for client connections and provides methods
+ class XmlRpcServer;
+ class XmlRpcServerMethod;
+
+ //! A class to handle XML RPC requests from a particular client
+ class XmlRpcServerConnection : public XmlRpcSource {
+ public:
+ // Static data
+ static const char METHODNAME_TAG[];
+ static const char PARAMS_TAG[];
+ static const char PARAMS_ETAG[];
+ static const char PARAM_TAG[];
+ static const char PARAM_ETAG[];
+
+ static const std::string SYSTEM_MULTICALL;
+ static const std::string METHODNAME;
+ static const std::string PARAMS;
+
+ static const std::string FAULTCODE;
+ static const std::string FAULTSTRING;
+
+ //! Constructor
+ XmlRpcServerConnection(int fd, XmlRpcServer* server, bool deleteOnClose = false);
+ //! Destructor
+ virtual ~XmlRpcServerConnection();
+
+ // XmlRpcSource interface implementation
+ //! Handle IO on the client connection socket.
+ //! @param eventType Type of IO event that occurred. @see XmlRpcDispatch::EventType.
+ virtual unsigned handleEvent(unsigned eventType);
+
+ protected:
+
+ bool readHeader();
+ bool readRequest();
+ bool writeResponse();
+
+ // Parses the request, runs the method, generates the response xml.
+ virtual void executeRequest();
+
+ // Parse the methodName and parameters from the request.
+ std::string parseRequest(XmlRpcValue& params);
+
+ // Execute a named method with the specified params.
+ bool executeMethod(const std::string& methodName, XmlRpcValue& params, XmlRpcValue& result);
+
+ // Execute multiple calls and return the results in an array.
+ bool executeMulticall(const std::string& methodName, XmlRpcValue& params, XmlRpcValue& result);
+
+ // Construct a response from the result XML.
+ void generateResponse(std::string const& resultXml);
+ void generateFaultResponse(std::string const& msg, int errorCode = -1);
+ std::string generateHeader(std::string const& body);
+
+
+ // The XmlRpc server that accepted this connection
+ XmlRpcServer* _server;
+
+ // Possible IO states for the connection
+ enum ServerConnectionState { READ_HEADER, READ_REQUEST, WRITE_RESPONSE };
+ ServerConnectionState _connectionState;
+
+ // Request headers
+ std::string _header;
+
+ // Number of bytes expected in the request body (parsed from header)
+ int _contentLength;
+
+ // Request body
+ std::string _request;
+
+ // Response
+ std::string _response;
+
+ // Number of bytes of the response written so far
+ int _bytesWritten;
+
+ // Whether to keep the current client connection open for further requests
+ bool _keepAlive;
+ };
+} // namespace XmlRpc
+
+#endif // _XMLRPCSERVERCONNECTION_H_
diff --git a/xmlrpc++/src/XmlRpcServerMethod.cpp b/xmlrpc++/src/XmlRpcServerMethod.cpp
new file mode 100644
index 0000000..1616ff4
--- /dev/null
+++ b/xmlrpc++/src/XmlRpcServerMethod.cpp
@@ -0,0 +1,21 @@
+
+#include "XmlRpcServerMethod.h"
+#include "XmlRpcServer.h"
+
+namespace XmlRpc {
+
+
+ XmlRpcServerMethod::XmlRpcServerMethod(std::string const& name, XmlRpcServer* server)
+ {
+ _name = name;
+ _server = server;
+ if (_server) _server->addMethod(this);
+ }
+
+ XmlRpcServerMethod::~XmlRpcServerMethod()
+ {
+ if (_server) _server->removeMethod(this);
+ }
+
+
+} // namespace XmlRpc
diff --git a/xmlrpc++/src/XmlRpcServerMethod.h b/xmlrpc++/src/XmlRpcServerMethod.h
new file mode 100644
index 0000000..738a9c8
--- /dev/null
+++ b/xmlrpc++/src/XmlRpcServerMethod.h
@@ -0,0 +1,47 @@
+
+#ifndef _XMLRPCSERVERMETHOD_H_
+#define _XMLRPCSERVERMETHOD_H_
+//
+// XmlRpc++ Copyright (c) 2002-2003 by Chris Morley
+//
+#if defined(_MSC_VER)
+# pragma warning(disable:4786) // identifier was truncated in debug info
+#endif
+
+#ifndef MAKEDEPEND
+# include <string>
+#endif
+
+namespace XmlRpc {
+
+ // Representation of a parameter or result value
+ class XmlRpcValue;
+
+ // The XmlRpcServer processes client requests to call RPCs
+ class XmlRpcServer;
+
+ //! Abstract class representing a single RPC method
+ class XmlRpcServerMethod {
+ public:
+ //! Constructor
+ XmlRpcServerMethod(std::string const& name, XmlRpcServer* server = 0);
+ //! Destructor
+ virtual ~XmlRpcServerMethod();
+
+ //! Returns the name of the method
+ std::string& name() { return _name; }
+
+ //! Execute the method. Subclasses must provide a definition for this method.
+ virtual void execute(XmlRpcValue& params, XmlRpcValue& result) = 0;
+
+ //! Returns a help string for the method.
+ //! Subclasses should define this method if introspection is being used.
+ virtual std::string help() { return std::string(); }
+
+ protected:
+ std::string _name;
+ XmlRpcServer* _server;
+ };
+} // namespace XmlRpc
+
+#endif // _XMLRPCSERVERMETHOD_H_
diff --git a/xmlrpc++/src/XmlRpcSocket.cpp b/xmlrpc++/src/XmlRpcSocket.cpp
new file mode 100644
index 0000000..b71ef94
--- /dev/null
+++ b/xmlrpc++/src/XmlRpcSocket.cpp
@@ -0,0 +1,260 @@
+
+#include "XmlRpcSocket.h"
+#include "XmlRpcUtil.h"
+
+#ifndef MAKEDEPEND
+
+#if defined(_WINDOWS)
+# include <stdio.h>
+# include <winsock2.h>
+//# pragma lib(WS2_32.lib)
+
+# define EINPROGRESS WSAEINPROGRESS
+# define EWOULDBLOCK WSAEWOULDBLOCK
+# define ETIMEDOUT WSAETIMEDOUT
+#else
+extern "C" {
+# include <unistd.h>
+# include <stdio.h>
+# include <sys/types.h>
+# include <sys/socket.h>
+# include <netinet/in.h>
+# include <netdb.h>
+# include <errno.h>
+# include <fcntl.h>
+}
+#endif // _WINDOWS
+
+#endif // MAKEDEPEND
+
+
+using namespace XmlRpc;
+
+
+
+#if defined(_WINDOWS)
+
+static void initWinSock()
+{
+ static bool wsInit = false;
+ if (! wsInit)
+ {
+ WORD wVersionRequested = MAKEWORD( 2, 0 );
+ WSADATA wsaData;
+ WSAStartup(wVersionRequested, &wsaData);
+ wsInit = true;
+ }
+}
+
+#else
+
+#define initWinSock()
+
+#endif // _WINDOWS
+
+
+// These errors are not considered fatal for an IO operation; the operation will be re-tried.
+static inline bool
+nonFatalError()
+{
+ int err = XmlRpcSocket::getError();
+ return (err == EINPROGRESS || err == EAGAIN || err == EWOULDBLOCK || err == EINTR);
+}
+
+
+
+int
+XmlRpcSocket::socket()
+{
+ initWinSock();
+ return (int) ::socket(AF_INET, SOCK_STREAM, 0);
+}
+
+
+void
+XmlRpcSocket::close(int fd)
+{
+ XmlRpcUtil::log(4, "XmlRpcSocket::close: fd %d.", fd);
+#if defined(_WINDOWS)
+ closesocket(fd);
+#else
+ ::close(fd);
+#endif // _WINDOWS
+}
+
+
+
+
+bool
+XmlRpcSocket::setNonBlocking(int fd)
+{
+#if defined(_WINDOWS)
+ unsigned long flag = 1;
+ return (ioctlsocket((SOCKET)fd, FIONBIO, &flag) == 0);
+#else
+ return (fcntl(fd, F_SETFL, O_NONBLOCK) == 0);
+#endif // _WINDOWS
+}
+
+
+bool
+XmlRpcSocket::setReuseAddr(int fd)
+{
+ // Allow this port to be re-bound immediately so server re-starts are not delayed
+ int sflag = 1;
+ return (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&sflag, sizeof(sflag)) == 0);
+}
+
+
+// Bind to a specified port
+bool
+XmlRpcSocket::bind(int fd, int port)
+{
+ struct sockaddr_in saddr;
+ memset(&saddr, 0, sizeof(saddr));
+ saddr.sin_family = AF_INET;
+ saddr.sin_addr.s_addr = htonl(INADDR_ANY);
+ saddr.sin_port = htons((u_short) port);
+ return (::bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)) == 0);
+}
+
+
+// Set socket in listen mode
+bool
+XmlRpcSocket::listen(int fd, int backlog)
+{
+ return (::listen(fd, backlog) == 0);
+}
+
+
+int
+XmlRpcSocket::accept(int fd)
+{
+ struct sockaddr_in addr;
+#if defined(_WINDOWS)
+ int
+#else
+ socklen_t
+#endif
+ addrlen = sizeof(addr);
+
+ return (int) ::accept(fd, (struct sockaddr*)&addr, &addrlen);
+}
+
+
+
+// Connect a socket to a server (from a client)
+bool
+XmlRpcSocket::connect(int fd, std::string& host, int port)
+{
+ struct sockaddr_in saddr;
+ memset(&saddr, 0, sizeof(saddr));
+ saddr.sin_family = AF_INET;
+
+ struct hostent *hp = gethostbyname(host.c_str());
+ if (hp == 0) return false;
+
+ saddr.sin_family = hp->h_addrtype;
+ memcpy(&saddr.sin_addr, hp->h_addr, hp->h_length);
+ saddr.sin_port = htons((u_short) port);
+
+ // For asynch operation, this will return EWOULDBLOCK (windows) or
+ // EINPROGRESS (linux) and we just need to wait for the socket to be writable...
+ int result = ::connect(fd, (struct sockaddr *)&saddr, sizeof(saddr));
+ return result == 0 || nonFatalError();
+}
+
+
+
+// Read available text from the specified socket. Returns false on error.
+bool
+XmlRpcSocket::nbRead(int fd, std::string& s, bool *eof)
+{
+ const int READ_SIZE = 4096; // Number of bytes to attempt to read at a time
+ char readBuf[READ_SIZE];
+
+ bool wouldBlock = false;
+ *eof = false;
+
+ while ( ! wouldBlock && ! *eof) {
+#if defined(_WINDOWS)
+ int n = recv(fd, readBuf, READ_SIZE-1, 0);
+#else
+ int n = read(fd, readBuf, READ_SIZE-1);
+#endif
+ XmlRpcUtil::log(5, "XmlRpcSocket::nbRead: read/recv returned %d.", n);
+
+ if (n > 0) {
+ readBuf[n] = 0;
+ s.append(readBuf, n);
+ } else if (n == 0) {
+ *eof = true;
+ } else if (nonFatalError()) {
+ wouldBlock = true;
+ } else {
+ return false; // Error
+ }
+ }
+ return true;
+}
+
+
+// Write text to the specified socket. Returns false on error.
+bool
+XmlRpcSocket::nbWrite(int fd, std::string& s, int *bytesSoFar)
+{
+ int nToWrite = int(s.length()) - *bytesSoFar;
+ char *sp = const_cast<char*>(s.c_str()) + *bytesSoFar;
+ bool wouldBlock = false;
+
+ while ( nToWrite > 0 && ! wouldBlock ) {
+#if defined(_WINDOWS)
+ int n = send(fd, sp, nToWrite, 0);
+#else
+ int n = write(fd, sp, nToWrite);
+#endif
+ XmlRpcUtil::log(5, "XmlRpcSocket::nbWrite: send/write returned %d.", n);
+
+ if (n > 0) {
+ sp += n;
+ *bytesSoFar += n;
+ nToWrite -= n;
+ } else if (nonFatalError()) {
+ wouldBlock = true;
+ } else {
+ return false; // Error
+ }
+ }
+ return true;
+}
+
+
+// Returns last errno
+int
+XmlRpcSocket::getError()
+{
+#if defined(_WINDOWS)
+ return WSAGetLastError();
+#else
+ return errno;
+#endif
+}
+
+
+// Returns message corresponding to last errno
+std::string
+XmlRpcSocket::getErrorMsg()
+{
+ return getErrorMsg(getError());
+}
+
+// Returns message corresponding to errno... well, it should anyway
+std::string
+XmlRpcSocket::getErrorMsg(int error)
+{
+ char err[60];
+ snprintf(err,sizeof(err),"error %d", error);
+ return std::string(err);
+}
+
+
diff --git a/xmlrpc++/src/XmlRpcSocket.h b/xmlrpc++/src/XmlRpcSocket.h
new file mode 100644
index 0000000..fa7f950
--- /dev/null
+++ b/xmlrpc++/src/XmlRpcSocket.h
@@ -0,0 +1,69 @@
+#ifndef _XMLRPCSOCKET_H_
+#define _XMLRPCSOCKET_H_
+//
+// XmlRpc++ Copyright (c) 2002-2003 by Chris Morley
+//
+#if defined(_MSC_VER)
+# pragma warning(disable:4786) // identifier was truncated in debug info
+#endif
+
+#ifndef MAKEDEPEND
+# include <string>
+#endif
+
+namespace XmlRpc {
+
+ //! A platform-independent socket API.
+ class XmlRpcSocket {
+ public:
+
+ //! Creates a stream (TCP) socket. Returns -1 on failure.
+ static int socket();
+
+ //! Closes a socket.
+ static void close(int socket);
+
+
+ //! Sets a stream (TCP) socket to perform non-blocking IO. Returns false on failure.
+ static bool setNonBlocking(int socket);
+
+ //! Read text from the specified socket. Returns false on error.
+ static bool nbRead(int socket, std::string& s, bool *eof);
+
+ //! Write text to the specified socket. Returns false on error.
+ static bool nbWrite(int socket, std::string& s, int *bytesSoFar);
+
+
+ // The next four methods are appropriate for servers.
+
+ //! Allow the port the specified socket is bound to to be re-bound immediately so
+ //! server re-starts are not delayed. Returns false on failure.
+ static bool setReuseAddr(int socket);
+
+ //! Bind to a specified port
+ static bool bind(int socket, int port);
+
+ //! Set socket in listen mode
+ static bool listen(int socket, int backlog);
+
+ //! Accept a client connection request
+ static int accept(int socket);
+
+
+ //! Connect a socket to a server (from a client)
+ static bool connect(int socket, std::string& host, int port);
+
+
+ //! Returns last errno
+ static int getError();
+
+ //! Returns message corresponding to last error
+ static std::string getErrorMsg();
+
+ //! Returns message corresponding to error
+ static std::string getErrorMsg(int error);
+ };
+
+} // namespace XmlRpc
+
+#endif
diff --git a/xmlrpc++/src/XmlRpcSource.cpp b/xmlrpc++/src/XmlRpcSource.cpp
new file mode 100644
index 0000000..99203b0
--- /dev/null
+++ b/xmlrpc++/src/XmlRpcSource.cpp
@@ -0,0 +1,35 @@
+
+#include "XmlRpcSource.h"
+#include "XmlRpcSocket.h"
+#include "XmlRpcUtil.h"
+
+namespace XmlRpc {
+
+
+ XmlRpcSource::XmlRpcSource(int fd /*= -1*/, bool deleteOnClose /*= false*/)
+ : _fd(fd), _deleteOnClose(deleteOnClose), _keepOpen(false)
+ {
+ }
+
+ XmlRpcSource::~XmlRpcSource()
+ {
+ }
+
+
+ void
+ XmlRpcSource::close()
+ {
+ if (_fd != -1) {
+ XmlRpcUtil::log(2,"XmlRpcSource::close: closing socket %d.", _fd);
+ XmlRpcSocket::close(_fd);
+ XmlRpcUtil::log(2,"XmlRpcSource::close: done closing socket %d.", _fd);
+ _fd = -1;
+ }
+ if (_deleteOnClose) {
+ XmlRpcUtil::log(2,"XmlRpcSource::close: deleting this");
+ _deleteOnClose = false;
+ delete this;
+ }
+ }
+
+} // namespace XmlRpc
diff --git a/xmlrpc++/src/XmlRpcSource.h b/xmlrpc++/src/XmlRpcSource.h
new file mode 100644
index 0000000..135dce4
--- /dev/null
+++ b/xmlrpc++/src/XmlRpcSource.h
@@ -0,0 +1,55 @@
+
+#ifndef _XMLRPCSOURCE_H_
+#define _XMLRPCSOURCE_H_
+//
+// XmlRpc++ Copyright (c) 2002-2003 by Chris Morley
+//
+#if defined(_MSC_VER)
+# pragma warning(disable:4786) // identifier was truncated in debug info
+#endif
+
+namespace XmlRpc {
+
+ //! An RPC source represents a file descriptor to monitor
+ class XmlRpcSource {
+ public:
+ //! Constructor
+ //! @param fd The socket file descriptor to monitor.
+ //! @param deleteOnClose If true, the object deletes itself when close is called.
+ XmlRpcSource(int fd = -1, bool deleteOnClose = false);
+
+ //! Destructor
+ virtual ~XmlRpcSource();
+
+ //! Return the file descriptor being monitored.
+ int getfd() const { return _fd; }
+ //! Specify the file descriptor to monitor.
+ void setfd(int fd) { _fd = fd; }
+
+ //! Return whether the file descriptor should be kept open if it is no longer monitored.
+ bool getKeepOpen() const { return _keepOpen; }
+ //! Specify whether the file descriptor should be kept open if it is no longer monitored.
+ void setKeepOpen(bool b=true) { _keepOpen = b; }
+
+ //! Close the owned fd. If deleteOnClose was specified at construction, the object is deleted.
+ virtual void close();
+
+ //! Return true to continue monitoring this source
+ virtual unsigned handleEvent(unsigned eventType) = 0;
+
+ private:
+
+ // Socket. This should really be a SOCKET (an alias for unsigned int*) on windows...
+ int _fd;
+
+ // In the server, a new source (XmlRpcServerConnection) is created
+ // for each connected client. When each connection is closed, the
+ // corresponding source object is deleted.
+ bool _deleteOnClose;
+
+ // In the client, keep connections open if you intend to make multiple calls.
+ bool _keepOpen;
+ };
+} // namespace XmlRpc
+
+#endif //_XMLRPCSOURCE_H_
diff --git a/xmlrpc++/src/XmlRpcUtil.cpp b/xmlrpc++/src/XmlRpcUtil.cpp
new file mode 100644
index 0000000..1bd583a
--- /dev/null
+++ b/xmlrpc++/src/XmlRpcUtil.cpp
@@ -0,0 +1,250 @@
+
+#include "XmlRpcUtil.h"
+
+#ifndef MAKEDEPEND
+# include <ctype.h>
+# include <iostream>
+# include <stdarg.h>
+# include <stdio.h>
+# include <string.h>
+#endif
+
+#include "XmlRpc.h"
+
+using namespace XmlRpc;
+
+
+//#define USE_WINDOWS_DEBUG // To make the error and log messages go to VC++ debug output
+#ifdef USE_WINDOWS_DEBUG
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#endif
+
+// Version id
+const char XmlRpc::XMLRPC_VERSION[] = "XMLRPC++ 0.7";
+
+// Default log verbosity: 0 for no messages through 5 (writes everything)
+int XmlRpcLogHandler::_verbosity = 0;
+
+// Default log handler
+static class DefaultLogHandler : public XmlRpcLogHandler {
+public:
+
+ void log(int level, const char* msg) {
+#ifdef USE_WINDOWS_DEBUG
+ if (level <= _verbosity) { OutputDebugString(msg); OutputDebugString("\n"); }
+#else
+ if (level <= _verbosity) std::cout << msg << std::endl;
+#endif
+ }
+
+} defaultLogHandler;
+
+// Message log singleton
+XmlRpcLogHandler* XmlRpcLogHandler::_logHandler = &defaultLogHandler;
+
+
+// Default error handler
+static class DefaultErrorHandler : public XmlRpcErrorHandler {
+public:
+
+ void error(const char* msg) {
+#ifdef USE_WINDOWS_DEBUG
+ OutputDebugString(msg); OutputDebugString("\n");
+#else
+ std::cerr << msg << std::endl;
+#endif
+ }
+} defaultErrorHandler;
+
+
+// Error handler singleton
+XmlRpcErrorHandler* XmlRpcErrorHandler::_errorHandler = &defaultErrorHandler;
+
+
+// Easy API for log verbosity
+int XmlRpc::getVerbosity() { return XmlRpcLogHandler::getVerbosity(); }
+void XmlRpc::setVerbosity(int level) { XmlRpcLogHandler::setVerbosity(level); }
+
+
+
+void XmlRpcUtil::log(int level, const char* fmt, ...)
+{
+ if (level <= XmlRpcLogHandler::getVerbosity())
+ {
+ va_list va;
+ char buf[1024];
+ va_start( va, fmt);
+ vsnprintf(buf,sizeof(buf)-1,fmt,va);
+ buf[sizeof(buf)-1] = 0;
+ XmlRpcLogHandler::getLogHandler()->log(level, buf);
+ }
+}
+
+
+void XmlRpcUtil::error(const char* fmt, ...)
+{
+ va_list va;
+ va_start(va, fmt);
+ char buf[1024];
+ vsnprintf(buf,sizeof(buf)-1,fmt,va);
+ buf[sizeof(buf)-1] = 0;
+ XmlRpcErrorHandler::getErrorHandler()->error(buf);
+}
+
+
+// Returns contents between <tag> and </tag>, updates offset to char after </tag>
+std::string
+XmlRpcUtil::parseTag(const char* tag, std::string const& xml, int* offset)
+{
+ if (*offset >= int(xml.length())) return std::string();
+ size_t istart = xml.find(tag, *offset);
+ if (istart == std::string::npos) return std::string();
+ istart += strlen(tag);
+ std::string etag = "</";
+ etag += tag + 1;
+ size_t iend = xml.find(etag, istart);
+ if (iend == std::string::npos) return std::string();
+
+ *offset = int(iend + etag.length());
+ return xml.substr(istart, iend-istart);
+}
+
+
+// Returns true if the tag is found and updates offset to the char after the tag
+bool
+XmlRpcUtil::findTag(const char* tag, std::string const& xml, int* offset)
+{
+ if (*offset >= int(xml.length())) return false;
+ size_t istart = xml.find(tag, *offset);
+ if (istart == std::string::npos)
+ return false;
+
+ *offset = int(istart + strlen(tag));
+ return true;
+}
+
+
+// Returns true if the tag is found at the specified offset (modulo any whitespace)
+// and updates offset to the char after the tag
+bool
+XmlRpcUtil::nextTagIs(const char* tag, std::string const& xml, int* offset)
+{
+ if (*offset >= int(xml.length())) return false;
+ const char* cp = xml.c_str() + *offset;
+ int nc = 0;
+ while (*cp && isspace(*cp)) {
+ ++cp;
+ ++nc;
+ }
+
+ int len = int(strlen(tag));
+ if (*cp && (strncmp(cp, tag, len) == 0)) {
+ *offset += nc + len;
+ return true;
+ }
+ return false;
+}
+
+// Returns the next tag and updates offset to the char after the tag, or empty string
+// if the next non-whitespace character is not '<'
+std::string
+XmlRpcUtil::getNextTag(std::string const& xml, int* offset)
+{
+ if (*offset >= int(xml.length())) return std::string();
+
+ size_t pos = *offset;
+ const char* cp = xml.c_str() + pos;
+ while (*cp && isspace(*cp)) {
+ ++cp;
+ ++pos;
+ }
+
+ if (*cp != '<') return std::string();
+
+ std::string s;
+ do {
+ s += *cp;
+ ++pos;
+ } while (*cp++ != '>' && *cp != 0);
+
+ *offset = int(pos);
+ return s;
+}
+
+
+
+// xml encodings (xml-encoded entities are preceded with '&')
+static const char AMP = '&';
+static const char rawEntity[] = { '<', '>', '&', '\'', '\"', 0 };
+static const char* xmlEntity[] = { "lt;", "gt;", "amp;", "apos;", "quot;", 0 };
+static const int xmlEntLen[] = { 3, 3, 4, 5, 5 };
+
+
+// Replace xml-encoded entities with the raw text equivalents.
+
+std::string
+XmlRpcUtil::xmlDecode(const std::string& encoded)
+{
+ std::string::size_type iAmp = encoded.find(AMP);
+ if (iAmp == std::string::npos)
+ return encoded;
+
+ std::string decoded(encoded, 0, iAmp);
+ std::string::size_type iSize = encoded.size();
+ decoded.reserve(iSize);
+
+ const char* ens = encoded.c_str();
+ while (iAmp != iSize) {
+ if (encoded[iAmp] == AMP && iAmp+1 < iSize) {
+ int iEntity;
+ for (iEntity=0; xmlEntity[iEntity] != 0; ++iEntity)
+ //if (encoded.compare(iAmp+1, xmlEntLen[iEntity], xmlEntity[iEntity]) == 0)
+ if (strncmp(ens+iAmp+1, xmlEntity[iEntity], xmlEntLen[iEntity]) == 0)
+ {
+ decoded += rawEntity[iEntity];
+ iAmp += xmlEntLen[iEntity]+1;
+ break;
+ }
+ if (xmlEntity[iEntity] == 0) // unrecognized sequence
+ decoded += encoded[iAmp++];
+
+ } else {
+ decoded += encoded[iAmp++];
+ }
+ }
+
+ return decoded;
+}
+
+
+// Replace raw text with xml-encoded entities.
+
+std::string
+XmlRpcUtil::xmlEncode(const std::string& raw)
+{
+ std::string::size_type iRep = raw.find_first_of(rawEntity);
+ if (iRep == std::string::npos)
+ return raw;
+
+ std::string encoded(raw, 0, iRep);
+ std::string::size_type iSize = raw.size();
+
+ while (iRep != iSize) {
+ int iEntity;
+ for (iEntity=0; rawEntity[iEntity] != 0; ++iEntity)
+ if (raw[iRep] == rawEntity[iEntity])
+ {
+ encoded += AMP;
+ encoded += xmlEntity[iEntity];
+ break;
+ }
+ if (rawEntity[iEntity] == 0)
+ encoded += raw[iRep];
+ ++iRep;
+ }
+ return encoded;
+}
+
+
+
diff --git a/xmlrpc++/src/XmlRpcUtil.h b/xmlrpc++/src/XmlRpcUtil.h
new file mode 100644
index 0000000..8128f72
--- /dev/null
+++ b/xmlrpc++/src/XmlRpcUtil.h
@@ -0,0 +1,61 @@
+#ifndef _XMLRPCUTIL_H_
+#define _XMLRPCUTIL_H_
+//
+// XmlRpc++ Copyright (c) 2002-2003 by Chris Morley
+//
+#if defined(_MSC_VER)
+# pragma warning(disable:4786) // identifier was truncated in debug info
+#endif
+
+#ifndef MAKEDEPEND
+# include <string>
+#endif
+
+#if defined(_MSC_VER)
+# define snprintf _snprintf
+# define vsnprintf _vsnprintf
+# define strcasecmp _stricmp
+# define strncasecmp _strnicmp
+#elif defined(__BORLANDC__)
+# define strcasecmp stricmp
+# define strncasecmp strnicmp
+#endif
+
+namespace XmlRpc {
+
+ //! Utilities for XML parsing, encoding, and decoding and message handlers.
+ class XmlRpcUtil {
+ public:
+ // hokey xml parsing
+ //! Returns contents between <tag> and </tag>, updates offset to char after </tag>
+ static std::string parseTag(const char* tag, std::string const& xml, int* offset);
+
+ //! Returns true if the tag is found and updates offset to the char after the tag
+ static bool findTag(const char* tag, std::string const& xml, int* offset);
+
+ //! Returns the next tag and updates offset to the char after the tag, or empty string
+ //! if the next non-whitespace character is not '<'
+ static std::string getNextTag(std::string const& xml, int* offset);
+
+ //! Returns true if the tag is found at the specified offset (modulo any whitespace)
+ //! and updates offset to the char after the tag
+ static bool nextTagIs(const char* tag, std::string const& xml, int* offset);
+
+
+ //! Convert raw text to encoded xml.
+ static std::string xmlEncode(const std::string& raw);
+
+ //! Convert encoded xml to raw text
+ static std::string xmlDecode(const std::string& encoded);
+
+
+ //! Dump messages somewhere
+ static void log(int level, const char* fmt, ...);
+
+ //! Dump error messages somewhere
+ static void error(const char* fmt, ...);
+
+ };
+} // namespace XmlRpc
+
+#endif // _XMLRPCUTIL_H_
diff --git a/xmlrpc++/src/XmlRpcValue.cpp b/xmlrpc++/src/XmlRpcValue.cpp
new file mode 100644
index 0000000..d6cf3f0
--- /dev/null
+++ b/xmlrpc++/src/XmlRpcValue.cpp
@@ -0,0 +1,611 @@
+
+#include "XmlRpcValue.h"
+#include "XmlRpcException.h"
+#include "XmlRpcUtil.h"
+#include "base64.h"
+
+#ifndef MAKEDEPEND
+# include <iostream>
+# include <ostream>
+# include <stdlib.h>
+# include <stdio.h>
+#endif
+
+namespace XmlRpc {
+
+
+ static const char VALUE_TAG[] = "<value>";
+ static const char VALUE_ETAG[] = "</value>";
+
+ static const char BOOLEAN_TAG[] = "<boolean>";
+ static const char BOOLEAN_ETAG[] = "</boolean>";
+ static const char DOUBLE_TAG[] = "<double>";
+ static const char DOUBLE_ETAG[] = "</double>";
+ static const char INT_TAG[] = "<int>";
+ static const char I4_TAG[] = "<i4>";
+ static const char I4_ETAG[] = "</i4>";
+ static const char STRING_TAG[] = "<string>";
+ static const char DATETIME_TAG[] = "<dateTime.iso8601>";
+ static const char DATETIME_ETAG[] = "</dateTime.iso8601>";
+ static const char BASE64_TAG[] = "<base64>";
+ static const char BASE64_ETAG[] = "</base64>";
+
+ static const char ARRAY_TAG[] = "<array>";
+ static const char DATA_TAG[] = "<data>";
+ static const char DATA_ETAG[] = "</data>";
+ static const char ARRAY_ETAG[] = "</array>";
+
+ static const char STRUCT_TAG[] = "<struct>";
+ static const char MEMBER_TAG[] = "<member>";
+ static const char NAME_TAG[] = "<name>";
+ static const char NAME_ETAG[] = "</name>";
+ static const char MEMBER_ETAG[] = "</member>";
+ static const char STRUCT_ETAG[] = "</struct>";
+
+
+
+ // Format strings
+ std::string XmlRpcValue::_doubleFormat("%f");
+
+
+
+ // Clean up
+ void XmlRpcValue::invalidate()
+ {
+ switch (_type) {
+ case TypeString: delete _value.asString; break;
+ case TypeDateTime: delete _value.asTime; break;
+ case TypeBase64: delete _value.asBinary; break;
+ case TypeArray: delete _value.asArray; break;
+ case TypeStruct: delete _value.asStruct; break;
+ default: break;
+ }
+ _type = TypeInvalid;
+ _value.asBinary = 0;
+ }
+
+
+ // Type checking
+ void XmlRpcValue::assertTypeOrInvalid(Type t)
+ {
+ if (_type == TypeInvalid)
+ {
+ _type = t;
+ switch (_type) { // Ensure there is a valid value for the type
+ case TypeString: _value.asString = new std::string(); break;
+ case TypeDateTime: _value.asTime = new struct tm(); break;
+ case TypeBase64: _value.asBinary = new BinaryData(); break;
+ case TypeArray: _value.asArray = new ValueArray(); break;
+ case TypeStruct: _value.asStruct = new ValueStruct(); break;
+ default: _value.asBinary = 0; break;
+ }
+ }
+ else if (_type != t)
+ throw XmlRpcException("type error");
+ }
+
+ void XmlRpcValue::assertArray(int size) const
+ {
+ if (_type != TypeArray)
+ throw XmlRpcException("type error: expected an array");
+ else if (int(_value.asArray->size()) < size)
+ throw XmlRpcException("range error: array index too large");
+ }
+
+
+ void XmlRpcValue::assertArray(int size)
+ {
+ if (_type == TypeInvalid) {
+ _type = TypeArray;
+ _value.asArray = new ValueArray(size);
+ } else if (_type == TypeArray) {
+ if (int(_value.asArray->size()) < size)
+ _value.asArray->resize(size);
+ } else
+ throw XmlRpcException("type error: expected an array");
+ }
+
+ void XmlRpcValue::assertStruct()
+ {
+ if (_type == TypeInvalid) {
+ _type = TypeStruct;
+ _value.asStruct = new ValueStruct();
+ } else if (_type != TypeStruct)
+ throw XmlRpcException("type error: expected a struct");
+ }
+
+
+ // Operators
+ XmlRpcValue& XmlRpcValue::operator=(XmlRpcValue const& rhs)
+ {
+ if (this != &rhs)
+ {
+ invalidate();
+ _type = rhs._type;
+ switch (_type) {
+ case TypeBoolean: _value.asBool = rhs._value.asBool; break;
+ case TypeInt: _value.asInt = rhs._value.asInt; break;
+ case TypeDouble: _value.asDouble = rhs._value.asDouble; break;
+ case TypeDateTime: _value.asTime = new struct tm(*rhs._value.asTime); break;
+ case TypeString: _value.asString = new std::string(*rhs._value.asString); break;
+ case TypeBase64: _value.asBinary = new BinaryData(*rhs._value.asBinary); break;
+ case TypeArray: _value.asArray = new ValueArray(*rhs._value.asArray); break;
+ case TypeStruct: _value.asStruct = new ValueStruct(*rhs._value.asStruct); break;
+ default: _value.asBinary = 0; break;
+ }
+ }
+ return *this;
+ }
+
+
+ // Predicate for tm equality
+ static bool tmEq(struct tm const& t1, struct tm const& t2) {
+ return t1.tm_sec == t2.tm_sec && t1.tm_min == t2.tm_min &&
+ t1.tm_hour == t2.tm_hour && t1.tm_mday == t1.tm_mday &&
+ t1.tm_mon == t2.tm_mon && t1.tm_year == t2.tm_year;
+ }
+
+ bool XmlRpcValue::operator==(XmlRpcValue const& other) const
+ {
+ if (_type != other._type)
+ return false;
+
+ switch (_type) {
+ case TypeBoolean: return ( !_value.asBool && !other._value.asBool) ||
+ ( _value.asBool && other._value.asBool);
+ case TypeInt: return _value.asInt == other._value.asInt;
+ case TypeDouble: return _value.asDouble == other._value.asDouble;
+ case TypeDateTime: return tmEq(*_value.asTime, *other._value.asTime);
+ case TypeString: return *_value.asString == *other._value.asString;
+ case TypeBase64: return *_value.asBinary == *other._value.asBinary;
+ case TypeArray: return *_value.asArray == *other._value.asArray;
+
+ // The map<>::operator== requires the definition of value< for kcc
+ case TypeStruct: //return *_value.asStruct == *other._value.asStruct;
+ {
+ if (_value.asStruct->size() != other._value.asStruct->size())
+ return false;
+
+ ValueStruct::const_iterator it1=_value.asStruct->begin();
+ ValueStruct::const_iterator it2=other._value.asStruct->begin();
+ while (it1 != _value.asStruct->end()) {
+ const XmlRpcValue& v1 = it1->second;
+ const XmlRpcValue& v2 = it2->second;
+ if ( ! (v1 == v2))
+ return false;
+ it1++;
+ it2++;
+ }
+ return true;
+ }
+ default: break;
+ }
+ return true; // Both invalid values ...
+ }
+
+ bool XmlRpcValue::operator!=(XmlRpcValue const& other) const
+ {
+ return !(*this == other);
+ }
+
+
+ // Works for strings, binary data, arrays, and structs.
+ int XmlRpcValue::size() const
+ {
+ switch (_type) {
+ case TypeString: return int(_value.asString->size());
+ case TypeBase64: return int(_value.asBinary->size());
+ case TypeArray: return int(_value.asArray->size());
+ case TypeStruct: return int(_value.asStruct->size());
+ default: break;
+ }
+
+ throw XmlRpcException("type error");
+ }
+
+ // Checks for existence of struct member
+ bool XmlRpcValue::hasMember(const std::string& name) const
+ {
+ return _type == TypeStruct && _value.asStruct->find(name) != _value.asStruct->end();
+ }
+
+ // Set the value from xml. The chars at *offset into valueXml
+ // should be the start of a <value> tag. Destroys any existing value.
+ bool XmlRpcValue::fromXml(std::string const& valueXml, int* offset)
+ {
+ int savedOffset = *offset;
+
+ invalidate();
+ if ( ! XmlRpcUtil::nextTagIs(VALUE_TAG, valueXml, offset))
+ return false; // Not a value, offset not updated
+
+ int afterValueOffset = *offset;
+ std::string typeTag = XmlRpcUtil::getNextTag(valueXml, offset);
+ bool result = false;
+ if (typeTag == BOOLEAN_TAG)
+ result = boolFromXml(valueXml, offset);
+ else if (typeTag == I4_TAG || typeTag == INT_TAG)
+ result = intFromXml(valueXml, offset);
+ else if (typeTag == DOUBLE_TAG)
+ result = doubleFromXml(valueXml, offset);
+ else if (typeTag.empty() || typeTag == STRING_TAG)
+ result = stringFromXml(valueXml, offset);
+ else if (typeTag == DATETIME_TAG)
+ result = timeFromXml(valueXml, offset);
+ else if (typeTag == BASE64_TAG)
+ result = binaryFromXml(valueXml, offset);
+ else if (typeTag == ARRAY_TAG)
+ result = arrayFromXml(valueXml, offset);
+ else if (typeTag == STRUCT_TAG)
+ result = structFromXml(valueXml, offset);
+ // Watch for empty/blank strings with no <string>tag
+ else if (typeTag == VALUE_ETAG)
+ {
+ *offset = afterValueOffset; // back up & try again
+ result = stringFromXml(valueXml, offset);
+ }
+
+ if (result) // Skip over the </value> tag
+ XmlRpcUtil::findTag(VALUE_ETAG, valueXml, offset);
+ else // Unrecognized tag after <value>
+ *offset = savedOffset;
+
+ return result;
+ }
+
+ // Encode the Value in xml
+ std::string XmlRpcValue::toXml() const
+ {
+ switch (_type) {
+ case TypeBoolean: return boolToXml();
+ case TypeInt: return intToXml();
+ case TypeDouble: return doubleToXml();
+ case TypeString: return stringToXml();
+ case TypeDateTime: return timeToXml();
+ case TypeBase64: return binaryToXml();
+ case TypeArray: return arrayToXml();
+ case TypeStruct: return structToXml();
+ default: break;
+ }
+ return std::string(); // Invalid value
+ }
+
+
+ // Boolean
+ bool XmlRpcValue::boolFromXml(std::string const& valueXml, int* offset)
+ {
+ const char* valueStart = valueXml.c_str() + *offset;
+ char* valueEnd;
+ long ivalue = strtol(valueStart, &valueEnd, 10);
+ if (valueEnd == valueStart || (ivalue != 0 && ivalue != 1))
+ return false;
+
+ _type = TypeBoolean;
+ _value.asBool = (ivalue == 1);
+ *offset += int(valueEnd - valueStart);
+ return true;
+ }
+
+ std::string XmlRpcValue::boolToXml() const
+ {
+ std::string xml = VALUE_TAG;
+ xml += BOOLEAN_TAG;
+ xml += (_value.asBool ? "1" : "0");
+ xml += BOOLEAN_ETAG;
+ xml += VALUE_ETAG;
+ return xml;
+ }
+
+ // Int
+ bool XmlRpcValue::intFromXml(std::string const& valueXml, int* offset)
+ {
+ const char* valueStart = valueXml.c_str() + *offset;
+ char* valueEnd;
+ long ivalue = strtol(valueStart, &valueEnd, 10);
+ if (valueEnd == valueStart)
+ return false;
+
+ _type = TypeInt;
+ _value.asInt = int(ivalue);
+ *offset += int(valueEnd - valueStart);
+ return true;
+ }
+
+ std::string XmlRpcValue::intToXml() const
+ {
+ char buf[256];
+ snprintf(buf, sizeof(buf)-1, "%d", _value.asInt);
+ buf[sizeof(buf)-1] = 0;
+ std::string xml = VALUE_TAG;
+ xml += I4_TAG;
+ xml += buf;
+ xml += I4_ETAG;
+ xml += VALUE_ETAG;
+ return xml;
+ }
+
+ // Double
+ bool XmlRpcValue::doubleFromXml(std::string const& valueXml, int* offset)
+ {
+ const char* valueStart = valueXml.c_str() + *offset;
+ char* valueEnd;
+ double dvalue = strtod(valueStart, &valueEnd);
+ if (valueEnd == valueStart)
+ return false;
+
+ _type = TypeDouble;
+ _value.asDouble = dvalue;
+ *offset += int(valueEnd - valueStart);
+ return true;
+ }
+
+ std::string XmlRpcValue::doubleToXml() const
+ {
+ char buf[256];
+ // this was fixed for windows use (frauenberger@iem.at) 12.10.2004
+ snprintf(buf, sizeof(buf)-1, "%f" , _value.asDouble);
+ buf[sizeof(buf)-1] = 0;
+
+ std::string xml = VALUE_TAG;
+ xml += DOUBLE_TAG;
+ xml += buf;
+ xml += DOUBLE_ETAG;
+ xml += VALUE_ETAG;
+ return xml;
+ }
+
+ // String
+ bool XmlRpcValue::stringFromXml(std::string const& valueXml, int* offset)
+ {
+ size_t valueEnd = valueXml.find('<', *offset);
+ if (valueEnd == std::string::npos)
+ return false; // No end tag;
+
+ _type = TypeString;
+ _value.asString = new std::string(XmlRpcUtil::xmlDecode(valueXml.substr(*offset, valueEnd-*offset)));
+ *offset += int(_value.asString->length());
+ return true;
+ }
+
+ std::string XmlRpcValue::stringToXml() const
+ {
+ std::string xml = VALUE_TAG;
+ //xml += STRING_TAG; optional
+ xml += XmlRpcUtil::xmlEncode(*_value.asString);
+ //xml += STRING_ETAG;
+ xml += VALUE_ETAG;
+ return xml;
+ }
+
+ // DateTime (stored as a struct tm)
+ bool XmlRpcValue::timeFromXml(std::string const& valueXml, int* offset)
+ {
+ size_t valueEnd = valueXml.find('<', *offset);
+ if (valueEnd == std::string::npos)
+ return false; // No end tag;
+
+ std::string stime = valueXml.substr(*offset, valueEnd-*offset);
+
+ struct tm t;
+ if (sscanf(stime.c_str(),"%4d%2d%2dT%2d:%2d:%2d",&t.tm_year,&t.tm_mon,&t.tm_mday,&t.tm_hour,&t.tm_min,&t.tm_sec) != 6)
+ return false;
+
+ t.tm_isdst = -1;
+ _type = TypeDateTime;
+ _value.asTime = new struct tm(t);
+ *offset += int(stime.length());
+ return true;
+ }
+
+ std::string XmlRpcValue::timeToXml() const
+ {
+ struct tm* t = _value.asTime;
+ char buf[20];
+ snprintf(buf, sizeof(buf)-1, "%4d%02d%02dT%02d:%02d:%02d",
+ t->tm_year,t->tm_mon,t->tm_mday,t->tm_hour,t->tm_min,t->tm_sec);
+ buf[sizeof(buf)-1] = 0;
+
+ std::string xml = VALUE_TAG;
+ xml += DATETIME_TAG;
+ xml += buf;
+ xml += DATETIME_ETAG;
+ xml += VALUE_ETAG;
+ return xml;
+ }
+
+
+ // Base64
+ bool XmlRpcValue::binaryFromXml(std::string const& valueXml, int* offset)
+ {
+ size_t valueEnd = valueXml.find('<', *offset);
+ if (valueEnd == std::string::npos)
+ return false; // No end tag;
+
+ _type = TypeBase64;
+ std::string asString = valueXml.substr(*offset, valueEnd-*offset);
+ _value.asBinary = new BinaryData();
+ // check whether base64 encodings can contain chars xml encodes...
+
+ // convert from base64 to binary
+ int iostatus = 0;
+ base64<char> decoder;
+ std::back_insert_iterator<BinaryData> ins = std::back_inserter(*(_value.asBinary));
+ decoder.get(asString.begin(), asString.end(), ins, iostatus);
+
+ *offset += int(asString.length());
+ return true;
+ }
+
+
+ std::string XmlRpcValue::binaryToXml() const
+ {
+ // convert to base64
+ std::vector<char> base64data;
+ int iostatus = 0;
+ base64<char> encoder;
+ std::back_insert_iterator<std::vector<char> > ins = std::back_inserter(base64data);
+ encoder.put(_value.asBinary->begin(), _value.asBinary->end(), ins, iostatus, base64<>::crlf());
+
+ // Wrap with xml
+ std::string xml = VALUE_TAG;
+ xml += BASE64_TAG;
+ xml.append(base64data.begin(), base64data.end());
+ xml += BASE64_ETAG;
+ xml += VALUE_ETAG;
+ return xml;
+ }
+
+
+ // Array
+ bool XmlRpcValue::arrayFromXml(std::string const& valueXml, int* offset)
+ {
+ if ( ! XmlRpcUtil::nextTagIs(DATA_TAG, valueXml, offset))
+ return false;
+
+ _type = TypeArray;
+ _value.asArray = new ValueArray;
+ XmlRpcValue v;
+ while (v.fromXml(valueXml, offset))
+ _value.asArray->push_back(v); // copy...
+
+ // Skip the trailing </data>
+ (void) XmlRpcUtil::nextTagIs(DATA_ETAG, valueXml, offset);
+ return true;
+ }
+
+
+ // In general, its preferable to generate the xml of each element of the
+ // array as it is needed rather than glomming up one big string.
+ std::string XmlRpcValue::arrayToXml() const
+ {
+ std::string xml = VALUE_TAG;
+ xml += ARRAY_TAG;
+ xml += DATA_TAG;
+
+ int s = int(_value.asArray->size());
+ for (int i=0; i<s; ++i)
+ xml += _value.asArray->at(i).toXml();
+
+ xml += DATA_ETAG;
+ xml += ARRAY_ETAG;
+ xml += VALUE_ETAG;
+ return xml;
+ }
+
+
+ // Struct
+ bool XmlRpcValue::structFromXml(std::string const& valueXml, int* offset)
+ {
+ _type = TypeStruct;
+ _value.asStruct = new ValueStruct;
+
+ while (XmlRpcUtil::nextTagIs(MEMBER_TAG, valueXml, offset)) {
+ // name
+ const std::string name = XmlRpcUtil::parseTag(NAME_TAG, valueXml, offset);
+ // value
+ XmlRpcValue val(valueXml, offset);
+ if ( ! val.valid()) {
+ invalidate();
+ return false;
+ }
+ const std::pair<const std::string, XmlRpcValue> p(name, val);
+ _value.asStruct->insert(p);
+
+ (void) XmlRpcUtil::nextTagIs(MEMBER_ETAG, valueXml, offset);
+ }
+ return true;
+ }
+
+
+ // In general, its preferable to generate the xml of each element
+ // as it is needed rather than glomming up one big string.
+ std::string XmlRpcValue::structToXml() const
+ {
+ std::string xml = VALUE_TAG;
+ xml += STRUCT_TAG;
+
+ ValueStruct::const_iterator it;
+ for (it=_value.asStruct->begin(); it!=_value.asStruct->end(); ++it) {
+ xml += MEMBER_TAG;
+ xml += NAME_TAG;
+ xml += XmlRpcUtil::xmlEncode(it->first);
+ xml += NAME_ETAG;
+ xml += it->second.toXml();
+ xml += MEMBER_ETAG;
+ }
+
+ xml += STRUCT_ETAG;
+ xml += VALUE_ETAG;
+ return xml;
+ }
+
+
+
+ // Write the value without xml encoding it
+ std::ostream& XmlRpcValue::write(std::ostream& os) const {
+ switch (_type) {
+ default: break;
+ case TypeBoolean: os << _value.asBool; break;
+ case TypeInt: os << _value.asInt; break;
+ case TypeDouble: os << _value.asDouble; break;
+ case TypeString: os << *_value.asString; break;
+ case TypeDateTime:
+ {
+ struct tm* t = _value.asTime;
+ char buf[20];
+ snprintf(buf, sizeof(buf)-1, "%4d%02d%02dT%02d:%02d:%02d",
+ t->tm_year,t->tm_mon,t->tm_mday,t->tm_hour,t->tm_min,t->tm_sec);
+ buf[sizeof(buf)-1] = 0;
+ os << buf;
+ break;
+ }
+ case TypeBase64:
+ {
+ int iostatus = 0;
+ std::ostreambuf_iterator<char> out(os);
+ base64<char> encoder;
+ encoder.put(_value.asBinary->begin(), _value.asBinary->end(), out, iostatus, base64<>::crlf());
+ break;
+ }
+ case TypeArray:
+ {
+ int s = int(_value.asArray->size());
+ os << '{';
+ for (int i=0; i<s; ++i)
+ {
+ if (i > 0) os << ',';
+ _value.asArray->at(i).write(os);
+ }
+ os << '}';
+ break;
+ }
+ case TypeStruct:
+ {
+ os << '[';
+ ValueStruct::const_iterator it;
+ for (it=_value.asStruct->begin(); it!=_value.asStruct->end(); ++it)
+ {
+ if (it!=_value.asStruct->begin()) os << ',';
+ os << it->first << ':';
+ it->second.write(os);
+ }
+ os << ']';
+ break;
+ }
+
+ }
+
+ return os;
+ }
+
+} // namespace XmlRpc
+
+
+// ostream
+std::ostream& operator<<(std::ostream& os, XmlRpc::XmlRpcValue& v)
+{
+ // If you want to output in xml format:
+ //return os << v.toXml();
+ return v.write(os);
+}
+
diff --git a/xmlrpc++/src/XmlRpcValue.h b/xmlrpc++/src/XmlRpcValue.h
new file mode 100644
index 0000000..7535d4a
--- /dev/null
+++ b/xmlrpc++/src/XmlRpcValue.h
@@ -0,0 +1,189 @@
+
+#ifndef _XMLRPCVALUE_H_
+#define _XMLRPCVALUE_H_
+//
+// XmlRpc++ Copyright (c) 2002-2003 by Chris Morley
+//
+#if defined(_MSC_VER)
+# pragma warning(disable:4786) // identifier was truncated in debug info
+#endif
+
+#ifndef MAKEDEPEND
+# include <map>
+# include <string>
+# include <vector>
+# include <time.h>
+#endif
+
+namespace XmlRpc {
+
+ //! RPC method arguments and results are represented by Values
+ // should probably refcount them...
+ class XmlRpcValue {
+ public:
+
+
+ enum Type {
+ TypeInvalid,
+ TypeBoolean,
+ TypeInt,
+ TypeDouble,
+ TypeString,
+ TypeDateTime,
+ TypeBase64,
+ TypeArray,
+ TypeStruct
+ };
+
+ // Non-primitive types
+ typedef std::vector<char> BinaryData;
+ typedef std::vector<XmlRpcValue> ValueArray;
+ typedef std::map<std::string, XmlRpcValue> ValueStruct;
+
+
+ //! Constructors
+ XmlRpcValue() : _type(TypeInvalid) { _value.asBinary = 0; }
+ XmlRpcValue(bool value) : _type(TypeBoolean) { _value.asBool = value; }
+ XmlRpcValue(int value) : _type(TypeInt) { _value.asInt = value; }
+ XmlRpcValue(double value) : _type(TypeDouble) { _value.asDouble = value; }
+
+ XmlRpcValue(std::string const& value) : _type(TypeString)
+ { _value.asString = new std::string(value); }
+
+ XmlRpcValue(const char* value) : _type(TypeString)
+ { _value.asString = new std::string(value); }
+
+ XmlRpcValue(struct tm* value) : _type(TypeDateTime)
+ { _value.asTime = new struct tm(*value); }
+
+
+ XmlRpcValue(void* value, int nBytes) : _type(TypeBase64)
+ {
+ _value.asBinary = new BinaryData((char*)value, ((char*)value)+nBytes);
+ }
+
+ //! Construct from xml, beginning at *offset chars into the string, updates offset
+ XmlRpcValue(std::string const& xml, int* offset) : _type(TypeInvalid)
+ { if ( ! fromXml(xml,offset)) _type = TypeInvalid; }
+
+ //! Copy
+ XmlRpcValue(XmlRpcValue const& rhs) : _type(TypeInvalid) { *this = rhs; }
+
+ //! Destructor (make virtual if you want to subclass)
+ /*virtual*/ ~XmlRpcValue() { invalidate(); }
+
+ //! Erase the current value
+ void clear() { invalidate(); }
+
+ // Operators
+ XmlRpcValue& operator=(XmlRpcValue const& rhs);
+ XmlRpcValue& operator=(int const& rhs) { return operator=(XmlRpcValue(rhs)); }
+ XmlRpcValue& operator=(double const& rhs) { return operator=(XmlRpcValue(rhs)); }
+ XmlRpcValue& operator=(const char* rhs) { return operator=(XmlRpcValue(std::string(rhs))); }
+
+ bool operator==(XmlRpcValue const& other) const;
+ bool operator!=(XmlRpcValue const& other) const;
+
+ operator bool&() { assertTypeOrInvalid(TypeBoolean); return _value.asBool; }
+ operator int&() { assertTypeOrInvalid(TypeInt); return _value.asInt; }
+ operator double&() { assertTypeOrInvalid(TypeDouble); return _value.asDouble; }
+ operator std::string&() { assertTypeOrInvalid(TypeString); return *_value.asString; }
+ operator BinaryData&() { assertTypeOrInvalid(TypeBase64); return *_value.asBinary; }
+ operator struct tm&() { assertTypeOrInvalid(TypeDateTime); return *_value.asTime; }
+
+ XmlRpcValue const& operator[](int i) const { assertArray(i+1); return _value.asArray->at(i); }
+ XmlRpcValue& operator[](int i) { assertArray(i+1); return _value.asArray->at(i); }
+
+ XmlRpcValue& operator[](std::string const& k) { assertStruct(); return (*_value.asStruct)[k]; }
+ XmlRpcValue& operator[](const char* k) { assertStruct(); std::string s(k); return (*_value.asStruct)[s]; }
+
+ // Accessors
+ //! Return true if the value has been set to something.
+ bool valid() const { return _type != TypeInvalid; }
+
+ //! Return the type of the value stored. \see Type.
+ Type const &getType() const { return _type; }
+
+ //! Return the size for string, base64, array, and struct values.
+ int size() const;
+
+ //! Specify the size for array values. Array values will grow beyond this size if needed.
+ void setSize(int size) { assertArray(size); }
+
+ //! Check for the existence of a struct member by name.
+ bool hasMember(const std::string& name) const;
+
+ //! Decode xml. Destroys any existing value.
+ bool fromXml(std::string const& valueXml, int* offset);
+
+ //! Encode the Value in xml
+ std::string toXml() const;
+
+ //! Write the value (no xml encoding)
+ std::ostream& write(std::ostream& os) const;
+
+ // Formatting
+ //! Return the format used to write double values.
+ static std::string const& getDoubleFormat() { return _doubleFormat; }
+
+ //! Specify the format used to write double values.
+ static void setDoubleFormat(const char* f) { _doubleFormat = f; }
+
+
+ protected:
+ // Clean up
+ void invalidate();
+
+ // Type checking
+ void assertTypeOrInvalid(Type t);
+ void assertArray(int size) const;
+ void assertArray(int size);
+ void assertStruct();
+
+ // XML decoding
+ bool boolFromXml(std::string const& valueXml, int* offset);
+ bool intFromXml(std::string const& valueXml, int* offset);
+ bool doubleFromXml(std::string const& valueXml, int* offset);
+ bool stringFromXml(std::string const& valueXml, int* offset);
+ bool timeFromXml(std::string const& valueXml, int* offset);
+ bool binaryFromXml(std::string const& valueXml, int* offset);
+ bool arrayFromXml(std::string const& valueXml, int* offset);
+ bool structFromXml(std::string const& valueXml, int* offset);
+
+ // XML encoding
+ std::string boolToXml() const;
+ std::string intToXml() const;
+ std::string doubleToXml() const;
+ std::string stringToXml() const;
+ std::string timeToXml() const;
+ std::string binaryToXml() const;
+ std::string arrayToXml() const;
+ std::string structToXml() const;
+
+ // Format strings
+ static std::string _doubleFormat;
+
+ // Type tag and values
+ Type _type;
+
+ // At some point I will split off Arrays and Structs into
+ // separate ref-counted objects for more efficient copying.
+ union {
+ bool asBool;
+ int asInt;
+ double asDouble;
+ struct tm* asTime;
+ std::string* asString;
+ BinaryData* asBinary;
+ ValueArray* asArray;
+ ValueStruct* asStruct;
+ } _value;
+
+ };
+} // namespace XmlRpc
+
+
+std::ostream& operator<<(std::ostream& os, XmlRpc::XmlRpcValue& v);
+
+
+#endif // _XMLRPCVALUE_H_
diff --git a/xmlrpc++/src/base64.h b/xmlrpc++/src/base64.h
new file mode 100644
index 0000000..519ee0f
--- /dev/null
+++ b/xmlrpc++/src/base64.h
@@ -0,0 +1,379 @@
+
+
+// base64.hpp
+// Autor Konstantin Pilipchuk
+// mailto:lostd@ukr.net
+//
+//
+
+#if !defined(__BASE64_H_INCLUDED__)
+#define __BASE64_H_INCLUDED__ 1
+
+#ifndef MAKEDEPEND
+# include <iterator>
+#endif
+
+static
+int _base64Chars[]= {'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
+ 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
+ '0','1','2','3','4','5','6','7','8','9',
+ '+','/' };
+
+
+#define _0000_0011 0x03
+#define _1111_1100 0xFC
+#define _1111_0000 0xF0
+#define _0011_0000 0x30
+#define _0011_1100 0x3C
+#define _0000_1111 0x0F
+#define _1100_0000 0xC0
+#define _0011_1111 0x3F
+
+#define _EQUAL_CHAR (-1)
+#define _UNKNOWN_CHAR (-2)
+
+#define _IOS_FAILBIT std::ios_base::failbit
+#define _IOS_EOFBIT std::ios_base::eofbit
+#define _IOS_BADBIT std::ios_base::badbit
+#define _IOS_GOODBIT std::ios_base::goodbit
+
+// TEMPLATE CLASS base64_put
+template<class _E = char, class _Tr = std::char_traits<_E> >
+class base64
+{
+public:
+
+ typedef unsigned char byte_t;
+ typedef _E char_type;
+ typedef _Tr traits_type;
+
+ // base64 requires max line length <= 72 characters
+ // you can fill end of line
+ // it may be crlf, crlfsp, noline or other class like it
+
+
+ struct crlf
+ {
+ template<class _OI>
+ _OI operator()(_OI _To) const{
+ *_To = _Tr::to_char_type('\r'); ++_To;
+ *_To = _Tr::to_char_type('\n'); ++_To;
+
+ return (_To);
+ }
+ };
+
+
+ struct crlfsp
+ {
+ template<class _OI>
+ _OI operator()(_OI _To) const{
+ *_To = _Tr::to_char_type('\r'); ++_To;
+ *_To = _Tr::to_char_type('\n'); ++_To;
+ *_To = _Tr::to_char_type(' '); ++_To;
+
+ return (_To);
+ }
+ };
+
+ struct noline
+ {
+ template<class _OI>
+ _OI operator()(_OI _To) const{
+ return (_To);
+ }
+ };
+
+ struct three2four
+ {
+ void zero()
+ {
+ _data[0] = 0;
+ _data[1] = 0;
+ _data[2] = 0;
+ }
+
+ byte_t get_0() const
+ {
+ return _data[0];
+ }
+ byte_t get_1() const
+ {
+ return _data[1];
+ }
+ byte_t get_2() const
+ {
+ return _data[2];
+ }
+
+ void set_0(byte_t _ch)
+ {
+ _data[0] = _ch;
+ }
+
+ void set_1(byte_t _ch)
+ {
+ _data[1] = _ch;
+ }
+
+ void set_2(byte_t _ch)
+ {
+ _data[2] = _ch;
+ }
+
+ // 0000 0000 1111 1111 2222 2222
+ // xxxx xxxx xxxx xxxx xxxx xxxx
+ // 0000 0011 1111 2222 2233 3333
+
+ int b64_0() const {return (_data[0] & _1111_1100) >> 2;}
+ int b64_1() const {return ((_data[0] & _0000_0011) << 4) + ((_data[1] & _1111_0000)>>4);}
+ int b64_2() const {return ((_data[1] & _0000_1111) << 2) + ((_data[2] & _1100_0000)>>6);}
+ int b64_3() const {return (_data[2] & _0011_1111);}
+
+ void b64_0(int _ch) {_data[0] = ((_ch & _0011_1111) << 2) | (_0000_0011 & _data[0]);}
+
+ void b64_1(int _ch) {
+ _data[0] = ((_ch & _0011_0000) >> 4) | (_1111_1100 & _data[0]);
+ _data[1] = ((_ch & _0000_1111) << 4) | (_0000_1111 & _data[1]); }
+
+ void b64_2(int _ch) {
+ _data[1] = ((_ch & _0011_1100) >> 2) | (_1111_0000 & _data[1]);
+ _data[2] = ((_ch & _0000_0011) << 6) | (_0011_1111 & _data[2]); }
+
+ void b64_3(int _ch){
+ _data[2] = (_ch & _0011_1111) | (_1100_0000 & _data[2]);}
+
+ private:
+ byte_t _data[3];
+
+ };
+
+
+
+
+ template<class _II, class _OI, class _State, class _Endline>
+ _II put(_II _First, _II _Last, _OI _To, _State& _St, _Endline _Endl) const
+ {
+ three2four _3to4;
+ int line_octets = 0;
+
+ while(_First != _Last)
+ {
+ _3to4.zero();
+
+ // 3
+ _3to4.set_0(*_First);
+ _First++;
+
+ if(_First == _Last)
+ {
+ *_To = _Tr::to_char_type(_base64Chars[_3to4.b64_0()]); ++_To;
+ *_To = _Tr::to_char_type(_base64Chars[_3to4.b64_1()]); ++_To;
+ *_To = _Tr::to_char_type('='); ++_To;
+ *_To = _Tr::to_char_type('='); ++_To;
+ goto __end;
+ }
+
+ _3to4.set_1(*_First);
+ _First++;
+
+ if(_First == _Last)
+ {
+ *_To = _Tr::to_char_type(_base64Chars[_3to4.b64_0()]); ++_To;
+ *_To = _Tr::to_char_type(_base64Chars[_3to4.b64_1()]); ++_To;
+ *_To = _Tr::to_char_type(_base64Chars[_3to4.b64_2()]); ++_To;
+ *_To = _Tr::to_char_type('='); ++_To;
+ goto __end;
+ }
+
+ _3to4.set_2(*_First);
+ _First++;
+
+ *_To = _Tr::to_char_type(_base64Chars[_3to4.b64_0()]); ++_To;
+ *_To = _Tr::to_char_type(_base64Chars[_3to4.b64_1()]); ++_To;
+ *_To = _Tr::to_char_type(_base64Chars[_3to4.b64_2()]); ++_To;
+ *_To = _Tr::to_char_type(_base64Chars[_3to4.b64_3()]); ++_To;
+
+ if(line_octets == 17) // base64 72
+ {
+ //_To = _Endl(_To);
+ *_To = '\n'; ++_To;
+ line_octets = 0;
+ }
+ else
+ ++line_octets;
+ }
+
+ __end: ;
+
+ return (_First);
+
+ }
+
+
+ template<class _II, class _OI, class _State>
+ _II get(_II _First, _II _Last, _OI _To, _State& _St) const
+ {
+ three2four _3to4;
+ int _Char;
+
+ while(_First != _Last)
+ {
+
+ // Take octet
+ _3to4.zero();
+
+ // -- 0 --
+ // Search next valid char...
+ while((_Char = _getCharType(*_First)) < 0 && _Char == _UNKNOWN_CHAR)
+ {
+ if(++_First == _Last)
+ {
+ _St |= _IOS_FAILBIT|_IOS_EOFBIT; return _First; // unexpected EOF
+ }
+ }
+
+ if(_Char == _EQUAL_CHAR){
+ // Error! First character in octet can't be '='
+ _St |= _IOS_FAILBIT;
+ return _First;
+ }
+ else
+ _3to4.b64_0(_Char);
+
+
+ // -- 1 --
+ // Search next valid char...
+ while(++_First != _Last)
+ if((_Char = _getCharType(*_First)) != _UNKNOWN_CHAR)
+ break;
+
+ if(_First == _Last) {
+ _St |= _IOS_FAILBIT|_IOS_EOFBIT; // unexpected EOF
+ return _First;
+ }
+
+ if(_Char == _EQUAL_CHAR){
+ // Error! Second character in octet can't be '='
+ _St |= _IOS_FAILBIT;
+ return _First;
+ }
+ else
+ _3to4.b64_1(_Char);
+
+
+ // -- 2 --
+ // Search next valid char...
+ while(++_First != _Last)
+ if((_Char = _getCharType(*_First)) != _UNKNOWN_CHAR)
+ break;
+
+ if(_First == _Last) {
+ // Error! Unexpected EOF. Must be '=' or base64 character
+ _St |= _IOS_FAILBIT|_IOS_EOFBIT;
+ return _First;
+ }
+
+ if(_Char == _EQUAL_CHAR){
+ // OK!
+ _3to4.b64_2(0);
+ _3to4.b64_3(0);
+
+ // chek for EOF
+ if(++_First == _Last)
+ {
+ // Error! Unexpected EOF. Must be '='. Ignore it.
+ //_St |= _IOS_BADBIT|_IOS_EOFBIT;
+ _St |= _IOS_EOFBIT;
+ }
+ else
+ if(_getCharType(*_First) != _EQUAL_CHAR)
+ {
+ // Error! Must be '='. Ignore it.
+ //_St |= _IOS_BADBIT;
+ }
+ else
+ ++_First; // Skip '='
+
+ // write 1 byte to output
+ *_To = (byte_t) _3to4.get_0();
+ return _First;
+ }
+ else
+ _3to4.b64_2(_Char);
+
+
+ // -- 3 --
+ // Search next valid char...
+ while(++_First != _Last)
+ if((_Char = _getCharType(*_First)) != _UNKNOWN_CHAR)
+ break;
+
+ if(_First == _Last) {
+ // Unexpected EOF. It's error. But ignore it.
+ //_St |= _IOS_FAILBIT|_IOS_EOFBIT;
+ _St |= _IOS_EOFBIT;
+
+ return _First;
+ }
+
+ if(_Char == _EQUAL_CHAR)
+ {
+ // OK!
+ _3to4.b64_3(0);
+
+ // write to output 2 bytes
+ *_To = (byte_t) _3to4.get_0();
+ *_To = (byte_t) _3to4.get_1();
+
+ ++_First; // set position to next character
+
+ return _First;
+ }
+ else
+ _3to4.b64_3(_Char);
+
+
+ // write to output 3 bytes
+ *_To = (byte_t) _3to4.get_0();
+ *_To = (byte_t) _3to4.get_1();
+ *_To = (byte_t) _3to4.get_2();
+
+ ++_First;
+
+
+ } // while(_First != _Last)
+
+ return (_First);
+ }
+
+protected:
+
+ int _getCharType(int _Ch) const
+ {
+ if(_base64Chars[62] == _Ch)
+ return 62;
+
+ if(_base64Chars[63] == _Ch)
+ return 63;
+
+ if((_base64Chars[0] <= _Ch) && (_base64Chars[25] >= _Ch))
+ return _Ch - _base64Chars[0];
+
+ if((_base64Chars[26] <= _Ch) && (_base64Chars[51] >= _Ch))
+ return _Ch - _base64Chars[26] + 26;
+
+ if((_base64Chars[52] <= _Ch) && (_base64Chars[61] >= _Ch))
+ return _Ch - _base64Chars[52] + 52;
+
+ if(_Ch == _Tr::to_int_type('='))
+ return _EQUAL_CHAR;
+
+ return _UNKNOWN_CHAR;
+ }
+
+
+};
+
+
+#endif
diff --git a/xmlrpc-init.pd b/xmlrpc-init.pd
new file mode 100644
index 0000000..d92b05f
--- /dev/null
+++ b/xmlrpc-init.pd
@@ -0,0 +1,12 @@
+#N canvas 33 240 529 222 10;
+#X obj 19 115 xmlrpc 8000;
+#X text 21 68 XMLRPC configuration;
+#X text 18 83 (this object can be destroyed again once it has been
+created);
+#X obj 11 10 cnv 15 500 40 empty empty xmlrpc 10 22 0 24 -260818 -1
+0;
+#X text 148 14 xmlrpc external for PD \, author: Thomas Grill;
+#X text 144 31 (C)2003 IEM \, Graz;
+#X obj 21 180 netreceive;
+#X text 25 144 For Windows user a dummy netreceive object MUST be present
+Otherwise \, Pd uses 99% CPU power when invoked with -nogui;
diff --git a/xmlrpc-test.pd b/xmlrpc-test.pd
new file mode 100644
index 0000000..4eb0acd
--- /dev/null
+++ b/xmlrpc-test.pd
@@ -0,0 +1,31 @@
+#N canvas 33 240 600 168 10;
+#X floatatom 19 126 5 0 0 0 - - -;
+#X text 19 66 some receivers;
+#X text 232 64 some senders;
+#X floatatom 234 92 5 0 0 0 - - -;
+#X obj 19 91 r recv1;
+#X obj 94 91 r recv2;
+#X obj 234 122 s send1;
+#X obj 327 123 s send2;
+#X msg 316 91 a b;
+#X msg 354 91 1 2 3 hula;
+#X obj 469 107 env~;
+#X obj 469 130 s send3;
+#X floatatom 504 107 5 0 0 0 - - -;
+#X obj 469 84 osc~ 0.1;
+#X obj 93 123 print PD;
+#X obj 11 10 cnv 15 500 40 empty empty xmlrpc 10 22 0 24 -260818 -1
+0;
+#X text 146 12 xmlrpc external for PD \, author: Thomas Grill;
+#X text 142 31 (C)2003 IEM \, Graz;
+#X obj 526 10 loadbang;
+#X msg 526 37 \; pd dsp 1;
+#X connect 3 0 6 0;
+#X connect 4 0 0 0;
+#X connect 5 0 14 0;
+#X connect 8 0 7 0;
+#X connect 9 0 7 0;
+#X connect 10 0 11 0;
+#X connect 10 0 12 0;
+#X connect 13 0 10 0;
+#X connect 18 0 19 0;
diff --git a/xmlrpc-test.py b/xmlrpc-test.py
new file mode 100644
index 0000000..92f8ced
--- /dev/null
+++ b/xmlrpc-test.py
@@ -0,0 +1,75 @@
+# testprogramm
+#* Author: Thomas Grill t.grill [at] gmx.net
+# License LGPL see LICENSE.txt
+# IEM - Institute of Electronic Music and Acoustics, Graz
+# Inffeldgasse 10/3, 8010 Graz, Austria
+# http://iem.at
+#************************************************************/
+# --- import some functions ---
+
+import xmlrpclib
+import time
+import sys
+
+# --- connect to external ---
+
+s = xmlrpclib.ServerProxy("http://localhost:8000")
+
+# --- load patch ----
+
+if len(sys.argv) >= 2:
+ patchname = sys.argv[1]
+else:
+ # defaulting
+ patchname = 'xmlrpc-test.pd'
+
+print "Loading file:",patchname
+
+# open PD patch as file
+patch=open(patchname,'r')
+
+# read all lines of patch
+lines=patch.readlines()
+
+# function to concatenate two lines
+def concat(l,b):
+ if b[0] != "#":
+ l[len(l)-1] = l[len(l)-1]+b
+ else:
+ return l.append(b)
+
+# add all lines that don't begin with # to their predecendants
+# this is necessary for objects with many parameters (e.g. IEM GUI objects)
+clines = []
+for l in lines:
+ concat(clines,l)
+
+# send it to the external
+s.load(clines)
+
+# close file
+patch.close()
+
+# --- send some data ---
+
+s.send("recv1",4)
+s.send("recv2",[1,2,3,"df"])
+
+# --- receive some data ---
+
+# bind to a PD symbol
+s.bind("send3")
+
+# get the value
+print "Got: ", s.query("send3")
+
+# unbind again (only necessary to save PD resources)
+s.unbind("send3")
+
+# --- wait a bit ---
+
+time.sleep(2)
+
+# --- close our PD test patch ---
+
+s.close()
diff --git a/xmlrpc.dsp b/xmlrpc.dsp
new file mode 100644
index 0000000..a2c693d
--- /dev/null
+++ b/xmlrpc.dsp
@@ -0,0 +1,96 @@
+# Microsoft Developer Studio Project File - Name="xmlrpc" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** NICHT BEARBEITEN **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=xmlrpc - Win32 Debug
+!MESSAGE Dies ist kein gltiges Makefile. Zum Erstellen dieses Projekts mit NMAKE
+!MESSAGE verwenden Sie den Befehl "Makefile exportieren" und fhren Sie den Befehl
+!MESSAGE
+!MESSAGE NMAKE /f "xmlrpc.mak".
+!MESSAGE
+!MESSAGE Sie knnen beim Ausfhren von NMAKE eine Konfiguration angeben
+!MESSAGE durch Definieren des Makros CFG in der Befehlszeile. Zum Beispiel:
+!MESSAGE
+!MESSAGE NMAKE /f "xmlrpc.mak" CFG="xmlrpc - Win32 Debug"
+!MESSAGE
+!MESSAGE Fr die Konfiguration stehen zur Auswahl:
+!MESSAGE
+!MESSAGE "xmlrpc - Win32 Release" (basierend auf "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "xmlrpc - Win32 Debug" (basierend auf "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName "xmlrpc"
+# PROP Scc_LocalPath "."
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "xmlrpc - 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 /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "XMLRPC_EXPORTS" /YX /FD /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /I "c:\programme\audio\pd\src" /I "../../xmlrpc++/src" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "XMLRPC_EXPORTS" /D "NT" /YX /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0xc07 /d "NDEBUG"
+# ADD RSC /l 0xc07 /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 pd.lib pthreadVC.lib Ws2_32.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 /libpath:"c:\programme\audio\pd\bin"
+
+!ELSEIF "$(CFG)" == "xmlrpc - 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 /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 "d:\pd\src" /I "../../xmlrpc++/src" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "XMLRPC_EXPORTS" /D "NT" /FR /YX /FD /GZ /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0xc07 /d "_DEBUG"
+# ADD RSC /l 0xc07 /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 pd.lib pthreadVC.lib Ws2_32.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 xmlrpc.lib /nologo /entry:"xmlrpc_setup" /dll /debug /machine:I386 /pdbtype:sept /libpath:"d:\pd\bin" /libpath:"..\..\xmlrpc++"
+# SUBTRACT LINK32 /pdb:none
+
+!ENDIF
+
+# Begin Target
+
+# Name "xmlrpc - Win32 Release"
+# Name "xmlrpc - Win32 Debug"
+# Begin Source File
+
+SOURCE=.\main.cpp
+# End Source File
+# End Target
+# End Project
diff --git a/xmlrpc.dsw b/xmlrpc.dsw
new file mode 100644
index 0000000..fb7f779
--- /dev/null
+++ b/xmlrpc.dsw
@@ -0,0 +1,29 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNUNG: DIESE ARBEITSBEREICHSDATEI DARF NICHT BEARBEITET ODER GELSCHT WERDEN!
+
+###############################################################################
+
+Project: "xmlrpc"=.\xmlrpc.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/xmlrpc.vcproj b/xmlrpc.vcproj
new file mode 100644
index 0000000..e10efbf
--- /dev/null
+++ b/xmlrpc.vcproj
@@ -0,0 +1,177 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.10"
+ Name="xmlrpc"
+ ProjectGUID="{824ADDB6-50B8-4019-8943-DFFAB0C0291D}"
+ SccProjectName="xmlrpc"
+ SccAuxPath=""
+ SccLocalPath="."
+ SccProvider="MSSCCI:Jalindi Igloo">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory=".\Debug"
+ IntermediateDirectory=".\Debug"
+ ConfigurationType="2"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="f:\prog\pd\pd-cvs\src,F:\prog\packs\pthreads,../../xmlrpc++/src"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;XMLRPC_EXPORTS;NT"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderFile=".\Debug/xmlrpc.pch"
+ AssemblerListingLocation=".\Debug/"
+ ObjectFile=".\Debug/"
+ ProgramDataBaseFileName=".\Debug/"
+ BrowseInformation="1"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="4"
+ CompileAs="0"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="pthreadVC.lib Ws2_32.lib "
+ OutputFile=".\Debug/xmlrpc.dll"
+ LinkIncremental="1"
+ SuppressStartupBanner="TRUE"
+ AdditionalLibraryDirectories="f:\prog\pd\pd-cvs\bin;f:\prog\packs\pthreads"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile=".\Debug/xmlrpc.pdb"
+ ImportLibrary=".\Debug/xmlrpc.lib"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="_DEBUG"
+ MkTypLibCompatible="TRUE"
+ SuppressStartupBanner="TRUE"
+ TargetEnvironment="1"
+ TypeLibraryName=".\Debug/xmlrpc.tlb"
+ HeaderFileName=""/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="3079"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory=".\Release"
+ IntermediateDirectory=".\Release"
+ ConfigurationType="2"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ InlineFunctionExpansion="1"
+ AdditionalIncludeDirectories="c:\programme\audio\pd\src,../../xmlrpc++/src"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;XMLRPC_EXPORTS;NT"
+ StringPooling="TRUE"
+ RuntimeLibrary="0"
+ EnableFunctionLevelLinking="TRUE"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderFile=".\Release/xmlrpc.pch"
+ AssemblerListingLocation=".\Release/"
+ ObjectFile=".\Release/"
+ ProgramDataBaseFileName=".\Release/"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ CompileAs="0"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies=" pthreadVC.lib Ws2_32.lib"
+ OutputFile=".\Release/xmlrpc.dll"
+ LinkIncremental="1"
+ SuppressStartupBanner="TRUE"
+ AdditionalLibraryDirectories="c:\programme\audio\pd\bin"
+ ProgramDatabaseFile=".\Release/xmlrpc.pdb"
+ ImportLibrary=".\Release/xmlrpc.lib"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="NDEBUG"
+ MkTypLibCompatible="TRUE"
+ SuppressStartupBanner="TRUE"
+ TargetEnvironment="1"
+ TypeLibraryName=".\Release/xmlrpc.tlb"
+ HeaderFileName=""/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="3079"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <File
+ RelativePath="main.cpp">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;XMLRPC_EXPORTS;NT;$(NoInherit)"
+ BasicRuntimeChecks="3"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;XMLRPC_EXPORTS;NT;$(NoInherit)"/>
+ </FileConfiguration>
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>