root/ext/fdf/fdf.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ZEND_GET_MODULE
  2. phpi_FDFClose
  3. PHP_GINIT_FUNCTION
  4. PHP_MINIT_FUNCTION
  5. PHP_RINIT_FUNCTION
  6. PHP_MINFO_FUNCTION
  7. PHP_MSHUTDOWN_FUNCTION
  8. PHP_FUNCTION
  9. PHP_FUNCTION
  10. PHP_FUNCTION
  11. PHP_FUNCTION
  12. PHP_FUNCTION
  13. PHP_FUNCTION
  14. PHP_FUNCTION
  15. PHP_FUNCTION
  16. PHP_FUNCTION
  17. PHP_FUNCTION
  18. PHP_FUNCTION
  19. PHP_FUNCTION
  20. PHP_FUNCTION
  21. PHP_FUNCTION
  22. PHP_FUNCTION
  23. PHP_FUNCTION
  24. PHP_FUNCTION
  25. PHP_FUNCTION
  26. PHP_FUNCTION
  27. PHP_FUNCTION
  28. PHP_FUNCTION
  29. PHP_FUNCTION
  30. PHP_FUNCTION
  31. PHP_FUNCTION
  32. SAPI_POST_HANDLER_FUNC
  33. PHP_FUNCTION
  34. PHP_FUNCTION
  35. PHP_FUNCTION
  36. PHP_FUNCTION
  37. PHP_FUNCTION
  38. PHP_FUNCTION
  39. PHP_FUNCTION
  40. PHP_FUNCTION
  41. PHP_FUNCTION
  42. enum_values_callback
  43. PHP_FUNCTION
  44. PHP_FUNCTION

/*
   +----------------------------------------------------------------------+
   | PHP Version 5                                                        |
   +----------------------------------------------------------------------+
   | Copyright (c) 1997-2008 The PHP Group                                |
   +----------------------------------------------------------------------+
   | This source file is subject to version 3.01 of the PHP license,      |
   | that is bundled with this package in the file LICENSE, and is        |
   | available through the world-wide-web at the following url:           |
   | http://www.php.net/license/3_01.txt                                  |
   | If you did not receive a copy of the PHP license and are unable to   |
   | obtain it through the world-wide-web, please send a note to          |
   | license@php.net so we can mail you a copy immediately.               |
   +----------------------------------------------------------------------+
   | Authors: Uwe Steinmann <Uwe.Steinmann@fernuni-hagen.de>              |
   |          Hartmut Holzgraefe <hholzgra@php.net>                       |
   +----------------------------------------------------------------------+
 */

/* $Id: fdf.c,v 1.89.2.2.2.10 2007/12/31 07:20:06 sebastian Exp $ */

/* FdfTk lib 2.0 is a Complete C/C++ FDF Toolkit available from
   http://beta1.adobe.com/ada/acrosdk/forms.html. */

/* Note that there is no code from the FdfTk lib in this file */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "php.h"
#include "php_open_temporary_file.h"

#if HAVE_FDFLIB

#include "SAPI.h"
#include "ext/standard/info.h"
#include "php_open_temporary_file.h"
#include "php_variables.h"
#include "php_fdf.h"

#ifndef S_ISDIR
#define S_ISDIR(m) (((m) & _S_IFDIR) == _S_IFDIR)
#endif

static int le_fdf;

SAPI_POST_HANDLER_FUNC(fdf_post_handler);

/* {{{ arginfo */
static
ZEND_BEGIN_ARG_INFO(arginfo_fdf_open, 0)
        ZEND_ARG_INFO(0, filename)
ZEND_END_ARG_INFO()

static
ZEND_BEGIN_ARG_INFO(arginfo_fdf_open_string, 0)
        ZEND_ARG_INFO(0, fdf_data)
ZEND_END_ARG_INFO()

static
ZEND_BEGIN_ARG_INFO(arginfo_fdf_create, 0)
ZEND_END_ARG_INFO()

static
ZEND_BEGIN_ARG_INFO(arginfo_fdf_close, 0)
        ZEND_ARG_INFO(0, fdfdoc)
ZEND_END_ARG_INFO()

static
ZEND_BEGIN_ARG_INFO_EX(arginfo_fdf_get_value, 0, 0, 2)
        ZEND_ARG_INFO(0, fdfdoc)
        ZEND_ARG_INFO(0, fieldname)
        ZEND_ARG_INFO(0, which)
ZEND_END_ARG_INFO()

static
ZEND_BEGIN_ARG_INFO_EX(arginfo_fdf_set_value, 0, 0, 3)
        ZEND_ARG_INFO(0, fdfdoc)
        ZEND_ARG_INFO(0, fieldname)
        ZEND_ARG_INFO(0, value)
        ZEND_ARG_INFO(0, isname)
ZEND_END_ARG_INFO()

static
ZEND_BEGIN_ARG_INFO_EX(arginfo_fdf_next_field_name, 0, 0, 1)
        ZEND_ARG_INFO(0, fdfdoc)
        ZEND_ARG_INFO(0, fieldname)
ZEND_END_ARG_INFO()

static
ZEND_BEGIN_ARG_INFO(arginfo_fdf_set_ap, 0)
        ZEND_ARG_INFO(0, fdfdoc)
        ZEND_ARG_INFO(0, fieldname)
        ZEND_ARG_INFO(0, face)
        ZEND_ARG_INFO(0, filename)
        ZEND_ARG_INFO(0, pagenr)
ZEND_END_ARG_INFO()

static
ZEND_BEGIN_ARG_INFO(arginfo_fdf_get_ap, 0)
        ZEND_ARG_INFO(0, fdfdoc)
        ZEND_ARG_INFO(0, fieldname)
        ZEND_ARG_INFO(0, face)
        ZEND_ARG_INFO(0, filename)
ZEND_END_ARG_INFO()

static
ZEND_BEGIN_ARG_INFO(arginfo_fdf_get_encoding, 0)
        ZEND_ARG_INFO(0, fdfdoc)
ZEND_END_ARG_INFO()

static
ZEND_BEGIN_ARG_INFO(arginfo_fdf_set_status, 0)
        ZEND_ARG_INFO(0, fdfdoc)
        ZEND_ARG_INFO(0, status)
ZEND_END_ARG_INFO()

static
ZEND_BEGIN_ARG_INFO(arginfo_fdf_get_status, 0)
        ZEND_ARG_INFO(0, fdfdoc)
ZEND_END_ARG_INFO()

static
ZEND_BEGIN_ARG_INFO_EX(arginfo_fdf_set_file, 0, 0, 2)
        ZEND_ARG_INFO(0, fdfdoc)
        ZEND_ARG_INFO(0, filename)
        ZEND_ARG_INFO(0, target_frame)
ZEND_END_ARG_INFO()

static
ZEND_BEGIN_ARG_INFO(arginfo_fdf_get_file, 0)
        ZEND_ARG_INFO(0, fdfdoc)
ZEND_END_ARG_INFO()

static
ZEND_BEGIN_ARG_INFO_EX(arginfo_fdf_save, 0, 0, 1)
        ZEND_ARG_INFO(0, fdfdoc)
        ZEND_ARG_INFO(0, filename)
ZEND_END_ARG_INFO()

static
ZEND_BEGIN_ARG_INFO(arginfo_fdf_save_string, 0)
        ZEND_ARG_INFO(0, fdfdoc)
ZEND_END_ARG_INFO()

static
ZEND_BEGIN_ARG_INFO(arginfo_fdf_add_template, 0)
        ZEND_ARG_INFO(0, fdfdoc)
        ZEND_ARG_INFO(0, newpage)
        ZEND_ARG_INFO(0, filename)
        ZEND_ARG_INFO(0, template)
        ZEND_ARG_INFO(0, rename)
ZEND_END_ARG_INFO()

static
ZEND_BEGIN_ARG_INFO(arginfo_fdf_set_flags, 0)
        ZEND_ARG_INFO(0, fdfdoc)
        ZEND_ARG_INFO(0, fieldname)
        ZEND_ARG_INFO(0, whichflags)
        ZEND_ARG_INFO(0, newflags)
ZEND_END_ARG_INFO()

static
ZEND_BEGIN_ARG_INFO(arginfo_fdf_get_flags, 0)
        ZEND_ARG_INFO(0, fdfdoc)
        ZEND_ARG_INFO(0, fieldname)
        ZEND_ARG_INFO(0, whichflags)
ZEND_END_ARG_INFO()

static
ZEND_BEGIN_ARG_INFO(arginfo_fdf_set_opt, 0)
        ZEND_ARG_INFO(0, fdfdoc)
        ZEND_ARG_INFO(0, fieldname)
        ZEND_ARG_INFO(0, element)
        ZEND_ARG_INFO(0, value)
        ZEND_ARG_INFO(0, name)
ZEND_END_ARG_INFO()

static
ZEND_BEGIN_ARG_INFO_EX(arginfo_fdf_get_opt, 0, 0, 2)
        ZEND_ARG_INFO(0, fdfdof)
        ZEND_ARG_INFO(0, fieldname)
        ZEND_ARG_INFO(0, element)
ZEND_END_ARG_INFO()

static
ZEND_BEGIN_ARG_INFO(arginfo_fdf_set_submit_form_action, 0)
        ZEND_ARG_INFO(0, fdfdoc)
        ZEND_ARG_INFO(0, fieldname)
        ZEND_ARG_INFO(0, whichtrigger)
        ZEND_ARG_INFO(0, url)
        ZEND_ARG_INFO(0, flags)
ZEND_END_ARG_INFO()

static
ZEND_BEGIN_ARG_INFO(arginfo_fdf_set_javascript_action, 0)
        ZEND_ARG_INFO(0, fdfdoc)
        ZEND_ARG_INFO(0, fieldname)
        ZEND_ARG_INFO(0, whichtrigger)
        ZEND_ARG_INFO(0, script)
ZEND_END_ARG_INFO()

static
ZEND_BEGIN_ARG_INFO(arginfo_fdf_set_encoding, 0)
        ZEND_ARG_INFO(0, fdf_document)
        ZEND_ARG_INFO(0, encoding)
ZEND_END_ARG_INFO()

static
ZEND_BEGIN_ARG_INFO(arginfo_fdf_errno, 0)
ZEND_END_ARG_INFO()

static
ZEND_BEGIN_ARG_INFO(arginfo_fdf_error, 0)
        ZEND_ARG_INFO(0, errno)
ZEND_END_ARG_INFO()

static
ZEND_BEGIN_ARG_INFO_EX(arginfo_fdf_get_version, 0, 0, 0)
        ZEND_ARG_INFO(0, fdfdoc)
ZEND_END_ARG_INFO()

static
ZEND_BEGIN_ARG_INFO(arginfo_fdf_set_version, 0)
        ZEND_ARG_INFO(0, fdfdoc)
        ZEND_ARG_INFO(0, version)
ZEND_END_ARG_INFO()

static
ZEND_BEGIN_ARG_INFO(arginfo_fdf_add_doc_javascript, 0)
        ZEND_ARG_INFO(0, fdfdoc)
        ZEND_ARG_INFO(0, scriptname)
        ZEND_ARG_INFO(0, script)
ZEND_END_ARG_INFO()

static
ZEND_BEGIN_ARG_INFO(arginfo_fdf_set_on_import_javascript, 0)
        ZEND_ARG_INFO(0, fdfdoc)
        ZEND_ARG_INFO(0, script)
        ZEND_ARG_INFO(0, before_data_import)
ZEND_END_ARG_INFO()

static
ZEND_BEGIN_ARG_INFO(arginfo_fdf_set_target_frame, 0)
        ZEND_ARG_INFO(0, fdfdoc)
        ZEND_ARG_INFO(0, target)
ZEND_END_ARG_INFO()

static
ZEND_BEGIN_ARG_INFO(arginfo_fdf_remove_item, 0)
        ZEND_ARG_INFO(0, fdfdoc)
        ZEND_ARG_INFO(0, fieldname)
        ZEND_ARG_INFO(0, item)
ZEND_END_ARG_INFO()

static
ZEND_BEGIN_ARG_INFO(arginfo_fdf_get_attachment, 0)
        ZEND_ARG_INFO(0, fdfdoc)
        ZEND_ARG_INFO(0, fieldname)
        ZEND_ARG_INFO(0, savepath)
ZEND_END_ARG_INFO()

static
ZEND_BEGIN_ARG_INFO_EX(arginfo_fdf_enum_values, 0, 0, 2)
        ZEND_ARG_INFO(0, fdfdoc)
        ZEND_ARG_INFO(0, function)
        ZEND_ARG_INFO(0, userdata)
ZEND_END_ARG_INFO()

static
ZEND_BEGIN_ARG_INFO(arginfo_fdf_header, 0)
ZEND_END_ARG_INFO()

/* }}} */

/* {{{ fdf_functions[]
 */
zend_function_entry fdf_functions[] = {
        PHP_FE(fdf_add_template,                                                arginfo_fdf_add_template)
        PHP_FE(fdf_close,                                                               arginfo_fdf_close)
        PHP_FE(fdf_create,                                                              arginfo_fdf_create)
        PHP_FE(fdf_enum_values,                         arginfo_fdf_enum_values)
        PHP_FE(fdf_errno,                                                       arginfo_fdf_errno)
        PHP_FE(fdf_error,                                                       arginfo_fdf_error)
        PHP_FE(fdf_get_ap,                                                              arginfo_fdf_get_ap)
        PHP_FE(fdf_get_encoding,                                                arginfo_fdf_get_encoding)
        PHP_FE(fdf_get_file,                                                    arginfo_fdf_get_file)
        PHP_FE(fdf_get_flags,                                                   arginfo_fdf_get_flags)
        PHP_FE(fdf_get_opt,                                                             arginfo_fdf_get_opt)
        PHP_FE(fdf_get_status,                                                  arginfo_fdf_get_status)
        PHP_FE(fdf_get_value,                                                   arginfo_fdf_get_value)
        PHP_FE(fdf_get_version,                         arginfo_fdf_get_version)
        PHP_FE(fdf_next_field_name,                                             arginfo_fdf_next_field_name)
        PHP_FE(fdf_open,                                                                arginfo_fdf_open)
        PHP_FE(fdf_open_string,                                                 arginfo_fdf_open_string)
        PHP_FE(fdf_remove_item,                         arginfo_fdf_remove_item)
        PHP_FE(fdf_save,                                                                arginfo_fdf_save)
        PHP_FE(fdf_save_string,                                         arginfo_fdf_save_string)
        PHP_FE(fdf_set_ap,                                                              arginfo_fdf_set_ap)
        PHP_FE(fdf_set_encoding,                                                arginfo_fdf_set_encoding)
        PHP_FE(fdf_set_file,                                                    arginfo_fdf_set_file)
        PHP_FE(fdf_set_flags,                                                   arginfo_fdf_set_flags)
        PHP_FE(fdf_set_javascript_action,                               arginfo_fdf_set_javascript_action)
        PHP_FE(fdf_set_opt,                                                             arginfo_fdf_set_opt)
        PHP_FE(fdf_set_status,                                                  arginfo_fdf_set_status)
        PHP_FE(fdf_set_submit_form_action,                              arginfo_fdf_set_submit_form_action)
        PHP_FE(fdf_set_value,                                                   arginfo_fdf_set_value)
        PHP_FE(fdf_header,                              arginfo_fdf_header)
#ifdef HAVE_FDFTK_5
        PHP_FE(fdf_add_doc_javascript,                  arginfo_fdf_add_doc_javascript)
        PHP_FE(fdf_get_attachment,                      arginfo_fdf_get_attachment)
        PHP_FE(fdf_set_on_import_javascript,            arginfo_fdf_set_on_import_javascript)
        PHP_FE(fdf_set_target_frame,                    arginfo_fdf_set_target_frame)
        PHP_FE(fdf_set_version,                         arginfo_fdf_set_version)
#endif
        {NULL, NULL, NULL}
};
/* }}} */

ZEND_DECLARE_MODULE_GLOBALS(fdf)
static PHP_GINIT_FUNCTION(fdf);

zend_module_entry fdf_module_entry = {
    STANDARD_MODULE_HEADER,
        "fdf", 
        fdf_functions, 
        PHP_MINIT(fdf), 
        PHP_MSHUTDOWN(fdf), 
        PHP_RINIT(fdf), 
        NULL,
        PHP_MINFO(fdf), 
    NO_VERSION_YET,
    PHP_MODULE_GLOBALS(fdf),
    PHP_GINIT(fdf),
    NULL,
    NULL,
        STANDARD_MODULE_PROPERTIES_EX
};

#ifdef COMPILE_DL_FDF
ZEND_GET_MODULE(fdf)
#endif

#define FDF_SUCCESS do { FDF_G(error)=FDFErcOK; RETURN_TRUE;} while(0)
#define FDF_FAILURE(err)  do { FDF_G(error)=err; RETURN_FALSE;} while(0)

static void phpi_FDFClose(zend_rsrc_list_entry *rsrc TSRMLS_DC)
{
        FDFDoc fdf = (FDFDoc)rsrc->ptr;

        (void) FDFClose(fdf);
}

#define FDF_POST_CONTENT_TYPE   "application/vnd.fdf"

static sapi_post_entry php_fdf_post_entry =     {
        FDF_POST_CONTENT_TYPE,
        sizeof(FDF_POST_CONTENT_TYPE)-1,
        sapi_read_standard_form_data,
        fdf_post_handler
};

static PHP_GINIT_FUNCTION(fdf)
{
        memset(fdf_globals, 0, sizeof(*fdf_globals));
}



/* {{{ PHP_MINIT_FUNCTION
 */
PHP_MINIT_FUNCTION(fdf)
{
        le_fdf = zend_register_list_destructors_ex(phpi_FDFClose, NULL, "fdf", module_number);

        /* add handler for Acrobat FDF form post requests */
        sapi_register_post_entry(&php_fdf_post_entry TSRMLS_CC);


        /* Constants used by fdf_set_opt() */ 
        REGISTER_LONG_CONSTANT("FDFValue", FDFValue, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("FDFStatus", FDFStatus, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("FDFFile", FDFFile, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("FDFID", FDFID, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("FDFFf", FDFFf, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("FDFSetFf", FDFSetFf, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("FDFClearFf", FDFClearFf, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("FDFFlags", FDFFlags, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("FDFSetF", FDFSetF, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("FDFClrF", FDFClrF, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("FDFAP", FDFAP, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("FDFAS", FDFAS, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("FDFAction", FDFAction, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("FDFAA", FDFAA, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("FDFAPRef", FDFAPRef, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("FDFIF", FDFIF, CONST_CS | CONST_PERSISTENT);

        /* Constants used by fdf_set_javascript_action() */
        REGISTER_LONG_CONSTANT("FDFEnter", FDFEnter, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("FDFExit", FDFExit, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("FDFDown", FDFDown, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("FDFUp", FDFUp, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("FDFFormat", FDFFormat, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("FDFValidate", FDFValidate, CONST_CS | CONST_PERSISTENT);

        REGISTER_LONG_CONSTANT("FDFKeystroke", FDFKeystroke, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("FDFCalculate", FDFCalculate, CONST_CS | CONST_PERSISTENT);

        /* Constants used by fdf_(set|get)_ap */
        REGISTER_LONG_CONSTANT("FDFNormalAP", 1, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("FDFRolloverAP", 2, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("FDFDownAP", 3, CONST_CS | CONST_PERSISTENT);

#ifdef PHP_WIN32
        return SUCCESS;
#else
        return (FDFInitialize() == FDFErcOK) ? SUCCESS : FAILURE;
#endif
}
/* }}} */

/* {{{ RINIT */
PHP_RINIT_FUNCTION(fdf)
{
        FDF_G(error) = FDFErcOK;
        return SUCCESS;
}
/* }}} */

/* {{{ PHP_MINFO_FUNCTION
 */
PHP_MINFO_FUNCTION(fdf)
{
        /* need to use a PHPAPI function here because it is external module in windows */
        php_info_print_table_start();
        php_info_print_table_row(2, "FDF Support", "enabled");
        php_info_print_table_row(2, "FdfTk Version", FDFGetVersion() );
        php_info_print_table_end();
}
/* }}} */

/* {{{ PHP_MSHUTDOWN_FUNCTION
 */
PHP_MSHUTDOWN_FUNCTION(fdf)
{
        /* remove handler for Acrobat FDF form post requests */
        sapi_unregister_post_entry(&php_fdf_post_entry TSRMLS_CC); 

#ifdef PHP_WIN32
        return SUCCESS;
#else
        return (FDFFinalize() == FDFErcOK) ? SUCCESS : FAILURE;
#endif
}
/* }}} */

/* {{{ proto resource fdf_open(string filename)
   Opens a new FDF document */
PHP_FUNCTION(fdf_open) 
{
        zval **file;
        FDFDoc fdf;
        FDFErc err;

        if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &file) == FAILURE) {
                WRONG_PARAM_COUNT;
        }

        convert_to_string_ex(file);

        if (php_check_open_basedir(Z_STRVAL_PP(file) TSRMLS_CC) || (PG(safe_mode) && !php_checkuid(Z_STRVAL_PP(file), "wb+", CHECKUID_CHECK_MODE_PARAM))) {
                RETURN_FALSE;
        }

        err = FDFOpen(Z_STRVAL_PP(file), 0, &fdf);

        if(err != FDFErcOK || !fdf) {
                if(err == FDFErcOK) err= FDFErcInternalError;
                FDF_FAILURE(err);
        }

        ZEND_REGISTER_RESOURCE(return_value, fdf, le_fdf);
} 
/* }}} */

/* {{{ proto resource fdf_open_string(string fdf_data)
   Opens a new FDF document from string */
PHP_FUNCTION(fdf_open_string) 
{
        char *fdf_data;
        int fdf_data_len;
        FDFDoc fdf;
        FDFErc err;
        char *temp_filename;
        FILE *fp;

        if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s",
                                                         &fdf_data, &fdf_data_len) 
           == FAILURE) {
                return;
        }

        fp = php_open_temporary_file(PG(upload_tmp_dir), "php", &temp_filename TSRMLS_CC);
        if(!fp) {
                RETURN_FALSE;
        }
        fwrite(fdf_data, fdf_data_len, 1, fp);
        fclose(fp);

        err = FDFOpen(temp_filename, 0, &fdf);
        unlink(temp_filename);
        efree(temp_filename);

        if(err != FDFErcOK || !fdf) {
                if(err == FDFErcOK) err= FDFErcInternalError;
                FDF_FAILURE(err);
        }

        ZEND_REGISTER_RESOURCE(return_value, fdf, le_fdf);
} 
/* }}} */

/* {{{ proto resource fdf_create(void)
   Creates a new FDF document */
PHP_FUNCTION(fdf_create) 
{
        FDFDoc fdf;
        FDFErc err;

        if (ZEND_NUM_ARGS() != 0) {
                WRONG_PARAM_COUNT;
        }

        err = FDFCreate(&fdf);

        if(err != FDFErcOK || !fdf) {
                if(err == FDFErcOK) err= FDFErcInternalError;
                FDF_FAILURE(err);
        }

        ZEND_REGISTER_RESOURCE(return_value, fdf, le_fdf);
}
/* }}} */

/* {{{ proto void fdf_close(resource fdfdoc)
   Closes the FDF document */
PHP_FUNCTION(fdf_close) 
{
        zval **fdfp;
        FDFDoc fdf;

        if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &fdfp) == FAILURE) {
                WRONG_PARAM_COUNT;
        }

        ZEND_FETCH_RESOURCE(fdf, FDFDoc *, fdfp, -1, "fdf", le_fdf);
        zend_list_delete(Z_RESVAL_PP(fdfp));
} 
/* }}} */

/* {{{ proto string fdf_get_value(resource fdfdoc, string fieldname [, int which])
   Gets the value of a field as string */
PHP_FUNCTION(fdf_get_value) 
{
        zval *r_fdf;
        char *fieldname;
        int fieldname_len;
        long which = -1;
        FDFDoc fdf;
        FDFErc err;
        ASInt32 nr, size = 256;
        char *buffer;

        if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|l",
                                                         &r_fdf, &fieldname, &fieldname_len,
                                                         &which) 
           == FAILURE) {
                return;
        }

        ZEND_FETCH_RESOURCE(fdf, FDFDoc *, &r_fdf, -1, "fdf", le_fdf);

        buffer = emalloc(size);
        if(which >= 0) {
#if HAVE_FDFTK_5
                err = FDFGetNthValue(fdf, fieldname, which, buffer, size-2, &nr);
#else
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "the optional 'which' parameter requires FDF toolkit 5.0 or above, it will be ignored for now");
                which = -1;
#endif
        } else {
                err = FDFGetValue(fdf, fieldname, buffer, size-2, &nr);
        }
        if(err == FDFErcBufTooShort && nr > 0 ) {
                buffer = erealloc(buffer, nr+2); 
                if(which >= 0) {
#if HAVE_FDFTK_5
                        err = FDFGetNthValue(fdf, fieldname, which, buffer, nr, &nr);
#endif
                } else {
                        err = FDFGetValue(fdf, fieldname, buffer, nr, &nr);
                } 
#if HAVE_FDFTK_5
        } else if((err == FDFErcValueIsArray) && (which == -1)) {
                array_init(return_value);
                which = 0;
                do {
                        err = FDFGetNthValue(fdf, fieldname, which, buffer, size-2, &nr); 
                        if(err == FDFErcBufTooShort && nr > 0 ) {
                                buffer = erealloc(buffer, nr+2); 
                                err = FDFGetNthValue(fdf, fieldname, which, buffer, nr, &nr);
                        } 
                        if (err == FDFErcOK) {
                                add_next_index_string(return_value, buffer, 1);
                        } 
                        which++;
                } while (err == FDFErcOK);
                efree(buffer); 
                buffer = NULL;
#endif
        }

        if((err != FDFErcOK) && (err != FDFErcNoValue)) {
                if(buffer) efree(buffer);
                FDF_FAILURE(err);
        }

        if(buffer) {
                RETVAL_STRING(buffer, 1);
                efree(buffer);
        }

        return;
}
/* }}} */

/* {{{ proto bool fdf_set_value(resource fdfdoc, string fieldname, mixed value [, int isname])
   Sets the value of a field */
PHP_FUNCTION(fdf_set_value) 
{
        zval **fdfp, **fieldname, **value, **dummy;
        FDFDoc fdf;
        FDFErc err;

        switch(ZEND_NUM_ARGS()) {
        case 3:
                if (zend_get_parameters_ex(3, &fdfp, &fieldname, &value) == FAILURE) {
                        WRONG_PARAM_COUNT;
                }
                break;
        case 4:
                if (zend_get_parameters_ex(4, &fdfp, &fieldname, &value, &dummy) == FAILURE) {
                        WRONG_PARAM_COUNT;
                }
                break;
        default:
                WRONG_PARAM_COUNT;
        }

        ZEND_FETCH_RESOURCE(fdf, FDFDoc *, fdfp, -1, "fdf", le_fdf);

        convert_to_string_ex(fieldname);

        if (Z_TYPE_PP(value) == IS_ARRAY) {
#ifdef HAVE_FDFTK_5
                ASInt32 nValues = zend_hash_num_elements(Z_ARRVAL_PP(value));
                char **newValues = ecalloc(nValues, sizeof(char *)), **next;
                HashPosition   pos;
                zval         **tmp;

                next = newValues;
                zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(value), &pos);
                while (zend_hash_get_current_data_ex(Z_ARRVAL_PP(value), 
                                                                                         (void **) &tmp,
                                                                                         &pos) == SUCCESS) {
                        convert_to_string_ex(tmp);
                        *next++ = estrdup(Z_STRVAL_PP(tmp));
                        zend_hash_move_forward_ex(Z_ARRVAL_PP(value), &pos);
                }

                err = FDFSetValues(fdf, Z_STRVAL_PP(fieldname), nValues, (const char **)newValues);
                
                for(next = newValues; nValues; nValues--) {
                        efree(*next++);
                }
                efree(newValues);
#else
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "setting array values is only possible with FDF toolkit 5.0 and above");
                RETURN_FALSE;
#endif
        } else {
                convert_to_string_ex(value);
                
                err = FDFSetValue(fdf, Z_STRVAL_PP(fieldname), Z_STRVAL_PP(value), (ASBool)0 /*dummy*/);
        }
        if(err != FDFErcOK) {
                FDF_FAILURE(err);
        }
        FDF_SUCCESS;
}
/* }}} */

/* {{{ proto string fdf_next_field_name(resource fdfdoc [, string fieldname])
   Gets the name of the next field name or the first field name */
PHP_FUNCTION(fdf_next_field_name) 
{
        zval **fdfp, **field;
        int argc=ZEND_NUM_ARGS();
        ASInt32 length=256, nr;
        char *buffer=NULL, *fieldname=NULL;
        FDFDoc fdf;
        FDFErc err;

        if (argc > 2 || argc < 1 || zend_get_parameters_ex(argc, &fdfp, &field) == FAILURE) {
                WRONG_PARAM_COUNT;
        }

        ZEND_FETCH_RESOURCE(fdf, FDFDoc *, fdfp, -1, "fdf", le_fdf);

        if(argc == 2) {
                convert_to_string_ex(field);
                fieldname = Z_STRVAL_PP(field);
        }

        buffer = emalloc(length);
        err = FDFNextFieldName(fdf, fieldname, buffer, length-1, &nr);

        if(err == FDFErcBufTooShort && nr > 0 ) {
                buffer = erealloc(buffer, nr+1); 
                err = FDFNextFieldName(fdf, fieldname, buffer, length-1, &nr);
        } 

        if(err != FDFErcOK) {
                efree(buffer);
                FDF_FAILURE(err);
        } 

        RETVAL_STRING(buffer, 1);
        efree(buffer);
}
/* }}} */

/* {{{ proto bool fdf_set_ap(resource fdfdoc, string fieldname, int face, string filename, int pagenr)
   Sets the appearence of a field */
PHP_FUNCTION(fdf_set_ap) 
{
        zval **fdfp, **fieldname, **face, **filename, **pagenr;
        FDFDoc fdf;
        FDFErc err;
        FDFAppFace facenr;

        if (ZEND_NUM_ARGS() != 5 || zend_get_parameters_ex(5, &fdfp, &fieldname, &face, &filename, &pagenr) == FAILURE) {
                WRONG_PARAM_COUNT;
        }

        ZEND_FETCH_RESOURCE(fdf, FDFDoc *, fdfp, -1, "fdf", le_fdf);

        convert_to_string_ex(fieldname);
        convert_to_long_ex(face);
        convert_to_string_ex(filename);

        if (php_check_open_basedir(Z_STRVAL_PP(filename) TSRMLS_CC) || (PG(safe_mode) && !php_checkuid(Z_STRVAL_PP(filename), "wb+", CHECKUID_CHECK_MODE_PARAM))) {
                RETURN_FALSE;
        }

        convert_to_long_ex(pagenr);

        switch(Z_LVAL_PP(face)) {
                case 1:
                        facenr = FDFNormalAP;
                        break;
                case 2:
                        facenr = FDFRolloverAP;
                        break;
                case 3:
                        facenr = FDFDownAP;
                        break;
                default:
                        facenr = FDFNormalAP;
                        break;
        }

        err = FDFSetAP(fdf, Z_STRVAL_PP(fieldname), facenr, NULL, Z_STRVAL_PP(filename), (ASInt32) Z_LVAL_PP(pagenr));

        /* This should be made more intelligent, ie. use switch() with the 
           possible errors this function can return. Or create global error handler function.
         */
        if(err != FDFErcOK) {
                FDF_FAILURE(err);
        }

        FDF_SUCCESS;

}
/* }}} */

/* {{{ proto bool fdf_get_ap(resource fdfdoc, string fieldname, int face, string filename) 
         Gets the appearance of a field and creates a PDF document out of it. */
PHP_FUNCTION(fdf_get_ap) {
        zval *r_fdf;
        char *fieldname, *filename;
        int fieldname_len, filename_len;
        long face;
        FDFDoc fdf;
        FDFErc err;
        FDFAppFace facenr;

        if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsls",
                                                         &r_fdf, &fieldname, &fieldname_len,
                                                         &face, &filename, &filename_len) 
           == FAILURE) {
                return;
        }

        ZEND_FETCH_RESOURCE(fdf, FDFDoc *, &r_fdf, -1, "fdf", le_fdf);

        if (php_check_open_basedir(filename TSRMLS_CC) || (PG(safe_mode) && !php_checkuid(filename, "wb+", CHECKUID_CHECK_MODE_PARAM))) {
                RETURN_FALSE;
        }

        switch(face) {
                case 1:
                        facenr = FDFNormalAP;
                        break;
                case 2:
                        facenr = FDFRolloverAP;
                        break;
                case 3:
                        facenr = FDFDownAP;
                        break;
                default:
                        facenr = FDFNormalAP;
                        break;
        }

        err = FDFGetAP(fdf, fieldname, facenr, filename);

        /* This should be made more intelligent, ie. use switch() with the 
           possible errors this function can return. Or create global error handler function.
         */
        if(err != FDFErcOK) {
                FDF_FAILURE(err);
        }

        FDF_SUCCESS;

        
}
/* }}} */

/* {{{ proto string fdf_get_encoding(resource fdf) 
   Gets FDF file encoding scheme */
PHP_FUNCTION(fdf_get_encoding) {
        zval *r_fdf;
        FDFDoc fdf;
        FDFErc err;
        char buffer[32];
        ASInt32 len;

        if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r",
                                                         &r_fdf) == FAILURE) {
                return;
        }

        ZEND_FETCH_RESOURCE(fdf, FDFDoc *, &r_fdf, -1, "fdf", le_fdf);

        err = FDFGetEncoding(fdf, buffer, 32, &len);

        /* This should be made more intelligent, ie. use switch() with the 
           possible errors this function can return. Or create global error handler function.
         */
        if(err != FDFErcOK) {
                FDF_FAILURE(err);
        }
        
        FDF_G(error) = FDFErcOK;
        RETURN_STRINGL(buffer, (size_t)len, 1);
}
/* }}} */

/* {{{ proto bool fdf_set_status(resource fdfdoc, string status)
   Sets the value of /Status key */
PHP_FUNCTION(fdf_set_status) 
{
        zval **fdfp, **status;
        FDFDoc fdf;
        FDFErc err;

        if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &fdfp, &status) == FAILURE) {
                WRONG_PARAM_COUNT;
        }

        ZEND_FETCH_RESOURCE(fdf, FDFDoc *, fdfp, -1, "fdf", le_fdf);

        convert_to_string_ex(status);

        err = FDFSetStatus(fdf, Z_STRVAL_PP(status));
        if(err != FDFErcOK) {
                FDF_FAILURE(err);
        }

        FDF_SUCCESS;
}
/* }}} */

/* {{{ proto string fdf_get_status(resource fdfdoc)
   Gets the value of /Status key */
PHP_FUNCTION(fdf_get_status) 
{
        zval **fdfp;
        ASInt32 nr, size = 256;
        char *buf;
        FDFDoc fdf;
        FDFErc err;

        if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &fdfp) == FAILURE) {
                WRONG_PARAM_COUNT;
        }

        ZEND_FETCH_RESOURCE(fdf, FDFDoc *, fdfp, -1, "fdf", le_fdf);

        buf = emalloc(size);
        err = FDFGetStatus(fdf, buf, size-1,  &nr);

        if(err == FDFErcBufTooShort && nr > 0 ) {
                buf = erealloc(buf, nr+1); 
                err = FDFGetStatus(fdf, buf, size-1,  &nr);
        }
        
        if(err != FDFErcOK) {
                efree(buf);
                FDF_FAILURE(err);
        }

        RETVAL_STRING(buf, 1);
        efree(buf);
}
/* }}} */

/* {{{ proto bool fdf_set_file(resource fdfdoc, string filename [, string target_frame])
   Sets the value of /F key */
PHP_FUNCTION(fdf_set_file) 
{
        zval *r_fdf;
        char *filename, *target_frame= NULL;
        int filename_len, target_frame_len;
        FDFDoc fdf;
        FDFErc err;

        if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|s", &r_fdf, 
                                                         &filename, &filename_len,
                                                         &target_frame, &target_frame_len)
           == FAILURE) {
                return;
        }

        if (php_check_open_basedir(filename TSRMLS_CC) || (PG(safe_mode) && !php_checkuid(filename, "wb+", CHECKUID_CHECK_MODE_PARAM))) {
                RETURN_FALSE;
        }

        ZEND_FETCH_RESOURCE(fdf, FDFDoc *, &r_fdf, -1, "fdf", le_fdf);

        err = FDFSetFile(fdf, filename);
        if(err != FDFErcOK) {
                FDF_FAILURE(err);
        }
        if(target_frame) {
#ifdef HAVE_FDFTK_5
                err = FDFSetTargetFrame(fdf, target_frame);
                if(err != FDFErcOK) {
                        FDF_FAILURE(err);
                }
#else
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "setting the target frame is only possible with FDF toolkit 5.0 and above, ignoring it for now");
#endif
        }

        FDF_SUCCESS;
}
/* }}} */

/* {{{ proto string fdf_get_file(resource fdfdoc)
   Gets the value of /F key */
PHP_FUNCTION(fdf_get_file) 
{
        zval **fdfp;
        ASInt32 nr, size = 256;
        char *buf;
        FDFDoc fdf;
        FDFErc err;

        if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &fdfp) == FAILURE) {
                WRONG_PARAM_COUNT;
        }

        ZEND_FETCH_RESOURCE(fdf, FDFDoc *, fdfp, -1, "fdf", le_fdf);

        buf = emalloc(size);
        err = FDFGetFile(fdf, buf, size-1,  &nr);

        if(err == FDFErcBufTooShort && nr > 0 ) {
                buf = erealloc(buf, nr+1); 
                err = FDFGetFile(fdf, buf, size-1,  &nr);
        }
        
        if(err != FDFErcOK) {
                efree(buf);
                FDF_FAILURE(err);
        }

        RETVAL_STRING(buf, 1);
        efree(buf);
}
/* }}} */

/* {{{ proto bool fdf_save(resource fdfdoc [, string filename])
   Writes out the FDF file */
PHP_FUNCTION(fdf_save) 
{
        zval *r_fdf;
        char *filename = NULL;
        int filename_len;
        FDFDoc fdf;
        FDFErc err;

        if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|s", &r_fdf, &filename, &filename_len)
           == FAILURE) {
                return;
        }

        ZEND_FETCH_RESOURCE(fdf, FDFDoc *, &r_fdf, -1, "fdf", le_fdf);

        if(filename) {
                if (php_check_open_basedir(filename TSRMLS_CC) || (PG(safe_mode) && !php_checkuid(filename, "wb+", CHECKUID_CHECK_MODE_PARAM))) {
                        RETURN_FALSE;
                }
                err = FDFSave(fdf, filename);   
        } else {
                FILE *fp;
                char *temp_filename;

                fp = php_open_temporary_file(PG(upload_tmp_dir), "php", &temp_filename TSRMLS_CC);
                if(!fp) {
                        err = FDFErcFileSysErr;
                } else {
                        fclose(fp);
                        err = FDFSave(fdf, temp_filename);

                        if(err == FDFErcOK) {
                                php_stream *stream = php_stream_open_wrapper(temp_filename, "rb", 0, NULL);
                                if (stream)     {
                                        php_stream_passthru(stream);
                                        php_stream_close(stream);
                                } else {
                                        err = FDFErcFileSysErr;
                                }       
                        }
                }
                if(temp_filename) {
                        unlink(temp_filename);
                        efree(temp_filename);
                }
        }

        if(err != FDFErcOK) {
                FDF_FAILURE(err);
        }
        
        FDF_SUCCESS;
} 
/* }}} */

/* {{{ proto string fdf_save_string(resource fdfdoc)
   Returns the FDF file as a string */
PHP_FUNCTION(fdf_save_string) 
{
        zval *r_fdf;
        FDFDoc fdf;
        FDFErc err;
        FILE *fp;
        char *temp_filename = NULL;

        if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &r_fdf)
           == FAILURE) {
                return;
        }

        ZEND_FETCH_RESOURCE(fdf, FDFDoc *, &r_fdf, -1, "fdf", le_fdf);

        fp = php_open_temporary_file(PG(upload_tmp_dir), "php", &temp_filename TSRMLS_CC);
        if(!fp) {
                err = FDFErcFileSysErr;
        } else {
                fclose(fp);
                err = FDFSave(fdf, temp_filename);

                if(err == FDFErcOK) {
                        fp = fopen(temp_filename, "rb");
                        if (fp) {
                                struct stat stat;
                                char *buf;

                                if (fstat(fileno(fp), &stat) == -1) {
                                        RETVAL_FALSE;
                                        goto err;
                                }
                                buf = safe_emalloc(1, stat.st_size, 1);
                                fread(buf, stat.st_size, 1, fp);
                                buf[stat.st_size] = '\0';
                                fclose(fp);

                                unlink(temp_filename);
                                efree(temp_filename);
                                RETURN_STRINGL(buf, stat.st_size, 0);
                        } else {
                                err = FDFErcFileSysErr;
                        }       
                }
        }

        if(err != FDFErcOK) {
                FDF_FAILURE(err);
        }
err:
        if(temp_filename) {
                unlink(temp_filename);
                efree(temp_filename);
        }

        return;
} 
/* }}} */

/* {{{ proto bool fdf_add_template(resource fdfdoc, int newpage, string filename, string template, int rename)
   Adds a template into the FDF document */
PHP_FUNCTION(fdf_add_template) 
{
        zval **fdfp, **newpage, **filename, **template, **rename;
        FDFDoc fdf;
        FDFErc err;
        pdfFileSpecRec filespec;

        if (ZEND_NUM_ARGS() != 5 || zend_get_parameters_ex(5, &fdfp, &newpage, &filename, &template, &rename) == FAILURE) {
                WRONG_PARAM_COUNT;
        }

        ZEND_FETCH_RESOURCE(fdf, FDFDoc *, fdfp, -1, "fdf", le_fdf);

        convert_to_long_ex(newpage);
        convert_to_string_ex(filename);
        convert_to_string_ex(template);
        convert_to_long_ex(rename);

        if (php_check_open_basedir(Z_STRVAL_PP(filename) TSRMLS_CC) || (PG(safe_mode) && !php_checkuid(Z_STRVAL_PP(filename), "wb+", CHECKUID_CHECK_MODE_PARAM))) {
                RETURN_FALSE;
        }

        filespec.FS = NULL;
        filespec.F = Z_STRVAL_PP(filename);
        filespec.Mac = NULL;
        filespec.DOS = NULL;
        filespec.Unix = NULL;
        filespec.ID[0] = NULL;
        filespec.ID[1] = NULL;
        filespec.bVolatile = false;

        err = FDFAddTemplate(fdf, (unsigned short)(Z_LVAL_PP(newpage)), &filespec, Z_STRVAL_PP(template), (unsigned short)(Z_LVAL_PP(rename)));
        if(err != FDFErcOK) {
                FDF_FAILURE(err);
        }

        FDF_SUCCESS;
}
/* }}} */

/* {{{ proto bool fdf_set_flags(resource fdfdoc, string fieldname, int whichflags, int newflags)
   Sets flags for a field in the FDF document */
PHP_FUNCTION(fdf_set_flags) 
{
        zval **fdfp, **fieldname, **flags, **newflags;
        FDFDoc fdf;
        FDFErc err;

        if (ZEND_NUM_ARGS() != 4 || zend_get_parameters_ex(4, &fdfp, &fieldname, &flags, &newflags) == FAILURE) {
                WRONG_PARAM_COUNT;
        }

        ZEND_FETCH_RESOURCE(fdf, FDFDoc *, fdfp, -1, "fdf", le_fdf);

        convert_to_string_ex(fieldname);
        convert_to_long_ex(flags);
        convert_to_long_ex(newflags);   

        err=FDFSetFlags(fdf, Z_STRVAL_PP(fieldname), Z_LVAL_PP(flags), Z_LVAL_PP(newflags));
        if(err != FDFErcOK) {
                FDF_FAILURE(err);
        }

        FDF_SUCCESS;
}
/* }}} */

/* {{{ proto int fdf_get_flags(resorce fdfdoc, string fieldname, int whichflags) 
   Gets the flags of a field */
PHP_FUNCTION(fdf_get_flags) {
        zval *r_fdf;
        char *fieldname;
        int fieldname_len;
        long whichflags;
        FDFDoc fdf;
        FDFErc err;
        ASUns32 flags;

        if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsl",
                                                         &r_fdf, &fieldname, &fieldname_len,
                                                         &whichflags) 
           == FAILURE) {
                return;
        }

        ZEND_FETCH_RESOURCE(fdf, FDFDoc *, &r_fdf, -1, "fdf", le_fdf);

        err = FDFGetFlags(fdf, fieldname, (FDFItem)whichflags, &flags);

        if(err != FDFErcOK) {
                FDF_FAILURE(err);
        }

        RETURN_LONG((long)flags);
}
/* }}} */

/* {{{ proto bool fdf_set_opt(resource fdfdoc, string fieldname, int element, string value, string name)
   Sets a value in the opt array for a field */
PHP_FUNCTION(fdf_set_opt)
{
        zval **fdfp, **fieldname, **element, **value, **name;
        FDFDoc fdf;
        FDFErc err;     

        if (ZEND_NUM_ARGS() != 5 || zend_get_parameters_ex(5, &fdfp, &fieldname, &element, &value, &name) == FAILURE) {
                WRONG_PARAM_COUNT;
        }

        ZEND_FETCH_RESOURCE(fdf, FDFDoc *, fdfp, -1, "fdf", le_fdf);

        convert_to_string_ex(fieldname);
        convert_to_long_ex(element);
        convert_to_string_ex(value);
        convert_to_string_ex(name);

        err = FDFSetOpt(fdf, Z_STRVAL_PP(fieldname), Z_LVAL_PP(element), Z_STRVAL_PP(value), Z_STRVAL_PP(name));
        if(err != FDFErcOK) {
                FDF_FAILURE(err);
        }
        FDF_SUCCESS;
}
/* }}} */

/* {{{ proto mixed fdf_get_opt(resource fdfdof, string fieldname [, int element])
   Gets a value from the opt array of a field */
PHP_FUNCTION(fdf_get_opt) {
        zval *r_fdf;
        char *fieldname;
        int fieldname_len;
        long element = -1;
        FDFDoc fdf;
        FDFErc err;

        if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|l",
                                                         &r_fdf, &fieldname, &fieldname_len,
                                                         &element) 
           == FAILURE) {
                return;
        }

        ZEND_FETCH_RESOURCE(fdf, FDFDoc *, &r_fdf, -1, "fdf", le_fdf);

        if(element == -1) {
                ASInt32 elements;
                err = FDFGetOpt(fdf, fieldname, (ASInt32)-1, NULL, NULL, 0, &elements);
                if(err != FDFErcOK) {
                        FDF_FAILURE(err);
                }
                RETURN_LONG((long)elements);
        } else {
                ASInt32 bufSize, nRet;
                char *buf1, *buf2;

                bufSize = 1024; 
                buf1 = emalloc(bufSize);
                buf2 = emalloc(bufSize);

                err = FDFGetOpt(fdf, fieldname, (ASInt32)element, buf1, buf2, bufSize, &nRet);
                if(err == FDFErcBufTooShort) {
                        efree(buf1);
                        efree(buf2);
                        buf1 = emalloc(nRet);
                        buf2 = emalloc(nRet);
                        bufSize = nRet;
                        err = FDFGetOpt(fdf, fieldname, (ASInt32)element, buf1, buf2, bufSize, &nRet);
                }
                if(err != FDFErcOK) {
                        FDF_FAILURE(err);
                }
                array_init(return_value);
                add_next_index_stringl(return_value, buf1, strlen(buf1), 1);
                add_next_index_stringl(return_value, buf2, strlen(buf2), 1);
                efree(buf1);
                efree(buf2);
        }
}
/* }}} */

/* {{{ proto bool fdf_set_submit_form_action(resource fdfdoc, string fieldname, int whichtrigger, string url, int flags)
   Sets the submit form action for a field */
PHP_FUNCTION(fdf_set_submit_form_action) 
{
        zval **fdfp, **fieldname, **trigger, **url, **flags;
        FDFDoc fdf;
        FDFErc err;     

        if (ZEND_NUM_ARGS() != 5 || zend_get_parameters_ex(5, &fdfp, &fieldname, &trigger, &url, &flags) == FAILURE) {
                WRONG_PARAM_COUNT;
        }

        ZEND_FETCH_RESOURCE(fdf, FDFDoc *, fdfp, -1, "fdf", le_fdf);

        convert_to_string_ex(fieldname);
        convert_to_long_ex(trigger);
        convert_to_string_ex(url);
        convert_to_long_ex(flags);

        err = FDFSetSubmitFormAction(fdf, Z_STRVAL_PP(fieldname), Z_LVAL_PP(trigger), Z_STRVAL_PP(url), Z_LVAL_PP(flags));
        if(err != FDFErcOK) {
                FDF_FAILURE(err);
        }
        FDF_SUCCESS;
}
/* }}} */

/* {{{ proto bool fdf_set_javascript_action(resource fdfdoc, string fieldname, int whichtrigger, string script)
   Sets the javascript action for a field */
PHP_FUNCTION(fdf_set_javascript_action) 
{
        zval **fdfp, **fieldname, **trigger, **script;
        FDFDoc fdf;
        FDFErc err;     

        if (ZEND_NUM_ARGS() != 4 || zend_get_parameters_ex(4, &fdfp, &fieldname, &trigger, &script) == FAILURE) {
                WRONG_PARAM_COUNT;
        }

        ZEND_FETCH_RESOURCE(fdf, FDFDoc *, fdfp, -1, "fdf", le_fdf);

        convert_to_string_ex(fieldname);
        convert_to_long_ex(trigger);
        convert_to_string_ex(script);
        
        err = FDFSetJavaScriptAction(fdf, Z_STRVAL_PP(fieldname), Z_LVAL_PP(trigger), Z_STRVAL_PP(script));
        if(err != FDFErcOK) {
                FDF_FAILURE(err);
        }
        FDF_SUCCESS;
}
/* }}} */

/* {{{ proto bool fdf_set_encoding(resource fdf_document, string encoding)
   Sets FDF encoding (either "Shift-JIS" or "Unicode") */  
PHP_FUNCTION(fdf_set_encoding) 
{
        zval **fdfp, **enc;
        FDFDoc fdf;
        FDFErc err;

        if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &fdfp, &enc) == FAILURE) {
                WRONG_PARAM_COUNT;
        }

        ZEND_FETCH_RESOURCE(fdf, FDFDoc *, fdfp, -1, "fdf", le_fdf);

        convert_to_string_ex(enc);

        err = FDFSetEncoding(fdf, Z_STRVAL_PP(enc));
    
        if(err != FDFErcOK) {
                FDF_FAILURE(err);
        }
        FDF_SUCCESS;
}
/* }}} */

/* {{{ SAPI_POST_HANDLER_FUNC
 * SAPI post handler for FDF forms */
SAPI_POST_HANDLER_FUNC(fdf_post_handler)
{
        FILE *fp;
        FDFDoc theFDF;
        char *name=NULL, *value=NULL, *p, *data;
        int name_len=0, value_len=0;
        char *lastfieldname =NULL;
        char *filename = NULL;
        FDFErc err;
        ASInt32 nBytes;
        zval *array_ptr = (zval *) arg;
        
        fp=php_open_temporary_file(NULL, "fdfdata.", &filename TSRMLS_CC);
        if(!fp) {
                if(filename) efree(filename);
                return;
        }
        fwrite(SG(request_info).post_data, SG(request_info).post_data_length, 1, fp);
        fclose(fp);

        /* Set HTTP_FDF_DATA variable */
        data = estrndup(SG(request_info).post_data, SG(request_info).post_data_length);
        SET_VAR_STRINGL("HTTP_FDF_DATA", data, SG(request_info).post_data_length);

        err = FDFOpen(filename, 0, &theFDF);

        if(err==FDFErcOK){      
                name = emalloc(name_len=256);
                value= emalloc(value_len=256);
                while (1) {
                        err = FDFNextFieldName(theFDF, lastfieldname, name, name_len-1, &nBytes);
                        if(err == FDFErcBufTooShort && nBytes >0 ) {
                                name = erealloc(name, name_len=(nBytes+1)); 
                                err = FDFNextFieldName(theFDF, lastfieldname, name, name_len-1, &nBytes);
                        } 
                        
                        if(err != FDFErcOK || nBytes == 0) break; 
                        
                        if(lastfieldname) efree(lastfieldname);
                        lastfieldname = estrdup(name);          

                        err = FDFGetValue(theFDF, name, NULL, 0, &nBytes);                      
                        if(err != FDFErcOK && err != FDFErcNoValue ) break; 

                        if(value_len<nBytes+1) value = erealloc(value, value_len=(nBytes+1));
                        
                        if(nBytes>0) {
                                err = FDFGetValue(theFDF, name, value, value_len-1, &nBytes);
                                if(err == FDFErcOK && nBytes != 0) {
                                        unsigned int new_val_len;

                                        for(p=value;*p;p++) if(*p=='\r') *p='\n';
                                        if(lastfieldname) efree(lastfieldname);
                                        lastfieldname = estrdup(name);

                                        if (sapi_module.input_filter(PARSE_POST, name, &value, nBytes, &new_val_len TSRMLS_CC)) {
                                                php_register_variable_safe(name, value, new_val_len, array_ptr TSRMLS_CC);
                                        }
                                } 
                        }
                }   
                FDFClose(theFDF);

                if(name)          efree(name);
                if(value)         efree(value);
                if(lastfieldname) efree(lastfieldname);
        } 
        VCWD_UNLINK((const char *)filename);
        efree(filename);
}
/* }}} */

/* {{{ proto int fdf_errno(void) 
   Gets error code for last operation */
PHP_FUNCTION(fdf_errno) {
        RETURN_LONG((long)FDF_G(error));
}
/* }}} */

/* {{{ proto string fdf_error([int errno]) 
   Gets error description for error code */
PHP_FUNCTION(fdf_error) {
        FDFErc err;
        long p_err = -1;

        if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &p_err)
           == FAILURE) {
                return;
        }

        err = (p_err >= 0) ? (FDFErc)p_err : FDF_G(error);

        switch(err) {
        case FDFErcOK: 
                RETURN_STRING("no error", 1);
        case FDFErcInternalError: 
                RETURN_STRING("An internal FDF Library error occurred", 1);
        case FDFErcBadParameter: 
                RETURN_STRING("One or more of the parameters passed were invalid. ", 1);
        case FDFErcFileSysErr: 
                RETURN_STRING("A file system error occurred or the file was not found", 1);
        case FDFErcBadFDF: 
                RETURN_STRING("The FDF file being opened or parsed was invalid", 1);
        case FDFErcFieldNotFound: 
                RETURN_STRING("The field whose name was passed in the parameter fieldName does not exist in the FDF file", 1);
        case FDFErcNoValue: 
                RETURN_STRING("The field whose value was requested has no value", 1);
        case FDFErcEnumStopped: 
                RETURN_STRING("Enumeration was stopped by FDFEnumValues by returning FALSE", 1);
        case FDFErcCantInsertField: 
                RETURN_STRING("The field whose name was passed in the parameter fieldName cannot be inserted into the FDF file", 1);
        case FDFErcNoOption: 
                RETURN_STRING("The requested element in a fields /Opt key does not exist, or the field has no /Opt key. ", 1);
        case FDFErcNoFlags: 
                RETURN_STRING("The field has no /F or /Ff keys", 1);
        case FDFErcBadPDF:
                RETURN_STRING("The PDF file passed as the parameter to FDFSetAP was invalid, or did not contain the requested page ", 1);
        case FDFErcBufTooShort: 
                RETURN_STRING("The buffer passed as a parameter was too short", 1);
        case FDFErcNoAP: 
                RETURN_STRING("The field has no /AP key", 1);
        case FDFErcIncompatibleFDF: 
                RETURN_STRING("An attempt to mix classic and template-based FDF files was made", 1);
#ifdef HAVE_FDFTK_5
        case FDFErcNoAppendSaves: 
                RETURN_STRING("The FDF does not include a /Difference key", 1);
        case FDFErcValueIsArray: 
                RETURN_STRING("The value of this field is an array. Use FDFGetNthValue. ", 1);
        case FDFErcEmbeddedFDFs: 
                RETURN_STRING("The FDF you passed as a parameter is a container for one or more FDFs embedded within it. Use FDFOpenFromEmbedded to gain access to each embedded FDF", 1);
        case FDFErcNoMoreFDFs: 
                RETURN_STRING("Returned by FDFOpenFromEmbedded when parameter iWhich >= the number of embedded FDFs (including the case when the passed FDF does not contain any embedded FDFs)", 1);
        case FDFErcInvalidPassword: 
                RETURN_STRING("Returned by FDFOpenFromEmbedded when the embedded FDF is encrypted, and you did not provide the correct password", 1);
#endif
        case FDFErcLast: 
                RETURN_STRING("Reserved for future use", 1);
        default: 
                RETURN_STRING("unknown error", 1);
        }
}
/* }}} */

/* {{{ proto string fdf_get_version([resource fdfdoc]) 
   Gets version number for FDF api or file */
PHP_FUNCTION(fdf_get_version) {
        zval *r_fdf = NULL;

        if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|r", &r_fdf)
           == FAILURE) {
                return;
        }

        if(r_fdf) {
#if HAVE_FDFTK_5
                const char *fdf_version; 
                FDFDoc fdf;

                ZEND_FETCH_RESOURCE(fdf, FDFDoc *, &r_fdf, -1, "fdf", le_fdf);
                fdf_version = FDFGetFDFVersion(fdf);
                RETURN_STRING((char *)fdf_version, 1);
#else
                RETURN_STRING("1.2",1);
#endif
        } else {
                const char *api_version = FDFGetVersion();
                RETURN_STRING((char *)api_version, 1);
        }
}
/* }}} */

#ifdef HAVE_FDFTK_5
/* {{{ proto bool fdf_set_version(resourece fdfdoc, string version)
   Sets FDF version for a file*/
PHP_FUNCTION(fdf_set_version) {
        zval *r_fdf;
        char *version;
        int version_len;
        FDFDoc fdf;
        FDFErc err;
        
        if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &r_fdf, &version, &version_len)
           == FAILURE) {
                return;
        }

        ZEND_FETCH_RESOURCE(fdf, FDFDoc *, &r_fdf, -1, "fdf", le_fdf);

        err = FDFSetFDFVersion(fdf, version);

        if(err != FDFErcOK) {
                FDF_FAILURE(err);
        }
        FDF_SUCCESS;
}
/* }}} */

/* {{{ proto bool fdf_add_doc_javascript(resource fdfdoc, string scriptname, string script) 
         Add javascript code to the fdf file */
PHP_FUNCTION(fdf_add_doc_javascript) {
        zval *r_fdf;
        char *name, *script;
        int name_len, script_len;
        FDFDoc fdf;
        FDFErc err;
        
        if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rss", &r_fdf, 
                                                         &name, &name_len,
                                                         &script, &script_len
                                                         )
           == FAILURE) {
                return;
        }
        
        ZEND_FETCH_RESOURCE(fdf, FDFDoc *, &r_fdf, -1, "fdf", le_fdf);
        
        err = FDFAddDocJavaScript(fdf, name, script);
        
        if(err != FDFErcOK) {
                FDF_FAILURE(err);
        }
        FDF_SUCCESS;
}
/* }}} */

/* {{{ proto bool fdf_set_on_import_javascript(resource fdfdoc, string script, bool before_data_import)
   Adds javascript code to be executed when Acrobat opens the FDF */
PHP_FUNCTION(fdf_set_on_import_javascript) {
        zval *r_fdf;
        char *script;
        int script_len;
        zend_bool before;
        FDFDoc fdf;
        FDFErc err;
        
        if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsb", &r_fdf, 
                                                         &script, &script_len, &before
                                                         )
           == FAILURE) {
                return;
        }
        
        ZEND_FETCH_RESOURCE(fdf, FDFDoc *, &r_fdf, -1, "fdf", le_fdf);
        
        err = FDFSetOnImportJavaScript(fdf, script, before);
        
        if(err != FDFErcOK) {
                FDF_FAILURE(err);
        }
        FDF_SUCCESS;
} 
/* }}} */

/* {{{ proto bool fdf_set_target_frame(resource fdfdoc, string target)
   Sets target frame for form */
PHP_FUNCTION(fdf_set_target_frame) {
        zval *r_fdf;
        char *target;
        int target_len;
        FDFDoc fdf;
        FDFErc err;
        
        if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &r_fdf, 
                                                         &target, &target_len
                                                         )
           == FAILURE) {
                return;
        }
        
        ZEND_FETCH_RESOURCE(fdf, FDFDoc *, &r_fdf, -1, "fdf", le_fdf);
        
        err = FDFSetTargetFrame(fdf, target);
        
        if(err != FDFErcOK) {
                FDF_FAILURE(err);
        }
        FDF_SUCCESS;
} 
/* }}} */
#endif

/* {{{ proto bool fdf_remove_item(resource fdfdoc, string fieldname, int item)
   Sets target frame for form */
PHP_FUNCTION(fdf_remove_item) {
        zval *r_fdf;
        char *fieldname;
        int fieldname_len;
        long item;
        FDFDoc fdf;
        FDFErc err;
        
        if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsl", &r_fdf, 
                                                         &fieldname, &fieldname_len,
                                                         &item
                                                         )
           == FAILURE) {
                return;
        }
        
        ZEND_FETCH_RESOURCE(fdf, FDFDoc *, &r_fdf, -1, "fdf", le_fdf);
        
        err = FDFRemoveItem(fdf, *fieldname ? fieldname : NULL, item);
        
        if(err != FDFErcOK) {
                FDF_FAILURE(err);
        }
        FDF_SUCCESS;
} 
/* }}} */

#ifdef HAVE_FDFTK_5
/* {{{ proto array fdf_get_attachment(resource fdfdoc, string fieldname, string savepath)
   Get attached uploaded file */
PHP_FUNCTION(fdf_get_attachment) {
        zval *r_fdf;
        char *fieldname, *savepath;
        int fieldname_len, savepath_len;
        int is_dir=0;
        FDFDoc fdf;
        FDFErc err;
        char pathbuf[MAXPATHLEN], mimebuf[1024];
    struct stat statBuf;

        if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rss", &r_fdf, 
                                                         &fieldname, &fieldname_len,
                                                         &savepath, &savepath_len
                                                         )
           == FAILURE) {
                return;
        }
        
        ZEND_FETCH_RESOURCE(fdf, FDFDoc *, &r_fdf, -1, "fdf", le_fdf);

        if (php_check_open_basedir(savepath TSRMLS_CC) || (PG(safe_mode) && !php_checkuid(savepath, "wb+", CHECKUID_CHECK_MODE_PARAM))) {
                RETURN_FALSE;
        }

        strlcpy(pathbuf, savepath, sizeof(pathbuf));

        if(0 == stat(pathbuf, &statBuf)) {
                is_dir = S_ISDIR(statBuf.st_mode);
        }

        err = FDFExtractAttachment(fdf, fieldname, pathbuf, sizeof(pathbuf), is_dir, mimebuf, sizeof(mimebuf)); 
        
        if(err != FDFErcOK) {
                FDF_FAILURE(err);
        }

        array_init(return_value);
        add_assoc_string(return_value, "path", pathbuf, 1);
    add_assoc_string(return_value, "type", mimebuf, 1);
        stat(pathbuf, &statBuf);
        add_assoc_long(return_value, "size", statBuf.st_size);
}
/* }}} */
#endif 

/* {{{ enum_values_callback */
static ASBool enum_values_callback(char *name, char *value, void *userdata)
{
        zval *retval_ptr, *z_name, *z_value, **args[3];
        long retval = 0;
        int numargs = 2;
        TSRMLS_FETCH();

        MAKE_STD_ZVAL(z_name);
        ZVAL_STRING(z_name, name, 1);
        args[0] = &z_name;

        if (*value) { /* simple value */
                MAKE_STD_ZVAL(z_value);
                ZVAL_STRING(z_value, value, 1);
                args[1] = &z_value;
        } else { /* empty value *might* be an array */
                /* TODO: do it like fdf_get_value (or re-implement yourself?) */
        }
        
        if (userdata) {
                args[2] = (zval **) userdata;
                numargs++;
        }

        if (call_user_function_ex(EG(function_table), 
                                                                NULL, 
                                                                FDF_G(enum_callback), 
                                                                &retval_ptr, 
                                                                numargs, args, 
                                                                0, NULL TSRMLS_CC) == SUCCESS
                && retval_ptr) {
                
                convert_to_long_ex(&retval_ptr);
                retval = Z_LVAL_P(retval_ptr);
                zval_ptr_dtor(&retval_ptr);
        } else {
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "callback failed");
        }

        zval_ptr_dtor(&z_name);
        zval_ptr_dtor(&z_value);

        return (ASBool)retval;
}
/* }}} */

/* {{{ proto bool fdf_enum_values(resource fdfdoc, callback function [, mixed userdata])
   Call a user defined function for each document value */
PHP_FUNCTION(fdf_enum_values) {
        zval *r_fdf;
        zval *callback;
        zval *userdata = NULL;
        FDFDoc fdf;
        FDFErc err;
        char *name;
        char namebuf[1024], valbuf[1024];

        if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rz|z", &r_fdf, 
                                                         &callback, &userdata
                                                         )
           == FAILURE) {
                return;
        }

        ZEND_FETCH_RESOURCE(fdf, FDFDoc *, &r_fdf, -1, "fdf", le_fdf);

        if (!zend_is_callable(callback, 0, &name)) {
                php_error_docref1(NULL TSRMLS_CC, name, E_WARNING, "Second argument is expected to be a valid callback");
                efree(name);
                RETURN_FALSE;
        }
        efree(name);
        FDF_G(enum_callback) = callback;
        FDF_G(enum_fdf) = fdf;

        err = FDFEnumValues(fdf, enum_values_callback, 
                                                namebuf, sizeof(namebuf), 
                                                valbuf, sizeof(valbuf), 
                                                userdata ? &userdata : NULL, 0); 

        if(err != FDFErcOK) {
                FDF_FAILURE(err);
        }
        FDF_SUCCESS;
}
/* }}} */

/* {{{ proto void fdf_header(void) 
   Set FDF specific HTTP headers */
PHP_FUNCTION(fdf_header) {
        sapi_header_line ctr = {0};
        
        ctr.line = "Content-type: application/vnd.fdf";
        ctr.line_len = strlen(ctr.line);
        ctr.response_code = 200;

        sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC);
} 
/* }}} */

#endif

/*
 * Local variables:
 * tab-width: 4
 * c-basic-offset: 4
 * End:
 * vim600: sw=4 ts=4 fdm=marker
 * vim<600: sw=4 ts=4
 */

/* [<][>][^][v][top][bottom][index][help] */