/* +----------------------------------------------------------------------+ | Swoole | +----------------------------------------------------------------------+ | This source file is subject to version 2.0 of the Apache 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.apache.org/licenses/LICENSE-2.0.html | | If you did not receive a copy of the Apache2.0 license and are unable| | to obtain it through the world-wide-web, please send a note to | | license@swoole.com so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Author: Tianfeng Han | +----------------------------------------------------------------------+ */ #include "php_swoole.h" static PHP_METHOD(swoole_buffer, __construct); static PHP_METHOD(swoole_buffer, __destruct); static PHP_METHOD(swoole_buffer, __toString); static PHP_METHOD(swoole_buffer, append); static PHP_METHOD(swoole_buffer, substr); static PHP_METHOD(swoole_buffer, read); static PHP_METHOD(swoole_buffer, write); static PHP_METHOD(swoole_buffer, expand); static PHP_METHOD(swoole_buffer, recycle); static PHP_METHOD(swoole_buffer, clear); ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_buffer_construct, 0, 0, 0) ZEND_ARG_INFO(0, size) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_buffer_void, 0, 0, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_buffer_expand, 0, 0, 1) ZEND_ARG_INFO(0, size) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_buffer_substr, 0, 0, 1) ZEND_ARG_INFO(0, offset) ZEND_ARG_INFO(0, length) ZEND_ARG_INFO(0, seek) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_buffer_write, 0, 0, 2) ZEND_ARG_INFO(0, offset) ZEND_ARG_INFO(0, data) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_buffer_read, 0, 0, 2) ZEND_ARG_INFO(0, offset) ZEND_ARG_INFO(0, length) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_buffer_append, 0, 0, 1) ZEND_ARG_INFO(0, data) ZEND_END_ARG_INFO() static const zend_function_entry swoole_buffer_methods[] = { PHP_ME(swoole_buffer, __construct, arginfo_swoole_buffer_construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) PHP_ME(swoole_buffer, __destruct, arginfo_swoole_buffer_void, ZEND_ACC_PUBLIC | ZEND_ACC_DTOR) PHP_ME(swoole_buffer, __toString, arginfo_swoole_buffer_void, ZEND_ACC_PUBLIC) PHP_ME(swoole_buffer, substr, arginfo_swoole_buffer_substr, ZEND_ACC_PUBLIC) PHP_ME(swoole_buffer, write, arginfo_swoole_buffer_write, ZEND_ACC_PUBLIC) PHP_ME(swoole_buffer, read, arginfo_swoole_buffer_read, ZEND_ACC_PUBLIC) PHP_ME(swoole_buffer, append, arginfo_swoole_buffer_append, ZEND_ACC_PUBLIC) PHP_ME(swoole_buffer, expand, arginfo_swoole_buffer_expand, ZEND_ACC_PUBLIC) PHP_ME(swoole_buffer, recycle, arginfo_swoole_buffer_void, ZEND_ACC_PUBLIC) PHP_ME(swoole_buffer, clear, arginfo_swoole_buffer_void, ZEND_ACC_PUBLIC) PHP_FALIAS(__sleep, swoole_unsupport_serialize, NULL) PHP_FALIAS(__wakeup, swoole_unsupport_serialize, NULL) PHP_FE_END }; zend_class_entry swoole_buffer_ce; zend_class_entry *swoole_buffer_class_entry_ptr; void swoole_buffer_init(int module_number TSRMLS_DC) { SWOOLE_INIT_CLASS_ENTRY(swoole_buffer_ce, "swoole_buffer", "Swoole\\Buffer", swoole_buffer_methods); swoole_buffer_class_entry_ptr = zend_register_internal_class(&swoole_buffer_ce TSRMLS_CC); SWOOLE_CLASS_ALIAS(swoole_buffer, "Swoole\\Buffer"); } static void swoole_buffer_recycle(swString *buffer) { if (buffer->offset == 0) { return; } long length; length = buffer->length - buffer->offset; if (length > 0) { memmove(buffer->str, buffer->str + buffer->offset, length); } buffer->offset = 0; buffer->length = length; } static PHP_METHOD(swoole_buffer, __construct) { long size = SW_STRING_BUFFER_DEFAULT; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &size) == FAILURE) { RETURN_FALSE; } if (size < 1) { zend_throw_exception(swoole_exception_class_entry_ptr, "buffer size can't be less than 0.", SW_ERROR_INVALID_PARAMS TSRMLS_CC); RETURN_FALSE; } else if (size > SW_STRING_BUFFER_MAXLEN) { zend_throw_exception_ex(swoole_exception_class_entry_ptr, errno TSRMLS_CC, "buffer size can't exceed %d", SW_STRING_BUFFER_MAXLEN); RETURN_FALSE; } swString *buffer = swString_new(size); if (buffer == NULL) { zend_throw_exception_ex(swoole_exception_class_entry_ptr, errno TSRMLS_CC, "malloc(%ld) failed.", size); RETURN_FALSE; } swoole_set_object(getThis(), buffer); zend_update_property_long(swoole_buffer_class_entry_ptr, getThis(), ZEND_STRL("capacity"), size TSRMLS_CC); zend_update_property_long(swoole_buffer_class_entry_ptr, getThis(), ZEND_STRL("length"), 0 TSRMLS_CC); } static PHP_METHOD(swoole_buffer, __destruct) { swString *buffer = swoole_get_object(getThis()); if (buffer) { swString_free(buffer); } } static PHP_METHOD(swoole_buffer, append) { swString str; bzero(&str, sizeof(str)); if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str.str, &str.length) == FAILURE) { RETURN_FALSE; } if (str.length < 1) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "string empty."); RETURN_FALSE; } swString *buffer = swoole_get_object(getThis()); if ((str.length + buffer->length) > buffer->size && (str.length + buffer->length) > SW_STRING_BUFFER_MAXLEN) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "buffer size can't exceed %d", SW_STRING_BUFFER_MAXLEN); RETURN_FALSE; } size_t size_old = buffer->size; if (swString_append(buffer, &str) == SW_OK) { if (buffer->size > size_old) { zend_update_property_long(swoole_buffer_class_entry_ptr, getThis(), ZEND_STRL("capacity"), buffer->size TSRMLS_CC); } zend_update_property_long(swoole_buffer_class_entry_ptr, getThis(), ZEND_STRL("length"), buffer->length - buffer->offset TSRMLS_CC); RETURN_LONG(buffer->length - buffer->offset); } else { RETURN_FALSE; } } static PHP_METHOD(swoole_buffer, substr) { long offset; long length = -1; zend_bool remove = 0; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|lb", &offset, &length, &remove) == FAILURE) { RETURN_FALSE; } swString *buffer = swoole_get_object(getThis()); if (remove && !(offset == 0 && length <= buffer->length)) { remove = 0; } if (offset < 0) { offset = buffer->length + offset; } offset += buffer->offset; if (length < 0) { length = buffer->length - offset; } if (offset + length > buffer->length) { swoole_php_error(E_WARNING, "offset(%ld, %ld) is out of bounds.", offset, length); RETURN_FALSE; } if (remove) { buffer->offset += length; zend_update_property_long(swoole_buffer_class_entry_ptr, getThis(), ZEND_STRL("length"), buffer->length - buffer->offset TSRMLS_CC); if (buffer->offset > SW_STRING_BUFFER_GARBAGE_MIN && buffer->offset * SW_STRING_BUFFER_GARBAGE_RATIO > buffer->size) { swoole_buffer_recycle(buffer); } } SW_RETURN_STRINGL(buffer->str + offset, length, 1); } static PHP_METHOD(swoole_buffer, __toString) { swString *buffer = swoole_get_object(getThis()); SW_RETURN_STRINGL(buffer->str + buffer->offset, buffer->length - buffer->offset, 1); } static PHP_METHOD(swoole_buffer, write) { long offset; swString str; bzero(&str, sizeof(str)); if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ls", &offset, &str.str, &str.length) == FAILURE) { RETURN_FALSE; } if (str.length < 1) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "string to write is empty."); RETURN_FALSE; } swString *buffer = swoole_get_object(getThis()); if (offset < 0) { offset = buffer->length - buffer->offset + offset; } if (offset < 0) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "offset(%ld) is out of bounds.", offset); RETURN_FALSE; } offset += buffer->offset; if ((str.length + offset) > buffer->size && (str.length + offset) > SW_STRING_BUFFER_MAXLEN) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "buffer size can't exceed %d", SW_STRING_BUFFER_MAXLEN); RETURN_FALSE; } size_t size_old = buffer->size; if (swString_write(buffer, offset, &str) == SW_OK) { if (buffer->size > size_old) { zend_update_property_long(swoole_buffer_class_entry_ptr, getThis(), ZEND_STRL("capacity"), buffer->size TSRMLS_CC); } zend_update_property_long(swoole_buffer_class_entry_ptr, getThis(), ZEND_STRL("length"), buffer->length - buffer->offset TSRMLS_CC); RETURN_LONG(buffer->length - buffer->offset); } else { RETURN_FALSE; } } static PHP_METHOD(swoole_buffer, read) { long offset; long length; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ll", &offset, &length) == FAILURE) { RETURN_FALSE; } swString *buffer = swoole_get_object(getThis()); if (offset < 0) { offset = buffer->length - buffer->offset + offset; } if (offset < 0) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "offset(%ld) is out of bounds.", offset); RETURN_FALSE; } offset += buffer->offset; if (length > buffer->length - offset) { RETURN_FALSE; } SW_RETURN_STRINGL(buffer->str + offset, length, 1); } static PHP_METHOD(swoole_buffer, expand) { long size = -1; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &size) == FAILURE) { RETURN_FALSE; } swString *buffer = swoole_get_object(getThis()); if (size <= buffer->size) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "new size must be more than %ld", buffer->size); RETURN_FALSE; } if (swString_extend(buffer, size) == SW_OK) { zend_update_property_long(swoole_buffer_class_entry_ptr, getThis(), ZEND_STRL("capacity"), size TSRMLS_CC); RETURN_TRUE; } else { RETURN_FALSE; } } static PHP_METHOD(swoole_buffer, recycle) { swString *buffer = swoole_get_object(getThis()); swoole_buffer_recycle(buffer); zend_update_property_long(swoole_buffer_class_entry_ptr, getThis(), ZEND_STRL("length"), buffer->length TSRMLS_CC); } static PHP_METHOD(swoole_buffer, clear) { swString *buffer = swoole_get_object(getThis()); buffer->length = 0; buffer->offset = 0; zend_update_property_long(swoole_buffer_class_entry_ptr, getThis(), ZEND_STRL("length"), 0 TSRMLS_CC); }