summaryrefslogtreecommitdiff
path: root/ext/interbase/ibase_blobs.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/interbase/ibase_blobs.c')
-rw-r--r--ext/interbase/ibase_blobs.c594
1 files changed, 594 insertions, 0 deletions
diff --git a/ext/interbase/ibase_blobs.c b/ext/interbase/ibase_blobs.c
new file mode 100644
index 000000000..5ce3f11f9
--- /dev/null
+++ b/ext/interbase/ibase_blobs.c
@@ -0,0 +1,594 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2004 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.0 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_0.txt. |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Ard Biesheuvel <a.k.biesheuvel@its.tudelft.nl> |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id: ibase_blobs.c,v 1.8 2004/06/03 12:00:23 abies Exp $ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "php.h"
+
+#if HAVE_IBASE
+
+#include "php_interbase.h"
+#include "php_ibase_includes.h"
+
+#define BLOB_CLOSE 1
+#define BLOB_CANCEL 2
+
+static int le_blob;
+
+static void _php_ibase_free_blob(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */
+{
+ ibase_blob *ib_blob = (ibase_blob *)rsrc->ptr;
+
+ if (ib_blob->bl_handle != NULL) { /* blob open*/
+ if (isc_cancel_blob(IB_STATUS, &ib_blob->bl_handle)) {
+ _php_ibase_module_error("You can lose data. Close any blob after reading from or "
+ "writing to it. Use ibase_blob_close() before calling ibase_close()" TSRMLS_CC);
+ }
+ }
+ efree(ib_blob);
+}
+/* }}} */
+
+void php_ibase_blobs_minit(INIT_FUNC_ARGS) /* {{{ */
+{
+ le_blob = zend_register_list_destructors_ex(_php_ibase_free_blob, NULL,
+ "interbase blob", module_number);
+}
+/* }}} */
+
+int _php_ibase_string_to_quad(char const *id, ISC_QUAD *qd) /* {{{ */
+{
+ /* shortcut for most common case */
+ if (sizeof(ISC_QUAD) == sizeof(ISC_UINT64)) {
+ return sscanf(id, BLOB_ID_MASK, (ISC_UINT64 *) qd);
+ } else {
+ ISC_UINT64 res;
+ if (sscanf(id, BLOB_ID_MASK, &res)) {
+ qd->gds_quad_high = (ISC_LONG) (res >> 0x20);
+ qd->gds_quad_low = (ISC_LONG) (res & 0xFFFFFFFF);
+ return 1;
+ }
+ return 0;
+ }
+}
+/* }}} */
+
+char *_php_ibase_quad_to_string(ISC_QUAD const qd) /* {{{ */
+{
+ char *result = (char *) emalloc(BLOB_ID_LEN+1);
+
+ /* shortcut for most common case */
+ if (sizeof(ISC_QUAD) == sizeof(ISC_UINT64)) {
+ sprintf(result, "0x%0*" LL_MASK "x", 16, *(ISC_UINT64*)(void *) &qd);
+ } else {
+ ISC_UINT64 res = ((ISC_UINT64) qd.gds_quad_high << 0x20) | qd.gds_quad_low;
+ sprintf(result, "0x%0*" LL_MASK "x", 16, res);
+ }
+ result[BLOB_ID_LEN] = '\0';
+ return result;
+}
+/* }}} */
+
+typedef struct { /* {{{ */
+ ISC_LONG max_segment; /* Length of longest segment */
+ ISC_LONG num_segments; /* Total number of segments */
+ ISC_LONG total_length; /* Total length of blob */
+ int bl_stream; /* blob is stream ? */
+/* }}} */
+} IBASE_BLOBINFO;
+
+int _php_ibase_blob_get(zval *return_value, ibase_blob *ib_blob, unsigned long max_len TSRMLS_DC) /* {{{ */
+{
+ if (ib_blob->bl_qd.gds_quad_high || ib_blob->bl_qd.gds_quad_low) { /*not null ?*/
+
+ ISC_STATUS stat;
+ char *bl_data;
+ unsigned long cur_len;
+ unsigned short seg_len;
+
+ bl_data = emalloc(max_len + 1);
+
+ for (cur_len = stat = 0; (stat == 0 || stat == isc_segment) && cur_len < max_len; cur_len += seg_len) {
+
+ unsigned short chunk_size = (max_len-cur_len) > USHRT_MAX ? USHRT_MAX
+ : (unsigned short)(max_len-cur_len);
+
+ stat = isc_get_segment(IB_STATUS, &ib_blob->bl_handle, &seg_len, chunk_size, &bl_data[cur_len]);
+ }
+
+ bl_data[cur_len] = '\0';
+ if (IB_STATUS[0] == 1 && (stat != 0 && stat != isc_segstr_eof && stat != isc_segment)) {
+ efree(bl_data);
+ _php_ibase_error(TSRMLS_C);
+ return FAILURE;
+ }
+ RETVAL_STRINGL(bl_data, cur_len, 0);
+ } else { /* null blob */
+ RETVAL_STRING("", 1); /* empty string */
+ }
+ return SUCCESS;
+}
+/* }}} */
+
+int _php_ibase_blob_add(zval **string_arg, ibase_blob *ib_blob TSRMLS_DC) /* {{{ */
+{
+ unsigned long put_cnt = 0, rem_cnt;
+ unsigned short chunk_size;
+
+ convert_to_string_ex(string_arg);
+
+ for (rem_cnt = Z_STRLEN_PP(string_arg); rem_cnt > 0; rem_cnt -= chunk_size) {
+
+ chunk_size = rem_cnt > USHRT_MAX ? USHRT_MAX : (unsigned short)rem_cnt;
+
+ if (isc_put_segment(IB_STATUS, &ib_blob->bl_handle, chunk_size, &Z_STRVAL_PP(string_arg)[put_cnt] )) {
+ _php_ibase_error(TSRMLS_C);
+ return FAILURE;
+ }
+ put_cnt += chunk_size;
+ }
+ return SUCCESS;
+}
+/* }}} */
+
+static int _php_ibase_blob_info(isc_blob_handle bl_handle, IBASE_BLOBINFO *bl_info TSRMLS_DC) /* {{{ */
+{
+ static char bl_items[] = {
+ isc_info_blob_num_segments,
+ isc_info_blob_max_segment,
+ isc_info_blob_total_length,
+ isc_info_blob_type
+ };
+
+ char bl_inf[sizeof(long)*8], *p;
+
+ bl_info->max_segment = 0;
+ bl_info->num_segments = 0;
+ bl_info->total_length = 0;
+ bl_info->bl_stream = 0;
+
+ if (isc_blob_info(IB_STATUS, &bl_handle, sizeof(bl_items), bl_items, sizeof(bl_inf), bl_inf)) {
+ _php_ibase_error(TSRMLS_C);
+ return FAILURE;
+ }
+
+ for (p = bl_inf; *p != isc_info_end && p < bl_inf + sizeof(bl_inf);) {
+ unsigned short item_len;
+ int item = *p++;
+
+ item_len = (short) isc_vax_integer(p, 2);
+ p += 2;
+ switch (item) {
+ case isc_info_blob_num_segments:
+ bl_info->num_segments = isc_vax_integer(p, item_len);
+ break;
+ case isc_info_blob_max_segment:
+ bl_info->max_segment = isc_vax_integer(p, item_len);
+ break;
+ case isc_info_blob_total_length:
+ bl_info->total_length = isc_vax_integer(p, item_len);
+ break;
+ case isc_info_blob_type:
+ bl_info->bl_stream = isc_vax_integer(p, item_len);
+ break;
+ case isc_info_end:
+ break;
+ case isc_info_truncated:
+ case isc_info_error: /* hmm. don't think so...*/
+ _php_ibase_module_error("PHP module internal error" TSRMLS_CC);
+ return FAILURE;
+ } /* switch */
+ p += item_len;
+ } /* for */
+ return SUCCESS;
+}
+/* }}} */
+
+/* {{{ proto resource ibase_blob_create([resource link_identifier])
+ Create blob for adding data */
+PHP_FUNCTION(ibase_blob_create)
+{
+ zval *link = NULL;
+ ibase_db_link *ib_link;
+ ibase_trans *trans = NULL;
+ ibase_blob *ib_blob;
+
+ RESET_ERRMSG;
+
+ if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|r", &link)) {
+ RETURN_FALSE;
+ }
+
+ PHP_IBASE_LINK_TRANS(link, ib_link, trans);
+
+ ib_blob = (ibase_blob *) emalloc(sizeof(ibase_blob));
+ ib_blob->bl_handle = NULL;
+ ib_blob->type = BLOB_INPUT;
+
+ if (isc_create_blob(IB_STATUS, &ib_link->handle, &trans->handle, &ib_blob->bl_handle, &ib_blob->bl_qd)) {
+ _php_ibase_error(TSRMLS_C);
+ efree(ib_blob);
+ RETURN_FALSE;
+ }
+
+ ZEND_REGISTER_RESOURCE(return_value, ib_blob, le_blob);
+}
+/* }}} */
+
+/* {{{ proto resource ibase_blob_open([ resource link_identifier, ] string blob_id)
+ Open blob for retrieving data parts */
+PHP_FUNCTION(ibase_blob_open)
+{
+ char *blob_id;
+ int blob_id_len;
+ zval *link = NULL;
+ ibase_db_link *ib_link;
+ ibase_trans *trans = NULL;
+ ibase_blob *ib_blob;
+
+ RESET_ERRMSG;
+
+ switch (ZEND_NUM_ARGS()) {
+ default:
+ WRONG_PARAM_COUNT;
+ case 1:
+ if (FAILURE == zend_parse_parameters(1 TSRMLS_CC, "s", &blob_id, &blob_id_len)) {
+ RETURN_FALSE;
+ }
+ break;
+ case 2:
+ if (FAILURE == zend_parse_parameters(2 TSRMLS_CC, "rs", &link, &blob_id, &blob_id_len)) {
+ RETURN_FALSE;
+ }
+ break;
+ }
+
+ PHP_IBASE_LINK_TRANS(link, ib_link, trans);
+
+ ib_blob = (ibase_blob *) emalloc(sizeof(ibase_blob));
+ ib_blob->bl_handle = NULL;
+ ib_blob->type = BLOB_OUTPUT;
+
+ do {
+ if (! _php_ibase_string_to_quad(blob_id, &ib_blob->bl_qd)) {
+ _php_ibase_module_error("String is not a BLOB ID" TSRMLS_CC);
+ break;
+ }
+
+ if (isc_open_blob(IB_STATUS, &ib_link->handle, &trans->handle, &ib_blob->bl_handle,
+ &ib_blob->bl_qd)) {
+ _php_ibase_error(TSRMLS_C);
+ break;
+ }
+
+ ZEND_REGISTER_RESOURCE(return_value, ib_blob, le_blob);
+ return;
+
+ } while (0);
+
+ efree(ib_blob);
+ RETURN_FALSE;
+}
+/* }}} */
+
+/* {{{ proto bool ibase_blob_add(resource blob_handle, string data)
+ Add data into created blob */
+PHP_FUNCTION(ibase_blob_add)
+{
+ zval **blob_arg, **string_arg;
+ ibase_blob *ib_blob;
+
+ RESET_ERRMSG;
+
+ if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &blob_arg, &string_arg) == FAILURE) {
+ WRONG_PARAM_COUNT;
+ }
+
+ ZEND_FETCH_RESOURCE(ib_blob, ibase_blob *, blob_arg, -1, "Interbase blob", le_blob);
+
+ if (ib_blob->type != BLOB_INPUT) {
+ _php_ibase_module_error("BLOB is not open for input" TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ if (_php_ibase_blob_add(string_arg, ib_blob TSRMLS_CC) != SUCCESS) {
+ RETURN_FALSE;
+ }
+}
+/* }}} */
+
+/* {{{ proto string ibase_blob_get(resource blob_handle, int len)
+ Get len bytes data from open blob */
+PHP_FUNCTION(ibase_blob_get)
+{
+ zval **blob_arg, **len_arg;
+ ibase_blob *ib_blob;
+
+ RESET_ERRMSG;
+
+ if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &blob_arg, &len_arg) == FAILURE) {
+ WRONG_PARAM_COUNT;
+ }
+
+ ZEND_FETCH_RESOURCE(ib_blob, ibase_blob *, blob_arg, -1, "Interbase blob", le_blob);
+
+ if (ib_blob->type != BLOB_OUTPUT) {
+ _php_ibase_module_error("BLOB is not open for output" TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ convert_to_long_ex(len_arg);
+
+ if (_php_ibase_blob_get(return_value, ib_blob, Z_LVAL_PP(len_arg) TSRMLS_CC) != SUCCESS) {
+ RETURN_FALSE;
+ }
+}
+/* }}} */
+
+static void _php_ibase_blob_end(INTERNAL_FUNCTION_PARAMETERS, int bl_end) /* {{{ */
+{
+ zval **blob_arg;
+ ibase_blob *ib_blob;
+
+ RESET_ERRMSG;
+
+ if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &blob_arg) == FAILURE) {
+ WRONG_PARAM_COUNT;
+ }
+
+ ZEND_FETCH_RESOURCE(ib_blob, ibase_blob *, blob_arg, -1, "Interbase blob", le_blob);
+
+ if (bl_end == BLOB_CLOSE) { /* return id here */
+
+ if (ib_blob->bl_qd.gds_quad_high || ib_blob->bl_qd.gds_quad_low) { /*not null ?*/
+ if (isc_close_blob(IB_STATUS, &ib_blob->bl_handle)) {
+ _php_ibase_error(TSRMLS_C);
+ RETURN_FALSE;
+ }
+ }
+ ib_blob->bl_handle = NULL;
+
+ RETVAL_STRINGL(_php_ibase_quad_to_string(ib_blob->bl_qd), BLOB_ID_LEN, 0);
+ } else { /* discard created blob */
+ if (isc_cancel_blob(IB_STATUS, &ib_blob->bl_handle)) {
+ _php_ibase_error(TSRMLS_C);
+ RETURN_FALSE;
+ }
+ ib_blob->bl_handle = NULL;
+ RETVAL_TRUE;
+ }
+ zend_list_delete(Z_LVAL_PP(blob_arg));
+}
+/* }}} */
+
+/* {{{ proto string ibase_blob_close(resource blob_handle)
+ Close blob */
+PHP_FUNCTION(ibase_blob_close)
+{
+ _php_ibase_blob_end(INTERNAL_FUNCTION_PARAM_PASSTHRU, BLOB_CLOSE);
+}
+/* }}} */
+
+/* {{{ proto bool ibase_blob_cancel(resource blob_handle)
+ Cancel creating blob */
+PHP_FUNCTION(ibase_blob_cancel)
+{
+ _php_ibase_blob_end(INTERNAL_FUNCTION_PARAM_PASSTHRU, BLOB_CANCEL);
+}
+/* }}} */
+
+/* {{{ proto array ibase_blob_info([ resource link_identifier, ] string blob_id)
+ Return blob length and other useful info */
+PHP_FUNCTION(ibase_blob_info)
+{
+ char *blob_id;
+ int blob_id_len;
+ zval *link = NULL;
+ ibase_db_link *ib_link;
+ ibase_trans *trans = NULL;
+ ibase_blob ib_blob = { NULL, BLOB_INPUT };
+ IBASE_BLOBINFO bl_info;
+
+ RESET_ERRMSG;
+
+ switch (ZEND_NUM_ARGS()) {
+ default:
+ WRONG_PARAM_COUNT;
+ case 1:
+ if (FAILURE == zend_parse_parameters(1 TSRMLS_CC, "s", &blob_id, &blob_id_len)) {
+ RETURN_FALSE;
+ }
+ break;
+ case 2:
+ if (FAILURE == zend_parse_parameters(2 TSRMLS_CC, "rs", &link, &blob_id, &blob_id_len)) {
+ RETURN_FALSE;
+ }
+ break;
+ }
+
+ PHP_IBASE_LINK_TRANS(link, ib_link, trans);
+
+ if (! _php_ibase_string_to_quad(blob_id, &ib_blob.bl_qd)) {
+ _php_ibase_module_error("Unrecognized BLOB ID" TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ if (ib_blob.bl_qd.gds_quad_high || ib_blob.bl_qd.gds_quad_low) { /* not null ? */
+ if (isc_open_blob(IB_STATUS, &ib_link->handle, &trans->handle, &ib_blob.bl_handle,
+ &ib_blob.bl_qd)) {
+ _php_ibase_error(TSRMLS_C);
+ RETURN_FALSE;
+ }
+
+ if (_php_ibase_blob_info(ib_blob.bl_handle, &bl_info TSRMLS_CC)) {
+ RETURN_FALSE;
+ }
+ if (isc_close_blob(IB_STATUS, &ib_blob.bl_handle)) {
+ _php_ibase_error(TSRMLS_C);
+ RETURN_FALSE;
+ }
+ } else { /* null blob, all values to zero */
+ bl_info.max_segment = 0;
+ bl_info.num_segments = 0;
+ bl_info.total_length = 0;
+ bl_info.bl_stream = 0;
+ }
+
+ array_init(return_value);
+
+ add_index_long(return_value, 0, bl_info.total_length);
+ add_assoc_long(return_value, "length", bl_info.total_length);
+
+ add_index_long(return_value, 1, bl_info.num_segments);
+ add_assoc_long(return_value, "numseg", bl_info.num_segments);
+
+ add_index_long(return_value, 2, bl_info.max_segment);
+ add_assoc_long(return_value, "maxseg", bl_info.max_segment);
+
+ add_index_bool(return_value, 3, bl_info.bl_stream);
+ add_assoc_bool(return_value, "stream", bl_info.bl_stream);
+
+ add_index_bool(return_value, 4, (!ib_blob.bl_qd.gds_quad_high && !ib_blob.bl_qd.gds_quad_low));
+ add_assoc_bool(return_value, "isnull", (!ib_blob.bl_qd.gds_quad_high && !ib_blob.bl_qd.gds_quad_low));
+}
+/* }}} */
+
+/* {{{ proto bool ibase_blob_echo([ resource link_identifier, ] string blob_id)
+ Output blob contents to browser */
+PHP_FUNCTION(ibase_blob_echo)
+{
+ char *blob_id;
+ int blob_id_len;
+ zval *link = NULL;
+ ibase_db_link *ib_link;
+ ibase_trans *trans = NULL;
+ ibase_blob ib_blob_id = { NULL, BLOB_OUTPUT };
+ char bl_data[IBASE_BLOB_SEG];
+ unsigned short seg_len;
+
+ RESET_ERRMSG;
+
+ switch (ZEND_NUM_ARGS()) {
+ default:
+ WRONG_PARAM_COUNT;
+ case 1:
+ if (FAILURE == zend_parse_parameters(1 TSRMLS_CC, "s", &blob_id, &blob_id_len)) {
+ RETURN_FALSE;
+ }
+ break;
+ case 2:
+ if (FAILURE == zend_parse_parameters(2 TSRMLS_CC, "rs", &link, &blob_id, &blob_id_len)) {
+ RETURN_FALSE;
+ }
+ break;
+ }
+
+ PHP_IBASE_LINK_TRANS(link, ib_link, trans);
+
+ if (! _php_ibase_string_to_quad(blob_id, &ib_blob_id.bl_qd)) {
+ _php_ibase_module_error("Unrecognized BLOB ID" TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ do {
+ if (isc_open_blob(IB_STATUS, &ib_link->handle, &trans->handle, &ib_blob_id.bl_handle,
+ &ib_blob_id.bl_qd)) {
+ break;
+ }
+
+ while (!isc_get_segment(IB_STATUS, &ib_blob_id.bl_handle, &seg_len, sizeof(bl_data), bl_data)
+ || IB_STATUS[1] == isc_segment) {
+ PHPWRITE(bl_data, seg_len);
+ }
+
+ if (IB_STATUS[0] && (IB_STATUS[1] != isc_segstr_eof)) {
+ break;
+ }
+
+ if (isc_close_blob(IB_STATUS, &ib_blob_id.bl_handle)) {
+ break;
+ }
+ RETURN_TRUE;
+ } while (0);
+
+ _php_ibase_error(TSRMLS_C);
+ RETURN_FALSE;
+}
+/* }}} */
+
+/* {{{ proto string ibase_blob_import([ resource link_identifier, ] resource file)
+ Create blob, copy file in it, and close it */
+PHP_FUNCTION(ibase_blob_import)
+{
+ zval *link = NULL, *file;
+ int size;
+ unsigned short b;
+ ibase_blob ib_blob = { NULL, 0 };
+ ibase_db_link *ib_link;
+ ibase_trans *trans = NULL;
+ char bl_data[IBASE_BLOB_SEG];
+ php_stream *stream;
+
+ RESET_ERRMSG;
+
+ if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|r",
+ (ZEND_NUM_ARGS()-1) ? &link : &file, &file)) {
+ RETURN_FALSE;
+ }
+
+ PHP_IBASE_LINK_TRANS(link, ib_link, trans);
+
+ php_stream_from_zval(stream, &file);
+
+ do {
+ if (isc_create_blob(IB_STATUS, &ib_link->handle, &trans->handle, &ib_blob.bl_handle,
+ &ib_blob.bl_qd)) {
+ break;
+ }
+
+ for (size = 0; (b = php_stream_read(stream, bl_data, sizeof(bl_data))); size += b) {
+ if (isc_put_segment(IB_STATUS, &ib_blob.bl_handle, b, bl_data)) {
+ break;
+ }
+ }
+
+ if (isc_close_blob(IB_STATUS, &ib_blob.bl_handle)) {
+ break;
+ }
+ RETURN_STRINGL( _php_ibase_quad_to_string(ib_blob.bl_qd), BLOB_ID_LEN, 0);
+ } while (0);
+
+ _php_ibase_error(TSRMLS_C);
+ RETURN_FALSE;
+}
+/* }}} */
+
+#endif /* HAVE_IBASE */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: sw=4 ts=4 fdm=marker
+ * vim<600: sw=4 ts=4
+ */