Exetools  

Go Back   Exetools > General > General Discussion

Notices

Reply
 
Thread Tools Display Modes
  #16  
Old 07-01-2014, 18:11
bytexorer bytexorer is offline
Friend
 
Join Date: Mar 2005
Posts: 12
Rept. Given: 0
Rept. Rcvd 7 Times in 1 Post
Thanks Given: 2
Thanks Rcvd at 0 Times in 0 Posts
bytexorer Reputation: 7
Any news on reversing ioncube?
also,while on this topic, any body knows how plesk .php and .php3 files are encrypted?
Reply With Quote
  #17  
Old 07-01-2014, 18:51
giv's Avatar
giv giv is offline
VIP
 
Join Date: Jan 2011
Location: Romania
Posts: 1,657
Rept. Given: 801
Rept. Rcvd 1,283 Times in 561 Posts
Thanks Given: 226
Thanks Rcvd at 562 Times in 240 Posts
giv Reputation: 1100-1299 giv Reputation: 1100-1299 giv Reputation: 1100-1299 giv Reputation: 1100-1299 giv Reputation: 1100-1299 giv Reputation: 1100-1299 giv Reputation: 1100-1299 giv Reputation: 1100-1299 giv Reputation: 1100-1299
You can ask Narciszu.
Reply With Quote
The Following User Gave Reputation+1 to giv For This Useful Post:
Mahmoudnia (07-05-2014)
  #18  
Old 07-05-2014, 05:06
Mahmoudnia's Avatar
Mahmoudnia Mahmoudnia is offline
Family
 
Join Date: Nov 2012
Posts: 228
Rept. Given: 64
Rept. Rcvd 142 Times in 49 Posts
Thanks Given: 198
Thanks Rcvd at 282 Times in 97 Posts
Mahmoudnia Reputation: 100-199 Mahmoudnia Reputation: 100-199
I don't have any encoded file with v7, but if you have, maybe i can help you. A few years ago I had the same question but there was no helpfull reference.
guys I'm not a decoder service!!!, just for testing decoded file.
Reply With Quote
  #19  
Old 07-05-2014, 16:32
uranus64 uranus64 is offline
VIP
 
Join Date: Mar 2011
Location: EE
Posts: 315
Rept. Given: 595
Rept. Rcvd 462 Times in 140 Posts
Thanks Given: 480
Thanks Rcvd at 241 Times in 82 Posts
uranus64 Reputation: 400-499 uranus64 Reputation: 400-499 uranus64 Reputation: 400-499 uranus64 Reputation: 400-499 uranus64 Reputation: 400-499
Encoded files with version 7 of Ioncube Encoder are more or less usefull these days. Exist already many tools able to decode encoded files with version 8 of the encoder.

I have last version of encoder with legit license. I have also source code for old version 6 that was leaked (and still exist on the internet). I have some tools able to decode version 8 via patched ioncube loader dll. I patched myself version 4.6.1 of loader - last one.

PHP is open source. We need to modify and recompile PHP engine for good results. All free decoder that exist today are based on modified PHP engine (old dezend engine). Differences between original php.exe and modified one need to be this: original php.exe executes instructions on web server but modified one needs to output source code instead of executes.

None decoders are able to deobfuscate functions and/or variable names if developer used this option in encoding process.

We need a motivated group in order to make a new valuable decoder for this.
Reply With Quote
The Following User Gave Reputation+1 to uranus64 For This Useful Post:
Mahmoudnia (07-05-2014)
The Following User Says Thank You to uranus64 For This Useful Post:
niculaita (06-06-2018)
  #20  
Old 07-05-2014, 23:01
Mahmoudnia's Avatar
Mahmoudnia Mahmoudnia is offline
Family
 
Join Date: Nov 2012
Posts: 228
Rept. Given: 64
Rept. Rcvd 142 Times in 49 Posts
Thanks Given: 198
Thanks Rcvd at 282 Times in 97 Posts
Mahmoudnia Reputation: 100-199 Mahmoudnia Reputation: 100-199
I found ionCube v6.0 leaked version and ionCube v7.0 cracked version by yoza and also I have a decoder that works on ionCube v8.0. So, for decoding functions we need to patch ionCube loader dll and modify php.exe ? becuase I'm working on Truebug right now.

could you please more details narciszu ? ionCube loader is a normal DLL ? can we use dynamic debugging?
Reply With Quote
  #21  
Old 10-10-2015, 23:06
CryptXor CryptXor is offline
Friend
 
Join Date: Oct 2015
Posts: 68
Rept. Given: 0
Rept. Rcvd 24 Times in 12 Posts
Thanks Given: 34
Thanks Rcvd at 131 Times in 39 Posts
CryptXor Reputation: 24
I do not know if this qualifies as digging up an old post or not; but I think the following code would be useful to someone somehow I have an updated version specifically for ionCube 6 & 7 if I can find it...
Code:
/***********************************************************************/
/*                                                                     */
/*  FILE        :dezender.c                                            */
/*  DATE        :2005/08/10                                            */
/*  DESCRIPTION :opcode->php source code                               */
/*  PROJECT     :deZender                                              */
/*                                                                     */
/***********************************************************************/


#include "php.h"
#include "ext/standard/url.h"


#if 0
#define ZEND_NOP					0				/* NOP */
#define ZEND_ADD					1				/* + */
#define ZEND_SUB					2				/* - */
#define ZEND_MUL					3				/* * */
#define ZEND_DIV					4				/* / */
#define ZEND_MOD					5				/* % */
#define ZEND_SL						6				/* << */
#define ZEND_SR						7				/* >> */
#define ZEND_CONCAT					8				/* . */
#define ZEND_BW_OR					9				/* | */
#define ZEND_BW_AND					10				/* & */
#define ZEND_BW_XOR					11				/* ^ */
#define ZEND_BW_NOT					12				/* ~ */
#define ZEND_BOOL_NOT				13				/* ! */
#define ZEND_BOOL_XOR				14				/* XOR */
#define ZEND_IS_IDENTICAL			15				/* === */
#define ZEND_IS_NOT_IDENTICAL		16				/* !== */
#define ZEND_IS_EQUAL				17				/* == */
#define ZEND_IS_NOT_EQUAL			18				/* != */
#define ZEND_IS_SMALLER				19				/* < */
#define ZEND_IS_SMALLER_OR_EQUAL	20				/* <= */
#define ZEND_CAST					21				/* (int), (real), (string), (array), (object), (bool), (unset) */
#define ZEND_QM_ASSIGN				22				/* a?b:c */
#define ZEND_ASSIGN_ADD				23				/* += */
#define ZEND_ASSIGN_SUB				24				/* -= */
#define ZEND_ASSIGN_MUL				25				/* *= */
#define ZEND_ASSIGN_DIV				26				/* /= */
#define ZEND_ASSIGN_MOD				27				/* %= */
#define ZEND_ASSIGN_SL				28				/* <<= */
#define ZEND_ASSIGN_SR				29				/* >>= */
#define ZEND_ASSIGN_CONCAT			30				/* .= */
#define ZEND_ASSIGN_BW_OR			31				/* |= */
#define ZEND_ASSIGN_BW_AND			32				/* &= */
#define ZEND_ASSIGN_BW_XOR			33				/* ^= */
#define ZEND_PRE_INC				34				/* ++a */
#define ZEND_PRE_DEC				35				/* --a */
#define ZEND_POST_INC				36				/* a++ */
#define ZEND_POST_DEC				37				/* a-- */
#define ZEND_ASSIGN					38				/* = */
#define ZEND_ASSIGN_REF				39				/* =&a */
#define ZEND_ECHO					40				/* echo */
#define ZEND_PRINT					41				/* print */
#define ZEND_JMP					42				/* JMP */
#define ZEND_JMPZ					43				/* JMPZ */
#define ZEND_JMPNZ					44				/* JMPNZ */
#define ZEND_JMPZNZ					45				/* JMPZNZ */
#define ZEND_JMPZ_EX				46				/* JMPZ_EX */
#define ZEND_JMPNZ_EX				47				/* JMPNZ_EX */
#define ZEND_CASE					48				/* case */
#define ZEND_SWITCH_FREE			49				/* return, foreach, switch */
#define ZEND_BRK					50				/* break */
#define ZEND_CONT					51				/* continue */
#define ZEND_BOOL					52				/* ||, &&, switch(expr), default:  */
#define ZEND_INIT_STRING			53				/* '' */
#define ZEND_ADD_CHAR				54				/* . */
#define ZEND_ADD_STRING				55				/* . */
#define ZEND_ADD_VAR				56				/* . */
#define ZEND_BEGIN_SILENCE			57				/* @:begin */
#define ZEND_END_SILENCE			58				/* @:end */
#define ZEND_INIT_FCALL_BY_NAME		59				/* call function */
#define ZEND_DO_FCALL				60				/* call function */
#define ZEND_DO_FCALL_BY_NAME		61				/* call function */
#define ZEND_RETURN					62				/* return */
#define ZEND_RECV					63				/* function parameter */
#define ZEND_RECV_INIT				64				/* function parameter: static? */
#define ZEND_SEND_VAL				65				/* function call parameter: without variable  */
#define ZEND_SEND_VAR				66				/* function call parameter: variable */
#define ZEND_SEND_REF				67				/* function call parameter: &variable */
#define ZEND_NEW 					68				/* new */
#define ZEND_JMP_NO_CTOR			69				/* free, end of new */
#define ZEND_FREE					70				/* free */
#define ZEND_INIT_ARRAY				71				/* array pair list (a => b, ...) */
#define ZEND_ADD_ARRAY_ELEMENT		72				/* array pair list (a => b, ...) */
#define ZEND_INCLUDE_OR_EVAL		73				/* include, include_once, evel, require, require_once */
#define ZEND_UNSET_VAR				74				/* unset variable */
#define ZEND_UNSET_DIM_OBJ			75				/* unset dim, unset object */
#define ZEND_ISSET_ISEMPTY			76				/* isset, empty */
#define ZEND_FE_RESET				77				/* foreach */
#define ZEND_FE_FETCH				78				/* foreach */
#define ZEND_EXIT					79				/* exit */
#define ZEND_FETCH_R				80				/* fetch variable: read mode */
#define ZEND_FETCH_DIM_R			81				/* fetch dim: read mode */
#define ZEND_FETCH_OBJ_R			82				/* fetch object: read mode */
#define ZEND_FETCH_W				83				/* fetch variable: write mode */
#define ZEND_FETCH_DIM_W			84				/* fetch dim: write mode */
#define ZEND_FETCH_OBJ_W			85				/* fetch object: write mode */
#define ZEND_FETCH_RW				86				/* fetch variable: read/write mode */
#define ZEND_FETCH_DIM_RW			87				/* fetch dim: read/write mode */
#define ZEND_FETCH_OBJ_RW			88				/* fetch object: read/write mode */
#define ZEND_FETCH_IS				89				/* fetch variable: is mode */
#define ZEND_FETCH_DIM_IS			90				/* fetch dim: is mode */
#define ZEND_FETCH_OBJ_IS			91				/* fetch object: is mode */
#define ZEND_FETCH_FUNC_ARG			92				/* fetch variable: argument mode */
#define ZEND_FETCH_DIM_FUNC_ARG		93				/* fetch dim: argument mode */
#define ZEND_FETCH_OBJ_FUNC_ARG		94				/* fetch object: argument mode */
#define ZEND_FETCH_UNSET			95				/* fetch unset variable */
#define ZEND_FETCH_DIM_UNSET		96				/* fetch unset dim */
#define ZEND_FETCH_OBJ_UNSET		97				/* fetch unset object */
#define ZEND_FETCH_DIM_TMP_VAR		98				/* list, foreach */
#define ZEND_FETCH_CONSTANT			99				/* constant declaration */
#define ZEND_DECLARE_FUNCTION_OR_CLASS	100			/* function, class */
#define ZEND_EXT_STMT				101				/* ??? */
#define ZEND_EXT_FCALL_BEGIN		102				/* ??? */
#define ZEND_EXT_FCALL_END			103				/* ??? */
#define ZEND_EXT_NOP				104				/* ??? */
#define ZEND_TICKS					105				/* declare (ticks=?) */
#define ZEND_SEND_VAR_NO_REF		106				/* function call parameter: no reference */
#endif

/*-- for php 5.0.4 --*/
#define ZEND_CATCH					107
#define ZEND_THROW					108
#define ZEND_FETCH_CLASS			109
#define ZEND_CLONE					110
#define ZEND_INIT_CTOR_CALL			111
#define ZEND_INIT_METHOD_CALL		112
#define ZEND_INIT_STATIC_METHOD_CALL 113
#define ZEND_ISSET_ISEMPTY_VAR		114
#define ZEND_ISSET_ISEMPTY_DIM_OBJ	115
#define	ZEND_IMPORT_FUNCTION		116
#define	ZEND_IMPORT_CLASS			117
#define	ZEND_IMPORT_CONST			118
#define ZEND_PRE_INC_OBJ			132
#define ZEND_PRE_DEC_OBJ			133
#define ZEND_POST_INC_OBJ			134
#define ZEND_POST_DEC_OBJ			135
#define ZEND_ASSIGN_OBJ				136
#define ZEND_OP_DATA				137
#define ZEND_INSTANCEOF				138
//#define ZEND_DECLARE_CLASS				139
//#define ZEND_DECLARE_INHERITED_CLASS	140
//#define ZEND_DECLARE_FUNCTION			141
#define ZEND_RAISE_ABSTRACT_ERROR	142


#define DEZ_OP_NOP						0			/* NOP */
#define DEZ_OP_ADD						1   		/* + */
#define DEZ_OP_SUB						2   		/* - */
#define DEZ_OP_MUL						3   		/* * */
#define DEZ_OP_DIV						4   		/* / */
#define DEZ_OP_MOD						5   		/* % */
#define DEZ_OP_SL						6   		/* << */
#define DEZ_OP_SR						7   		/* >> */
#define DEZ_OP_CONCAT					8   		/* . */
#define DEZ_OP_BW_OR					9   		/* | */
#define DEZ_OP_BW_AND					10  		/* & */
#define DEZ_OP_BW_XOR					11  		/* ^ */
#define DEZ_OP_BW_NOT					12  		/* ~ */
#define DEZ_OP_BOOL_NOT					13  		/* ! */
#define DEZ_OP_IS_IDENTICAL				14  		/* === */
#define DEZ_OP_IS_NOT_IDENTICAL			15  		/* !== */
#define DEZ_OP_IS_EQUAL					16  		/* == */
#define DEZ_OP_IS_NOT_EQUAL				17  		/* != */
#define DEZ_OP_IS_SMALLER				18  		/* < */
#define DEZ_OP_IS_SMALLER_OR_EQUAL		19  		/* <= */
#define	DEZ_OP_CAST						20  		/* (double)a, (string)a, (array)a, (object)a, (bool)a, (unset)a */
#define DEZ_OP_QM_ASSIGN				21  		/* a?b:c */
#define DEZ_OP_ASSIGN_ADD				22  		/* += */
#define DEZ_OP_ASSIGN_SUB				23  		/* -= */
#define DEZ_OP_ASSIGN_MUL				24  		/* *= */
#define DEZ_OP_ASSIGN_DIV				25  		/* /= */
#define DEZ_OP_ASSIGN_MOD				26  		/* %= */
#define DEZ_OP_ASSIGN_SL				27  		/* <<= */
#define DEZ_OP_ASSIGN_SR				28  		/* >>= */
#define DEZ_OP_ASSIGN_CONCAT			29  		/* .= */
#define DEZ_OP_ASSIGN_BW_OR				30  		/* |= */
#define DEZ_OP_ASSIGN_BW_AND			31  		/* &= */
#define DEZ_OP_ASSIGN_BW_XOR			32  		/* ^= */
#define DEZ_OP_PRE_INC					33  		/* ++a */
#define DEZ_OP_PRE_DEC					34  		/* --a */
#define DEZ_OP_POST_INC					35  		/* a++ */
#define DEZ_OP_POST_DEC					36  		/* a-- */
#define DEZ_OP_ASSIGN					37  		/* = */
#define DEZ_OP_ASSIGN_REF				38  		/* =&a, static, global */
#define DEZ_OP_ECHO						39  		/* echo */
#define DEZ_OP_PRINT					40  		/* print */
#define	DEZ_OP_INCLUDE_OR_EVAL			41  		/* include, include_once, eval, require, require_once */
#define	DEZ_OP_LOGICAL_OR				42  		/* OR */
#define	DEZ_OP_LOGICAL_XOR				43  		/* XOR */
#define	DEZ_OP_LOGICAL_AND				44  		/* AND */
#define	DEZ_OP_NEW						45  		/* new */
#define	DEZ_OP_EXIT						46  		/* exit */
#define	DEZ_OP_IF						47  		/* if */
#define	DEZ_OP_ELSEIF					48  		/* elseif */
#define	DEZ_OP_ELSE						49  		/* else */
#define	DEZ_OP_DO						50  		/* do */
#define	DEZ_OP_WHILE					51  		/* while */
#define	DEZ_OP_FOR						52  		/* for */
#define	DEZ_OP_FOREACH					53  		/* foreach */
#define	DEZ_OP_DECLARE					54  		/* declare */
#define	DEZ_OP_AS						55  		/* as */
#define	DEZ_OP_SWITCH					56  		/* switch */
#define	DEZ_OP_CASE						57  		/* case */
#define	DEZ_OP_DEFAULT					58  		/* default */
#define	DEZ_OP_BREAK					59  		/* break */
#define	DEZ_OP_CONTINUE					60  		/* continue */
#define	DEZ_OP_OLD_FUNCTION				61  		/* old_function */
#define	DEZ_OP_FUNCTION					62  		/* function */
#define	DEZ_OP_CONST					63  		/* const */
#define	DEZ_OP_RETURN					64  		/* return */
#define	DEZ_OP_USE						65  		/* use */
#define	DEZ_OP_VAR						66  		/* var */
#define	DEZ_OP_UNSET					67  		/* unset */
#define	DEZ_OP_ISSET					68  		/* isset */
#define	DEZ_OP_EMPTY					69  		/* empty */
#define	DEZ_OP_CLASS					70  		/* class */
#define	DEZ_OP_EXTENDS					71  		/* extends */
#define	DEZ_OP_OBJECT_OPERATOR			72  		/* a->b */
#define	DEZ_OP_DOUBLE_ARROW				73  		/* a=>b */
#define	DEZ_OP_LIST						74  		/* list */
#define	DEZ_OP_ARRAY					75  		/* array */
#define	DEZ_OP_CLASS_C					76  		/* __CLASS__ */
#define	DEZ_OP_FUNC_C					77  		/* __FUNCTION__ */
#define	DEZ_OP_LINE						78  		/* __LINE__ */
#define	DEZ_OP_FILE						79  		/* __FILE__ */
#define	DEZ_OP_COMMENT					80  		/* comment */
#define	DEZ_OP_HEREDOC					81  		/* <<< */
#define	DEZ_OP_DOLLAR_OPEN_CURLY_BRACES	82  		/* ${...} */
#define	DEZ_OP_PAAMAYIM_NEKUDOTAYIM		83  		/* :: */
#define DEZ_OP_CALL_PARAM				84  		/* parameter of function calling */
#define DEZ_OP_CALL_INIT				85  		/* initialize function calling */
#define DEZ_OP_CALL						86  		/* function call */
#define DEZ_OP_CALL_EX					87  		/* function call (ex) */
#define DEZ_OP_BOOL						88  		/* end of OR, AND, ... */
#define DEZ_OP_FETCH_DIM				89  		/* fetch dim */
#define DEZ_OP_INIT_STRING				90  		/* init string */
#define DEZ_OP_FETCH					91  		/* fetch variable */
#define DEZ_OP_FETCH_CONSTANT			92  		/* fetch constant */
#define DEZ_OP_JMP						93  		/* jmp */
#define DEZ_OP_FUNC_PARAM				94  		/* parameter of function */
#define DEZ_OP_BEGIN_SILENCE			95  		/* @: begin */
#define DEZ_OP_END_SILENCE				96  		/* @: end */
#define DEZ_OP_LE						97  		/* list element */
#define DEZ_OP_UNKNOWN					98  		/* unknown op */

#define DEZ_IS_OPLINE					(1<<15)
#define DEZ_IS_CLASS					(1<<16)

#define OPC_STACK_SIZE					1024
#define OPCS_MAX_LEN					16
#define DEZ_VARS_NUM					1024
#define NODE_STACK_SIZE					2048


#define DEZ_ADD_NODE(x)					\
	m_dez_op_prev	= (x);				\
	(x)->prev		= m_dez_op_current;	\
	(x)->next		= NULL;				\
	if (m_dez_op_current != NULL)		\
	{									\
		m_dez_op_current->next	= (x);	\
	}									\
	m_dez_op_current		= (x);


#define DEZ_DEL_NODE(x)												\
	if ((x)->prev != NULL) (x)->prev->next = (x)->next;				\
	if ((x)->next != NULL) (x)->next->prev = (x)->prev;				\
	(x)->next = NULL;												\
	if (m_dez_op_current == (x)) m_dez_op_current = (x)->prev;		\
	dez_node_specs[(x)->dez_op].dez_node_free_func(x);


#define DEZ_DEL_CURRENT_NODE()			\
	m_dez_op_current		= m_dez_op_current->prev;	\
	dez_node_specs[m_dez_op_current->next->dez_op].dez_node_free_func(m_dez_op_current->next);	\
	m_dez_op_current->next	= NULL;


#define ZEND_LINENUM(x)					\
	((x) == NULL ? 0 : ((x) >= (zend_op *)m_zend_op_dup && (x) < (zend_op *)(m_zend_op_dup+m_zend_op_dup_num) ? *((int *)((x)+1)) : ((x) - m_zend_op_start)))


typedef struct
{
	zend_op zop;
	int linenum;
} DEZ_ZEND_OP_DUP;

typedef struct
{
	int index;
	char varname[1024];
} DEZ_VAR;

typedef struct DEZ_EG_VAR_NAME_t
{
	unsigned type;
	char *var;
	unsigned len;
	unsigned other;
} DEZ_EG_VAR_NAME;

typedef struct DEZ_EG_FUNC_NAME_t
{
	unsigned type;
	char *func;
	unsigned len;
	unsigned other;
} DEZ_EG_FUNC_NAME;

typedef struct DEZ_EG_FUNC_t
{
	DEZ_EG_FUNC_NAME *funcs;
	unsigned func_num;
	unsigned r2;
	unsigned r3;
} DEZ_EG_FUNC;

typedef struct DEZ_EG_E_t
{
	unsigned r1;
	unsigned r2;
	unsigned r3;
	unsigned r4;
	unsigned r5;
	unsigned r6;
	void *p1;
	unsigned char *zop2op;
	void *p2;
	unsigned r7;
	void *p3;
	unsigned r8;
} DEZ_EG_E;

typedef struct DEZ_EG_RESERVED_t
{
	DEZ_EG_VAR_NAME	*vars;
	unsigned		var_num;
	unsigned		r1;
	DEZ_EG_FUNC		*funcs;
	unsigned		r2;
	DEZ_EG_E		*e;
	void			*p3;
} DEZ_EG_RESERVED;

/*-- type: dez node --*/
typedef struct DEZ_NODE_s
{
	unsigned char dez_op;							/* dez op code */
	zend_op *zop;
	void *content;									/* dez node content */
	struct DEZ_NODE_s *prev;						/* pointer the previous dez node */
	struct DEZ_NODE_s *next;						/* pointer the next dez node */
} DEZ_NODE;

/*-- dez node content: expression --*/
typedef struct DEZ_NODE_EXPR_s
{
	DEZ_NODE *branch_node;							/* must is first one */
	DEZ_NODE *op1_node;
	DEZ_NODE *op2_node;
} DEZ_NODE_EXPR;

/*-- dez node content: if --*/
typedef struct DEZ_NODE_IF_s
{
	DEZ_NODE *branch_node;							/* must is first one */
	DEZ_NODE *op1_node;
	DEZ_NODE *op2_node;
	int dest;
} DEZ_NODE_IF;

/*-- dez node content: for --*/
typedef struct DEZ_NODE_FOR_s
{
	DEZ_NODE *branch_node;							/* must is first one */
	DEZ_NODE *before_node;
	DEZ_NODE *cond_node;
	DEZ_NODE *after_node;
} DEZ_NODE_FOR;

/*-- dez node content: => --*/
typedef struct DEZ_NODE_DA_s
{
	DEZ_NODE *branch_node;							/* must is first one */
	DEZ_NODE *key_node;
	DEZ_NODE *value_node;
	DEZ_NODE *next_node;
} DEZ_NODE_DA;

/*-- dez node content: foreach --*/
typedef struct DEZ_NODE_FOREACH_s
{
	DEZ_NODE *branch_node;							/* must is first one */
	DEZ_NODE *source_node;
	DEZ_NODE *key_node;
	DEZ_NODE *value_node;
} DEZ_NODE_FOREACH;

/*-- dez node content: function --*/
typedef struct DEZ_NODE_FUNCTION_s
{
	DEZ_NODE *branch_node;							/* must is first one */
	DEZ_NODE *param_node;
	char *name;
	DEZ_VAR m_dez_vars[DEZ_VARS_NUM];
	int m_dez_var_num;
	zend_op_array *op_array;
} DEZ_NODE_FUNCTION;

/*-- dez node content: class --*/
typedef struct DEZ_NODE_CLASS_s
{
	DEZ_NODE *branch_node;							/* must is first one */
	char *name;
	zend_class_entry *parent;
} DEZ_NODE_CLASS;

/*-- dez node content: var --*/
typedef struct DEZ_NODE_VAR_s
{
	DEZ_NODE *branch_node;							/* must is first one */
	Bucket *property;
} DEZ_NODE_VAR;

/*-- dez node content: list element --*/
typedef struct DEZ_NODE_LE_s
{
	DEZ_NODE *branch_node;							/* must is first one */
	DEZ_NODE *a_node;
	int pos;
} DEZ_NODE_LE;

/*-- dez node content: list --*/
typedef struct DEZ_NODE_LIST_s
{
	DEZ_NODE *branch_node;							/* must is first one */
	DEZ_NODE *le_node;
	DEZ_NODE *dest_node;
	int level;
} DEZ_NODE_LIST;


typedef int (*DEZ_NODE_CVT_FUNC)(unsigned char dez_op, zend_op *pzop);
typedef int (*DEZ_NODE_OUTPUT_FUNC)(DEZ_NODE *pdez_node);
typedef void (*DEZ_NODE_FREE_FUNC)(DEZ_NODE *pdez_node);


static int dez_node_cvt_nop  (unsigned char dez_op, zend_op *pzop);
static int dez_node_cvt_expr (unsigned char dez_op, zend_op *pzop);
static int dez_node_cvt_qm_assign (unsigned char dez_op, zend_op *pzop);
static int dez_node_cvt_if (unsigned char dez_op, zend_op *pzop);
static int dez_node_cvt_do (unsigned char dez_op, zend_op *pzop);
static int dez_node_cvt_for (unsigned char dez_op, zend_op *pzop);
static int dez_node_cvt_foreach (unsigned char dez_op, zend_op *pzop);
static int dez_node_cvt_case (unsigned char dez_op, zend_op *pzop);
static int dez_node_cvt_default (unsigned char dez_op, zend_op *pzop);
static int dez_node_cvt_function_or_class (unsigned char dez_op, zend_op *pzop);
static int dez_node_cvt_double_arrow (unsigned char dez_op, zend_op *pzop);
static int dez_node_cvt_array (unsigned char dez_op, zend_op *pzop);
static int dez_node_cvt_heredoc (unsigned char dez_op, zend_op *pzop);
static int dez_node_cvt_dollar_open_curly_braces (unsigned char dez_op, zend_op *pzop);
static int dez_node_cvt_call (unsigned char dez_op, zend_op *pzop);
static int dez_node_cvt_bool (unsigned char dez_op, zend_op *pzop);
static int dez_node_cvt_jmp (unsigned char dez_op, zend_op *pzop);
static int dez_node_cvt_func_param (unsigned char dez_op, zend_op *pzop);
static int dez_node_cvt_unknown (unsigned char dez_op, zend_op *pzop);

static int dez_node_output_nop(DEZ_NODE *pdez_node);
static int dez_node_output_expr(DEZ_NODE *pdez_node);
static int dez_node_output_cast(DEZ_NODE *pdez_node);
static int dez_node_output_pre(DEZ_NODE *pdez_node);
static int dez_node_output_pre2(DEZ_NODE *pdez_node);
static int dez_node_output_post(DEZ_NODE *pdez_node);
static int dez_node_output_qm_assign(DEZ_NODE *pdez_node);
static int dez_node_output_assign(DEZ_NODE *pdez_node);
static int dez_node_output_assign_ref(DEZ_NODE *pdez_node);
static int dez_node_output_include_or_eval(DEZ_NODE *pdez_node);
static int dez_node_output_or_and(DEZ_NODE *pdez_node);
static int dez_node_output_new(DEZ_NODE *pdez_node);
static int dez_node_output_exit(DEZ_NODE *pdez_node);
static int dez_node_output_if(DEZ_NODE *pdez_node);
static int dez_node_output_do(DEZ_NODE *pdez_node);
static int dez_node_output_for(DEZ_NODE *pdez_node);
static int dez_node_output_foreach(DEZ_NODE *pdez_node);
static int dez_node_output_declare(DEZ_NODE *pdez_node);
static int dez_node_output_case(DEZ_NODE *pdez_node);
static int dez_node_output_default(DEZ_NODE *pdez_node);
static int dez_node_output_function(DEZ_NODE *pdez_node);
static int dez_node_output_var(DEZ_NODE *pdez_node);
static int dez_node_output_unset(DEZ_NODE *pdez_node);
static int dez_node_output_isset_or_empty(DEZ_NODE *pdez_node);
static int dez_node_output_class(DEZ_NODE *pdez_node);
static int dez_node_output_double_arrow(DEZ_NODE *pdez_node);
static int dez_node_output_list(DEZ_NODE *pdez_node);
static int dez_node_output_array(DEZ_NODE *pdez_node);
static int dez_node_output_heredoc(DEZ_NODE *pdez_node);
static int dez_node_output_dollar_open_curly_braces(DEZ_NODE *pdez_node);
static int dez_node_output_call_param(DEZ_NODE *pdez_node);
static int dez_node_output_call_init(DEZ_NODE *pdez_node);
static int dez_node_output_call(DEZ_NODE *pdez_node);
static int dez_node_output_call_ex(DEZ_NODE *pdez_node);
static int dez_node_output_fetch_dim(DEZ_NODE *pdez_node);
static int dez_node_output_init_string(DEZ_NODE *pdez_node);
static int dez_node_output_fetch_constant(DEZ_NODE *pdez_node);
static int dez_node_output_func_param(DEZ_NODE *pdez_node);
static int dez_node_output_property(DEZ_NODE *pdez_node);
static int dez_node_output_le(DEZ_NODE *pdez_node);
static int dez_node_output_unknown(DEZ_NODE *pdez_node);

static void dez_node_free_nop (DEZ_NODE *pdez_node);
static void dez_node_free_expr (DEZ_NODE *pdez_node);
static void dez_node_free_if (DEZ_NODE *pdez_node);
static void dez_node_free_for (DEZ_NODE *pdez_node);
static void dez_node_free_foreach (DEZ_NODE *pdez_node);
static void dez_node_free_case (DEZ_NODE *pdez_node);
static void dez_node_free_default (DEZ_NODE *pdez_node);
static void dez_node_free_function (DEZ_NODE *pdez_node);
static void dez_node_free_var (DEZ_NODE *pdez_node);
static void dez_node_free_class (DEZ_NODE *pdez_node);
static void dez_node_free_da (DEZ_NODE *pdez_node);
static void dez_node_free_list (DEZ_NODE *pdez_node);
static void dez_node_free_heredoc (DEZ_NODE *pdez_node);
static void dez_node_free_dollar_open_curly_braces (DEZ_NODE *pdez_node);
static void dez_node_free_property(DEZ_NODE *pdez_node);
static void dez_node_free_le (DEZ_NODE *pdez_node);
static void dez_node_free_unknown (DEZ_NODE *pdez_node);


typedef struct
{
	char *desc;
	DEZ_NODE_CVT_FUNC		dez_node_cvt_func;			/* the node convert function */
	DEZ_NODE_OUTPUT_FUNC 	dez_node_output_func;		/* the node output function */
	DEZ_NODE_FREE_FUNC		dez_node_free_func;			/* the node free function */
} DEZ_NODE_SPEC;

typedef struct
{
	unsigned char dez_op;							/* dez op code */
	short opcs_len;                 				/* the length of opcs[] */
	unsigned char opcs[OPCS_MAX_LEN];				/* the matching zend op codes */
} DEZ_OP_TYPE;

typedef struct DEZ_BRK_CNT_NODE_s
{
	const DEZ_NODE *node;							/* pointer to if(false) node */
	struct DEZ_BRK_CNT_NODE_s *prev;
	struct DEZ_BRK_CNT_NODE_s *next;
} DEZ_BRK_CNT_NODE;


static DEZ_VAR m_dez_vars[DEZ_VARS_NUM];
static int m_dez_var_num = 0;

static char *ZEND_OP_STRING[] = 
{
	"ZEND_NOP                         ",
	"ZEND_ADD                         ",
	"ZEND_SUB                         ",
	"ZEND_MUL                         ",
	"ZEND_DIV                         ",
	"ZEND_MOD                         ",
	"ZEND_SL                          ",
	"ZEND_SR                          ",
	"ZEND_CONCAT                      ",
	"ZEND_BW_OR                       ",
	"ZEND_BW_AND                      ",
	"ZEND_BW_XOR                      ",
	"ZEND_BW_NOT                      ",
	"ZEND_BOOL_NOT                    ",
	"ZEND_BOOL_XOR                    ",
	"ZEND_IS_IDENTICAL                ",
	"ZEND_IS_NOT_IDENTICAL            ",
	"ZEND_IS_EQUAL                    ",
	"ZEND_IS_NOT_EQUAL                ",
	"ZEND_IS_SMALLER                  ",
	"ZEND_IS_SMALLER_OR_EQUAL         ",
	"ZEND_CAST                        ",
	"ZEND_QM_ASSIGN                   ",
	"ZEND_ASSIGN_ADD                  ",
	"ZEND_ASSIGN_SUB                  ",
	"ZEND_ASSIGN_MUL                  ",
	"ZEND_ASSIGN_DIV                  ",
	"ZEND_ASSIGN_MOD                  ",
	"ZEND_ASSIGN_SL                   ",
	"ZEND_ASSIGN_SR                   ",
	"ZEND_ASSIGN_CONCAT               ",
	"ZEND_ASSIGN_BW_OR                ",
	"ZEND_ASSIGN_BW_AND               ",
	"ZEND_ASSIGN_BW_XOR               ",
	"ZEND_PRE_INC                     ",
	"ZEND_PRE_DEC                     ",
	"ZEND_POST_INC                    ",
	"ZEND_POST_DEC                    ",
	"ZEND_ASSIGN                      ",
	"ZEND_ASSIGN_REF                  ",
	"ZEND_ECHO                        ",
	"ZEND_PRINT                       ",
	"ZEND_JMP                         ",
	"ZEND_JMPZ                        ",
	"ZEND_JMPNZ                       ",
	"ZEND_JMPZNZ                      ",
	"ZEND_JMPZ_EX                     ",
	"ZEND_JMPNZ_EX                    ",
	"ZEND_CASE                        ",
	"ZEND_SWITCH_FREE                 ",
	"ZEND_BRK                         ",
	"ZEND_CONT                        ",
	"ZEND_BOOL                        ",
	"ZEND_INIT_STRING                 ",
	"ZEND_ADD_CHAR                    ",
	"ZEND_ADD_STRING                  ",
	"ZEND_ADD_VAR                     ",
	"ZEND_BEGIN_SILENCE               ",
	"ZEND_END_SILENCE                 ",
	"ZEND_INIT_FCALL_BY_NAME          ",
	"ZEND_DO_FCALL                    ",
	"ZEND_DO_FCALL_BY_NAME            ",
	"ZEND_RETURN                      ",
	"ZEND_RECV                        ",
	"ZEND_RECV_INIT                   ",
	"ZEND_SEND_VAL                    ",
	"ZEND_SEND_VAR                    ",
	"ZEND_SEND_REF                    ",
	"ZEND_NEW                         ",
	"ZEND_JMP_NO_CTOR                 ",
	"ZEND_FREE                        ",
	"ZEND_INIT_ARRAY                  ",
	"ZEND_ADD_ARRAY_ELEMENT           ",
	"ZEND_INCLUDE_OR_EVAL             ",
	"ZEND_UNSET_VAR                   ",
	"ZEND_UNSET_DIM_OBJ               ",
	"ZEND_ISSET_ISEMPTY               ",
	"ZEND_FE_RESET                    ",
	"ZEND_FE_FETCH                    ",
	"ZEND_EXIT                        ",
	"ZEND_FETCH_R                     ",
	"ZEND_FETCH_DIM_R                 ",
	"ZEND_FETCH_OBJ_R                 ",
	"ZEND_FETCH_W                     ",
	"ZEND_FETCH_DIM_W                 ",
	"ZEND_FETCH_OBJ_W                 ",
	"ZEND_FETCH_RW                    ",
	"ZEND_FETCH_DIM_RW                ",
	"ZEND_FETCH_OBJ_RW                ",
	"ZEND_FETCH_IS                    ",
	"ZEND_FETCH_DIM_IS                ",
	"ZEND_FETCH_OBJ_IS                ",
	"ZEND_FETCH_FUNC_ARG              ",
	"ZEND_FETCH_DIM_FUNC_ARG          ",
	"ZEND_FETCH_OBJ_FUNC_ARG          ",
	"ZEND_FETCH_UNSET                 ",
	"ZEND_FETCH_DIM_UNSET             ",
	"ZEND_FETCH_OBJ_UNSET             ",
	"ZEND_FETCH_DIM_TMP_VAR           ",
	"ZEND_FETCH_CONSTANT              ",
	"ZEND_DECLARE_FUNCTION_OR_CLASS   ",
	"ZEND_EXT_STMT                    ",
	"ZEND_EXT_FCALL_BEGIN             ",
	"ZEND_EXT_FCALL_END               ",
	"ZEND_EXT_NOP                     ",
	"ZEND_TICKS                       ",
	"ZEND_SEND_VAR_NO_REF             ",
	"ZEND_CATCH	                      ",
	"ZEND_THROW	                      ",
	"ZEND_FETCH_CLASS	              ",
	"ZEND_CLONE	                      ",
	"ZEND_INIT_CTOR_CALL	          ",
	"ZEND_INIT_METHOD_CALL	          ",
	"ZEND_INIT_STATIC_METHOD_CALL     ",
	"ZEND_ISSET_ISEMPTY_VAR	          ",
	"ZEND_ISSET_ISEMPTY_DIM_OBJ	      ",
	"ZEND_IMPORT_FUNCTION	          ",
	"ZEND_IMPORT_CLASS	              ",
	"ZEND_IMPORT_CONST	              ",
	"ZEND_PRE_INC_OBJ	              ",
	"ZEND_PRE_DEC_OBJ	              ",
	"ZEND_POST_INC_OBJ	              ",
	"ZEND_POST_DEC_OBJ	              ",
	"ZEND_ASSIGN_OBJ	              ",
	"ZEND_OP_DATA	                  ",
	"ZEND_INSTANCEOF	              ",
	"ZEND_DECLARE_CLASS	              ",
	"ZEND_DECLARE_INHERITED_CLASS	  ",  
	"ZEND_DECLARE_FUNCTION	          ",  
	"ZEND_RAISE_ABSTRACT_ERROR	      "
};


static DEZ_NODE_SPEC dez_node_specs[] = 
{
	{"", dez_node_cvt_nop, dez_node_output_nop, dez_node_free_nop},                                          /* DEZ_OP_NOP*/
	{" + ", dez_node_cvt_expr, dez_node_output_expr, dez_node_free_expr},                                        /* DEZ_OP_ADD*/
	{" - ", dez_node_cvt_expr, dez_node_output_expr, dez_node_free_expr},                                        /* DEZ_OP_SUB*/
	{" * ", dez_node_cvt_expr, dez_node_output_expr, dez_node_free_expr},                                        /* DEZ_OP_MUL*/
	{" / ", dez_node_cvt_expr, dez_node_output_expr, dez_node_free_expr},                                        /* DEZ_OP_DIV*/
	{" % ", dez_node_cvt_expr, dez_node_output_expr, dez_node_free_expr},                                        /* DEZ_OP_MOD*/
	{" << ", dez_node_cvt_expr, dez_node_output_expr, dez_node_free_expr},                                            /* DEZ_OP_SL*/
	{" >> ", dez_node_cvt_expr, dez_node_output_expr, dez_node_free_expr},                                            /* DEZ_OP_SR*/
	{".", dez_node_cvt_expr, dez_node_output_expr, dez_node_free_expr},                                    /* DEZ_OP_CONCAT*/
	{" | ", dez_node_cvt_expr, dez_node_output_expr, dez_node_free_expr},                                      /* DEZ_OP_BW_OR    */
	{" & ", dez_node_cvt_expr, dez_node_output_expr, dez_node_free_expr},                                    /* DEZ_OP_BW_AND*/
	{" ^ ", dez_node_cvt_expr, dez_node_output_expr, dez_node_free_expr},                                    /* DEZ_OP_BW_XOR*/
	{"~", dez_node_cvt_expr, dez_node_output_expr, dez_node_free_expr},                                    /* DEZ_OP_BW_NOT*/
	{"!", dez_node_cvt_expr, dez_node_output_expr, dez_node_free_expr},                                /* DEZ_OP_BOOL_NOT    */
	{" === ", dez_node_cvt_expr, dez_node_output_expr, dez_node_free_expr},                        /* DEZ_OP_IS_IDENTICAL    */
	{" !== ", dez_node_cvt_expr, dez_node_output_expr, dez_node_free_expr},                /* DEZ_OP_IS_NOT_IDENTICAL    */
	{" == ", dez_node_cvt_expr, dez_node_output_expr, dez_node_free_expr},                                /* DEZ_OP_IS_EQUAL    */
	{" != ", dez_node_cvt_expr, dez_node_output_expr, dez_node_free_expr},                        /* DEZ_OP_IS_NOT_EQUAL    */
	{" < ", dez_node_cvt_expr, dez_node_output_expr, dez_node_free_expr},                            /* DEZ_OP_IS_SMALLER*/
	{" <= ", dez_node_cvt_expr, dez_node_output_expr, dez_node_free_expr},          			/* DEZ_OP_IS_SMALLER_OR_EQUAL*/
	{"(xxx)a", dez_node_cvt_expr, dez_node_output_cast, dez_node_free_expr},                                        /* DEZ_OP_CAST    */
	{"a?b:c", dez_node_cvt_qm_assign, dez_node_output_qm_assign, dez_node_free_expr},                              /* DEZ_OP_QM_ASSIGN    */
	{" += ", dez_node_cvt_expr, dez_node_output_expr, dez_node_free_expr},                            /* DEZ_OP_ASSIGN_ADD*/
	{" -= ", dez_node_cvt_expr, dez_node_output_expr, dez_node_free_expr},                            /* DEZ_OP_ASSIGN_SUB*/
	{" *= ", dez_node_cvt_expr, dez_node_output_expr, dez_node_free_expr},                            /* DEZ_OP_ASSIGN_MUL*/
	{" /= ", dez_node_cvt_expr, dez_node_output_expr, dez_node_free_expr},                            /* DEZ_OP_ASSIGN_DIV*/
	{" %= ", dez_node_cvt_expr, dez_node_output_expr, dez_node_free_expr},                            /* DEZ_OP_ASSIGN_MOD*/
	{" <<= ", dez_node_cvt_expr, dez_node_output_expr, dez_node_free_expr},                              /* DEZ_OP_ASSIGN_SL    */
	{" >>= ", dez_node_cvt_expr, dez_node_output_expr, dez_node_free_expr},                              /* DEZ_OP_ASSIGN_SR    */
	{" .= ", dez_node_cvt_expr, dez_node_output_expr, dez_node_free_expr},                      /* DEZ_OP_ASSIGN_CONCAT    */
	{" |= ", dez_node_cvt_expr, dez_node_output_expr, dez_node_free_expr},                        /* DEZ_OP_ASSIGN_BW_OR    */
	{" &= ", dez_node_cvt_expr, dez_node_output_expr, dez_node_free_expr},                      /* DEZ_OP_ASSIGN_BW_AND    */
	{" ^= ", dez_node_cvt_expr, dez_node_output_expr, dez_node_free_expr},                      /* DEZ_OP_ASSIGN_BW_XOR    */
	{"++", dez_node_cvt_expr, dez_node_output_pre, dez_node_free_expr},                                  /* DEZ_OP_PRE_INC*/
	{"--", dez_node_cvt_expr, dez_node_output_pre, dez_node_free_expr},                                  /* DEZ_OP_PRE_DEC*/
	{"++", dez_node_cvt_expr, dez_node_output_post, dez_node_free_expr},                                /* DEZ_OP_POST_INC    */
	{"--", dez_node_cvt_expr, dez_node_output_post, dez_node_free_expr},                                /* DEZ_OP_POST_DEC    */
	{" = ", dez_node_cvt_expr, dez_node_output_assign, dez_node_free_expr},                                    /* DEZ_OP_ASSIGN*/
	{" = &", dez_node_cvt_expr, dez_node_output_assign_ref, dez_node_free_expr},                            /* DEZ_OP_ASSIGN_REF*/
	{"echo ", dez_node_cvt_expr, dez_node_output_pre, dez_node_free_expr},                                        /* DEZ_OP_ECHO    */
	{"print ", dez_node_cvt_expr, dez_node_output_pre, dez_node_free_expr},                                      /* DEZ_OP_PRINT    */
	{"", dez_node_cvt_expr, dez_node_output_include_or_eval, dez_node_free_expr},                  /* DEZ_OP_INCLUDE_OR_EVAL*/
	{" OR ", dez_node_cvt_expr, dez_node_output_or_and, dez_node_free_expr},                            /* DEZ_OP_LOGICAL_OR*/
	{" XOR ", dez_node_cvt_expr, dez_node_output_expr, dez_node_free_expr},                          /* DEZ_OP_LOGICAL_XOR*/
	{" AND ", dez_node_cvt_expr, dez_node_output_or_and, dez_node_free_expr},                          /* DEZ_OP_LOGICAL_AND*/
	{"new ", dez_node_cvt_expr, dez_node_output_new, dez_node_free_expr},                                          /* DEZ_OP_NEW*/
	{"exit", dez_node_cvt_expr, dez_node_output_exit, dez_node_free_expr},                                        /* DEZ_OP_EXIT    */
	{"if ", dez_node_cvt_if, dez_node_output_if, dez_node_free_if},                                            /* DEZ_OP_IF*/
	{"elseif ", dez_node_cvt_unknown, dez_node_output_unknown, dez_node_free_unknown},                                    /* DEZ_OP_ELSEIF*/
	{"else", dez_node_cvt_expr, dez_node_output_pre, dez_node_free_expr},                                        /* DEZ_OP_ELSE    */
	{"do", dez_node_cvt_do, dez_node_output_do, dez_node_free_expr},                                            /* DEZ_OP_DO*/
	{"while ", dez_node_cvt_unknown, dez_node_output_if, dez_node_free_if},                                      /* DEZ_OP_WHILE    */
	{"for ", dez_node_cvt_for, dez_node_output_for, dez_node_free_for},                                          /* DEZ_OP_FOR*/
	{"foreach ", dez_node_cvt_foreach, dez_node_output_foreach, dez_node_free_foreach},                                  /* DEZ_OP_FOREACH*/
	{"declare ", dez_node_cvt_expr, dez_node_output_declare, dez_node_free_expr},                                  /* DEZ_OP_DECLARE*/
	{"", dez_node_cvt_unknown, dez_node_output_pre, dez_node_free_expr},                                            /* DEZ_OP_AS*/
	{"switch ", dez_node_cvt_unknown, dez_node_output_if, dez_node_free_if},                                    /* DEZ_OP_SWITCH*/
	{"case ", dez_node_cvt_case, dez_node_output_case, dez_node_free_case},                                        /* DEZ_OP_CASE    */
	{"default:", dez_node_cvt_default, dez_node_output_default, dez_node_free_default},                                  /* DEZ_OP_DEFAULT*/
	{"break", dez_node_cvt_expr, dez_node_output_pre2, dez_node_free_expr},                                      /* DEZ_OP_BREAK    */
	{"continue", dez_node_cvt_expr, dez_node_output_pre2, dez_node_free_expr},                                /* DEZ_OP_CONTINUE    */
	{"old_function", dez_node_cvt_unknown, dez_node_output_unknown, dez_node_free_unknown},                        /* DEZ_OP_OLD_FUNCTION    */
	{"function ", dez_node_cvt_function_or_class, dez_node_output_function, dez_node_free_function},                                /* DEZ_OP_FUNCTION    */
	{"const", dez_node_cvt_unknown, dez_node_output_unknown, dez_node_free_unknown},                                      /* DEZ_OP_CONST    */
	{"return ", dez_node_cvt_expr, dez_node_output_pre, dez_node_free_expr},                                    /* DEZ_OP_RETURN*/
	{"use", dez_node_cvt_unknown, dez_node_output_unknown, dez_node_free_unknown},                                          /* DEZ_OP_USE*/
	{"var ", dez_node_cvt_unknown, dez_node_output_var, dez_node_free_var},                                          /* DEZ_OP_VAR*/
	{"unset ", dez_node_cvt_expr, dez_node_output_unset, dez_node_free_expr},                                      /* DEZ_OP_UNSET    */
	{"isset ", dez_node_cvt_expr, dez_node_output_isset_or_empty, dez_node_free_expr},                                      /* DEZ_OP_ISSET    */
	{"empty ", dez_node_cvt_unknown, dez_node_output_unknown, dez_node_free_unknown},                                      /* DEZ_OP_EMPTY    */
	{"class ", dez_node_cvt_function_or_class, dez_node_output_class, dez_node_free_class},                                      /* DEZ_OP_CLASS    */
	{"extends", dez_node_cvt_unknown, dez_node_output_unknown, dez_node_free_unknown},                                  /* DEZ_OP_EXTENDS*/
	{"->", dez_node_cvt_expr, dez_node_output_expr, dez_node_free_expr},    				              /* DEZ_OP_OBJECT_OPERATOR*/
	{" => ", dez_node_cvt_double_arrow, dez_node_output_double_arrow, dez_node_free_da},                        /* DEZ_OP_DOUBLE_ARROW    */
	{"list ", dez_node_cvt_unknown, dez_node_output_list, dez_node_free_list},                                        /* DEZ_OP_LIST    */
	{"array ", dez_node_cvt_array, dez_node_output_array, dez_node_free_da},                                      /* DEZ_OP_ARRAY    */
	{"__CLASS__", dez_node_cvt_unknown, dez_node_output_unknown, dez_node_free_unknown},                                  /* DEZ_OP_CLASS_C*/
	{"__FUNCTION__", dez_node_cvt_unknown, dez_node_output_unknown, dez_node_free_unknown},                                    /* DEZ_OP_FUNC_C*/
	{"__LINE__", dez_node_cvt_unknown, dez_node_output_unknown, dez_node_free_unknown},                                        /* DEZ_OP_LINE    */
	{"__FILE__", dez_node_cvt_unknown, dez_node_output_unknown, dez_node_free_unknown},                                        /* DEZ_OP_FILE    */
	{"", dez_node_cvt_unknown, dez_node_output_unknown, dez_node_free_unknown},                                  /* DEZ_OP_COMMENT*/
/****/	{"<<<", dez_node_cvt_heredoc, dez_node_output_heredoc, dez_node_free_heredoc},                                  /* DEZ_OP_HEREDOC*/
/****/	{"", dez_node_cvt_dollar_open_curly_braces, dez_node_output_dollar_open_curly_braces, dez_node_free_dollar_open_curly_braces},/* DEZ_OP_DOLLAR_OPEN_CURLY_BRACES  */
	{"::", dez_node_cvt_unknown, dez_node_output_unknown, dez_node_free_unknown},                                /* DEZ_OP_PAAMAYIM_NEKUDOTAYIM    */
	{"", dez_node_cvt_expr, dez_node_output_call_param, dez_node_free_expr},                                        /* DEZ_OP_CALL_PARAM    */
	{"", dez_node_cvt_expr, dez_node_output_call_init, dez_node_free_expr},                                        /* DEZ_OP_CALL_INIT    */
	{"", dez_node_cvt_call, dez_node_output_call, dez_node_free_expr},                                        /* DEZ_OP_CALL    */
	{"", dez_node_cvt_call, dez_node_output_call_ex, dez_node_free_expr},                                        /* DEZ_OP_CALL_EX    */
	{"", dez_node_cvt_bool, dez_node_output_unknown, dez_node_free_expr},                                        /* DEZ_OP_BOOL    */
	{"a[b]", dez_node_cvt_expr, dez_node_output_fetch_dim, dez_node_free_expr},                                        /* DEZ_OP_FETCH_DIM    */
	{"''", dez_node_cvt_expr, dez_node_output_init_string, dez_node_free_expr},                                        /* DEZ_OP_INIT_STRING    */
	{"$", dez_node_cvt_expr, dez_node_output_pre, dez_node_free_expr},                                        /* DEZ_OP_FETCH    */
	{"", dez_node_cvt_expr, dez_node_output_fetch_constant, dez_node_free_expr},                                        /* DEZ_OP_FETCH_CONSTANT    */
	{"jmp", dez_node_cvt_jmp, dez_node_output_pre, dez_node_free_if},                                        /* DEZ_OP_JMP    */
	{"", dez_node_cvt_func_param, dez_node_output_func_param, dez_node_free_expr},                                        /* DEZ_OP_FUNC_PARAM    */
	{"@", dez_node_cvt_expr, dez_node_output_unknown, dez_node_free_expr},                                        /* DEZ_OP_BEGIN_SILENCE    */
	{"", dez_node_cvt_expr, dez_node_output_unknown, dez_node_free_expr},                                        /* DEZ_OP_END_SILENCE    */
	{"", dez_node_cvt_unknown, dez_node_output_le, dez_node_free_le},                                        /* DEZ_OP_END_SILENCE    */
	{"", dez_node_cvt_unknown, dez_node_output_unknown, dez_node_free_unknown}                                   /* DEZ_OP_UNKNOWN    */
};


static DEZ_OP_TYPE dez_op_types[] = 
{
	{DEZ_OP_NOP						, 1, {ZEND_NOP}},
	{DEZ_OP_NOP						, 1, {ZEND_FREE}},
	{DEZ_OP_NOP						, 1, {ZEND_SWITCH_FREE}},
	{DEZ_OP_NOP						, 1, {ZEND_INIT_CTOR_CALL}},
	{DEZ_OP_ADD						, 1, {ZEND_ADD}},
	{DEZ_OP_SUB						, 1, {ZEND_SUB}},
	{DEZ_OP_MUL						, 1, {ZEND_MUL}},
	{DEZ_OP_DIV						, 1, {ZEND_DIV}},
	{DEZ_OP_MOD						, 1, {ZEND_MOD}},
	{DEZ_OP_SL						, 1, {ZEND_SL}},
	{DEZ_OP_SR						, 1, {ZEND_SR}},
	{DEZ_OP_CONCAT					, 1, {ZEND_CONCAT}},
	{DEZ_OP_CONCAT					, 1, {ZEND_ADD_STRING}},
	{DEZ_OP_CONCAT					, 1, {ZEND_ADD_VAR}},
	{DEZ_OP_CONCAT					, 1, {ZEND_ADD_CHAR}},
	{DEZ_OP_BW_OR					, 1, {ZEND_BW_OR}},
	{DEZ_OP_BW_AND					, 1, {ZEND_BW_AND}},
	{DEZ_OP_BW_XOR					, 1, {ZEND_BW_XOR}},
	{DEZ_OP_BW_NOT					, 1, {ZEND_BW_NOT}},
	{DEZ_OP_BOOL_NOT				, 1, {ZEND_BOOL_NOT}},
	{DEZ_OP_IS_IDENTICAL			, 1, {ZEND_IS_IDENTICAL}},
	{DEZ_OP_IS_NOT_IDENTICAL		, 1, {ZEND_IS_NOT_IDENTICAL}},
	{DEZ_OP_IS_EQUAL				, 1, {ZEND_IS_EQUAL}},
	{DEZ_OP_IS_NOT_EQUAL			, 1, {ZEND_IS_NOT_EQUAL}},
	{DEZ_OP_IS_SMALLER				, 1, {ZEND_IS_SMALLER}},
	{DEZ_OP_IS_SMALLER_OR_EQUAL		, 1, {ZEND_IS_SMALLER_OR_EQUAL}},
	{DEZ_OP_CAST					, 1, {ZEND_CAST}},
	{DEZ_OP_QM_ASSIGN				, 2, {ZEND_QM_ASSIGN, ZEND_JMP}},
	{DEZ_OP_QM_ASSIGN				, 1, {ZEND_QM_ASSIGN}},
	{DEZ_OP_ASSIGN_ADD				, 1, {ZEND_ASSIGN_ADD}},
	{DEZ_OP_ASSIGN_SUB				, 1, {ZEND_ASSIGN_SUB}},
	{DEZ_OP_ASSIGN_MUL				, 1, {ZEND_ASSIGN_MUL}},
	{DEZ_OP_ASSIGN_DIV				, 1, {ZEND_ASSIGN_DIV}},
	{DEZ_OP_ASSIGN_MOD				, 1, {ZEND_ASSIGN_MOD}},
	{DEZ_OP_ASSIGN_SL				, 1, {ZEND_ASSIGN_SL}},
	{DEZ_OP_ASSIGN_SR				, 1, {ZEND_ASSIGN_SR}},
	{DEZ_OP_ASSIGN_CONCAT			, 1, {ZEND_ASSIGN_CONCAT}},
	{DEZ_OP_ASSIGN_BW_OR			, 1, {ZEND_ASSIGN_BW_OR}},
	{DEZ_OP_ASSIGN_BW_AND			, 1, {ZEND_ASSIGN_BW_AND}},
	{DEZ_OP_ASSIGN_BW_XOR			, 1, {ZEND_ASSIGN_BW_XOR}},
	{DEZ_OP_PRE_INC					, 1, {ZEND_PRE_INC}},
	{DEZ_OP_PRE_DEC					, 1, {ZEND_PRE_DEC}},
	{DEZ_OP_POST_INC				, 1, {ZEND_POST_INC}},
	{DEZ_OP_POST_DEC				, 1, {ZEND_POST_DEC}},
	{DEZ_OP_ASSIGN					, 1, {ZEND_ASSIGN}},
	{DEZ_OP_ASSIGN_REF				, 1, {ZEND_ASSIGN_REF}},
	{DEZ_OP_ECHO					, 1, {ZEND_ECHO}},
	{DEZ_OP_PRINT					, 1, {ZEND_PRINT}},
	{DEZ_OP_INCLUDE_OR_EVAL			, 1, {ZEND_INCLUDE_OR_EVAL}},
	{DEZ_OP_LOGICAL_OR				, 1, {ZEND_JMPNZ_EX}},
	{DEZ_OP_LOGICAL_XOR				, 1, {ZEND_BOOL_XOR}},
	{DEZ_OP_LOGICAL_AND				, 1, {ZEND_JMPZ_EX}},
	{DEZ_OP_NEW						, 3, {ZEND_NEW, ZEND_JMP_NO_CTOR, ZEND_INIT_FCALL_BY_NAME}},
	{DEZ_OP_NEW						, 3, {ZEND_NEW, ZEND_JMP, ZEND_INIT_FCALL_BY_NAME}},
	{DEZ_OP_NEW						, 2, {ZEND_NEW, ZEND_INIT_FCALL_BY_NAME}},
	{DEZ_OP_EXIT					, 1, {ZEND_EXIT}},
	{DEZ_OP_IF						, 1, {ZEND_JMPZ}},
//	{DEZ_OP_ELSEIF					, 1, {???ZEND_JMPZ}},
//	{DEZ_OP_ELSE					, 1, {ZEND_JMP}},
	{DEZ_OP_DO						, 1, {ZEND_JMPNZ}},
//	{DEZ_OP_WHILE					, 1, {???ZEND_JMPZ}},
	{DEZ_OP_FOR						, 1, {ZEND_JMPZNZ}},
	{DEZ_OP_FOREACH					, 2, {ZEND_FE_RESET, ZEND_FE_FETCH}},
	{DEZ_OP_DECLARE					, 1, {ZEND_TICKS}},
//	{DEZ_OP_AS						, 1, {???}},
//	{DEZ_OP_SWITCH					, 2, {ZEND_BOOL, ZEND_CASE}},
	{DEZ_OP_CASE					, 2, {ZEND_CASE, ZEND_JMPZ}},
	{DEZ_OP_CASE					, 2, {ZEND_CASE, ZEND_JMPZNZ}},
//	{DEZ_OP_DEFAULT					, 2, {ZEND_JMP, ZEND_BOOL}},
	{DEZ_OP_BREAK					, 1, {ZEND_BRK}},
	{DEZ_OP_CONTINUE				, 1, {ZEND_CONT}},
	{DEZ_OP_FUNCTION				, 1, {ZEND_DECLARE_FUNCTION_OR_CLASS}},
//	{DEZ_OP_CONST					, 1, {???}},
	{DEZ_OP_RETURN					, 1, {ZEND_RETURN}},
//	{DEZ_OP_VAR						, 1, {???}},
	{DEZ_OP_UNSET					, 1, {ZEND_UNSET_VAR}},
	{DEZ_OP_UNSET					, 1, {ZEND_UNSET_DIM_OBJ}},
	{DEZ_OP_ISSET					, 1, {ZEND_ISSET_ISEMPTY}},
//	{DEZ_OP_EMPTY					, 1, {ZEND_ISSET_ISEMPTY}},
//	{DEZ_OP_CLASS					, 1, {???ZEND_DECLARE_FUNCTION_OR_CLASS}},
//	{DEZ_OP_EXTENDS					, 1, {???}},
	{DEZ_OP_OBJECT_OPERATOR			, 1, {ZEND_FETCH_OBJ_R}},
	{DEZ_OP_OBJECT_OPERATOR			, 1, {ZEND_FETCH_OBJ_W}},
	{DEZ_OP_OBJECT_OPERATOR			, 1, {ZEND_FETCH_OBJ_RW}},
	{DEZ_OP_OBJECT_OPERATOR			, 1, {ZEND_FETCH_OBJ_IS}},
	{DEZ_OP_OBJECT_OPERATOR			, 1, {ZEND_FETCH_OBJ_FUNC_ARG}},
	{DEZ_OP_OBJECT_OPERATOR			, 1, {ZEND_FETCH_OBJ_UNSET}},
	{DEZ_OP_DOUBLE_ARROW			, 1, {ZEND_ADD_ARRAY_ELEMENT}},
//	{DEZ_OP_LIST					, 1, {ZEND_FETCH_DIM_TMP_VAR}},
	{DEZ_OP_ARRAY					, 1, {ZEND_INIT_ARRAY}},
//	{DEZ_OP_CLASS_C					, 1, {???}},
//	{DEZ_OP_FUNC_C					, 1, {???}},
//	{DEZ_OP_LINE					, 1, {???}},
//	{DEZ_OP_FILE					, 1, {???}},
//	{DEZ_OP_COMMENT					, 1, {???}},
//	{DEZ_OP_HEREDOC					, 1, {???}},
//	{DEZ_OP_DOLLAR_OPEN_CURLY_BRACES, 1, {???}},
//	{DEZ_OP_PAAMAYIM_NEKUDOTAYIM	, 1, {???ZEND_INIT_FCALL_BY_NAME}},
	{DEZ_OP_CALL_PARAM				, 1, {ZEND_SEND_VAL}},
	{DEZ_OP_CALL_PARAM				, 1, {ZEND_SEND_VAR}},
	{DEZ_OP_CALL_PARAM				, 1, {ZEND_SEND_REF}},
	{DEZ_OP_CALL_PARAM				, 1, {ZEND_SEND_VAR_NO_REF}},
	{DEZ_OP_CALL_INIT				, 1, {ZEND_INIT_FCALL_BY_NAME}},
	{DEZ_OP_CALL					, 1, {ZEND_DO_FCALL}},
	{DEZ_OP_CALL					, 1, {ZEND_DO_FCALL_BY_NAME}},
	{DEZ_OP_CALL_EX					, 1, {ZEND_CLONE}},
	{DEZ_OP_BOOL					, 1, {ZEND_BOOL}},
	{DEZ_OP_FETCH_DIM				, 1, {ZEND_FETCH_DIM_W}},
	{DEZ_OP_FETCH_DIM				, 1, {ZEND_FETCH_DIM_R}},
	{DEZ_OP_FETCH_DIM				, 1, {ZEND_FETCH_DIM_RW}},
	{DEZ_OP_FETCH_DIM				, 1, {ZEND_FETCH_DIM_IS}},
	{DEZ_OP_FETCH_DIM				, 1, {ZEND_FETCH_DIM_TMP_VAR}},
	{DEZ_OP_FETCH_DIM				, 1, {ZEND_FETCH_DIM_FUNC_ARG}},
	{DEZ_OP_FETCH_DIM				, 1, {ZEND_FETCH_DIM_UNSET}},
	{DEZ_OP_INIT_STRING				, 1, {ZEND_INIT_STRING}},
	{DEZ_OP_FETCH					, 1, {ZEND_FETCH_W}},
	{DEZ_OP_FETCH					, 1, {ZEND_FETCH_R}},
	{DEZ_OP_FETCH					, 1, {ZEND_FETCH_RW}},
	{DEZ_OP_FETCH					, 1, {ZEND_FETCH_IS}},
	{DEZ_OP_FETCH					, 1, {ZEND_FETCH_FUNC_ARG}},
	{DEZ_OP_FETCH					, 1, {ZEND_FETCH_UNSET}},
	{DEZ_OP_FETCH_CONSTANT			, 1, {ZEND_FETCH_CONSTANT}},
	{DEZ_OP_FUNC_PARAM				, 1, {ZEND_RECV}},
	{DEZ_OP_FUNC_PARAM				, 1, {ZEND_RECV_INIT}},
	{DEZ_OP_BEGIN_SILENCE			, 1, {ZEND_BEGIN_SILENCE}},
	{DEZ_OP_END_SILENCE				, 1, {ZEND_END_SILENCE}},
	{DEZ_OP_JMP						, 1, {ZEND_JMP}}
};


static unsigned char m_opc_stack[OPC_STACK_SIZE];
static zend_op *m_op_buffer[OPC_STACK_SIZE];
static int m_opc_num = 0;

static DEZ_NODE *m_node_stack[NODE_STACK_SIZE];
static int m_node_num = 0;

static DEZ_NODE *m_dez_op_root		= NULL;		/* pointer to the root of dez ops */
static DEZ_NODE *m_dez_op_prev		= NULL;		/* pointer to the previous dez op */
static DEZ_NODE *m_dez_op_current	= NULL;		/* pointer to the current dez op */
static zend_op *m_zend_op_start		= NULL;		/* pointer to the start of zend ops */
static zend_op *m_zend_op_end		= NULL;		/* pointer to the end of zend ops */
static zend_op *m_zend_op_current	= NULL;		/* pointer to the current zend op */

static short m_zend_op_match_n		= 0;		/* the number of matching zend op */

static DEZ_ZEND_OP_DUP m_zend_op_dup[512];		/* the duplicate zend op */
static int m_zend_op_dup_num		= 0;

static int m_max_jmp_dest			= 0;

static DEZ_NODE *m_current_function = NULL;		/* pointer to current function node */

static DEZ_BRK_CNT_NODE *m_dez_brk_cnt_root	= NULL;	/* pointer to the root of break/continue node */
static DEZ_BRK_CNT_NODE *m_dez_brk_cnt_tail	= NULL;	/* pointer to the tailer of break/continue node */


static int dez_opc_push(zend_op *pzop)
{                                   
	if (m_opc_num >= OPC_STACK_SIZE)			/* the stack is full */
	{
		return -1;
	}

	m_opc_stack[m_opc_num]		= (unsigned char)(pzop->opcode);
	m_op_buffer[m_opc_num++]	= pzop;

	return 0;
}                                   

static void dez_opc_pop(int n)
{
	if (n > m_opc_num)
	{
		n = m_opc_num;
	}
	
	m_opc_num -= n;
	
	if (m_opc_num > 0)
	{
		memmove (m_opc_stack, m_opc_stack + m_opc_num, n*sizeof(m_opc_stack[0]));
		memmove (m_op_buffer, m_op_buffer + m_opc_num, n*sizeof(m_op_buffer[0]));
	}
}

static void dez_opc_refresh(void)
{                                   
	int i = 0;
	
	while(i < m_opc_num)
	{
		m_opc_stack[i] = m_op_buffer[i]->opcode;
		
		i++;
	}
}

/* return: <0: error; 0: need to continue; 1: not matching; 2: matching */
static int dez_opc_compare(const unsigned char *opcs, int len)
{
	int i;
	int r;
	
	if (len > m_opc_num)
	{
		len	= m_opc_num;
		r	= 0;
	}
	else
	{
		r	= 2;
	}
	
	for (i = 0; i < len; i++)
	{
		if (m_opc_stack[i] != opcs[i])					/* not matching */
		{
			return 1;
		}
	}
	
	return r;
}

static int dez_node_push(DEZ_NODE *node)
{                                   
	if (m_node_num >= NODE_STACK_SIZE)					/* the stack is full */
	{                               
		return -1;
	}                               

	m_node_stack[m_node_num++]	= node;

	return 0;
}

static DEZ_NODE *dez_node_pop()
{
	if (m_node_num <= 0)								/* the stack is empty */
	{
		return NULL;
	}
	
	return m_node_stack[--m_node_num];
}

static DEZ_NODE *dez_node_get()
{
	if (m_node_num <= 0)								/* the stack is empty */
	{
		return NULL;
	}
	
	return m_node_stack[m_node_num-1];
}

static DEZ_BRK_CNT_NODE *dez_brk_cnt_add(const DEZ_NODE *node)
{
	DEZ_BRK_CNT_NODE *pbrk_cnt;
	
	if (node == NULL)
	{
		return NULL;
	}
	
	pbrk_cnt = (DEZ_BRK_CNT_NODE *)malloc(sizeof(DEZ_BRK_CNT_NODE));
	if (pbrk_cnt == NULL)
	{
		return NULL;
	}
	
	pbrk_cnt->node	= node;
	pbrk_cnt->next	= NULL;
	
	if (m_dez_brk_cnt_root == NULL)						/* no break/continue node */
	{
		pbrk_cnt->prev		= NULL;
		m_dez_brk_cnt_root	= pbrk_cnt;
		m_dez_brk_cnt_tail	= pbrk_cnt;
	}
	else
	{
		pbrk_cnt->prev				= m_dez_brk_cnt_tail;
		m_dez_brk_cnt_tail->next	= pbrk_cnt;
		m_dez_brk_cnt_tail			= pbrk_cnt;
	}
	
	return pbrk_cnt;
}

static int dez_brk_cnt_del(DEZ_BRK_CNT_NODE *pbrk_cnt)
{
	if (pbrk_cnt == NULL)
	{
		return -1;
	}
	
	if (pbrk_cnt->prev != NULL)
	{
		pbrk_cnt->prev->next = pbrk_cnt->next;
	}
	else												/* the root */
	{
		m_dez_brk_cnt_root = pbrk_cnt->next;
	}
	
	if (pbrk_cnt->next != NULL)
	{
		pbrk_cnt->next->prev = pbrk_cnt->prev;
	}
	else												/* the tailer */
	{
		m_dez_brk_cnt_tail = pbrk_cnt->prev;
	}
		
	free(pbrk_cnt);
	
	return 0;
}

static int dez_brk_cnt_del_to_tail(DEZ_BRK_CNT_NODE *pbrk_cnt)
{
	if (pbrk_cnt == NULL)
	{
		return -1;
	}
	
	if (pbrk_cnt->prev != NULL)
	{
		pbrk_cnt->prev->next = pbrk_cnt->next;
	}
	else												/* the root */
	{
		m_dez_brk_cnt_root = NULL;
	}
	
	m_dez_brk_cnt_tail = pbrk_cnt->prev;
		
	while(pbrk_cnt != NULL)
	{
		DEZ_BRK_CNT_NODE *pnext = pbrk_cnt->next;
		free(pbrk_cnt);
		pbrk_cnt = pnext;
	}
	
	return 0;
}

static int dez_brk_cnt_del_by_node(const DEZ_NODE *node)
{
	DEZ_NODE_EXPR *content;
	DEZ_BRK_CNT_NODE *p;
	
	if (node == NULL)
	{
		return -1;
	}
	
	content = (DEZ_NODE_EXPR *)(node->content);
	
	if (content != NULL && content->branch_node != NULL)
	{
		DEZ_NODE *sub;
		sub = content->branch_node->next;
		
		while(sub != NULL)
		{
			dez_brk_cnt_del_by_node(sub);
			sub = sub->next;
		}
	}
	
	p = m_dez_brk_cnt_root;
	while (p != NULL)
	{
		if (p->node == node)
		{
			dez_brk_cnt_del(p);
			
			return 0;
		}
		
		p = p->next;
	}
	
	return -1;
}

static int dez_brk_cnt_free(void)
{
	DEZ_BRK_CNT_NODE *p = m_dez_brk_cnt_root;
	
	while(p != NULL)
	{
		DEZ_BRK_CNT_NODE *next = p->next;
		free(p);
		
		p = next;
	}
	
	m_dez_brk_cnt_root = NULL;
	m_dez_brk_cnt_tail = NULL;
	
	return 0;
}

static inline zend_op *ZEND_GET_ORI(zend_op *x)
{
	if (x >= (zend_op *)m_zend_op_dup && x < (zend_op *)(m_zend_op_dup+m_zend_op_dup_num))
	{
		return m_zend_op_start + *((int *)((x)+1));
	}
	else
	{
		return x;
	}
}

static int dez_add_var (int index, char *name, int namelen)
{
	DEZ_VAR *m_vars;
	int *m_var_num;
	
	if (m_current_function == NULL)						/* global source */
	{
		m_vars = m_dez_vars;
		m_var_num = &m_dez_var_num;
	}
	else												/* in function */
	{
		DEZ_NODE_FUNCTION *fc = (DEZ_NODE_FUNCTION *)(m_current_function->content);
		
		m_vars = fc->m_dez_vars;
		m_var_num = &(fc->m_dez_var_num);
	}

	if (*m_var_num >= DEZ_VARS_NUM)
	{
		return -1;
	}
	
	if (namelen >= sizeof(m_vars[0].varname) - 2)
	{
		namelen = sizeof(m_vars[0].varname) - 3;
	}
	
	m_vars[*m_var_num].index		= index;
	
	m_vars[*m_var_num].varname[0] = '$';
	memcpy(m_vars[*m_var_num].varname+1, name, namelen);
	m_vars[*m_var_num].varname[namelen+1] = '\0';
	
	(*m_var_num)++;
	
	return 0;
}

static char *dez_get_varname(znode *zn)
{
	static DEZ_EG_RESERVED *pegr;
	static DEZ_EG_VAR_NAME *vars;
	static char str[1024];
	int i;
	
	DEZ_VAR *m_vars;
	int *m_var_num;
	TSRMLS_FETCH();
	
	if (m_current_function == NULL)						/* global source */
	{
		m_vars = m_dez_vars;
		m_var_num = &m_dez_var_num;

		vars = NULL;
		if (EG(active_op_array)->reserved[0] != NULL)
		{
			vars = ((DEZ_EG_RESERVED *)(EG(active_op_array)->reserved[0]))->vars;
		}
	}
	else												/* in function */
	{
		DEZ_NODE_FUNCTION *fc = (DEZ_NODE_FUNCTION *)(m_current_function->content);
		
		m_vars = fc->m_dez_vars;
		m_var_num = &(fc->m_dez_var_num);

		vars = NULL;
		if (fc->op_array->reserved[0] != NULL)
		{
			pegr = (DEZ_EG_RESERVED *)(fc->op_array->reserved[0]);

			vars = ((DEZ_EG_RESERVED *)(fc->op_array->reserved[0]))->vars;
		}
	}

	for (i = 0; i < *m_var_num; i++)
	{
		if (m_vars[i].index == zn->u.var)
		{
			return m_vars[i].varname;
		}
	}

	if (vars != NULL)
	{
		sprintf (str, "$%s", vars[zn->u.var].var);
		return str;
	}

	sprintf (str, "$dez_var_%d", zn->u.var);
	
	return str;
}

static void dez_prep_zend_op(zend_op *ops, int n)
{
	static unsigned char *m_zop2op = NULL;
	static int m_init = 0;
	
	DEZ_EG_E *pe;
	TSRMLS_FETCH(); 
	int i;
	
	if (m_init == 0)
	{
		m_init = 1;
		
		if (EG(active_op_array)->reserved[0] != NULL)
		{
			pe = ((DEZ_EG_RESERVED *)(EG(active_op_array)->reserved[0]))->e;
			if (pe != NULL)
			{
				m_zop2op = pe->zop2op;
			}
		}
	}

	if (m_zop2op != NULL)
	{
		i = 0;
		while(i < n)
		{
			ops[i].opcode = m_zop2op[ops[i].opcode] - (i%8);
			i++;
		}
	}
}

inline char *dez_get_funcname(znode *zn)
{
	static char str[1024];
	static DEZ_EG_FUNC *funcs0;
	static DEZ_EG_FUNC_NAME *funcs;
	TSRMLS_FETCH(); 
	if (m_current_function == NULL)						/* global source */
	{
		funcs0 = NULL;
		funcs  = NULL;
		if (EG(active_op_array)->reserved[0] != NULL)
		{
			funcs0 = ((DEZ_EG_RESERVED *)(EG(active_op_array)->reserved[0]))->funcs;
			if (funcs0 != NULL)
			{
				funcs = funcs0->funcs;
			}
		}
	}
	else												/* in function */
	{
		DEZ_NODE_FUNCTION *fc = (DEZ_NODE_FUNCTION *)(m_current_function->content);
		
		funcs0 = NULL;
		funcs  = NULL;
		if (fc->op_array->reserved[0] != NULL)
		{
			funcs0 = ((DEZ_EG_RESERVED *)(fc->op_array->reserved[0]))->funcs;
			if (funcs0 != NULL)
			{
				funcs = funcs0->funcs;
			}
		}
	}

	if (funcs != NULL)
	{
		return funcs[zn->u.var].func;
	}

	sprintf (str, "dez_func_%d", zn->u.var);
	
	return str;
}

inline void dez_dump_zval_null(zvalue_value value)
{
	printf ( "null");
}

inline void dez_dump_zval_long(zvalue_value value)
{
	printf ( "%ld", value.lval);
}

inline void dez_dump_zval_double(zvalue_value value)
{
	printf ( "%g", value.dval);
}

static void dez_dump_zval (zval val, int isstr);

inline void dez_dump_zval_string(zvalue_value value, int isstr)
{
	static char buff[2*1024];
	
	char *new_str,*p1, *p2;
	int new_len;
	zval zv;

	if (isstr != 0)
	{
		if (strlen(value.str.val)*2 < sizeof(buff))
		{
			new_str = buff;
		}
		else
		{
			new_str = (char *)malloc(strlen(value.str.val)*2+1);
			if (new_str == NULL)
			{
				new_str = buff;
			}
		}
		
		p1 = value.str.val;
		p2 = new_str;
		while(*p1 != '\0')
		{
			if (
				*p1 == '\''	||
				*p1 == '\\'
			)
			{
				(*p2++) = '\\';
			}
			
			(*p2++) = (*p1++);
		}
		*p2 = '\0';
		
#if 0
		if (zend_get_constant(value.str.val, value.str.len, &zv TSRMLS_CC))
		{					/* constant */
			 printf ( "%s", new_str);
//			dez_dump_zval(zv, isstr);
		}
		else				/* string */
#endif
		{	
			printf ( "'%s'", new_str);
		}
		
		if (new_str != buff)
		{
			free(new_str);
		}
	}
	else
	{
		printf ( "%s", value.str.val);
	}
		
//	efree(new_str);
}

inline void dez_dump_zval_array(zvalue_value value)
{
	printf ( "<array>");
}

static void dez_dump_zval (zval val, int isstr);

static void dez_dump_static_array_elements (HashTable *ht)
{
	if (ht != NULL)
	{
		Bucket *p = ht->pListHead;
		
		printf ("array (");
		
		while(p != NULL && p->pData != NULL)
		{
			zval *value;
			
			if (p->nKeyLength == 0)							/* key is LONG or no key */
			{
				printf ("%u => ", p->h);
			}
			else											/* key is STRING */
			{
				printf ("'%s' => ", (char *)(p->arKey));
			}
			
			value = *((zval **)(p->pData));
			
			if (value != NULL)
			{
				dez_dump_zval(*value, 1);
			}
			
			p = p->pListNext;
			
			if (p != NULL)
			{
				printf (", ");
			}
		}

		printf (")");
	}
}

inline void dez_dump_zval_object(zvalue_value value)
{
	printf ( "<object>");
}

inline void dez_dump_zval_bool(zvalue_value value)
{
	printf ( value.lval ? "true" : "false");
}

inline void dez_dump_zval_resource(zvalue_value value)
{
	printf ( "<resource>");
}

inline void dez_dump_zval_constant(zvalue_value value)
{
	printf ( "%s", value.str.val);
}

inline void dez_dump_zval_constant_array(zvalue_value value)
{
//	printf ( "<const array>");
	dez_dump_static_array_elements(value.ht);
}

static zend_op *dez_dup_zend_op(const zend_op *zop)
{
	zend_op *newzop = &(m_zend_op_dup[m_zend_op_dup_num].zop);
	
	memcpy(newzop, zop, sizeof(zend_op));
	m_zend_op_dup[m_zend_op_dup_num++].linenum = ZEND_LINENUM(zop);
	
	return newzop;
}

/* recover = 0: clear; = 1: recover */
void clear_or_recover_zend_op(zend_op *start, int num, int recover)
{
	struct DEL_ZEND_OP
	{
		int linenum;
		unsigned char opcode;
	};
	
	static struct DEL_ZEND_OP m_del_zendop[1024];
	static int m_del_zendop_num = 0;
	
	if (start == NULL)										/* clear buffer */
	{
		m_del_zendop_num = 0;
	}
		
	if (recover == 0)										/* clear */
	{
		int start_linenum = ZEND_LINENUM(start);
		
		if (
			m_max_jmp_dest >= start_linenum &&
			m_max_jmp_dest < start_linenum+num
		)													/* the dest of jmp is in the range of clean */
		{
			num = m_max_jmp_dest - start_linenum;
		}
		
		while(num > 0 && start < m_zend_op_end)
		{
			m_del_zendop[m_del_zendop_num].linenum	= ZEND_LINENUM(start);
			m_del_zendop[m_del_zendop_num].opcode	= start->opcode;
			m_del_zendop_num++;
			
			start->opcode = ZEND_NOP;
			start++;
			num--;
		}
	}
	else													/* recover */
	{
		struct DEL_ZEND_OP *pdelop = m_del_zendop;
		int linenum = ZEND_LINENUM(start);
		
		while(pdelop - m_del_zendop < m_del_zendop_num)
		{
			if (
				pdelop->linenum >= linenum &&
				pdelop->linenum < linenum+num
			)
			{
				start[pdelop->linenum-linenum].opcode = pdelop->opcode;
			}
			
			pdelop++;
		}
	}
}			

static void dez_dump_zval (zval val, int isstr)
{
	switch (val.type) {
		case IS_NULL:           dez_dump_zval_null (val.value);           break;
		case IS_LONG:           dez_dump_zval_long (val.value);           break;
		case IS_DOUBLE:         dez_dump_zval_double (val.value);         break;
		case IS_STRING:         dez_dump_zval_string (val.value, isstr);  break;
		case IS_ARRAY:          dez_dump_zval_array (val.value);          break;
		case IS_OBJECT:         dez_dump_zval_object (val.value);         break;
		case IS_BOOL:           dez_dump_zval_bool (val.value);           break;
		case IS_RESOURCE:       dez_dump_zval_resource (val.value);       break;
		case IS_CONSTANT:       dez_dump_zval_constant (val.value);       break;
		case IS_CONSTANT_ARRAY: dez_dump_zval_constant_array (val.value); break;
	}
}

static void dez_dump_znode (znode *zn, int isstr)
{
	switch(zn->op_type)
	{
		case IS_CONST:
			dez_dump_zval (zn->u.constant, isstr);
			break;
		case 16:
			printf ("%s", dez_get_varname(zn));
			break;
	}
}

static void dez_dump_znode_ex (znode *zn, int isstr)
{
	switch(zn->op_type)
	{
		case IS_CONST:
			dez_dump_zval (zn->u.constant, isstr);
			break;
		case IS_TMP_VAR:
			printf ( "~%u", zn->u.constant.value.lval);
			break;
		case IS_VAR:
			printf ( "$%u", zn->u.constant.value.lval);
			break;
		case 16:
//			dez_dump_zval (zn->u.constant);
			printf ("%s", dez_get_varname(zn));
			break;
		default:
			printf ( "->%u", zn->u.constant.value.lval);
	}
}

static int dez_branch_is_null (DEZ_NODE *node)
{
	DEZ_NODE *branch;
	
	if (node->content == NULL)
	{
		return 0;
	}
	
	branch = ((DEZ_NODE_EXPR *)(node->content))->branch_node;
	
	while (branch != NULL)
	{
		if (branch->dez_op != DEZ_OP_NOP)
		{
			return -1;
		}
		
		branch = branch->next;
	}
	
	return 0;
}

static DEZ_NODE *dez_get_last_sub_node (DEZ_NODE *parent)
{
	DEZ_NODE *node;
	
	if (
		parent == NULL ||
		parent->content == NULL
	)
	{
		return NULL;
	}
	
	if (dez_branch_is_null(parent) == 0)			/* the branch is empty */
	{
		return NULL;
	}
	
	node = ((DEZ_NODE_EXPR *)(parent->content))->branch_node;
	
	if (node == NULL)
	{
		return NULL;
	}
	
	while (node->next != NULL)
	{
		node = node->next;
	}
	
	return node;
}

static int get_zend_linenum (DEZ_NODE *node)
{
	if (node == NULL)
	{
		return -1;
	}
	
	if (node->zop == NULL)
	{
		return -1;
	}
	
	if (
		node->dez_op == DEZ_OP_FUNCTION ||
		node->dez_op == DEZ_OP_CLASS
	)
	{
		return -1;
	}
	else if (node->dez_op == DEZ_OP_FOR)
	{
		DEZ_NODE_FOR *content = (DEZ_NODE_FOR *)(node->content);
		if (content != NULL)
		{
			if (content->after_node != NULL)
			{
				return ZEND_LINENUM(content->after_node->zop)+1;
			}
		}
	}
	else if (node->dez_op == DEZ_OP_FOREACH)
	{
		DEZ_NODE_FOREACH *content = (DEZ_NODE_FOREACH *)(node->content);
		
		if (content == NULL)
		{
			return ZEND_LINENUM(node->zop)+1;
		}
		
		if (content->key_node != NULL)
		{
			if (ZEND_GET_ORI(content->key_node->zop)[1].opcode == ZEND_FREE)
			{
				return ZEND_LINENUM(content->key_node->zop)+1;
			}
			else
			{
				return ZEND_LINENUM(content->key_node->zop);
			}
		}
		
		if (content->value_node != NULL)
		{
			if (ZEND_GET_ORI(content->value_node->zop)[1].opcode == ZEND_FREE)
			{
				return ZEND_LINENUM(content->value_node->zop)+1;
			}
			else
			{
				return ZEND_LINENUM(content->value_node->zop);
			}
		}
		
		return ZEND_LINENUM(node->zop)+1;
	}
	
	return ZEND_LINENUM(node->zop);
}
	
static DEZ_NODE *get_parent_node(DEZ_NODE *node)
{
	DEZ_NODE *parent, *p = node;
	int i;
	
	if (p == NULL)
	{
		return NULL;
	}
	
	while (p->prev != NULL)
	{
		p = p->prev;
	}
	
	for (i = m_node_num-1; i >= 0; i--)
	{
		parent = m_node_stack[i];
		if (((DEZ_NODE_EXPR *)(parent->content))->branch_node == p)
		{
			return parent;
		}
	}
	
	return NULL;
}

static int get_prev_zend_linenum (DEZ_NODE *node)
{
	DEZ_NODE *prev, *next, *sub, *p = node;
	
	if (p == NULL)
	{
		return -1;
	}
	
	next = node;
	prev = p->prev;
	while (prev != NULL)
	{
		if (
			prev->dez_op == DEZ_OP_FUNCTION ||
			prev->dez_op == DEZ_OP_CLASS
		)
		{
			return -1;
		}
		else if (prev->dez_op != DEZ_OP_NOP)
		{
			break;
		}
		
		next = prev;
		prev = prev->prev;
	}
	
	if (prev == NULL)
	{
		int i;
		
		for (i = m_node_num-1; i >= 0; i--)
		{
			prev = m_node_stack[i];
			if (((DEZ_NODE_EXPR *)(prev->content))->branch_node == next)
			{
				break;
			}
		}
		
		if (i < 0)								/* no parent */
		{
			return -1;
		}

		if (
			prev->dez_op == DEZ_OP_DO	||										/* do{...}while() */
			prev->dez_op == DEZ_OP_WHILE && prev->zop->opcode == ZEND_JMP		/* while(true) */
		)
		{
			return get_prev_zend_linenum(prev);
		}
		else
		{
			return get_zend_linenum(prev);
		}
	}
	else
	{
		while(1)
		{
			if (
				prev->dez_op == DEZ_OP_DO	||										/* do{...}while() */
				prev->dez_op == DEZ_OP_WHILE && prev->zop->opcode == ZEND_JMP		/* while(true) */
			)
			{
				break;
			}
			
			sub = dez_get_last_sub_node(prev);
			
			if (sub == NULL)
			{
				break;
			}
			
			prev = sub;
		}
	
		return get_zend_linenum(prev);
	}
}

static int dez_in_branch(DEZ_NODE *node, unsigned char parent_dop)
{
	DEZ_NODE *p;
	int i;
	
	p = node;
	
	while(1)
	{
		p = get_parent_node(p);
		
		if (p == NULL)
		{
			return -1;
		}
		
		if (
			p->dez_op == DEZ_OP_FUNCTION	||
			p->dez_op == DEZ_OP_CLASS
		)
		{
			break;
		}
		
		if (p->dez_op == parent_dop)
		{
			return 0;
		}
	}
	
	return -1;
}
	
static int dez_get_dest (DEZ_NODE *node)
{
	int dest = 0;
	
	if (node == NULL)
	{
		return 0;
	}
	
	if (
		node->dez_op == DEZ_OP_FUNCTION ||
		node->dez_op == DEZ_OP_CLASS
	)
	{
		return 1000000;
	}
	
	if (node->zop != NULL)
	{
		if
		(
			node->zop->opcode == ZEND_JMP				&&
			node->zop->op1.op_type == IS_UNUSED
		)
		{
			dest = node->zop->op1.u.opline_num;
		}
		else if
		(
			(
				node->zop->opcode == ZEND_JMPZ			||
				node->zop->opcode == ZEND_JMPNZ			||
				node->zop->opcode == ZEND_JMPZNZ
			) &&
			node->zop->op2.op_type == IS_UNUSED
		)
		{
			dest = node->zop->op2.u.opline_num;
		}
		else if
		(
			node->dez_op == DEZ_OP_CASE					&&
			(
				ZEND_GET_ORI(node->zop)[1].opcode == ZEND_JMPZ		||
				ZEND_GET_ORI(node->zop)[1].opcode == ZEND_JMPZNZ
			)											&&
			ZEND_GET_ORI(node->zop)[1].op2.op_type == IS_UNUSED
		)
		{
			dest = ZEND_GET_ORI(node->zop)[1].op2.u.opline_num;
		}
		else if
		(
			node->dez_op == DEZ_OP_FOREACH				&&
			ZEND_GET_ORI(node->zop)[1].opcode == ZEND_FE_FETCH		&&
			ZEND_GET_ORI(node->zop)[1].op2.op_type == IS_UNUSED
		)
		{
			dest = ZEND_GET_ORI(node->zop)[1].op2.u.opline_num;
		}
	}
	
	return dest;
}

static int dez_get_branch_end (DEZ_NODE *parent)
{
	int i;
	int dest, mindest;
	DEZ_NODE *header;
	DEZ_NODE *pp = NULL;
	
	if (parent == NULL)
	{
		return 100000;
	}
	
	header = parent;
	while (header->prev != NULL)
	{
		header = header->prev;
	}

	i = m_node_num-1;
	while (i >= 0)
	{
		pp = m_node_stack[i];
		
		if (
			pp->dez_op == DEZ_OP_FUNCTION ||
			pp->dez_op == DEZ_OP_CLASS
		)
		{
			pp = NULL;
			break;
		}
		
		if (((DEZ_NODE_EXPR *)(pp->content))->branch_node == header)
		{
			break;
		}
		
		i--;
	}
	
	if (i < 0)								/* the parent node was not found */
	{
		pp = NULL;
	}

	mindest = 100000;
	while (i >= 0)
	{
		DEZ_NODE *ppp = m_node_stack[i];
		
		if (
			ppp->dez_op == DEZ_OP_FUNCTION ||
			ppp->dez_op == DEZ_OP_CLASS
		)
		{
			break;
		}
		
		dest = dez_get_dest(ppp);
		
		if (dest > get_zend_linenum(ppp))			/* goto foreward */
		{
			if (dest < mindest)
			{
				mindest = dest;
			}
		}
		
		i--;
	}
	
	dest = dez_get_dest(parent);

	if (dest < get_zend_linenum(parent))			/* goto afterward */
	{
		dest = mindest;
	}
	else if (dest > mindest)
	{
		dest = mindest;
	}
	
	return dest;
}
		
static DEZ_NODE *dez_list_get_last_fetch (DEZ_NODE *node)
{
	if (node == NULL)
	{
		return NULL;
	}
	
	if (node->dez_op == DEZ_OP_ASSIGN)
	{
		DEZ_NODE_EXPR *c = (DEZ_NODE_EXPR *)(node->content);
		DEZ_NODE *fetch, *prev;
		
		if (c == NULL)
		{
			return NULL;
		}
		
		fetch	= c->op2_node;
		prev	= NULL;
		
		while (fetch != NULL)
		{
			if (fetch->dez_op != DEZ_OP_FETCH_DIM)
			{
				break;
			}
			
			prev	= fetch;
			fetch	= ((DEZ_NODE_EXPR *)(fetch->content))->op1_node;
		}
		
		return prev;
	}
	
	return NULL;
}

static int dez_list_get_base_level (DEZ_NODE *list, DEZ_NODE *node)
{
	DEZ_NODE_LIST *lc;
	DEZ_NODE *fetch;
	DEZ_NODE *last_fetch;
	int n;

	if (list == NULL)
	{
		return 0;
	}
	
	last_fetch = dez_list_get_last_fetch(node);
	if (last_fetch == NULL)
	{
		return 0;
	}
	
	lc = (DEZ_NODE_LIST *)(list->content);
	fetch = lc->dest_node;
	
	n = 0;
	while (fetch != NULL && fetch->dez_op == DEZ_OP_FETCH_DIM)
	{
		if (
			fetch->zop->op1.op_type == last_fetch->zop->op1.op_type &&
			fetch->zop->op1.u.var == last_fetch->zop->op1.u.var
		)
		{
			return lc->level - n;
		}
		
		fetch = ((DEZ_NODE_EXPR *)(fetch->content))->op1_node;
		
		n++;
	}
	
	return 0;
}
	
static int dez_list_get_level (DEZ_NODE *list, DEZ_NODE *node)
{
	int level;
	
	if (node == NULL)
	{
		return -1;
	}
	
	if (node->dez_op == DEZ_OP_ASSIGN)
	{
		DEZ_NODE_EXPR *c = (DEZ_NODE_EXPR *)(node->content);
		DEZ_NODE *fetch;
		
		if (c == NULL)
		{
			return -1;
		}
		
		level	= 0;
		fetch	= c->op2_node;
		
		while (fetch != NULL)
		{
			if (fetch->dez_op != DEZ_OP_FETCH_DIM)
			{
				break;
			}
			
			level++;
			
			fetch = ((DEZ_NODE_EXPR *)(fetch->content))->op1_node;
		}
		
		return level + dez_list_get_base_level(list, node);
	}
	else if (node->dez_op == DEZ_OP_LIST)
	{
		DEZ_NODE_LIST *c = (DEZ_NODE_LIST *)(node->content);
		return c->level;
	}
	
	return -1;
}

static int dez_list_get_lei (DEZ_NODE *list, DEZ_NODE *node, int level)
{
	DEZ_NODE *fetch;
	
	int maxl;
	int n;
	
	if (
		list == NULL ||
		node == NULL ||
		level <= 0
	)
	{
		return 10000;
	}
	
	if (node->dez_op == DEZ_OP_ASSIGN)
	{
		DEZ_NODE_EXPR *c;
		c = (DEZ_NODE_EXPR *)(node->content);
		fetch	= c->op2_node;
	}
	else if (node->dez_op == DEZ_OP_LIST)
	{
		DEZ_NODE_LIST *c;
		c = (DEZ_NODE_LIST *)(node->content);
		fetch	= c->dest_node;
		
		if (fetch != NULL)
		{
			fetch = ((DEZ_NODE_EXPR *)(fetch->content))->op1_node;
		}
	}
	else if (node->dez_op == DEZ_OP_LE)
	{
		if (level == ((DEZ_NODE_LIST *)(list->content))->level + 1)
		{
			return ((DEZ_NODE_LE *)(node->content))->pos;
		}
		
		return 10000;
	}
	
	maxl = dez_list_get_level (list, node);
	
	if (maxl < level)
	{
		return 10000;
	}
	
	n = maxl - level;
	
	while (n > 0)
	{
		if (
			fetch == NULL ||
			fetch->dez_op != DEZ_OP_FETCH_DIM
		)
		{
			return 10000;
		}
		
		fetch = ((DEZ_NODE_EXPR *)(fetch->content))->op1_node;
		
		n--;
	}
	
	if (
		fetch == NULL ||
		fetch->dez_op != DEZ_OP_FETCH_DIM
	)
	{
		return 10000;
	}
	
	return fetch->zop->op2.u.var;
}

static DEZ_NODE *dez_list_fetch_sub_dest (DEZ_NODE *node)
{
	if (node == NULL)
	{
		return NULL;
	}
	
	if (node->dez_op == DEZ_OP_ASSIGN)
	{
		DEZ_NODE_EXPR *c = (DEZ_NODE_EXPR *)(node->content);
		DEZ_NODE *fetch;
		
		if (c == NULL)
		{
			return NULL;
		}
		
		fetch	= c->op2_node;
		
		c->op2_node = NULL;
		
		return fetch;
	}
	else if (node->dez_op == DEZ_OP_LIST)
	{
		DEZ_NODE_LIST *c = (DEZ_NODE_LIST *)(node->content);
		DEZ_NODE *fetch;
		
		if (c->dest_node == NULL)
		{
			return NULL;
		}
		
		fetch = ((DEZ_NODE_EXPR *)(c->dest_node->content))->op1_node;
		((DEZ_NODE_EXPR *)(c->dest_node->content))->op1_node = NULL;
		
		return fetch;
	}
	
	return NULL;
}

static DEZ_NODE *dez_list_create (int level)
{
	DEZ_NODE *node;
	DEZ_NODE_LIST *content;
	
	content = (DEZ_NODE_LIST *)malloc(sizeof(DEZ_NODE_LIST));
	if (content == NULL)
	{
		return NULL;
	}
	
	node = (DEZ_NODE *)malloc(sizeof(DEZ_NODE));
	if (node == NULL)
	{
		free(content);
		return NULL;
	}
	
	content->branch_node	= NULL;
	content->le_node		= NULL;
	content->dest_node		= NULL;
	content->level			= level;
	
	node->dez_op			= DEZ_OP_LIST;
	node->zop				= NULL;
	node->content			= content;
	node->prev				= NULL;
	node->next				= NULL;
	
	return node;
}

static int dez_list_add_le (DEZ_NODE *list, DEZ_NODE *node, int node_level)
{
	DEZ_NODE *le, *sl;
	DEZ_NODE_LIST *lc;
	DEZ_NODE_LE *lec;
	int level;
	
	lc = (DEZ_NODE_LIST *)(list->content);
	
	if (node_level > 0)
	{
		level = node_level;
	}
	else
	{
		level = dez_list_get_level(list, node);
		
		if (level <= 0)
		{
			return -1;
		}
	}
	
	if (level > lc->level+1)
	{
		/*-- search sub list --*/
		int lei = dez_list_get_lei(list, node, lc->level+1);
		
		le = lc->le_node;
		while (le != NULL)
		{
			if (
				((DEZ_NODE_LE *)(le->content))->a_node->dez_op == DEZ_OP_LIST &&
				lei == dez_list_get_lei (list, le, lc->level+1)
			)
			{
				break;
			}
			
			le = le->next;
		}
		
		if (le != NULL)							/* the sub list is found --*/
		{
			dez_list_add_le(((DEZ_NODE_LE *)(le->content))->a_node, node, level);
		}
		else
		{
			sl = dez_list_create(lc->level+1);
			dez_list_add_le(sl, node, level);
			dez_list_add_le(list, sl, lc->level+1);
		}
	}
	else if (level == lc->level+1)
	{
		int lei;
		
		lec = (DEZ_NODE_LE *)malloc(sizeof(DEZ_NODE_LE));
		if (lec == NULL)
		{
			return -1;
		}
		
		le = (DEZ_NODE *)malloc(sizeof(DEZ_NODE));
		if (le == NULL)
		{
			free(lec);
			return -1;
		}
		
		lei = dez_list_get_lei(list, node, level);
		
		lec->branch_node	= NULL;
		lec->a_node			= node;
		lec->pos			= lei;
		le->dez_op			= DEZ_OP_LE;
		le->zop				= node->zop;
		le->content			= lec;
		le->prev			= NULL;
		le->next			= NULL;
		
		if (lc->le_node == NULL)					/* the list is empty */
		{
			lc->le_node		= le;
			lc->dest_node	= dez_list_fetch_sub_dest(node);
			list->zop		= node->zop;
		}
		else
		{
			DEZ_NODE *prev, *le1;
			
			le1 = lc->le_node;
			prev= NULL;
			
			while(le1 != NULL)
			{
				int le1_lei = dez_list_get_lei(list, le1, level);
				
				if (le1_lei == lei)					/* the element is exist */
				{
					free(lec);
					free(le);
					
					return -1;
				}
				else if (le1_lei > lei)
				{
					break;
				}
				
				prev = le1;
				le1 = le1->next;
			}
			
			if (prev == NULL)						/* the first element added */
			{
				le->next		= lc->le_node;
				lc->le_node		= le;
				if (le->next != NULL) le->next->prev = le;
			}
			else
			{
				le->next		= prev->next;
				le->prev		= prev;
				if (le->next != NULL) le->next->prev = le;
				if (le->prev != NULL) le->prev->next = le;
			}
		}
	}
	else
	{
		sl = dez_list_create(lc->level-1);
		
		sl->next	= list->next;
		sl->prev	= list->prev;
		if (sl->next != NULL) sl->next->prev = sl;
		if (sl->prev != NULL) sl->prev->next = sl;
		list->next	= NULL;
		list->prev	= NULL;
		
		if (list == m_dez_op_current)
		{
			m_dez_op_current = sl;
		}
		
		dez_list_add_le(sl, list, lc->level);
		dez_list_add_le(sl, node, level);
	}
	
	return 0;
}

static int dez_list_is_le (DEZ_NODE *node)
{
	DEZ_NODE *last_fetch;
	DEZ_NODE_EXPR *expr;
	
	last_fetch = dez_list_get_last_fetch(node);
	
	if (last_fetch == NULL)
	{
		return -1;
	}
	
	expr = (DEZ_NODE_EXPR *)(last_fetch->content);
	
	if (
		expr != NULL &&
		expr->op1_node == NULL &&
		(last_fetch->zop->op1.op_type == IS_TMP_VAR || last_fetch->zop->op1.op_type == IS_VAR)
	)
	{
		return 0;
	}
	
	return -1;
}

static DEZ_NODE *dez_list_find_dest (DEZ_NODE *le)
{
	DEZ_NODE *p = m_dez_op_current;
	DEZ_NODE *last_fetch = dez_list_get_last_fetch(le);
	
	if (last_fetch == NULL)
	{
		return NULL;
	}
	
	while(p != NULL)
	{
		DEZ_NODE_EXPR *c;
		DEZ_NODE *fetch;
		
		if (p->dez_op != DEZ_OP_ASSIGN)
		{
			p = p->prev;
			continue;
		}

		c = (DEZ_NODE_EXPR *)(p->content);
		
		if (c == NULL)
		{
			p = p->prev;
			continue;
		}
		
		fetch	= c->op2_node;
		
		while (fetch != NULL)
		{
			if (
				fetch->dez_op == DEZ_OP_FETCH_DIM &&
				((DEZ_NODE_EXPR *)(fetch->content))->op1_node != NULL &&
				fetch->zop->op1.op_type == last_fetch->zop->op1.op_type &&
				fetch->zop->op1.u.var == last_fetch->zop->op1.u.var
			)
			{
				return p;
			}
			
			fetch	= ((DEZ_NODE_EXPR *)(fetch->content))->op1_node;
		}

		p = p->prev;
	}

	return NULL;
}

static int dez_list_is_dest (DEZ_NODE *node, znode *zn)
{
	if (node->dez_op == DEZ_OP_LIST)
	{
		DEZ_NODE_LIST *c = (DEZ_NODE_LIST *)(node->content);
		
		if (
			c != NULL										&&
			c->dest_node != NULL							&&
			c->dest_node->zop != NULL						&&
			c->dest_node->zop->op1.op_type == zn->op_type	&&
			c->dest_node->zop->op1.u.var == zn->u.var
		)
		{
			return 0;
		}
	}
	
	return -1;
}

static DEZ_NODE *find_tmp_node (znode *zn)
{
	DEZ_NODE *p = m_dez_op_current;
	
	while(p != NULL)
	{
		if (
			p->zop != NULL							&&
			p->zop->result.op_type == zn->op_type	&&
			p->zop->result.u.var == zn->u.var
		)
		{
			return p;
		}
		
		p = p->prev;
	}
	
	return NULL;
}

static DEZ_NODE *fetch_node (DEZ_NODE *node)
{
	if (node == NULL || node->prev == NULL)
	{
		return NULL;
	}
	
	node->prev->next = node->next;
	if (node->next != NULL) node->next->prev = node->prev;
	
	if (node == m_dez_op_current)
	{
		m_dez_op_current = node->prev;
	}
	
	node->prev = NULL;
	node->next = NULL;
	
	return node;
}

static DEZ_NODE *fetch_current_node (void)
{
	DEZ_NODE *p = m_dez_op_current;
	
	if (p == NULL || p->prev == NULL)
	{
		return NULL;
	}
	
	p->prev->next = NULL;
	m_dez_op_current = p->prev;
	
	p->prev = NULL;
	
	return p;
}

static DEZ_NODE *fetch_tmp_node (znode *zn)
{
	DEZ_NODE *p = m_dez_op_current;
	zend_op *zop = m_zend_op_current-m_opc_num;
	
	if (zn->op_type == IS_TMP_VAR || zn->op_type == IS_VAR)
	{
		while (zop >= m_zend_op_start)
		{
			if (
				zop->result.op_type == zn->op_type	&&
				zop->result.u.var == zn->u.var
			)
			{
				break;
			}
			
			zop--;
		}
		
		if (zop < m_zend_op_start)						/* not found */
		{
			return NULL;
		}
		
		while(p != NULL)
		{
			if (p->zop != NULL)
			{
				if (p->zop < zop)
				{
					break;
				}
				else if (
					p->zop->result.op_type == zn->op_type	&&
					p->zop->result.u.var == zn->u.var
				)
				{
					if (p->prev != NULL) p->prev->next = p->next;
					if (p->next != NULL) p->next->prev = p->prev;
					
					if (p == m_dez_op_current)
					{
						m_dez_op_current = p->prev;
					}
					
					p->prev	= NULL;
					p->next	= NULL;
					
					return p;
				}
			}
			
			p = p->prev;
		}
	}
	
	/*-- fetch list node --*/
	p = m_dez_op_current;
	if(p != NULL)
	{
		if (dez_list_is_dest(p, zn) == 0)
		{
			if (p->prev != NULL) p->prev->next = p->next;
			if (p->next != NULL) p->next->prev = p->prev;
			
			m_dez_op_current = p->prev;
			
			p->prev	= NULL;
			p->next	= NULL;
			
			return p;
		}
	}
	
	return NULL;
}

static DEZ_NODE *fetch_call_ini_node (znode *zn)
{
	DEZ_NODE *p = fetch_tmp_node(zn);
	
	if (p != NULL)
	{
		return p;
	}
	
	if (
		zn->op_type == IS_CONST &&
		zn->u.constant.type == IS_STRING
	)
	{
		p = m_dez_op_current;
		
		while(p != NULL)
		{
			if (
				p->dez_op == DEZ_OP_CALL_INIT			&&
				p->zop != NULL							&&
				p->zop->op2.op_type == IS_CONST			&&
				p->zop->op2.u.constant.type == IS_STRING&&
				strcmp((char *)(p->zop->op2.u.var), (char *)(zn->u.var)) == 0
			)
			{
				return fetch_node(p);
			}
			
			p = p->prev;
		}
	}
	else
	{
		p = m_dez_op_current;
		
		while(p != NULL)
		{
			if (
				p->dez_op == DEZ_OP_CALL_INIT			&&
				p->zop != NULL							&&
				p->zop->op2.op_type == zn->op_type		&&
//				p->zop->op2.u.constant.type == zn->u.constant.type &&
				p->zop->op2.u.var == zn->u.var
			)
			{
				return fetch_node(p);
			}
			
			p = p->prev;
		}
	}
	
	return NULL;
}

static DEZ_NODE *fetch_jmp_src_node (int jmpcode, int dest)
{
	DEZ_NODE *p = m_dez_op_current;
	
	while(p != NULL)
	{
		if (
			p->zop != NULL							&&
			p->zop->opcode == jmpcode				&&
			p->zop->op2.op_type == IS_UNUSED		&&
			p->zop->op2.u.opline_num == dest
		)
		{
			if (p->prev != NULL) p->prev->next = p->next;
			if (p->next != NULL) p->next->prev = p->prev;
			
			if (p == m_dez_op_current)
			{
				m_dez_op_current = p->prev;
			}
			
			p->prev	= NULL;
			p->next	= NULL;
			
			return p;
		}
		
		p = p->prev;
	}
	
	return NULL;
}

static DEZ_NODE *get_jmp_dest_node (int dest)
{
	DEZ_NODE *p = m_dez_op_current;
	
	if (
		p->zop != NULL								&&
		get_zend_linenum(p) < dest
	)
	{
		return NULL;
	}
	
	while(p->prev != NULL)
	{
		if (
			p->prev->zop != NULL					&&
			get_zend_linenum(p->prev) < dest
		)
		{
			break;
		}
		
		p = p->prev;
	}
	
	if (p->prev == NULL)
	{
		p = p->next;
	}
	
	return p;
}

static DEZ_NODE *fetch_jmp_dest_node (int dest)
{
	DEZ_NODE *p = get_jmp_dest_node(dest);
	
	if (p == NULL)
	{
		return NULL;
	}
	
	m_dez_op_current = p->prev;
	m_dez_op_current->next = NULL;
	
	p->prev	= NULL;
	
	return p;
}

static DEZ_NODE *find_last_node (int dez_op)
{
	DEZ_NODE *p = m_dez_op_current;
	
	while(p != NULL)
	{
		if (p->dez_op == dez_op)
		{
			break;
		}
		
		p = p->prev;
	}
	
	return p;
}

static DEZ_NODE *find_last_node_ex (int dez_op, znode *result, znode *op1, znode *op2)
{
	DEZ_NODE *p = m_dez_op_current;
	znode *zn;
	
	while(p != NULL)
	{
		if (p->dez_op == dez_op)
		{
			int found = 1;
			
			if (result != NULL)
			{
				zn = &(p->zop->result);
				
				if (
					zn->op_type != result->op_type		||
					zn->u.var != result->u.var
				)
				{
					found = 0;
				}
			}
			
			if (op1 != NULL)
			{
				zn = &(p->zop->op1);
				
				if (
					zn->op_type != op1->op_type		||
					zn->u.var != op1->u.var
				)
				{
					found = 0;
				}
			}
			
			if (op2 != NULL)
			{
				zn = &(p->zop->op2);
				
				if (
					zn->op_type != op2->op_type		||
					zn->u.var != op2->u.var
				)
				{
					found = 0;
				}
			}
			
			if (found != 0)
			{
				return p;
			}
		}
		
		p = p->prev;
	}
	
	return NULL;
}

static int dez_is_first_node (DEZ_NODE *node)
{
	if (node == NULL)
	{
		return 0;
	}
	
	node = node->prev;
	
	while (node != NULL)
	{
		if (node->dez_op != DEZ_OP_NOP)
		{
			return -1;
		}
		
		node = node->prev;
	}
	
	return 0;
}

static int dez_branch_get_range (DEZ_NODE *parent, int *header, int *tailer)
{
	if (
		parent == NULL			||
		parent->content == NULL	||
		header == NULL			||
		tailer == NULL
	)
	{
		return -1;
	}
	
	if (parent->dez_op == DEZ_OP_FOR)
	{
		DEZ_NODE *before_node = ((DEZ_NODE_FOR *)(parent->content))->before_node;
		
		if (before_node != NULL)
		{
			*header = get_zend_linenum(before_node)+1;
		}
		else
		{
			*header = get_prev_zend_linenum(parent)+1;
		}
	}
	else
	{
		*header = get_prev_zend_linenum(parent)+1;
	}
	
	if (
		parent->dez_op == DEZ_OP_DO	||											/* do{...}while() */
		parent->dez_op == DEZ_OP_WHILE && parent->zop->opcode == ZEND_JMP		/* while(true) */
	)
	{
		*tailer = get_zend_linenum(parent);
	}
	else
	{
		DEZ_NODE *lastnode;
		
		lastnode = parent;
		
		while(1)
		{
			DEZ_NODE *sub;
			
			sub = dez_get_last_sub_node(lastnode);
			
			if (sub == NULL)												/* no sub node */
			{
				break;
			}
			
			lastnode = sub;
			
			if (
				lastnode->dez_op == DEZ_OP_DO	||										/* do{...}while() */
				lastnode->dez_op == DEZ_OP_WHILE && lastnode->zop->opcode == ZEND_JMP	/* while(true) */
			)
			{
				break;
			}
		}
		
		*tailer = get_zend_linenum(lastnode);
	}
	
	return 0;
}

static int dez_enter_branch (void)
{
	DEZ_NODE_EXPR *content;
	
	content = (DEZ_NODE_EXPR *)(m_dez_op_current->content);
	
	if (content->branch_node == NULL)
	{
		content->branch_node = (DEZ_NODE *)malloc(sizeof(DEZ_NODE));
		if (content->branch_node == NULL)
		{
			return -1;
		}
		
		content->branch_node->dez_op	= DEZ_OP_NOP;
		content->branch_node->zop		= NULL;
		content->branch_node->content	= NULL;
		content->branch_node->prev		= NULL;
		content->branch_node->next		= NULL;
	}
	
	dez_node_push(m_dez_op_current);
	m_dez_op_current = content->branch_node;
		
	return 0;
}

static int dez_enter_branch_ex (DEZ_NODE *node)
{
	DEZ_NODE_EXPR *content;
	
	content = (DEZ_NODE_EXPR *)(node->content);
	content->branch_node = (DEZ_NODE *)malloc(sizeof(DEZ_NODE));
	if (content->branch_node == NULL)
	{
		return -1;
	}
	
	dez_node_push(node);
	
	content->branch_node->dez_op	= DEZ_OP_NOP;
	content->branch_node->zop		= NULL;
	content->branch_node->content	= NULL;
	content->branch_node->prev		= NULL;
	content->branch_node->next		= node->next;
	if (content->branch_node->next != NULL) content->branch_node->next->prev = content->branch_node;
	
	if (node == m_dez_op_current)
	{
		m_dez_op_current = content->branch_node;
	}
	
	return 0;
}

// enterelse = 0: don't enter else node, 1: enter else node
static int dez_exit_branch (int enterelse)
{
	DEZ_NODE *node, *els, *tmp, *m_dez_op_current2;
	DEZ_NODE_EXPR *content;
	int nextline, dest;
	int remove_node = 0;
	int dup_jmp = 0;
	zend_op *cur_zop;
	
	node = dez_node_pop();
	
	if (node == NULL)
	{
		return -1;
	}
	
	cur_zop = ZEND_GET_ORI(m_zend_op_current) - m_opc_num + m_zend_op_match_n;
	
	content = (DEZ_NODE_EXPR *)(node->content);
	
	m_dez_op_current2 = NULL;
	els = NULL;
	nextline = ZEND_LINENUM(cur_zop) + 1;
	
	if (node->dez_op  == DEZ_OP_IF)							/* if */
	{
		if (
			enterelse == 1	&&								/* need enter else node */
			node->zop->opcode != ZEND_JMP					/* not if (false) */
		)
		{
			int dest;
			
			dest = dez_get_dest(node);
			
			if (dest == nextline)							/* there maybe is else node */
			{
				DEZ_NODE *lastnode = NULL;
				int jmpdest;
				
				tmp = dez_get_last_sub_node(node);
				
				while(tmp != NULL)
				{
					lastnode = tmp;
					tmp = dez_get_last_sub_node(tmp);
				}
				
				jmpdest = dez_get_dest(lastnode);
				
				if (
					lastnode != NULL	&&
					lastnode->dez_op == DEZ_OP_IF	&&			/* if */
					lastnode->zop->opcode == ZEND_JMP &&		/* if (false) */
					(jmpdest > dest || jmpdest <= get_prev_zend_linenum(node)) &&	/* has some zend ops */
//					dez_get_branch_end(lastnode) > dest &&		/* has some zend ops */
					dez_branch_is_null(lastnode) == 0			/* the sub branch is null */
				)
				{
					m_dez_op_current = node;
					
					dez_node_cvt_if(DEZ_OP_ELSE, lastnode->zop);/* add else node */
					dez_enter_branch();							/* enter else node */
					
					return 0;
				}
			}
		}
	}
	else if (
		node->dez_op == DEZ_OP_CASE		||					/* case of switch */
		node->dez_op == DEZ_OP_DEFAULT						/* default of switch */
	)
	{
		m_dez_op_current2 = content->op1_node;				/* return to switch node */
	}
	else if (node->dez_op == DEZ_OP_ELSE)					/* else node */
	{
		if (dez_branch_is_null(node) == 0)					/* the branch is null */
		{
			tmp = node->prev;
			tmp->next = node->next;
			node->prev = NULL;
			
			m_dez_op_current2 = tmp;
			
			remove_node = 1;
		}
	}

	if (m_dez_op_current2 == NULL)
	{
		m_dez_op_current = node;
	}
	else
	{
		m_dez_op_current = m_dez_op_current2;
	}
	
	if (node != NULL)
	{
		DEZ_NODE *lastsubnode = dez_get_last_sub_node(node);
			
		dest = dez_get_dest(node);

#if 0
		if (
			dest >= nextline &&
			node->dez_op == DEZ_OP_IF && node->zop->opcode == ZEND_JMP &&	/* maybe break */
			lastsubnode != NULL	&&
			lastsubnode->dez_op == DEZ_OP_IF && lastsubnode->zop->opcode == ZEND_JMP	/* if (false) */
		)
		{
			DEZ_NODE *pp = dez_node_get();
			
			if (
				pp != NULL	&&
				pp->dez_op == DEZ_OP_IF && pp->zop->opcode != ZEND_JMP
			)
			{
				int ppbegin = get_prev_zend_linenum(pp);
				int ppend = dez_get_branch_end(pp);
				
				if (
					(int)(node->zop->op1.u.opline_num) <= ppbegin &&
					(int)(node->zop->op1.u.opline_num) > ppend &&		/* jmp out of branch of node */
					(int)(lastsubnode->zop->op1.u.opline_num) <= ZEND_LINENUM(pp->zop) &&
					(int)(lastsubnode->zop->op1.u.opline_num) > ppbegin	/* jmp to header of pp */
				)
				{
					dez_node_cvt_jmp(DEZ_OP_JMP, lastsubnode->zop);
					return 0;
				}
			}
		}
#endif
		
		if (dest <= get_zend_linenum(node))								/* jump afterward */
		{
			dup_jmp = 1;
		}
		else if (dest >= nextline)
		{
//			if (cur_zop->opcode == ZEND_JMP)
			if (
				lastsubnode != NULL	&&
				lastsubnode->dez_op == DEZ_OP_IF && lastsubnode->zop->opcode == ZEND_JMP	/* if (false) */
			)
			{
				int dest_is_case_default = 0;
				zend_op *zop_dest = m_zend_op_start + lastsubnode->zop->op1.u.opline_num;
				
				if (
					(zop_dest[-1].opcode == ZEND_JMPZ || zop_dest[-1].opcode == ZEND_JMPZNZ)	&&
					zop_dest[-2].opcode == ZEND_CASE
				)														/* the dest is 'case' */
				{
					dest_is_case_default = 1;
				}
				else if (
					zop_dest[-1].opcode == ZEND_BOOL	&&
					zop_dest[-2].opcode == ZEND_JMP
				)														/* the dest is 'default' */
				{
					dest_is_case_default = 1;
				}
				
				if (
					!(
						node->dez_op == DEZ_OP_ELSE				&&
						dez_in_branch(node, DEZ_OP_CASE) == 0	&&		/* within case branch */
						dest_is_case_default							/* the dest node is case or default node */
					)
				)
				{
					dup_jmp = 1;
				}
			}
		}

		if (dup_jmp != 0)
		{
			zend_op *dupzop;
			
			dupzop = dez_dup_zend_op(cur_zop);
			dupzop->opcode = ZEND_JMP;
			dupzop->op1.op_type = IS_UNUSED;
			dupzop->op1.u.opline_num = dest;
			dupzop->op2.op_type = IS_UNUSED;
			dupzop->op2.u.opline_num = 0;
			dupzop->result.op_type = IS_UNUSED;
			dupzop->result.u.opline_num = 0;
			
			dez_node_cvt_jmp(DEZ_OP_JMP, dupzop);
		}
	}

	if (remove_node != 0)
	{	
		dez_node_specs[node->dez_op].dez_node_free_func(node);	/* remove the else node */
	}
	
	return 0;
}

static int dez_check_exit_branch (void)
{
	DEZ_NODE *node;
	int nextline,dest;
	int i;
	
	nextline = ZEND_LINENUM(m_zend_op_current) - m_opc_num + m_zend_op_match_n + 1;
	
	for (i = 0; i < m_node_num; i++)
	{
		node = m_node_stack[i];
		
		if (
			node->dez_op == DEZ_OP_FUNCTION ||
			node->dez_op == DEZ_OP_CLASS
		)
		{
			continue;
		}
		
		dest = dez_get_branch_end(node);
		
		if (dest <= nextline)
		{
			break;
		}
	}
	
#if 0
	if (i < m_node_num)												/* found */
	{
		int n = m_node_num - 1;
		
		/*-- exit child branch tree --*/
		while (n > i)
		{
			dez_exit_branch(0);
			n--;
		}
		
		dez_exit_branch(1);											/* exit self */
	}
#endif
	
	while (i+1 < m_node_num)
	{
		dez_exit_branch(0);
	}
	
	if (i < m_node_num)
	{
		dez_exit_branch(1);
	}
	
	return 0;
}

static int dez_check_exit_all (void)
{
	while(m_node_num > 0)
	{
		DEZ_NODE *node = dez_node_get();
		
		if (
			node->dez_op == DEZ_OP_FUNCTION	||
			node->dez_op == DEZ_OP_CLASS
		)
		{
			break;
		}
		
		dez_exit_branch(0);
	}
	
	return 0;
}
	
#if 0
static int dez_check_exit_branch (void)
{
	int nextline;
	DEZ_NODE *tmp, *node, *els;
	DEZ_NODE_EXPR *content;
	int i,j;
	
	nextline = ZEND_LINENUM(m_zend_op_current - m_opc_num) + 1;
	
	for (i = 0; i < m_node_num; i++)
	{
		int dest;
		
		node = m_node_stack[i];
		
		if (
			node->dez_op == DEZ_OP_FUNCTION ||
			node->dez_op == DEZ_OP_CLASS
		)
		{
			continue;
		}
		
		content = (DEZ_NODE_EXPR *)(node->content);
		
		dest = dez_get_dest(node);
		
		if (
			dest > get_zend_linenum(node) &&						/* jump forward */
			dest <= nextline
		)
		{
			m_dez_op_current = node;
			
			els = NULL;
			
			if (
				node->dez_op  == DEZ_OP_IF &&						/* if */
				node->zop->opcode != ZEND_JMP						/* not if (false) */
			)
			{
				tmp = dez_node_get();
				
				if (
					node != tmp &&
					tmp != NULL	&&
					tmp->dez_op == DEZ_OP_IF	&&				/* if */
					tmp->zop->opcode == ZEND_JMP &&				/* if (false) */
					dez_get_dest(tmp) > nextline &&				/* has some zend ops */
					dez_branch_is_null(tmp) == 0				/* the sub branch is null */
				)
				{
					els = dez_node_pop();
					els->dez_op = DEZ_OP_ELSE;
					els = fetch_node(els);
				}
			}
			else if (
				node->dez_op == DEZ_OP_CASE		||				/* case of switch */
				node->dez_op == DEZ_OP_DEFAULT					/* default of switch */
			)
			{
				m_dez_op_current = content->op1_node;			/* return to switch node */
			}

			/*-- exit all child branchs --*/
			while (m_node_num > i)
			{
				node = m_node_stack[m_node_num-1];
				
				if (node->dez_op == DEZ_OP_ELSE)			/* else node */
				{
					if (dez_branch_is_null(node) == 0)		/* the branch is null */
					{
						tmp = node->prev;
						
						if (m_dez_op_current == node)
						{
							m_dez_op_current = tmp;
						}
						
						tmp->next = node->next;
						node->prev = NULL;
						
						dez_node_specs[node->dez_op].dez_node_free_func(node);	/* remove the else node */
						node = tmp;
					}
				}
				else if (node->dez_op == DEZ_OP_IF && node->zop->opcode == ZEND_JMP)	/* if (false) */
				{
					DEZ_NODE_IF *ifc = (DEZ_NODE_IF *)(node->content);
#if 0					
					node->next = ifc->branch_node->next;		/* moveup all sub node */
					
					ifc->branch_node->next = NULL;
					dez_node_specs[ifc->branch_node->dez_op].dez_node_free_func(ifc->branch_node);
					ifc->branch_node = NULL;
#endif					
					node->dez_op = DEZ_OP_JMP;					/* change this node into JMP (maybe break) */
				}
				
				m_node_num--;
			}
					
			if (els != NULL)
			{
				DEZ_ADD_NODE(els);
				
				dez_enter_branch();								/* enter else branch */
			}
			
			break;
		}
	}
	
	return 0;
}
#endif

/*-- convertor for DEZ_NODE_NOP --*/
static int dez_node_cvt_nop (unsigned char dez_op, zend_op *pzop)
{
	return 0;
}

/*-- convertor for expr --*/
static int dez_node_cvt_expr (unsigned char dez_op, zend_op *pzop)
{
	DEZ_NODE *parent, *node;
	DEZ_NODE_EXPR *content, *c;
	
	parent = dez_node_get();
	
	content = (DEZ_NODE_EXPR *)malloc(sizeof(DEZ_NODE_EXPR));
	if (content == NULL)
	{
		return -1;
	}
	
	node = (DEZ_NODE *)malloc(sizeof(DEZ_NODE));
	if (node == NULL)
	{
		free(content);
		return -1;
	}
	
	content->branch_node	= NULL;
	content->op1_node		= fetch_tmp_node(&(pzop->op1));
	content->op2_node		= fetch_tmp_node(&(pzop->op2));
	
	node->dez_op	= dez_op;
	node->zop		= pzop;
	node->content	= content;
	node->prev		= NULL;
	node->next		= NULL;

	if (
		dez_op == DEZ_OP_ASSIGN				&&
		parent != NULL						&&
		parent->dez_op == DEZ_OP_FOREACH
	)
	{
		DEZ_NODE_FOREACH *fe = (DEZ_NODE_FOREACH *)(parent->content);
		
		if (
			content->op2_node != NULL &&
			content->op2_node->zop->opcode == ZEND_FETCH_DIM_TMP_VAR &&
			content->op2_node->zop->op1.op_type == ZEND_GET_ORI(parent->zop)[1].result.op_type &&
			content->op2_node->zop->op1.u.var == ZEND_GET_ORI(parent->zop)[1].result.u.var
		)
		{
			if (
				fe->value_node == NULL &&
				content->op2_node->zop->op2.u.var == 0
			)
			{
				node->dez_op = DEZ_OP_AS;
				fe->value_node = node;
				
				return 0;
			}
			else if
			(
				fe->key_node == NULL &&
				content->op2_node->zop->op2.u.var == 1
			)
			{
				node->dez_op = DEZ_OP_AS;
				fe->key_node = node;
				
				return 0;
			}
			
		}
		else if (content->op2_node == NULL)
		{
			if (
				fe->value_node == NULL &&
				pzop->op2.op_type == ZEND_GET_ORI(parent->zop)[1].result.op_type &&
				pzop->op2.u.var == ZEND_GET_ORI(parent->zop)[1].result.u.var
			)
			{
				node->dez_op = DEZ_OP_AS;
				fe->value_node = node;
				
				return 0;
			}
		}
	}
	
	if (
		dez_op == DEZ_OP_ASSIGN				&&
		content->op2_node != NULL			&&
		content->op2_node->dez_op == DEZ_OP_FETCH_DIM
	)
	{
		DEZ_NODE *fetch = dez_list_get_last_fetch(node);
		
		if (fetch != NULL)
		{
			c = (DEZ_NODE_EXPR *)(fetch->content);
			
			if (
				c->op1_node != NULL &&
				c->op1_node->dez_op == DEZ_OP_LIST				/* list element */
			)
			{
				DEZ_NODE *list = c->op1_node;
				c->op1_node = NULL;
				
				DEZ_ADD_NODE(list);
				
				dez_list_add_le(list, node, -1);				/* add element into list */
				
				return 0;
			}
		}
	}
	
	if (dez_list_is_le(node) == 0)								/* list element */
	{
		int level;
		DEZ_NODE *list, *dest;
		
		dest = dez_list_find_dest(node);
		
		if (dest != NULL)
		{
			fetch_node(dest);
			
			level = dez_list_get_level(NULL, dest);
			list = dez_list_create(level-1);					/* create an empty list */
			dez_list_add_le(list, dest, level);
			
			DEZ_ADD_NODE(list);
		}
		else
		{
			list = find_last_node(DEZ_OP_LIST);
		}
		
		if (list != NULL)
		{
			dez_list_add_le(list, node, -1);
			
			return 0;
		}
	}
	
	DEZ_ADD_NODE(node);

	if (dez_op == DEZ_OP_QM_ASSIGN && (m_opc_num < 2 || ZEND_GET_ORI(pzop)[1].opcode != ZEND_JMP))			/* qm false */
	{
		return 2;					/* exit branch */
	}
	else
	{
		return 0;
	}
}

/*-- convertor for if --*/
static int dez_node_cvt_if (unsigned char dez_op, zend_op *pzop)
{
	DEZ_NODE *parent, *node;
	DEZ_NODE_IF *content;
	
	parent = dez_node_get();
	
	if (dez_op == DEZ_OP_IF && pzop->opcode != ZEND_JMP)
	{
		DEZ_NODE *current_node = m_dez_op_current;
		
		while(current_node != NULL)
		{
			if (
				current_node->dez_op == DEZ_OP_IF &&
				current_node->zop->opcode == ZEND_JMP
			)														/* if (false) */
			{
				current_node = current_node->prev;
				continue;
			}
			else if
			(
				current_node->dez_op == DEZ_OP_FUNCTION ||
				current_node->dez_op == DEZ_OP_CLASS
			)
			{
				current_node = NULL;
			}
			
			break;
		}
		
		node = find_tmp_node(&(pzop->op1));
		
		
		if (
			node != NULL					&&
			node->dez_op == DEZ_OP_SWITCH	&&
			current_node == node			&&
			ZEND_LINENUM(pzop) >= pzop->op2.u.opline_num			/* ZEND_JMPZ: goto afterward */
		)	/* the end of default of switch */
		{
			return 0;
		}
	}

	content = (DEZ_NODE_IF *)malloc(sizeof(DEZ_NODE_IF));
	if (content == NULL)
	{
		return -1;
	}
	
	node = (DEZ_NODE *)malloc(sizeof(DEZ_NODE));
	if (node == NULL)
	{
		free(content);
		return -1;
	}
	
	content->branch_node	= NULL;
	
	if (pzop->opcode == ZEND_JMP)								/* if (false) or else */
	{
		content->op1_node 		= NULL;
		content->op2_node 		= NULL;
		content->dest			= pzop->op1.u.opline_num;
	}
	else
	{
		content->op1_node 		= fetch_tmp_node(&(pzop->op1));
		content->op2_node 		= fetch_tmp_node(&(pzop->op2));
		content->dest			= pzop->op2.u.opline_num;
	}
	
	node->dez_op	= dez_op;
	node->zop		= pzop;
	node->content	= content;
	node->prev		= NULL;
	node->next		= NULL;

	DEZ_ADD_NODE(node);

	if (dez_op == DEZ_OP_IF)
	{
		return 1;					/* enter branch */
	}
	else
	{
		return 0;
	}
}

/*-- convertor for DEZ_OP_QM_ASSIGN --*/
static int dez_node_cvt_qm_assign (unsigned char dez_op, zend_op *pzop)
{
	DEZ_NODE *node;
	DEZ_NODE_EXPR *content;
	
	content = (DEZ_NODE_EXPR *)malloc(sizeof(DEZ_NODE_EXPR));
	if (content == NULL)
	{
		return -1;
	}
	
	node = (DEZ_NODE *)malloc(sizeof(DEZ_NODE));
	if (node == NULL)
	{
		free(content);
		return -1;
	}
	
	content->branch_node	= NULL;
	content->op1_node		= fetch_tmp_node(&(pzop->op1));
	
	if (m_opc_num >= 2 && ZEND_GET_ORI(pzop)[1].opcode == ZEND_JMP)			/* qm true */
	{
		DEZ_NODE *cond;
		
		/*-- fetch qm condition node --*/
//		content->op2_node = fetch_jmp_src_node (ZEND_JMPZ, (ZEND_LINENUM(pzop)+2);
		cond = dez_node_get();
		if (
			cond != NULL &&
			cond->dez_op == DEZ_OP_IF &&
			((DEZ_NODE_IF *)(cond->content))->dest == ZEND_LINENUM(pzop)+2
		)
		{
			content->op2_node = dez_node_pop();					/* fetch the condition node */
		
			m_dez_op_current = content->op2_node->prev;
			content->op2_node->prev = NULL;
		}
		else
		{
			content->op2_node = NULL;
		}
	}
	else														/* qm false */
	{
		/*-- fetch qm true node --*/
		content->op2_node = fetch_tmp_node (&(pzop->result));
	}
		
	node->dez_op	= dez_op;
	node->zop		= pzop;
	node->content	= content;

	DEZ_ADD_NODE(node);

	return 0;
}

/*-- convertor for DEZ_OP_DO --*/
static int dez_node_cvt_do (unsigned char dez_op, zend_op *pzop)
{
	DEZ_NODE *node;
	DEZ_NODE_EXPR *content;
	
	content = (DEZ_NODE_EXPR *)malloc(sizeof(DEZ_NODE_EXPR));
	if (content == NULL)
	{
		return -1;
	}
	
	node = (DEZ_NODE *)malloc(sizeof(DEZ_NODE));
	if (node == NULL)
	{
		free(content);
		return -1;
	}
	
	content->op1_node = fetch_tmp_node(&(pzop->op1));
	content->op2_node = NULL;
	content->branch_node = (DEZ_NODE *)malloc(sizeof(DEZ_NODE));
	
	if (content->branch_node == NULL)
	{
		return -1;
	}
	
	content->branch_node->dez_op	= DEZ_OP_NOP;
	content->branch_node->zop		= NULL;
	content->branch_node->content	= NULL;
	content->branch_node->prev		= NULL;
	content->branch_node->next		= fetch_jmp_dest_node(pzop->op2.u.opline_num);
	if (content->branch_node->next != NULL) content->branch_node->next->prev = content->branch_node;
	
	DEZ_ADD_NODE(node);

	node->dez_op	= dez_op;
	node->zop		= pzop;
	node->content	= content;

	return 0;
}

/*-- convertor for DEZ_OP_FOR --*/
static int dez_node_cvt_for (unsigned char dez_op, zend_op *pzop)
{
	DEZ_NODE *node;
	DEZ_NODE_FOR *content;
	
	content = (DEZ_NODE_FOR *)malloc(sizeof(DEZ_NODE_FOR));
	if (content == NULL)
	{
		return -1;
	}
	
	node = (DEZ_NODE *)malloc(sizeof(DEZ_NODE));
	if (node == NULL)
	{
		free(content);
		return -1;
	}
	
	content->branch_node	= NULL;
	content->cond_node		= fetch_tmp_node(&(pzop->op1));
	
	if (m_dez_op_current->dez_op == DEZ_OP_ASSIGN)
	{
		content->before_node	= fetch_current_node();
	}
	else
	{
		content->before_node	= NULL;
	}
	
	content->after_node		= NULL;
	
	node->dez_op	= dez_op;
	node->zop		= pzop;
	node->content	= content;

	DEZ_ADD_NODE(node);

	return 1;					/* enter branch */
}

/*-- convertor for DEZ_OP_FOREACH --*/
static int dez_node_cvt_foreach (unsigned char dez_op, zend_op *pzop)
{
	DEZ_NODE *node;
	DEZ_NODE_FOREACH *content;
	
	content = (DEZ_NODE_FOREACH *)malloc(sizeof(DEZ_NODE_FOREACH));
	if (content == NULL)
	{
		return -1;
	}
	
	node = (DEZ_NODE *)malloc(sizeof(DEZ_NODE));
	if (node == NULL)
	{
		free(content);
		return -1;
	}
	
	content->branch_node	= NULL;
	
	content->source_node	= fetch_tmp_node(&(pzop->op1));
	content->key_node		= NULL;
	content->value_node		= NULL;
	
	node->dez_op	= dez_op;
	node->zop		= pzop;
	node->content	= content;

	DEZ_ADD_NODE(node);

	return 1;					/* enter branch */
}

/*-- convertor for DEZ_OP_CASE --*/
static int dez_node_cvt_case (unsigned char dez_op, zend_op *pzop)
{
	DEZ_NODE *node, *parent, *branch;
	DEZ_NODE_EXPR *content, *swcontent;
	
	content = (DEZ_NODE_EXPR *)malloc(sizeof(DEZ_NODE_EXPR));
	if (content == NULL)
	{
		return -1;
	}
	
	node = (DEZ_NODE *)malloc(sizeof(DEZ_NODE));
	if (node == NULL)
	{
		free(content);
		return -1;
	}
	
	content->branch_node	= NULL;
	content->op1_node		= fetch_tmp_node(&(pzop->op1));
	content->op2_node		= fetch_tmp_node(&(pzop->op2));
	
	node->dez_op	= dez_op;
	node->zop		= pzop;
	node->content	= content;
	node->prev		= NULL;
	node->next		= NULL;

	parent = find_tmp_node(&(pzop->result));
	
	if (parent == NULL)
	{
		return -1;
	}
	
	if (parent->dez_op == DEZ_OP_BOOL)
	{
		if (
			parent->zop->op1.op_type == IS_CONST			&&
			parent->zop->op1.u.constant.type == IS_BOOL		&&
			parent->zop->op1.u.constant.value.lval == 0
		)
		{
			parent->dez_op	= DEZ_OP_SWITCH;
	
			/* set the condition of switch */
			swcontent = (DEZ_NODE_EXPR *)(parent->content);
			swcontent->op1_node = content->op1_node;
			parent->zop->op1 = pzop->op1;
			content->op1_node = NULL;
			
			branch = (DEZ_NODE *)malloc(sizeof(DEZ_NODE));
			if (branch == NULL)
			{
				return -1;
			}
			
			branch->dez_op		= DEZ_OP_NOP;
			branch->zop			= NULL;
			branch->content		= NULL;
			branch->prev		= NULL;
			branch->next		= NULL;
			
			swcontent->branch_node = branch;
		}
		else
		{
			return -1;
		}
	}
	else if (parent->dez_op == DEZ_OP_SWITCH)
	{
		branch = ((DEZ_NODE_EXPR *)(parent->content))->branch_node;
		
		while(branch->next != NULL) branch = branch->next;
	}
	else
	{
		return -1;
	}
	
	content->op1_node	= parent;							/* pointer to switch node */
	
	branch->next	= node;
	node->prev		= branch;
	
	m_dez_op_current= node;
	
	return 1;										/* enter case branch */
}

/*-- convertor for DEZ_OP_DEFAULT --*/
static int dez_node_cvt_default (unsigned char dez_op, zend_op *pzop)
{
	DEZ_NODE *node, *parent, *branch;
	DEZ_NODE_EXPR *content, *swcontent;
	
	content = (DEZ_NODE_EXPR *)malloc(sizeof(DEZ_NODE_EXPR));
	if (content == NULL)
	{
		return -1;
	}
	
	node = (DEZ_NODE *)malloc(sizeof(DEZ_NODE));
	if (node == NULL)
	{
		free(content);
		return -1;
	}
	
	content->branch_node	= NULL;
	content->op1_node		= NULL;
	content->op2_node		= NULL;
	
	node->dez_op	= dez_op;
	node->zop		= pzop;
	node->content	= content;
	node->prev		= NULL;
	node->next		= NULL;

	while (1)
	{
		DEZ_NODE *tmp;
		
		parent = find_tmp_node(&(ZEND_GET_ORI(pzop)[1].result));
		
		if (parent != NULL)
		{
			break;
		}
		
		tmp = dez_node_get();
		
		if (tmp == NULL)
		{
			free(content);
			free(node);
			
			return 0;
		}
		
		if (
			(tmp->dez_op == DEZ_OP_IF && tmp->zop->opcode == ZEND_JMP)	||		/* if(false) */
			tmp->dez_op == DEZ_OP_CASE									||		/* case */
			dez_get_dest(tmp) >= ZEND_LINENUM(pzop)+2							/* the dest of parent is next node */
		)
		{
			if (ZEND_GET_ORI(pzop) == ZEND_GET_ORI(tmp->zop))					/* is ZEND_JMP of default */
			{
				m_dez_op_current = dez_node_pop();
			}
			else
			{
				dez_exit_branch(0);			//m_dez_op_current = dez_node_pop();
			}
		}
		else
		{
			free(content);
			free(node);
			
			return 0;
		}
	}
	
	if (parent->dez_op == DEZ_OP_BOOL)
	{
		if (
			parent->zop->op1.op_type == IS_CONST			&&
			parent->zop->op1.u.constant.type == IS_BOOL		&&
			parent->zop->op1.u.constant.value.lval == 0
		)
		{
			parent->dez_op	= DEZ_OP_SWITCH;
			
			swcontent = (DEZ_NODE_EXPR *)(parent->content);
			
			branch = (DEZ_NODE *)malloc(sizeof(DEZ_NODE));
			if (branch == NULL)
			{
				return -1;
			}
			
			branch->dez_op		= DEZ_OP_NOP;
			branch->zop			= NULL;
			branch->content		= NULL;
			branch->prev		= NULL;
			branch->next		= NULL;
			
			swcontent->branch_node = branch;
		}
		else
		{
			return -1;
		}
	}
	else if (parent->dez_op == DEZ_OP_SWITCH)
	{
		branch = ((DEZ_NODE_EXPR *)(parent->content))->branch_node;
		
		while(branch->next != NULL) branch = branch->next;
	}
	else
	{
		return -1;
	}
	
	content->op1_node	= parent;							/* pointer to switch node */
	
	branch->next	= node;
	node->prev		= branch;
	
	m_dez_op_current= node;
	
	return 1;												/* enter default branch */
}

/*-- convertor for DEZ_OP_FUNCTION or DEZ_OP_CLASS --*/
static int dez_node_cvt_function_or_class (unsigned char dez_op, zend_op *pzop)
{
	DEZ_NODE *node;
	
	node = m_dez_op_root;
	
	while(node != NULL)
	{
		if (pzop->extended_value == ZEND_DECLARE_FUNCTION)
		{
			if (node->dez_op == DEZ_OP_FUNCTION)
			{
				DEZ_NODE_FUNCTION *content;
				
				content = (DEZ_NODE_FUNCTION *)(node->content);
				
				if (0 == strcmp(content->name, pzop->op2.u.constant.value.str.val))
				{
					fetch_node(node);
					
					DEZ_ADD_NODE(node);
					
					return 0;
				}
			}
		}
		else if
		(
			pzop->extended_value == ZEND_DECLARE_CLASS	||
			pzop->extended_value == ZEND_DECLARE_INHERITED_CLASS
		)		/* declare class */
		{
			if (node->dez_op == DEZ_OP_CLASS)
			{
				DEZ_NODE_CLASS *content;
				
				content = (DEZ_NODE_CLASS *)(node->content);
				
				if (0 == strcmp(content->name, pzop->op2.u.constant.value.str.val))
				{
					fetch_node(node);
					
					DEZ_ADD_NODE(node);
					
					return 0;
				}
			}
		}
		
		node = node->next;
	}
	
	return 0;
}

/*-- convertor for DEZ_OP_DOUBLE_ARROW --*/
static int dez_node_cvt_double_arrow (unsigned char dez_op, zend_op *pzop)
{
	DEZ_NODE *node, *parent;
	DEZ_NODE_DA *content;
	
	content = (DEZ_NODE_DA *)malloc(sizeof(DEZ_NODE_DA));
	if (content == NULL)
	{
		return -1;
	}
	
	node = (DEZ_NODE *)malloc(sizeof(DEZ_NODE));
	if (node == NULL)
	{
		free(content);
		return -1;
	}
	
	parent = fetch_tmp_node(&(pzop->result));
	
	content->branch_node	= NULL;
	content->key_node		= fetch_tmp_node(&(pzop->op2));
	content->value_node		= fetch_tmp_node(&(pzop->op1));
	content->next_node		= parent;
	if (parent != NULL) parent->prev = node;
	
	node->dez_op	= DEZ_OP_ARRAY;
	node->zop		= pzop;
	node->content	= content;
	node->prev		= NULL;
	node->next		= NULL;

	DEZ_ADD_NODE(node);

	return 0;
}

/*-- convertor for DEZ_OP_ARRAY --*/
static int dez_node_cvt_array (unsigned char dez_op, zend_op *pzop)
{
	DEZ_NODE *node;
	DEZ_NODE_DA *content;
	
	content = (DEZ_NODE_DA *)malloc(sizeof(DEZ_NODE_DA));
	if (content == NULL)
	{
		return -1;
	}
	
	node = (DEZ_NODE *)malloc(sizeof(DEZ_NODE));
	if (node == NULL)
	{
		free(content);
		return -1;
	}
	
	content->branch_node	= NULL;
	content->key_node		= fetch_tmp_node(&(pzop->op2));
	content->value_node		= fetch_tmp_node(&(pzop->op1));
	content->next_node		= NULL;
	
	node->dez_op	= dez_op;
	node->zop		= pzop;
	node->content	= content;

	DEZ_ADD_NODE(node);

	return 0;
}

/*-- convertor for DEZ_OP_HEREDOC --*/
static int dez_node_cvt_heredoc (unsigned char dez_op, zend_op *pzop)
{
	/**********/
	return 0;
}

/*-- convertor for DEZ_OP_DOLLAR_OPEN_CURLY_BRACES --*/
static int dez_node_cvt_dollar_open_curly_braces (unsigned char dez_op, zend_op *pzop)
{
	/**********/
	return 0;
}

/*-- convertor for DEZ_OP_CALL --*/
static int dez_node_cvt_call (unsigned char dez_op, zend_op *pzop)
{
	DEZ_NODE *node, *param, *tmp;
	DEZ_NODE_EXPR *content;
	int param_num;
	
	content = (DEZ_NODE_EXPR *)malloc(sizeof(DEZ_NODE_EXPR));
	if (content == NULL)
	{
		return -1;
	}
	
	node = (DEZ_NODE *)malloc(sizeof(DEZ_NODE));
	if (node == NULL)
	{
		free(content);
		return -1;
	}
	
	content->branch_node	= NULL;
	content->op1_node		= fetch_call_ini_node(&(pzop->op1));
	
	param = NULL;
	tmp = m_dez_op_current;
	param_num = pzop->extended_value;
	
	while (tmp != NULL && param_num > 0)
	{
		DEZ_NODE *prev = tmp->prev;
		
		if (tmp->dez_op == DEZ_OP_CALL_PARAM)
		{
			if (tmp == m_dez_op_current)
			{
				m_dez_op_current = prev;
			}
			
			if (tmp->prev != NULL)
			{
				tmp->prev->next = tmp->next;
				tmp->prev = NULL;
			}
			
			if (tmp->next != NULL)
			{
				tmp->next->prev = prev;
				tmp->next = NULL;
			}
			
			tmp->next = param;
			param = tmp;

			param_num--;
		}
		
		tmp = prev;
	}
	
	content->op2_node = param;
	
	node->dez_op	= dez_op;
	node->zop		= pzop;
	node->content	= content;
	node->next		= NULL;

	if (pzop->opcode == ZEND_DO_FCALL_BY_NAME)
	{
		if (m_dez_op_current->dez_op == DEZ_OP_NEW)
		{
			content = (DEZ_NODE_EXPR *)(m_dez_op_current->content);
			
			if (content->op1_node != NULL)
			{
				((DEZ_NODE_EXPR *)(node->content))->op1_node = content->op1_node;
			}
			
			content->op1_node = node;
			
			return 0;
		}
	}
	
	DEZ_ADD_NODE(node);

	return 0;
}

/*-- convertor for DEZ_OP_BOOL --*/
static int dez_node_cvt_bool (unsigned char dez_op, zend_op *pzop)
{
	DEZ_NODE *node, *tmp;
	DEZ_NODE_EXPR *content;
	
	if (
		pzop->op1.op_type == IS_CONST &&
		pzop->op1.u.constant.type == IS_BOOL &&
		pzop->op1.u.constant.value.lval == 1 &&
		ZEND_GET_ORI(pzop)[-1].opcode == ZEND_JMP
	)								/* default of switch */
	{
		return dez_node_cvt_default(DEZ_OP_DEFAULT, ZEND_GET_ORI(pzop)-1);
	}		
	
	content = (DEZ_NODE_EXPR *)malloc(sizeof(DEZ_NODE_EXPR));
	if (content == NULL)
	{
		return -1;
	}
	
	node = (DEZ_NODE *)malloc(sizeof(DEZ_NODE));
	if (node == NULL)
	{
		free(content);
		return -1;
	}
	
	content->branch_node	= NULL;
	content->op1_node		= NULL;
	content->op2_node		= NULL;

	node->dez_op			= dez_op;
	node->zop				= pzop;
	node->content			= content;
	node->prev				= NULL;
	node->next				= NULL;
	
	tmp = fetch_tmp_node(&(pzop->result));
	
	if (tmp == NULL)
	{
		DEZ_ADD_NODE(node);

		return 0;
	}
	
	if (tmp->dez_op == DEZ_OP_LOGICAL_OR || tmp->dez_op == DEZ_OP_LOGICAL_AND)
	{
		content->op1_node	= fetch_tmp_node(&(pzop->op1));	/* 2nd condition */
		
		content->op2_node	= tmp;							/* 1st condition */
		
		node->dez_op		= tmp->dez_op;
		
		DEZ_ADD_NODE(node);

		return 0;
	}
	else
	{
		return -1;
	}
}


static int dez_add_jmp_node(zend_op *pzop)
{
	DEZ_NODE *node;
	DEZ_NODE_EXPR *content;
	
	content = (DEZ_NODE_EXPR *)malloc(sizeof(DEZ_NODE_EXPR));
	if (content == NULL)
	{
		return -1;
	}
	
	node = (DEZ_NODE *)malloc(sizeof(DEZ_NODE));
	if (node == NULL)
	{
		free(content);
		return -1;
	}
	
	content->branch_node	= NULL;
	content->op1_node		= NULL;
	content->op2_node		= NULL;
	
	node->dez_op	= DEZ_OP_JMP;
	node->zop		= pzop;
	node->content	= content;
	node->prev		= NULL;
	node->next		= NULL;
	
	DEZ_ADD_NODE(node);
	
	return 0;
}	

/*-- convertor for DEZ_OP_JMP --*/
static int dez_node_cvt_jmp (unsigned char dez_op, zend_op *pzop)
{
	DEZ_NODE *parent;
	int p_linenum;
	
	parent	= dez_node_get();
	if (parent == NULL)
	{
		p_linenum = -1;
	}
	else
	{
		p_linenum = get_zend_linenum(parent);
	}
	
	if (ZEND_LINENUM(pzop) < (int)(pzop->op1.u.opline_num))			/* goto forward */
	{
		if (m_max_jmp_dest < pzop->op1.u.opline_num)
		{
			m_max_jmp_dest = pzop->op1.u.opline_num;
		}
		
		if (
			parent != NULL						&&
			parent->dez_op == DEZ_OP_CASE
		)
		{
			zend_op *dest;
			
			dest = m_zend_op_start + pzop->op1.u.opline_num;
			
			if (
				(dest[-1].opcode == ZEND_JMPZ || dest[-1].opcode == ZEND_JMPZNZ)	&&
				dest[-2].opcode == ZEND_CASE
			)														/* the dest is 'case' */
			{
				dez_exit_branch(0);									/* exit the case branch */
				return 0;
			}
			else if (
				dest[-1].opcode == ZEND_BOOL	&&
				dest[-2].opcode == ZEND_JMP
			)														/* the dest is 'default' */
			{
				dez_exit_branch(0);									/* exit the case branch */
				return 0;
			}
		}
		
		return dez_node_cvt_if(DEZ_OP_IF, pzop);					/* add if (false) node */
	}
	else															/* goto afterware */
	{
		int header_linenum;
		if (
			parent != NULL && parent->dez_op == DEZ_OP_FOR &&
			((DEZ_NODE_FOR *)(parent->content))->before_node != NULL
		)
		{
			header_linenum = get_zend_linenum(((DEZ_NODE_FOR *)(parent->content))->before_node);
		}
		else
		{
			header_linenum = get_prev_zend_linenum(parent);
		}
		
		if ((int)(pzop->op1.u.opline_num) > p_linenum)				/* within this branch */
		{
			DEZ_NODE *node, *branch;
			DEZ_NODE_IF *content;
			int dest;
			
			if (
				parent != NULL						&&
				parent->dez_op == DEZ_OP_FOR
			)
			{
				DEZ_NODE_FOR *content;
				
				content = (DEZ_NODE_FOR *)(parent->content);
				if (content == NULL)
				{
					return -1;
				}
				
				if (
					content->after_node != NULL &&
					pzop->op1.u.opline_num <= get_zend_linenum(content->after_node)
				)
				{
					return 0;
				}
			}
#if 0
			else if (
				parent != NULL						&&
				parent->dez_op == DEZ_OP_FOREACH
			)
			{
				DEZ_NODE *dest;
				
				if (pzop->op1.u.opline_num == p_linenum+1)
				{
					return 2;										/* exit foreach branch */
				}
			}
#endif
			
			content = (DEZ_NODE_IF *)malloc(sizeof(DEZ_NODE_IF));
			if (content == NULL)
			{
				return -1;
			}
			
			node = (DEZ_NODE *)malloc(sizeof(DEZ_NODE));
			if (node == NULL)
			{
				free(content);
				return -1;
			}
			
			branch = (DEZ_NODE *)malloc(sizeof(DEZ_NODE));
			if (branch == NULL)
			{
				return -1;
			}
			
			branch->dez_op	= DEZ_OP_NOP;
			branch->zop		= NULL;
			branch->content	= NULL;
			branch->prev	= NULL;
			branch->next	= fetch_jmp_dest_node(pzop->op1.u.opline_num);
			if (branch->next != NULL) branch->next->prev = branch;
			
			content->branch_node	= branch;
			content->op1_node		= NULL;
			content->op2_node		= NULL;
			content->dest			= ZEND_LINENUM(pzop);
			
			node->dez_op	= DEZ_OP_WHILE;
			node->zop		= pzop;/*branch->next->zop;*/
			node->content	= content;
			node->prev		= NULL;
			node->next		= NULL;
			
			dest = dez_get_branch_end(parent);

//			dez_node_cvt_if(DEZ_OP_IF, pzop);					/* add if (false) */

			clear_or_recover_zend_op(ZEND_GET_ORI(pzop)+1, dest-ZEND_LINENUM(pzop)-1, 1);		/* recover the remainder opcodes in this branch */

			DEZ_ADD_NODE(node);									/* add while (true) */
	
			return 0;
		}
		else if (
			(int)(pzop->op1.u.opline_num) <= p_linenum &&
			(int)(pzop->op1.u.opline_num) > header_linenum
		)														/* the dest is the header of this branch */
		{
			int dest;
			
			if (parent == NULL)
			{
				return 0;
			}
			
			dest = dez_get_branch_end(parent);
			
			if (parent->dez_op == DEZ_OP_IF)
			{
				DEZ_NODE *pp;
				int n = dest-ZEND_LINENUM(pzop)-1;
				
				if (parent->zop->opcode != ZEND_JMP)			/* not if (false) */
				{
					parent->dez_op = DEZ_OP_WHILE;
				}
				
				if (dez_in_branch(parent, DEZ_OP_CASE) == 0)	/* the while() is in case branch */
				{
					int i;
					zend_op *zp = ZEND_GET_ORI(pzop)+1;
					
					i = 0;
					while(i < n)
					{
						if (
							(
								zp[i].opcode == ZEND_JMP	&&
								zp[i+1].opcode == ZEND_BOOL
							)	||								/* default node */
							(
								zp[i].opcode == ZEND_CASE	&&
								(zp[i+1].opcode == ZEND_JMPZ || zp[i+1].opcode == ZEND_JMPZNZ)
							)									/* case node */
						)
						{
							break;
						}
						
						i++;
					}
					
					if (i < n)									/* the case or default node was found */
					{
						zend_op *dupzop;
						
						dupzop = dez_dup_zend_op(pzop);
						dupzop->op1.u.opline_num = dest;
						
//						dez_node_cvt_jmp(DEZ_OP_JMP, dupzop);	/* add if (false) */
						
						n = i;
					}
				}
				
				clear_or_recover_zend_op(ZEND_GET_ORI(pzop)+1, n, 0);	/* clear the remainder opcodes in this branch */
	
				dez_node_cvt_if(DEZ_OP_IF, pzop);				/* add if (false) */

				dez_exit_branch(0);								/* exit the branch */
				
				return 0;
			}
			else if (parent->dez_op == DEZ_OP_FOR)
			{
				DEZ_NODE_FOR *content;
				
				content = (DEZ_NODE_FOR *)(parent->content);
				if (content == NULL)
				{
					return -1;
				}
				
				if (content->after_node == NULL)
				{
					content->after_node = fetch_jmp_dest_node(pzop->op1.u.opline_num);
				}
				else if (pzop->op1.u.opline_num == get_zend_linenum(content->after_node))
				{
					clear_or_recover_zend_op(ZEND_GET_ORI(pzop)+1, dest-ZEND_LINENUM(pzop)-1, 0);		/* clear the remainder opcodes in this branch */
					
					dez_node_cvt_if(DEZ_OP_IF, pzop);			/* add if (false) */

					dez_exit_branch(0);							/* exit the branch */
					
//					return dez_node_specs[DEZ_OP_CONTINUE].dez_node_cvt_func (DEZ_OP_CONTINUE, pzop);	/* add continue node */
				}
				
				return 0;
			}
			else if (parent->dez_op == DEZ_OP_FOREACH)
			{
				clear_or_recover_zend_op(ZEND_GET_ORI(pzop)+1, dest-ZEND_LINENUM(pzop)-1, 0);			/* clear the remainder opcodes in this branch */
				
				dez_node_cvt_if(DEZ_OP_IF, pzop);				/* add if (false) */

//				return dez_node_specs[DEZ_OP_CONTINUE].dez_node_cvt_func (DEZ_OP_CONTINUE, pzop);		/* add continue node */
			}
			
			return 0;
		}
		else													/* the dest is without this branch */
		{
			int dest;
			zend_op *prev_zop;
			
			dest = dez_get_branch_end(parent);
			clear_or_recover_zend_op(ZEND_GET_ORI(pzop)+1, dest-ZEND_LINENUM(pzop)-1, 0);				/* clear the remainder opcodes in this branch */

			dest = dez_get_dest(parent);						// dez_get_branch_end(parent);
			
			if (
				dest > ZEND_LINENUM(pzop) &&					/* jump foreward away */
				parent != NULL	&&
				parent->dez_op == DEZ_OP_ELSE
			)													/* break? */
			{
				DEZ_NODE_EXPR *c;
				
				dez_exit_branch(0);								/* exit this branch */
				
				/*-- fetch the sub branch and add them into m_dez_op_current --*/
				c = (DEZ_NODE_EXPR *)(parent->content);
				if (c != NULL && c->branch_node != NULL)		/* the sub branch is exist */
				{
					m_dez_op_current->next = c->branch_node->next;
					if (c->branch_node->next != NULL) c->branch_node->next->prev = m_dez_op_current;
					
					free(c->branch_node);
					c->branch_node = NULL;
					
					while(m_dez_op_current->next != NULL) m_dez_op_current = m_dez_op_current->next;
				}
				
				DEZ_DEL_NODE(parent);							/* remove the else node */
				
				return dez_node_cvt_jmp(DEZ_OP_JMP, pzop);
			}
			
			prev_zop = ZEND_GET_ORI(pzop)-1;
			if (
				m_dez_op_current->dez_op == DEZ_OP_WHILE && m_dez_op_current->zop->opcode == ZEND_JMP &&	/* the previous node is while(true) */
				prev_zop->opcode == ZEND_JMP					&&
				(int)(prev_zop->op1.u.opline_num) <= p_linenum 	&&			/* jmp to header */
				(int)(prev_zop->op1.u.opline_num) > header_linenum			/* ------------- */
			)
			{
				/* do nothing */
			}
			else
			{	
				dez_node_cvt_if(DEZ_OP_IF, pzop);				/* add if (false) node */
			}

			dez_exit_branch(1);									/* exit this branch */

			return 0;
		}
	}
	
	return dez_node_cvt_expr (dez_op, pzop);					/* add jmp node */
}

/*-- convertor for DEZ_OP_FUNC_PARAM --*/
static int dez_node_cvt_func_param (unsigned char dez_op, zend_op *pzop)
{
	static char paramname[1024];
	
	DEZ_NODE *node, *parent, *param;
	DEZ_NODE_EXPR *content;
	DEZ_NODE_FUNCTION *funcc;
	
	parent = dez_node_get();
	
	if (parent == NULL)
	{
		return -1;
	}
	
	if (parent->dez_op != DEZ_OP_FUNCTION)
	{
		return -1;
	}
	
	funcc = (DEZ_NODE_FUNCTION *)(parent->content);
	
	if (funcc == NULL)
	{
		return -1;
	}
	
	content = (DEZ_NODE_EXPR *)malloc(sizeof(DEZ_NODE_EXPR));
	if (content == NULL)
	{
		return -1;
	}
	
	node = (DEZ_NODE *)malloc(sizeof(DEZ_NODE));
	if (node == NULL)
	{
		free(content);
		return -1;
	}
	
	content->branch_node	= NULL;
	content->op1_node		= fetch_tmp_node(&(pzop->result));
	
#if 0
	if (content->op1_node == NULL)
	{
		sprintf(paramname, "dez_param_%u", pzop->result.u.var);
		dez_add_var(pzop->result.u.var, paramname, strlen(paramname));
	}
#endif
	
	if (pzop->opcode == ZEND_RECV_INIT)
	{
		content->op2_node = fetch_tmp_node(&(pzop->op2));
	}
	else
	{
		content->op2_node = NULL;
	}

	node->dez_op	= dez_op;
	node->zop		= pzop;
	node->content	= content;
	node->prev		= NULL;
	node->next		= NULL;
	
	param = funcc->param_node;
	
	if (param == NULL)
	{
		funcc->param_node = node;
	}
	else
	{
		while(param->next != NULL)
		{
			param = param->next;
		}
	
		param->next		= node;
		node->prev		= param;
	}
	
	return 0;
}

/*-- convertor for DEZ_OP_UNKNOWN --*/
static int dez_node_cvt_unknown (unsigned char dez_op, zend_op *pzop)
{
	/**********/
	return 0;
}


static int dez_node_output_nop(DEZ_NODE *pdez_node)
{
	/******************/
	return 0;
}

static int dez_node_output_expr(DEZ_NODE *pdez_node)
{
	DEZ_NODE_EXPR *content;

	if (pdez_node == NULL)
	{
		return -1;
	}
	
	content = (DEZ_NODE_EXPR *)(pdez_node->content);
	if (content == NULL)
	{
		return -1;
	}
	
	if (
		pdez_node->dez_op == DEZ_OP_BW_NOT			||		/* ~ */
		pdez_node->dez_op == DEZ_OP_BOOL_NOT				/* ! */
	)
	{
		printf ("%s", dez_node_specs[pdez_node->dez_op].desc);
		
		if (content->op1_node != NULL)
		{
			dez_node_specs[content->op1_node->dez_op].dez_node_output_func (content->op1_node);
		}
		else
		{
			dez_dump_znode(&(pdez_node->zop->op1), 1);
		}
	}
	else if (
		pdez_node->dez_op == DEZ_OP_CONCAT			&&
		pdez_node->zop->opcode == ZEND_ADD_CHAR
	)
	{
		printf ( "(");
		
		if (content->op1_node != NULL)
		{
			dez_node_specs[content->op1_node->dez_op].dez_node_output_func (content->op1_node);
		}
		else
		{
			dez_dump_znode(&(pdez_node->zop->op1), 1);
		}
		
		printf ("%s", dez_node_specs[pdez_node->dez_op].desc);
		
		if (content->op2_node != NULL)
		{
			dez_node_specs[content->op2_node->dez_op].dez_node_output_func (content->op2_node);
		}
		else
		{
			printf ( "'%c'", (char)(pdez_node->zop->op2.u.constant.value.lval));
		}

		printf ( ")");
	}
	else
	{	
		if (
			pdez_node->dez_op != DEZ_OP_OBJECT_OPERATOR
		)
		{
			printf ( "(");
		}
		
		if (content->op1_node != NULL)
		{
			dez_node_specs[content->op1_node->dez_op].dez_node_output_func (content->op1_node);
		}
		else
		{
			dez_dump_znode(&(pdez_node->zop->op1), 1);
		}
		
		printf ("%s", dez_node_specs[pdez_node->dez_op].desc);
		
		if (content->op2_node != NULL)
		{
			dez_node_specs[content->op2_node->dez_op].dez_node_output_func (content->op2_node);
		}
		else
		{
			dez_dump_znode(&(pdez_node->zop->op2), (pdez_node->dez_op == DEZ_OP_OBJECT_OPERATOR ? 0: 1));
		}
		
		if (
			pdez_node->dez_op != DEZ_OP_OBJECT_OPERATOR
		)
		{
			printf ( ")");
		}
	}
	
	return 0;
}

static int dez_node_output_cast(DEZ_NODE *pdez_node)
{
	static char *dez_cast_str[] =
	{
		"(unset)",
		"(int)",
		"(double)",
		"(string)",
		"(array)",
		"(object)",
		"(bool)"
	};
	
	DEZ_NODE_EXPR *content;

	if (pdez_node == NULL)
	{
		return -1;
	}
	
	content = (DEZ_NODE_EXPR *)(pdez_node->content);
	if (content == NULL)
	{
		return -1;
	}
	
	printf ("%s", dez_cast_str[pdez_node->zop->extended_value]);
	
	if (content->op1_node != NULL)
	{
		dez_node_specs[content->op1_node->dez_op].dez_node_output_func (content->op1_node);
	}
	else
	{
		dez_dump_znode(&(pdez_node->zop->op1), 1);
	}
	
	return 0;
}

static int dez_node_output_qm_assign(DEZ_NODE *pdez_node)
{
	DEZ_NODE_EXPR *content;
	DEZ_NODE *qm_true;
	DEZ_NODE_EXPR *content1;
	DEZ_NODE *qm_cond;
	DEZ_NODE_EXPR *content2;

	if (pdez_node == NULL)
	{
		return -1;
	}
	
	content = (DEZ_NODE_EXPR *)(pdez_node->content);
	if (content == NULL)
	{
		return -1;
	}
	
	qm_true = content->op2_node;
	if (qm_true == NULL)
	{
		return -1;
	}
	
	content1 = (DEZ_NODE_EXPR *)(qm_true->content);
	if (content1 == NULL)
	{
		return -1;
	}
	
	printf ( "(");
	
	qm_cond = content1->op2_node;
	if (qm_cond == NULL)
	{
		printf ("true");
	}
	else
	{
		content2 = (DEZ_NODE_EXPR *)(qm_cond->content);
		if (content2 == NULL)
		{
			return -1;
		}
		
		if (qm_cond->zop->opcode == ZEND_JMP)
		{
			printf ("false");
		}
		else if (content2->op1_node != NULL)
		{
			dez_node_specs[content2->op1_node->dez_op].dez_node_output_func (content2->op1_node);
		}
		else
		{
			dez_dump_znode(&(qm_cond->zop->op1), 1);
		}
	}
	
	printf ( " ? ");
	
	if (content1->op1_node != NULL)
	{
		dez_node_specs[content1->op1_node->dez_op].dez_node_output_func (content1->op1_node);
	}
	else
	{
		dez_dump_znode(&(qm_true->zop->op1), 1);
	}
	
	printf ( " : ");
	
	if (content->op1_node != NULL)
	{
		dez_node_specs[content->op1_node->dez_op].dez_node_output_func (content->op1_node);
	}
	else
	{
		dez_dump_znode(&(pdez_node->zop->op1), 1);
	}
	
	printf ( ")");
	
	return 0;
}

static int dez_node_output_pre(DEZ_NODE *pdez_node)
{
	DEZ_NODE_EXPR *content;

	if (pdez_node == NULL)
	{
		return -1;
	}
	
	content = (DEZ_NODE_EXPR *)(pdez_node->content);
	if (content == NULL)
	{
		return -1;
	}
	
	printf ("%s", dez_node_specs[pdez_node->dez_op].desc);
	
	if (content->op1_node != NULL)
	{
		dez_node_specs[content->op1_node->dez_op].dez_node_output_func (content->op1_node);
	}
	else
	{
		dez_dump_znode(&(pdez_node->zop->op1), (pdez_node->dez_op == DEZ_OP_FETCH ? 0 : 1));
	}
	
	return 0;
}

static int dez_node_output_pre2(DEZ_NODE *pdez_node)
{
	DEZ_NODE_IF *content;

	if (pdez_node == NULL)
	{
		return -1;
	}
	
	content = (DEZ_NODE_IF *)(pdez_node->content);
	if (content == NULL)
	{
		return -1;
	}
	
	printf ("%s", dez_node_specs[pdez_node->dez_op].desc);
	
	if (pdez_node->dez_op == DEZ_OP_BREAK)
	{
		if (pdez_node->zop->opcode == ZEND_BRK)
		{
			if (
				pdez_node->zop->op2.op_type == IS_CONST &&
				pdez_node->zop->op2.u.constant.type == IS_LONG &&
				pdez_node->zop->op2.u.constant.value.lval == 1
			)
			{
				/* do nothing */
			}
			else
			{
				printf (" ");
				
				if (content->op2_node != NULL)
				{
					dez_node_specs[content->op2_node->dez_op].dez_node_output_func (content->op2_node);
				}
				else
				{
					dez_dump_znode(&(pdez_node->zop->op2), 1);
				}
			}
		}
		else						/* ZEND_JMP */
		{
			if (content->dest > 1)
			{
				printf (" %u", content->dest);
			}
		}
	}
	
	return 0;
}

static int dez_node_output_post(DEZ_NODE *pdez_node)
{
	DEZ_NODE_EXPR *content;

	if (pdez_node == NULL)
	{
		return -1;
	}
	
	content = (DEZ_NODE_EXPR *)(pdez_node->content);
	if (content == NULL)
	{
		return -1;
	}
	
	if (content->op1_node != NULL)
	{
		dez_node_specs[content->op1_node->dez_op].dez_node_output_func (content->op1_node);
	}
	else
	{
		dez_dump_znode(&(pdez_node->zop->op1), 1);
	}
	
	printf ("%s", dez_node_specs[pdez_node->dez_op].desc);
	
	return 0;
}

static int dez_node_output_assign(DEZ_NODE *pdez_node)
{
	DEZ_NODE_EXPR *content;

	if (pdez_node == NULL)
	{
		return -1;
	}
	
	content = (DEZ_NODE_EXPR *)(pdez_node->content);
	if (content == NULL)
	{
		return -1;
	}
	
	if (content->op1_node != NULL)
	{
		dez_node_specs[content->op1_node->dez_op].dez_node_output_func (content->op1_node);
	}
	else
	{
		dez_dump_znode(&(pdez_node->zop->op1), 1);
	}
	
	printf ("%s", dez_node_specs[pdez_node->dez_op].desc);
	
	if (content->op2_node != NULL)
	{
		dez_node_specs[content->op2_node->dez_op].dez_node_output_func (content->op2_node);
	}
	else
	{
		dez_dump_znode(&(pdez_node->zop->op2), 1);
	}
	
	return 0;
}

static int dez_node_output_assign_ref(DEZ_NODE *pdez_node)
{
	DEZ_NODE_EXPR *content;
	zend_op *zop;
	zval **tmp;
	TSRMLS_FETCH(); 
	if (pdez_node == NULL)
	{
		return -1;
	}
	
	content = (DEZ_NODE_EXPR *)(pdez_node->content);
	if (content == NULL)
	{
		return -1;
	}
	
	if (content->op2_node != NULL)
	{
		zop = content->op2_node->zop;
		
		if (zop->opcode == ZEND_FETCH_W && zop->op2.u.fetch_type == ZEND_FETCH_STATIC)			/* static variable */
		{
			zend_op_array *op_array;
			
			printf ( "static ");
			
			if (content->op1_node != NULL)
			{
				dez_node_specs[content->op1_node->dez_op].dez_node_output_func (content->op1_node);
			}
			else
			{
				dez_dump_znode(&(pdez_node->zop->op1), 1);
			}
			
/*
			dez_add_var (pdez_node->zop->op1.u.var, zop->op1.u.constant.value.str.val, zop->op1.u.constant.value.str.len);
			
			printf ( "static %s", dez_get_varname(&(pdez_node->zop->op1)));
*/

						
			if (m_current_function == NULL)					/* main branch */
			{
				op_array = EG(active_op_array);
			}
			else
			{
				op_array = ((DEZ_NODE_FUNCTION *)(m_current_function->content))->op_array;
			}
			
			tmp = NULL;
			zend_hash_find(op_array->static_variables, zop->op1.u.constant.value.str.val, zop->op1.u.constant.value.str.len+1, (void **)&tmp);
			if (tmp != NULL)		/* init value assigned */
			{
				printf ( " = ");
				dez_dump_zval(**tmp, 1);
			}
			
			return 0;
		}
		else if (zop->opcode == ZEND_FETCH_W && zop->op2.u.fetch_type == ZEND_FETCH_GLOBAL)		/* global variable */
		{
			printf ( "global ");

			if (content->op1_node != NULL)
			{
				dez_node_specs[content->op1_node->dez_op].dez_node_output_func (content->op1_node);
			}
			else
			{
				dez_dump_znode(&(pdez_node->zop->op1), 1);
			}
			
/*
			dez_add_var (pdez_node->zop->op1.u.var, zop->op1.u.constant.value.str.val, zop->op1.u.constant.value.str.len);
			
			printf ( "global %s", dez_get_varname(&(pdez_node->zop->op1)));
*/
			
			return 0;
		}
#if 0
		else if (zop->opcode == ZEND_FETCH_W && zop->op2.u.fetch_type == ZEND_FETCH_LOCAL)		/* local variable */
		{
			dez_add_var (pdez_node->zop->op1.u.var, zop->op1.u.constant.value.str.val, zop->op1.u.constant.value.str.len);
			
			printf ( "%s", dez_get_varname(&(pdez_node->zop->op1)));
			
			return 0;
		}
#endif
	}
	
	/*-- a = &b --*/
	if (content->op1_node != NULL)
	{
		dez_node_specs[content->op1_node->dez_op].dez_node_output_func (content->op1_node);
	}
	else
	{
		dez_dump_znode(&(pdez_node->zop->op1), 1);
	}
	
	printf ("%s", dez_node_specs[pdez_node->dez_op].desc);
	
	if (content->op2_node != NULL)
	{
		dez_node_specs[content->op2_node->dez_op].dez_node_output_func (content->op2_node);
	}
	else
	{
		dez_dump_znode(&(pdez_node->zop->op2), 1);
	}
	
	return 0;
}

static int dez_node_output_include_or_eval(DEZ_NODE *pdez_node)
{
	DEZ_NODE_EXPR *content;
	char *str;

	if (pdez_node == NULL)
	{
		return -1;
	}
	
	content = (DEZ_NODE_EXPR *)(pdez_node->content);
	if (content == NULL)
	{
		return -1;
	}
	
	switch (pdez_node->zop->op2.u.constant.value.lval)
	{
		case ZEND_EVAL:
			str = "eval (";
			break;
		case ZEND_INCLUDE:
			str = "include ";
			break;
		case ZEND_INCLUDE_ONCE:
			str = "include_once ";
			break;
		case ZEND_REQUIRE:
			str = "require ";
			break;
		case ZEND_REQUIRE_ONCE:
			str = "require_once ";
			break;
	}
	
	printf ( str);
	
	if (content->op1_node != NULL)
	{
		dez_node_specs[content->op1_node->dez_op].dez_node_output_func (content->op1_node);
	}
	else
	{
		dez_dump_znode(&(pdez_node->zop->op1), 1);
	}
	
	if (pdez_node->zop->op2.u.constant.value.lval == ZEND_EVAL)
	{
		printf ( ")");
	}
	
	return 0;
}

static int dez_node_output_or_and(DEZ_NODE *pdez_node)
{
	DEZ_NODE_EXPR *content;

	if (pdez_node == NULL)
	{
		return -1;
	}
	
	content = (DEZ_NODE_EXPR *)(pdez_node->content);
	if (content == NULL)
	{
		return -1;
	}

	printf ( "(");
	
	if (content->op2_node != NULL)
	{
		DEZ_NODE_EXPR *cond1 = (DEZ_NODE_EXPR *)(content->op2_node->content);
		
		if (cond1->op1_node != NULL)
		{
			dez_node_specs[cond1->op1_node->dez_op].dez_node_output_func (cond1->op1_node);
		}
		else
		{
			dez_dump_znode(&(content->op2_node->zop->op1), 1);
		}
	}
	
	printf ("%s", dez_node_specs[pdez_node->dez_op].desc);
	
	if (content->op1_node != NULL)
	{
		dez_node_specs[content->op1_node->dez_op].dez_node_output_func (content->op1_node);
	}
	else
	{
		dez_dump_znode(&(pdez_node->zop->op1), 1);
	}
	
	printf ( ")");
	
	return 0;
}

static int dez_node_output_new(DEZ_NODE *pdez_node)
{
	DEZ_NODE_EXPR *content;

	if (pdez_node == NULL)
	{
		return -1;
	}
	
	content = (DEZ_NODE_EXPR *)(pdez_node->content);
	if (content == NULL)
	{
		return -1;
	}
	
	printf ("%s", dez_node_specs[pdez_node->dez_op].desc);
	
	if (content->op1_node != NULL)
	{
		dez_node_specs[content->op1_node->dez_op].dez_node_output_func (content->op1_node);
	}
	else
	{
		dez_dump_znode(&(pdez_node->zop->op1), 1);
		
/*
		switch(pdez_node->zop->op1.op_type)
		{
			case IS_CONST:
				printf ("%s", pdez_node->zop->op1.u.constant.value.str.val);
				break;
			case 16:
				printf ("%s", dez_get_varname(&(pdez_node->zop->op1)));
				break;
		}
*/
	}
	
	return 0;
}

static int dez_node_output_exit(DEZ_NODE *pdez_node)
{
	DEZ_NODE_EXPR *content;

	if (pdez_node == NULL)
	{
		return -1;
	}
	
	content = (DEZ_NODE_EXPR *)(pdez_node->content);
	if (content == NULL)
	{
		return -1;
	}
	
	printf ( "exit (");
	
	if (content->op1_node != NULL)
	{
		dez_node_specs[content->op1_node->dez_op].dez_node_output_func (content->op1_node);
	}
	else
	{
		dez_dump_znode(&(pdez_node->zop->op1), 1);
	}
	
	printf ( ")");
	
	return 0;
}

static int dez_node_output_if(DEZ_NODE *pdez_node)
{
	DEZ_NODE_EXPR *content;

	if (pdez_node == NULL)
	{
		return -1;
	}
	
	content = (DEZ_NODE_EXPR *)(pdez_node->content);
	if (content == NULL)
	{
		return -1;
	}
	
	printf ("%s", dez_node_specs[pdez_node->dez_op].desc);
	
	printf ( "(");
	
	if (pdez_node->zop->opcode == ZEND_JMP)
	{
		printf ( (pdez_node->dez_op == DEZ_OP_WHILE ? "true" : "false"));
	}
	else
	{
		if (content->op1_node != NULL)
		{
			dez_node_specs[content->op1_node->dez_op].dez_node_output_func (content->op1_node);
		}
		else
		{
			dez_dump_znode(&(pdez_node->zop->op1), 1);
		}
	}
	
	printf ( ")");
	
	return 0;
}

static int dez_node_output_do(DEZ_NODE *pdez_node)
{
	printf ("%s", dez_node_specs[pdez_node->dez_op].desc);
	
	return 0;
}

static int dez_node_output_for(DEZ_NODE *pdez_node)
{
	DEZ_NODE *node;
	DEZ_NODE_FOR *content;

	if (pdez_node == NULL)
	{
		return -1;
	}
	
	content = (DEZ_NODE_FOR *)(pdez_node->content);
	if (content == NULL)
	{
		return -1;
	}
	
	printf ("%s", dez_node_specs[pdez_node->dez_op].desc);
	
	printf ( "(");
	
	if (content->before_node != NULL)
	{
		dez_node_specs[content->before_node->dez_op].dez_node_output_func (content->before_node);
	}
	
	printf ( "; ");
	
	if (content->cond_node != NULL)
	{
		dez_node_specs[content->cond_node->dez_op].dez_node_output_func (content->cond_node);
	}
	else
	{
		dez_dump_znode(&(pdez_node->zop->op1), 1);
	}
	
	printf ( "; ");
	
	node = content->after_node;
	while (node != NULL)
	{
		dez_node_specs[node->dez_op].dez_node_output_func (node);
		
		node = node->next;
		
		if (node != NULL)
		{
			printf ( ", ");
		}
	}
	
	printf ( ")");
	
	return 0;
}

static int dez_node_output_foreach(DEZ_NODE *pdez_node)
{
	DEZ_NODE *node;
	DEZ_NODE_FOREACH *content;

	if (pdez_node == NULL)
	{
		return -1;
	}
	
	content = (DEZ_NODE_FOREACH *)(pdez_node->content);
	if (content == NULL)
	{
		return -1;
	}
	
	printf ("%s", dez_node_specs[pdez_node->dez_op].desc);
	
	printf ( "(");
	
	if (content->source_node != NULL)
	{
		dez_node_specs[content->source_node->dez_op].dez_node_output_func (content->source_node);
	}
	else
	{
		dez_dump_znode(&(pdez_node->zop->op1), 1);
	}
	
	printf ( " as ");
	
	if (content->key_node != NULL)
	{
		dez_node_specs[content->key_node->dez_op].dez_node_output_func (content->key_node);
		printf ("%s", dez_node_specs[DEZ_OP_DOUBLE_ARROW].desc);
	}
	
	if (content->value_node != NULL)
	{
		dez_node_specs[content->value_node->dez_op].dez_node_output_func (content->value_node);
	}
	
	printf ( ")");
	
	return 0;
}

static int dez_node_output_declare(DEZ_NODE *pdez_node)
{
	DEZ_NODE_EXPR *content;

	if (pdez_node == NULL)
	{
		return -1;
	}
	
	content = (DEZ_NODE_EXPR *)(pdez_node->content);
	if (content == NULL)
	{
		return -1;
	}
	
	printf ("%s", dez_node_specs[pdez_node->dez_op].desc);
	
	printf ( "(");
	
	if (pdez_node->zop->opcode == ZEND_TICKS)
	{
		printf ( "ticks = ");
		dez_dump_znode(&(pdez_node->zop->op1), 1);
	}
	
	printf ( ")");
	
	return 0;
}

static int dez_node_output_case(DEZ_NODE *pdez_node)
{
	DEZ_NODE_EXPR *content;

	if (pdez_node == NULL)
	{
		return -1;
	}
	
	content = (DEZ_NODE_EXPR *)(pdez_node->content);
	if (content == NULL)
	{
		return -1;
	}
	
	printf ("%s", dez_node_specs[pdez_node->dez_op].desc);
	
	if (content->op2_node != NULL)
	{
		dez_node_specs[content->op2_node->dez_op].dez_node_output_func (content->op2_node);
	}
	else
	{
		dez_dump_znode(&(pdez_node->zop->op2), 1);
	}
	
	printf ( ":");
	
	return 0;
}

static int dez_node_output_default(DEZ_NODE *pdez_node)
{
	printf ("%s", dez_node_specs[pdez_node->dez_op].desc);
	
	return 0;
}

static int dez_node_output_function(DEZ_NODE *pdez_node)
{
	DEZ_NODE *node;
	DEZ_NODE_FUNCTION *content;

	if (pdez_node == NULL)
	{
		return -1;
	}
	
	content = (DEZ_NODE_FUNCTION *)(pdez_node->content);
	if (content == NULL)
	{
		return -1;
	}
	
	printf ("%s", dez_node_specs[pdez_node->dez_op].desc);
	
	printf ("%s", content->name);
	
	printf ( " (");
	
	for (node = content->param_node; node != NULL; node = node->next)
	{
		if (
			content->op_array != NULL &&
			content->op_array->arg_types != NULL &&
			content->op_array->arg_types[node->zop->op1.u.constant.value.lval] == BYREF_FORCE
		)
		{
			printf ("&");
		}

		dez_node_specs[node->dez_op].dez_node_output_func (node);
		
		if (node->next != NULL)
		{
			printf ( ", ");
		}
	}
	
	printf ( ")");
	
	return 0;
}

static int dez_node_output_var(DEZ_NODE *pdez_node)
{
	DEZ_NODE_VAR *content;

	if (pdez_node == NULL)
	{
		return -1;
	}
	
	content = (DEZ_NODE_VAR *)(pdez_node->content);
	if (content == NULL)
	{
		return -1;
	}
	
	printf ("%s", dez_node_specs[pdez_node->dez_op].desc);
	
	if (content->property != NULL)
	{
		printf ("$%s", content->property->arKey);
		
		if (content->property->pData != NULL)
		{
			printf ( " = ");
			
			dez_dump_zval(**((zval **)(content->property->pData)), 1);
		}
	}
	
	return 0;
}

static int dez_node_output_unset(DEZ_NODE *pdez_node)
{
	DEZ_NODE_EXPR *content;

	if (pdez_node == NULL)
	{
		return -1;
	}
	
	content = (DEZ_NODE_EXPR *)(pdez_node->content);
	if (content == NULL)
	{
		return -1;
	}
	
	printf ("%s", dez_node_specs[pdez_node->dez_op].desc);
	
	printf ( "($");
	
	if (content->op1_node != NULL)
	{
		dez_node_specs[content->op1_node->dez_op].dez_node_output_func (content->op1_node);
	}
	else
	{
		dez_dump_znode(&(pdez_node->zop->op1), 0);
	}
	
	printf ( ")");
	
	return 0;
}

static int dez_node_output_isset_or_empty(DEZ_NODE *pdez_node)
{
	DEZ_NODE_EXPR *content;

	if (pdez_node == NULL)
	{
		return -1;
	}
	
	content = (DEZ_NODE_EXPR *)(pdez_node->content);
	if (content == NULL)
	{
		return -1;
	}
	
	if (pdez_node->zop->op2.u.constant.value.lval == 1)
	{
		printf ("%s", dez_node_specs[DEZ_OP_ISSET].desc);
	}
	else
	{
		printf ("%s", dez_node_specs[DEZ_OP_EMPTY].desc);
	}
	
	printf ( "(");
	
	if (content->op1_node != NULL)
	{
		dez_node_specs[content->op1_node->dez_op].dez_node_output_func (content->op1_node);
	}
	else
	{
		dez_dump_znode(&(pdez_node->zop->op1), 1);
	}
	
	printf ( ")");
	
	return 0;
}

static int dez_node_output_class(DEZ_NODE *pdez_node)
{
	DEZ_NODE *node;
	DEZ_NODE_CLASS *content;

	if (pdez_node == NULL)
	{
		return -1;
	}
	
	content = (DEZ_NODE_CLASS *)(pdez_node->content);
	if (content == NULL)
	{
		return -1;
	}
	
	printf ("%s", dez_node_specs[pdez_node->dez_op].desc);
	
	printf ("%s", content->name);
	
	if (content->parent != NULL)
	{
		printf ( " extends %s", content->parent->name);
	}
	
	return 0;
}

static int dez_node_output_double_arrow(DEZ_NODE *pdez_node)
{
	DEZ_NODE *node;
	DEZ_NODE_DA *content;

	if (pdez_node == NULL)
	{
		return -1;
	}
	
	content = (DEZ_NODE_DA *)(pdez_node->content);
	if (content == NULL)
	{
		return -1;
	}
	
	if (content->next_node != NULL)					/* is not the first element */
	{
		dez_node_output_double_arrow(content->next_node);
		printf ( ", ");
	}
	
	if (pdez_node->zop->op2.op_type != IS_UNUSED)
	{
		if (content->key_node != NULL)
		{
			dez_node_specs[content->key_node->dez_op].dez_node_output_func (content->key_node);
		}
		else
		{
			dez_dump_znode(&(pdez_node->zop->op2), 1);
		}
		
		printf ("%s", dez_node_specs[DEZ_OP_DOUBLE_ARROW].desc);
	}
	
	if (content->value_node != NULL)
	{
		if (content->value_node->zop->opcode == ZEND_FETCH_W)			/* refrence variable */
		{
			printf ( "&");
		}
		
		dez_node_specs[content->value_node->dez_op].dez_node_output_func (content->value_node);
	}
	else
	{
		dez_dump_znode(&(pdez_node->zop->op1), 1);
	}
	
	return 0;
}

static int dez_node_output_list(DEZ_NODE *pdez_node)
{
	DEZ_NODE_LIST *lc;
	DEZ_NODE *le;

	if (pdez_node == NULL)
	{
		return -1;
	}
	
	lc = (DEZ_NODE_LIST *)(pdez_node->content);
	if (lc == NULL)
	{
		return -1;
	}
	
	printf ("%s", dez_node_specs[pdez_node->dez_op].desc);
	printf ( "(");
	
	le = lc->le_node;
	while (le != NULL)
	{
		dez_node_specs[le->dez_op].dez_node_output_func (le);
		
		le = le->next;
		
		if (le != NULL)
		{
			printf ( ", ");
		}
	}
	
	printf ( ")");
	
	if (lc->dest_node != NULL)
	{
		DEZ_NODE *last_fetch, *next;
		DEZ_NODE_EXPR *dc = (DEZ_NODE_EXPR *)(lc->dest_node->content);
		
		last_fetch = lc->dest_node;
		while (last_fetch != NULL)
		{
			next = ((DEZ_NODE_EXPR *)(last_fetch->content))->op1_node;
			if (
				next == NULL ||
				next->dez_op != DEZ_OP_FETCH_DIM
			)
			{
				break;
			}
			
			last_fetch = next;
		}
		
		if (
			last_fetch != NULL &&
			(
				((DEZ_NODE_EXPR *)(last_fetch->content))->op1_node != NULL ||
				(last_fetch->zop->op1.op_type != IS_TMP_VAR && last_fetch->zop->op1.op_type != IS_VAR)
			)
		)
		{
			printf ("%s", dez_node_specs[DEZ_OP_ASSIGN].desc);
			
			if (dc->op1_node != NULL)
			{
				dez_node_specs[dc->op1_node->dez_op].dez_node_output_func (dc->op1_node);
			}
			else
			{
				dez_dump_znode(&(lc->dest_node->zop->op1), 1);
			}
		}
	}

	return 0;
}

static int dez_node_output_le(DEZ_NODE *pdez_node)
{
	DEZ_NODE_LE *lec;

	if (pdez_node == NULL)
	{
		return -1;
	}
	
	lec = (DEZ_NODE_LE *)(pdez_node->content);
	if (lec == NULL)
	{
		return -1;
	}
	
	if (lec->a_node != NULL)
	{
		if (lec->a_node->dez_op == DEZ_OP_LIST)
		{
			dez_node_specs[lec->a_node->dez_op].dez_node_output_func (lec->a_node);
		}
		else if (lec->a_node->dez_op == DEZ_OP_ASSIGN)
		{
			DEZ_NODE_EXPR *ac = (DEZ_NODE_EXPR *)(lec->a_node->content);
			
			if (ac->op1_node != NULL)
			{
				dez_node_specs[ac->op1_node->dez_op].dez_node_output_func (ac->op1_node);
			}
			else
			{
				dez_dump_znode(&(lec->a_node->zop->op1), 1);
			}
		}
	}
	
	return 0;
}

static int dez_node_output_array(DEZ_NODE *pdez_node)
{
	DEZ_NODE_DA *content;

	if (pdez_node == NULL)
	{
		return -1;
	}
	
	content = (DEZ_NODE_DA *)(pdez_node->content);
	if (content == NULL)
	{
		return -1;
	}
	
	printf ("%s", dez_node_specs[pdez_node->dez_op].desc);
	
	printf ( "(");
	
	pdez_node->dez_op = DEZ_OP_DOUBLE_ARROW;
	dez_node_output_double_arrow(pdez_node);
	pdez_node->dez_op = DEZ_OP_ARRAY;
	
	printf ( ")");
	
	return 0;
}

static int dez_node_output_heredoc(DEZ_NODE *pdez_node)
{
	/******************/
	return 0;
}

static int dez_node_output_dollar_open_curly_braces(DEZ_NODE *pdez_node)
{
	/******************/
	return 0;
}

static int dez_node_output_call_param(DEZ_NODE *pdez_node)
{
	DEZ_NODE_EXPR *content;

	if (pdez_node == NULL)
	{
		return -1;
	}
	
	content = (DEZ_NODE_EXPR *)(pdez_node->content);
	if (content == NULL)
	{
		return -1;
	}
	
	if (pdez_node->zop->opcode == ZEND_SEND_REF)
	{
		printf ( "&");
	}
	
	if (content->op1_node != NULL)
	{
		dez_node_specs[content->op1_node->dez_op].dez_node_output_func (content->op1_node);
	}
	else
	{
		dez_dump_znode(&(pdez_node->zop->op1), 1);
	}
	
	return 0;
}

static int dez_node_output_call_init(DEZ_NODE *pdez_node)
{
	DEZ_NODE_EXPR *content;

	if (pdez_node == NULL)
	{
		return -1;
	}
	
	content = (DEZ_NODE_EXPR *)(pdez_node->content);
	if (content == NULL)
	{
		return -1;
	}
	
	if (pdez_node->zop->op1.op_type != IS_UNUSED)
	{
		if (content->op1_node != NULL)
		{
			dez_node_specs[content->op1_node->dez_op].dez_node_output_func (content->op1_node);
			
			printf ( "->");
		}
		else
		{
			dez_dump_znode(&(pdez_node->zop->op1), 0);
			
			if (
				pdez_node->zop->op1.op_type == IS_CONST		&&
				pdez_node->zop->op1.u.constant.type == IS_STRING
			)									/* class method calling */
			{
				printf ( "::");
			}
			else
			{
				printf ( "->");
			}
		}
		
	}
	
	if (content->op2_node != NULL)
	{
		dez_node_specs[content->op2_node->dez_op].dez_node_output_func (content->op2_node);
	}
	else
	{
		dez_dump_znode(&(pdez_node->zop->op2), 0);
	}
	
	return 0;
}

static int dez_node_output_call(DEZ_NODE *pdez_node)
{
	DEZ_NODE_EXPR *content;
	DEZ_NODE *param;

	if (pdez_node == NULL)
	{
		return -1;
	}
	
	content = (DEZ_NODE_EXPR *)(pdez_node->content);
	if (content == NULL)
	{
		return -1;
	}
	
	if (content->op1_node != NULL)
	{
		dez_node_specs[content->op1_node->dez_op].dez_node_output_func (content->op1_node);
	}
	else
	{
		dez_dump_znode(&(pdez_node->zop->op1), 0);
	}
	
	printf ( " (");
	
	for (param = content->op2_node; param != NULL; param = param->next)
	{
		dez_node_specs[param->dez_op].dez_node_output_func (param);
		
		if (param->next != NULL)
		{
			printf ( ", ");
		}
	}
	
	printf ( ")");
	
	return 0;
}

static int dez_node_output_call_ex(DEZ_NODE *pdez_node)
{
	DEZ_NODE_EXPR *content;
	DEZ_NODE *param;

	if (pdez_node == NULL)
	{
		return -1;
	}
	
	content = (DEZ_NODE_EXPR *)(pdez_node->content);
	if (content == NULL)
	{
		return -1;
	}
	
	printf ("%s", dez_get_funcname(&(pdez_node->zop->op1)));
	
	printf ( " (");
	
	for (param = content->op2_node; param != NULL; param = param->next)
	{
		dez_node_specs[param->dez_op].dez_node_output_func (param);
		
		if (param->next != NULL)
		{
			printf ( ", ");
		}
	}
	
	printf ( ")");
	
	return 0;
}

static int dez_node_output_fetch_dim(DEZ_NODE *pdez_node)
{
	DEZ_NODE_EXPR *content;

	if (pdez_node == NULL)
	{
		return -1;
	}
	
	content = (DEZ_NODE_EXPR *)(pdez_node->content);
	if (content == NULL)
	{
		return -1;
	}
	
	if (content->op1_node != NULL)
	{
		dez_node_specs[content->op1_node->dez_op].dez_node_output_func (content->op1_node);
	}
	else
	{
		dez_dump_znode(&(pdez_node->zop->op1), 1);
	}
	
	printf ( "[");
	
	if (content->op2_node != NULL)
	{
		dez_node_specs[content->op2_node->dez_op].dez_node_output_func (content->op2_node);
	}
	else
	{
		dez_dump_znode(&(pdez_node->zop->op2), 1);
	}
	
	printf ( "]");
	
	return 0;
}

static int dez_node_output_init_string(DEZ_NODE *pdez_node)
{
	printf ("%s", dez_node_specs[pdez_node->dez_op].desc);
	
	return 0;
}

static int dez_node_output_fetch_constant(DEZ_NODE *pdez_node)
{
	dez_dump_znode(&(pdez_node->zop->op1), 0);
	
	return 0;
}

static int dez_node_output_func_param(DEZ_NODE *pdez_node)
{
	DEZ_NODE_EXPR *content;

	if (pdez_node == NULL)
	{
		return -1;
	}
	
	content = (DEZ_NODE_EXPR *)(pdez_node->content);
	if (content == NULL)
	{
		return -1;
	}
	
	printf ("%s", dez_node_specs[pdez_node->dez_op].desc);
	
	if (content->op1_node != NULL)
	{
		dez_node_specs[content->op1_node->dez_op].dez_node_output_func (content->op1_node);
	}
	else
	{
		dez_dump_znode(&(pdez_node->zop->result), 1);
	}
	
	if (pdez_node->zop->opcode == ZEND_RECV_INIT)
	{
		printf ( " = ");
		
		if (content->op2_node != NULL)
		{
			dez_node_specs[content->op2_node->dez_op].dez_node_output_func (content->op2_node);
		}
		else
		{
			dez_dump_znode(&(pdez_node->zop->op2), 1);
		}
	}
		
	return 0;
}


static int dez_node_output_unknown(DEZ_NODE *pdez_node)
{
	/******************/
	return 0;
}


/*-- free all dez nodes --*/
static void dez_node_free (void)
{
	if (m_dez_op_root != NULL)
	{
		dez_node_specs[m_dez_op_root->dez_op].dez_node_free_func(m_dez_op_root);
		
		m_dez_op_root = NULL;
	}
}


/*-- free function for DEZ_NODE_NOP node --*/
static void dez_node_free_nop (DEZ_NODE *pdez_node)
{
	if (pdez_node == NULL)
	{
		return;
	}
	
	/*-- free the next node --*/
	if (pdez_node->next != NULL)
	{
		dez_node_specs[pdez_node->next->dez_op].dez_node_free_func(pdez_node->next);
	}
	
	/*-- free the node content --*/
	if (pdez_node->content != NULL)
	{
		/**********/
		
		free(pdez_node->content);
	}
	
	/*-- free the node self */
	free(pdez_node);
}

static void dez_node_free_expr (DEZ_NODE *pdez_node)
{
	DEZ_NODE_EXPR *content;

	if (pdez_node == NULL)
	{
		return;
	}
	
	/*-- free the next node --*/
	if (pdez_node->next != NULL)
	{
		dez_node_specs[pdez_node->next->dez_op].dez_node_free_func(pdez_node->next);
	}
	
	/*-- free the node content --*/
	content = (DEZ_NODE_EXPR *)(pdez_node->content);
	if (content != NULL)
	{
		if (content->branch_node) dez_node_specs[content->branch_node->dez_op].dez_node_free_func(content->branch_node);
		if (content->op1_node) dez_node_specs[content->op1_node->dez_op].dez_node_free_func(content->op1_node);
		if (content->op2_node) dez_node_specs[content->op2_node->dez_op].dez_node_free_func(content->op2_node);
		
		free(content);
	}
	
	/*-- free the node self */
	free(pdez_node);
}

static void dez_node_free_if (DEZ_NODE *pdez_node)
{
	DEZ_NODE_IF *content;

	if (pdez_node == NULL)
	{
		return;
	}
	
	/*-- free the next node --*/
	if (pdez_node->next != NULL)
	{
		dez_node_specs[pdez_node->next->dez_op].dez_node_free_func(pdez_node->next);
	}
	
	/*-- free the node content --*/
	content = (DEZ_NODE_IF *)(pdez_node->content);
	if (content != NULL)
	{
		if (content->branch_node) dez_node_specs[content->branch_node->dez_op].dez_node_free_func(content->branch_node);
		if (content->op1_node) dez_node_specs[content->op1_node->dez_op].dez_node_free_func(content->op1_node);
		if (content->op2_node) dez_node_specs[content->op2_node->dez_op].dez_node_free_func(content->op2_node);
		
		free(content);
	}
	
	/*-- free the node self */
	free(pdez_node);
}

static void dez_node_free_for (DEZ_NODE *pdez_node)
{
	DEZ_NODE_FOR *content;

	if (pdez_node == NULL)
	{
		return;
	}
	
	/*-- free the next node --*/
	if (pdez_node->next != NULL)
	{
		dez_node_specs[pdez_node->next->dez_op].dez_node_free_func(pdez_node->next);
	}
	
	/*-- free the node content --*/
	content = (DEZ_NODE_FOR *)(pdez_node->content);
	if (content != NULL)
	{
		if (content->branch_node) dez_node_specs[content->branch_node->dez_op].dez_node_free_func(content->branch_node);
		if (content->before_node) dez_node_specs[content->before_node->dez_op].dez_node_free_func(content->before_node);
		if (content->cond_node) dez_node_specs[content->cond_node->dez_op].dez_node_free_func(content->cond_node);
		if (content->after_node) dez_node_specs[content->after_node->dez_op].dez_node_free_func(content->after_node);
		
		free(content);
	}
	
	/*-- free the node self */
	free(pdez_node);
}

static void dez_node_free_foreach (DEZ_NODE *pdez_node)
{
	DEZ_NODE_FOREACH *content;

	if (pdez_node == NULL)
	{
		return;
	}
	
	/*-- free the next node --*/
	if (pdez_node->next != NULL)
	{
		dez_node_specs[pdez_node->next->dez_op].dez_node_free_func(pdez_node->next);
	}
	
	/*-- free the node content --*/
	content = (DEZ_NODE_FOREACH *)(pdez_node->content);
	if (content != NULL)
	{
		if (content->branch_node) dez_node_specs[content->branch_node->dez_op].dez_node_free_func(content->branch_node);
		if (content->source_node) dez_node_specs[content->source_node->dez_op].dez_node_free_func(content->source_node);
		if (content->key_node) dez_node_specs[content->key_node->dez_op].dez_node_free_func(content->key_node);
		if (content->value_node) dez_node_specs[content->value_node->dez_op].dez_node_free_func(content->value_node);
		
		free(content);
	}
	
	/*-- free the node self */
	free(pdez_node);
}

static void dez_node_free_case (DEZ_NODE *pdez_node)
{
	DEZ_NODE_EXPR *content;

	if (pdez_node == NULL)
	{
		return;
	}
	
	/*-- free the next node --*/
	if (pdez_node->next != NULL)
	{
		dez_node_specs[pdez_node->next->dez_op].dez_node_free_func(pdez_node->next);
	}
	
	/*-- free the node content --*/
	content = (DEZ_NODE_EXPR *)(pdez_node->content);
	if (content != NULL)
	{
		if (content->branch_node) dez_node_specs[content->branch_node->dez_op].dez_node_free_func(content->branch_node);
		if (content->op2_node) dez_node_specs[content->op2_node->dez_op].dez_node_free_func(content->op2_node);
		
		free(content);
	}
	
	/*-- free the node self */
	free(pdez_node);
}

static void dez_node_free_default (DEZ_NODE *pdez_node)
{
	DEZ_NODE_EXPR *content;

	if (pdez_node == NULL)
	{
		return;
	}
	
	/*-- free the next node --*/
	if (pdez_node->next != NULL)
	{
		dez_node_specs[pdez_node->next->dez_op].dez_node_free_func(pdez_node->next);
	}
	
	/*-- free the node content --*/
	content = (DEZ_NODE_EXPR *)(pdez_node->content);
	if (content != NULL)
	{
		if (content->branch_node) dez_node_specs[content->branch_node->dez_op].dez_node_free_func(content->branch_node);
		
		free(content);
	}
	
	/*-- free the node self */
	free(pdez_node);
}

static void dez_node_free_function (DEZ_NODE *pdez_node)
{
	DEZ_NODE_FUNCTION *content;

	if (pdez_node == NULL)
	{
		return;
	}
	
	/*-- free the next node --*/
	if (pdez_node->next != NULL)
	{
		dez_node_specs[pdez_node->next->dez_op].dez_node_free_func(pdez_node->next);
	}
	
	/*-- free the node content --*/
	content = (DEZ_NODE_FUNCTION *)(pdez_node->content);
	if (content != NULL)
	{
		if (content->branch_node) dez_node_specs[content->branch_node->dez_op].dez_node_free_func(content->branch_node);
		if (content->param_node) dez_node_specs[content->param_node->dez_op].dez_node_free_func(content->param_node);
		
		free(content);
	}
	
	/*-- free the node self */
	free(pdez_node);
}

static void dez_node_free_var (DEZ_NODE *pdez_node)
{
	DEZ_NODE_VAR *content;

	if (pdez_node == NULL)
	{
		return;
	}
	
	/*-- free the next node --*/
	if (pdez_node->next != NULL)
	{
		dez_node_specs[pdez_node->next->dez_op].dez_node_free_func(pdez_node->next);
	}
	
	/*-- free the node content --*/
	content = (DEZ_NODE_VAR *)(pdez_node->content);
	if (content != NULL)
	{
		if (content->branch_node) dez_node_specs[content->branch_node->dez_op].dez_node_free_func(content->branch_node);
		
		free(content);
	}
	
	/*-- free the node self */
	free(pdez_node);
}

static void dez_node_free_class (DEZ_NODE *pdez_node)
{
	DEZ_NODE_CLASS *content;

	if (pdez_node == NULL)
	{
		return;
	}
	
	/*-- free the next node --*/
	if (pdez_node->next != NULL)
	{
		dez_node_specs[pdez_node->next->dez_op].dez_node_free_func(pdez_node->next);
	}
	
	/*-- free the node content --*/
	content = (DEZ_NODE_CLASS *)(pdez_node->content);
	if (content != NULL)
	{
		if (content->branch_node) dez_node_specs[content->branch_node->dez_op].dez_node_free_func(content->branch_node);
		
		free(content);
	}
	
	/*-- free the node self */
	free(pdez_node);
}

static void dez_node_free_da (DEZ_NODE *pdez_node)
{
	DEZ_NODE_DA *content;

	if (pdez_node == NULL)
	{
		return;
	}
	
	/*-- free the next node --*/
	if (pdez_node->next != NULL)
	{
		dez_node_specs[pdez_node->next->dez_op].dez_node_free_func(pdez_node->next);
	}
	
	/*-- free the node content --*/
	content = (DEZ_NODE_DA *)(pdez_node->content);
	if (content != NULL)
	{
		if (content->branch_node) dez_node_specs[content->branch_node->dez_op].dez_node_free_func(content->branch_node);
		if (content->key_node) dez_node_specs[content->key_node->dez_op].dez_node_free_func(content->key_node);
		if (content->value_node) dez_node_specs[content->value_node->dez_op].dez_node_free_func(content->value_node);
		if (content->next_node) dez_node_specs[content->next_node->dez_op].dez_node_free_func(content->next_node);
		
		free(content);
	}
	
	/*-- free the node self */
	free(pdez_node);
}

static void dez_node_free_array (DEZ_NODE *pdez_node)
{
	if (pdez_node == NULL)
	{
		return;
	}
	
	/*-- free the next node --*/
	if (pdez_node->next != NULL)
	{
		dez_node_specs[pdez_node->next->dez_op].dez_node_free_func(pdez_node->next);
	}
	
	/*-- free the node content --*/
	if (pdez_node->content != NULL)
	{
		/**********/
		
		free(pdez_node->content);
	}
	
	/*-- free the node self */
	free(pdez_node);
}

static void dez_node_free_list (DEZ_NODE *pdez_node)
{
	DEZ_NODE_LIST *content;

	if (pdez_node == NULL)
	{
		return;
	}
	
	/*-- free the next node --*/
	if (pdez_node->next != NULL)
	{
		dez_node_specs[pdez_node->next->dez_op].dez_node_free_func(pdez_node->next);
	}
	
	/*-- free the node content --*/
	content = (DEZ_NODE_LIST *)(pdez_node->content);
	if (content != NULL)
	{
		if (content->branch_node) dez_node_specs[content->branch_node->dez_op].dez_node_free_func(content->branch_node);
		if (content->le_node) dez_node_specs[content->le_node->dez_op].dez_node_free_func(content->le_node);
		if (content->dest_node) dez_node_specs[content->dest_node->dez_op].dez_node_free_func(content->dest_node);
		
		free(content);
	}
	
	/*-- free the node self */
	free(pdez_node);
}

static void dez_node_free_le (DEZ_NODE *pdez_node)
{
	DEZ_NODE_LE *content;

	if (pdez_node == NULL)
	{
		return;
	}
	
	/*-- free the next node --*/
	if (pdez_node->next != NULL)
	{
		dez_node_specs[pdez_node->next->dez_op].dez_node_free_func(pdez_node->next);
	}
	
	/*-- free the node content --*/
	content = (DEZ_NODE_LE *)(pdez_node->content);
	if (content != NULL)
	{
		if (content->branch_node) dez_node_specs[content->branch_node->dez_op].dez_node_free_func(content->branch_node);
		if (content->a_node) dez_node_specs[content->a_node->dez_op].dez_node_free_func(content->a_node);
		
		free(content);
	}
	
	/*-- free the node self */
	free(pdez_node);
}

static void dez_node_free_heredoc (DEZ_NODE *pdez_node)
{
	if (pdez_node == NULL)
	{
		return;
	}
	
	/*-- free the next node --*/
	if (pdez_node->next != NULL)
	{
		dez_node_specs[pdez_node->next->dez_op].dez_node_free_func(pdez_node->next);
	}
	
	/*-- free the node content --*/
	if (pdez_node->content != NULL)
	{
		/**********/
		
		free(pdez_node->content);
	}
	
	/*-- free the node self */
	free(pdez_node);
}

static void dez_node_free_dollar_open_curly_braces (DEZ_NODE *pdez_node)
{
	if (pdez_node == NULL)
	{
		return;
	}
	
	/*-- free the next node --*/
	if (pdez_node->next != NULL)
	{
		dez_node_specs[pdez_node->next->dez_op].dez_node_free_func(pdez_node->next);
	}
	
	/*-- free the node content --*/
	if (pdez_node->content != NULL)
	{
		/**********/
		
		free(pdez_node->content);
	}
	
	/*-- free the node self */
	free(pdez_node);
}

static void dez_node_free_unknown (DEZ_NODE *pdez_node)
{
	if (pdez_node == NULL)
	{
		return;
	}
	
	/*-- free the next node --*/
	if (pdez_node->next != NULL)
	{
		dez_node_specs[pdez_node->next->dez_op].dez_node_free_func(pdez_node->next);
	}
	
	/*-- free the node content --*/
	if (pdez_node->content != NULL)
	{
		/**********/
		
		free(pdez_node->content);
	}
	
	/*-- free the node self */
	free(pdez_node);
}


/**********************************************************
*  dez_dump_op: dump a dez op
*
*  @param dez_op: the dez op code need to be dumped
*  @return 0: normal, 1: enter a branch, 2: exit the branch, 3: need to continue -1: error
**********************************************************/
static int dez_dump_op (unsigned char dez_op)
{
	return dez_node_specs[dez_op].dez_node_cvt_func (dez_op, m_op_buffer[0]);
}


/**********************************************************
*  dez_dump_zend_op: dump a zend op
*
*  @param pzop:	pointer to the zend_op need to be dumped
*  @return 0: normal, 1: enter a branch, 2: exit the branch, -1: error
**********************************************************/
static int dez_dump_zend_op (zend_op *pzop)
{
//printf ( "%u,", pzop->opcode);
//return 0;

	printf ( "    %6u:", ZEND_LINENUM(pzop));
	
	if (pzop->opcode >= sizeof(ZEND_OP_STRING)/sizeof(ZEND_OP_STRING[0]))
	{
		printf ( "<%u>     ", pzop->opcode);
	}
	else
	{
		printf ("%s", ZEND_OP_STRING[pzop->opcode]);
	}

	dez_dump_znode_ex(&(pzop->result), 1);
	printf ( ", ");

	dez_dump_znode_ex(&(pzop->op1), 1);
	printf ( ", ");

	dez_dump_znode_ex(&(pzop->op2), 1);
	printf ( "\r\n");

	return 0;
	
//	return dez_node_specs[DEZ_OP_UNKNOWN].dez_node_cvt_func (DEZ_OP_UNKNOWN, pzop);
}


/**********************************************************
*  dez_deal_op: deal with a zend_op
*
*  @param pzop:	pointer to the zend_op would be dealed with. NULL means uninitialization
*  @param match_n: used to retreive the number of matching zend_op
*  @return 0: success, 1: enter a branch, 2: exit the branch, -1: error
**********************************************************/
static int dez_deal_op (zend_op *pzop, short *match_n)
{
	static unsigned char *op_masks = NULL;					/* each element: 0: need to continue, 1: not matching, 2: matching */
	static int op_num = 0;
	
	register int i;
	int needcontinues;
	short mn;
	int matching_i;
	int r;
	
	*match_n = 0;
	
	if (op_masks == NULL)									/* initialization */
	{
		op_masks = (unsigned char *)malloc(sizeof(dez_op_types)/sizeof(dez_op_types[0]));
		if (op_masks == NULL)								/* fail to alloc memery */
		{
			return -1;
		}
		
		op_num = sizeof(dez_op_types)/sizeof(dez_op_types[0]);
		
		memset (op_masks, 0, op_num);						/* initialize op_masks */
	}
	
	if (pzop != NULL)
	{
		if (dez_opc_push (pzop) != 0)						/* push the zend op into stack */
		{													/* fail */
			return -1;
		}
	}
	
	needcontinues	= 0;
	mn				= 0;
	for (i = 0; i < op_num; i++)
	{
		if (op_masks[i] == 0)								/* need to continue */
		{
			op_masks[i] = dez_opc_compare (dez_op_types[i].opcs, dez_op_types[i].opcs_len);
		}
		
		switch (op_masks[i])
		{
			case 0:											/* need to continue */
				needcontinues++;
				break;
			case 1:											/* not matching */
				break;
			case 2:											/* matching */
				if (mn < dez_op_types[i].opcs_len)
				{
					mn				= dez_op_types[i].opcs_len;
					matching_i		= i;
				}
				break;
		}
	}
	
	if (pzop == NULL)										/* uninitialization */
	{
		if (m_opc_num > 0)									/* the stack is not empty */
		{
			if (mn > 0)										/* any dez op is matching */
			{
				*match_n = mn;
				dez_dump_op (dez_op_types[matching_i].dez_op);	/* dump the matching dez op */
			}
			else											/* all dez ops ara not matching */
			{
				mn = 1;
				*match_n = mn;
				dez_dump_zend_op (m_op_buffer[0]);			/* dump the zend op at the top of stack */
			}
			
			memset (op_masks, 0, op_num);					/* reset op_masks */
			
			dez_opc_pop(mn);
			
			dez_deal_op (NULL, match_n);
		}
		else
		{
			if (op_masks != NULL)
			{
				free (op_masks);
				op_masks = NULL;
			}
		}
	}
	else if (needcontinues == 0)							/* no one dez op need to continue */
	{
		if (mn > 0)											/* any dez op is matching */
		{
			*match_n = mn;
			
			do
			{
				r = dez_dump_op (dez_op_types[matching_i].dez_op);	/* dump the matching dez op */
			} while(r == 3);								/* continue to deal with the zend op */
		}
		else												/* all dez ops ara not matching */
		{
			mn = 1;
			*match_n = mn;
			
			r = dez_dump_zend_op (m_op_buffer[0]);			/* dump the zend op at the top of stack */
		}
		
		memset (op_masks, 0, op_num);						/* reset op_masks */
		
		return r;
	}
	
	return 0;
}


/**********************************************************
*  dez_deal_op_end: end process
*
*  @param header: the header of dez nodes
*  @param perant: the parent node
*  @return 0: success; other: failed
**********************************************************/
static int dez_deal_node_end(DEZ_NODE *header, DEZ_NODE *parent)
{
	DEZ_NODE_EXPR *content;
	DEZ_NODE *p, *next;
	int begin, end, prevcond;
	DEZ_BRK_CNT_NODE *pbcn_header, *pbcn, *pbcn_next;
	
	pbcn_header	= m_dez_brk_cnt_tail;
	
	begin		= 0;
	end			= 100000;
	prevcond	= -1;
	
	dez_branch_get_range(parent, &begin, &end);

	if (parent != NULL && parent->dez_op == DEZ_OP_DO)
	{
		DEZ_NODE *prev, *sub;
		
		prev = dez_get_last_sub_node(parent);
		
		while(prev)
		{
			if (
				prev->dez_op == DEZ_OP_DO	||										/* do{...}while() */
				prev->dez_op == DEZ_OP_WHILE && prev->zop->opcode == ZEND_JMP		/* while(true) */
			)
			{
				break;
			}
			
			sub = dez_get_last_sub_node(prev);
			
			if (sub == NULL)
			{
				break;
			}
			
			prev = sub;
		}
		
		if (prev == NULL)							/* no sub branch */
		{
			prevcond = get_prev_zend_linenum(parent);
		}
		else
		{
			prevcond = get_zend_linenum(prev);
		}
	}
	else if (parent != NULL && parent->dez_op == DEZ_OP_FOR)
	{
		DEZ_NODE *before_node = ((DEZ_NODE_FOR *)(parent->content))->before_node;
		
		if (before_node != NULL)
		{
			prevcond = get_zend_linenum(before_node);
		}
		else
		{
			prevcond = get_prev_zend_linenum(parent);
		}
	}
	else
	{
		prevcond = get_prev_zend_linenum(parent);
	}
	
	p = header;
	
	while(p != NULL)
	{
		content = (DEZ_NODE_EXPR *)(p->content);
		
		if (p->dez_op == DEZ_OP_IF && p->zop->opcode == ZEND_JMP)	/* if (false) node */
		{
			int dest;
			
			if (content != NULL && content->branch_node != NULL)	/* sub branch is exist */
			{
				dez_node_specs[content->branch_node->dez_op].dez_node_free_func(content->branch_node);	/* remove the sub branch */
				content->branch_node = NULL;
			}
			
			dest = p->zop->op1.u.opline_num;
			
			if (dest < begin || dest > end)							/* jmp out of the branch */
			{
				if (p->next != NULL)
				{
					dez_node_specs[p->next->dez_op].dez_node_free_func(p->next);	/* remove remainder nodes in this  branch */
					p->next = NULL;
				}
			}

			((DEZ_NODE_IF *)content)->dest = 0;						/* maybe break */
			dez_brk_cnt_add(p);
		}
		else if (content != NULL && content->branch_node != NULL)	/* sub branch is exist */
		{
			dez_node_push(p);										/* for get_prev_zend_linenum() */
			
			dez_deal_node_end(content->branch_node, p);				/* deal with the sub branch */

			dez_node_pop();											/* for get_prev_zend_linenum() */
		}

		p = p->next;
	}
	
	if (pbcn_header != NULL)
	{
		pbcn = pbcn_header->next;
	}
	else
	{
		pbcn = m_dez_brk_cnt_root;
	}
	
	while(pbcn != NULL)
	{
		DEZ_NODE *n;
		DEZ_NODE_IF *c;
		int dest;
		int checked;
		
		pbcn_next = pbcn->next;
		
		n = (DEZ_NODE*)(pbcn->node);
		c = (DEZ_NODE_IF *)(n->content);
		dest = n->zop->op1.u.opline_num;
		
		checked = 0;
		
		if (
			parent != NULL							&&
			(
				parent->dez_op == DEZ_OP_WHILE		||
				parent->dez_op == DEZ_OP_DO			||
				parent->dez_op == DEZ_OP_FOR		||
				parent->dez_op == DEZ_OP_FOREACH	||
				parent->dez_op == DEZ_OP_SWITCH
			)
		)														/* loop or switch */
		{
			int endcond;
			if (parent->dez_op == DEZ_OP_WHILE && parent->zop->opcode == ZEND_JMP)	/* while(true) */
			{
				endcond = prevcond+1;
			}
			else
			{
				endcond = get_zend_linenum(parent);
			}
			
			if (dest < begin || dest > end)						/* jmp out of the branch */
			{
				n->dez_op = DEZ_OP_BREAK;
				c->dest++;
				
				checked = 1;
			}
			else if (
				c->dest == 0					&&				/* maybe continue */
				dest > prevcond && dest <= endcond				/* jmp to condition */
			)
			{
				n->dez_op = DEZ_OP_CONTINUE;
				
				checked = 1;
			}
		}
		else if (
			parent != NULL						&&
			parent->dez_op == DEZ_OP_IF
		)
		{
			if (
				n->dez_op == DEZ_OP_BREAK		&&
				dest > prevcond					&&				/* jmp to condition */
				dest <= get_zend_linenum(parent)				/*                  */
			)
			{
				parent->dez_op = DEZ_OP_WHILE;					/* IF -> WHILE */
			}
		}
		
		if (checked != 0)										/* break or continue was found */
		{
#if 0
			if (c != NULL && c->branch_node != NULL)			/* sub branch is exist */
			{
				DEZ_NODE *lastsubnode = c->branch_node;
				while(lastsubnode->next != NULL)
				{
					lastsubnode = lastsubnode->next;
				}
				
				lastsubnode->next = n->next;
				if (lastsubnode->next != NULL) lastsubnode->next->prev = lastsubnode;
				
				n->next = c->branch_node->next;
				if (n->next != NULL) n->next->prev = n;
				
				c->branch_node->next = NULL;
				free(c->branch_node);
				c->branch_node = NULL;
			}
#endif
		}
		
		if (dest >= begin && dest <= end)						/* jmp within the branch */
		{
			dez_brk_cnt_del(pbcn);
			
			if (n->dez_op == DEZ_OP_IF)							/* not break/continue */
			{
				DEZ_DEL_NODE(n);
			}
			else if(n->dez_op == DEZ_OP_CONTINUE)				/* the continue node */
			{
				DEZ_NODE *lastsubnode = dez_get_last_sub_node(parent);
				if (lastsubnode == n)							/* the continue node is last node in branch */
				{
					DEZ_DEL_NODE(n);
				}
			}
		}
		
		pbcn = pbcn_next;
	}
	
	return 0;
}

/**********************************************************
*  dez_decompile: decompile some zend ops
*
*  @param ops:	the array of zend_ops would be decompiled
*  @param n:	the number of ops
*  @return 0: success; other: failed
**********************************************************/
static int dez_decompile (zend_op *ops, int n)
{
	int r;
	DEZ_NODE_EXPR *content;
	
static struct _zend_executor_globals *zeg;
	TSRMLS_FETCH(); 
	dez_prep_zend_op(ops, n);						/* pre process the zend op */
		
	m_zend_op_start		= ops;
	m_zend_op_end		= ops+n;
	
	m_zend_op_current	= m_zend_op_start;

	while (m_zend_op_current < m_zend_op_end)
	{
zeg = (struct _zend_executor_globals *)&EG(return_value_ptr_ptr);
//dez_dump_zend_op(m_zend_op_current);	/****** for debug */
//m_zend_op_current++;
//continue;

		r = dez_deal_op (m_zend_op_current, &m_zend_op_match_n);	/* deal with a zend_op */

		if (r == 0)									/* success to deal with the zend_op */
		{
			/* do nothing */
		}
		else if (r == 1)							/* enter a branch */
		{
			dez_enter_branch();
		}
		else if (r == 2)							/* exit the branch */
		{
			dez_exit_branch(1);						/* exit the branch */
		}
		else										/* error */
		{
			return r;
		}
		
		dez_check_exit_branch();
		
		dez_opc_pop (m_zend_op_match_n);			/* pop the matching zend op */

		if (m_opc_num > 0)							/* some zend_ops is in stack */
		{
			dez_opc_refresh();						/* update the opcodes in stack */
		}
		
		m_zend_op_current++;
	}
	
	dez_deal_op(NULL, &m_zend_op_match_n);			/* process the remainder zend op in stack */
	
	dez_check_exit_all();							/* exit all branch */

	dez_deal_node_end(m_dez_op_root, NULL);			/* end process (make BREAK, CONTINUE node) */
	
	dez_brk_cnt_free();								/* free the break/continue list */

	clear_or_recover_zend_op(NULL, 0, 0);			/* clear the opcodes cleared */
	
	return 0;
}


/**********************************************************
*  dez_output: output the zend nodes
*
*  @param header: the header of dez nodes
*  @param perant: the parent node
*  @return 0: success; other: failed
**********************************************************/
static int dez_output (DEZ_NODE *header, DEZ_NODE *parent)
{
	static char m_tab[1024] = {' ',' ','\0'};
	
	static int m_dez_declare = 0;
	static int m_dez_silence = 0;

	DEZ_NODE_EXPR *content;
	DEZ_NODE *p, *next;
	DEZ_NODE *function_node;
	
	if (m_dez_declare > 0)
	{
		m_dez_declare++;
	}
	
	p = header;
	
	while(p != NULL)
	{
		next = p->next;
		 
		if (
			p->dez_op == DEZ_OP_NOP		||
			p->dez_op == DEZ_OP_DECLARE
		)
		{
			p = next;
			continue;
		}
		else if (p->dez_op == DEZ_OP_BEGIN_SILENCE)
		{
			m_dez_silence = 1;
			
			p = next;
			continue;
		}
		else if (p->dez_op == DEZ_OP_END_SILENCE)
		{
			m_dez_silence = 0;
			
			p = next;
			continue;
		}
		
		if (
			next != NULL &&
			next->dez_op == DEZ_OP_DECLARE
		)
		{
			if (m_dez_declare == 0)
			{
				m_dez_declare = 1;									/* enter declare branch */
				printf ("%s", m_tab);
				dez_node_specs[next->dez_op].dez_node_output_func (next);
				printf ("\r\n%s{\r\n", m_tab);
				strcat(m_tab, "  ");
			}
		}
		else
		{
			if (m_dez_declare == 1)
			{
				m_dez_declare = 0;									/* exit declare branch */
				m_tab[strlen(m_tab)-2] = '\0';
				printf ("%s}\r\n\r\n", m_tab);
			}
		}
		
		/*-- remove the last return in function() or main branch --*/
		if (
			next == NULL &&
			(parent == NULL || parent->dez_op == DEZ_OP_FUNCTION) &&
			p->dez_op == DEZ_OP_RETURN
		)															/* the last return */
		{
			break;													/* skip the last return */
		}
		
		if (p->dez_op == DEZ_OP_FUNCTION)
		{
			function_node = m_current_function;						/* save the old function node */
			m_current_function = p;
		}

		printf ("%s", m_tab);
		
		if (m_dez_silence != 0)										/* silence */
		{
			printf ("%s", dez_node_specs[DEZ_OP_BEGIN_SILENCE].desc);
		}
		
		dez_node_specs[p->dez_op].dez_node_output_func (p);
		
		content = (DEZ_NODE_EXPR *)(p->content);
		
		if (content != NULL && content->branch_node != NULL)		/* enter branch */
		{
			printf ("\r\n%s{\r\n", m_tab);
			strcat(m_tab, "  ");
			dez_output (content->branch_node, p);					/* output the branch */
			m_tab[strlen(m_tab)-2] = '\0';
			
			if (p->dez_op == DEZ_OP_DO)
			{
				printf ( "%s}", m_tab);
				p->dez_op = DEZ_OP_WHILE;
				dez_node_output_if(p);								/* output while(...) */
				p->dez_op = DEZ_OP_DO;
				printf ( ";\r\n");
			}
			else
			{
				printf ( "%s}\r\n", m_tab);
			}
			
			if (p->next != NULL && p->next->dez_op != DEZ_OP_ELSE)
			{
				printf ( "\r\n");
			}
		}
		else
		{
			printf ( ";\r\n");
		}

		if (p->dez_op == DEZ_OP_FUNCTION)
		{
			m_current_function = function_node;						/* restore the old function node */
		}
		
		p = next;
	}
	
	if (m_dez_declare > 0)
	{
		m_dez_declare--;

		if (m_dez_declare == 0)										/* exit declare branch */
		{
			m_tab[strlen(m_tab)-2] = '\0';
			printf ( "%s}\r\n\r\n", m_tab);
		}
	}
	
	return 0;
}


/**********************************************************
*  dez_property: decompile properties
*
*  @param ht: properties
*  @return 0: success; other: failed
**********************************************************/
static int dez_property (HashTable *ht)
{
	DEZ_NODE *parent;
	DEZ_NODE_CLASS *ccontent;

	if (ht != NULL)
	{
		Bucket *p = ht->pListHead;
		
		parent = dez_node_get();
		
		/*-- decompile properties --*/
		while(p != NULL)
		{
			DEZ_NODE *node;
			DEZ_NODE_VAR *content;

			if (
				parent != NULL		&&
				parent->dez_op == DEZ_OP_CLASS
			)											/* property declaration */
			{
				ccontent = (DEZ_NODE_CLASS *)(parent->content);
				
				if (ccontent->parent != NULL)			/* extands */
				{
					HashTable *pht = &(ccontent->parent->default_properties);
					
					Bucket *pp = pht->pListHead;
					
					while(pp != NULL)
					{
						if (
							strcmp((char *)(pp->arKey), (char *)(p->arKey)) == 0 &&
							*((zval **)(pp->pData)) == *((zval **)(p->pData))
						)								/* property for parent class */
						{
							break;
						}
						
						pp = pp->pListNext;
					}
					
					if (pp != NULL)						/* the method belongs parent class */
					{
						p = p->pListNext;
						continue;
					}
				}
			}

			content = (DEZ_NODE_VAR *)malloc(sizeof(DEZ_NODE_VAR));
			if (content == NULL)
			{
				return -1;
			}
			
			node = (DEZ_NODE *)malloc(sizeof(DEZ_NODE));
			if (node == NULL)
			{
				free(content);
				return -1;
			}
			
			content->branch_node	= NULL;
			content->property		= p;
			
			node->dez_op			= DEZ_OP_VAR;
			node->zop				= NULL;
			node->content			= content;
		
			DEZ_ADD_NODE(node);
			
			p = p->pListNext;
		}
	}
	
	return 0;
}


/**********************************************************
*  dez_function: decompile functions
*
*  @param ht: function_table
*  @return 0: success; other: failed
**********************************************************/
static int dez_function (HashTable *ht)
{
	static zend_op_array *op_array;
	DEZ_NODE *parent;
	DEZ_NODE_CLASS *ccontent;

	if (ht != NULL)
	{
		Bucket *p = ht->pListHead;
		
		parent = dez_node_get();
		
		/*-- decompile the user functions --*/
		while(p != NULL)
		{
			op_array = (zend_op_array *)(p->pData);
			
			if (
				op_array != NULL	&&
				op_array->type == 2					/* user function */
			)
			{
				DEZ_NODE *node;
				DEZ_NODE_FUNCTION *content;
				
				if (
					parent != NULL		&&
					parent->dez_op == DEZ_OP_CLASS
				)									/* method declaration */
				{
					ccontent = (DEZ_NODE_CLASS *)(parent->content);
					
					if (ccontent->parent != NULL)	/* extands */
					{
						HashTable *pht = &(ccontent->parent->function_table);
						
						Bucket *pp = pht->pListHead;
						
						while(pp != NULL)
						{
							if (((zend_op_array *)(pp->pData))->opcodes == op_array->opcodes)	/* function for parent class */
							{
								break;
							}
							
							pp = pp->pListNext;
						}
						
						if (pp != NULL)				/* the method belongs parent class */
						{
							p = p->pListNext;
							continue;
						}
					}
				}

				content = (DEZ_NODE_FUNCTION *)malloc(sizeof(DEZ_NODE_FUNCTION));
				if (content == NULL)
				{
					return -1;
				}
				
				node = (DEZ_NODE *)malloc(sizeof(DEZ_NODE));
				if (node == NULL)
				{
					free(content);
					return -1;
				}
				
				content->branch_node	= NULL;
				content->param_node		= NULL;
				content->name			= op_array->function_name;
				content->m_dez_var_num	= 0;
				content->op_array		= op_array;
				
				node->dez_op			= DEZ_OP_FUNCTION;
				node->zop				= op_array->opcodes;
				node->content			= content;
			
				DEZ_ADD_NODE(node);
				
//printf("*%s:\r\n", op_array->function_name);
				m_current_function = node;
				
				dez_enter_branch();									/* enter function branch */
				
				dez_decompile (op_array->opcodes, op_array->size);	/* zend op -> dez op */
				
				dez_exit_branch(0);									/* exit function branch */
				
				m_current_function = NULL;
			}
			
			p = p->pListNext;
		}
	}
	
	return 0;
}


/**********************************************************
*  dez_class: decompile classes
*
*  @param none
*  @return 0: success; other: failed
**********************************************************/
static int dez_class (void)
{
	static HashTable *ht;
	static zend_class_entry *c_entry;
	static zend_op_array *op_array;
	TSRMLS_FETCH(); 
	ht = (EG(class_table));
	
	if (ht != NULL)
	{
		Bucket *p = ht->pListHead;
		
		/*-- decompile the user functions --*/
		while(p != NULL)
		{
			c_entry = (zend_class_entry *)(p->pData);
			
			if (
				c_entry != NULL	&&
				c_entry->type == ZEND_USER_CLASS				/* user class */
			)
			{
				DEZ_NODE *node;
				DEZ_NODE_CLASS *content;
				
				content = (DEZ_NODE_CLASS *)malloc(sizeof(DEZ_NODE_CLASS));
				if (content == NULL)
				{
					return -1;
				}
				
				node = (DEZ_NODE *)malloc(sizeof(DEZ_NODE));
				if (node == NULL)
				{
					free(content);
					return -1;
				}
				
				content->branch_node	= NULL;
				content->name			= c_entry->name;
				content->parent			= c_entry->parent;
				
				node->dez_op			= DEZ_OP_CLASS;

				node->zop				= NULL;
				node->content			= content;
			
				DEZ_ADD_NODE(node);
				
//printf("class %s:\r\n", c_entry->name);
				
				dez_enter_branch();									/* enter class branch */
				
				dez_property (&(c_entry->default_properties));		/* decompile the properties */
				
				dez_function (&(c_entry->function_table));			/* decompile the motheds */
				
				dez_exit_branch(0);									/* exit class branch */
			}
			
			p = p->pListNext;
		}
	}
	
	return 0;
}


/**********************************************************
*  dez_global: decompile global source
*
*  @param none
*  @return 0: success; other: failed
**********************************************************/
static int dez_global (void)
{
	TSRMLS_FETCH(); 
	m_current_function = NULL;
	
	return dez_decompile (EG(active_op_array)->opcodes, EG(active_op_array)->size);	/* zend op -> dez op */
}


/**********************************************************
*  dez_main: decompile the zend op
*
*  @param none
*  @return 0: success; other: failed
**********************************************************/
int dez_main (void)
{
	TSRMLS_FETCH(); 
	static char *m_Header = 
"/***********************************************************************/\r\n"
"/*                                                                     */\r\n"
"/*  This file is created by Dezender                                   */\r\n"
"/*                                                                     */\r\n"
"/*  Dezender (Decoder for Zend Encoder/SafeGuard):                     */\r\n"
"/*    Version:      0.9.0.1                                            */\r\n"
"/*    Author:       qinvent.com                                        */\r\n"
"/*    Release Date: 2005.10.04                                         */\r\n"
"/*                                                                     */\r\n"
"/***********************************************************************/\r\n"
"\r\n\r\n";

	m_dez_op_root = (DEZ_NODE *)malloc(sizeof(DEZ_NODE));
	if (m_dez_op_root == NULL)						/* fail to alloc memory */
	{
		return -1;
	}
	
	m_dez_op_root->dez_op	= DEZ_OP_NOP;
	m_dez_op_root->zop		= NULL;
	m_dez_op_root->content	= NULL;
	m_dez_op_root->prev		= NULL; 
	m_dez_op_root->next		= NULL;
	
	m_dez_op_current		= m_dez_op_root;
	
	dez_class ();									/* decompile classes */
	
	dez_function (EG(function_table));				/* decompile functions */
	
	dez_global ();									/* decompile global source */
	
	m_current_function = NULL;
	
	printf ( "<?php\r\n%s", m_Header);
	
	dez_output(m_dez_op_root, NULL);				/* output the dez nodes */
	
	printf ( "?>\r\n");
	
	dez_node_free();								/* free dez nodes */
	
	return 0;
}


/************************************************
 * @ dezender.c v1.0 log @
 *
 * Revision 1.0.0.0     lkq       2005/08/10
 * create the file
 * 
 ***********************************************/
Reply With Quote
The Following 2 Users Gave Reputation+1 to CryptXor For This Useful Post:
giv (10-11-2015), uranus64 (10-11-2015)
The Following 2 Users Say Thank You to CryptXor For This Useful Post:
giv (10-11-2015), uranus64 (10-11-2015)
  #22  
Old 06-05-2018, 17:27
vilciucostel vilciucostel is offline
Friend
 
Join Date: Feb 2009
Location: Oltenita
Posts: 44
Rept. Given: 4
Rept. Rcvd 4 Times in 2 Posts
Thanks Given: 6
Thanks Rcvd at 1 Time in 1 Post
vilciucostel Reputation: 4
Maybe Narciszu holds more information.
Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
PHP Decode S3ri@l CoDe9x General Discussion 1 04-11-2013 14:28


All times are GMT +8. The time now is 13:19.


Always Your Best Friend: Aaron, JMI, ahmadmansoor, ZeNiX, chessgod101
( 1998 - 2024 )