/* Copyright and license information is at the end of the file */

#ifndef XMLRPC_H_INCLUDED
#define XMLRPC_H_INCLUDED

#include <stddef.h>
#include <stdarg.h>
#include <time.h>

#ifdef HAVE_UNICODE_WCHAR
#include <wchar.h>
#endif

#ifdef __cplusplus
extern "C" {
#endif


/*=========================================================================
**  Typedefs
**=========================================================================
**  We define names for these types, because they may change from platform
**  to platform.
*/

typedef signed int xmlrpc_int;  
    /* An integer of the type defined by XML-RPC <int>; i.e. 32 bit */
typedef signed int xmlrpc_int32;
    /* An integer of the type defined by XML-RPC <int4>; i.e. 32 bit */
typedef int xmlrpc_bool;
    /* A boolean (of the type defined by XML-RPC <boolean>, but there's
       really only one kind)
    */
typedef double xmlrpc_double;
    /* A double precision floating point number as defined by
       XML-RPC <float>.  But the C "double" type is universally the same,
       so it's probably clearer just to use that.  This typedef is here 
       for mathematical completeness.
    */

#define XMLRPC_INT32_MAX (2147483647)
#define XMLRPC_INT32_MIN (-XMLRPC_INT32_MAX - 1)



/*=========================================================================
**  C struct size computations
**=======================================================================*/

/* Use XMLRPC_STRUCT_MEMBER_SIZE() to determine how big a structure is
   up to and including a specified member.  E.g. if you have
   struct mystruct {int red; int green; int blue};, then
   XMLRPC_STRUCT_MEMBER_SIZE(mystruct, green) is (8).
*/

#define _XMLRPC_STRUCT_MEMBER_OFFSET(TYPE, MBRNAME) \
  ((unsigned long)(char*)&((TYPE *)0)->MBRNAME)
#define _XMLRPC_STRUCT_MEMBER_SIZE(TYPE, MBRNAME) \
  sizeof(((TYPE *)0)->MBRNAME)
#define XMLRPC_STRUCTSIZE(TYPE, MBRNAME) \
  (_XMLRPC_STRUCT_MEMBER_OFFSET(TYPE, MBRNAME) + \
  _XMLRPC_STRUCT_MEMBER_SIZE(TYPE, MBRNAME))

/*=========================================================================
**  Assertions and Debugging
**=========================================================================
**  Note that an assertion is _not_ a directive to check a condition and
**  crash if it isn't true.  It is an assertion that the condition _is_
**  true.  This assertion helps people to read the code.  The program
**  may also check the assertion as it runs, and if it conflicts with reality,
**  recognize that the program is incorrect and abort it.  In practice,
**  it does this checking when the program was compiled without the NDEBUG
**  macro defined.
*/

#ifndef NDEBUG

#define XMLRPC_ASSERT(cond) \
    do \
        if (!(cond)) \
            xmlrpc_assertion_failed(__FILE__, __LINE__); \
    while (0)

#else
#define XMLRPC_ASSERT(cond) (0)
#endif

extern void xmlrpc_assertion_failed (char* file, int line);

/* Validate a pointer. */
#define XMLRPC_ASSERT_PTR_OK(ptr) \
    XMLRPC_ASSERT((ptr) != NULL)

/* We only call this if something truly drastic happens. */
#define XMLRPC_FATAL_ERROR(msg) xmlrpc_fatal_error(__FILE__, __LINE__, (msg))

extern void xmlrpc_fatal_error (char* file, int line, char* msg);


/*=========================================================================
**  Strings
**=======================================================================*/

/* Traditional C strings are char *, because they come from a time before
   there was 'const'.  Now, const char * makes a lot more sense.  Also,
   in modern times, we tend to dynamically allocate memory for strings.
   We need this free function accordingly.  Ordinary free() doesn't check
   the type, and can generate a warning due to the 'const'.
*/
void
xmlrpc_strfree(const char * const string);



/*=========================================================================
**  xmlrpc_env
**=========================================================================
**  XML-RPC represents runtime errors as <fault> elements. These contain
**  <faultCode> and <faultString> elements.
**
**  Since we need as much thread-safety as possible, we borrow an idea from
**  CORBA--we store exception information in an "environment" object.
**  You'll pass this to many different functions, and it will get filled
**  out appropriately.
**
**  For example:
**
**    xmlrpc_env env;
**
**    xmlrpc_env_init(&env);
**
**    xmlrpc_do_something(&env);
**    if (env.fault_occurred)
**        report_error_appropriately();
**
**    xmlrpc_env_clean(&env);
*/

#define XMLRPC_INTERNAL_ERROR               (-500)
#define XMLRPC_TYPE_ERROR                   (-501)
#define XMLRPC_INDEX_ERROR                  (-502)
#define XMLRPC_PARSE_ERROR                  (-503)
#define XMLRPC_NETWORK_ERROR                (-504)
#define XMLRPC_TIMEOUT_ERROR                (-505)
#define XMLRPC_NO_SUCH_METHOD_ERROR         (-506)
#define XMLRPC_REQUEST_REFUSED_ERROR        (-507)
#define XMLRPC_INTROSPECTION_DISABLED_ERROR (-508)
#define XMLRPC_LIMIT_EXCEEDED_ERROR         (-509)
#define XMLRPC_INVALID_UTF8_ERROR           (-510)

typedef struct _xmlrpc_env {
    int   fault_occurred;
    xmlrpc_int32 fault_code;
    char* fault_string;
} xmlrpc_env;

/* Initialize and destroy the contents of the provided xmlrpc_env object.
** These functions will never fail. */
void xmlrpc_env_init (xmlrpc_env* env);
void xmlrpc_env_clean (xmlrpc_env* env);

/* Fill out an xmlrpc_fault with the specified values, and set the
** fault_occurred flag. This function will make a private copy of 'string',
** so you retain responsibility for your copy. */
void 
xmlrpc_env_set_fault(xmlrpc_env * const env, 
                     int          const faultCode, 
                     const char * const faultDescription);

/* The same as the above, but using a printf-style format string. */
void 
xmlrpc_env_set_fault_formatted (xmlrpc_env * const envP, 
                                int          const code,
                                const char * const format, 
                                ...);

/* This one infers XMLRPC_INTERNAL_ERROR and has a shorter name.
   So a call takes up less source code space.
*/
void
xmlrpc_faultf(xmlrpc_env * const envP,
              const char * const format,
              ...);

/* A simple debugging assertion. */
#define XMLRPC_ASSERT_ENV_OK(env) \
    XMLRPC_ASSERT((env) != NULL && !(env)->fault_occurred)

/* This version must *not* interpret 'str' as a format string, to avoid
** several evil attacks. */
#define XMLRPC_FAIL(env,code,str) \
    do { xmlrpc_env_set_fault((env),(code),(str)); goto cleanup; } while (0)

#define XMLRPC_FAIL1(env,code,str,arg1) \
    do { \
        xmlrpc_env_set_fault_formatted((env),(code),(str),(arg1)); \
        goto cleanup; \
    } while (0)

#define XMLRPC_FAIL2(env,code,str,arg1,arg2) \
    do { \
        xmlrpc_env_set_fault_formatted((env),(code),(str),(arg1),(arg2)); \
        goto cleanup; \
    } while (0)

#define XMLRPC_FAIL3(env,code,str,arg1,arg2,arg3) \
    do { \
        xmlrpc_env_set_fault_formatted((env),(code), \
                                       (str),(arg1),(arg2),(arg3)); \
        goto cleanup; \
    } while (0)

#define XMLRPC_FAIL_IF_NULL(ptr,env,code,str) \
    do { \
        if ((ptr) == NULL) \
            XMLRPC_FAIL((env),(code),(str)); \
    } while (0)

#define XMLRPC_FAIL_IF_FAULT(env) \
    do { if ((env)->fault_occurred) goto cleanup; } while (0)


/*=========================================================================
**  Resource Limits
**=========================================================================
**  To discourage denial-of-service attacks, we provide several adjustable
**  resource limits. These functions are *not* re-entrant.
*/

/* Limit IDs. There will be more of these as time goes on. */
#define XMLRPC_NESTING_LIMIT_ID   (0)
#define XMLRPC_XML_SIZE_LIMIT_ID  (1)
#define XMLRPC_LAST_LIMIT_ID      (XMLRPC_XML_SIZE_LIMIT_ID)

/* By default, deserialized data may be no more than 64 levels deep. */
#define XMLRPC_NESTING_LIMIT_DEFAULT  (64)

/* By default, XML data from the network may be no larger than 512K.
** Some client and server modules may fail to enforce this properly. */
#define XMLRPC_XML_SIZE_LIMIT_DEFAULT (512*1024)

/* Set a specific limit to the specified value. */
extern void xmlrpc_limit_set (int limit_id, size_t value);

/* Get the value of a specified limit. */
extern size_t xmlrpc_limit_get (int limit_id);


/*=========================================================================
**  xmlrpc_mem_block
**=========================================================================
**  A resizable chunk of memory. This is mostly used internally, but it is
**  also used by the public API in a few places.
**  The struct fields are private!
*/

typedef struct _xmlrpc_mem_block {
    size_t _size;
    size_t _allocated;
    void*  _block;
} xmlrpc_mem_block;

/* Allocate a new xmlrpc_mem_block. */
xmlrpc_mem_block* xmlrpc_mem_block_new (xmlrpc_env* env, size_t size);

/* Destroy an existing xmlrpc_mem_block, and everything it contains. */
void xmlrpc_mem_block_free (xmlrpc_mem_block* block);

/* Initialize the contents of the provided xmlrpc_mem_block. */
void xmlrpc_mem_block_init
    (xmlrpc_env* env, xmlrpc_mem_block* block, size_t size);

/* Deallocate the contents of the provided xmlrpc_mem_block, but not the
** block itself. */
void xmlrpc_mem_block_clean (xmlrpc_mem_block* block);

/* Get the size and contents of the xmlrpc_mem_block. */
size_t 
xmlrpc_mem_block_size(const xmlrpc_mem_block * const block);

void * 
xmlrpc_mem_block_contents(const xmlrpc_mem_block * const block);

/* Resize an xmlrpc_mem_block, preserving as much of the contents as
** possible. */
void xmlrpc_mem_block_resize
    (xmlrpc_env* env, xmlrpc_mem_block* block, size_t size);

/* Append data to an existing xmlrpc_mem_block. */
void xmlrpc_mem_block_append
    (xmlrpc_env* env, xmlrpc_mem_block* block, const void *data, size_t len);

#define XMLRPC_MEMBLOCK_NEW(type,env,size) \
    xmlrpc_mem_block_new((env), sizeof(type) * (size))
#define XMLRPC_MEMBLOCK_FREE(type,block) \
    xmlrpc_mem_block_free(block)
#define XMLRPC_MEMBLOCK_INIT(type,env,block,size) \
    xmlrpc_mem_block_init((env), (block), sizeof(type) * (size))
#define XMLRPC_MEMBLOCK_CLEAN(type,block) \
    xmlrpc_mem_block_clean(block)
#define XMLRPC_MEMBLOCK_SIZE(type,block) \
    (xmlrpc_mem_block_size(block) / sizeof(type))
#define XMLRPC_MEMBLOCK_CONTENTS(type,block) \
    ((type*) xmlrpc_mem_block_contents(block))
#define XMLRPC_MEMBLOCK_RESIZE(type,env,block,size) \
    xmlrpc_mem_block_resize(env, block, sizeof(type) * (size))
#define XMLRPC_MEMBLOCK_APPEND(type,env,block,data,size) \
    xmlrpc_mem_block_append(env, block, data, sizeof(type) * (size))

/* Here are some backward compatibility definitions.  These longer names
   used to be the only ones and typed memory blocks were considered
   special.
*/
#define XMLRPC_TYPED_MEM_BLOCK_NEW(type,env,size) \
    XMLRPC_MEMBLOCK_NEW(type,env,size)
#define XMLRPC_TYPED_MEM_BLOCK_FREE(type,block) \
    XMLRPC_MEMBLOCK_FREE(type,block)
#define XMLRPC_TYPED_MEM_BLOCK_INIT(type,env,block,size) \
    XMLRPC_MEMBLOCK_INIT(type,env,block,size)
#define XMLRPC_TYPED_MEM_BLOCK_CLEAN(type,block) \
    XMLRPC_MEMBLOCK_CLEAN(type,block)
#define XMLRPC_TYPED_MEM_BLOCK_SIZE(type,block) \
    XMLRPC_MEMBLOCK_SIZE(type,block)
#define XMLRPC_TYPED_MEM_BLOCK_CONTENTS(type,block) \
    XMLRPC_MEMBLOCK_CONTENTS(type,block)
#define XMLRPC_TYPED_MEM_BLOCK_RESIZE(type,env,block,size) \
    XMLRPC_MEMBLOCK_RESIZE(type,env,block,size)
#define XMLRPC_TYPED_MEM_BLOCK_APPEND(type,env,block,data,size) \
    XMLRPC_MEMBLOCK_APPEND(type,env,block,data,size)



/*=========================================================================
**  xmlrpc_value
**=========================================================================
**  An XML-RPC value (of any type).
*/

typedef enum {
    XMLRPC_TYPE_INT      = 0,
    XMLRPC_TYPE_BOOL     = 1,
    XMLRPC_TYPE_DOUBLE   = 2,
    XMLRPC_TYPE_DATETIME = 3,
    XMLRPC_TYPE_STRING   = 4,
    XMLRPC_TYPE_BASE64   = 5,
    XMLRPC_TYPE_ARRAY    = 6,
    XMLRPC_TYPE_STRUCT   = 7,
    XMLRPC_TYPE_C_PTR    = 8,
    XMLRPC_TYPE_NIL      = 9,
    XMLRPC_TYPE_DEAD     = 0xDEAD
} xmlrpc_type;

/* These are *always* allocated on the heap. No exceptions. */
typedef struct _xmlrpc_value xmlrpc_value;

void
xmlrpc_abort_if_array_bad(xmlrpc_value * const arrayP);

#define XMLRPC_ASSERT_ARRAY_OK(val) \
    xmlrpc_abort_if_array_bad(val)

/* Increment the reference count of an xmlrpc_value. */
extern void xmlrpc_INCREF (xmlrpc_value* value);

/* Decrement the reference count of an xmlrpc_value. If there
** are no more references, free it. */
extern void xmlrpc_DECREF (xmlrpc_value* value);

/* Get the type of an XML-RPC value. */
extern xmlrpc_type xmlrpc_value_type (xmlrpc_value* value);

xmlrpc_value *
xmlrpc_int_new(xmlrpc_env * const envP,
               int          const intValue);

void 
xmlrpc_read_int(xmlrpc_env *         const envP,
                const xmlrpc_value * const valueP,
                int *                const intValueP);

xmlrpc_value *
xmlrpc_bool_new(xmlrpc_env * const envP,
                xmlrpc_bool  const boolValue);

void
xmlrpc_read_bool(xmlrpc_env *         const envP,
                 const xmlrpc_value * const valueP,
                 xmlrpc_bool *        const boolValueP);

xmlrpc_value *
xmlrpc_double_new(xmlrpc_env * const envP,
                  double       const doubleValue);

void
xmlrpc_read_double(xmlrpc_env *         const envP,
                   const xmlrpc_value * const valueP,
                   xmlrpc_double *      const doubleValueP);

xmlrpc_value *
xmlrpc_datetime_new_str(xmlrpc_env * const envP,
                        const char * const value);

xmlrpc_value *
xmlrpc_datetime_new_sec(xmlrpc_env * const envP, 
                        time_t       const value);

void
xmlrpc_read_datetime_str(xmlrpc_env *         const envP,
                         const xmlrpc_value * const valueP,
                         const char **        const stringValueP);

void
xmlrpc_read_datetime_sec(xmlrpc_env *         const envP,
                         const xmlrpc_value * const valueP,
                         time_t *             const timeValueP);

xmlrpc_value *
xmlrpc_string_new(xmlrpc_env * const envP,
                  const char * const stringValue);

xmlrpc_value *
xmlrpc_string_new_lp(xmlrpc_env * const envP, 
                     size_t       const length,
                     const char * const stringValue);

void
xmlrpc_read_string(xmlrpc_env *         const envP,
                   const xmlrpc_value * const valueP,
                   const char **        const stringValueP);


void
xmlrpc_read_string_lp(xmlrpc_env *         const envP,
                      const xmlrpc_value * const valueP,
                      size_t *             const lengthP,
                      const char **        const stringValueP);

#ifdef HAVE_UNICODE_WCHAR
xmlrpc_value *
xmlrpc_string_w_new(xmlrpc_env *    const envP,
                    const wchar_t * const stringValue);

xmlrpc_value *
xmlrpc_string_w_new_lp(xmlrpc_env *    const envP, 
                       size_t          const length,
                       const wchar_t * const stringValue);

void
xmlrpc_read_string_w(xmlrpc_env *     const envP,
                     xmlrpc_value *   const valueP,
                     const wchar_t ** const stringValueP);

void
xmlrpc_read_string_w_lp(xmlrpc_env *     const envP,
                        xmlrpc_value *   const valueP,
                        size_t *         const lengthP,
                        const wchar_t ** const stringValueP);
#endif

xmlrpc_value *
xmlrpc_base64_new(xmlrpc_env *          const envP, 
                  size_t                const length,
                  const unsigned char * const value);

void
xmlrpc_read_base64(xmlrpc_env *           const envP,
                   const xmlrpc_value *   const valueP,
                   size_t *               const lengthP,
                   const unsigned char ** const bytestringValueP);

void
xmlrpc_read_base64_size(xmlrpc_env *           const envP,
                        const xmlrpc_value *   const valueP,
                        size_t *               const lengthP);

xmlrpc_value *
xmlrpc_array_new(xmlrpc_env * const envP);

/* Return the number of elements in an XML-RPC array.
** Sets XMLRPC_TYPE_ERROR if 'array' is not an array. */
int 
xmlrpc_array_size(xmlrpc_env *         const env, 
                  const xmlrpc_value * const array);

/* Append an item to an XML-RPC array.
** Sets XMLRPC_TYPE_ERROR if 'array' is not an array. */
extern void
xmlrpc_array_append_item (xmlrpc_env   * envP,
                          xmlrpc_value * arrayP,
                          xmlrpc_value * valueP);

void
xmlrpc_array_read_item(xmlrpc_env *         const envP,
                       const xmlrpc_value * const arrayP,
                       unsigned int         const index,
                       xmlrpc_value **      const valuePP);

/* Deprecated.  Use xmlrpc_array_read_item() instead.

   Get an item from an XML-RPC array.
   Does not increment the reference count of the returned value.
   Sets XMLRPC_TYPE_ERROR if 'array' is not an array.
   Sets XMLRPC_INDEX_ERROR if 'index' is out of bounds.
*/
xmlrpc_value * 
xmlrpc_array_get_item(xmlrpc_env *         const envP,
                      const xmlrpc_value * const arrayP,
                      int                  const index);

/* Not implemented--we don't need it yet.
extern 
int xmlrpc_array_set_item (xmlrpc_env* env,
xmlrpc_value* array,
int index,
                                  xmlrpc_value* value);
*/

void
xmlrpc_read_nil(xmlrpc_env *   const envP,
                xmlrpc_value * const valueP);
                

void
xmlrpc_read_cptr(xmlrpc_env *         const envP,
                 const xmlrpc_value * const valueP,
                 void **              const ptrValueP);

xmlrpc_value *
xmlrpc_struct_new(xmlrpc_env * env);

/* Return the number of key/value pairs in a struct.
** Sets XMLRPC_TYPE_ERROR if 'strct' is not a struct. */
int
xmlrpc_struct_size (xmlrpc_env   * env, 
                    xmlrpc_value * strct);

/* Returns true iff 'strct' contains 'key'.
** Sets XMLRPC_TYPE_ERROR if 'strct' is not a struct. */
int 
xmlrpc_struct_has_key(xmlrpc_env *   const envP,
                      xmlrpc_value * const strctP,
                      const char *   const key);

/* The same as the above, but the key may contain zero bytes.
   Deprecated.  xmlrpc_struct_get_value_v() is more general, and this
   case is not common enough to warrant a shortcut.
*/
int 
xmlrpc_struct_has_key_n(xmlrpc_env   * const envP,
                        xmlrpc_value * const strctP,
                        const char *   const key, 
                        size_t         const key_len);

#if 0
/* Not implemented yet, but needed for completeness. */
int
xmlrpc_struct_has_key_v(xmlrpc_env *   env, 
                        xmlrpc_value * strct,
                        xmlrpc_value * const keyval);
#endif


void
xmlrpc_struct_find_value(xmlrpc_env *    const envP,
                         xmlrpc_value *  const structP,
                         const char *    const key,
                         xmlrpc_value ** const valuePP);


void
xmlrpc_struct_find_value_v(xmlrpc_env *    const envP,
                           xmlrpc_value *  const structP,
                           xmlrpc_value *  const keyP,
                           xmlrpc_value ** const valuePP);

void
xmlrpc_struct_read_value_v(xmlrpc_env *    const envP,
                           xmlrpc_value *  const structP,
                           xmlrpc_value *  const keyP,
                           xmlrpc_value ** const valuePP);

void
xmlrpc_struct_read_value(xmlrpc_env *    const envP,
                         xmlrpc_value *  const strctP,
                         const char *    const key,
                         xmlrpc_value ** const valuePP);

/* The "get_value" functions are deprecated.  Use the "find_value"
   and "read_value" functions instead.
*/
xmlrpc_value * 
xmlrpc_struct_get_value(xmlrpc_env *   const envP,
                        xmlrpc_value * const strctP,
                        const char *   const key);

/* The same as above, but the key may contain zero bytes. 
   Deprecated.  xmlrpc_struct_get_value_v() is more general, and this
   case is not common enough to warrant a shortcut.
*/
xmlrpc_value * 
xmlrpc_struct_get_value_n(xmlrpc_env *   const envP,
                          xmlrpc_value * const strctP,
                          const char *   const key, 
                          size_t         const key_len);

/* Set the value associated with 'key' in 'strct' to 'value'.
   Sets XMLRPC_TYPE_ERROR if 'strct' is not a struct. 
*/
void 
xmlrpc_struct_set_value(xmlrpc_env *   const env,
                        xmlrpc_value * const strct,
                        const char *   const key,
                        xmlrpc_value * const value);

/* The same as above, but the key may contain zero bytes.  Deprecated.
   The general way to set a structure value is xmlrpc_struct_set_value_v(),
   and this case is not common enough to deserve a shortcut.
*/
void 
xmlrpc_struct_set_value_n(xmlrpc_env *    const env,
                          xmlrpc_value *  const strct,
                          const char *    const key, 
                          size_t          const key_len,
                          xmlrpc_value *  const value);

/* The same as above, but the key must be an XML-RPC string.
** Fails with XMLRPC_TYPE_ERROR if 'keyval' is not a string. */
void 
xmlrpc_struct_set_value_v(xmlrpc_env *   const env,
                          xmlrpc_value * const strct,
                          xmlrpc_value * const keyval,
                          xmlrpc_value * const value);

/* Given a zero-based index, return the matching key and value. This
** is normally used in conjunction with xmlrpc_struct_size.
** Fails with XMLRPC_TYPE_ERROR if 'struct' is not a struct.
** Fails with XMLRPC_INDEX_ERROR if 'index' is out of bounds. */

void 
xmlrpc_struct_read_member(xmlrpc_env *    const envP,
                          xmlrpc_value *  const structP,
                          unsigned int    const index,
                          xmlrpc_value ** const keyvalP,
                          xmlrpc_value ** const valueP);

/* The same as above, but does not increment the reference count of the
   two values it returns, and return NULL for both if it fails, and
   takes a signed integer for the index (but fails if it is negative).

   Deprecated.  Use xmlrpc_struct_read_member() instead.
*/
void
xmlrpc_struct_get_key_and_value(xmlrpc_env *    env,
                                xmlrpc_value *  strct,
                                int             index,
                                xmlrpc_value ** out_keyval,
                                xmlrpc_value ** out_value);

xmlrpc_value *
xmlrpc_cptr_new(xmlrpc_env * const envP,
                void *       const value);

xmlrpc_value *
xmlrpc_nil_new(xmlrpc_env * const envP);


/* Build an xmlrpc_value from a format string. */

xmlrpc_value * 
xmlrpc_build_value(xmlrpc_env * const env,
                   const char * const format, 
                   ...);

/* The same as the above, but using a va_list and more general */
void
xmlrpc_build_value_va(xmlrpc_env *    const env,
                      const char *    const format,
                      va_list               args,
                      xmlrpc_value ** const valPP,
                      const char **   const tailP);

void 
xmlrpc_decompose_value(xmlrpc_env *   const envP,
                       xmlrpc_value * const value,
                       const char *   const format, 
                       ...);

void 
xmlrpc_decompose_value_va(xmlrpc_env *   const envP,
                          xmlrpc_value * const value,
                          const char *   const format,
                          va_list              args);

/* xmlrpc_parse_value... is the same as xmlrpc_decompose_value... except
   that it doesn't do proper memory management -- it returns xmlrpc_value's
   without incrementing the reference count and returns pointers to data
   inside an xmlrpc_value structure.

   These are deprecated.  Use xmlrpc_decompose_value... instead.
*/
void 
xmlrpc_parse_value(xmlrpc_env *   const envP,
                   xmlrpc_value * const value,
                   const char *   const format, 
                   ...);

/* The same as the above, but using a va_list. */
void 
xmlrpc_parse_value_va(xmlrpc_env *   const envP,
                      xmlrpc_value * const value,
                      const char *   const format,
                      va_list              args);

/*=========================================================================
**  Encoding XML
**=======================================================================*/

/* Serialize an XML value without any XML header. This is primarily used
** for testing purposes. */
void
xmlrpc_serialize_value(xmlrpc_env *       env,
                       xmlrpc_mem_block * output,
                       xmlrpc_value *     value);

/* Serialize a list of parameters without any XML header. This is
** primarily used for testing purposes. */
void
xmlrpc_serialize_params(xmlrpc_env *       env,
                        xmlrpc_mem_block * output,
                        xmlrpc_value *     param_array);

/* Serialize an XML-RPC call. */
void 
xmlrpc_serialize_call (xmlrpc_env *       const env,
                       xmlrpc_mem_block * const output,
                       const char *       const method_name,
                       xmlrpc_value *     const param_array);

/* Serialize an XML-RPC return value. */
extern void
xmlrpc_serialize_response(xmlrpc_env *       env,
                          xmlrpc_mem_block * output,
                          xmlrpc_value *     value);

/* Serialize an XML-RPC fault (as specified by 'fault'). */
extern void
xmlrpc_serialize_fault(xmlrpc_env *       env,
                       xmlrpc_mem_block * output,
                       xmlrpc_env *       fault);


/*=========================================================================
**  Decoding XML
**=======================================================================*/

/* Parse an XML-RPC call. If an error occurs, set a fault and set
** the output variables to NULL.
** The caller is responsible for calling free(*out_method_name) and
** xmlrpc_DECREF(*out_param_array). */
void 
xmlrpc_parse_call(xmlrpc_env *    const envP,
                  const char *    const xml_data,
                  size_t          const xml_len,
                  const char **   const out_method_name,
                  xmlrpc_value ** const out_param_array);

/* Parse an XML-RPC response. If a fault occurs (or was received over the
** wire), return NULL and set up 'env'. The calling is responsible for
** calling xmlrpc_DECREF on the return value (if it isn't NULL). */
xmlrpc_value *
xmlrpc_parse_response(xmlrpc_env * env, 
                      const char * xml_data, 
                      size_t       xml_len);


/*=========================================================================
**  XML-RPC Base64 Utilities
**=========================================================================
**  Here are some lightweight utilities which can be used to encode and
**  decode Base64 data. These are exported mainly for testing purposes.
*/

/* This routine inserts newlines every 76 characters, as required by the
** Base64 specification. */
xmlrpc_mem_block *
xmlrpc_base64_encode(xmlrpc_env *    env,
                     unsigned char * bin_data,
                     size_t          bin_len);

/* This routine encodes everything in one line. This is needed for HTTP
** authentication and similar tasks. */
xmlrpc_mem_block *
xmlrpc_base64_encode_without_newlines(xmlrpc_env *    env,
                                      unsigned char * bin_data,
                                      size_t          bin_len);

/* This decodes Base64 data with or without newlines. */
extern xmlrpc_mem_block *
xmlrpc_base64_decode(xmlrpc_env * const envP,
                     const char * const ascii_data,
                     size_t       const ascii_len);


/*=========================================================================
**  UTF-8 Encoding and Decoding
**=========================================================================
**  We need a correct, reliable and secure UTF-8 decoder. This decoder
**  raises a fault if it encounters invalid UTF-8.
**
**  Note that ANSI C does not precisely define the representation used
**  by wchar_t--it may be UCS-2, UTF-16, UCS-4, or something from outer
**  space. If your platform does something especially bizarre, you may
**  need to reimplement these routines.
*/

#ifdef HAVE_UNICODE_WCHAR

/* Ensure that a string contains valid, legally-encoded UTF-8 data.
** (Incorrectly-encoded UTF-8 strings are often used to bypass security
** checks.) */
void 
xmlrpc_validate_utf8 (xmlrpc_env * const env,
                      const char * const utf8_data,
                      size_t       const utf8_len);

/* Decode a UTF-8 string. */
xmlrpc_mem_block *
xmlrpc_utf8_to_wcs(xmlrpc_env * env,
                   char *       utf8_data,
                   size_t       utf8_len);

/* Encode a UTF-8 string. */
xmlrpc_mem_block *
xmlrpc_wcs_to_utf8(xmlrpc_env * env,
                   wchar_t *    wcs_data,
                   size_t       wcs_len);

#endif /* HAVE_UNICODE_WCHAR */

/*=========================================================================
**  Authorization Cookie Handling
**=========================================================================
**  Routines to get and set values for authorizing via authorization
**  cookies. Both the client and server use HTTP_COOKIE_AUTH to store
**  the representation of the authorization value, which is actually
**  just a base64 hash of username:password. (This entire method is
**  a cookie replacement of basic authentication.)
**/

extern void xmlrpc_authcookie_set(xmlrpc_env * env,
                                  const char * username,
                                  const char * password);

char *xmlrpc_authcookie(void);

#ifdef __cplusplus
}
#endif

/* Copyright (C) 2001 by First Peer, Inc. All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
** 1. Redistributions of source code must retain the above copyright
**    notice, this list of conditions and the following disclaimer.
** 2. 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.
** 3. The name of the author may not be used to endorse or promote products
**    derived from this software without specific prior written permission. 
**  
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS 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. */

#endif

