Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Tree: 408de75c5c
Fetching contributors…

Cannot retrieve contributors at this time

933 lines (746 sloc) 25.403 kB
/*
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
| Copyright (c) 1997-2007 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: Why the lucky stiff |
| Alexey Zakhlestin <indeyets@gmail.com> |
+----------------------------------------------------------------------+
$Id: phpext.c 330 2008-11-18 19:55:57Z indeyets $
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <syck.h>
#include <php.h>
#include <zend_exceptions.h>
#include <zend_interfaces.h>
#include <php_ini.h>
#include <ext/standard/info.h>
#include "php_syck.h"
#ifndef Z_SET_REFCOUNT_P
# define Z_SET_REFCOUNT_P(x, y) (x)->refcount = (y)
#endif
#ifndef true
# define true 1
# define false 0
#endif
#define PHP_SYCK_VERSION "0.9.4-dev"
/**
* SyckException class
**/
#define PHP_SYCK_EXCEPTION_PARENT "UnexpectedValueException"
#define PHP_SYCK_EXCEPTION_PARENT_LC "unexpectedvalueexception"
#define PHP_SYCK_EXCEPTION_NAME "SyckException"
static zend_class_entry *spl_ce_RuntimeException;
zend_class_entry *syck_exception_entry;
/* {{{ arginfo */
ZEND_BEGIN_ARG_INFO_EX(arginfo_syck_load, 0, 0, 1)
ZEND_ARG_INFO(0, string)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_syck_dump, 0, 0, 1)
ZEND_ARG_INFO(0, variable)
ZEND_END_ARG_INFO()
/* }}} */
PHP_SYCK_API zend_class_entry *php_syck_get_exception_base()
{
TSRMLS_FETCH();
if (!spl_ce_RuntimeException) {
zend_class_entry **pce;
if (zend_hash_find(CG(class_table), PHP_SYCK_EXCEPTION_PARENT_LC, sizeof(PHP_SYCK_EXCEPTION_PARENT_LC), (void **) &pce) == SUCCESS) {
spl_ce_RuntimeException = *pce;
return *pce;
}
} else {
return spl_ce_RuntimeException;
}
return zend_exception_get_default(TSRMLS_C);
}
static double inline zero() { return 0.0; }
static double inline one() { return 1.0; }
static double inline inf() { return one() / zero(); }
static double inline nanphp() { return zero() / zero(); }
typedef struct {
char *output;
size_t output_size;
size_t output_alloc;
unsigned char level;
zval **stack;
} php_syck_emitter_xtra;
void psex_init(php_syck_emitter_xtra *ptr)
{
ptr->output = NULL;
ptr->output_size = 0;
ptr->output_alloc = 0;
ptr->stack = emalloc(sizeof(zval *) * 255);
ptr->level = 0;
}
void psex_free(php_syck_emitter_xtra *ptr)
{
if (ptr->output) {
efree(ptr->output);
ptr->output = NULL;
}
if (ptr->stack) {
efree(ptr->stack);
ptr->stack = NULL;
}
ptr->output_size = 0;
ptr->output_alloc = 0;
ptr->level = 0;
}
void psex_add_output(php_syck_emitter_xtra *ptr, const char *data, size_t len)
{
while (ptr->output_size + len > ptr->output_alloc) {
if (ptr->output_alloc == 0) {
ptr->output_alloc = 8192;
ptr->output = emalloc(ptr->output_alloc);
} else {
ptr->output_alloc += 8192;
ptr->output = erealloc(ptr->output, ptr->output_alloc);
}
}
strncpy(ptr->output + ptr->output_size, data, len);
ptr->output_size += len;
}
int psex_push_obj(php_syck_emitter_xtra *ptr, zval *obj)
{
if (ptr->level == 255)
return 0;
ptr->stack[++(ptr->level)] = obj;
return 1;
}
zval * psex_pop_obj(php_syck_emitter_xtra *ptr)
{
if (ptr->level == 0)
return NULL;
return ptr->stack[(ptr->level)--];
}
/**
* returns
* 0 for sequential numeric arrays
* 1 for insequential or associative arrays
**/
static int psex_determine_array_type(HashTable *myht TSRMLS_DC) /* {{{ */
{
int i = myht ? zend_hash_num_elements(myht) : 0;
if (i > 0) {
char *key = NULL;
uint key_len;
HashPosition pos;
ulong index, idx = 0;
zend_hash_internal_pointer_reset_ex(myht, &pos);
for (;; zend_hash_move_forward_ex(myht, &pos)) {
i = zend_hash_get_current_key_ex(myht, &key, &key_len, &index, 0, &pos);
if (i == HASH_KEY_NON_EXISTANT)
break;
if (i == HASH_KEY_IS_STRING) {
return 1;
} else {
if (index != idx) {
return 1;
}
}
idx++;
}
}
return 0;
}
function_entry syck_functions[] = {
PHP_FE(syck_load, arginfo_syck_load)
PHP_FE(syck_dump, arginfo_syck_dump)
{NULL, NULL, NULL} /* Must be the last line in syck_functions[] */
};
static zend_module_dep syck_deps[] = {
ZEND_MOD_REQUIRED("spl")
ZEND_MOD_REQUIRED("hash")
ZEND_MOD_REQUIRED("date")
{NULL, NULL, NULL}
};
zend_module_entry syck_module_entry = {
STANDARD_MODULE_HEADER_EX, NULL,
syck_deps,
"syck",
syck_functions,
PHP_MINIT(syck), /* module init function */
NULL, /* module shutdown function */
NULL, /* request init function */
NULL, /* request shutdown function */
PHP_MINFO(syck), /* module info function */
PHP_SYCK_VERSION, /* Replace with version number for your extension */
STANDARD_MODULE_PROPERTIES
};
#ifdef COMPILE_DL_SYCK
ZEND_GET_MODULE(syck)
#endif
PHP_MINIT_FUNCTION(syck)
{
zend_class_entry ce;
INIT_CLASS_ENTRY(ce, PHP_SYCK_EXCEPTION_NAME, NULL);
syck_exception_entry = zend_register_internal_class_ex(&ce, php_syck_get_exception_base(), PHP_SYCK_EXCEPTION_PARENT TSRMLS_CC);
return SUCCESS;
}
PHP_MINFO_FUNCTION(syck)
{
php_info_print_table_start();
php_info_print_table_header(2, "Extension version", PHP_SYCK_VERSION);
php_info_print_table_header(2, "Syck library version", SYCK_VERSION);
php_info_print_table_end();
}
SYMID php_syck_handler(SyckParser *p, SyckNode *n)
{
zval *o = NULL;
MAKE_STD_ZVAL(o);
switch (n->kind) {
case syck_str_kind:
if (n->type_id == NULL || strcmp(n->type_id, "str") == 0) {
ZVAL_STRINGL(o, n->data.str->ptr, n->data.str->len, 1);
} else if (strcmp(n->type_id, "null") == 0) {
ZVAL_NULL(o);
} else if (strcmp(n->type_id, "bool#yes") == 0) {
ZVAL_BOOL(o, 1);
} else if (strcmp(n->type_id, "bool#no") == 0) {
ZVAL_BOOL(o, 0);
} else if (strcmp(n->type_id, "bool") == 0) {
/* implicit boolean */
char *ptr = n->data.str->ptr;
size_t len = n->data.str->len;
TSRMLS_FETCH();
if (len == 1) {
if (ptr[0] == 'y' || ptr[0] == 'Y') {
ZVAL_BOOL(o, 1);
} else if (ptr[0] == 'n' || ptr[0] == 'N') {
ZVAL_BOOL(o, 0);
}
} else if (len == 2) {
if (strncmp(ptr, "on", len) == 0 || strncmp(ptr, "On", len) == 0 || strncmp(ptr, "ON", len) == 0) {
ZVAL_BOOL(o, 1);
} else if (strncmp(ptr, "no", len) == 0 || strncmp(ptr, "No", len) == 0 || strncmp(ptr, "NO", len) == 0) {
ZVAL_BOOL(o, 0);
}
} else if (len == 3) {
if (strncmp(ptr, "yes", len) == 0 || strncmp(ptr, "Yes", len) == 0 || strncmp(ptr, "YES", len) == 0) {
ZVAL_BOOL(o, 1);
} else if (strncmp(ptr, "off", len) == 0 || strncmp(ptr, "Off", len) == 0 || strncmp(ptr, "OFF", len) == 0) {
ZVAL_BOOL(o, 0);
}
} else if (len == 4) {
if (strncmp(ptr, "true", len) == 0 || strncmp(ptr, "True", len) == 0 || strncmp(ptr, "TRUE", len) == 0) {
ZVAL_BOOL(o, 1);
}
} else if (len == 3) {
if (strncmp(ptr, "false", len) == 0 || strncmp(ptr, "False", len) == 0 || strncmp(ptr, "FALSE", len) == 0) {
ZVAL_BOOL(o, 1);
}
}
if (Z_TYPE_P(o) != IS_BOOL) {
zend_throw_exception_ex(syck_exception_entry, 0 TSRMLS_CC, "!bool specified, but value \"%s\" (len=%d) is incorrect on line %d, col %d: '%s'", ptr, len, p->linect + 1, p->cursor - p->lineptr, p->lineptr);
}
} else if (strcmp(n->type_id, "int#hex") == 0) {
long intVal;
syck_str_blow_away_commas(n);
intVal = strtol(n->data.str->ptr, NULL, 16);
ZVAL_LONG(o, intVal);
} else if (strcmp(n->type_id, "int#base60") == 0) {
char *ptr = NULL, *end = NULL;
long sixty = 1;
long total = 0;
syck_str_blow_away_commas(n);
ptr = n->data.str->ptr;
end = n->data.str->ptr + n->data.str->len;
while (end > ptr) {
long bnum = 0;
char *colon = end - 1;
while (colon >= ptr && *colon != ':') {
colon--;
}
if (colon >= ptr && *colon == ':')
*colon = '\0';
bnum = strtol(colon + 1, NULL, 10);
total += bnum * sixty;
sixty *= 60;
end = colon;
}
ZVAL_LONG(o, total);
} else if (strcmp(n->type_id, "int#oct") == 0) {
long intVal;
syck_str_blow_away_commas(n);
intVal = strtol(n->data.str->ptr, NULL, 8);
ZVAL_LONG(o, intVal);
} else if (strcmp(n->type_id, "int") == 0) {
long intVal;
syck_str_blow_away_commas(n);
intVal = strtol(n->data.str->ptr, NULL, 10);
ZVAL_LONG(o, intVal);
} else if (strcmp(n->type_id, "float") == 0 || strcmp(n->type_id, "float#fix") == 0 || strcmp(n->type_id, "float#exp") == 0) {
double f;
syck_str_blow_away_commas(n);
f = strtod(n->data.str->ptr, NULL);
ZVAL_DOUBLE(o, f);
} else if (strcmp(n->type_id, "float#base60") == 0) {
char *ptr = NULL, *end = NULL;
long multiplier = 1;
double total = 0;
syck_str_blow_away_commas(n);
ptr = n->data.str->ptr;
end = n->data.str->ptr + n->data.str->len;
while (end > ptr) {
double bnum = 0;
char *colon = end - 1;
while (colon >= ptr && *colon != ':') {
colon--;
}
if (colon >= ptr && *colon == ':')
*colon = '\0';
bnum = strtod(colon + 1, NULL);
total += bnum * multiplier;
multiplier *= 60;
end = colon;
}
ZVAL_DOUBLE(o, total);
} else if (strcmp(n->type_id, "float#nan") == 0) {
ZVAL_DOUBLE(o, nanphp());
} else if (strcmp(n->type_id, "float#inf") == 0) {
ZVAL_DOUBLE(o, inf());
} else if (strcmp(n->type_id, "float#neginf") == 0) {
ZVAL_DOUBLE(o, -inf());
} else if (strncmp(n->type_id, "timestamp", 9) == 0 || strcmp(n->type_id, "php/object::Datetime") == 0) {
zval fname, param, *params[1];
TSRMLS_FETCH();
ZVAL_STRING(&fname, "date_create", 1);
INIT_ZVAL(param);
params[0] = &param;
ZVAL_STRINGL(params[0], n->data.str->ptr, n->data.str->len, 1);
call_user_function(EG(function_table), NULL, &fname, o, 1, params TSRMLS_CC);
zval_dtor(&fname);
zval_dtor(params[0]);
} else if (strncmp(n->type_id, "php/object::", 12) == 0) {
/* Some custom php-class packed in a string. Only ones implementing Serializable ar supported */
size_t classname_len = strlen(n->type_id) - 12;
char *classname = emalloc(classname_len + 1);
zend_class_entry **ce;
zval *param = NULL;
TSRMLS_FETCH();
strncpy(classname, n->type_id + 12, classname_len + 1);
if (FAILURE == zend_lookup_class_ex(classname, classname_len, 1, &ce TSRMLS_CC)) {
zend_throw_exception_ex(syck_exception_entry, 0 TSRMLS_CC, "Couldn't find %s class on line %d, col %d: '%s'", classname, p->linect + 1, p->cursor - p->lineptr, p->lineptr);
efree(classname);
break;
}
if (0 == instanceof_function_ex(*ce, zend_ce_serializable, 1 TSRMLS_CC)) {
zend_throw_exception_ex(syck_exception_entry, 0 TSRMLS_CC, "Class %s doesn't implement Serializable on line %d, col %d: '%s'", classname, p->linect + 1, p->cursor - p->lineptr, p->lineptr);
efree(classname);
break;
}
efree(classname);
object_init_ex(o, *ce);
MAKE_STD_ZVAL(param);
ZVAL_STRINGL(param, n->data.str->ptr, n->data.str->len, 1);
zend_call_method_with_1_params(&o, *ce, NULL, "unserialize", NULL, param);
zval_ptr_dtor(&param);
} else {
php_error(E_NOTICE, "syck extension didn't handle %s type => treating as a string", n->type_id);
ZVAL_STRINGL(o, n->data.str->ptr, n->data.str->len, 1);
}
break;
case syck_seq_kind:
{
if (NULL != n->type_id && strncmp(n->type_id, "php/array::", 11) == 0) {
/* some class which implements ArrayAccess */
size_t i;
size_t classname_len = strlen(n->type_id) - 11;
char *classname = emalloc(classname_len + 1);
zend_class_entry **ce;
TSRMLS_FETCH();
strncpy(classname, n->type_id + 11, classname_len + 1);
if (FAILURE == zend_lookup_class_ex(classname, classname_len, 1, &ce TSRMLS_CC)) {
zend_throw_exception_ex(syck_exception_entry, 0 TSRMLS_CC, "Couldn't find %s class on line %d, col %d: '%s'", classname, p->linect + 1, p->cursor - p->lineptr, p->lineptr);
efree(classname);
break;
}
if (0 != instanceof_function_ex(*ce, zend_ce_arrayaccess, 1 TSRMLS_CC)) {
object_init_ex(o, *ce);
for (i = 0; i < n->data.list->idx; i++) {
SYMID oid = syck_seq_read(n, i);
zval *o2 = NULL;
zval *key = NULL;
syck_lookup_sym(p, oid, (char **) &o2); /* retrieving child-node */
MAKE_STD_ZVAL(key);
ZVAL_LONG(key, i);
zend_call_method_with_2_params(&o, *ce, NULL, "offsetset", NULL, key, o2);
zval_ptr_dtor(&o2);
efree(key);
}
if (zend_hash_exists(&(*ce)->function_table, "__wakeup", 9)) {
zend_call_method_with_0_params(&o, *ce, NULL, "__wakeup", NULL);
}
} else {
zend_throw_exception_ex(syck_exception_entry, 0 TSRMLS_CC, "Class %s doesn't implement ArrayAccess on line %d, col %d: '%s'", classname, p->linect + 1, p->cursor - p->lineptr, p->lineptr);
efree(classname);
break;
}
efree(classname);
} else {
size_t i;
if (NULL != n->type_id && strcmp(n->type_id, "php/array") != 0) {
php_error(E_NOTICE, "syck extension didn't handle sequence of %s type. treating as php/array", n->type_id);
}
/* Just an array */
array_init(o);
for (i = 0; i < n->data.list->idx; i++) {
SYMID oid = syck_seq_read(n, i);
zval *o2 = NULL;
syck_lookup_sym(p, oid, (char **) &o2); /* retrieving child-node */
add_index_zval(o, i, o2);
}
}
}
break;
case syck_map_kind:
{
if (NULL != n->type_id && strncmp(n->type_id, "php/hash::", 10) == 0) {
/* some class which implements ArrayAccess */
SYMID oid;
size_t i;
zval *o2 = NULL, *o3 = NULL;
size_t classname_len = strlen(n->type_id) - 10;
char *classname = emalloc(classname_len + 1);
zend_class_entry **ce;
TSRMLS_FETCH();
strncpy(classname, n->type_id + 10, classname_len + 1);
if (FAILURE == zend_lookup_class_ex(classname, classname_len, 1, &ce TSRMLS_CC)) {
zend_throw_exception_ex(syck_exception_entry, 0 TSRMLS_CC, "Couldn't find %s class on line %d, col %d: '%s'", classname, p->linect + 1, p->cursor - p->lineptr, p->lineptr);
efree(classname);
break;
}
if (0 == instanceof_function_ex(*ce, zend_ce_arrayaccess, 1 TSRMLS_CC)) {
zend_throw_exception_ex(syck_exception_entry, 0 TSRMLS_CC, "Class %s doesn't implement ArrayAccess on line %d, col %d: '%s'", classname, p->linect + 1, p->cursor - p->lineptr, p->lineptr);
efree(classname);
break;
}
object_init_ex(o, *ce);
for (i = 0; i < n->data.pairs->idx; i++) {
oid = syck_map_read(n, map_key, i);
syck_lookup_sym(p, oid, (char **) &o2); /* retrieving key-node */
if (o2->type == IS_STRING || o2->type == IS_LONG) {
oid = syck_map_read(n, map_value, i);
syck_lookup_sym(p, oid, (char **) &o3); /* retrieving value-node */
zend_call_method_with_2_params(&o, *ce, NULL, "offsetset", NULL, o2, o3);
zval_ptr_dtor(&o3);
}
zval_ptr_dtor(&o2);
}
if (zend_hash_exists(&(*ce)->function_table, "__wakeup", 9)) {
zend_call_method_with_0_params(&o, *ce, NULL, "__wakeup", NULL);
}
efree(classname);
} else {
SYMID oid;
size_t i;
zval *o2 = NULL, *o3 = NULL;
zval *res = NULL;
if (NULL != n->type_id && strcmp(n->type_id, "php/hash") != 0) {
php_error(E_NOTICE, "syck extension didn't handle map of %s type. treating as php/hash", n->type_id);
}
array_init(o);
for (i = 0; i < n->data.pairs->idx; i++) {
oid = syck_map_read(n, map_key, i);
syck_lookup_sym(p, oid, (char **) &o2); /* retrieving key-node */
if (o2->type == IS_STRING || o2->type == IS_LONG) {
oid = syck_map_read(n, map_value, i);
syck_lookup_sym(p, oid, (char **) &o3); /* retrieving value-node */
if (o2->type == IS_LONG) {
add_index_zval(o, Z_LVAL_P(o2), o3);
} else {
add_assoc_zval(o, Z_STRVAL_P(o2), o3);
}
}
zval_ptr_dtor(&o2);
}
}
}
break;
}
return syck_add_sym(p, (char *)o); /* storing node */
}
SyckNode * php_syck_badanchor_handler(SyckParser *p, const char *str)
{
SyckNode *res;
char *endl = p->cursor;
TSRMLS_FETCH();
while (*endl != '\0' && *endl != '\n')
endl++;
endl[0] = '\0';
res = syck_alloc_str();
zend_throw_exception_ex(syck_exception_entry, 0 TSRMLS_CC, "bad anchor \"%s\" on line %d, col %d", str, p->linect + 1, p->cursor - p->lineptr - strlen(str));
return res;
}
enum st_retval my_cleaner(char *key, char *value, char *smth)
{
zval *ptr = (zval *)value;
zval_ptr_dtor(&ptr);
return ST_DELETE;
}
void php_syck_ehandler(SyckParser *p, const char *str)
{
char *endl = p->cursor;
zval *exc;
TSRMLS_FETCH();
while (*endl != '\0' && *endl != '\n')
endl++;
endl[0] = '\0';
if (NULL == p->bonus) {
/* silence second exceptions */
exc = zend_throw_exception_ex(syck_exception_entry, 0 TSRMLS_CC, "%s on line %d, col %d: '%s'", str, p->linect + 1, p->cursor - p->lineptr, p->lineptr);
Z_SET_REFCOUNT_P(exc, 2);
p->bonus = exc;
}
if (p->syms)
st_foreach(p->syms, my_cleaner, NULL);
}
void php_syck_emitter_handler(SyckEmitter *e, st_data_t id)
{
php_syck_emitter_xtra *bonus = (php_syck_emitter_xtra *) e->bonus;
zval *data = bonus->stack[id];
TSRMLS_FETCH();
switch (Z_TYPE_P(data)) {
case IS_NULL:
syck_emit_scalar(e, "null", scalar_none, 0, 0, 0, "", 0);
break;
case IS_BOOL:
{
char *bool_s = Z_BVAL_P(data) ? "true" : "false";
syck_emit_scalar(e, "boolean", scalar_none, 0, 0, 0, bool_s, strlen(bool_s));
}
break;
case IS_LONG:
{
size_t res_size;
char *res = NULL;
res_size = snprintf(res, 0, "%ld", Z_LVAL_P(data)); /* getting size ("0" doesn't let output) */
res = emalloc(res_size + 1);
snprintf(res, res_size + 1, "%ld", Z_LVAL_P(data));
syck_emit_scalar(e, "number", scalar_none, 0, 0, 0, res, res_size);
efree(res);
}
break;
case IS_DOUBLE:
{
size_t res_size;
char *res = NULL;
res_size = snprintf(res, 0, "%f", Z_DVAL_P(data)); /* getting size ("0" doesn't let output) */
res = emalloc(res_size + 1);
snprintf(res, res_size + 1, "%f", Z_DVAL_P(data));
syck_emit_scalar(e, "number", scalar_none, 0, 0, 0, res, res_size);
efree(res);
}
break;
case IS_STRING:
{
enum scalar_style style = scalar_2quote;
const char *ptr;
for (ptr = Z_STRVAL_P(data); ptr != Z_STRVAL_P(data) + Z_STRLEN_P(data); ptr++) {
if (*ptr == '\n') {
style = scalar_fold;
}
}
syck_emit_scalar(e, "str", style, 0, 0, 0, Z_STRVAL_P(data), Z_STRLEN_P(data));
}
break;
case IS_ARRAY:
{
HashTable *tbl = Z_ARRVAL_P(data);
int flat_and_short = false;
/* we try to detect if array is short and flat */
if (tbl->nNumOfElements <= 6) {
flat_and_short = true;
for (zend_hash_internal_pointer_reset(tbl); zend_hash_has_more_elements(tbl) == SUCCESS; zend_hash_move_forward(tbl)) {
zval **ppzval = NULL;
zend_hash_get_current_data(tbl, (void **)&ppzval);
if (Z_TYPE_P(*ppzval) == IS_ARRAY || Z_TYPE_P(*ppzval) == IS_OBJECT) {
flat_and_short = false;
}
}
}
if (0 == psex_determine_array_type(tbl TSRMLS_CC)) {
/* indexed array */
if (flat_and_short)
syck_emit_seq(e, "table", seq_inline);
else
syck_emit_seq(e, "table", seq_none);
for (zend_hash_internal_pointer_reset(tbl); zend_hash_has_more_elements(tbl) == SUCCESS; zend_hash_move_forward(tbl)) {
zval **ppzval = NULL;
zend_hash_get_current_data(tbl, (void **)&ppzval);
if (psex_push_obj(bonus, *ppzval)) {
syck_emit_item(e, bonus->level);
psex_pop_obj(bonus);
}
}
syck_emit_end(e);
} else {
/* associative array */
if (flat_and_short)
syck_emit_map(e, "table", map_inline);
else
syck_emit_map(e, "table", map_none);
for (zend_hash_internal_pointer_reset(tbl); zend_hash_has_more_elements(tbl) == SUCCESS; zend_hash_move_forward(tbl)) {
zval **ppzval = NULL, kzval;
uint key_len;
ulong idx;
size_t key_type;
key_type = zend_hash_get_current_key_type_ex(tbl, NULL);
if (key_type == HASH_KEY_IS_LONG) {
zend_hash_get_current_key_ex(tbl, NULL, NULL, &idx, 0, NULL);
ZVAL_LONG(&kzval, idx);
} else {
char *skey = NULL;
zend_hash_get_current_key_ex(tbl, (char **)&skey, &key_len, NULL, 0, NULL);
ZVAL_STRINGL(&kzval, skey, key_len - 1, 1);
}
zend_hash_get_current_data(tbl, (void **)&ppzval);
if (psex_push_obj(bonus, &kzval)) {
syck_emit_item(e, bonus->level);
psex_pop_obj(bonus);
if (psex_push_obj(bonus, *ppzval)) {
syck_emit_item(e, bonus->level);
psex_pop_obj(bonus);
}
}
zval_dtor(&kzval);
}
syck_emit_end(e);
}
}
break;
case IS_OBJECT:
{
char *name = NULL;
zend_uint name_len;
zend_class_entry *ce;
TSRMLS_FETCH();
ce = Z_OBJCE_P(data);
zend_get_object_classname(data, &name, &name_len TSRMLS_CC);
if (strncmp(name, "DateTime", name_len) == 0) {
/* DateTime is encoded as timestamp */
zval *retval = NULL;
zval constant;
#if ZEND_MODULE_API_NO >= 20071006
zend_get_constant_ex("DateTime::ISO8601", 17, &constant, ce, 0 TSRMLS_CC);
#else
zend_get_constant_ex("DateTime::ISO8601", 17, &constant, ce TSRMLS_CC);
#endif
zend_call_method_with_1_params(&data, ce, NULL, "format", &retval, &constant);
zval_dtor(&constant);
syck_emit_scalar(e, "tag:yaml.org,2002:timestamp#iso8601", scalar_none, 0, 0, 0, Z_STRVAL_P(retval), Z_STRLEN_P(retval));
zval_dtor(retval);
efree(retval);
} else {
if (0 != instanceof_function_ex(ce, zend_ce_serializable, 1 TSRMLS_CC)) {
/* Some class which implements Serializable interface */
char *prefix = "tag:php:object::";
size_t prefix_len = strlen(prefix) + 1;
char *tagname = emalloc(name_len + prefix_len);
zval *serialized = NULL;
snprintf(tagname, name_len + prefix_len, "%s%s", prefix, name);
zend_call_method_with_0_params(&data, ce, NULL, "serialize", &serialized);
syck_emit_scalar(e, tagname, scalar_2quote, 0, 0, 0, Z_STRVAL_P(serialized), Z_STRLEN_P(serialized));
efree(tagname);
}
}
efree(name);
}
break;
case IS_RESOURCE:
default:
/* something unknown */
break;
}
}
void php_syck_output_handler(SyckEmitter *e, const char *str, long len)
{
php_syck_emitter_xtra *bonus = (php_syck_emitter_xtra *) e->bonus;
psex_add_output(bonus, str, (size_t)len);
}
/* {{{ proto object syck_load(string arg)
Return PHP object from a YAML string */
PHP_FUNCTION(syck_load)
{
char *arg = NULL;
int arg_len;
SYMID v;
zval *obj = NULL;
SyckParser *parser;
if (ZEND_NUM_ARGS() != 1) {
WRONG_PARAM_COUNT;
}
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arg, &arg_len) == FAILURE) {
return;
}
parser = syck_new_parser();
syck_parser_handler(parser, php_syck_handler);
syck_parser_bad_anchor_handler(parser, php_syck_badanchor_handler);
syck_parser_error_handler(parser, php_syck_ehandler);
syck_parser_implicit_typing(parser, 1);
syck_parser_taguri_expansion(parser, 0);
syck_parser_str(parser, arg, arg_len, NULL);
v = syck_parse(parser);
if (parser->bonus) {
*return_value = *((zval *)parser->bonus);
zval_copy_ctor(return_value);
// zval_ptr_dtor(&obj);
} else {
if (1 == syck_lookup_sym(parser, v, (char **) &obj)) {
if (NULL != &obj && NULL != obj) {
*return_value = *obj;
zval_copy_ctor(return_value);
zval_ptr_dtor(&obj);
}
}
}
syck_free_parser(parser);
}
/* }}} */
/* {{{ proto object syck_load(string arg)
Convert PHP object into YAML string */
PHP_FUNCTION(syck_dump)
{
SyckEmitter *emitter;
php_syck_emitter_xtra *extra;
zval *ptr;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &ptr) == FAILURE) {
return;
}
extra = emalloc(sizeof(php_syck_emitter_xtra));
psex_init(extra);
psex_push_obj(extra, ptr);
emitter = syck_new_emitter();
emitter->bonus = extra;
emitter->use_header = 1;
emitter->use_version = 1;
syck_emitter_handler(emitter, php_syck_emitter_handler);
syck_output_handler(emitter, php_syck_output_handler);
syck_emit(emitter, extra->level);
syck_emitter_flush(emitter, 0);
ZVAL_STRINGL(return_value, extra->output, extra->output_size, 1);
psex_free(extra);
efree(extra);
syck_free_emitter(emitter);
}
/* }}} */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
Jump to Line
Something went wrong with that request. Please try again.