source: trunk/Decompiler.class.php @ 753

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

decompiler: namespace support

  • Property svn:eol-style set to native
File size: 54.2 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 foldToCode($dim, $indent);
270            }
271            return foldToCode($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 $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 (substr($src, 1, -1) == substr($lvalue, 1)) {
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 = substr($src, 1, -1);
1116                                if (isset($statics[$name])) {
1117                                    $var = $statics[$name];
1118                                    $resvar .= ' = ';
1119                                    $resvar .= str(value($var), $EX);
1120                                }
1121                                unset($statics);
1122                                break 2;
1123                            default:
1124                            }
1125                        }
1126                    }
1127                    // TODO: PHP_6 global
1128                    $rvalue = foldToCode($rvalue, $EX);
1129                    $resvar = "$lvalue = &$rvalue";
1130                    break;
1131                    // }}}
1132                // {{{ case XC_FETCH_OBJ_*
1133                case XC_FETCH_OBJ_R:
1134                case XC_FETCH_OBJ_W:
1135                case XC_FETCH_OBJ_RW:
1136                case XC_FETCH_OBJ_FUNC_ARG:
1137                case XC_FETCH_OBJ_UNSET:
1138                case XC_FETCH_OBJ_IS:
1139                case XC_ASSIGN_OBJ:
1140                    $obj = $this->getOpVal($op1, $EX);
1141                    if (!isset($obj)) {
1142                        $obj = '$this';
1143                    }
1144                    $rvalue = str($obj) . "->" . unquoteProperty($this->getOpVal($op2, $EX), $EX);
1145                    if ($res['op_type'] != XC_IS_UNUSED) {
1146                        $resvar = $rvalue;
1147                    }
1148                    if ($opc == XC_ASSIGN_OBJ) {
1149                        ++ $i;
1150                        $lvalue = $rvalue;
1151                        $rvalue = $this->getOpVal($opcodes[$i]['op1'], $EX);
1152                        $resvar = "$lvalue = " . str($rvalue);
1153                    }
1154                    break;
1155                    // }}}
1156                case XC_ISSET_ISEMPTY_DIM_OBJ:
1157                case XC_ISSET_ISEMPTY_PROP_OBJ:
1158                case XC_ISSET_ISEMPTY:
1159                case XC_ISSET_ISEMPTY_VAR: // {{{
1160                    if ($opc == XC_ISSET_ISEMPTY_VAR) {
1161                        $rvalue = $this->getOpVal($op1, $EX);;
1162                        if (preg_match($this->rQuotedName, $rvalue)) {
1163                            $rvalue = '$' . substr($rvalue, 1, -1);
1164                        }
1165                        else {
1166                            $rvalue = '${' . $rvalue . '}';
1167                        }
1168                        if ($op2['EA.type'] == ZEND_FETCH_STATIC_MEMBER) {
1169                            $class = $this->getOpVal($op2, $EX);
1170                            $rvalue = $class . '::' . $rvalue;
1171                        }
1172                    }
1173                    else if ($opc == XC_ISSET_ISEMPTY) {
1174                        $rvalue = $this->getOpVal($op1, $EX);
1175                    }
1176                    else {
1177                        $container = $this->getOpVal($op1, $EX);
1178                        $dim = $this->getOpVal($op2, $EX);
1179                        if ($opc == XC_ISSET_ISEMPTY_PROP_OBJ) {
1180                            if (preg_match($this->rQuotedName, $dim)) {
1181                                $rvalue = $container . "->" . substr($dim, 1, -1);
1182                            }
1183                            else {
1184                                $rvalue = $container . "->{" . $dim . "}";
1185                            }
1186                        }
1187                        else {
1188                            $rvalue = $container . "[$dim]";
1189                        }
1190                    }
1191
1192                    switch ((!ZEND_ENGINE_2 ? $op['op2']['var'] /* constant */ : $ext) & (ZEND_ISSET|ZEND_ISEMPTY)) {
1193                    case ZEND_ISSET:
1194                        $rvalue = "isset($rvalue)";
1195                        break;
1196                    case ZEND_ISEMPTY:
1197                        $rvalue = "empty($rvalue)";
1198                        break;
1199                    }
1200                    $resvar = $rvalue;
1201                    break;
1202                    // }}}
1203                case XC_SEND_VAR_NO_REF:
1204                case XC_SEND_VAL:
1205                case XC_SEND_REF:
1206                case XC_SEND_VAR: // {{{
1207                    $ref = ($opc == XC_SEND_REF ? '&' : '');
1208                    $EX['argstack'][] = $ref . str($this->getOpVal($op1, $EX));
1209                    break;
1210                    // }}}
1211                case XC_INIT_STATIC_METHOD_CALL:
1212                case XC_INIT_METHOD_CALL: // {{{
1213                    array_push($EX['arg_types_stack'], array($EX['fbc'], $EX['object'], $EX['called_scope']));
1214                    if ($opc == XC_INIT_STATIC_METHOD_CALL || $opc == XC_INIT_METHOD_CALL || $op1['op_type'] != XC_IS_UNUSED) {
1215                        $obj = $this->getOpVal($op1, $EX);
1216                        if (!isset($obj)) {
1217                            $obj = '$this';
1218                        }
1219                        if ($opc == XC_INIT_STATIC_METHOD_CALL || /* PHP4 */ isset($op1['constant'])) {
1220                            $EX['object'] = null;
1221                            $EX['called_scope'] = $this->stripNamespace(unquoteName($obj, $EX));
1222                        }
1223                        else {
1224                            $EX['object'] = $obj;
1225                            $EX['called_scope'] = null;
1226                        }
1227                        if ($res['op_type'] != XC_IS_UNUSED) {
1228                            $resvar = '$obj call$';
1229                        }
1230                    }
1231                    else {
1232                        $EX['object'] = null;
1233                        $EX['called_scope'] = null;
1234                    }
1235
1236                    $EX['fbc'] = $this->getOpVal($op2, $EX, false);
1237                    if (($opc == XC_INIT_STATIC_METHOD_CALL || $opc == XC_INIT_METHOD_CALL) && !isset($EX['fbc'])) {
1238                        $EX['fbc'] = '__construct';
1239                    }
1240                    break;
1241                    // }}}
1242                case XC_INIT_NS_FCALL_BY_NAME:
1243                case XC_INIT_FCALL_BY_NAME: // {{{
1244                    if (!ZEND_ENGINE_2 && ($ext & ZEND_CTOR_CALL)) {
1245                        break;
1246                    }
1247                    $EX['object'] = null;
1248                    $EX['called_scope'] = null;
1249                    $EX['fbc'] = $this->getOpVal($op2, $EX);
1250                    break;
1251                    // }}}
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                    // }}}
1259                case XC_DO_FCALL_BY_FUNC:
1260                    $which = $op1['var'];
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:
1266                    $fname = unquoteName($this->getOpVal($op1, $EX, false), $EX);
1267                    $args = $this->popargs($EX, $ext);
1268                    $resvar = $fname . "($args)";
1269                    break;
1270                case XC_DO_FCALL_BY_NAME: // {{{
1271                    $object = null;
1272
1273                    $fname = unquoteName($EX['fbc'], $EX);
1274                    if (!is_int($EX['object'])) {
1275                        $object = $EX['object'];
1276                    }
1277
1278                    $args = $this->popargs($EX, $ext);
1279
1280                    $prefix = (isset($object) ? $object . '->' : '' )
1281                        . (isset($EX['called_scope']) ? $EX['called_scope'] . '::' : '' );
1282                    $resvar = $prefix
1283                        . (!$prefix ? $this->stripNamespace($fname) : $fname)
1284                        . "($args)";
1285                    unset($args);
1286
1287                    if (is_int($EX['object'])) {
1288                        $T[$EX['object']] = $resvar;
1289                        $resvar = null;
1290                    }
1291                    list($EX['fbc'], $EX['object'], $EX['called_scope']) = array_pop($EX['arg_types_stack']);
1292                    break;
1293                    // }}}
1294                case XC_VERIFY_ABSTRACT_CLASS: // {{{
1295                    //unset($T[$op1['var']]);
1296                    break;
1297                    // }}}
1298                case XC_DECLARE_CLASS: 
1299                case XC_DECLARE_INHERITED_CLASS:
1300                case XC_DECLARE_INHERITED_CLASS_DELAYED: // {{{
1301                    $key = $op1['constant'];
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']));
1305                        exit;
1306                    }
1307                    $class = &$this->dc['class_table'][$key];
1308                    if (!isset($class['name'])) {
1309                        $class['name'] = unquoteName($this->getOpVal($op2, $EX), $EX);
1310                    }
1311                    if ($opc == XC_DECLARE_INHERITED_CLASS || $opc == XC_DECLARE_INHERITED_CLASS_DELAYED) {
1312                        $ext /= XC_SIZEOF_TEMP_VARIABLE;
1313                        $class['parent'] = $T[$ext];
1314                        unset($T[$ext]);
1315                    }
1316                    else {
1317                        $class['parent'] = null;
1318                    }
1319
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
1336                        $fetchop = &$opcodes[$i + 1];
1337                        $interface = $this->stripNamespace(unquoteName($this->getOpVal($fetchop['op2'], $EX), $EX));
1338                        $addop = &$opcodes[$i + 2];
1339                        $class['interfaces'][$addop['extended_value']] = $interface;
1340                        unset($fetchop, $addop);
1341                        $i += 2;
1342                    }
1343                    $this->dclass($class);
1344                    echo "\n";
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:
1359                        $op2val = value(chr(str($op2val)));
1360                        break;
1361                    case XC_ADD_STRING:
1362                        break;
1363                    case XC_ADD_VAR:
1364                        break;
1365                    }
1366                    if (str($op1val) == "''") {
1367                        $rvalue = $op2val;
1368                    }
1369                    else if (str($op2val) == "''") {
1370                        $rvalue = $op1val;
1371                    }
1372                    else {
1373                        $rvalue = str($op1val) . ' . ' . str($op2val);
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);
1385                    $resvar = "echo " . str($op1val);
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) {
1398                        $assoc = $this->getOpVal($op2, $EX);
1399                        if (isset($assoc)) {
1400                            $T[$res['var']]->value[] = array($assoc, $rvalue);
1401                        }
1402                        else {
1403                            $T[$res['var']]->value[] = array(null, $rvalue);
1404                        }
1405                    }
1406                    else {
1407                        if ($opc == XC_INIT_ARRAY) {
1408                            $resvar = new Decompiler_Array();
1409                            if (!isset($rvalue)) {
1410                                continue;
1411                            }
1412                        }
1413
1414                        $assoc = $this->getOpVal($op2, $EX);
1415                        if (isset($assoc)) {
1416                            $resvar->value[] = array($assoc, $rvalue);
1417                        }
1418                        else {
1419                            $resvar->value[] = array(null, $rvalue);
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: // {{{
1433                    $resvar = "return " . str($this->getOpVal($op1, $EX));
1434                    break;
1435                    // }}}
1436                case XC_INCLUDE_OR_EVAL: // {{{
1437                    $type = $op2['var']; // hack
1438                    $keyword = $this->includeTypes[$type];
1439                    $resvar = "$keyword " . str($this->getOpVal($op1, $EX));
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;
1450                    $T[$res['var']] = $fe;
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'];
1458                        $T[$res['var']] = $fe;
1459                    }
1460                    break;
1461                    // }}}
1462                case XC_SWITCH_FREE: // {{{
1463                    // unset($T[$op1['var']]);
1464                    break;
1465                    // }}}
1466                case XC_FREE: // {{{
1467                    $free = $T[$op1['var']];
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                    }
1472                    unset($T[$op1['var']], $free);
1473                    break;
1474                    // }}}
1475                case XC_JMP_NO_CTOR:
1476                    break;
1477                case XC_JMP_SET: // ?:
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'])) {
1496                        echo "TODO(cond_false):\n";
1497                        var_dump($op);// exit;
1498                    }
1499                    if ($opc == XC_JMPZ_EX || $opc == XC_JMPNZ_EX || $opc == XC_JMPZ) {
1500                        $targetop = &$EX['opcodes'][$op2['opline_num']];
1501                        if ($opc == XC_JMPNZ_EX) {
1502                            $targetop['cond_true'][] = foldToCode($rvalue, $EX);
1503                        }
1504                        else {
1505                            $targetop['cond_false'][] = foldToCode($rvalue, $EX);
1506                        }
1507                        unset($targetop);
1508                    }
1509                    else {
1510                        $op['cond'] = $rvalue; 
1511                        $op['isjmp'] = true;
1512                    }
1513                    break;
1514                    // }}}
1515                case XC_GOTO:
1516                case XC_JMP: // {{{
1517                    $op['cond'] = null;
1518                    $op['isjmp'] = true;
1519                    break;
1520                    // }}}
1521                case XC_CASE:
1522                    $switchValue = $this->getOpVal($op1, $EX);
1523                    $caseValue = $this->getOpVal($op2, $EX);
1524                    $resvar = str($switchValue) . ' == ' . str($caseValue);
1525                    break;
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) {
1533                        $default = value($op['op2']['constant']);
1534                    }
1535                    else {
1536                        $default = null;
1537                    }
1538                    $EX['recvs'][str($offset)] = array($lvalue, $default);
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'])) {
1550                        $resvar = $this->getOpVal($op1, $EX) . '->' . unquoteProperty($this->getOpVal($op2, $EX), $EX);
1551                    }
1552                    else {
1553                        $resvar = $this->getOpVal($op1, $EX);
1554                    }
1555                    $opstr = isset($flags['DEC']) ? '--' : '++';
1556                    if (isset($flags['POST'])) {
1557                        $resvar .= $opstr;
1558                    }
1559                    else {
1560                        $resvar = "$opstr$resvar";
1561                    }
1562                    break;
1563                    // }}}
1564
1565                case XC_BEGIN_SILENCE: // {{{
1566                    $EX['silence'] ++;
1567                    break;
1568                    // }}}
1569                case XC_END_SILENCE: // {{{
1570                    $EX['silence'] --;
1571                    $lastresvar = '@' . str($lastresvar, $EX);
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;
1598                case XC_DECLARE_FUNCTION:
1599                    $this->dfunction($this->dc['function_table'][$op1['constant']], $EX['indent']);
1600                    break;
1601                case XC_DECLARE_LAMBDA_FUNCTION: // {{{
1602                    ob_start();
1603                    $this->dfunction($this->dc['function_table'][$op1['constant']], $EX['indent']);
1604                    $resvar = ob_get_clean();
1605                    $istmpres = true;
1606                    break;
1607                    // }}}
1608                case XC_DECLARE_CONST:
1609                    $name = $this->stripNamespace(unquoteName($this->getOpVal($op1, $EX), $EX));
1610                    $value = str($this->getOpVal($op2, $EX));
1611                    $resvar = 'const ' . $name . ' = ' . $value;
1612                    break;
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;
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;
1628                default: // {{{
1629                    echo "\x1B[31m * TODO ", $opname, "\x1B[0m\n";
1630                    // }}}
1631                }
1632            }
1633            if (isset($resvar)) {
1634                if ($istmpres) {
1635                    $T[$res['var']] = $resvar;
1636                    $lastresvar = &$T[$res['var']];
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)) {
1664                array_unshift($args, foldToCode($a, $EX));
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:
1682                $d[$kk] = '*UNUSED* ' . $op[$k]['opline_num'];
1683                break;
1684
1685            case XC_IS_VAR:
1686                $d[$kk] = '$' . $op[$k]['var'];
1687                if ($kk != 'res') {
1688                    $d[$kk] .= ':' . str($this->getOpVal($op[$k], $EX));
1689                }
1690                break;
1691
1692            case XC_IS_TMP_VAR:
1693                $d[$kk] = '#' . $op[$k]['var'];
1694                if ($kk != 'res') {
1695                    $d[$kk] .= ':' . str($this->getOpVal($op[$k], $EX));
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') {
1705                    var_dump($op);
1706                    exit;
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            }
1739            $arg = $EX['recvs'][$i + 1];
1740            if (isset($op_array['arg_info'])) {
1741                $ai = $op_array['arg_info'][$i];
1742                if (!empty($ai['class_name'])) {
1743                    echo $this->stripNamespace($ai['class_name']), ' ';
1744                    if (!ZEND_ENGINE_2_2 && $ai['allow_null']) {
1745                        echo 'or NULL ';
1746                    }
1747                }
1748                else if (!empty($ai['array_type_hint'])) {
1749                    echo 'array ';
1750                    if (!ZEND_ENGINE_2_2 && $ai['allow_null']) {
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                }
1779                echo str($arg[0], $indent);
1780            }
1781            if (isset($arg[1])) {
1782                echo ' = ', str($arg[1], $indent);
1783            }
1784        }
1785    }
1786    // }}}
1787    function dfunction($func, $indent = '', $nobody = false) // {{{
1788    {
1789        $this->detectNamespace($func['op_array']['function_name']);
1790
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
1806        $functionName = $this->stripNamespace($func['op_array']['function_name']);
1807        if ($functionName == '{closure}') {
1808            $functionName = '';
1809        }
1810        echo 'function ', $functionName, '(';
1811        $this->dargs($EX, $indent);
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        }
1831    }
1832    // }}}
1833    function dclass($class, $indent = '') // {{{
1834    {
1835        $this->detectNamespace($class['name']);
1836
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 {
1849                if ($class['ce_flags'] & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS) {
1850                    echo "abstract ";
1851                }
1852                if ($class['ce_flags'] & ZEND_ACC_FINAL_CLASS) {
1853                    echo "final ";
1854                }
1855            }
1856        }
1857        echo $isinterface ? 'interface ' : 'class ', $this->stripNamespace($class['name']);
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, ' = ';
1879                    echo str(value($v), $newindent);
1880                    echo ";\n";
1881                }
1882            }
1883        }
1884        // }}}
1885        // {{{ properties
1886        $member_variables = isset($class['properties_info']) ? $class['properties_info'] : ($class['default_static_members'] + $class['default_properties']);
1887        if ($member_variables) {
1888            echo "\n";
1889            $infos = !empty($class['properties_info']) ? $class['properties_info'] : null;
1890            foreach ($member_variables as $name => $dummy) {
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;
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;
1916                if (!ZEND_ENGINE_2) {
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 ";
1932                        $mangled = true;
1933                        break;
1934                    case ZEND_ACC_PROTECTED:
1935                        echo "protected ";
1936                        $mangled = true;
1937                        break;
1938                    }
1939                }
1940
1941                echo '$', $name;
1942
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;
1948
1949                    $value = $class[$static ? 'default_static_members' : 'default_properties'][$key];
1950                }
1951                if (isset($value)) {
1952                    echo ' = ';
1953                    echo str(value($value), $newindent);
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;
1972                    $isAbstractMethod = false;
1973                    if (isset($opa['fn_flags'])) {
1974                        if (($opa['fn_flags'] & ZEND_ACC_ABSTRACT) && !$isinterface) {
1975                            echo "abstract ";
1976                            $isAbstractMethod = true;
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                    }
2000                    $this->dfunction($func, $newindent, $isinterface || $isAbstractMethod);
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    {
2031        echo "<?". "php\n\n";
2032        foreach ($this->dc['class_table'] as $key => $class) {
2033            if ($key{0} != "\0") {
2034                $this->dclass($class);
2035                echo "\n";
2036            }
2037        }
2038
2039        foreach ($this->dc['function_table'] as $key => $func) {
2040            if ($key{0} != "\0") {
2041                $this->dfunction($func);
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
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
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);
2069if (ZEND_ENGINE_2_4) {
2070    define('ZEND_ACC_TRAIT',                  0x120);
2071}
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
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
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);
2113define('ZEND_FETCH_CLASS_STATIC',     7);
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}
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));
2129if (ZEND_ENGINE_2_4) {
2130    define('EXT_TYPE_UNUSED',     (1<<5));
2131}
2132else {
2133    define('EXT_TYPE_UNUSED',     (1<<0));
2134}
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,
2185    'XC_UNSET_OBJ' => -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,
2190    'XC_INIT_STATIC_METHOD_CALL' => -1,
2191    'XC_INIT_METHOD_CALL' => -1,
2192    'XC_VERIFY_ABSTRACT_CLASS' => -1,
2193    'XC_DECLARE_CLASS' => -1,
2194    'XC_DECLARE_INHERITED_CLASS' => -1,
2195    'XC_DECLARE_INHERITED_CLASS_DELAYED' => -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,
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,
2221) as $k => $v) {
2222    if (!defined($k)) {
2223        define($k, $v);
2224    }
2225}
2226
2227//* XC_UNDEF XC_OP_DATA
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.