source: trunk/Decompiler.class.php @ 755

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

fix nested function call

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