source: trunk/Decompiler.class.php @ 756

Last change on this file since 756 was 756, checked in by moo, 4 years ago

remove unncessary debug code

  • Property svn:eol-style set to native
File size: 54.3 KB
Line 
1<?php
2
3define('INDENT', "\t");
4ini_set('error_reporting', E_ALL);
5
6function color($str, $color = 33)
7{
8    return "\x1B[{$color}m$str\x1B[0m";
9}
10
11function str($code, $indent = '') // {{{
12{
13    if (is_array($code)) {
14        $array = array();
15        foreach ($code as $key => $value) {
16            $array[$key] = str($value, $indent);
17        }
18        return $array;
19    }
20    if (is_object($code)) {
21        $code = foldToCode($code, $indent);
22        return $code->toCode($indent);
23    }
24
25    return (string) $code;
26}
27// }}}
28function foldToCode($src, $indent = '') // {{{ wrap or rewrap anything to Decompiler_Code
29{
30    if (is_array($indent)) {
31        $indent = $indent['indent'];
32    }
33
34    if (!is_object($src)) {
35        return new Decompiler_Code($src);
36    }
37
38    if (!method_exists($src, 'toCode')) {
39        var_dump($src);
40        exit('no toCode');
41    }
42    if (get_class($src) != 'Decompiler_Code') {
43        // rewrap it
44        $src = new Decompiler_Code($src->toCode($indent));
45    }
46
47    return $src;
48}
49// }}}
50function value($value) // {{{
51{
52    $spec = xcache_get_special_value($value);
53    if (isset($spec)) {
54        $value = $spec;
55        if (!is_array($value)) {
56            // constant
57            return $value;
58        }
59    }
60
61    if (is_a($value, 'Decompiler_Object')) {
62        // use as is
63    }
64    else if (is_array($value)) {
65        $value = new Decompiler_ConstArray($value);
66    }
67    else {
68        $value = new Decompiler_Value($value);
69    }
70    return $value;
71}
72// }}}
73function unquoteName_($str, $asProperty, $indent = '') // {{{
74{
75    $str = str($str, $indent);
76    if (preg_match("!^'[\\w_][\\w\\d_\\\\]*'\$!", $str)) {
77        return str_replace('\\\\', '\\', substr($str, 1, -1));
78    }
79    else if ($asProperty) {
80        return "{" . $str . "}";
81    }
82    else {
83        return $str;
84    }
85}
86// }}}
87function unquoteProperty($str, $indent = '') // {{{
88{
89    return unquoteName_($str, true, $indent);
90}
91// }}}
92function unquoteName($str, $indent = '') // {{{
93{
94    return unquoteName_($str, false, $indent);
95}
96// }}}
97class Decompiler_Object // {{{
98{
99}
100// }}}
101class Decompiler_Value extends Decompiler_Object // {{{
102{
103    var $value;
104
105    function Decompiler_Value($value = null)
106    {
107        $this->value = $value;
108    }
109
110    function toCode($indent)
111    {
112        $code = var_export($this->value, true);
113        if (gettype($this->value) == 'string') {
114            switch ($this->value) {
115            case "\r":
116                return '"\\r"';
117            case "\n":
118                return '"\\n"';
119            case "\r\n":
120                return '"\\r\\n"';
121            }
122            $code = str_replace("\r\n", '\' . "\\r\\n" . \'', $code);
123            $code = str_replace("\r", '\' . "\\r" . \'', $code);
124            $code = str_replace("\n", '\' . "\\n" . \'', $code);
125        }
126        return $code;
127    }
128}
129// }}}
130class Decompiler_Code extends Decompiler_Object // {{{
131{
132    var $src;
133
134    function Decompiler_Code($src)
135    {
136        assert('isset($src)');
137        $this->src = $src;
138    }
139
140    function toCode($indent)
141    {
142        return $this->src;
143    }
144}
145// }}}
146class Decompiler_Binop extends Decompiler_Code // {{{
147{
148    var $opc;
149    var $op1;
150    var $op2;
151    var $parent;
152    var $indent;
153
154    function Decompiler_Binop($parent, $op1, $opc, $op2)
155    {
156        $this->parent = &$parent;
157        $this->opc = $opc;
158        $this->op1 = $op1;
159        $this->op2 = $op2;
160    }
161
162    function toCode($indent)
163    {
164        $op1 = foldToCode($this->op1, $indent);
165        if (is_a($this->op1, 'Decompiler_Binop') && $this->op1->opc != $this->opc) {
166            $op1 = "($op1)";
167        }
168        $opstr = $this->parent->binops[$this->opc];
169        if ($op1 == '0' && $this->opc == XC_SUB) {
170            return $opstr . str($this->op2, $indent);
171        }
172        return str($op1) . ' ' . $opstr . ' ' . str($this->op2, $indent);
173    }
174}
175// }}}
176class Decompiler_Fetch extends Decompiler_Code // {{{
177{
178    var $src;
179    var $fetchType;
180
181    function Decompiler_Fetch($src, $type, $globalsrc)
182    {
183        $this->src = $src;
184        $this->fetchType = $type;
185        $this->globalsrc = $globalsrc;
186    }
187
188    function toCode($indent)
189    {
190        switch ($this->fetchType) {
191        case ZEND_FETCH_LOCAL:
192            return '$' . substr($this->src, 1, -1);
193        case ZEND_FETCH_STATIC:
194            if (ZEND_ENGINE_2_3) {
195                // closure local variable?
196                return str($this->src);
197            }
198            die('static fetch cant to string');
199        case ZEND_FETCH_GLOBAL:
200        case ZEND_FETCH_GLOBAL_LOCK:
201            return $this->globalsrc;
202        default:
203            var_dump($this->fetchType);
204            assert(0);
205        }
206    }
207}
208// }}}
209class Decompiler_Box // {{{
210{
211    var $obj;
212
213    function Decompiler_Box(&$obj)
214    {
215        $this->obj = &$obj;
216    }
217
218    function toCode($indent)
219    {
220        return $this->obj->toCode($indent);
221    }
222}
223// }}}
224class Decompiler_Dim extends Decompiler_Value // {{{
225{
226    var $offsets = array();
227    var $isLast = false;
228    var $isObject = false;
229    var $assign = null;
230
231    function toCode($indent)
232    {
233        if (is_a($this->value, 'Decompiler_ListBox')) {
234            $exp = str($this->value->obj->src, $indent);
235        }
236        else {
237            $exp = str($this->value, $indent);
238        }
239        $last = count($this->offsets) - 1;
240        foreach ($this->offsets as $i => $dim) {
241            if ($this->isObject && $i == $last) {
242                $exp .= '->' . unquoteProperty($dim, $indent);
243            }
244            else {
245                $exp .= '[' . str($dim, $indent) . ']';
246            }
247        }
248        return $exp;
249    }
250}
251// }}}
252class Decompiler_DimBox extends Decompiler_Box // {{{
253{
254}
255// }}}
256class Decompiler_List extends Decompiler_Code // {{{
257{
258    var $src;
259    var $dims = array();
260    var $everLocked = false;
261
262    function toCode($indent)
263    {
264        if (count($this->dims) == 1 && !$this->everLocked) {
265            $dim = $this->dims[0];
266            unset($dim->value);
267            $dim->value = $this->src;
268            if (!isset($dim->assign)) {
269                return str($dim, $indent);
270            }
271            return str($this->dims[0]->assign, $indent) . ' = ' . str($dim, $indent);
272        }
273        /* flatten dims */
274        $assigns = array();
275        foreach ($this->dims as $dim) {
276            $assign = &$assigns;
277            foreach ($dim->offsets as $offset) {
278                $assign = &$assign[$offset];
279            }
280            $assign = foldToCode($dim->assign, $indent);
281        }
282        return str($this->toList($assigns)) . ' = ' . str($this->src, $indent);
283    }
284
285    function toList($assigns)
286    {
287        $keys = array_keys($assigns);
288        if (count($keys) < 2) {
289            $keys[] = 0;
290        }
291        $max = call_user_func_array('max', $keys);
292        $list = 'list(';
293        for ($i = 0; $i <= $max; $i ++) {
294            if ($i) {
295                $list .= ', ';
296            }
297            if (!isset($assigns[$i])) {
298                continue;
299            }
300            if (is_array($assigns[$i])) {
301                $list .= $this->toList($assigns[$i]);
302            }
303            else {
304                $list .= $assigns[$i];
305            }
306        }
307        return $list . ')';
308    }
309}
310// }}}
311class Decompiler_ListBox extends Decompiler_Box // {{{
312{
313}
314// }}}
315class Decompiler_Array extends Decompiler_Value // {{{
316{
317    // emenets
318    function Decompiler_Array()
319    {
320        $this->value = array();
321    }
322
323    function toCode($indent)
324    {
325        $subindent = $indent . INDENT;
326
327        $elementsCode = array();
328        $index = 0;
329        foreach ($this->value as $element) {
330            list($key, $value) = $element;
331            if (!isset($key)) {
332                $key = $index++;
333            }
334            $elementsCode[] = array(str($key, $subindent), str($value, $subindent), $key, $value);
335        }
336
337        $exp = "array(";
338        $indent = $indent . INDENT;
339        $assocWidth = 0;
340        $multiline = 0;
341        $i = 0;
342        foreach ($elementsCode as $element) {
343            list($keyCode, $valueCode) = $element;
344            if ((string) $i !== $keyCode) {
345                $assocWidth = 1;
346                break;
347            }
348            ++$i;
349        }
350        foreach ($elementsCode as $element) {
351            list($keyCode, $valueCode, $key, $value) = $element;
352            if ($assocWidth) {
353                $len = strlen($keyCode);
354                if ($assocWidth < $len) {
355                    $assocWidth = $len;
356                }
357            }
358            if (is_array($value) || is_a($value, 'Decompiler_Array')) {
359                $multiline ++;
360            }
361        }
362
363        $i = 0;
364        foreach ($elementsCode as $element) {
365            list($keyCode, $value) = $element;
366            if ($multiline) {
367                if ($i) {
368                    $exp .= ",";
369                }
370                $exp .= "\n";
371                $exp .= $indent;
372            }
373            else {
374                if ($i) {
375                    $exp .= ", ";
376                }
377            }
378
379            if ($assocWidth) {
380                if ($multiline) {
381                    $exp .= sprintf("%-{$assocWidth}s => ", $keyCode);
382                }
383                else {
384                    $exp .= $keyCode . ' => ';
385                }
386            }
387
388            $exp .= $value;
389
390            $i ++;
391        }
392        if ($multiline) {
393            $exp .= "\n$indent)";
394        }
395        else {
396            $exp .= ")";
397        }
398        return $exp;
399    }
400}
401// }}}
402class Decompiler_ConstArray extends Decompiler_Array // {{{
403{
404    function Decompiler_ConstArray($array)
405    {
406        $elements = array();
407        foreach ($array as $key => $value) {
408            $elements[] = array(value($key), value($value));
409        }
410        $this->value = $elements;
411    }
412}
413// }}}
414class Decompiler_ForeachBox extends Decompiler_Box // {{{
415{
416    var $iskey;
417
418    function toCode($indent)
419    {
420        return 'foreach (' . '';
421    }
422}
423// }}}
424
425class Decompiler
426{
427    var $namespace;
428    var $namespaceDecided;
429
430    function Decompiler()
431    {
432        // {{{ opinfo
433        $this->unaryops = array(
434                XC_BW_NOT   => '~',
435                XC_BOOL_NOT => '!',
436                );
437        $this->binops = array(
438                XC_ADD                 => "+",
439                XC_ASSIGN_ADD          => "+=",
440                XC_SUB                 => "-",
441                XC_ASSIGN_SUB          => "-=",
442                XC_MUL                 => "*",
443                XC_ASSIGN_MUL          => "*=",
444                XC_DIV                 => "/",
445                XC_ASSIGN_DIV          => "/=",
446                XC_MOD                 => "%",
447                XC_ASSIGN_MOD          => "%=",
448                XC_SL                  => "<<",
449                XC_ASSIGN_SL           => "<<=",
450                XC_SR                  => ">>",
451                XC_ASSIGN_SR           => ">>=",
452                XC_CONCAT              => ".",
453                XC_ASSIGN_CONCAT       => ".=",
454                XC_IS_IDENTICAL        => "===",
455                XC_IS_NOT_IDENTICAL    => "!==",
456                XC_IS_EQUAL            => "==",
457                XC_IS_NOT_EQUAL        => "!=",
458                XC_IS_SMALLER          => "<",
459                XC_IS_SMALLER_OR_EQUAL => "<=",
460                XC_BW_OR               => "|",
461                XC_ASSIGN_BW_OR        => "|=",
462                XC_BW_AND              => "&",
463                XC_ASSIGN_BW_AND       => "&=",
464                XC_BW_XOR              => "^",
465                XC_ASSIGN_BW_XOR       => "^=",
466                XC_BOOL_XOR            => "xor",
467                );
468        // }}}
469        $this->includeTypes = array( // {{{
470                ZEND_EVAL         => 'eval',
471                ZEND_INCLUDE      => 'include',
472                ZEND_INCLUDE_ONCE => 'include_once',
473                ZEND_REQUIRE      => 'require',
474                ZEND_REQUIRE_ONCE => 'require_once',
475                );
476                // }}}
477    }
478    function detectNamespace($name) // {{{
479    {
480        if ($this->namespaceDecided) {
481            return;
482        }
483
484        if (strpos($name, '\\') !== false) {
485            $this->namespace = strtok($name, '\\');
486            echo 'namespace ', $this->namespace, ";\n\n";
487        }
488
489        $this->namespaceDecided = true;
490    }
491    // }}}
492    function stripNamespace($name) // {{{
493    {
494        $len = strlen($this->namespace) + 1;
495        if (substr($name, 0, $len) == $this->namespace . '\\') {
496            return substr($name, $len);
497        }
498        else {
499            return $name;
500        }
501    }
502    // }}}
503    function outputPhp(&$opcodes, $opline, $last, $indent) // {{{
504    {
505        $origindent = $indent;
506        $curticks = 0;
507        for ($i = $opline; $i <= $last; $i ++) {
508            $op = $opcodes[$i];
509            if (isset($op['php'])) {
510                $toticks = isset($op['ticks']) ? (int) str($op['ticks']) : 0;
511                if ($curticks != $toticks) {
512                    $oldticks = $curticks;
513                    $curticks = $toticks;
514                    if (!$curticks) {
515                        echo $origindent, "}\n\n";
516                        $indent = $origindent;
517                    }
518                    else {
519                        if ($oldticks) {
520                            echo $origindent, "}\n\n";
521                        }
522                        else if (!$oldticks) {
523                            $indent .= INDENT;
524                        }
525                        echo $origindent, "declare (ticks=$curticks) {\n";
526                    }
527                }
528                echo $indent, str($op['php'], $indent), ";\n";
529            }
530        }
531        if ($curticks) {
532            echo $origindent, "}\n";
533        }
534    }
535    // }}}
536    function getOpVal($op, &$EX, $tostr = true, $free = false) // {{{
537    {
538        switch ($op['op_type']) {
539        case XC_IS_CONST:
540            return foldToCode(value($op['constant']), $EX);
541
542        case XC_IS_VAR:
543        case XC_IS_TMP_VAR:
544            $T = &$EX['Ts'];
545            $ret = $T[$op['var']];
546            if ($tostr) {
547                $ret = foldToCode($ret, $EX);
548            }
549            if ($free) {
550                unset($T[$op['var']]);
551            }
552            return $ret;
553
554        case XC_IS_CV:
555            $var = $op['var'];
556            $var = $EX['op_array']['vars'][$var];
557            return '$' . $var['name'];
558
559        case XC_IS_UNUSED:
560            return null;
561        }
562    }
563    // }}}
564    function removeKeyPrefix($array, $prefix) // {{{
565    {
566        $prefixLen = strlen($prefix);
567        $ret = array();
568        foreach ($array as $key => $value) {
569            if (substr($key, 0, $prefixLen) == $prefix) {
570                $key = substr($key, $prefixLen);
571            }
572            $ret[$key] = $value;
573        }
574        return $ret;
575    }
576    // }}}
577    function &fixOpcode($opcodes, $removeTailing = false, $defaultReturnValue = null) // {{{
578    {
579        for ($i = 0, $cnt = count($opcodes); $i < $cnt; $i ++) {
580            if (function_exists('xcache_get_fixed_opcode')) {
581                $opcodes[$i]['opcode'] = xcache_get_fixed_opcode($opcodes[$i]['opcode'], $i);
582            }
583            if (isset($opcodes[$i]['op1'])) {
584                $opcodes[$i]['op1'] = $this->removeKeyPrefix($opcodes[$i]['op1'], 'u.');
585                $opcodes[$i]['op2'] = $this->removeKeyPrefix($opcodes[$i]['op2'], 'u.');
586                $opcodes[$i]['result'] = $this->removeKeyPrefix($opcodes[$i]['result'], 'u.');
587            }
588            else {
589                $op = array(
590                    'op1' => array(),
591                    'op2' => array(),
592                    'op3' => array(),
593                );
594                foreach ($opcodes[$i] as $name => $value) {
595                    if (preg_match('!^(op1|op2|result)\\.(.*)!', $name, $m)) {
596                        list(, $which, $field) = $m;
597                        $op[$which][$field] = $value;
598                    }
599                    else if (preg_match('!^(op1|op2|result)_type$!', $name, $m)) {
600                        list(, $which) = $m;
601                        $op[$which]['op_type'] = $value;
602                    }
603                    else {
604                        $op[$name] = $value;
605                    }
606                }
607                $opcodes[$i] = $op;
608            }
609        }
610
611        if ($removeTailing) {
612            $last = count($opcodes) - 1;
613            if ($opcodes[$last]['opcode'] == XC_HANDLE_EXCEPTION) {
614                unset($opcodes[$last]);
615                --$last;
616            }
617            if ($opcodes[$last]['opcode'] == XC_RETURN) {
618                $op1 = $opcodes[$last]['op1'];
619                if ($op1['op_type'] == XC_IS_CONST && array_key_exists('constant', $op1) && $op1['constant'] === $defaultReturnValue) {
620                    unset($opcodes[$last]);
621                    --$last;
622                }
623            }
624        }
625        return $opcodes;
626    }
627    // }}}
628    function &dop_array($op_array, $indent = '') // {{{
629    {
630        $op_array['opcodes'] = $this->fixOpcode($op_array['opcodes'], true, $indent == '' ? 1 : null);
631        $opcodes = &$op_array['opcodes'];
632        $EX['indent'] = '';
633        // {{{ build jmp array
634        for ($i = 0, $cnt = count($opcodes); $i < $cnt; $i ++) {
635            $op = &$opcodes[$i];
636            /*
637            if ($op['opcode'] == XC_JMPZ) {
638                $this->dumpop($op, $EX);
639                var_dump($op);
640            }
641            continue;
642            */
643            $op['line'] = $i;
644            switch ($op['opcode']) {
645            case XC_GOTO:
646            case XC_JMP:
647                $target = $op['op1']['var'];
648                $op['jmpouts'] = array($target);
649                $opcodes[$target]['jmpins'][] = $i;
650                break;
651
652            case XC_JMPZNZ:
653                $jmpz = $op['op2']['opline_num'];
654                $jmpnz = $op['extended_value'];
655                $op['jmpouts'] = array($jmpz, $jmpnz);
656                $opcodes[$jmpz]['jmpins'][] = $i;
657                $opcodes[$jmpnz]['jmpins'][] = $i;
658                break;
659
660            case XC_JMPZ:
661            case XC_JMPNZ:
662            case XC_JMPZ_EX:
663            case XC_JMPNZ_EX:
664            case XC_JMP_SET:
665            // case XC_FE_RESET:
666            case XC_FE_FETCH:
667            // case XC_JMP_NO_CTOR:
668                $target = $op['op2']['opline_num'];
669                //if (!isset($target)) {
670                //  $this->dumpop($op, $EX);
671                //  var_dump($op); exit;
672                //}
673                $op['jmpouts'] = array($target);
674                $opcodes[$target]['jmpins'][] = $i;
675                break;
676
677            /*
678            case XC_RETURN:
679                $op['jmpouts'] = array();
680                break;
681            */
682            }
683        }
684        unset($op);
685        // }}}
686        // build semi-basic blocks
687        $nextbbs = array();
688        $starti = 0;
689        for ($i = 1, $cnt = count($opcodes); $i < $cnt; $i ++) {
690            if (isset($opcodes[$i]['jmpins'])
691             || isset($opcodes[$i - 1]['jmpouts'])) {
692                $nextbbs[$starti] = $i;
693                $starti = $i;
694            }
695        }
696        $nextbbs[$starti] = $cnt;
697
698        $EX = array();
699        $EX['Ts'] = array();
700        $EX['indent'] = $indent;
701        $EX['nextbbs'] = $nextbbs;
702        $EX['op_array'] = &$op_array;
703        $EX['opcodes'] = &$opcodes;
704        // func call
705        $EX['object'] = null;
706        $EX['called_scope'] = null;
707        $EX['fbc'] = null;
708        $EX['argstack'] = array();
709        $EX['arg_types_stack'] = array();
710        $EX['last'] = count($opcodes) - 1;
711        $EX['silence'] = 0;
712
713        for ($next = 0, $last = $EX['last'];
714                $loop = $this->outputCode($EX, $next, $last, $indent, true);
715                list($next, $last) = $loop) {
716            // empty
717        }
718        return $EX;
719    }
720    // }}}
721    function outputCode(&$EX, $opline, $last, $indent, $loop = false) // {{{
722    {
723        $op = &$EX['opcodes'][$opline];
724        $next = $EX['nextbbs'][$opline];
725
726        $end = $next - 1;
727        if ($end > $last) {
728            $end = $last;
729        }
730
731        if (isset($op['jmpins'])) {
732            echo "\nline", $op['line'], ":\n";
733        }
734        else {
735            // echo ";;;\n";
736        }
737        $this->dasmBasicBlock($EX, $opline, $end);
738        $this->outputPhp($EX['opcodes'], $opline, $end, $indent);
739        // jmpout op
740        $op = &$EX['opcodes'][$end];
741        $op1 = $op['op1'];
742        $op2 = $op['op2'];
743        $ext = $op['extended_value'];
744        $line = $op['line'];
745
746        if (isset($EX['opcodes'][$next])) {
747            if (isset($last) && $next > $last) {
748                $next = null;
749            }
750        }
751        else {
752            $next = null;
753        }
754        if ($op['opcode'] == XC_FE_FETCH) {
755            $opline = $next;
756            $next = $op['op2']['opline_num'];
757            $end = $next - 1;
758
759            ob_start();
760            $this->outputCode($EX, $opline, $end /* - 1 skip last jmp */, $indent . INDENT);
761            $body = ob_get_clean();
762
763            $as = foldToCode($op['fe_as'], $EX);
764            if (isset($op['fe_key'])) {
765                $as = str($op['fe_key'], $EX) . ' => ' . str($as);
766            }
767            echo "{$indent}foreach (" . str($op['fe_src'], $EX) . " as $as) {\n";
768            echo $body;
769            echo "{$indent}}";
770            // $this->outputCode($EX, $next, $last, $indent);
771            // return;
772        }
773        /*
774        if ($op['opcode'] == XC_JMPZ) {
775            $target = $op2['opline_num'];
776            if ($line + 1) {
777                $nextblock = $EX['nextbbs'][$next];
778                $jmpop = end($nextblock);
779                if ($jmpop['opcode'] == XC_JMP) {
780                    $ifendline = $op2['opline_num'];
781                    if ($ifendline >= $line) {
782                        $cond = $op['cond'];
783                        echo "{$indent}if ($cond) {\n";
784                        $this->outputCode($EX, $next, $last, INDENT . $indent);
785                        echo "$indent}\n";
786                        $this->outputCode($EX, $target, $last, $indent);
787                        return;
788                    }
789                }
790            }
791        }
792        */
793        if (!isset($next)) {
794            return;
795        }
796        if (!empty($op['jmpouts']) && isset($op['isjmp'])) {
797            if (isset($op['cond'])) {
798                echo "{$indent}check (" . str($op["cond"]) . ") {\n";
799                echo INDENT;
800            }
801            echo $indent;
802            echo xcache_get_opcode($op['opcode']), ' line', $op['jmpouts'][0];
803            if (isset($op['jmpouts'][1])) {
804                echo ', line', $op['jmpouts'][1];
805            }
806            echo ";";
807            // echo ' // <- line', $op['line'];
808            echo "\n";
809            if (isset($op['cond'])) echo "$indent}\n";
810        }
811
812        // proces JMPZ_EX/JMPNZ_EX for AND,OR
813        $op = &$EX['opcodes'][$next];
814        /*
815        if (isset($op['jmpins'])) {
816            foreach (array_reverse($op['jmpins']) as $fromline) {
817                $fromop = $EX['opcodes'][$fromline];
818                switch ($fromop['opcode']) {
819                case XC_JMPZ_EX: $opstr = 'and'; break;
820                case XC_JMPNZ_EX: $opstr = 'or'; break;
821                case XC_JMPZNZ: var_dump($fromop); exit;
822                default: continue 2;
823                }
824
825                $var = $fromop['result']['var'];
826                var_dump($EX['Ts'][$var]);
827                $EX['Ts'][$var] = '(' . $fromop['and_or'] . " $opstr " . $EX['Ts'][$var] . ')';
828            }
829            #$this->outputCode($EX, $next, $last, $indent);
830            #return;
831        }
832        */
833        if (isset($op['cond_false'])) {
834            // $this->dumpop($op, $EX);
835            // any true comes here, so it's a "or"
836            $cond = implode(' and ', str($op['cond_false']));
837            // var_dump($op['cond'] = $cond);
838            /*
839            $rvalue = implode(' or ', $op['cond_true']) . ' or ' . $rvalue;
840            unset($op['cond_true']);
841            */
842        }
843
844        if ($loop) {
845            return array($next, $last);
846        }
847        $this->outputCode($EX, $next, $last, $indent);
848    }
849    // }}}
850    function dasmBasicBlock(&$EX, $opline, $last) // {{{
851    {
852        $T = &$EX['Ts'];
853        $opcodes = &$EX['opcodes'];
854        $lastphpop = null;
855
856        for ($i = $opline, $ic = $last + 1; $i < $ic; $i ++) {
857            // {{{ prepair
858            $op = &$opcodes[$i];
859            $opc = $op['opcode'];
860            if ($opc == XC_NOP) {
861                continue;
862            }
863
864            $op1 = $op['op1'];
865            $op2 = $op['op2'];
866            $res = $op['result'];
867            $ext = $op['extended_value'];
868
869            $opname = xcache_get_opcode($opc);
870
871            if ($opname == 'UNDEF' || !isset($opname)) {
872                echo 'UNDEF OP:';
873                $this->dumpop($op, $EX);
874                continue;
875            }
876            // $this->dumpop($op, $EX); //var_dump($op);
877
878            $resvar = null;
879            if ((ZEND_ENGINE_2_4 ? ($res['op_type'] & EXT_TYPE_UNUSED) : ($res['EA.type'] & EXT_TYPE_UNUSED)) || $res['op_type'] == XC_IS_UNUSED) {
880                $istmpres = false;
881            }
882            else {
883                $istmpres = true;
884            }
885            // }}}
886            // echo $opname, "\n";
887
888            $call = array(&$this, $opname);
889            if (is_callable($call)) {
890                $this->{$opname}($op, $EX);
891            }
892            else if (isset($this->binops[$opc])) { // {{{
893                $op1val = $this->getOpVal($op1, $EX, false);
894                $op2val = $this->getOpVal($op2, $EX, false);
895                $rvalue = new Decompiler_Binop($this, $op1val, $opc, $op2val);
896                $resvar = $rvalue;
897                // }}}
898            }
899            else if (isset($this->unaryops[$opc])) { // {{{
900                $op1val = $this->getOpVal($op1, $EX);
901                $myop = $this->unaryops[$opc];
902                $rvalue = "$myop$op1val";
903                $resvar = $rvalue;
904                // }}}
905            }
906            else {
907                switch ($opc) {
908                case XC_NEW: // {{{
909                    array_push($EX['arg_types_stack'], array($EX['fbc'], $EX['object'], $EX['called_scope']));
910                    $EX['object'] = (int) $res['var'];
911                    $EX['called_scope'] = null;
912                    $EX['fbc'] = 'new ' . unquoteName($this->getOpVal($op1, $EX), $EX);
913                    if (!ZEND_ENGINE_2) {
914                        $resvar = '$new object$';
915                    }
916                    break;
917                    // }}}
918                case XC_THROW: // {{{
919                    $resvar = 'throw ' . str($this->getOpVal($op1, $EX));
920                    break;
921                    // }}}
922                case XC_CLONE: // {{{
923                    $resvar = 'clone ' . str($this->getOpVal($op1, $EX));
924                    break;
925                    // }}}
926                case XC_CATCH: // {{{
927                    $resvar = 'catch (' . str($this->getOpVal($op1, $EX)) . ' ' . str($this->getOpVal($op2, $EX)) . ')';
928                    break;
929                    // }}}
930                case XC_INSTANCEOF: // {{{
931                    $resvar = str($this->getOpVal($op1, $EX)) . ' instanceof ' . str($this->getOpVal($op2, $EX));
932                    break;
933                    // }}}
934                case XC_FETCH_CLASS: // {{{
935                    if ($op2['op_type'] == XC_IS_UNUSED) {
936                        switch (($ext & (defined('ZEND_FETCH_CLASS_MASK') ? ZEND_FETCH_CLASS_MASK : 0xFF))) {
937                        case ZEND_FETCH_CLASS_SELF:
938                            $class = 'self';
939                            break;
940                        case ZEND_FETCH_CLASS_PARENT:
941                            $class = 'parent';
942                            break;
943                        case ZEND_FETCH_CLASS_STATIC:
944                            $class = 'static';
945                            break;
946                        }
947                        $istmpres = true;
948                    }
949                    else {
950                        $class = $this->getOpVal($op2, $EX);
951                        if (isset($op2['constant'])) {
952                            $class = $this->stripNamespace(unquoteName($class));
953                        }
954                    }
955                    $resvar = $class;
956                    break;
957                    // }}}
958                case XC_FETCH_CONSTANT: // {{{
959                    if ($op1['op_type'] == XC_IS_UNUSED) {
960                        $resvar = $this->stripNamespace($op2['constant']);
961                        break;
962                    }
963
964                    if ($op1['op_type'] == XC_IS_CONST) {
965                        $resvar = $this->stripNamespace($op1['constant']);
966                    }
967                    else {
968                        $resvar = $this->getOpVal($op1, $EX);
969                    }
970
971                    $resvar = str($resvar) . '::' . unquoteName($this->getOpVal($op2, $EX));
972                    break;
973                    // }}}
974                    // {{{ case XC_FETCH_*
975                case XC_FETCH_R:
976                case XC_FETCH_W:
977                case XC_FETCH_RW:
978                case XC_FETCH_FUNC_ARG:
979                case XC_FETCH_UNSET:
980                case XC_FETCH_IS:
981                case XC_UNSET_VAR:
982                    $rvalue = $this->getOpVal($op1, $EX);
983                    if (defined('ZEND_FETCH_TYPE_MASK')) {
984                        $fetchtype = ($ext & ZEND_FETCH_TYPE_MASK);
985                    }
986                    else {
987                        $fetchtype = $op2[!ZEND_ENGINE_2 ? 'fetch_type' : 'EA.type'];
988                    }
989                    switch ($fetchtype) {
990                    case ZEND_FETCH_STATIC_MEMBER:
991                        $class = $this->getOpVal($op2, $EX);
992                        $rvalue = str($class) . '::$' . unquoteName($rvalue, $EX);
993                        break;
994                    default:
995                        $name = unquoteName($rvalue, $EX);
996                        $globalname = xcache_is_autoglobal($name) ? "\$$name" : "\$GLOBALS[" . str($rvalue) . "]";
997                        $rvalue = new Decompiler_Fetch($rvalue, $fetchtype, $globalname);
998                        break;
999                    }
1000                    if ($opc == XC_UNSET_VAR) {
1001                        $op['php'] = "unset(" . str($rvalue, $EX) . ")";
1002                        $lastphpop = &$op;
1003                    }
1004                    else if ($res['op_type'] != XC_IS_UNUSED) {
1005                        $resvar = $rvalue;
1006                    }
1007                    break;
1008                    // }}}
1009                    // {{{ case XC_FETCH_DIM_*
1010                case XC_FETCH_DIM_TMP_VAR:
1011                case XC_FETCH_DIM_R:
1012                case XC_FETCH_DIM_W:
1013                case XC_FETCH_DIM_RW:
1014                case XC_FETCH_DIM_FUNC_ARG:
1015                case XC_FETCH_DIM_UNSET:
1016                case XC_FETCH_DIM_IS:
1017                case XC_ASSIGN_DIM:
1018                case XC_UNSET_DIM_OBJ: // PHP 4 only
1019                case XC_UNSET_DIM:
1020                case XC_UNSET_OBJ:
1021                    $src = $this->getOpVal($op1, $EX, false);
1022                    if (is_a($src, "Decompiler_ForeachBox")) {
1023                        $src->iskey = $this->getOpVal($op2, $EX);
1024                        $resvar = $src;
1025                        break;
1026                    }
1027
1028                    if (is_a($src, "Decompiler_DimBox")) {
1029                        $dimbox = $src;
1030                    }
1031                    else {
1032                        if (!is_a($src, "Decompiler_ListBox")) {
1033                            $op1val = $this->getOpVal($op1, $EX, false);
1034                            $list = new Decompiler_List(isset($op1val) ? $op1val : '$this');
1035
1036                            $src = new Decompiler_ListBox($list);
1037                            if (!isset($op1['var'])) {
1038                                $this->dumpop($op, $EX);
1039                                var_dump($op);
1040                                die('missing var');
1041                            }
1042                            $T[$op1['var']] = $src;
1043                            unset($list);
1044                        }
1045                        $dim = new Decompiler_Dim($src);
1046                        $src->obj->dims[] = &$dim;
1047
1048                        $dimbox = new Decompiler_DimBox($dim);
1049                    }
1050                    $dim = &$dimbox->obj;
1051                    $dim->offsets[] = $this->getOpVal($op2, $EX);
1052                    if ($ext == ZEND_FETCH_ADD_LOCK) {
1053                        $src->obj->everLocked = true;
1054                    }
1055                    else if ($ext == ZEND_FETCH_STANDARD) {
1056                        $dim->isLast = true;
1057                    }
1058                    if ($opc == XC_UNSET_OBJ) {
1059                        $dim->isObject = true;
1060                    }
1061                    unset($dim);
1062                    $rvalue = $dimbox;
1063                    unset($dimbox);
1064
1065                    if ($opc == XC_ASSIGN_DIM) {
1066                        $lvalue = $rvalue;
1067                        ++ $i;
1068                        $rvalue = $this->getOpVal($opcodes[$i]['op1'], $EX);
1069                        $resvar = str($lvalue, $EX) . ' = ' . str($rvalue);
1070                    }
1071                    else if ($opc == XC_UNSET_DIM || $opc == XC_UNSET_OBJ) {
1072                        $op['php'] = "unset(" . str($rvalue, $EX) . ")";
1073                        $lastphpop = &$op;
1074                    }
1075                    else if ($res['op_type'] != XC_IS_UNUSED) {
1076                        $resvar = $rvalue;
1077                    }
1078                    break;
1079                    // }}}
1080                case XC_ASSIGN: // {{{
1081                    $lvalue = $this->getOpVal($op1, $EX);
1082                    $rvalue = $this->getOpVal($op2, $EX, false);
1083                    if (is_a($rvalue, 'Decompiler_ForeachBox')) {
1084                        $type = $rvalue->iskey ? 'fe_key' : 'fe_as';
1085                        $rvalue->obj[$type] = $lvalue;
1086                        unset($T[$op2['var']]);
1087                        break;
1088                    }
1089                    if (is_a($rvalue, "Decompiler_DimBox")) {
1090                        $dim = &$rvalue->obj;
1091                        $dim->assign = $lvalue;
1092                        if ($dim->isLast) {
1093                            $resvar = foldToCode($dim->value, $EX);
1094                        }
1095                        unset($dim);
1096                        break;
1097                    }
1098                    $resvar = "$lvalue = " . str($rvalue, $EX);
1099                    break;
1100                    // }}}
1101                case XC_ASSIGN_REF: // {{{
1102                    $lvalue = $this->getOpVal($op1, $EX);
1103                    $rvalue = $this->getOpVal($op2, $EX, false);
1104                    if (is_a($rvalue, 'Decompiler_Fetch')) {
1105                        $src = str($rvalue->src, $EX);
1106                        if ('$' . unquoteName($src) == $lvalue) {
1107                            switch ($rvalue->fetchType) {
1108                            case ZEND_FETCH_GLOBAL:
1109                            case ZEND_FETCH_GLOBAL_LOCK:
1110                                $resvar = 'global ' . $lvalue;
1111                                break 2;
1112                            case ZEND_FETCH_STATIC:
1113                                $statics = &$EX['op_array']['static_variables'];
1114                                $resvar = 'static ' . $lvalue;
1115                                $name = unquoteName($src);
1116                                if (isset($statics[$name])) {
1117                                    $var = $statics[$name];
1118                                    $resvar .= ' = ';
1119                                    $resvar .= str(value($var), $EX);
1120                                }
1121                                unset($statics);
1122                                break 2;
1123                            default:
1124                            }
1125                        }
1126                    }
1127                    // TODO: PHP_6 global
1128                    $rvalue = str($rvalue, $EX);
1129                    $resvar = "$lvalue = &$rvalue";
1130                    break;
1131                    // }}}
1132                // {{{ case XC_FETCH_OBJ_*
1133                case XC_FETCH_OBJ_R:
1134                case XC_FETCH_OBJ_W:
1135                case XC_FETCH_OBJ_RW:
1136                case XC_FETCH_OBJ_FUNC_ARG:
1137                case XC_FETCH_OBJ_UNSET:
1138                case XC_FETCH_OBJ_IS:
1139                case XC_ASSIGN_OBJ:
1140                    $obj = $this->getOpVal($op1, $EX);
1141                    if (!isset($obj)) {
1142                        $obj = '$this';
1143                    }
1144                    $rvalue = str($obj) . "->" . unquoteProperty($this->getOpVal($op2, $EX), $EX);
1145                    if ($res['op_type'] != XC_IS_UNUSED) {
1146                        $resvar = $rvalue;
1147                    }
1148                    if ($opc == XC_ASSIGN_OBJ) {
1149                        ++ $i;
1150                        $lvalue = $rvalue;
1151                        $rvalue = $this->getOpVal($opcodes[$i]['op1'], $EX);
1152                        $resvar = "$lvalue = " . str($rvalue);
1153                    }
1154                    break;
1155                    // }}}
1156                case XC_ISSET_ISEMPTY_DIM_OBJ:
1157                case XC_ISSET_ISEMPTY_PROP_OBJ:
1158                case XC_ISSET_ISEMPTY:
1159                case XC_ISSET_ISEMPTY_VAR: // {{{
1160                    if ($opc == XC_ISSET_ISEMPTY_VAR) {
1161                        $rvalue = $this->getOpVal($op1, $EX);;
1162                        if (preg_match($this->rQuotedName, $rvalue)) {
1163                            $rvalue = '$' . substr($rvalue, 1, -1);
1164                        }
1165                        else {
1166                            $rvalue = '${' . $rvalue . '}';
1167                        }
1168                        if ($op2['EA.type'] == ZEND_FETCH_STATIC_MEMBER) {
1169                            $class = $this->getOpVal($op2, $EX);
1170                            $rvalue = $class . '::' . $rvalue;
1171                        }
1172                    }
1173                    else if ($opc == XC_ISSET_ISEMPTY) {
1174                        $rvalue = $this->getOpVal($op1, $EX);
1175                    }
1176                    else {
1177                        $container = $this->getOpVal($op1, $EX);
1178                        $dim = $this->getOpVal($op2, $EX);
1179                        if ($opc == XC_ISSET_ISEMPTY_PROP_OBJ) {
1180                            if (preg_match($this->rQuotedName, $dim)) {
1181                                $rvalue = $container . "->" . substr($dim, 1, -1);
1182                            }
1183                            else {
1184                                $rvalue = $container . "->{" . $dim . "}";
1185                            }
1186                        }
1187                        else {
1188                            $rvalue = $container . "[$dim]";
1189                        }
1190                    }
1191
1192                    switch ((!ZEND_ENGINE_2 ? $op['op2']['var'] /* constant */ : $ext) & (ZEND_ISSET|ZEND_ISEMPTY)) {
1193                    case ZEND_ISSET:
1194                        $rvalue = "isset($rvalue)";
1195                        break;
1196                    case ZEND_ISEMPTY:
1197                        $rvalue = "empty($rvalue)";
1198                        break;
1199                    }
1200                    $resvar = $rvalue;
1201                    break;
1202                    // }}}
1203                case XC_SEND_VAR_NO_REF:
1204                case XC_SEND_VAL:
1205                case XC_SEND_REF:
1206                case XC_SEND_VAR: // {{{
1207                    $ref = ($opc == XC_SEND_REF ? '&' : '');
1208                    $EX['argstack'][] = $ref . str($this->getOpVal($op1, $EX));
1209                    break;
1210                    // }}}
1211                case XC_INIT_STATIC_METHOD_CALL:
1212                case XC_INIT_METHOD_CALL: // {{{
1213                    array_push($EX['arg_types_stack'], array($EX['fbc'], $EX['object'], $EX['called_scope']));
1214                    if ($opc == XC_INIT_STATIC_METHOD_CALL || $opc == XC_INIT_METHOD_CALL || $op1['op_type'] != XC_IS_UNUSED) {
1215                        $obj = $this->getOpVal($op1, $EX);
1216                        if (!isset($obj)) {
1217                            $obj = '$this';
1218                        }
1219                        if ($opc == XC_INIT_STATIC_METHOD_CALL || /* PHP4 */ isset($op1['constant'])) {
1220                            $EX['object'] = null;
1221                            $EX['called_scope'] = $this->stripNamespace(unquoteName($obj, $EX));
1222                        }
1223                        else {
1224                            $EX['object'] = $obj;
1225                            $EX['called_scope'] = null;
1226                        }
1227                        if ($res['op_type'] != XC_IS_UNUSED) {
1228                            $resvar = '$obj call$';
1229                        }
1230                    }
1231                    else {
1232                        $EX['object'] = null;
1233                        $EX['called_scope'] = null;
1234                    }
1235
1236                    $EX['fbc'] = $this->getOpVal($op2, $EX, false);
1237                    if (($opc == XC_INIT_STATIC_METHOD_CALL || $opc == XC_INIT_METHOD_CALL) && !isset($EX['fbc'])) {
1238                        $EX['fbc'] = '__construct';
1239                    }
1240                    break;
1241                    // }}}
1242                case XC_INIT_NS_FCALL_BY_NAME:
1243                case XC_INIT_FCALL_BY_NAME: // {{{
1244                    array_push($EX['arg_types_stack'], array($EX['fbc'], $EX['object'], $EX['called_scope']));
1245                    if (!ZEND_ENGINE_2 && ($ext & ZEND_CTOR_CALL)) {
1246                        break;
1247                    }
1248                    $EX['object'] = null;
1249                    $EX['called_scope'] = null;
1250                    $EX['fbc'] = $this->getOpVal($op2, $EX);
1251                    break;
1252                    // }}}
1253                case XC_INIT_FCALL_BY_FUNC: // {{{ deprecated even in PHP 4?
1254                    $EX['object'] = null;
1255                    $EX['called_scope'] = null;
1256                    $which = $op1['var'];
1257                    $EX['fbc'] = $EX['op_array']['funcs'][$which]['name'];
1258                    break;
1259                    // }}}
1260                case XC_DO_FCALL_BY_FUNC:
1261                    $which = $op1['var'];
1262                    $fname = $EX['op_array']['funcs'][$which]['name'];
1263                    $args = $this->popargs($EX, $ext);
1264                    $resvar = $fname . "($args)";
1265                    break;
1266                case XC_DO_FCALL:
1267                    $fname = unquoteName($this->getOpVal($op1, $EX, false), $EX);
1268                    $args = $this->popargs($EX, $ext);
1269                    $resvar = $fname . "($args)";
1270                    break;
1271                case XC_DO_FCALL_BY_NAME: // {{{
1272                    $object = null;
1273
1274                    $fname = unquoteName($EX['fbc'], $EX);
1275                    if (!is_int($EX['object'])) {
1276                        $object = $EX['object'];
1277                    }
1278
1279                    $args = $this->popargs($EX, $ext);
1280
1281                    $prefix = (isset($object) ? $object . '->' : '' )
1282                        . (isset($EX['called_scope']) ? $EX['called_scope'] . '::' : '' );
1283                    $resvar = $prefix
1284                        . (!$prefix ? $this->stripNamespace($fname) : $fname)
1285                        . "($args)";
1286                    unset($args);
1287
1288                    if (is_int($EX['object'])) {
1289                        $T[$EX['object']] = $resvar;
1290                        $resvar = null;
1291                    }
1292                    list($EX['fbc'], $EX['object'], $EX['called_scope']) = array_pop($EX['arg_types_stack']);
1293                    break;
1294                    // }}}
1295                case XC_VERIFY_ABSTRACT_CLASS: // {{{
1296                    //unset($T[$op1['var']]);
1297                    break;
1298                    // }}}
1299                case XC_DECLARE_CLASS: 
1300                case XC_DECLARE_INHERITED_CLASS:
1301                case XC_DECLARE_INHERITED_CLASS_DELAYED: // {{{
1302                    $key = $op1['constant'];
1303                    if (!isset($this->dc['class_table'][$key])) {
1304                        echo 'class not found: ', $key, 'existing classes are:', "\n";
1305                        var_dump(array_keys($this->dc['class_table']));
1306                        exit;
1307                    }
1308                    $class = &$this->dc['class_table'][$key];
1309                    if (!isset($class['name'])) {
1310                        $class['name'] = unquoteName($this->getOpVal($op2, $EX), $EX);
1311                    }
1312                    if ($opc == XC_DECLARE_INHERITED_CLASS || $opc == XC_DECLARE_INHERITED_CLASS_DELAYED) {
1313                        $ext /= XC_SIZEOF_TEMP_VARIABLE;
1314                        $class['parent'] = $T[$ext];
1315                        unset($T[$ext]);
1316                    }
1317                    else {
1318                        $class['parent'] = null;
1319                    }
1320
1321                    for (;;) {
1322                        if ($i + 1 < $ic
1323                         && $opcodes[$i + 1]['opcode'] == XC_ADD_INTERFACE
1324                         && $opcodes[$i + 1]['op1']['var'] == $res['var']) {
1325                            // continue
1326                        }
1327                        else if ($i + 2 < $ic
1328                         && $opcodes[$i + 2]['opcode'] == XC_ADD_INTERFACE
1329                         && $opcodes[$i + 2]['op1']['var'] == $res['var']
1330                         && $opcodes[$i + 1]['opcode'] == XC_FETCH_CLASS) {
1331                            // continue
1332                        }
1333                        else {
1334                            break;
1335                        }
1336
1337                        $fetchop = &$opcodes[$i + 1];
1338                        $interface = $this->stripNamespace(unquoteName($this->getOpVal($fetchop['op2'], $EX), $EX));
1339                        $addop = &$opcodes[$i + 2];
1340                        $class['interfaces'][$addop['extended_value']] = $interface;
1341                        unset($fetchop, $addop);
1342                        $i += 2;
1343                    }
1344                    $this->dclass($class);
1345                    echo "\n";
1346                    unset($class);
1347                    break;
1348                    // }}}
1349                case XC_INIT_STRING: // {{{
1350                    $resvar = "''";
1351                    break;
1352                    // }}}
1353                case XC_ADD_CHAR:
1354                case XC_ADD_STRING:
1355                case XC_ADD_VAR: // {{{
1356                    $op1val = $this->getOpVal($op1, $EX);
1357                    $op2val = $this->getOpVal($op2, $EX);
1358                    switch ($opc) {
1359                    case XC_ADD_CHAR:
1360                        $op2val = value(chr(str($op2val)));
1361                        break;
1362                    case XC_ADD_STRING:
1363                        break;
1364                    case XC_ADD_VAR:
1365                        break;
1366                    }
1367                    if (str($op1val) == "''") {
1368                        $rvalue = $op2val;
1369                    }
1370                    else if (str($op2val) == "''") {
1371                        $rvalue = $op1val;
1372                    }
1373                    else {
1374                        $rvalue = str($op1val) . ' . ' . str($op2val);
1375                    }
1376                    $resvar = $rvalue;
1377                    // }}}
1378                    break;
1379                case XC_PRINT: // {{{
1380                    $op1val = $this->getOpVal($op1, $EX);
1381                    $resvar = "print($op1val)";
1382                    break;
1383                    // }}}
1384                case XC_ECHO: // {{{
1385                    $op1val = $this->getOpVal($op1, $EX);
1386                    $resvar = "echo " . str($op1val);
1387                    break;
1388                    // }}}
1389                case XC_EXIT: // {{{
1390                    $op1val = $this->getOpVal($op1, $EX);
1391                    $resvar = "exit($op1val)";
1392                    break;
1393                    // }}}
1394                case XC_INIT_ARRAY:
1395                case XC_ADD_ARRAY_ELEMENT: // {{{
1396                    $rvalue = $this->getOpVal($op1, $EX, false, true);
1397
1398                    if ($opc == XC_ADD_ARRAY_ELEMENT) {
1399                        $assoc = $this->getOpVal($op2, $EX);
1400                        if (isset($assoc)) {
1401                            $T[$res['var']]->value[] = array($assoc, $rvalue);
1402                        }
1403                        else {
1404                            $T[$res['var']]->value[] = array(null, $rvalue);
1405                        }
1406                    }
1407                    else {
1408                        if ($opc == XC_INIT_ARRAY) {
1409                            $resvar = new Decompiler_Array();
1410                            if (!isset($rvalue)) {
1411                                continue;
1412                            }
1413                        }
1414
1415                        $assoc = $this->getOpVal($op2, $EX);
1416                        if (isset($assoc)) {
1417                            $resvar->value[] = array($assoc, $rvalue);
1418                        }
1419                        else {
1420                            $resvar->value[] = array(null, $rvalue);
1421                        }
1422                    }
1423                    break;
1424                    // }}}
1425                case XC_QM_ASSIGN: // {{{
1426                    $resvar = $this->getOpVal($op1, $EX);
1427                    break;
1428                    // }}}
1429                case XC_BOOL: // {{{
1430                    $resvar = /*'(bool) ' .*/ $this->getOpVal($op1, $EX);
1431                    break;
1432                    // }}}
1433                case XC_RETURN: // {{{
1434                    $resvar = "return " . str($this->getOpVal($op1, $EX));
1435                    break;
1436                    // }}}
1437                case XC_INCLUDE_OR_EVAL: // {{{
1438                    $type = $op2['var']; // hack
1439                    $keyword = $this->includeTypes[$type];
1440                    $resvar = "$keyword " . str($this->getOpVal($op1, $EX));
1441                    break;
1442                    // }}}
1443                case XC_FE_RESET: // {{{
1444                    $resvar = $this->getOpVal($op1, $EX);
1445                    break;
1446                    // }}}
1447                case XC_FE_FETCH: // {{{
1448                    $op['fe_src'] = $this->getOpVal($op1, $EX);
1449                    $fe = new Decompiler_ForeachBox($op);
1450                    $fe->iskey = false;
1451                    $T[$res['var']] = $fe;
1452
1453                    ++ $i;
1454                    if (($ext & ZEND_FE_FETCH_WITH_KEY)) {
1455                        $fe = new Decompiler_ForeachBox($op);
1456                        $fe->iskey = true;
1457
1458                        $res = $opcodes[$i]['result'];
1459                        $T[$res['var']] = $fe;
1460                    }
1461                    break;
1462                    // }}}
1463                case XC_SWITCH_FREE: // {{{
1464                    // unset($T[$op1['var']]);
1465                    break;
1466                    // }}}
1467                case XC_FREE: // {{{
1468                    $free = $T[$op1['var']];
1469                    if (!is_a($free, 'Decompiler_Array') && !is_a($free, 'Decompiler_Box')) {
1470                        $op['php'] = is_object($free) ? $free : $this->unquote($free, '(', ')');
1471                        $lastphpop = &$op;
1472                    }
1473                    unset($T[$op1['var']], $free);
1474                    break;
1475                    // }}}
1476                case XC_JMP_NO_CTOR:
1477                    break;
1478                case XC_JMP_SET: // ?:
1479                case XC_JMPNZ: // while
1480                case XC_JMPZNZ: // for
1481                case XC_JMPZ_EX: // and
1482                case XC_JMPNZ_EX: // or
1483                case XC_JMPZ: // {{{
1484                    if ($opc == XC_JMP_NO_CTOR && $EX['object']) {
1485                        $rvalue = $EX['object'];
1486                    }
1487                    else {
1488                        $rvalue = $this->getOpVal($op1, $EX);
1489                    }
1490
1491                    if (isset($op['cond_true'])) {
1492                        // any true comes here, so it's a "or"
1493                        $rvalue = implode(' or ', $op['cond_true']) . ' or ' . $rvalue;
1494                        unset($op['cond_true']);
1495                    }
1496                    if (isset($op['cond_false'])) {
1497                        echo "TODO(cond_false):\n";
1498                        var_dump($op);// exit;
1499                    }
1500                    if ($opc == XC_JMPZ_EX || $opc == XC_JMPNZ_EX || $opc == XC_JMPZ) {
1501                        $targetop = &$EX['opcodes'][$op2['opline_num']];
1502                        if ($opc == XC_JMPNZ_EX) {
1503                            $targetop['cond_true'][] = foldToCode($rvalue, $EX);
1504                        }
1505                        else {
1506                            $targetop['cond_false'][] = foldToCode($rvalue, $EX);
1507                        }
1508                        unset($targetop);
1509                    }
1510                    else {
1511                        $op['cond'] = $rvalue; 
1512                        $op['isjmp'] = true;
1513                    }
1514                    break;
1515                    // }}}
1516                case XC_GOTO:
1517                case XC_JMP: // {{{
1518                    $op['cond'] = null;
1519                    $op['isjmp'] = true;
1520                    break;
1521                    // }}}
1522                case XC_CASE:
1523                    $switchValue = $this->getOpVal($op1, $EX);
1524                    $caseValue = $this->getOpVal($op2, $EX);
1525                    $resvar = str($switchValue) . ' == ' . str($caseValue);
1526                    break;
1527                case XC_BRK:
1528                    break;
1529                case XC_RECV_INIT:
1530                case XC_RECV:
1531                    $offset = $this->getOpVal($op1, $EX);
1532                    $lvalue = $this->getOpVal($op['result'], $EX);
1533                    if ($opc == XC_RECV_INIT) {
1534                        $default = value($op['op2']['constant']);
1535                    }
1536                    else {
1537                        $default = null;
1538                    }
1539                    $EX['recvs'][str($offset)] = array($lvalue, $default);
1540                    break;
1541                case XC_POST_DEC:
1542                case XC_POST_INC:
1543                case XC_POST_DEC_OBJ:
1544                case XC_POST_INC_OBJ:
1545                case XC_PRE_DEC:
1546                case XC_PRE_INC:
1547                case XC_PRE_DEC_OBJ:
1548                case XC_PRE_INC_OBJ: // {{{
1549                    $flags = array_flip(explode('_', $opname));
1550                    if (isset($flags['OBJ'])) {
1551                        $resvar = $this->getOpVal($op1, $EX) . '->' . unquoteProperty($this->getOpVal($op2, $EX), $EX);
1552                    }
1553                    else {
1554                        $resvar = $this->getOpVal($op1, $EX);
1555                    }
1556                    $opstr = isset($flags['DEC']) ? '--' : '++';
1557                    if (isset($flags['POST'])) {
1558                        $resvar .= $opstr;
1559                    }
1560                    else {
1561                        $resvar = "$opstr$resvar";
1562                    }
1563                    break;
1564                    // }}}
1565
1566                case XC_BEGIN_SILENCE: // {{{
1567                    $EX['silence'] ++;
1568                    break;
1569                    // }}}
1570                case XC_END_SILENCE: // {{{
1571                    $EX['silence'] --;
1572                    $lastresvar = '@' . str($lastresvar, $EX);
1573                    break;
1574                    // }}}
1575                case XC_CONT: // {{{
1576                    break;
1577                    // }}}
1578                case XC_CAST: // {{{
1579                    $type = $ext;
1580                    static $type2cast = array(
1581                            IS_LONG   => '(int)',
1582                            IS_DOUBLE => '(double)',
1583                            IS_STRING => '(string)',
1584                            IS_ARRAY  => '(array)',
1585                            IS_OBJECT => '(object)',
1586                            IS_BOOL   => '(bool)',
1587                            IS_NULL   => '(unset)',
1588                            );
1589                    assert(isset($type2cast[$type]));
1590                    $cast = $type2cast[$type];
1591                    $resvar = $cast . ' ' . $this->getOpVal($op1, $EX);
1592                    break;
1593                    // }}}
1594                case XC_EXT_STMT:
1595                case XC_EXT_FCALL_BEGIN:
1596                case XC_EXT_FCALL_END:
1597                case XC_EXT_NOP:
1598                    break;
1599                case XC_DECLARE_FUNCTION:
1600                    $this->dfunction($this->dc['function_table'][$op1['constant']], $EX['indent']);
1601                    break;
1602                case XC_DECLARE_LAMBDA_FUNCTION: // {{{
1603                    ob_start();
1604                    $this->dfunction($this->dc['function_table'][$op1['constant']], $EX['indent']);
1605                    $resvar = ob_get_clean();
1606                    $istmpres = true;
1607                    break;
1608                    // }}}
1609                case XC_DECLARE_CONST:
1610                    $name = $this->stripNamespace(unquoteName($this->getOpVal($op1, $EX), $EX));
1611                    $value = str($this->getOpVal($op2, $EX));
1612                    $resvar = 'const ' . $name . ' = ' . $value;
1613                    break;
1614                case XC_DECLARE_FUNCTION_OR_CLASS:
1615                    /* always removed by compiler */
1616                    break;
1617                case XC_TICKS:
1618                    $lastphpop['ticks'] = $this->getOpVal($op1, $EX);
1619                    // $EX['tickschanged'] = true;
1620                    break;
1621                case XC_RAISE_ABSTRACT_ERROR:
1622                    // abstract function body is empty, don't need this code
1623                    break;
1624                case XC_USER_OPCODE:
1625                    echo '// ZEND_USER_OPCODE, impossible to decompile';
1626                    break;
1627                case XC_OP_DATA:
1628                    break;
1629                default: // {{{
1630                    echo "\x1B[31m * TODO ", $opname, "\x1B[0m\n";
1631                    // }}}
1632                }
1633            }
1634            if (isset($resvar)) {
1635                if ($istmpres) {
1636                    $T[$res['var']] = $resvar;
1637                    $lastresvar = &$T[$res['var']];
1638                }
1639                else {
1640                    $op['php'] = $resvar;
1641                    $lastphpop = &$op;
1642                    $lastresvar = &$op['php'];
1643                }
1644            }
1645        }
1646        return $T;
1647    }
1648    // }}}
1649    function unquote($str, $st, $ed) // {{{
1650    {
1651        $l1 = strlen($st);
1652        $l2 = strlen($ed);
1653        if (substr($str, 0, $l1) === $st && substr($str, -$l2) === $ed) {
1654            $str = substr($str, $l1, -$l2);
1655        }
1656        return $str;
1657    }
1658    // }}}
1659    function popargs(&$EX, $n) // {{{
1660    {
1661        $args = array();
1662        for ($i = 0; $i < $n; $i ++) {
1663            $a = array_pop($EX['argstack']);
1664            if (is_array($a)) {
1665                array_unshift($args, foldToCode($a, $EX));
1666            }
1667            else {
1668                array_unshift($args, $a);
1669            }
1670        }
1671        return implode(', ', $args);
1672    }
1673    // }}}
1674    function dumpop($op, &$EX) // {{{
1675    {
1676        $op1 = $op['op1'];
1677        $op2 = $op['op2'];
1678        $d = array('opname' => xcache_get_opcode($op['opcode']), 'opcode' => $op['opcode']);
1679
1680        foreach (array('op1' => 'op1', 'op2' => 'op2', 'result' => 'res') as $k => $kk) {
1681            switch ($op[$k]['op_type']) {
1682            case XC_IS_UNUSED:
1683                $d[$kk] = '*UNUSED* ' . $op[$k]['opline_num'];
1684                break;
1685
1686            case XC_IS_VAR:
1687                $d[$kk] = '$' . $op[$k]['var'];
1688                if ($kk != 'res') {
1689                    $d[$kk] .= ':' . str($this->getOpVal($op[$k], $EX));
1690                }
1691                break;
1692
1693            case XC_IS_TMP_VAR:
1694                $d[$kk] = '#' . $op[$k]['var'];
1695                if ($kk != 'res') {
1696                    $d[$kk] .= ':' . str($this->getOpVal($op[$k], $EX));
1697                }
1698                break;
1699
1700            case XC_IS_CV:
1701                $d[$kk] = $this->getOpVal($op[$k], $EX);
1702                break;
1703
1704            default:
1705                if ($kk == 'res') {
1706                    var_dump($op);
1707                    exit;
1708                    assert(0);
1709                }
1710                else {
1711                    $d[$kk] = $this->getOpVal($op[$k], $EX);
1712                }
1713            }
1714        }
1715        $d['ext'] = $op['extended_value'];
1716
1717        var_dump($d);
1718    }
1719    // }}}
1720    function dargs(&$EX, $indent) // {{{
1721    {
1722        $op_array = &$EX['op_array'];
1723
1724        if (isset($op_array['num_args'])) {
1725            $c = $op_array['num_args'];
1726        }
1727        else if ($op_array['arg_types']) {
1728            $c = count($op_array['arg_types']);
1729        }
1730        else {
1731            // php4
1732            $c = count($EX['recvs']);
1733        }
1734
1735        $refrest = false;
1736        for ($i = 0; $i < $c; $i ++) {
1737            if ($i) {
1738                echo ', ';
1739            }
1740            $arg = $EX['recvs'][$i + 1];
1741            if (isset($op_array['arg_info'])) {
1742                $ai = $op_array['arg_info'][$i];
1743                if (!empty($ai['class_name'])) {
1744                    echo $this->stripNamespace($ai['class_name']), ' ';
1745                    if (!ZEND_ENGINE_2_2 && $ai['allow_null']) {
1746                        echo 'or NULL ';
1747                    }
1748                }
1749                else if (!empty($ai['array_type_hint'])) {
1750                    echo 'array ';
1751                    if (!ZEND_ENGINE_2_2 && $ai['allow_null']) {
1752                        echo 'or NULL ';
1753                    }
1754                }
1755                if ($ai['pass_by_reference']) {
1756                    echo '&';
1757                }
1758                printf("\$%s", $ai['name']);
1759            }
1760            else {
1761                if ($refrest) {
1762                    echo '&';
1763                }
1764                else if (isset($op_array['arg_types'][$i])) {
1765                    switch ($op_array['arg_types'][$i]) {
1766                    case BYREF_FORCE_REST:
1767                        $refrest = true;
1768                        /* fall */
1769                    case BYREF_FORCE:
1770                        echo '&';
1771                        break;
1772
1773                    case BYREF_NONE:
1774                    case BYREF_ALLOW:
1775                        break;
1776                    default:
1777                        assert(0);
1778                    }
1779                }
1780                echo str($arg[0], $indent);
1781            }
1782            if (isset($arg[1])) {
1783                echo ' = ', str($arg[1], $indent);
1784            }
1785        }
1786    }
1787    // }}}
1788    function dfunction($func, $indent = '', $nobody = false) // {{{
1789    {
1790        $this->detectNamespace($func['op_array']['function_name']);
1791
1792        if ($nobody) {
1793            $EX = array();
1794            $EX['op_array'] = &$func['op_array'];
1795            $EX['recvs'] = array();
1796        }
1797        else {
1798            ob_start();
1799            $newindent = INDENT . $indent;
1800            $EX = &$this->dop_array($func['op_array'], $newindent);
1801            $body = ob_get_clean();
1802            if (!isset($EX['recvs'])) {
1803                $EX['recvs'] = array();
1804            }
1805        }
1806
1807        $functionName = $this->stripNamespace($func['op_array']['function_name']);
1808        if ($functionName == '{closure}') {
1809            $functionName = '';
1810        }
1811        echo 'function ', $functionName, '(';
1812        $this->dargs($EX, $indent);
1813        echo ")";
1814        if ($nobody) {
1815            echo ";\n";
1816        }
1817        else {
1818            if ($functionName !== '') {
1819                echo "\n";
1820                echo $indent, "{\n";
1821            }
1822            else {
1823                echo " {\n";
1824            }
1825
1826            echo $body;
1827            echo "$indent}";
1828            if ($functionName !== '') {
1829                echo "\n";
1830            }
1831        }
1832    }
1833    // }}}
1834    function dclass($class, $indent = '') // {{{
1835    {
1836        $this->detectNamespace($class['name']);
1837
1838        // {{{ class decl
1839        if (!empty($class['doc_comment'])) {
1840            echo $indent;
1841            echo $class['doc_comment'];
1842            echo "\n";
1843        }
1844        $isinterface = false;
1845        if (!empty($class['ce_flags'])) {
1846            if ($class['ce_flags'] & ZEND_ACC_INTERFACE) {
1847                $isinterface = true;
1848            }
1849            else {
1850                if ($class['ce_flags'] & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS) {
1851                    echo "abstract ";
1852                }
1853                if ($class['ce_flags'] & ZEND_ACC_FINAL_CLASS) {
1854                    echo "final ";
1855                }
1856            }
1857        }
1858        echo $isinterface ? 'interface ' : 'class ', $this->stripNamespace($class['name']);
1859        if ($class['parent']) {
1860            echo ' extends ', $class['parent'];
1861        }
1862        /* TODO */
1863        if (!empty($class['interfaces'])) {
1864            echo ' implements ';
1865            echo implode(', ', $class['interfaces']);
1866        }
1867        echo "\n";
1868        echo $indent, "{";
1869        // }}}
1870        $newindent = INDENT . $indent;
1871        // {{{ const, static
1872        foreach (array('constants_table' => 'const '
1873                    , 'static_members' => 'static $') as $type => $prefix) {
1874            if (!empty($class[$type])) {
1875                echo "\n";
1876                // TODO: skip shadow?
1877                foreach ($class[$type] as $name => $v) {
1878                    echo $newindent;
1879                    echo $prefix, $name, ' = ';
1880                    echo str(value($v), $newindent);
1881                    echo ";\n";
1882                }
1883            }
1884        }
1885        // }}}
1886        // {{{ properties
1887        $member_variables = isset($class['properties_info']) ? $class['properties_info'] : ($class['default_static_members'] + $class['default_properties']);
1888        if ($member_variables) {
1889            echo "\n";
1890            $infos = !empty($class['properties_info']) ? $class['properties_info'] : null;
1891            foreach ($member_variables as $name => $dummy) {
1892                $info = (isset($infos) && isset($infos[$name])) ? $infos[$name] : null;
1893                if (isset($info)) {
1894                    if (!empty($info['doc_comment'])) {
1895                        echo $newindent;
1896                        echo $info['doc_comment'];
1897                        echo "\n";
1898                    }
1899                }
1900
1901                echo $newindent;
1902                $static = false;
1903                if (isset($info)) {
1904                    if ($info['flags'] & ZEND_ACC_STATIC) {
1905                        $static = true;
1906                    }
1907                }
1908                else if (isset($class['default_static_members'][$name])) {
1909                    $static = true;
1910                }
1911
1912                if ($static) {
1913                    echo "static ";
1914                }
1915
1916                $mangled = false;
1917                if (!ZEND_ENGINE_2) {
1918                    echo 'var ';
1919                }
1920                else if (!isset($info)) {
1921                    echo 'public ';
1922                }
1923                else {
1924                    if ($info['flags'] & ZEND_ACC_SHADOW) {
1925                        continue;
1926                    }
1927                    switch ($info['flags'] & ZEND_ACC_PPP_MASK) {
1928                    case ZEND_ACC_PUBLIC:
1929                        echo "public ";
1930                        break;
1931                    case ZEND_ACC_PRIVATE:
1932                        echo "private ";
1933                        $mangled = true;
1934                        break;
1935                    case ZEND_ACC_PROTECTED:
1936                        echo "protected ";
1937                        $mangled = true;
1938                        break;
1939                    }
1940                }
1941
1942                echo '$', $name;
1943
1944                if (isset($info['offset'])) {
1945                    $value = $class[$static ? 'default_static_members_table' : 'default_properties_table'][$info['offset']];
1946                }
1947                else {
1948                    $key = isset($info) ? $info['name'] . ($mangled ? "\000" : "") : $name;
1949
1950                    $value = $class[$static ? 'default_static_members' : 'default_properties'][$key];
1951                }
1952                if (isset($value)) {
1953                    echo ' = ';
1954                    echo str(value($value), $newindent);
1955                }
1956                echo ";\n";
1957            }
1958        }
1959        // }}}
1960        // {{{ function_table
1961        if (isset($class['function_table'])) {
1962            foreach ($class['function_table'] as $func) {
1963                if (!isset($func['scope']) || $func['scope'] == $class['name']) {
1964                    // TODO: skip shadow here
1965                    echo "\n";
1966                    $opa = $func['op_array'];
1967                    if (!empty($opa['doc_comment'])) {
1968                        echo $newindent;
1969                        echo $opa['doc_comment'];
1970                        echo "\n";
1971                    }
1972                    echo $newindent;
1973                    $isAbstractMethod = false;
1974                    if (isset($opa['fn_flags'])) {
1975                        if (($opa['fn_flags'] & ZEND_ACC_ABSTRACT) && !$isinterface) {
1976                            echo "abstract ";
1977                            $isAbstractMethod = true;
1978                        }
1979                        if ($opa['fn_flags'] & ZEND_ACC_FINAL) {
1980                            echo "final ";
1981                        }
1982                        if ($opa['fn_flags'] & ZEND_ACC_STATIC) {
1983                            echo "static ";
1984                        }
1985
1986                        switch ($opa['fn_flags'] & ZEND_ACC_PPP_MASK) {
1987                            case ZEND_ACC_PUBLIC:
1988                                echo "public ";
1989                                break;
1990                            case ZEND_ACC_PRIVATE:
1991                                echo "private ";
1992                                break;
1993                            case ZEND_ACC_PROTECTED:
1994                                echo "protected ";
1995                                break;
1996                            default:
1997                                echo "<visibility error> ";
1998                                break;
1999                        }
2000                    }
2001                    $this->dfunction($func, $newindent, $isinterface || $isAbstractMethod);
2002                    if ($opa['function_name'] == 'Decompiler') {
2003                        //exit;
2004                    }
2005                }
2006            }
2007        }
2008        // }}}
2009        echo $indent, "}\n";
2010    }
2011    // }}}
2012    function decompileString($string) // {{{
2013    {
2014        $this->dc = xcache_dasm_string($string);
2015        if ($this->dc === false) {
2016            echo "error compling string\n";
2017            return false;
2018        }
2019    }
2020    // }}}
2021    function decompileFile($file) // {{{
2022    {
2023        $this->dc = xcache_dasm_file($file);
2024        if ($this->dc === false) {
2025            echo "error compling $file\n";
2026            return false;
2027        }
2028    }
2029    // }}}
2030    function output() // {{{
2031    {
2032        echo "<?". "php\n\n";
2033        foreach ($this->dc['class_table'] as $key => $class) {
2034            if ($key{0} != "\0") {
2035                $this->dclass($class);
2036                echo "\n";
2037            }
2038        }
2039
2040        foreach ($this->dc['function_table'] as $key => $func) {
2041            if ($key{0} != "\0") {
2042                $this->dfunction($func);
2043                echo "\n";
2044            }
2045        }
2046
2047        $this->dop_array($this->dc['op_array']);
2048        echo "\n?" . ">\n";
2049        return true;
2050    }
2051    // }}}
2052}
2053
2054// {{{ defines
2055define('ZEND_ENGINE_2_4', PHP_VERSION >= "5.3.99");
2056define('ZEND_ENGINE_2_3', ZEND_ENGINE_2_4 || PHP_VERSION >= "5.3.");
2057define('ZEND_ENGINE_2_2', ZEND_ENGINE_2_3 || PHP_VERSION >= "5.2.");
2058define('ZEND_ENGINE_2_1', ZEND_ENGINE_2_2 || PHP_VERSION >= "5.1.");
2059define('ZEND_ENGINE_2',   ZEND_ENGINE_2_1 || PHP_VERSION >= "5.0.");
2060
2061define('ZEND_ACC_STATIC',         0x01);
2062define('ZEND_ACC_ABSTRACT',       0x02);
2063define('ZEND_ACC_FINAL',          0x04);
2064define('ZEND_ACC_IMPLEMENTED_ABSTRACT',       0x08);
2065
2066define('ZEND_ACC_IMPLICIT_ABSTRACT_CLASS',    0x10);
2067define('ZEND_ACC_EXPLICIT_ABSTRACT_CLASS',    0x20);
2068define('ZEND_ACC_FINAL_CLASS',                0x40);
2069define('ZEND_ACC_INTERFACE',                  0x80);
2070if (ZEND_ENGINE_2_4) {
2071    define('ZEND_ACC_TRAIT',                  0x120);
2072}
2073define('ZEND_ACC_PUBLIC',     0x100);
2074define('ZEND_ACC_PROTECTED',  0x200);
2075define('ZEND_ACC_PRIVATE',    0x400);
2076define('ZEND_ACC_PPP_MASK',  (ZEND_ACC_PUBLIC | ZEND_ACC_PROTECTED | ZEND_ACC_PRIVATE));
2077
2078define('ZEND_ACC_CHANGED',    0x800);
2079define('ZEND_ACC_IMPLICIT_PUBLIC',    0x1000);
2080
2081define('ZEND_ACC_CTOR',       0x2000);
2082define('ZEND_ACC_DTOR',       0x4000);
2083define('ZEND_ACC_CLONE',      0x8000);
2084
2085define('ZEND_ACC_ALLOW_STATIC',   0x10000);
2086
2087define('ZEND_ACC_SHADOW', 0x2000);
2088
2089if (ZEND_ENGINE_2_4) {
2090    define('ZEND_FETCH_GLOBAL',           0x00000000);
2091    define('ZEND_FETCH_LOCAL',            0x10000000);
2092    define('ZEND_FETCH_STATIC',           0x20000000);
2093    define('ZEND_FETCH_STATIC_MEMBER',    0x30000000);
2094    define('ZEND_FETCH_GLOBAL_LOCK',      0x40000000);
2095    define('ZEND_FETCH_LEXICAL',          0x50000000);
2096
2097    define('ZEND_FETCH_TYPE_MASK',        0x70000000);
2098}
2099else {
2100    define('ZEND_FETCH_GLOBAL',           0);
2101    define('ZEND_FETCH_LOCAL',            1);
2102    define('ZEND_FETCH_STATIC',           2);
2103    define('ZEND_FETCH_STATIC_MEMBER',    3);
2104    define('ZEND_FETCH_GLOBAL_LOCK',      4);
2105}
2106
2107define('ZEND_FETCH_CLASS_DEFAULT',    0);
2108define('ZEND_FETCH_CLASS_SELF',       1);
2109define('ZEND_FETCH_CLASS_PARENT',     2);
2110define('ZEND_FETCH_CLASS_MAIN',       3);
2111define('ZEND_FETCH_CLASS_GLOBAL',     4);
2112define('ZEND_FETCH_CLASS_AUTO',       5);
2113define('ZEND_FETCH_CLASS_INTERFACE',  6);
2114define('ZEND_FETCH_CLASS_STATIC',     7);
2115if (ZEND_ENGINE_2_4) {
2116    define('ZEND_FETCH_CLASS_TRAIT',     14);
2117}
2118if (ZEND_ENGINE_2_3) {
2119    define('ZEND_FETCH_CLASS_MASK',     0xF);
2120}
2121
2122define('ZEND_EVAL',               (1<<0));
2123define('ZEND_INCLUDE',            (1<<1));
2124define('ZEND_INCLUDE_ONCE',       (1<<2));
2125define('ZEND_REQUIRE',            (1<<3));
2126define('ZEND_REQUIRE_ONCE',       (1<<4));
2127
2128define('ZEND_ISSET',              (1<<0));
2129define('ZEND_ISEMPTY',            (1<<1));
2130if (ZEND_ENGINE_2_4) {
2131    define('EXT_TYPE_UNUSED',     (1<<5));
2132}
2133else {
2134    define('EXT_TYPE_UNUSED',     (1<<0));
2135}
2136
2137define('ZEND_FETCH_STANDARD',     0);
2138define('ZEND_FETCH_ADD_LOCK',     1);
2139
2140define('ZEND_FE_FETCH_BYREF',     1);
2141define('ZEND_FE_FETCH_WITH_KEY',  2);
2142
2143define('ZEND_MEMBER_FUNC_CALL',   1<<0);
2144define('ZEND_CTOR_CALL',          1<<1);
2145
2146define('ZEND_ARG_SEND_BY_REF',        (1<<0));
2147define('ZEND_ARG_COMPILE_TIME_BOUND', (1<<1));
2148define('ZEND_ARG_SEND_FUNCTION',      (1<<2));
2149
2150define('BYREF_NONE',       0);
2151define('BYREF_FORCE',      1);
2152define('BYREF_ALLOW',      2);
2153define('BYREF_FORCE_REST', 3);
2154define('IS_NULL',     0);
2155define('IS_LONG',     1);
2156define('IS_DOUBLE',   2);
2157define('IS_STRING',   3);
2158define('IS_ARRAY',    4);
2159define('IS_OBJECT',   5);
2160define('IS_BOOL',     6);
2161define('IS_RESOURCE', 7);
2162define('IS_CONSTANT', 8);
2163define('IS_CONSTANT_ARRAY',   9);
2164
2165@define('XC_IS_CV', 16);
2166
2167/*
2168if (preg_match_all('!XC_[A-Z_]+!', file_get_contents(__FILE__), $ms)) {
2169    $verdiff = array();
2170    foreach ($ms[0] as $k) {
2171        if (!defined($k)) {
2172            $verdiff[$k] = -1;
2173            define($k, -1);
2174        }
2175    }
2176    var_export($verdiff);
2177}
2178/*/
2179foreach (array (
2180    'XC_HANDLE_EXCEPTION' => -1,
2181    'XC_FETCH_CLASS' => -1,
2182    'XC_FETCH_' => -1,
2183    'XC_FETCH_DIM_' => -1,
2184    'XC_ASSIGN_DIM' => -1,
2185    'XC_UNSET_DIM' => -1,
2186    'XC_UNSET_OBJ' => -1,
2187    'XC_ASSIGN_OBJ' => -1,
2188    'XC_ISSET_ISEMPTY_DIM_OBJ' => -1,
2189    'XC_ISSET_ISEMPTY_PROP_OBJ' => -1,
2190    'XC_ISSET_ISEMPTY_VAR' => -1,
2191    'XC_INIT_STATIC_METHOD_CALL' => -1,
2192    'XC_INIT_METHOD_CALL' => -1,
2193    'XC_VERIFY_ABSTRACT_CLASS' => -1,
2194    'XC_DECLARE_CLASS' => -1,
2195    'XC_DECLARE_INHERITED_CLASS' => -1,
2196    'XC_DECLARE_INHERITED_CLASS_DELAYED' => -1,
2197    'XC_ADD_INTERFACE' => -1,
2198    'XC_POST_DEC_OBJ' => -1,
2199    'XC_POST_INC_OBJ' => -1,
2200    'XC_PRE_DEC_OBJ' => -1,
2201    'XC_PRE_INC_OBJ' => -1,
2202    'XC_UNSET_OBJ' => -1,
2203    'XC_JMP_NO_CTOR' => -1,
2204    'XC_FETCH_' => -1,
2205    'XC_FETCH_DIM_' => -1,
2206    'XC_UNSET_DIM_OBJ' => -1,
2207    'XC_ISSET_ISEMPTY' => -1,
2208    'XC_INIT_FCALL_BY_FUNC' => -1,
2209    'XC_DO_FCALL_BY_FUNC' => -1,
2210    'XC_DECLARE_FUNCTION_OR_CLASS' => -1,
2211    'XC_INIT_NS_FCALL_BY_NAME' => -1,
2212    'XC_GOTO' => -1,
2213    'XC_CATCH' => -1,
2214    'XC_THROW' => -1,
2215    'XC_INSTANCEOF' => -1,
2216    'XC_DECLARE_FUNCTION' => -1,
2217    'XC_RAISE_ABSTRACT_ERROR' => -1,
2218    'XC_DECLARE_CONST' => -1,
2219    'XC_USER_OPCODE' => -1,
2220    'XC_JMP_SET' => -1,
2221    'XC_DECLARE_LAMBDA_FUNCTION' => -1,
2222) as $k => $v) {
2223    if (!defined($k)) {
2224        define($k, $v);
2225    }
2226}
2227
2228//* XC_UNDEF XC_OP_DATA
2229$content = file_get_contents(__FILE__);
2230for ($i = 0; $opname = xcache_get_opcode($i); $i ++) {
2231    if (!preg_match("/\\bXC_" . $opname . "\\b(?!')/", $content)) {
2232        echo "not done ", $opname, "\n";
2233    }
2234}
2235// */
2236// }}}
2237
Note: See TracBrowser for help on using the repository browser.