source: trunk/Decompiler.class.php @ 753

Last change on this file since 753 was 753, checked in by moo, 3 years ago

decompiler: namespace support

  • Property svn:eol-style set to native
File size: 54.2 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    {
[744]164        $op1 = foldToCode($this->op1, $indent);
[1]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) {
[744]170            return $opstr . str($this->op2, $indent);
[1]171        }
[745]172        return str($op1) . ' ' . $opstr . ' ' . str($this->op2, $indent);
[1]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
[732]188    function toCode($indent)
[1]189    {
190        switch ($this->fetchType) {
191        case ZEND_FETCH_LOCAL:
192            return '$' . substr($this->src, 1, -1);
193        case ZEND_FETCH_STATIC:
[749]194            if (ZEND_ENGINE_2_3) {
195                // closure local variable?
196                return str($this->src);
197            }
[1]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
[732]218    function toCode($indent)
[1]219    {
[732]220        return $this->obj->toCode($indent);
[1]221    }
222}
223// }}}
224class Decompiler_Dim extends Decompiler_Value // {{{
225{
226    var $offsets = array();
227    var $isLast = false;
[749]228    var $isObject = false;
[1]229    var $assign = null;
230
[732]231    function toCode($indent)
[1]232    {
233        if (is_a($this->value, 'Decompiler_ListBox')) {
[749]234            $exp = str($this->value->obj->src, $indent);
[1]235        }
236        else {
[749]237            $exp = str($this->value, $indent);
[1]238        }
[749]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            }
[1]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
[732]262    function toCode($indent)
[1]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)) {
[744]269                return foldToCode($dim, $indent);
[1]270            }
[749]271            return foldToCode($this->dims[0]->assign, $indent) . ' = ' . str($dim, $indent);
[1]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            }
[744]280            $assign = foldToCode($dim->assign, $indent);
[1]281        }
[749]282        return $this->toList($assigns) . ' = ' . str($this->src, $indent);
[1]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{
[737]317    // emenets
318    function Decompiler_Array()
[1]319    {
[737]320        $this->value = array();
[1]321    }
322
[732]323    function toCode($indent)
[1]324    {
[737]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
[1]337        $exp = "array(";
[732]338        $indent = $indent . INDENT;
[735]339        $assocWidth = 0;
[1]340        $multiline = 0;
341        $i = 0;
[737]342        foreach ($elementsCode as $element) {
343            list($keyCode, $valueCode) = $element;
344            if ((string) $i !== $keyCode) {
[735]345                $assocWidth = 1;
[737]346                break;
[735]347            }
348            ++$i;
349        }
[737]350        foreach ($elementsCode as $element) {
351            list($keyCode, $valueCode, $key, $value) = $element;
[735]352            if ($assocWidth) {
[737]353                $len = strlen($keyCode);
[735]354                if ($assocWidth < $len) {
355                    $assocWidth = $len;
[1]356                }
357            }
[737]358            if (is_array($value) || is_a($value, 'Decompiler_Array')) {
[1]359                $multiline ++;
360            }
361        }
362
363        $i = 0;
[737]364        foreach ($elementsCode as $element) {
365            list($keyCode, $value) = $element;
[1]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
[735]379            if ($assocWidth) {
380                if ($multiline) {
[737]381                    $exp .= sprintf("%-{$assocWidth}s => ", $keyCode);
[735]382                }
383                else {
[737]384                    $exp .= $keyCode . ' => ';
[735]385                }
[1]386            }
387
[737]388            $exp .= $value;
[1]389
390            $i ++;
391        }
392        if ($multiline) {
[732]393            $exp .= "\n$indent)";
[1]394        }
395        else {
396            $exp .= ")";
397        }
398        return $exp;
399    }
400}
401// }}}
[737]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// }}}
[1]414class Decompiler_ForeachBox extends Decompiler_Box // {{{
415{
416    var $iskey;
417
[732]418    function toCode($indent)
[1]419    {
420        return 'foreach (' . '';
421    }
422}
423// }}}
424
425class Decompiler
426{
[753]427    var $namespace;
428    var $namespaceDecided;
[1]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    }
[753]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    // }}}
[1]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'])) {
[746]510                $toticks = isset($op['ticks']) ? (int) str($op['ticks']) : 0;
[1]511                if ($curticks != $toticks) {
[746]512                    $oldticks = $curticks;
513                    $curticks = $toticks;
514                    if (!$curticks) {
[749]515                        echo $origindent, "}\n\n";
[1]516                        $indent = $origindent;
517                    }
518                    else {
[746]519                        if ($oldticks) {
[749]520                            echo $origindent, "}\n\n";
[1]521                        }
[746]522                        else if (!$oldticks) {
[1]523                            $indent .= INDENT;
524                        }
[746]525                        echo $origindent, "declare (ticks=$curticks) {\n";
[1]526                    }
527                }
[744]528                echo $indent, str($op['php'], $indent), ";\n";
[1]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:
[744]540            return foldToCode(value($op['constant']), $EX);
[1]541
542        case XC_IS_VAR:
543        case XC_IS_TMP_VAR:
544            $T = &$EX['Ts'];
[716]545            $ret = $T[$op['var']];
[1]546            if ($tostr) {
[744]547                $ret = foldToCode($ret, $EX);
[1]548            }
549            if ($free) {
[716]550                unset($T[$op['var']]);
[1]551            }
552            return $ret;
553
554        case XC_IS_CV:
[716]555            $var = $op['var'];
[1]556            $var = $EX['op_array']['vars'][$var];
557            return '$' . $var['name'];
558
559        case XC_IS_UNUSED:
560            return null;
561        }
562    }
563    // }}}
[716]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    // }}}
[735]577    function &fixOpcode($opcodes, $removeTailing = false, $defaultReturnValue = null) // {{{
[1]578    {
[716]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        }
[735]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        }
[731]625        return $opcodes;
626    }
627    // }}}
628    function &dop_array($op_array, $indent = '') // {{{
629    {
[735]630        $op_array['opcodes'] = $this->fixOpcode($op_array['opcodes'], true, $indent == '' ? 1 : null);
[731]631        $opcodes = &$op_array['opcodes'];
632        $EX['indent'] = '';
[1]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']) {
[749]645            case XC_GOTO:
[1]646            case XC_JMP:
[716]647                $target = $op['op1']['var'];
[1]648                $op['jmpouts'] = array($target);
649                $opcodes[$target]['jmpins'][] = $i;
650                break;
651
652            case XC_JMPZNZ:
[716]653                $jmpz = $op['op2']['opline_num'];
[1]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:
[749]664            case XC_JMP_SET:
[1]665            // case XC_FE_RESET:
666            case XC_FE_FETCH:
667            // case XC_JMP_NO_CTOR:
[716]668                $target = $op['op2']['opline_num'];
[1]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;
[720]706        $EX['called_scope'] = null;
[1]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;
[716]756            $next = $op['op2']['opline_num'];
[1]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
[744]763            $as = foldToCode($op['fe_as'], $EX);
[1]764            if (isset($op['fe_key'])) {
[744]765                $as = str($op['fe_key'], $EX) . ' => ' . str($as);
[1]766            }
[744]767            echo "{$indent}foreach (" . str($op['fe_src'], $EX) . " as $as) {\n";
[1]768            echo $body;
769            echo "{$indent}}";
770            // $this->outputCode($EX, $next, $last, $indent);
771            // return;
772        }
773        /*
774        if ($op['opcode'] == XC_JMPZ) {
[716]775            $target = $op2['opline_num'];
[1]776            if ($line + 1) {
777                $nextblock = $EX['nextbbs'][$next];
778                $jmpop = end($nextblock);
779                if ($jmpop['opcode'] == XC_JMP) {
[716]780                    $ifendline = $op2['opline_num'];
[1]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'])) {
[746]798                echo "{$indent}check (" . str($op["cond"]) . ") {\n";
[1]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
[716]825                $var = $fromop['result']['var'];
[1]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"
[744]836            $cond = implode(' and ', str($op['cond_false']));
[1]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;
[731]879            if ((ZEND_ENGINE_2_4 ? ($res['op_type'] & EXT_TYPE_UNUSED) : ($res['EA.type'] & EXT_TYPE_UNUSED)) || $res['op_type'] == XC_IS_UNUSED) {
[1]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: // {{{
[720]909                    array_push($EX['arg_types_stack'], array($EX['fbc'], $EX['object'], $EX['called_scope']));
[716]910                    $EX['object'] = (int) $res['var'];
[720]911                    $EX['called_scope'] = null;
[749]912                    $EX['fbc'] = 'new ' . unquoteName($this->getOpVal($op1, $EX), $EX);
[731]913                    if (!ZEND_ENGINE_2) {
[1]914                        $resvar = '$new object$';
915                    }
916                    break;
917                    // }}}
[749]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                    // }}}
[1]934                case XC_FETCH_CLASS: // {{{
935                    if ($op2['op_type'] == XC_IS_UNUSED) {
[731]936                        switch (($ext & (defined('ZEND_FETCH_CLASS_MASK') ? ZEND_FETCH_CLASS_MASK : 0xFF))) {
[1]937                        case ZEND_FETCH_CLASS_SELF:
938                            $class = 'self';
939                            break;
940                        case ZEND_FETCH_CLASS_PARENT:
941                            $class = 'parent';
[722]942                            break;
943                        case ZEND_FETCH_CLASS_STATIC:
944                            $class = 'static';
945                            break;
[1]946                        }
[722]947                        $istmpres = true;
[1]948                    }
949                    else {
[749]950                        $class = $this->getOpVal($op2, $EX);
951                        if (isset($op2['constant'])) {
[753]952                            $class = $this->stripNamespace(unquoteName($class));
[1]953                        }
954                    }
955                    $resvar = $class;
956                    break;
957                    // }}}
958                case XC_FETCH_CONSTANT: // {{{
[749]959                    if ($op1['op_type'] == XC_IS_UNUSED) {
[753]960                        $resvar = $this->stripNamespace($op2['constant']);
[749]961                        break;
962                    }
963
[1]964                    if ($op1['op_type'] == XC_IS_CONST) {
[753]965                        $resvar = $this->stripNamespace($op1['constant']);
[1]966                    }
967                    else {
[749]968                        $resvar = $this->getOpVal($op1, $EX);
[1]969                    }
[749]970
971                    $resvar = str($resvar) . '::' . unquoteName($this->getOpVal($op2, $EX));
[1]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);
[731]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                    }
[1]989                    switch ($fetchtype) {
990                    case ZEND_FETCH_STATIC_MEMBER:
991                        $class = $this->getOpVal($op2, $EX);
[749]992                        $rvalue = str($class) . '::$' . unquoteName($rvalue, $EX);
[1]993                        break;
994                    default:
[749]995                        $name = unquoteName($rvalue, $EX);
996                        $globalname = xcache_is_autoglobal($name) ? "\$$name" : "\$GLOBALS[" . str($rvalue) . "]";
[1]997                        $rvalue = new Decompiler_Fetch($rvalue, $fetchtype, $globalname);
998                        break;
999                    }
1000                    if ($opc == XC_UNSET_VAR) {
[744]1001                        $op['php'] = "unset(" . str($rvalue, $EX) . ")";
[1]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:
[749]1018                case XC_UNSET_DIM_OBJ: // PHP 4 only
[1]1019                case XC_UNSET_DIM:
[749]1020                case XC_UNSET_OBJ:
[1]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                    }
[749]1027
1028                    if (is_a($src, "Decompiler_DimBox")) {
[1]1029                        $dimbox = $src;
1030                    }
1031                    else {
1032                        if (!is_a($src, "Decompiler_ListBox")) {
[749]1033                            $op1val = $this->getOpVal($op1, $EX, false);
1034                            $list = new Decompiler_List(isset($op1val) ? $op1val : '$this');
[1]1035
1036                            $src = new Decompiler_ListBox($list);
[716]1037                            if (!isset($op1['var'])) {
[1]1038                                $this->dumpop($op, $EX);
1039                                var_dump($op);
[716]1040                                die('missing var');
[1]1041                            }
[716]1042                            $T[$op1['var']] = $src;
[1]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                    }
[749]1058                    if ($opc == XC_UNSET_OBJ) {
1059                        $dim->isObject = true;
1060                    }
[1]1061                    unset($dim);
1062                    $rvalue = $dimbox;
[749]1063                    unset($dimbox);
[1]1064
1065                    if ($opc == XC_ASSIGN_DIM) {
1066                        $lvalue = $rvalue;
1067                        ++ $i;
1068                        $rvalue = $this->getOpVal($opcodes[$i]['op1'], $EX);
[749]1069                        $resvar = str($lvalue, $EX) . ' = ' . str($rvalue);
[1]1070                    }
[749]1071                    else if ($opc == XC_UNSET_DIM || $opc == XC_UNSET_OBJ) {
[744]1072                        $op['php'] = "unset(" . str($rvalue, $EX) . ")";
[1]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;
[716]1086                        unset($T[$op2['var']]);
[1]1087                        break;
1088                    }
1089                    if (is_a($rvalue, "Decompiler_DimBox")) {
1090                        $dim = &$rvalue->obj;
1091                        $dim->assign = $lvalue;
1092                        if ($dim->isLast) {
[744]1093                            $resvar = foldToCode($dim->value, $EX);
[1]1094                        }
1095                        unset($dim);
1096                        break;
1097                    }
[744]1098                    $resvar = "$lvalue = " . str($rvalue, $EX);
[1]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')) {
[749]1105                        $src = str($rvalue->src, $EX);
[1]1106                        if (substr($src, 1, -1) == substr($lvalue, 1)) {
1107                            switch ($rvalue->fetchType) {
1108                            case ZEND_FETCH_GLOBAL:
[731]1109                            case ZEND_FETCH_GLOBAL_LOCK:
[1]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 = substr($src, 1, -1);
1116                                if (isset($statics[$name])) {
1117                                    $var = $statics[$name];
1118                                    $resvar .= ' = ';
[744]1119                                    $resvar .= str(value($var), $EX);
[1]1120                                }
1121                                unset($statics);
1122                                break 2;
[731]1123                            default:
[1]1124                            }
1125                        }
1126                    }
[731]1127                    // TODO: PHP_6 global
[744]1128                    $rvalue = foldToCode($rvalue, $EX);
[1]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                    }
[749]1144                    $rvalue = str($obj) . "->" . unquoteProperty($this->getOpVal($op2, $EX), $EX);
[1]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);
[749]1152                        $resvar = "$lvalue = " . str($rvalue);
[1]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 {
[733]1166                            $rvalue = '${' . $rvalue . '}';
[1]1167                        }
[716]1168                        if ($op2['EA.type'] == ZEND_FETCH_STATIC_MEMBER) {
[1]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);
[717]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                        }
[1]1190                    }
1191
[731]1192                    switch ((!ZEND_ENGINE_2 ? $op['op2']['var'] /* constant */ : $ext) & (ZEND_ISSET|ZEND_ISEMPTY)) {
[1]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 ? '&' : '');
[744]1208                    $EX['argstack'][] = $ref . str($this->getOpVal($op1, $EX));
[1]1209                    break;
1210                    // }}}
[720]1211                case XC_INIT_STATIC_METHOD_CALL:
[749]1212                case XC_INIT_METHOD_CALL: // {{{
[720]1213                    array_push($EX['arg_types_stack'], array($EX['fbc'], $EX['object'], $EX['called_scope']));
[722]1214                    if ($opc == XC_INIT_STATIC_METHOD_CALL || $opc == XC_INIT_METHOD_CALL || $op1['op_type'] != XC_IS_UNUSED) {
[1]1215                        $obj = $this->getOpVal($op1, $EX);
1216                        if (!isset($obj)) {
1217                            $obj = '$this';
1218                        }
[722]1219                        if ($opc == XC_INIT_STATIC_METHOD_CALL || /* PHP4 */ isset($op1['constant'])) {
[720]1220                            $EX['object'] = null;
[753]1221                            $EX['called_scope'] = $this->stripNamespace(unquoteName($obj, $EX));
[720]1222                        }
1223                        else {
1224                            $EX['object'] = $obj;
1225                            $EX['called_scope'] = null;
1226                        }
[1]1227                        if ($res['op_type'] != XC_IS_UNUSED) {
1228                            $resvar = '$obj call$';
1229                        }
1230                    }
1231                    else {
1232                        $EX['object'] = null;
[720]1233                        $EX['called_scope'] = null;
[1]1234                    }
1235
[749]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';
[1]1239                    }
[749]1240                    break;
1241                    // }}}
[753]1242                case XC_INIT_NS_FCALL_BY_NAME:
[749]1243                case XC_INIT_FCALL_BY_NAME: // {{{
1244                    if (!ZEND_ENGINE_2 && ($ext & ZEND_CTOR_CALL)) {
1245                        break;
[1]1246                    }
[749]1247                    $EX['object'] = null;
1248                    $EX['called_scope'] = null;
1249                    $EX['fbc'] = $this->getOpVal($op2, $EX);
[1]1250                    break;
1251                    // }}}
[749]1252                case XC_INIT_FCALL_BY_FUNC: // {{{ deprecated even in PHP 4?
1253                    $EX['object'] = null;
1254                    $EX['called_scope'] = null;
1255                    $which = $op1['var'];
1256                    $EX['fbc'] = $EX['op_array']['funcs'][$which]['name'];
1257                    break;
1258                    // }}}
[1]1259                case XC_DO_FCALL_BY_FUNC:
[716]1260                    $which = $op1['var'];
[1]1261                    $fname = $EX['op_array']['funcs'][$which]['name'];
1262                    $args = $this->popargs($EX, $ext);
1263                    $resvar = $fname . "($args)";
1264                    break;
1265                case XC_DO_FCALL:
[749]1266                    $fname = unquoteName($this->getOpVal($op1, $EX, false), $EX);
[1]1267                    $args = $this->popargs($EX, $ext);
1268                    $resvar = $fname . "($args)";
1269                    break;
1270                case XC_DO_FCALL_BY_NAME: // {{{
1271                    $object = null;
1272
[749]1273                    $fname = unquoteName($EX['fbc'], $EX);
[1]1274                    if (!is_int($EX['object'])) {
1275                        $object = $EX['object'];
1276                    }
1277
1278                    $args = $this->popargs($EX, $ext);
1279
[753]1280                    $prefix = (isset($object) ? $object . '->' : '' )
1281                        . (isset($EX['called_scope']) ? $EX['called_scope'] . '::' : '' );
1282                    $resvar = $prefix
1283                        . (!$prefix ? $this->stripNamespace($fname) : $fname)
1284                        . "($args)";
[1]1285                    unset($args);
1286
1287                    if (is_int($EX['object'])) {
1288                        $T[$EX['object']] = $resvar;
1289                        $resvar = null;
1290                    }
[720]1291                    list($EX['fbc'], $EX['object'], $EX['called_scope']) = array_pop($EX['arg_types_stack']);
[1]1292                    break;
1293                    // }}}
1294                case XC_VERIFY_ABSTRACT_CLASS: // {{{
[716]1295                    //unset($T[$op1['var']]);
[1]1296                    break;
1297                    // }}}
1298                case XC_DECLARE_CLASS: 
[714]1299                case XC_DECLARE_INHERITED_CLASS:
1300                case XC_DECLARE_INHERITED_CLASS_DELAYED: // {{{
[716]1301                    $key = $op1['constant'];
[714]1302                    if (!isset($this->dc['class_table'][$key])) {
1303                        echo 'class not found: ', $key, 'existing classes are:', "\n";
1304                        var_dump(array_keys($this->dc['class_table']));
[1]1305                        exit;
1306                    }
[714]1307                    $class = &$this->dc['class_table'][$key];
[751]1308                    if (!isset($class['name'])) {
1309                        $class['name'] = unquoteName($this->getOpVal($op2, $EX), $EX);
1310                    }
[714]1311                    if ($opc == XC_DECLARE_INHERITED_CLASS || $opc == XC_DECLARE_INHERITED_CLASS_DELAYED) {
[1]1312                        $ext /= XC_SIZEOF_TEMP_VARIABLE;
1313                        $class['parent'] = $T[$ext];
1314                        unset($T[$ext]);
1315                    }
1316                    else {
1317                        $class['parent'] = null;
1318                    }
1319
[749]1320                    for (;;) {
1321                        if ($i + 1 < $ic
1322                         && $opcodes[$i + 1]['opcode'] == XC_ADD_INTERFACE
1323                         && $opcodes[$i + 1]['op1']['var'] == $res['var']) {
1324                            // continue
1325                        }
1326                        else if ($i + 2 < $ic
1327                         && $opcodes[$i + 2]['opcode'] == XC_ADD_INTERFACE
1328                         && $opcodes[$i + 2]['op1']['var'] == $res['var']
1329                         && $opcodes[$i + 1]['opcode'] == XC_FETCH_CLASS) {
1330                            // continue
1331                        }
1332                        else {
1333                            break;
1334                        }
1335
[1]1336                        $fetchop = &$opcodes[$i + 1];
[753]1337                        $interface = $this->stripNamespace(unquoteName($this->getOpVal($fetchop['op2'], $EX), $EX));
[1]1338                        $addop = &$opcodes[$i + 2];
[753]1339                        $class['interfaces'][$addop['extended_value']] = $interface;
[1]1340                        unset($fetchop, $addop);
1341                        $i += 2;
1342                    }
1343                    $this->dclass($class);
[749]1344                    echo "\n";
[1]1345                    unset($class);
1346                    break;
1347                    // }}}
1348                case XC_INIT_STRING: // {{{
1349                    $resvar = "''";
1350                    break;
1351                    // }}}
1352                case XC_ADD_CHAR:
1353                case XC_ADD_STRING:
1354                case XC_ADD_VAR: // {{{
1355                    $op1val = $this->getOpVal($op1, $EX);
1356                    $op2val = $this->getOpVal($op2, $EX);
1357                    switch ($opc) {
1358                    case XC_ADD_CHAR:
[749]1359                        $op2val = value(chr(str($op2val)));
[1]1360                        break;
1361                    case XC_ADD_STRING:
1362                        break;
1363                    case XC_ADD_VAR:
1364                        break;
1365                    }
[749]1366                    if (str($op1val) == "''") {
[1]1367                        $rvalue = $op2val;
1368                    }
[749]1369                    else if (str($op2val) == "''") {
[1]1370                        $rvalue = $op1val;
1371                    }
1372                    else {
[744]1373                        $rvalue = str($op1val) . ' . ' . str($op2val);
[1]1374                    }
1375                    $resvar = $rvalue;
1376                    // }}}
1377                    break;
1378                case XC_PRINT: // {{{
1379                    $op1val = $this->getOpVal($op1, $EX);
1380                    $resvar = "print($op1val)";
1381                    break;
1382                    // }}}
1383                case XC_ECHO: // {{{
1384                    $op1val = $this->getOpVal($op1, $EX);
[744]1385                    $resvar = "echo " . str($op1val);
[1]1386                    break;
1387                    // }}}
1388                case XC_EXIT: // {{{
1389                    $op1val = $this->getOpVal($op1, $EX);
1390                    $resvar = "exit($op1val)";
1391                    break;
1392                    // }}}
1393                case XC_INIT_ARRAY:
1394                case XC_ADD_ARRAY_ELEMENT: // {{{
1395                    $rvalue = $this->getOpVal($op1, $EX, false, true);
1396
1397                    if ($opc == XC_ADD_ARRAY_ELEMENT) {
[737]1398                        $assoc = $this->getOpVal($op2, $EX);
1399                        if (isset($assoc)) {
1400                            $T[$res['var']]->value[] = array($assoc, $rvalue);
[1]1401                        }
1402                        else {
[737]1403                            $T[$res['var']]->value[] = array(null, $rvalue);
[1]1404                        }
1405                    }
1406                    else {
1407                        if ($opc == XC_INIT_ARRAY) {
1408                            $resvar = new Decompiler_Array();
1409                            if (!isset($rvalue)) {
1410                                continue;
1411                            }
1412                        }
1413
[737]1414                        $assoc = $this->getOpVal($op2, $EX);
1415                        if (isset($assoc)) {
1416                            $resvar->value[] = array($assoc, $rvalue);
[1]1417                        }
1418                        else {
[737]1419                            $resvar->value[] = array(null, $rvalue);
[1]1420                        }
1421                    }
1422                    break;
1423                    // }}}
1424                case XC_QM_ASSIGN: // {{{
1425                    $resvar = $this->getOpVal($op1, $EX);
1426                    break;
1427                    // }}}
1428                case XC_BOOL: // {{{
1429                    $resvar = /*'(bool) ' .*/ $this->getOpVal($op1, $EX);
1430                    break;
1431                    // }}}
1432                case XC_RETURN: // {{{
[744]1433                    $resvar = "return " . str($this->getOpVal($op1, $EX));
[1]1434                    break;
1435                    // }}}
1436                case XC_INCLUDE_OR_EVAL: // {{{
[716]1437                    $type = $op2['var']; // hack
[1]1438                    $keyword = $this->includeTypes[$type];
[749]1439                    $resvar = "$keyword " . str($this->getOpVal($op1, $EX));
[1]1440                    break;
1441                    // }}}
1442                case XC_FE_RESET: // {{{
1443                    $resvar = $this->getOpVal($op1, $EX);
1444                    break;
1445                    // }}}
1446                case XC_FE_FETCH: // {{{
1447                    $op['fe_src'] = $this->getOpVal($op1, $EX);
1448                    $fe = new Decompiler_ForeachBox($op);
1449                    $fe->iskey = false;
[716]1450                    $T[$res['var']] = $fe;
[1]1451
1452                    ++ $i;
1453                    if (($ext & ZEND_FE_FETCH_WITH_KEY)) {
1454                        $fe = new Decompiler_ForeachBox($op);
1455                        $fe->iskey = true;
1456
1457                        $res = $opcodes[$i]['result'];
[716]1458                        $T[$res['var']] = $fe;
[1]1459                    }
1460                    break;
1461                    // }}}
1462                case XC_SWITCH_FREE: // {{{
[716]1463                    // unset($T[$op1['var']]);
[1]1464                    break;
1465                    // }}}
1466                case XC_FREE: // {{{
[716]1467                    $free = $T[$op1['var']];
[1]1468                    if (!is_a($free, 'Decompiler_Array') && !is_a($free, 'Decompiler_Box')) {
1469                        $op['php'] = is_object($free) ? $free : $this->unquote($free, '(', ')');
1470                        $lastphpop = &$op;
1471                    }
[716]1472                    unset($T[$op1['var']], $free);
[1]1473                    break;
1474                    // }}}
1475                case XC_JMP_NO_CTOR:
1476                    break;
[749]1477                case XC_JMP_SET: // ?:
[1]1478                case XC_JMPNZ: // while
1479                case XC_JMPZNZ: // for
1480                case XC_JMPZ_EX: // and
1481                case XC_JMPNZ_EX: // or
1482                case XC_JMPZ: // {{{
1483                    if ($opc == XC_JMP_NO_CTOR && $EX['object']) {
1484                        $rvalue = $EX['object'];
1485                    }
1486                    else {
1487                        $rvalue = $this->getOpVal($op1, $EX);
1488                    }
1489
1490                    if (isset($op['cond_true'])) {
1491                        // any true comes here, so it's a "or"
1492                        $rvalue = implode(' or ', $op['cond_true']) . ' or ' . $rvalue;
1493                        unset($op['cond_true']);
1494                    }
1495                    if (isset($op['cond_false'])) {
[723]1496                        echo "TODO(cond_false):\n";
[1]1497                        var_dump($op);// exit;
1498                    }
1499                    if ($opc == XC_JMPZ_EX || $opc == XC_JMPNZ_EX || $opc == XC_JMPZ) {
[716]1500                        $targetop = &$EX['opcodes'][$op2['opline_num']];
[1]1501                        if ($opc == XC_JMPNZ_EX) {
[744]1502                            $targetop['cond_true'][] = foldToCode($rvalue, $EX);
[1]1503                        }
1504                        else {
[744]1505                            $targetop['cond_false'][] = foldToCode($rvalue, $EX);
[1]1506                        }
1507                        unset($targetop);
1508                    }
1509                    else {
1510                        $op['cond'] = $rvalue; 
1511                        $op['isjmp'] = true;
1512                    }
1513                    break;
1514                    // }}}
[749]1515                case XC_GOTO:
[1]1516                case XC_JMP: // {{{
1517                    $op['cond'] = null;
1518                    $op['isjmp'] = true;
1519                    break;
1520                    // }}}
1521                case XC_CASE:
[743]1522                    $switchValue = $this->getOpVal($op1, $EX);
1523                    $caseValue = $this->getOpVal($op2, $EX);
[744]1524                    $resvar = str($switchValue) . ' == ' . str($caseValue);
[743]1525                    break;
[1]1526                case XC_BRK:
1527                    break;
1528                case XC_RECV_INIT:
1529                case XC_RECV:
1530                    $offset = $this->getOpVal($op1, $EX);
1531                    $lvalue = $this->getOpVal($op['result'], $EX);
1532                    if ($opc == XC_RECV_INIT) {
[716]1533                        $default = value($op['op2']['constant']);
[1]1534                    }
1535                    else {
1536                        $default = null;
1537                    }
[737]1538                    $EX['recvs'][str($offset)] = array($lvalue, $default);
[1]1539                    break;
1540                case XC_POST_DEC:
1541                case XC_POST_INC:
1542                case XC_POST_DEC_OBJ:
1543                case XC_POST_INC_OBJ:
1544                case XC_PRE_DEC:
1545                case XC_PRE_INC:
1546                case XC_PRE_DEC_OBJ:
1547                case XC_PRE_INC_OBJ: // {{{
1548                    $flags = array_flip(explode('_', $opname));
1549                    if (isset($flags['OBJ'])) {
[749]1550                        $resvar = $this->getOpVal($op1, $EX) . '->' . unquoteProperty($this->getOpVal($op2, $EX), $EX);
[1]1551                    }
1552                    else {
1553                        $resvar = $this->getOpVal($op1, $EX);
1554                    }
1555                    $opstr = isset($flags['DEC']) ? '--' : '++';
1556                    if (isset($flags['POST'])) {
[749]1557                        $resvar .= $opstr;
[1]1558                    }
1559                    else {
[749]1560                        $resvar = "$opstr$resvar";
[1]1561                    }
1562                    break;
1563                    // }}}
1564
1565                case XC_BEGIN_SILENCE: // {{{
1566                    $EX['silence'] ++;
1567                    break;
1568                    // }}}
1569                case XC_END_SILENCE: // {{{
1570                    $EX['silence'] --;
[744]1571                    $lastresvar = '@' . str($lastresvar, $EX);
[1]1572                    break;
1573                    // }}}
1574                case XC_CONT: // {{{
1575                    break;
1576                    // }}}
1577                case XC_CAST: // {{{
1578                    $type = $ext;
1579                    static $type2cast = array(
1580                            IS_LONG   => '(int)',
1581                            IS_DOUBLE => '(double)',
1582                            IS_STRING => '(string)',
1583                            IS_ARRAY  => '(array)',
1584                            IS_OBJECT => '(object)',
1585                            IS_BOOL   => '(bool)',
1586                            IS_NULL   => '(unset)',
1587                            );
1588                    assert(isset($type2cast[$type]));
1589                    $cast = $type2cast[$type];
1590                    $resvar = $cast . ' ' . $this->getOpVal($op1, $EX);
1591                    break;
1592                    // }}}
1593                case XC_EXT_STMT:
1594                case XC_EXT_FCALL_BEGIN:
1595                case XC_EXT_FCALL_END:
1596                case XC_EXT_NOP:
1597                    break;
[751]1598                case XC_DECLARE_FUNCTION:
1599                    $this->dfunction($this->dc['function_table'][$op1['constant']], $EX['indent']);
1600                    break;
[752]1601                case XC_DECLARE_LAMBDA_FUNCTION: // {{{
[749]1602                    ob_start();
1603                    $this->dfunction($this->dc['function_table'][$op1['constant']], $EX['indent']);
1604                    $resvar = ob_get_clean();
1605                    $istmpres = true;
1606                    break;
[752]1607                    // }}}
1608                case XC_DECLARE_CONST:
[753]1609                    $name = $this->stripNamespace(unquoteName($this->getOpVal($op1, $EX), $EX));
1610                    $value = str($this->getOpVal($op2, $EX));
1611                    $resvar = 'const ' . $name . ' = ' . $value;
[752]1612                    break;
[1]1613                case XC_DECLARE_FUNCTION_OR_CLASS:
1614                    /* always removed by compiler */
1615                    break;
1616                case XC_TICKS:
1617                    $lastphpop['ticks'] = $this->getOpVal($op1, $EX);
1618                    // $EX['tickschanged'] = true;
1619                    break;
[749]1620                case XC_RAISE_ABSTRACT_ERROR:
1621                    // abstract function body is empty, don't need this code
1622                    break;
1623                case XC_USER_OPCODE:
1624                    echo '// ZEND_USER_OPCODE, impossible to decompile';
1625                    break;
1626                case XC_OP_DATA:
1627                    break;
[1]1628                default: // {{{
1629                    echo "\x1B[31m * TODO ", $opname, "\x1B[0m\n";
1630                    // }}}
1631                }
1632            }
1633            if (isset($resvar)) {
1634                if ($istmpres) {
[716]1635                    $T[$res['var']] = $resvar;
1636                    $lastresvar = &$T[$res['var']];
[1]1637                }
1638                else {
1639                    $op['php'] = $resvar;
1640                    $lastphpop = &$op;
1641                    $lastresvar = &$op['php'];
1642                }
1643            }
1644        }
1645        return $T;
1646    }
1647    // }}}
1648    function unquote($str, $st, $ed) // {{{
1649    {
1650        $l1 = strlen($st);
1651        $l2 = strlen($ed);
1652        if (substr($str, 0, $l1) === $st && substr($str, -$l2) === $ed) {
1653            $str = substr($str, $l1, -$l2);
1654        }
1655        return $str;
1656    }
1657    // }}}
1658    function popargs(&$EX, $n) // {{{
1659    {
1660        $args = array();
1661        for ($i = 0; $i < $n; $i ++) {
1662            $a = array_pop($EX['argstack']);
1663            if (is_array($a)) {
[744]1664                array_unshift($args, foldToCode($a, $EX));
[1]1665            }
1666            else {
1667                array_unshift($args, $a);
1668            }
1669        }
1670        return implode(', ', $args);
1671    }
1672    // }}}
1673    function dumpop($op, &$EX) // {{{
1674    {
1675        $op1 = $op['op1'];
1676        $op2 = $op['op2'];
1677        $d = array('opname' => xcache_get_opcode($op['opcode']), 'opcode' => $op['opcode']);
1678
1679        foreach (array('op1' => 'op1', 'op2' => 'op2', 'result' => 'res') as $k => $kk) {
1680            switch ($op[$k]['op_type']) {
1681            case XC_IS_UNUSED:
[716]1682                $d[$kk] = '*UNUSED* ' . $op[$k]['opline_num'];
[1]1683                break;
1684
1685            case XC_IS_VAR:
[716]1686                $d[$kk] = '$' . $op[$k]['var'];
[1]1687                if ($kk != 'res') {
[749]1688                    $d[$kk] .= ':' . str($this->getOpVal($op[$k], $EX));
[1]1689                }
1690                break;
1691
1692            case XC_IS_TMP_VAR:
[716]1693                $d[$kk] = '#' . $op[$k]['var'];
[1]1694                if ($kk != 'res') {
[749]1695                    $d[$kk] .= ':' . str($this->getOpVal($op[$k], $EX));
[1]1696                }
1697                break;
1698
1699            case XC_IS_CV:
1700                $d[$kk] = $this->getOpVal($op[$k], $EX);
1701                break;
1702
1703            default:
1704                if ($kk == 'res') {
[731]1705                    var_dump($op);
1706                    exit;
[1]1707                    assert(0);
1708                }
1709                else {
1710                    $d[$kk] = $this->getOpVal($op[$k], $EX);
1711                }
1712            }
1713        }
1714        $d['ext'] = $op['extended_value'];
1715
1716        var_dump($d);
1717    }
1718    // }}}
1719    function dargs(&$EX, $indent) // {{{
1720    {
1721        $op_array = &$EX['op_array'];
1722
1723        if (isset($op_array['num_args'])) {
1724            $c = $op_array['num_args'];
1725        }
1726        else if ($op_array['arg_types']) {
1727            $c = count($op_array['arg_types']);
1728        }
1729        else {
1730            // php4
1731            $c = count($EX['recvs']);
1732        }
1733
1734        $refrest = false;
1735        for ($i = 0; $i < $c; $i ++) {
1736            if ($i) {
1737                echo ', ';
1738            }
[736]1739            $arg = $EX['recvs'][$i + 1];
[1]1740            if (isset($op_array['arg_info'])) {
1741                $ai = $op_array['arg_info'][$i];
1742                if (!empty($ai['class_name'])) {
[753]1743                    echo $this->stripNamespace($ai['class_name']), ' ';
[736]1744                    if (!ZEND_ENGINE_2_2 && $ai['allow_null']) {
[1]1745                        echo 'or NULL ';
1746                    }
1747                }
1748                else if (!empty($ai['array_type_hint'])) {
1749                    echo 'array ';
[736]1750                    if (!ZEND_ENGINE_2_2 && $ai['allow_null']) {
[1]1751                        echo 'or NULL ';
1752                    }
1753                }
1754                if ($ai['pass_by_reference']) {
1755                    echo '&';
1756                }
1757                printf("\$%s", $ai['name']);
1758            }
1759            else {
1760                if ($refrest) {
1761                    echo '&';
1762                }
1763                else if (isset($op_array['arg_types'][$i])) {
1764                    switch ($op_array['arg_types'][$i]) {
1765                    case BYREF_FORCE_REST:
1766                        $refrest = true;
1767                        /* fall */
1768                    case BYREF_FORCE:
1769                        echo '&';
1770                        break;
1771
1772                    case BYREF_NONE:
1773                    case BYREF_ALLOW:
1774                        break;
1775                    default:
1776                        assert(0);
1777                    }
1778                }
[744]1779                echo str($arg[0], $indent);
[1]1780            }
[736]1781            if (isset($arg[1])) {
[744]1782                echo ' = ', str($arg[1], $indent);
[736]1783            }
[1]1784        }
1785    }
1786    // }}}
1787    function dfunction($func, $indent = '', $nobody = false) // {{{
1788    {
[753]1789        $this->detectNamespace($func['op_array']['function_name']);
1790
[1]1791        if ($nobody) {
1792            $EX = array();
1793            $EX['op_array'] = &$func['op_array'];
1794            $EX['recvs'] = array();
1795        }
1796        else {
1797            ob_start();
1798            $newindent = INDENT . $indent;
1799            $EX = &$this->dop_array($func['op_array'], $newindent);
1800            $body = ob_get_clean();
1801            if (!isset($EX['recvs'])) {
1802                $EX['recvs'] = array();
1803            }
1804        }
1805
[753]1806        $functionName = $this->stripNamespace($func['op_array']['function_name']);
[749]1807        if ($functionName == '{closure}') {
1808            $functionName = '';
1809        }
1810        echo 'function ', $functionName, '(';
[1]1811        $this->dargs($EX, $indent);
[749]1812        echo ")";
1813        if ($nobody) {
1814            echo ";\n";
1815        }
1816        else {
1817            if ($functionName !== '') {
1818                echo "\n";
1819                echo $indent, "{\n";
1820            }
1821            else {
1822                echo " {\n";
1823            }
1824
1825            echo $body;
1826            echo "$indent}";
1827            if ($functionName !== '') {
1828                echo "\n";
1829            }
1830        }
[1]1831    }
1832    // }}}
1833    function dclass($class, $indent = '') // {{{
1834    {
[753]1835        $this->detectNamespace($class['name']);
1836
[1]1837        // {{{ class decl
1838        if (!empty($class['doc_comment'])) {
1839            echo $indent;
1840            echo $class['doc_comment'];
1841            echo "\n";
1842        }
1843        $isinterface = false;
1844        if (!empty($class['ce_flags'])) {
1845            if ($class['ce_flags'] & ZEND_ACC_INTERFACE) {
1846                $isinterface = true;
1847            }
1848            else {
[749]1849                if ($class['ce_flags'] & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS) {
[1]1850                    echo "abstract ";
1851                }
[749]1852                if ($class['ce_flags'] & ZEND_ACC_FINAL_CLASS) {
[1]1853                    echo "final ";
1854                }
1855            }
1856        }
[753]1857        echo $isinterface ? 'interface ' : 'class ', $this->stripNamespace($class['name']);
[1]1858        if ($class['parent']) {
1859            echo ' extends ', $class['parent'];
1860        }
1861        /* TODO */
1862        if (!empty($class['interfaces'])) {
1863            echo ' implements ';
1864            echo implode(', ', $class['interfaces']);
1865        }
1866        echo "\n";
1867        echo $indent, "{";
1868        // }}}
1869        $newindent = INDENT . $indent;
1870        // {{{ const, static
1871        foreach (array('constants_table' => 'const '
1872                    , 'static_members' => 'static $') as $type => $prefix) {
1873            if (!empty($class[$type])) {
1874                echo "\n";
1875                // TODO: skip shadow?
1876                foreach ($class[$type] as $name => $v) {
1877                    echo $newindent;
1878                    echo $prefix, $name, ' = ';
[744]1879                    echo str(value($v), $newindent);
[1]1880                    echo ";\n";
1881                }
1882            }
1883        }
1884        // }}}
1885        // {{{ properties
[730]1886        $member_variables = isset($class['properties_info']) ? $class['properties_info'] : ($class['default_static_members'] + $class['default_properties']);
1887        if ($member_variables) {
[1]1888            echo "\n";
[713]1889            $infos = !empty($class['properties_info']) ? $class['properties_info'] : null;
[730]1890            foreach ($member_variables as $name => $dummy) {
[1]1891                $info = (isset($infos) && isset($infos[$name])) ? $infos[$name] : null;
1892                if (isset($info)) {
1893                    if (!empty($info['doc_comment'])) {
1894                        echo $newindent;
1895                        echo $info['doc_comment'];
1896                        echo "\n";
1897                    }
1898                }
1899
1900                echo $newindent;
[713]1901                $static = false;
1902                if (isset($info)) {
1903                    if ($info['flags'] & ZEND_ACC_STATIC) {
1904                        $static = true;
1905                    }
1906                }
1907                else if (isset($class['default_static_members'][$name])) {
1908                    $static = true;
1909                }
1910
1911                if ($static) {
1912                    echo "static ";
1913                }
1914
1915                $mangled = false;
[731]1916                if (!ZEND_ENGINE_2) {
[1]1917                    echo 'var ';
1918                }
1919                else if (!isset($info)) {
1920                    echo 'public ';
1921                }
1922                else {
1923                    if ($info['flags'] & ZEND_ACC_SHADOW) {
1924                        continue;
1925                    }
1926                    switch ($info['flags'] & ZEND_ACC_PPP_MASK) {
1927                    case ZEND_ACC_PUBLIC:
1928                        echo "public ";
1929                        break;
1930                    case ZEND_ACC_PRIVATE:
1931                        echo "private ";
[713]1932                        $mangled = true;
[1]1933                        break;
1934                    case ZEND_ACC_PROTECTED:
1935                        echo "protected ";
[713]1936                        $mangled = true;
[1]1937                        break;
1938                    }
1939                }
1940
1941                echo '$', $name;
[713]1942
[730]1943                if (isset($info['offset'])) {
1944                    $value = $class[$static ? 'default_static_members_table' : 'default_properties_table'][$info['offset']];
1945                }
1946                else {
1947                    $key = isset($info) ? $info['name'] . ($mangled ? "\000" : "") : $name;
[713]1948
[730]1949                    $value = $class[$static ? 'default_static_members' : 'default_properties'][$key];
1950                }
[713]1951                if (isset($value)) {
[1]1952                    echo ' = ';
[744]1953                    echo str(value($value), $newindent);
[1]1954                }
1955                echo ";\n";
1956            }
1957        }
1958        // }}}
1959        // {{{ function_table
1960        if (isset($class['function_table'])) {
1961            foreach ($class['function_table'] as $func) {
1962                if (!isset($func['scope']) || $func['scope'] == $class['name']) {
1963                    // TODO: skip shadow here
1964                    echo "\n";
1965                    $opa = $func['op_array'];
1966                    if (!empty($opa['doc_comment'])) {
1967                        echo $newindent;
1968                        echo $opa['doc_comment'];
1969                        echo "\n";
1970                    }
1971                    echo $newindent;
[749]1972                    $isAbstractMethod = false;
[1]1973                    if (isset($opa['fn_flags'])) {
[749]1974                        if (($opa['fn_flags'] & ZEND_ACC_ABSTRACT) && !$isinterface) {
[1]1975                            echo "abstract ";
[749]1976                            $isAbstractMethod = true;
[1]1977                        }
1978                        if ($opa['fn_flags'] & ZEND_ACC_FINAL) {
1979                            echo "final ";
1980                        }
1981                        if ($opa['fn_flags'] & ZEND_ACC_STATIC) {
1982                            echo "static ";
1983                        }
1984
1985                        switch ($opa['fn_flags'] & ZEND_ACC_PPP_MASK) {
1986                            case ZEND_ACC_PUBLIC:
1987                                echo "public ";
1988                                break;
1989                            case ZEND_ACC_PRIVATE:
1990                                echo "private ";
1991                                break;
1992                            case ZEND_ACC_PROTECTED:
1993                                echo "protected ";
1994                                break;
1995                            default:
1996                                echo "<visibility error> ";
1997                                break;
1998                        }
1999                    }
[749]2000                    $this->dfunction($func, $newindent, $isinterface || $isAbstractMethod);
[1]2001                    if ($opa['function_name'] == 'Decompiler') {
2002                        //exit;
2003                    }
2004                }
2005            }
2006        }
2007        // }}}
2008        echo $indent, "}\n";
2009    }
2010    // }}}
2011    function decompileString($string) // {{{
2012    {
2013        $this->dc = xcache_dasm_string($string);
2014        if ($this->dc === false) {
2015            echo "error compling string\n";
2016            return false;
2017        }
2018    }
2019    // }}}
2020    function decompileFile($file) // {{{
2021    {
2022        $this->dc = xcache_dasm_file($file);
2023        if ($this->dc === false) {
2024            echo "error compling $file\n";
2025            return false;
2026        }
2027    }
2028    // }}}
2029    function output() // {{{
2030    {
[749]2031        echo "<?". "php\n\n";
[1]2032        foreach ($this->dc['class_table'] as $key => $class) {
2033            if ($key{0} != "\0") {
[749]2034                $this->dclass($class);
[1]2035                echo "\n";
2036            }
2037        }
2038
2039        foreach ($this->dc['function_table'] as $key => $func) {
2040            if ($key{0} != "\0") {
[749]2041                $this->dfunction($func);
[1]2042                echo "\n";
2043            }
2044        }
2045
2046        $this->dop_array($this->dc['op_array']);
2047        echo "\n?" . ">\n";
2048        return true;
2049    }
2050    // }}}
2051}
2052
2053// {{{ defines
[749]2054define('ZEND_ENGINE_2_4', PHP_VERSION >= "5.3.99");
2055define('ZEND_ENGINE_2_3', ZEND_ENGINE_2_4 || PHP_VERSION >= "5.3.");
2056define('ZEND_ENGINE_2_2', ZEND_ENGINE_2_3 || PHP_VERSION >= "5.2.");
2057define('ZEND_ENGINE_2_1', ZEND_ENGINE_2_2 || PHP_VERSION >= "5.1.");
2058define('ZEND_ENGINE_2',   ZEND_ENGINE_2_1 || PHP_VERSION >= "5.0.");
2059
[1]2060define('ZEND_ACC_STATIC',         0x01);
2061define('ZEND_ACC_ABSTRACT',       0x02);
2062define('ZEND_ACC_FINAL',          0x04);
2063define('ZEND_ACC_IMPLEMENTED_ABSTRACT',       0x08);
2064
2065define('ZEND_ACC_IMPLICIT_ABSTRACT_CLASS',    0x10);
2066define('ZEND_ACC_EXPLICIT_ABSTRACT_CLASS',    0x20);
2067define('ZEND_ACC_FINAL_CLASS',                0x40);
2068define('ZEND_ACC_INTERFACE',                  0x80);
[749]2069if (ZEND_ENGINE_2_4) {
2070    define('ZEND_ACC_TRAIT',                  0x120);
2071}
[1]2072define('ZEND_ACC_PUBLIC',     0x100);
2073define('ZEND_ACC_PROTECTED',  0x200);
2074define('ZEND_ACC_PRIVATE',    0x400);
2075define('ZEND_ACC_PPP_MASK',  (ZEND_ACC_PUBLIC | ZEND_ACC_PROTECTED | ZEND_ACC_PRIVATE));
2076
2077define('ZEND_ACC_CHANGED',    0x800);
2078define('ZEND_ACC_IMPLICIT_PUBLIC',    0x1000);
2079
2080define('ZEND_ACC_CTOR',       0x2000);
2081define('ZEND_ACC_DTOR',       0x4000);
2082define('ZEND_ACC_CLONE',      0x8000);
2083
2084define('ZEND_ACC_ALLOW_STATIC',   0x10000);
2085
2086define('ZEND_ACC_SHADOW', 0x2000);
2087
[731]2088if (ZEND_ENGINE_2_4) {
2089    define('ZEND_FETCH_GLOBAL',           0x00000000);
2090    define('ZEND_FETCH_LOCAL',            0x10000000);
2091    define('ZEND_FETCH_STATIC',           0x20000000);
2092    define('ZEND_FETCH_STATIC_MEMBER',    0x30000000);
2093    define('ZEND_FETCH_GLOBAL_LOCK',      0x40000000);
2094    define('ZEND_FETCH_LEXICAL',          0x50000000);
2095
2096    define('ZEND_FETCH_TYPE_MASK',        0x70000000);
2097}
2098else {
2099    define('ZEND_FETCH_GLOBAL',           0);
2100    define('ZEND_FETCH_LOCAL',            1);
2101    define('ZEND_FETCH_STATIC',           2);
2102    define('ZEND_FETCH_STATIC_MEMBER',    3);
2103    define('ZEND_FETCH_GLOBAL_LOCK',      4);
2104}
2105
[1]2106define('ZEND_FETCH_CLASS_DEFAULT',    0);
2107define('ZEND_FETCH_CLASS_SELF',       1);
2108define('ZEND_FETCH_CLASS_PARENT',     2);
2109define('ZEND_FETCH_CLASS_MAIN',       3);
2110define('ZEND_FETCH_CLASS_GLOBAL',     4);
2111define('ZEND_FETCH_CLASS_AUTO',       5);
2112define('ZEND_FETCH_CLASS_INTERFACE',  6);
[722]2113define('ZEND_FETCH_CLASS_STATIC',     7);
[731]2114if (ZEND_ENGINE_2_4) {
2115    define('ZEND_FETCH_CLASS_TRAIT',     14);
2116}
2117if (ZEND_ENGINE_2_3) {
2118    define('ZEND_FETCH_CLASS_MASK',     0xF);
2119}
[1]2120
2121define('ZEND_EVAL',               (1<<0));
2122define('ZEND_INCLUDE',            (1<<1));
2123define('ZEND_INCLUDE_ONCE',       (1<<2));
2124define('ZEND_REQUIRE',            (1<<3));
2125define('ZEND_REQUIRE_ONCE',       (1<<4));
2126
2127define('ZEND_ISSET',              (1<<0));
2128define('ZEND_ISEMPTY',            (1<<1));
[731]2129if (ZEND_ENGINE_2_4) {
2130    define('EXT_TYPE_UNUSED',     (1<<5));
2131}
2132else {
2133    define('EXT_TYPE_UNUSED',     (1<<0));
2134}
[1]2135
2136define('ZEND_FETCH_STANDARD',     0);
2137define('ZEND_FETCH_ADD_LOCK',     1);
2138
2139define('ZEND_FE_FETCH_BYREF',     1);
2140define('ZEND_FE_FETCH_WITH_KEY',  2);
2141
2142define('ZEND_MEMBER_FUNC_CALL',   1<<0);
2143define('ZEND_CTOR_CALL',          1<<1);
2144
2145define('ZEND_ARG_SEND_BY_REF',        (1<<0));
2146define('ZEND_ARG_COMPILE_TIME_BOUND', (1<<1));
2147define('ZEND_ARG_SEND_FUNCTION',      (1<<2));
2148
2149define('BYREF_NONE',       0);
2150define('BYREF_FORCE',      1);
2151define('BYREF_ALLOW',      2);
2152define('BYREF_FORCE_REST', 3);
2153define('IS_NULL',     0);
2154define('IS_LONG',     1);
2155define('IS_DOUBLE',   2);
2156define('IS_STRING',   3);
2157define('IS_ARRAY',    4);
2158define('IS_OBJECT',   5);
2159define('IS_BOOL',     6);
2160define('IS_RESOURCE', 7);
2161define('IS_CONSTANT', 8);
2162define('IS_CONSTANT_ARRAY',   9);
2163
2164@define('XC_IS_CV', 16);
2165
2166/*
2167if (preg_match_all('!XC_[A-Z_]+!', file_get_contents(__FILE__), $ms)) {
2168    $verdiff = array();
2169    foreach ($ms[0] as $k) {
2170        if (!defined($k)) {
2171            $verdiff[$k] = -1;
2172            define($k, -1);
2173        }
2174    }
2175    var_export($verdiff);
2176}
2177/*/
2178foreach (array (
2179    'XC_HANDLE_EXCEPTION' => -1,
2180    'XC_FETCH_CLASS' => -1,
2181    'XC_FETCH_' => -1,
2182    'XC_FETCH_DIM_' => -1,
2183    'XC_ASSIGN_DIM' => -1,
2184    'XC_UNSET_DIM' => -1,
[749]2185    'XC_UNSET_OBJ' => -1,
[1]2186    'XC_ASSIGN_OBJ' => -1,
2187    'XC_ISSET_ISEMPTY_DIM_OBJ' => -1,
2188    'XC_ISSET_ISEMPTY_PROP_OBJ' => -1,
2189    'XC_ISSET_ISEMPTY_VAR' => -1,
[720]2190    'XC_INIT_STATIC_METHOD_CALL' => -1,
[1]2191    'XC_INIT_METHOD_CALL' => -1,
2192    'XC_VERIFY_ABSTRACT_CLASS' => -1,
2193    'XC_DECLARE_CLASS' => -1,
2194    'XC_DECLARE_INHERITED_CLASS' => -1,
[714]2195    'XC_DECLARE_INHERITED_CLASS_DELAYED' => -1,
[1]2196    'XC_ADD_INTERFACE' => -1,
2197    'XC_POST_DEC_OBJ' => -1,
2198    'XC_POST_INC_OBJ' => -1,
2199    'XC_PRE_DEC_OBJ' => -1,
2200    'XC_PRE_INC_OBJ' => -1,
2201    'XC_UNSET_OBJ' => -1,
2202    'XC_JMP_NO_CTOR' => -1,
2203    'XC_FETCH_' => -1,
2204    'XC_FETCH_DIM_' => -1,
2205    'XC_UNSET_DIM_OBJ' => -1,
2206    'XC_ISSET_ISEMPTY' => -1,
2207    'XC_INIT_FCALL_BY_FUNC' => -1,
2208    'XC_DO_FCALL_BY_FUNC' => -1,
2209    'XC_DECLARE_FUNCTION_OR_CLASS' => -1,
[749]2210    'XC_INIT_NS_FCALL_BY_NAME' => -1,
2211    'XC_GOTO' => -1,
2212    'XC_CATCH' => -1,
2213    'XC_THROW' => -1,
2214    'XC_INSTANCEOF' => -1,
2215    'XC_DECLARE_FUNCTION' => -1,
2216    'XC_RAISE_ABSTRACT_ERROR' => -1,
2217    'XC_DECLARE_CONST' => -1,
2218    'XC_USER_OPCODE' => -1,
2219    'XC_JMP_SET' => -1,
2220    'XC_DECLARE_LAMBDA_FUNCTION' => -1,
[1]2221) as $k => $v) {
2222    if (!defined($k)) {
2223        define($k, $v);
2224    }
2225}
2226
[749]2227//* XC_UNDEF XC_OP_DATA
[1]2228$content = file_get_contents(__FILE__);
2229for ($i = 0; $opname = xcache_get_opcode($i); $i ++) {
2230    if (!preg_match("/\\bXC_" . $opname . "\\b(?!')/", $content)) {
2231        echo "not done ", $opname, "\n";
2232    }
2233}
2234// */
2235// }}}
2236
Note: See TracBrowser for help on using the repository browser.