Merge branch 'master' of git@github.com:sustrik/zeromq2

This commit is contained in:
malosek 2009-09-15 09:44:44 +02:00
commit 364281343c
27 changed files with 4218 additions and 163 deletions

View File

@ -14,8 +14,8 @@ if BUILD_PERF
DIR_PERF = perf
endif
SUBDIRS = src $(DIR_P) $(DIR_R) $(DIR_J) $(DIR_PERF)
DIST_SUBDIRS = src python ruby java perf
SUBDIRS = src $(DIR_P) $(DIR_R) $(DIR_J) $(DIR_PERF) devices
DIST_SUBDIRS = src python ruby java perf devices
EXTRA_DIST = $(top_srcdir)/foreign/openpgm/@pgm_basename@.tar.bz2

25
c/zmq.h
View File

@ -44,16 +44,15 @@ extern "C" {
#define ZMQ_VSM 32
// Socket options.
#define ZMQ_HWM 1
#define ZMQ_LWM 2
#define ZMQ_SWAP 3
#define ZMQ_MASK 4
#define ZMQ_AFFINITY 5
#define ZMQ_IDENTITY 6
#define ZMQ_SUBSCRIBE 7
#define ZMQ_UNSUBSCRIBE 8
#define ZMQ_RATE 9
#define ZMQ_RECOVERY_IVL 10
#define ZMQ_HWM 1 // int64_t
#define ZMQ_LWM 2 // int64_t
#define ZMQ_SWAP 3 // int64_t
#define ZMQ_AFFINITY 4 // int64_t
#define ZMQ_IDENTITY 5 // string
#define ZMQ_SUBSCRIBE 6 // string
#define ZMQ_UNSUBSCRIBE 7 // string
#define ZMQ_RATE 8 // int64_t
#define ZMQ_RECOVERY_IVL 9 // int64_t
// The operation should be performed in non-blocking mode. I.e. if it cannot
// be processed immediately, error should be returned with errno set to EAGAIN.
@ -186,12 +185,12 @@ ZMQ_EXPORT int zmq_connect (void *s, const char *addr);
//
// Errors: EAGAIN - message cannot be sent at the moment (applies only to
// non-blocking send).
// ENOTSUP - function isn't supported by particular socket type.
// EFAULT - function isn't supported by particular socket type.
ZMQ_EXPORT int zmq_send (void *s, struct zmq_msg_t *msg, int flags);
// Flush the messages that were send using ZMQ_NOFLUSH flag down the stream.
//
// Errors: ENOTSUP - function isn't supported by particular socket type.
// Errors: FAULT - function isn't supported by particular socket type.
ZMQ_EXPORT int zmq_flush (void *s);
// Send a message from the socket 's'. 'flags' argument can be combination
@ -200,7 +199,7 @@ ZMQ_EXPORT int zmq_flush (void *s);
//
// Errors: EAGAIN - message cannot be received at the moment (applies only to
// non-blocking receive).
// ENOTSUP - function isn't supported by particular socket type.
// EFAULT - function isn't supported by particular socket type.
ZMQ_EXPORT int zmq_recv (void *s, struct zmq_msg_t *msg, int flags);
// Helper functions used by perf tests so that they don't have to care

View File

@ -441,6 +441,16 @@ if test "x$with_pgm_ext" != "xno"; then
pgm_ext="yes"
fi
# forwarder device
forwarder="no"
AC_ARG_WITH([forwarder], [AS_HELP_STRING([--with-forwarder],
[build forwarder device [default=no]])], [with_forwarder=yes], [with_forwarder=no])
if test "x$with_forwarder" != "xno"; then
forwarder="yes"
fi
# Perf
perf="no"
AC_ARG_WITH([perf], [AS_HELP_STRING([--with-perf],
@ -462,6 +472,7 @@ AM_CONDITIONAL(BUILD_RUBY, test "x$rbzmq" = "xyes")
AM_CONDITIONAL(BUILD_C, test "x$czmq" = "xyes")
AM_CONDITIONAL(BUILD_CPP, test "x$cppzmq" = "xyes")
AM_CONDITIONAL(BUILD_PGM, test "x$pgm_ext" = "xyes")
AM_CONDITIONAL(BUILD_FORWARDER, test "x$forwarder" = "xyes")
AM_CONDITIONAL(BUILD_PERF, test "x$perf" = "xyes")
AC_SUBST(stdint)
@ -479,7 +490,8 @@ AC_CHECK_FUNCS(perror gettimeofday memset socket getifaddrs freeifaddrs)
AC_OUTPUT(Makefile src/Makefile python/Makefile python/setup.py ruby/Makefile \
java/Makefile perf/Makefile perf/c/Makefile perf/cpp/Makefile \
perf/python/Makefile perf/ruby/Makefile perf/java/Makefile src/libzmq.pc)
perf/python/Makefile perf/ruby/Makefile perf/java/Makefile src/libzmq.pc \
devices/Makefile devices/forwarder/Makefile)
AC_MSG_RESULT([])
AC_MSG_RESULT([ ******************************************************** ])
@ -492,19 +504,26 @@ AC_MSG_RESULT([ license text. ])
AC_MSG_RESULT([ ******************************************************** ])
AC_MSG_RESULT([])
AC_MSG_RESULT([ 0MQ install dir: $prefix])
AC_MSG_RESULT([ C language binding: $czmq])
AC_MSG_RESULT([ C++ language binding: $cppzmq])
AC_MSG_RESULT([ Python language binding: $pyzmq])
AC_MSG_RESULT([ Ruby language binding: $rbzmq])
AC_MSG_RESULT([ Language bindings:])
AC_MSG_RESULT([ C: $czmq])
AC_MSG_RESULT([ C++: $cppzmq])
AC_MSG_RESULT([ Java: $jzmq])
AC_MSG_RESULT([ Python: $pyzmq])
AC_MSG_RESULT([ Ruby: $rbzmq])
if test "x$rbzmq" = "xyes"; then
AC_MSG_RESULT([ Ruby library install dir: $rubydir])
AC_MSG_RESULT([ Ruby library install dir: $rubydir])
fi
AC_MSG_RESULT([ Java language binding: $jzmq])
AC_MSG_RESULT([ Network protocols:])
AC_MSG_RESULT([ TCP: yes])
if test "x$pgm_ext" = "xyes"; then
AC_MSG_RESULT([ PGM extension: $pgm_ext ($pgm_name)])
AC_MSG_RESULT([ PGM: $pgm_ext ($pgm_name)])
else
AC_MSG_RESULT([ PGM extension: $pgm_ext])
AC_MSG_RESULT([ PGM: $pgm_ext])
fi
AC_MSG_RESULT([ performance tests: $perf])
AC_MSG_RESULT([ Devices:])
AC_MSG_RESULT([ forwarder: $forwarder])
AC_MSG_RESULT([ Performance tests: $perf])
AC_MSG_RESULT([])
AC_MSG_RESULT([ ******************************************************** ])
AC_MSG_RESULT([])

6
devices/Makefile.am Normal file
View File

@ -0,0 +1,6 @@
if BUILD_FORWARDER
FORWARDER_DIR = forwarder
endif
SUBDIRS = $(FORWARDER_DIR)
DIST_SUBDIRS = forwarder

View File

@ -0,0 +1,9 @@
INCLUDES = -I$(top_builddir)/c -I$(top_builddir)/cpp
bin_PROGRAMS = forwarder
forwarder_LDADD = $(top_builddir)/src/libzmq.la
forwarder_SOURCES = forwarder.cpp
forwarder_CXXFLAGS = -Wall -pedantic -Werror

View File

@ -0,0 +1,122 @@
/*
Copyright (c) 2007-2009 FastMQ Inc.
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the Lesser GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ 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
Lesser GNU General Public License for more details.
You should have received a copy of the Lesser GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "../../cpp/zmq.hpp"
#include "../../foreign/xmlParser/xmlParser.cpp"
int main (int argc, char *argv [])
{
if (argc != 2) {
fprintf (stderr, "usage: forwarder <config-file>\n");
return 1;
}
XMLNode root = XMLNode::parseFile (argv [1]);
if (root.isEmpty ()) {
fprintf (stderr, "configuration file not found\n");
return 1;
}
if (strcmp (root.getName (), "forwarder") != 0) {
fprintf (stderr, "root element in the configuration file should be "
"named 'forwarder'\n");
return 1;
}
XMLNode in_node = root.getChildNode ("in");
if (in_node.isEmpty ()) {
fprintf (stderr, "'in' node is missing in the configuration file\n");
return 1;
}
XMLNode out_node = root.getChildNode ("out");
if (out_node.isEmpty ()) {
fprintf (stderr, "'out' node is missing in the configuration file\n");
return 1;
}
// TODO: make the number of I/O threads configurable.
zmq::context_t ctx (1, 1);
zmq::socket_t in_socket (ctx, ZMQ_P2P);
zmq::socket_t out_socket (ctx, ZMQ_P2P);
int n = 0;
while (true) {
XMLNode bind = in_node.getChildNode ("bind", n);
if (bind.isEmpty ())
break;
const char *addr = bind.getAttribute ("addr");
if (!addr) {
fprintf (stderr, "'bind' node is missing 'addr' attribute\n");
return 1;
}
in_socket.bind (addr);
n++;
}
n = 0;
while (true) {
XMLNode connect = in_node.getChildNode ("connect", n);
if (connect.isEmpty ())
break;
const char *addr = connect.getAttribute ("addr");
if (!addr) {
fprintf (stderr, "'connect' node is missing 'addr' attribute\n");
return 1;
}
in_socket.connect (addr);
n++;
}
n = 0;
while (true) {
XMLNode bind = out_node.getChildNode ("bind", n);
if (bind.isEmpty ())
break;
const char *addr = bind.getAttribute ("addr");
if (!addr) {
fprintf (stderr, "'bind' node is missing 'addr' attribute\n");
return 1;
}
out_socket.bind (addr);
n++;
}
n = 0;
while (true) {
XMLNode connect = out_node.getChildNode ("connect", n);
if (connect.isEmpty ())
break;
const char *addr = connect.getAttribute ("addr");
if (!addr) {
fprintf (stderr, "'connect' node is missing 'addr' attribute\n");
return 1;
}
out_socket.connect (addr);
n++;
}
zmq::message_t msg;
while (true) {
in_socket.recv (&msg);
out_socket.send (msg);
}
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,762 @@
/****************************************************************************/
/*! \mainpage XMLParser library
* \section intro_sec Introduction
*
* This is a basic XML parser written in ANSI C++ for portability.
* It works by using recursion and a node tree for breaking
* down the elements of an XML document.
* Copyright (c) 2002, Frank Vanden Berghen
* All rights reserved.
*
* The following license terms apply to projects that are in some way related to
* the "ZeroMQ project", including applications
* using "ZeroMQ project" and tools developed
* for enhancing "ZeroMQ project". All other projects
* (not related to "ZeroMQ project") have to use this
* code under the Aladdin Free Public License (AFPL)
* See the file "AFPL-license.txt" for more informations about the AFPL license.
* (see http://www.artifex.com/downloads/doc/Public.htm for detailed AFPL terms)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Frank Vanden Berghen nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY Frank Vanden Berghen ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* @version V2.39
* @author Frank Vanden Berghen
*
* \section tutorial First Tutorial
* You can follow a simple <a href="../../xmlParser.html">Tutorial</a> to know the basics...
*
* \section usage General usage: How to include the XMLParser library inside your project.
*
* The library is composed of two files: <a href="../../xmlParser.cpp">xmlParser.cpp</a> and
* <a href="../../xmlParser.h">xmlParser.h</a>. These are the ONLY 2 files that you need when
* using the library inside your own projects.
*
* All the functions of the library are documented inside the comments of the file
* <a href="../../xmlParser.h">xmlParser.h</a>. These comments can be transformed in
* full-fledged HTML documentation using the DOXYGEN software: simply type: "doxygen doxy.cfg"
*
* By default, the XMLParser library uses (char*) for string representation.To use the (wchar_t*)
* version of the library, you need to define the "_UNICODE" preprocessor definition variable
* (this is usually done inside your project definition file) (This is done automatically for you
* when using Visual Studio).
*
* \section example Advanced Tutorial and Many Examples of usage.
*
* Some very small introductory examples are described inside the Tutorial file
* <a href="../../xmlParser.html">xmlParser.html</a>
*
* Some additional small examples are also inside the file <a href="../../xmlTest.cpp">xmlTest.cpp</a>
* (for the "char*" version of the library) and inside the file
* <a href="../../xmlTestUnicode.cpp">xmlTestUnicode.cpp</a> (for the "wchar_t*"
* version of the library). If you have a question, please review these additionnal examples
* before sending an e-mail to the author.
*
* To build the examples:
* - linux/unix: type "make"
* - solaris: type "make -f makefile.solaris"
* - windows: Visual Studio: double-click on xmlParser.dsw
* (under Visual Studio .NET, the .dsp and .dsw files will be automatically converted to .vcproj and .sln files)
*
* In order to build the examples you need some additional files:
* - linux/unix: makefile
* - solaris: makefile.solaris
* - windows: Visual Studio: *.dsp, xmlParser.dsw and also xmlParser.lib and xmlParser.dll
*
* \section debugging Debugging with the XMLParser library
*
* \subsection debugwin Debugging under WINDOWS
*
* Inside Visual C++, the "debug versions" of the memory allocation functions are
* very slow: Do not forget to compile in "release mode" to get maximum speed.
* When I have to debug a software that is using the XMLParser Library, it was usually
* a nightmare because the library was sooOOOoooo slow in debug mode (because of the
* slow memory allocations in Debug mode). To solve this
* problem, during all the debugging session, I use a very fast DLL version of the
* XMLParser Library (the DLL is compiled in release mode). Using the DLL version of
* the XMLParser Library allows me to have lightening XML parsing speed even in debug!
* Other than that, the DLL version is useless: In the release version of my tool,
* I always use the normal, ".cpp"-based, XMLParser Library (I simply include the
* <a href="../../xmlParser.cpp">xmlParser.cpp</a> and
* <a href="../../xmlParser.h">xmlParser.h</a> files into the project).
*
* The file <a href="../../XMLNodeAutoexp.txt">XMLNodeAutoexp.txt</a> contains some
* "tweaks" that improve substancially the display of the content of the XMLNode objects
* inside the Visual Studio Debugger. Believe me, once you have seen inside the debugger
* the "smooth" display of the XMLNode objects, you cannot live without it anymore!
*
* \subsection debuglinux Debugging under LINUX/UNIX
*
* The speed of the debug version of the XMLParser library is tolerable so no extra
* work.has been done.
*
****************************************************************************/
#ifndef __INCLUDE_XML_NODE__
#define __INCLUDE_XML_NODE__
#include <stdlib.h>
#ifdef _UNICODE
// If you comment the next "define" line then the library will never "switch to" _UNICODE (wchar_t*) mode (16/32 bits per characters).
// This is useful when you get error messages like:
// 'XMLNode::openFileHelper' : cannot convert parameter 2 from 'const char [5]' to 'const wchar_t *'
// The _XMLWIDECHAR preprocessor variable force the XMLParser library into either utf16/32-mode (the proprocessor variable
// must be defined) or utf8-mode(the pre-processor variable must be undefined).
#define _XMLWIDECHAR
#endif
#if defined(WIN32) || defined(UNDER_CE) || defined(_WIN32) || defined(WIN64) || defined(__BORLANDC__)
// comment the next line if you are under windows and the compiler is not Microsoft Visual Studio (6.0 or .NET) or Borland
#define _XMLWINDOWS
#endif
#ifdef XMLDLLENTRY
#undef XMLDLLENTRY
#endif
#ifdef _USE_XMLPARSER_DLL
#ifdef _DLL_EXPORTS_
#define XMLDLLENTRY __declspec(dllexport)
#else
#define XMLDLLENTRY __declspec(dllimport)
#endif
#else
#define XMLDLLENTRY
#endif
// uncomment the next line if you want no support for wchar_t* (no need for the <wchar.h> or <tchar.h> libraries anymore to compile)
//#define XML_NO_WIDE_CHAR
#ifdef XML_NO_WIDE_CHAR
#undef _XMLWINDOWS
#undef _XMLWIDECHAR
#endif
#ifdef _XMLWINDOWS
#include <tchar.h>
#else
#define XMLDLLENTRY
#ifndef XML_NO_WIDE_CHAR
#include <wchar.h> // to have 'wcsrtombs' for ANSI version
// to have 'mbsrtowcs' for WIDECHAR version
#endif
#endif
// Some common types for char set portable code
#ifdef _XMLWIDECHAR
#define _CXML(c) L ## c
#define XMLCSTR const wchar_t *
#define XMLSTR wchar_t *
#define XMLCHAR wchar_t
#else
#define _CXML(c) c
#define XMLCSTR const char *
#define XMLSTR char *
#define XMLCHAR char
#endif
#ifndef FALSE
#define FALSE 0
#endif /* FALSE */
#ifndef TRUE
#define TRUE 1
#endif /* TRUE */
/// Enumeration for XML parse errors.
typedef enum XMLError
{
eXMLErrorNone = 0,
eXMLErrorMissingEndTag,
eXMLErrorNoXMLTagFound,
eXMLErrorEmpty,
eXMLErrorMissingTagName,
eXMLErrorMissingEndTagName,
eXMLErrorUnmatchedEndTag,
eXMLErrorUnmatchedEndClearTag,
eXMLErrorUnexpectedToken,
eXMLErrorNoElements,
eXMLErrorFileNotFound,
eXMLErrorFirstTagNotFound,
eXMLErrorUnknownCharacterEntity,
eXMLErrorCharacterCodeAbove255,
eXMLErrorCharConversionError,
eXMLErrorCannotOpenWriteFile,
eXMLErrorCannotWriteFile,
eXMLErrorBase64DataSizeIsNotMultipleOf4,
eXMLErrorBase64DecodeIllegalCharacter,
eXMLErrorBase64DecodeTruncatedData,
eXMLErrorBase64DecodeBufferTooSmall
} XMLError;
/// Enumeration used to manage type of data. Use in conjunction with structure XMLNodeContents
typedef enum XMLElementType
{
eNodeChild=0,
eNodeAttribute=1,
eNodeText=2,
eNodeClear=3,
eNodeNULL=4
} XMLElementType;
/// Structure used to obtain error details if the parse fails.
typedef struct XMLResults
{
enum XMLError error;
int nLine,nColumn;
} XMLResults;
/// Structure for XML clear (unformatted) node (usually comments)
typedef struct XMLClear {
XMLCSTR lpszValue; XMLCSTR lpszOpenTag; XMLCSTR lpszCloseTag;
} XMLClear;
/// Structure for XML attribute.
typedef struct XMLAttribute {
XMLCSTR lpszName; XMLCSTR lpszValue;
} XMLAttribute;
/// XMLElementPosition are not interchangeable with simple indexes
typedef int XMLElementPosition;
struct XMLNodeContents;
/** @defgroup XMLParserGeneral The XML parser */
/// Main Class representing a XML node
/**
* All operations are performed using this class.
* \note The constructors of the XMLNode class are protected, so use instead one of these four methods to get your first instance of XMLNode:
* <ul>
* <li> XMLNode::parseString </li>
* <li> XMLNode::parseFile </li>
* <li> XMLNode::openFileHelper </li>
* <li> XMLNode::createXMLTopNode (or XMLNode::createXMLTopNode_WOSD)</li>
* </ul> */
typedef struct XMLDLLENTRY XMLNode
{
private:
struct XMLNodeDataTag;
/// Constructors are protected, so use instead one of: XMLNode::parseString, XMLNode::parseFile, XMLNode::openFileHelper, XMLNode::createXMLTopNode
XMLNode(struct XMLNodeDataTag *pParent, XMLSTR lpszName, char isDeclaration);
/// Constructors are protected, so use instead one of: XMLNode::parseString, XMLNode::parseFile, XMLNode::openFileHelper, XMLNode::createXMLTopNode
XMLNode(struct XMLNodeDataTag *p);
public:
static XMLCSTR getVersion();///< Return the XMLParser library version number
/** @defgroup conversions Parsing XML files/strings to an XMLNode structure and Rendering XMLNode's to files/string.
* @ingroup XMLParserGeneral
* @{ */
/// Parse an XML string and return the root of a XMLNode tree representing the string.
static XMLNode parseString (XMLCSTR lpXMLString, XMLCSTR tag=NULL, XMLResults *pResults=NULL);
/**< The "parseString" function parse an XML string and return the root of a XMLNode tree. The "opposite" of this function is
* the function "createXMLString" that re-creates an XML string from an XMLNode tree. If the XML document is corrupted, the
* "parseString" method will initialize the "pResults" variable with some information that can be used to trace the error.
* If you still want to parse the file, you can use the APPROXIMATE_PARSING option as explained inside the note at the
* beginning of the "xmlParser.cpp" file.
*
* @param lpXMLString the XML string to parse
* @param tag the name of the first tag inside the XML file. If the tag parameter is omitted, this function returns a node that represents the head of the xml document including the declaration term (<? ... ?>).
* @param pResults a pointer to a XMLResults variable that will contain some information that can be used to trace the XML parsing error. You can have a user-friendly explanation of the parsing error with the "getError" function.
*/
/// Parse an XML file and return the root of a XMLNode tree representing the file.
static XMLNode parseFile (XMLCSTR filename, XMLCSTR tag=NULL, XMLResults *pResults=NULL);
/**< The "parseFile" function parse an XML file and return the root of a XMLNode tree. The "opposite" of this function is
* the function "writeToFile" that re-creates an XML file from an XMLNode tree. If the XML document is corrupted, the
* "parseFile" method will initialize the "pResults" variable with some information that can be used to trace the error.
* If you still want to parse the file, you can use the APPROXIMATE_PARSING option as explained inside the note at the
* beginning of the "xmlParser.cpp" file.
*
* @param filename the path to the XML file to parse
* @param tag the name of the first tag inside the XML file. If the tag parameter is omitted, this function returns a node that represents the head of the xml document including the declaration term (<? ... ?>).
* @param pResults a pointer to a XMLResults variable that will contain some information that can be used to trace the XML parsing error. You can have a user-friendly explanation of the parsing error with the "getError" function.
*/
/// Parse an XML file and return the root of a XMLNode tree representing the file. A very crude error checking is made. An attempt to guess the Char Encoding used in the file is made.
static XMLNode openFileHelper(XMLCSTR filename, XMLCSTR tag=NULL);
/**< The "openFileHelper" function reports to the screen all the warnings and errors that occurred during parsing of the XML file.
* This function also tries to guess char Encoding (UTF-8, ASCII or SHIT-JIS) based on the first 200 bytes of the file. Since each
* application has its own way to report and deal with errors, you should rather use the "parseFile" function to parse XML files
* and program yourself thereafter an "error reporting" tailored for your needs (instead of using the very crude "error reporting"
* mechanism included inside the "openFileHelper" function).
*
* If the XML document is corrupted, the "openFileHelper" method will:
* - display an error message on the console (or inside a messageBox for windows).
* - stop execution (exit).
*
* I strongly suggest that you write your own "openFileHelper" method tailored to your needs. If you still want to parse
* the file, you can use the APPROXIMATE_PARSING option as explained inside the note at the beginning of the "xmlParser.cpp" file.
*
* @param filename the path of the XML file to parse.
* @param tag the name of the first tag inside the XML file. If the tag parameter is omitted, this function returns a node that represents the head of the xml document including the declaration term (<? ... ?>).
*/
static XMLCSTR getError(XMLError error); ///< this gives you a user-friendly explanation of the parsing error
/// Create an XML string starting from the current XMLNode.
XMLSTR createXMLString(int nFormat=1, int *pnSize=NULL) const;
/**< The returned string should be free'd using the "freeXMLString" function.
*
* If nFormat==0, no formatting is required otherwise this returns an user friendly XML string from a given element
* with appropriate white spaces and carriage returns. if pnSize is given it returns the size in character of the string. */
/// Save the content of an xmlNode inside a file
XMLError writeToFile(XMLCSTR filename,
const char *encoding=NULL,
char nFormat=1) const;
/**< If nFormat==0, no formatting is required otherwise this returns an user friendly XML string from a given element with appropriate white spaces and carriage returns.
* If the global parameter "characterEncoding==encoding_UTF8", then the "encoding" parameter is ignored and always set to "utf-8".
* If the global parameter "characterEncoding==encoding_ShiftJIS", then the "encoding" parameter is ignored and always set to "SHIFT-JIS".
* If "_XMLWIDECHAR=1", then the "encoding" parameter is ignored and always set to "utf-16".
* If no "encoding" parameter is given the "ISO-8859-1" encoding is used. */
/** @} */
/** @defgroup navigate Navigate the XMLNode structure
* @ingroup XMLParserGeneral
* @{ */
XMLCSTR getName() const; ///< name of the node
XMLCSTR getText(int i=0) const; ///< return ith text field
int nText() const; ///< nbr of text field
XMLNode getParentNode() const; ///< return the parent node
XMLNode getChildNode(int i=0) const; ///< return ith child node
XMLNode getChildNode(XMLCSTR name, int i) const; ///< return ith child node with specific name (return an empty node if failing). If i==-1, this returns the last XMLNode with the given name.
XMLNode getChildNode(XMLCSTR name, int *i=NULL) const; ///< return next child node with specific name (return an empty node if failing)
XMLNode getChildNodeWithAttribute(XMLCSTR tagName,
XMLCSTR attributeName,
XMLCSTR attributeValue=NULL,
int *i=NULL) const; ///< return child node with specific name/attribute (return an empty node if failing)
XMLNode getChildNodeByPath(XMLCSTR path, char createNodeIfMissing=0, XMLCHAR sep='/');
///< return the first child node with specific path
XMLNode getChildNodeByPathNonConst(XMLSTR path, char createNodeIfMissing=0, XMLCHAR sep='/');
///< return the first child node with specific path.
int nChildNode(XMLCSTR name) const; ///< return the number of child node with specific name
int nChildNode() const; ///< nbr of child node
XMLAttribute getAttribute(int i=0) const; ///< return ith attribute
XMLCSTR getAttributeName(int i=0) const; ///< return ith attribute name
XMLCSTR getAttributeValue(int i=0) const; ///< return ith attribute value
char isAttributeSet(XMLCSTR name) const; ///< test if an attribute with a specific name is given
XMLCSTR getAttribute(XMLCSTR name, int i) const; ///< return ith attribute content with specific name (return a NULL if failing)
XMLCSTR getAttribute(XMLCSTR name, int *i=NULL) const; ///< return next attribute content with specific name (return a NULL if failing)
int nAttribute() const; ///< nbr of attribute
XMLClear getClear(int i=0) const; ///< return ith clear field (comments)
int nClear() const; ///< nbr of clear field
XMLNodeContents enumContents(XMLElementPosition i) const; ///< enumerate all the different contents (attribute,child,text, clear) of the current XMLNode. The order is reflecting the order of the original file/string. NOTE: 0 <= i < nElement();
int nElement() const; ///< nbr of different contents for current node
char isEmpty() const; ///< is this node Empty?
char isDeclaration() const; ///< is this node a declaration <? .... ?>
XMLNode deepCopy() const; ///< deep copy (duplicate/clone) a XMLNode
static XMLNode emptyNode(); ///< return XMLNode::emptyXMLNode;
/** @} */
~XMLNode();
XMLNode(const XMLNode &A); ///< to allow shallow/fast copy:
XMLNode& operator=( const XMLNode& A ); ///< to allow shallow/fast copy:
XMLNode(): d(NULL){};
static XMLNode emptyXMLNode;
static XMLClear emptyXMLClear;
static XMLAttribute emptyXMLAttribute;
/** @defgroup xmlModify Create or Update the XMLNode structure
* @ingroup XMLParserGeneral
* The functions in this group allows you to create from scratch (or update) a XMLNode structure. Start by creating your top
* node with the "createXMLTopNode" function and then add new nodes with the "addChild" function. The parameter 'pos' gives
* the position where the childNode, the text or the XMLClearTag will be inserted. The default value (pos=-1) inserts at the
* end. The value (pos=0) insert at the beginning (Insertion at the beginning is slower than at the end). <br>
*
* REMARK: 0 <= pos < nChild()+nText()+nClear() <br>
*/
/** @defgroup creation Creating from scratch a XMLNode structure
* @ingroup xmlModify
* @{ */
static XMLNode createXMLTopNode(XMLCSTR lpszName, char isDeclaration=FALSE); ///< Create the top node of an XMLNode structure
XMLNode addChild(XMLCSTR lpszName, char isDeclaration=FALSE, XMLElementPosition pos=-1); ///< Add a new child node
XMLNode addChild(XMLNode nodeToAdd, XMLElementPosition pos=-1); ///< If the "nodeToAdd" has some parents, it will be detached from it's parents before being attached to the current XMLNode
XMLAttribute *addAttribute(XMLCSTR lpszName, XMLCSTR lpszValuev); ///< Add a new attribute
XMLCSTR addText(XMLCSTR lpszValue, XMLElementPosition pos=-1); ///< Add a new text content
XMLClear *addClear(XMLCSTR lpszValue, XMLCSTR lpszOpen=NULL, XMLCSTR lpszClose=NULL, XMLElementPosition pos=-1);
/**< Add a new clear tag
* @param lpszOpen default value "<![CDATA["
* @param lpszClose default value "]]>"
*/
/** @} */
/** @defgroup xmlUpdate Updating Nodes
* @ingroup xmlModify
* Some update functions:
* @{
*/
XMLCSTR updateName(XMLCSTR lpszName); ///< change node's name
XMLAttribute *updateAttribute(XMLAttribute *newAttribute, XMLAttribute *oldAttribute); ///< if the attribute to update is missing, a new one will be added
XMLAttribute *updateAttribute(XMLCSTR lpszNewValue, XMLCSTR lpszNewName=NULL,int i=0); ///< if the attribute to update is missing, a new one will be added
XMLAttribute *updateAttribute(XMLCSTR lpszNewValue, XMLCSTR lpszNewName,XMLCSTR lpszOldName);///< set lpszNewName=NULL if you don't want to change the name of the attribute if the attribute to update is missing, a new one will be added
XMLCSTR updateText(XMLCSTR lpszNewValue, int i=0); ///< if the text to update is missing, a new one will be added
XMLCSTR updateText(XMLCSTR lpszNewValue, XMLCSTR lpszOldValue); ///< if the text to update is missing, a new one will be added
XMLClear *updateClear(XMLCSTR lpszNewContent, int i=0); ///< if the clearTag to update is missing, a new one will be added
XMLClear *updateClear(XMLClear *newP,XMLClear *oldP); ///< if the clearTag to update is missing, a new one will be added
XMLClear *updateClear(XMLCSTR lpszNewValue, XMLCSTR lpszOldValue); ///< if the clearTag to update is missing, a new one will be added
/** @} */
/** @defgroup xmlDelete Deleting Nodes or Attributes
* @ingroup xmlModify
* Some deletion functions:
* @{
*/
/// The "deleteNodeContent" function forces the deletion of the content of this XMLNode and the subtree.
void deleteNodeContent();
/**< \note The XMLNode instances that are referring to the part of the subtree that has been deleted CANNOT be used anymore!!. Unexpected results will occur if you continue using them. */
void deleteAttribute(int i=0); ///< Delete the ith attribute of the current XMLNode
void deleteAttribute(XMLCSTR lpszName); ///< Delete the attribute with the given name (the "strcmp" function is used to find the right attribute)
void deleteAttribute(XMLAttribute *anAttribute); ///< Delete the attribute with the name "anAttribute->lpszName" (the "strcmp" function is used to find the right attribute)
void deleteText(int i=0); ///< Delete the Ith text content of the current XMLNode
void deleteText(XMLCSTR lpszValue); ///< Delete the text content "lpszValue" inside the current XMLNode (direct "pointer-to-pointer" comparison is used to find the right text)
void deleteClear(int i=0); ///< Delete the Ith clear tag inside the current XMLNode
void deleteClear(XMLCSTR lpszValue); ///< Delete the clear tag "lpszValue" inside the current XMLNode (direct "pointer-to-pointer" comparison is used to find the clear tag)
void deleteClear(XMLClear *p); ///< Delete the clear tag "p" inside the current XMLNode (direct "pointer-to-pointer" comparison on the lpszName of the clear tag is used to find the clear tag)
/** @} */
/** @defgroup xmlWOSD ???_WOSD functions.
* @ingroup xmlModify
* The strings given as parameters for the "add" and "update" methods that have a name with
* the postfix "_WOSD" (that means "WithOut String Duplication")(for example "addText_WOSD")
* will be free'd by the XMLNode class. For example, it means that this is incorrect:
* \code
* xNode.addText_WOSD("foo");
* xNode.updateAttribute_WOSD("#newcolor" ,NULL,"color");
* \endcode
* In opposition, this is correct:
* \code
* xNode.addText("foo");
* xNode.addText_WOSD(stringDup("foo"));
* xNode.updateAttribute("#newcolor" ,NULL,"color");
* xNode.updateAttribute_WOSD(stringDup("#newcolor"),NULL,"color");
* \endcode
* Typically, you will never do:
* \code
* char *b=(char*)malloc(...);
* xNode.addText(b);
* free(b);
* \endcode
* ... but rather:
* \code
* char *b=(char*)malloc(...);
* xNode.addText_WOSD(b);
* \endcode
* ('free(b)' is performed by the XMLNode class)
* @{ */
static XMLNode createXMLTopNode_WOSD(XMLSTR lpszName, char isDeclaration=FALSE); ///< Create the top node of an XMLNode structure
XMLNode addChild_WOSD(XMLSTR lpszName, char isDeclaration=FALSE, XMLElementPosition pos=-1); ///< Add a new child node
XMLAttribute *addAttribute_WOSD(XMLSTR lpszName, XMLSTR lpszValue); ///< Add a new attribute
XMLCSTR addText_WOSD(XMLSTR lpszValue, XMLElementPosition pos=-1); ///< Add a new text content
XMLClear *addClear_WOSD(XMLSTR lpszValue, XMLCSTR lpszOpen=NULL, XMLCSTR lpszClose=NULL, XMLElementPosition pos=-1); ///< Add a new clear Tag
XMLCSTR updateName_WOSD(XMLSTR lpszName); ///< change node's name
XMLAttribute *updateAttribute_WOSD(XMLAttribute *newAttribute, XMLAttribute *oldAttribute); ///< if the attribute to update is missing, a new one will be added
XMLAttribute *updateAttribute_WOSD(XMLSTR lpszNewValue, XMLSTR lpszNewName=NULL,int i=0); ///< if the attribute to update is missing, a new one will be added
XMLAttribute *updateAttribute_WOSD(XMLSTR lpszNewValue, XMLSTR lpszNewName,XMLCSTR lpszOldName); ///< set lpszNewName=NULL if you don't want to change the name of the attribute if the attribute to update is missing, a new one will be added
XMLCSTR updateText_WOSD(XMLSTR lpszNewValue, int i=0); ///< if the text to update is missing, a new one will be added
XMLCSTR updateText_WOSD(XMLSTR lpszNewValue, XMLCSTR lpszOldValue); ///< if the text to update is missing, a new one will be added
XMLClear *updateClear_WOSD(XMLSTR lpszNewContent, int i=0); ///< if the clearTag to update is missing, a new one will be added
XMLClear *updateClear_WOSD(XMLClear *newP,XMLClear *oldP); ///< if the clearTag to update is missing, a new one will be added
XMLClear *updateClear_WOSD(XMLSTR lpszNewValue, XMLCSTR lpszOldValue); ///< if the clearTag to update is missing, a new one will be added
/** @} */
/** @defgroup xmlPosition Position helper functions (use in conjunction with the update&add functions
* @ingroup xmlModify
* These are some useful functions when you want to insert a childNode, a text or a XMLClearTag in the
* middle (at a specified position) of a XMLNode tree already constructed. The value returned by these
* methods is to be used as last parameter (parameter 'pos') of addChild, addText or addClear.
* @{ */
XMLElementPosition positionOfText(int i=0) const;
XMLElementPosition positionOfText(XMLCSTR lpszValue) const;
XMLElementPosition positionOfClear(int i=0) const;
XMLElementPosition positionOfClear(XMLCSTR lpszValue) const;
XMLElementPosition positionOfClear(XMLClear *a) const;
XMLElementPosition positionOfChildNode(int i=0) const;
XMLElementPosition positionOfChildNode(XMLNode x) const;
XMLElementPosition positionOfChildNode(XMLCSTR name, int i=0) const; ///< return the position of the ith childNode with the specified name if (name==NULL) return the position of the ith childNode
/** @} */
/// Enumeration for XML character encoding.
typedef enum XMLCharEncoding
{
char_encoding_error=0,
char_encoding_UTF8=1,
char_encoding_legacy=2,
char_encoding_ShiftJIS=3,
char_encoding_GB2312=4,
char_encoding_Big5=5,
char_encoding_GBK=6 // this is actually the same as Big5
} XMLCharEncoding;
/** \addtogroup conversions
* @{ */
/// Sets the global options for the conversions
static char setGlobalOptions(XMLCharEncoding characterEncoding=XMLNode::char_encoding_UTF8, char guessWideCharChars=1,
char dropWhiteSpace=1, char removeCommentsInMiddleOfText=1);
/**< The "setGlobalOptions" function allows you to change four global parameters that affect string & file
* parsing. First of all, you most-probably will never have to change these 3 global parameters.
*
* @param guessWideCharChars If "guessWideCharChars"=1 and if this library is compiled in WideChar mode, then the
* XMLNode::parseFile and XMLNode::openFileHelper functions will test if the file contains ASCII
* characters. If this is the case, then the file will be loaded and converted in memory to
* WideChar before being parsed. If 0, no conversion will be performed.
*
* @param guessWideCharChars If "guessWideCharChars"=1 and if this library is compiled in ASCII/UTF8/char* mode, then the
* XMLNode::parseFile and XMLNode::openFileHelper functions will test if the file contains WideChar
* characters. If this is the case, then the file will be loaded and converted in memory to
* ASCII/UTF8/char* before being parsed. If 0, no conversion will be performed.
*
* @param characterEncoding This parameter is only meaningful when compiling in char* mode (multibyte character mode).
* In wchar_t* (wide char mode), this parameter is ignored. This parameter should be one of the
* three currently recognized encodings: XMLNode::encoding_UTF8, XMLNode::encoding_ascii,
* XMLNode::encoding_ShiftJIS.
*
* @param dropWhiteSpace In most situations, text fields containing only white spaces (and carriage returns)
* are useless. Even more, these "empty" text fields are annoying because they increase the
* complexity of the user's code for parsing. So, 99% of the time, it's better to drop
* the "empty" text fields. However The XML specification indicates that no white spaces
* should be lost when parsing the file. So to be perfectly XML-compliant, you should set
* dropWhiteSpace=0. A note of caution: if you set "dropWhiteSpace=0", the parser will be
* slower and your code will be more complex.
*
* @param removeCommentsInMiddleOfText To explain this parameter, let's consider this code:
* \code
* XMLNode x=XMLNode::parseString("<a>foo<!-- hello -->bar<!DOCTYPE world >chu</a>","a");
* \endcode
* If removeCommentsInMiddleOfText=0, then we will have:
* \code
* x.getText(0) -> "foo"
* x.getText(1) -> "bar"
* x.getText(2) -> "chu"
* x.getClear(0) --> "<!-- hello -->"
* x.getClear(1) --> "<!DOCTYPE world >"
* \endcode
* If removeCommentsInMiddleOfText=1, then we will have:
* \code
* x.getText(0) -> "foobar"
* x.getText(1) -> "chu"
* x.getClear(0) --> "<!DOCTYPE world >"
* \endcode
*
* \return "0" when there are no errors. If you try to set an unrecognized encoding then the return value will be "1" to signal an error.
*
* \note Sometime, it's useful to set "guessWideCharChars=0" to disable any conversion
* because the test to detect the file-type (ASCII/UTF8/char* or WideChar) may fail (rarely). */
/// Guess the character encoding of the string (ascii, utf8 or shift-JIS)
static XMLCharEncoding guessCharEncoding(void *buffer, int bufLen, char useXMLEncodingAttribute=1);
/**< The "guessCharEncoding" function try to guess the character encoding. You most-probably will never
* have to use this function. It then returns the appropriate value of the global parameter
* "characterEncoding" described in the XMLNode::setGlobalOptions. The guess is based on the content of a buffer of length
* "bufLen" bytes that contains the first bytes (minimum 25 bytes; 200 bytes is a good value) of the
* file to be parsed. The XMLNode::openFileHelper function is using this function to automatically compute
* the value of the "characterEncoding" global parameter. There are several heuristics used to do the
* guess. One of the heuristic is based on the "encoding" attribute. The original XML specifications
* forbids to use this attribute to do the guess but you can still use it if you set
* "useXMLEncodingAttribute" to 1 (this is the default behavior and the behavior of most parsers).
* If an inconsistency in the encoding is detected, then the return value is "0". */
/** @} */
private:
// these are functions and structures used internally by the XMLNode class (don't bother about them):
typedef struct XMLNodeDataTag // to allow shallow copy and "intelligent/smart" pointers (automatic delete):
{
XMLCSTR lpszName; // Element name (=NULL if root)
int nChild, // Number of child nodes
nText, // Number of text fields
nClear, // Number of Clear fields (comments)
nAttribute; // Number of attributes
char isDeclaration; // Whether node is an XML declaration - '<?xml ?>'
struct XMLNodeDataTag *pParent; // Pointer to parent element (=NULL if root)
XMLNode *pChild; // Array of child nodes
XMLCSTR *pText; // Array of text fields
XMLClear *pClear; // Array of clear fields
XMLAttribute *pAttribute; // Array of attributes
int *pOrder; // order of the child_nodes,text_fields,clear_fields
int ref_count; // for garbage collection (smart pointers)
} XMLNodeData;
XMLNodeData *d;
char parseClearTag(void *px, void *pa);
char maybeAddTxT(void *pa, XMLCSTR tokenPStr);
int ParseXMLElement(void *pXML);
void *addToOrder(int memInc, int *_pos, int nc, void *p, int size, XMLElementType xtype);
int indexText(XMLCSTR lpszValue) const;
int indexClear(XMLCSTR lpszValue) const;
XMLNode addChild_priv(int,XMLSTR,char,int);
XMLAttribute *addAttribute_priv(int,XMLSTR,XMLSTR);
XMLCSTR addText_priv(int,XMLSTR,int);
XMLClear *addClear_priv(int,XMLSTR,XMLCSTR,XMLCSTR,int);
void emptyTheNode(char force);
static inline XMLElementPosition findPosition(XMLNodeData *d, int index, XMLElementType xtype);
static int CreateXMLStringR(XMLNodeData *pEntry, XMLSTR lpszMarker, int nFormat);
static int removeOrderElement(XMLNodeData *d, XMLElementType t, int index);
static void exactMemory(XMLNodeData *d);
static int detachFromParent(XMLNodeData *d);
} XMLNode;
/// This structure is given by the function XMLNode::enumContents.
typedef struct XMLNodeContents
{
/// This dictates what's the content of the XMLNodeContent
enum XMLElementType etype;
/**< should be an union to access the appropriate data. Compiler does not allow union of object with constructor... too bad. */
XMLNode child;
XMLAttribute attrib;
XMLCSTR text;
XMLClear clear;
} XMLNodeContents;
/** @defgroup StringAlloc String Allocation/Free functions
* @ingroup xmlModify
* @{ */
/// Duplicate (copy in a new allocated buffer) the source string.
XMLDLLENTRY XMLSTR stringDup(XMLCSTR source, int cbData=-1);
/**< This is
* a very handy function when used with all the "XMLNode::*_WOSD" functions (\link xmlWOSD \endlink).
* @param cbData If !=0 then cbData is the number of chars to duplicate. New strings allocated with
* this function should be free'd using the "freeXMLString" function. */
/// to free the string allocated inside the "stringDup" function or the "createXMLString" function.
XMLDLLENTRY void freeXMLString(XMLSTR t); // {free(t);}
/** @} */
/** @defgroup atoX ato? like functions
* @ingroup XMLParserGeneral
* The "xmlto?" functions are equivalents to the atoi, atol, atof functions.
* The only difference is: If the variable "xmlString" is NULL, than the return value
* is "defautValue". These 6 functions are only here as "convenience" functions for the
* user (they are not used inside the XMLparser). If you don't need them, you can
* delete them without any trouble.
*
* @{ */
XMLDLLENTRY char xmltob(XMLCSTR xmlString,char defautValue=0);
XMLDLLENTRY int xmltoi(XMLCSTR xmlString,int defautValue=0);
XMLDLLENTRY long xmltol(XMLCSTR xmlString,long defautValue=0);
XMLDLLENTRY double xmltof(XMLCSTR xmlString,double defautValue=.0);
XMLDLLENTRY XMLCSTR xmltoa(XMLCSTR xmlString,XMLCSTR defautValue=_CXML(""));
XMLDLLENTRY XMLCHAR xmltoc(XMLCSTR xmlString,XMLCHAR defautValue=_CXML('\0'));
/** @} */
/** @defgroup ToXMLStringTool Helper class to create XML files using "printf", "fprintf", "cout",... functions.
* @ingroup XMLParserGeneral
* @{ */
/// Helper class to create XML files using "printf", "fprintf", "cout",... functions.
/** The ToXMLStringTool class helps you creating XML files using "printf", "fprintf", "cout",... functions.
* The "ToXMLStringTool" class is processing strings so that all the characters
* &,",',<,> are replaced by their XML equivalent:
* \verbatim &amp;, &quot;, &apos;, &lt;, &gt; \endverbatim
* Using the "ToXMLStringTool class" and the "fprintf function" is THE most efficient
* way to produce VERY large XML documents VERY fast.
* \note If you are creating from scratch an XML file using the provided XMLNode class
* you must not use the "ToXMLStringTool" class (because the "XMLNode" class does the
* processing job for you during rendering).*/
typedef struct XMLDLLENTRY ToXMLStringTool
{
public:
ToXMLStringTool(): buf(NULL),buflen(0){}
~ToXMLStringTool();
void freeBuffer();///<call this function when you have finished using this object to release memory used by the internal buffer.
XMLSTR toXML(XMLCSTR source);///< returns a pointer to an internal buffer that contains a XML-encoded string based on the "source" parameter.
/** The "toXMLUnSafe" function is deprecated because there is a possibility of
* "destination-buffer-overflow". It converts the string
* "source" to the string "dest". */
static XMLSTR toXMLUnSafe(XMLSTR dest,XMLCSTR source); ///< deprecated: use "toXML" instead
static int lengthXMLString(XMLCSTR source); ///< deprecated: use "toXML" instead
private:
XMLSTR buf;
int buflen;
} ToXMLStringTool;
/** @} */
/** @defgroup XMLParserBase64Tool Helper class to include binary data inside XML strings using "Base64 encoding".
* @ingroup XMLParserGeneral
* @{ */
/// Helper class to include binary data inside XML strings using "Base64 encoding".
/** The "XMLParserBase64Tool" class allows you to include any binary data (images, sounds,...)
* into an XML document using "Base64 encoding". This class is completely
* separated from the rest of the xmlParser library and can be removed without any problem.
* To include some binary data into an XML file, you must convert the binary data into
* standard text (using "encode"). To retrieve the original binary data from the
* b64-encoded text included inside the XML file, use "decode". Alternatively, these
* functions can also be used to "encrypt/decrypt" some critical data contained inside
* the XML (it's not a strong encryption at all, but sometimes it can be useful). */
typedef struct XMLDLLENTRY XMLParserBase64Tool
{
public:
XMLParserBase64Tool(): buf(NULL),buflen(0){}
~XMLParserBase64Tool();
void freeBuffer();///< Call this function when you have finished using this object to release memory used by the internal buffer.
/**
* @param formatted If "formatted"=true, some space will be reserved for a carriage-return every 72 chars. */
static int encodeLength(int inBufLen, char formatted=0); ///< return the length of the base64 string that encodes a data buffer of size inBufLen bytes.
/**
* The "base64Encode" function returns a string containing the base64 encoding of "inByteLen" bytes
* from "inByteBuf". If "formatted" parameter is true, then there will be a carriage-return every 72 chars.
* The string will be free'd when the XMLParserBase64Tool object is deleted.
* All returned strings are sharing the same memory space. */
XMLSTR encode(unsigned char *inByteBuf, unsigned int inByteLen, char formatted=0); ///< returns a pointer to an internal buffer containing the base64 string containing the binary data encoded from "inByteBuf"
/// returns the number of bytes which will be decoded from "inString".
static unsigned int decodeSize(XMLCSTR inString, XMLError *xe=NULL);
/**
* The "decode" function returns a pointer to a buffer containing the binary data decoded from "inString"
* The output buffer will be free'd when the XMLParserBase64Tool object is deleted.
* All output buffer are sharing the same memory space.
* @param inString If "instring" is malformed, NULL will be returned */
unsigned char* decode(XMLCSTR inString, int *outByteLen=NULL, XMLError *xe=NULL); ///< returns a pointer to an internal buffer containing the binary data decoded from "inString"
/**
* decodes data from "inString" to "outByteBuf". You need to provide the size (in byte) of "outByteBuf"
* in "inMaxByteOutBuflen". If "outByteBuf" is not large enough or if data is malformed, then "FALSE"
* will be returned; otherwise "TRUE". */
static unsigned char decode(XMLCSTR inString, unsigned char *outByteBuf, int inMaxByteOutBuflen, XMLError *xe=NULL); ///< deprecated.
private:
void *buf;
int buflen;
void alloc(int newsize);
}XMLParserBase64Tool;
/** @} */
#undef XMLDLLENTRY
#endif

View File

@ -22,6 +22,8 @@
#include <assert.h>
#include <errno.h>
#include "../src/stdint.hpp"
#include "zmq.h"
#include "org_zmq_Socket.h"
@ -86,80 +88,60 @@ JNIEXPORT void JNICALL Java_org_zmq_Socket_finalize (JNIEnv *env, jobject obj)
assert (rc == 0);
}
JNIEXPORT void JNICALL Java_org_zmq_Socket_setHwm (JNIEnv *env, jobject obj,
jlong hwm)
JNIEXPORT void JNICALL Java_org_zmq_Socket_setsockopt__IJ (JNIEnv *env,
jobject obj, jint option, jlong optval)
{
void *s = (void*) env->GetLongField (obj, socket_handle_fid);
assert (s);
int rc = zmq_setsockopt (s, ZMQ_HWM, &hwm, sizeof hwm);
if (rc == -1)
raise_exception (env, errno);
}
switch (option) {
case ZMQ_HWM:
case ZMQ_LWM:
case ZMQ_SWAP:
case ZMQ_AFFINITY:
case ZMQ_RATE:
case ZMQ_RECOVERY_IVL:
{
void *s = (void*) env->GetLongField (obj, socket_handle_fid);
assert (s);
JNIEXPORT void JNICALL Java_org_zmq_Socket_setLwm (JNIEnv *env, jobject obj,
jlong lwm)
{
void *s = (void*) env->GetLongField (obj, socket_handle_fid);
assert (s);
int rc = zmq_setsockopt (s, ZMQ_LWM, &lwm, sizeof lwm);
if (rc == -1)
raise_exception (env, errno);
}
JNIEXPORT void JNICALL Java_org_zmq_Socket_setSwap (JNIEnv *env, jobject obj,
jlong swap_size)
{
void *s = (void*) env->GetLongField (obj, socket_handle_fid);
assert (s);
int rc = zmq_setsockopt (s, ZMQ_SWAP, &swap_size, sizeof swap_size);
if (rc == -1)
raise_exception (env, errno);
}
JNIEXPORT void JNICALL Java_org_zmq_Socket_setMask (JNIEnv *env, jobject obj,
jlong mask)
{
void *s = (void*) env->GetLongField (obj, socket_handle_fid);
assert (s);
int rc = zmq_setsockopt (s, ZMQ_MASK, &mask, sizeof mask);
if (rc == -1)
raise_exception (env, errno);
}
JNIEXPORT void JNICALL Java_org_zmq_Socket_setAffinity (JNIEnv *env,
jobject obj, jlong affinity)
{
void *s = (void*) env->GetLongField (obj, socket_handle_fid);
assert (s);
int rc = zmq_setsockopt (s, ZMQ_AFFINITY, &affinity, sizeof affinity);
if (rc == -1)
raise_exception (env, errno);
}
JNIEXPORT void JNICALL Java_org_zmq_Socket_setIdentity (JNIEnv *env,
jobject obj, jstring identity)
{
void *s = (void*) env->GetLongField (obj, socket_handle_fid);
assert (s);
if (identity == NULL) {
int64_t value = optval;
int rc = zmq_setsockopt (s, option, &value, sizeof (value));
if (rc != 0)
raise_exception (env, errno);
return;
}
default:
raise_exception (env, EINVAL);
return;
}
}
const char *c_identity = env->GetStringUTFChars (identity, NULL);
if (c_identity == NULL)
JNIEXPORT void JNICALL Java_org_zmq_Socket_setsockopt__ILjava_lang_String_2 (
JNIEnv *env, jobject obj, jint option, jstring optval)
{
switch (option) {
case ZMQ_IDENTITY:
case ZMQ_SUBSCRIBE:
case ZMQ_UNSUBSCRIBE:
{
if (optval == NULL) {
raise_exception (env, EINVAL);
return;
}
void *s = (void*) env->GetLongField (obj, socket_handle_fid);
assert (s);
const char *value = env->GetStringUTFChars (optval, NULL);
assert (value);
int rc = zmq_setsockopt (s, option, value, strlen (value));
env->ReleaseStringUTFChars (optval, value);
if (rc != 0)
raise_exception (env, errno);
return;
}
default:
raise_exception (env, EINVAL);
return;
int rc = zmq_setsockopt (s, ZMQ_IDENTITY, c_identity, sizeof c_identity);
env->ReleaseStringUTFChars (identity, c_identity);
if (rc == -1)
raise_exception (env, errno);
}
}
JNIEXPORT void JNICALL Java_org_zmq_Socket_bind (JNIEnv *env, jobject obj,

View File

@ -27,19 +27,24 @@ public class Socket
}
public static final int NOBLOCK = 1;
public static final int NOFLUSH = 2;
public static final int P2P = 0;
public static final int PUB = 1;
public static final int SUB = 2;
public static final int REQ = 3;
public static final int REP = 4;
public static final int HWM = 1;
public static final int LWM = 2;
public static final int SWAP = 3;
public static final int AFFINITY = 4;
public static final int IDENTITY = 5;
public static final int SUBSCRIBE = 6;
public static final int UNSUBSCRIBE = 7;
public static final int RATE = 8;
public static final int RECOVERY_IVL = 9;
/**
* Class constructor.
*
@ -51,46 +56,13 @@ public class Socket
}
/**
* Set the high watermark on the socket.
* Set the socket option value.
*
* @param hwm high watermark.
* @param option ID of the option to set
* @param optval value to set the option to
*/
public native void setHwm (long hwm);
/**
* Set the low watermark on the socket.
*
* @param lwm low watermark.
*/
public native void setLwm (long lwm);
/**
* Set swap size.
*
* @param swap_size swap size.
*/
public native void setSwap (long swap_size);
/**
* Set reception mask.
*
* @param mask mask.
*/
public native void setMask (long mask);
/**
* Set affinity.
*
* @param affinity
*/
public native void setAffinity (long affinity);
/**
* Set identity.
*
* @param identity
*/
public native void setIdentity (String identity);
public native void setsockopt (int option, long optval);
public native void setsockopt (int option, String optval);
/**
* Bind to network interface. Start listening for new connections.

View File

@ -0,0 +1,174 @@
<?xml version="1.0" encoding="windows-1250"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9.00"
Name="forwarder"
ProjectGUID="{7529DFB2-685C-4534-B40E-0B148509178A}"
RootNamespace="forwarder"
TargetFrameworkVersion="196613"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="../../c;../../cpp"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
WarningLevel="3"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
GenerateDebugInformation="true"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="2"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="2"
EnableIntrinsicFunctions="true"
AdditionalIncludeDirectories="../../c;../../cpp"
RuntimeLibrary="2"
EnableFunctionLevelLinking="true"
WarningLevel="3"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
GenerateDebugInformation="true"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath="..\..\devices\forwarder\forwarder.cpp"
>
</File>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

@ -229,6 +229,10 @@
RelativePath="..\..\src\poll.cpp"
>
</File>
<File
RelativePath="..\..\src\pub.cpp"
>
</File>
<File
RelativePath="..\..\src\select.cpp"
>

View File

@ -73,6 +73,11 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "python", "python\python.vcp
{641C5F36-32EE-4323-B740-992B651CF9D6} = {641C5F36-32EE-4323-B740-992B651CF9D6}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "forwarder", "forwarder\forwarder.vcproj", "{7529DFB2-685C-4534-B40E-0B148509178A}"
ProjectSection(ProjectDependencies) = postProject
{641C5F36-32EE-4323-B740-992B651CF9D6} = {641C5F36-32EE-4323-B740-992B651CF9D6}
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
@ -138,6 +143,10 @@ Global
{CB9B47E2-3F9C-45B2-9C30-C27038CDB856}.Debug|Win32.ActiveCfg = Debug|Win32
{CB9B47E2-3F9C-45B2-9C30-C27038CDB856}.Release|Win32.ActiveCfg = Release|Win32
{CB9B47E2-3F9C-45B2-9C30-C27038CDB856}.Release|Win32.Build.0 = Release|Win32
{7529DFB2-685C-4534-B40E-0B148509178A}.Debug|Win32.ActiveCfg = Debug|Win32
{7529DFB2-685C-4534-B40E-0B148509178A}.Debug|Win32.Build.0 = Debug|Win32
{7529DFB2-685C-4534-B40E-0B148509178A}.Release|Win32.ActiveCfg = Release|Win32
{7529DFB2-685C-4534-B40E-0B148509178A}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -484,9 +484,6 @@ PyMODINIT_FUNC initlibpyzmq ()
t = PyInt_FromLong (ZMQ_SWAP);
PyDict_SetItemString (dict, "SWAP", t);
Py_DECREF (t);
t = PyInt_FromLong (ZMQ_MASK);
PyDict_SetItemString (dict, "MASK", t);
Py_DECREF (t);
t = PyInt_FromLong (ZMQ_AFFINITY);
PyDict_SetItemString (dict, "AFFINITY", t);
Py_DECREF (t);

View File

@ -280,11 +280,12 @@ extern "C" void Init_librbzmq ()
rb_define_global_const ("HWM", INT2NUM (ZMQ_HWM));
rb_define_global_const ("LWM", INT2NUM (ZMQ_LWM));
rb_define_global_const ("SWAP", INT2NUM (ZMQ_SWAP));
rb_define_global_const ("MASK", INT2NUM (ZMQ_MASK));
rb_define_global_const ("AFFINITY", INT2NUM (ZMQ_AFFINITY));
rb_define_global_const ("IDENTITY", INT2NUM (ZMQ_IDENTITY));
rb_define_global_const ("NOBLOCK", INT2NUM (ZMQ_NOBLOCK));
rb_define_global_const ("NOFLUSH", INT2NUM (ZMQ_NOFLUSH));
rb_define_global_const ("P2P", INT2NUM (ZMQ_P2P));
rb_define_global_const ("SUB", INT2NUM (ZMQ_SUB));
rb_define_global_const ("PUB", INT2NUM (ZMQ_PUB));

View File

@ -67,6 +67,7 @@ libzmq_la_SOURCES = $(pgm_sources) \
pipe.hpp \
platform.hpp \
poll.hpp \
pub.hpp \
select.hpp \
session.hpp \
simple_semaphore.hpp \
@ -107,6 +108,7 @@ libzmq_la_SOURCES = $(pgm_sources) \
pgm_socket.cpp \
pipe.cpp \
poll.cpp \
pub.cpp \
select.cpp \
session.cpp \
socket_base.cpp \

View File

@ -35,6 +35,7 @@
#include "pipe.hpp"
#include "config.hpp"
#include "socket_base.hpp"
#include "pub.hpp"
#include "sub.hpp"
// If the RDTSC is available we use it to prevent excessive
@ -138,11 +139,13 @@ zmq::socket_base_t *zmq::app_thread_t::create_socket (int type_)
{
socket_base_t *s = NULL;
switch (type_) {
case ZMQ_PUB:
s = new pub_t (this);
break;
case ZMQ_SUB:
s = new sub_t (this);
break;
case ZMQ_P2P:
case ZMQ_PUB:
case ZMQ_REQ:
case ZMQ_REP:
s = new socket_base_t (this, type_);

View File

@ -23,9 +23,8 @@ zmq::options_t::options_t () :
hwm (0),
lwm (0),
swap (0),
mask (0),
affinity (0),
rate (0),
recovery_ivl (0)
rate (100),
recovery_ivl (10)
{
}

View File

@ -34,7 +34,6 @@ namespace zmq
int64_t hwm;
int64_t lwm;
int64_t swap;
uint64_t mask;
uint64_t affinity;
std::string identity;

39
src/pub.cpp Normal file
View File

@ -0,0 +1,39 @@
/*
Copyright (c) 2007-2009 FastMQ Inc.
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the Lesser GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ 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
Lesser GNU General Public License for more details.
You should have received a copy of the Lesser GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "../c/zmq.h"
#include "pub.hpp"
#include "err.hpp"
zmq::pub_t::pub_t (class app_thread_t *parent_) :
socket_base_t (parent_, ZMQ_SUB)
{
}
zmq::pub_t::~pub_t ()
{
}
int zmq::pub_t::recv (struct zmq_msg_t *msg_, int flags_)
{
errno = EFAULT;
return -1;
}

41
src/pub.hpp Normal file
View File

@ -0,0 +1,41 @@
/*
Copyright (c) 2007-2009 FastMQ Inc.
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the Lesser GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ 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
Lesser GNU General Public License for more details.
You should have received a copy of the Lesser GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_PUB_INCLUDED__
#define __ZMQ_PUB_INCLUDED__
#include "socket_base.hpp"
namespace zmq
{
class pub_t : public socket_base_t
{
public:
pub_t (class app_thread_t *parent_);
~pub_t ();
// Overloads of API functions from socket_base_t.
int recv (struct zmq_msg_t *msg_, int flags_);
};
}
#endif

View File

@ -53,10 +53,10 @@ zmq::select_t::select_t () :
zmq::select_t::~select_t ()
{
worker.stop ();
// Make sure there are no fds registered on shutdown.
zmq_assert (load.get () == 0);
worker.stop ();
}
zmq::handle_t zmq::select_t::add_fd (fd_t fd_, i_poll_events *events_)

View File

@ -123,14 +123,6 @@ int zmq::socket_base_t::setsockopt (int option_, const void *optval_,
options.swap = *((int64_t*) optval_);
return 0;
case ZMQ_MASK:
if (optvallen_ != sizeof (int64_t)) {
errno = EINVAL;
return -1;
}
options.mask = (uint64_t) *((int64_t*) optval_);
return 0;
case ZMQ_AFFINITY:
if (optvallen_ != sizeof (int64_t)) {
errno = EINVAL;
@ -149,19 +141,19 @@ int zmq::socket_base_t::setsockopt (int option_, const void *optval_,
return -1;
case ZMQ_RATE:
if (optvallen_ != sizeof (uint32_t)) {
if (optvallen_ != sizeof (int64_t)) {
errno = EINVAL;
return -1;
}
options.rate = *((int32_t*) optval_);
options.rate = (uint32_t) *((int64_t*) optval_);
return 0;
case ZMQ_RECOVERY_IVL:
if (optvallen_ != sizeof (uint32_t)) {
if (optvallen_ != sizeof (int64_t)) {
errno = EINVAL;
return -1;
}
options.recovery_ivl = *((int32_t*) optval_);
options.recovery_ivl = (uint32_t) *((int64_t*) optval_);
return 0;
default:
@ -287,7 +279,7 @@ int zmq::socket_base_t::connect (const char *addr_)
#endif
// Unknown address type.
errno = ENOTSUP;
errno = EFAULT;
return -1;
}

View File

@ -78,6 +78,18 @@ int zmq::sub_t::setsockopt (int option_, const void *optval_,
return socket_base_t::setsockopt (option_, optval_, optvallen_);
}
int zmq::sub_t::send (struct zmq_msg_t *msg_, int flags_)
{
errno = EFAULT;
return -1;
}
int zmq::sub_t::flush ()
{
errno = EFAULT;
return -1;
}
int zmq::sub_t::recv (struct zmq_msg_t *msg_, int flags_)
{
while (true) {

View File

@ -37,6 +37,8 @@ namespace zmq
// Overloads of API functions from socket_base_t.
int setsockopt (int option_, const void *optval_, size_t optvallen_);
int send (struct zmq_msg_t *msg_, int flags_);
int flush ();
int recv (struct zmq_msg_t *msg_, int flags_);
private:

View File

@ -20,6 +20,7 @@
#include "zmq_decoder.hpp"
#include "i_inout.hpp"
#include "wire.hpp"
#include "err.hpp"
zmq::zmq_decoder_t::zmq_decoder_t () :
destination (NULL)
@ -48,7 +49,11 @@ bool zmq::zmq_decoder_t::one_byte_size_ready ()
if (*tmpbuf == 0xff)
next_step (tmpbuf, 8, &zmq_decoder_t::eight_byte_size_ready);
else {
zmq_msg_init_size (&in_progress, *tmpbuf);
// TODO: Handle over-sized message decently.
int rc = zmq_msg_init_size (&in_progress, *tmpbuf);
errno_assert (rc == 0);
next_step (zmq_msg_data (&in_progress), *tmpbuf,
&zmq_decoder_t::message_ready);
}
@ -60,7 +65,11 @@ bool zmq::zmq_decoder_t::eight_byte_size_ready ()
// 8-byte size is read. Allocate the buffer for message body and
// read the message data into it.
size_t size = (size_t) get_uint64 (tmpbuf);
zmq_msg_init_size (&in_progress, size);
// TODO: Handle over-sized message decently.
int rc = zmq_msg_init_size (&in_progress, size);
errno_assert (rc == 0);
next_step (zmq_msg_data (&in_progress), size,
&zmq_decoder_t::message_ready);
return true;

View File

@ -93,8 +93,11 @@ void zmq::zmq_listener_init_t::flush ()
void zmq::zmq_listener_init_t::detach ()
{
// TODO: Engine is closing down. Init object is to be closed as well.
zmq_assert (false);
// This function is called by engine when disconnection occurs.
// The engine will destroy itself, so we just drop the pointer here and
// start termination of the init object.
engine = NULL;
term ();
}
void zmq::zmq_listener_init_t::process_plug ()