source: trunk/Decompiler.class.php @ 757

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

Decompiler: improves operator decompile

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