-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathnode_php_jsbuffer_class.cc
More file actions
197 lines (165 loc) · 6.78 KB
/
node_php_jsbuffer_class.cc
File metadata and controls
197 lines (165 loc) · 6.78 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
// This is a PHP class which wraps a node Buffer object.
// This helps paper over a difference between PHP and JS: PHP strings
// are bytestrings (like node Buffers); JavaScript strings are unicode
// strings (nominally encoded in UTF-8 when converted to bytestrings).
// In order to avoid incorrect decoding/encoding, we sometimes must
// pass strings from PHP to Node as Buffer objects, not String objects.
// This class provides a PHP-accessible wrapper to allow doing so.
// Copyright (c) 2015 C. Scott Ananian <[email protected]>
#include "src/node_php_jsbuffer_class.h"
extern "C" {
#include "main/php.h"
#include "Zend/zend.h"
#include "Zend/zend_exceptions.h"
}
#include "src/macros.h"
using node_php_embed::OwnershipType;
using node_php_embed::node_php_jsbuffer;
/* Class entries */
zend_class_entry *php_ce_jsbuffer;
/*Object handlers */
static zend_object_handlers node_php_jsbuffer_handlers;
/* Constructors and destructors */
static void node_php_jsbuffer_free_storage(
void *object,
zend_object_handle handle TSRMLS_DC) {
TRACE(">");
node_php_jsbuffer *c = reinterpret_cast<node_php_jsbuffer *>(object);
TRACEX("- dealloc %p", c);
zend_object_std_dtor(&c->std TSRMLS_CC);
if (c->z) {
TRACEX("- freeing zval refcount %d", Z_REFCOUNT_P(c->z));
zval_ptr_dtor(&(c->z));
}
if (c->owner == OwnershipType::PHP_OWNED) {
TRACE("- freeing PHP owned data");
efree(const_cast<char*>(c->data));
} else if (c->owner == OwnershipType::CPP_OWNED) {
TRACE("- freeing C++ owned data");
delete[] c->data;
}
efree(object);
TRACE("<");
}
static zend_object_value node_php_jsbuffer_new(zend_class_entry *ce TSRMLS_DC) {
TRACE(">");
zend_object_value retval;
node_php_jsbuffer *c;
c = reinterpret_cast<node_php_jsbuffer *>(ecalloc(1, sizeof(*c)));
TRACEX("- alloc %p", c);
zend_object_std_init(&c->std, ce TSRMLS_CC);
retval.handle = zend_objects_store_put(
c, nullptr,
(zend_objects_free_object_storage_t) node_php_jsbuffer_free_storage,
nullptr TSRMLS_CC);
retval.handlers = &node_php_jsbuffer_handlers;
TRACE("<");
return retval;
}
void node_php_embed::node_php_jsbuffer_create(zval *res,
const char *data, ulong length,
OwnershipType owner TSRMLS_DC) {
TRACE(">");
object_init_ex(res, php_ce_jsbuffer);
node_php_jsbuffer *c = reinterpret_cast<node_php_jsbuffer *>
(zend_object_store_get_object(res TSRMLS_CC));
if (owner != OwnershipType::NOT_OWNED) {
char *tmp = (owner == OwnershipType::PHP_OWNED) ?
reinterpret_cast<char*>(ecalloc(length, 1)) :
new char[length]; // NOLINT(runtime/arrays)
memcpy(tmp, data, length);
data = tmp;
}
c->data = data;
c->length = length;
c->owner = owner;
c->z = nullptr;
TRACE("<");
}
/* Methods */
#define PARSE_PARAMS(method, ...) \
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, __VA_ARGS__) == \
FAILURE) { \
zend_throw_exception(zend_exception_get_default(TSRMLS_C), \
"bad args to " #method, 0 TSRMLS_CC); \
return; \
} \
ZEND_BEGIN_ARG_INFO_EX(node_php_jsbuffer_construct_args, 0, 0, 1)
ZEND_ARG_INFO(0, str)
ZEND_END_ARG_INFO()
PHP_METHOD(JsBuffer, __construct) {
TRACE(">");
node_php_jsbuffer *obj = reinterpret_cast<node_php_jsbuffer *>
(zend_object_store_get_object(this_ptr TSRMLS_CC));
zval *str;
PARSE_PARAMS(__construct, "z/", &str);
convert_to_string(str);
obj->z = str; Z_ADDREF_P(str);
obj->data = Z_STRVAL_P(str);
obj->length = Z_STRLEN_P(str);
// Mark this as not owned directly; the ref to str will take care of it.
obj->owner = OwnershipType::NOT_OWNED;
TRACE("<");
}
ZEND_BEGIN_ARG_INFO_EX(node_php_jsbuffer_toString_args, 0, 0, 0)
ZEND_END_ARG_INFO()
PHP_METHOD(JsBuffer, __toString) {
node_php_jsbuffer *obj = reinterpret_cast<node_php_jsbuffer *>
(zend_object_store_get_object(this_ptr TSRMLS_CC));
RETURN_STRINGL(obj->data, obj->length, 1);
}
ZEND_BEGIN_ARG_INFO_EX(node_php_jsbuffer_debugInfo_args, 0, 0, 0)
ZEND_END_ARG_INFO()
PHP_METHOD(JsBuffer, __debugInfo) {
node_php_jsbuffer *obj = reinterpret_cast<node_php_jsbuffer *>
(zend_object_store_get_object(this_ptr TSRMLS_CC));
array_init_size(return_value, 1);
add_assoc_stringl_ex(return_value, "value", 6,
const_cast<char*>(obj->data), obj->length, 1);
}
#define STUB_METHOD(name) \
PHP_METHOD(JsBuffer, name) { \
TRACE(">"); \
zend_throw_exception( \
zend_exception_get_default(TSRMLS_C), \
"Can't directly serialize or unserialize JsBuffer.", \
0 TSRMLS_CC); \
TRACE("<"); \
RETURN_FALSE; \
}
/* NOTE: We could also override node_php_jsbuffer_handlers.get_constructor
* to throw an exception when invoked, but doing so causes the
* half-constructed object to leak -- this seems to be a PHP bug. So
* we'll define magic __construct methods instead. */
STUB_METHOD(__sleep)
STUB_METHOD(__wakeup)
static const zend_function_entry node_php_jsbuffer_methods[] = {
PHP_ME(JsBuffer, __construct, node_php_jsbuffer_construct_args,
ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
PHP_ME(JsBuffer, __sleep, nullptr,
ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
PHP_ME(JsBuffer, __wakeup, nullptr,
ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
PHP_ME(JsBuffer, __toString, node_php_jsbuffer_toString_args,
ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
PHP_ME(JsBuffer, __debugInfo, node_php_jsbuffer_debugInfo_args,
ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
ZEND_FE_END
};
PHP_MINIT_FUNCTION(node_php_jsbuffer_class) {
TRACE("> PHP_MINIT_FUNCTION");
zend_class_entry ce;
/* JsBuffer class */
INIT_CLASS_ENTRY(ce, "Js\\Buffer", node_php_jsbuffer_methods);
php_ce_jsbuffer = zend_register_internal_class(&ce TSRMLS_CC);
php_ce_jsbuffer->ce_flags |= ZEND_ACC_FINAL;
php_ce_jsbuffer->create_object = node_php_jsbuffer_new;
/* JsBuffer handlers */
memcpy(&node_php_jsbuffer_handlers, zend_get_std_object_handlers(),
sizeof(zend_object_handlers));
node_php_jsbuffer_handlers.clone_obj = nullptr;
node_php_jsbuffer_handlers.cast_object = nullptr;
node_php_jsbuffer_handlers.get_property_ptr_ptr = nullptr;
TRACE("< PHP_MINIT_FUNCTION");
return SUCCESS;
}