source: branches/1.3/Decompiler.class.php @ 739

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

merge decompiler updates from trunk

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