root/eaccelerator/tags/start/encoder.c

Revision 5, 37.5 kB (checked in by anonymous, 4 years ago)

This commit was manufactured by cvs2svn to create branch 'eAccelerator'.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 /*
2    +----------------------------------------------------------------------+
3    | Turck MMCache for PHP Version 4                                      |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 2002-2003 TurckSoft, St. Petersburg                    |
6    | http://www.turcksoft.com                                             |
7    +----------------------------------------------------------------------+
8    | This program is free software; you can redistribute it and/or        |
9    | modify it under the terms of the GNU General Public License          |
10    | as published by the Free Software Foundation; either version 2       |
11    | of the License, or (at your option) any later version.               |
12    |                                                                      |
13    | This program is distributed in the hope that it will be useful,      |
14    | but WITHOUT ANY WARRANTY; without even the implied warranty of       |
15    | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        |
16    | GNU General Public License for more details.                         |
17    |                                                                      |
18    | You should have received a copy of the GNU General Public License    |
19    | along with this program; if not, write to the Free Software          |
20    | Foundation, Inc., 59 Temple Place - Suite 330, Boston,               |
21    | MA  02111-1307, USA.                                                 |
22    |                                                                      |
23    | A copy is availble at http://www.gnu.org/copyleft/gpl.txt            |
24    +----------------------------------------------------------------------+
25    | Author: Dmitry Stogov <mmcache@turckware.ru>                         |
26    +----------------------------------------------------------------------+
27    $Id$
28 */
29
30 #include "eaccelerator.h"
31 #include "eaccelerator_version.h"
32
33 #ifdef HAVE_EACCELERATOR
34 #ifdef WITH_EACCELERATOR_ENCODER
35
36 #include "opcodes.h"
37
38 #include "zend.h"
39 #include "zend_API.h"
40 #include "php.h"
41
42 #include <math.h>
43
44 #define MMC_ENCODER_VERSION   0x00000002
45
46 #define MMC_ENCODER_END       0x00
47 #define MMC_ENCODER_NAMESPACE 0x01
48 #define MMC_ENCODER_CLASS     0x02
49 #define MMC_ENCODER_FUNCTION  0x03
50
51 #ifndef WITHOUT_FILE_FILTER
52 #define IEQ(need)  (ch == (need) || \
53                     ((need) >= 'a' && (need) <= 'z' && ch == ((need)-'a'+'A')))
54
55 #define SKIP_WHITESPACES() do {\
56                              ch = fgetc(yyin);\
57                              while (ch == ' ' || ch == '\t' ||\
58                                     ch == '\r' || ch == '\n') {\
59                                fputc(ch,yyout);\
60                                ch = fgetc(yyin);\
61                              }\
62                            } while(0)
63
64 static void filter_script(FILE *yyin, FILE *yyout TSRMLS_DC) {
65   register int ch = EOF;
66   int repeat = 0;
67   int allow = 1;
68
69   int label_len, pos;
70   char label[256];
71
72   while (1) {
73     if (!repeat) {
74       ch = fgetc(yyin);
75     } else {
76       repeat = 0;
77     }
78     if (ch == EOF) break;
79     fputc(ch,yyout);
80     if (ch == '\'' || ch == '"' || ch == '`') {
81       /* skip strings */
82       register int start = ch;
83       do {
84         ch = fgetc(yyin);
85         if (ch == EOF) break;
86         fputc(ch,yyout);
87         if (ch == '\\') {
88           ch = fgetc(yyin);
89           if (ch == EOF) break;
90           fputc(ch,yyout);
91           ch = fgetc(yyin);
92           if (ch == EOF) break;
93           fputc(ch,yyout);
94         }
95       } while (ch != start);
96       allow = 1;
97     } else if (ch == '#') {
98       /* skip one line comments */
99 one_line_comment:
100       do {
101         ch = fgetc(yyin);
102         if (ch == EOF) break;
103         fputc(ch,yyout);
104       } while (ch != '\r' && ch != '\n');
105       allow = 1;
106     } else if (ch == '/') {
107       ch = fgetc(yyin);
108       if (ch == EOF) break;
109       if (ch == '/') {
110         fputc(ch,yyout);
111         /* skip one line comments */
112         goto one_line_comment;
113       } else if (ch == '*') {
114         fputc(ch,yyout);
115         /* skip multiline comments */
116         while (1) {
117           do {
118             ch = fgetc(yyin);
119             if (ch == EOF) break;
120             fputc(ch,yyout);
121           } while (ch != '*');
122           if (ch == EOF) break;
123           while (ch == '*') {
124             ch = fgetc(yyin);
125             if (ch == EOF) break;
126             fputc(ch,yyout);
127           }
128           if (ch == EOF || ch == '/') break;
129         }
130       } else {
131         repeat = 1;
132       }
133       allow = 1;
134     } else if (ch == '?' || (ch == '%' && CG(asp_tags))) {
135       /* end of script */
136       ch = fgetc(yyin);
137       if (ch == EOF) break;
138       if (ch == '>') {
139         fputc(ch,yyout);
140         return;
141       } else {
142         repeat = 1;
143       }
144       allow = 1;
145     } else if (ch == '<') {
146       repeat = 1;
147       /* </script> */
148       ch = fgetc(yyin);
149       if (ch == EOF) break;
150       if (ch == '/') {
151         fputc(ch,yyout);
152         ch = fgetc(yyin);
153         if (ch == EOF) break;
154         if (IEQ('s')) {
155           fputc(ch,yyout);
156           ch = fgetc(yyin);
157           if (ch == EOF) break;
158           if (IEQ('c')) {
159             fputc(ch,yyout);
160             ch = fgetc(yyin);
161             if (ch == EOF) break;
162             if (IEQ('r')) {
163               fputc(ch,yyout);
164               ch = fgetc(yyin);
165               if (ch == EOF) break;
166               if (IEQ('i')) {
167                 fputc(ch,yyout);
168                 ch = fgetc(yyin);
169                 if (ch == EOF) break;
170                 if (IEQ('p')) {
171                   fputc(ch,yyout);
172                   ch = fgetc(yyin);
173                   if (ch == EOF) break;
174                   if (IEQ('t')) {
175                     fputc(ch,yyout);
176                     SKIP_WHITESPACES();
177                     if (ch == '>') {
178                       fputc(ch,yyout);
179                       return;
180                     }
181                   }
182                 }
183               }
184             }
185           }
186         }
187       } else if (ch == '<') {
188         repeat = 1;
189         fputc(ch,yyout);
190         ch = fgetc(yyin);
191         if (ch == EOF) break;
192         if (ch == '<') {
193           /* heredoc */
194           fputc(ch,yyout);
195           do {
196             ch = fgetc(yyin);
197             if (ch == EOF) break;
198             fputc(ch,yyout);
199           } while (ch == '\t' || ch == ' ');
200           if ((ch >= 'a' && ch <= 'z') ||
201               (ch >= 'A' && ch <= 'Z') ||
202               ch == '_' ||
203               (ch >= '\x7f' && ch <= '\xff')) {
204             label[0] = ch;
205             label_len = 1;
206             while(1) {
207               ch = fgetc(yyin);
208               if (ch == EOF) break;
209               fputc(ch,yyout);
210               if ((ch >= 'a' && ch <= 'z') ||
211                   (ch >= 'A' && ch <= 'Z') ||
212                   (ch >= '0' && ch <= '9') ||
213                   ch == '_' ||
214                   (ch >= '\x7f' && ch <= '\xff')) {
215                 label[label_len] = ch;
216                 label_len++;
217                 if (label_len >= sizeof(label)-1) break;
218               } else {
219                 break;
220               }
221             }
222             if (ch == '\r' || ch =='\n') {
223               label[label_len] = '\000';
224               while (1) {
225                 if (ch == '\r' || ch == '\n') {
226                   ch = fgetc(yyin);
227                   if (ch == EOF) break;
228                   fputc(ch,yyout);
229                   pos = 0;
230                   while (1) {
231                     if (pos == label_len && ch == ';') {
232                       ch = fgetc(yyin);
233                       if (ch == EOF) break;
234                       fputc(ch,yyout);
235                     }
236                     if (pos == label_len && (ch == '\r' || ch == '\n')) {
237                       break;
238                     }
239                     if (pos > label_len || label[pos] != ch) {
240                       break;
241                     }
242                     pos++;
243                     ch = fgetc(yyin);
244                     if (ch == EOF) break;
245                     fputc(ch,yyout);
246                   }
247                   if (pos == label_len && (ch == '\r' || ch == '\n')) {
248                     break;
249                   }
250                 } else {
251                   ch = fgetc(yyin);
252                   if (ch == EOF) break;
253                   fputc(ch,yyout);
254                 }
255               }
256             }
257           }
258           repeat = 0;
259         }
260       }
261       allow = 1;
262     } else if (allow && ch == '_') {
263       label[0] = ch = fgetc(yyin);
264       if (ch == EOF) {break;}
265       if (ch == '_') {
266         label[1] = ch = fgetc(yyin);
267         if (ch == EOF) {fwrite(label,1,1,yyout); break;}
268         if (IEQ('f')) {
269           label[2] = ch = fgetc(yyin);
270           if (ch == EOF) {fwrite(label,2,1,yyout); break;}
271           if (IEQ('i')) {
272             label[3] = ch = fgetc(yyin);
273             if (ch == EOF) {fwrite(label,3,1,yyout); break;}
274             if (IEQ('l')) {
275               label[4] = ch = fgetc(yyin);
276               if (ch == EOF) {fwrite(label,4,1,yyout); break;}
277               if (IEQ('e')) {
278                 label[5] = ch = fgetc(yyin);
279                 if (ch == EOF) {fwrite(label,5,1,yyout); break;}
280                 if (ch == '_') {
281                   label[6] = ch = fgetc(yyin);
282                   if (ch == EOF) {fwrite(label,6,1,yyout); break;}
283                   if (ch == '_') {
284                     ch = fgetc(yyin);
285                     repeat = 1;
286                     if ((ch >= 'a' && ch <= 'z') ||
287                         (ch >= 'A' && ch <= 'Z') ||
288                         (ch >= '0' && ch <= '9') ||
289                         (ch >= '\x7f' && ch <= '\xff') ||
290                         ch == '_') {
291                       fwrite(label,7,1,yyout);
292                     } else {
293                       fputs("eaccelerator_loader_file()",yyout);
294                     }
295                   } else {
296                     fwrite(label,7,1,yyout);
297                   }
298                 } else {
299                   fwrite(label,6,1,yyout);
300                 }
301               } else {
302                 fwrite(label,5,1,yyout);
303               }
304             } else {
305               fwrite(label,4,1,yyout);
306             }
307           } else {
308             fwrite(label,3,1,yyout);
309           }
310         } else if (IEQ('l')) {
311           label[2] = ch = fgetc(yyin);
312           if (ch == EOF) {fwrite(label,2,1,yyout); break;}
313           if (IEQ('i')) {
314             label[3] = ch = fgetc(yyin);
315             if (ch == EOF) {fwrite(label,3,1,yyout); break;}
316             if (IEQ('n')) {
317               label[4] = ch = fgetc(yyin);
318               if (ch == EOF) {fwrite(label,4,1,yyout); break;}
319               if (IEQ('e')) {
320                 label[5] = ch = fgetc(yyin);
321                 if (ch == EOF) {fwrite(label,5,1,yyout); break;}
322                 if (ch == '_') {
323                   label[6] = ch = fgetc(yyin);
324                   if (ch == EOF) {fwrite(label,6,1,yyout); break;}
325                   if (ch == '_') {
326                     ch = fgetc(yyin);
327                     repeat = 1;
328                     if ((ch >= 'a' && ch <= 'z') ||
329                         (ch >= 'A' && ch <= 'Z') ||
330                         (ch >= '0' && ch <= '9') ||
331                         (ch >= '\x7f' && ch <= '\xff') ||
332                         ch == '_') {
333                       fwrite(label,7,1,yyout);
334                     } else {
335                       fputs("eaccelerator_loader_line()",yyout);
336                     }
337                   } else {
338                     fwrite(label,7,1,yyout);
339                   }
340                 } else {
341                   fwrite(label,6,1,yyout);
342                 }
343               } else {
344                 fwrite(label,5,1,yyout);
345               }
346             } else {
347               fwrite(label,4,1,yyout);
348             }
349           } else {
350             fwrite(label,3,1,yyout);
351           }
352         } else {
353           fwrite(label,2,1,yyout);
354         }
355       } else {
356         fwrite(label,1,1,yyout);
357       }
358       allow = 0;
359     } else if ((ch >= 'a' && ch <= 'z') ||
360                (ch >= 'A' && ch <= 'Z') ||
361                (ch >= '\x7f' && ch <= '\xff') ||
362                ch == '_' || ch == '$') {
363       allow = 0;
364     } else if (ch == '-') {
365       ch = fgetc(yyin);
366       if (ch == EOF) break;
367       if (ch == '>') {
368         fputc(ch,yyout);
369         allow = 0;
370       } else {
371         repeat = 1;
372         allow = 1;
373       }
374     } else {
375       allow = 1;
376     }
377   }
378 }
379
380 static void filter_file(FILE *yyin, FILE *yyout TSRMLS_DC) {
381   register int ch = EOF;
382   int repeat = 0;
383
384   while (1) {
385     if (!repeat) {
386       ch = fgetc(yyin);
387     } else {
388       repeat = 0;
389     }
390     if (ch == EOF) break;
391     fputc(ch,yyout);
392     if (ch == '<') {
393       ch = fgetc(yyin);
394       if (ch == EOF) break;
395       if (ch == '?') {
396         fputc(ch,yyout);
397         if (CG(short_tags)) {
398           filter_script(yyin, yyout TSRMLS_CC);
399         } else {
400           repeat = 1;
401           ch = fgetc(yyin);
402           if (ch == EOF) break;
403           if (IEQ('p')) {
404             fputc(ch,yyout);
405             ch = fgetc(yyin);
406             if (ch == EOF) break;
407             if (IEQ('h')) {
408               fputc(ch,yyout);
409               ch = fgetc(yyin);
410               if (ch == EOF) break;
411               if (IEQ('p')) {
412                 fputc(ch,yyout);
413                 ch = fgetc(yyin);
414                 if (ch == EOF) break;
415                 if (ch == '\r' || ch == '\n' || ch == ' ' || ch == '\t') {
416                   fputc(ch,yyout);
417                   filter_script(yyin, yyout TSRMLS_CC);
418                   repeat = 0;
419                 }
420               }
421             }
422           }
423         }
424       } else if (ch == '%' && CG(asp_tags)) {
425         fputc(ch,yyout);
426         filter_script(yyin, yyout TSRMLS_CC);
427       } else if (IEQ('s')) {
428         repeat = 1;
429         fputc(ch,yyout);
430         ch = fgetc(yyin);
431         if (ch == EOF) break;
432         if (IEQ('c')) {
433           fputc(ch,yyout);
434           ch = fgetc(yyin);
435           if (ch == EOF) break;
436           if (IEQ('r')) {
437             fputc(ch,yyout);
438             ch = fgetc(yyin);
439             if (ch == EOF) break;
440             if (IEQ('i')) {
441               fputc(ch,yyout);
442               ch = fgetc(yyin);
443               if (ch == EOF) break;
444               if (IEQ('p')) {
445                 fputc(ch,yyout);
446                 ch = fgetc(yyin);
447                 if (ch == EOF) break;
448                 if (IEQ('t')) {
449                   fputc(ch,yyout);
450                   SKIP_WHITESPACES();
451                   if (ch == EOF) break;
452                   if (IEQ('l')) {
453                     fputc(ch,yyout);
454                     ch = fgetc(yyin);
455                     if (ch == EOF) break;
456                     if (IEQ('a')) {
457                       fputc(ch,yyout);
458                       ch = fgetc(yyin);
459                       if (ch == EOF) break;
460                       if (IEQ('n')) {
461                         fputc(ch,yyout);
462                         ch = fgetc(yyin);
463                         if (ch == EOF) break;
464                         if (IEQ('g')) {
465                           fputc(ch,yyout);
466                           ch = fgetc(yyin);
467                           if (ch == EOF) break;
468                           if (IEQ('u')) {
469                             fputc(ch,yyout);
470                             ch = fgetc(yyin);
471                             if (ch == EOF) break;
472                             if (IEQ('a')) {
473                               fputc(ch,yyout);
474                               ch = fgetc(yyin);
475                               if (ch == EOF) break;
476                               if (IEQ('g')) {
477                                 fputc(ch,yyout);
478                                 ch = fgetc(yyin);
479                                 if (ch == EOF) break;
480                                 if (IEQ('e')) {
481                                   register int start = '\000';
482                                   fputc(ch,yyout);
483                                   SKIP_WHITESPACES();
484                                   if (ch == EOF) break;
485                                   if (ch == '=') {
486                                     fputc(ch,yyout);
487                                     SKIP_WHITESPACES();
488                                     if (ch == EOF) break;
489                                     if (ch == '\'' || ch == '"') {
490                                       fputc(ch,yyout);
491                                       start = ch;
492                                       ch = fgetc(yyin);
493                                       if (ch == EOF) break;
494                                     }
495                                     if (IEQ('p')) {
496                                       fputc(ch,yyout);
497                                       ch = fgetc(yyin);
498                                       if (ch == EOF) break;
499                                       if (IEQ('h')) {
500                                         fputc(ch,yyout);
501                                         ch = fgetc(yyin);
502                                         if (ch == EOF) break;
503                                         if (IEQ('p')) {
504                                           fputc(ch,yyout);
505                                           if (start != '\000') {
506                                             ch = fgetc(yyin);
507                                             if (ch == EOF) break;
508                                             if (ch == start) {
509                                               fputc(ch,yyout);
510                                               start = '\000';
511                                             }
512                                           }
513                                           if (start == '\000') {
514                                             SKIP_WHITESPACES();
515                                             if (ch == '>') {
516                                               fputc(ch,yyout);
517                                               filter_script(yyin, yyout TSRMLS_CC);
518                                               repeat = 0;
519                                             }
520                                           }
521                                         }
522                                       }
523                                     }
524                                   }
525                                 }
526                               }
527                             }
528                           }
529                         }
530                       }
531                     }
532                   }
533                 }
534               }
535             }
536           }
537         }
538       } else {
539         repeat = 1;
540       }
541     }
542   }
543 }
544 #endif
545
546 static inline void encode(unsigned char c) {
547   zend_write((char*)&c, 1);
548 }
549
550 static inline void encode32(unsigned int i) {
551   encode((unsigned char)(i & 0xff));
552   encode((unsigned char)((i >> 8) & 0xff));
553   encode((unsigned char)((i >> 16) & 0xff));
554   encode((unsigned char)((i >> 24) & 0xff));
555 }
556
557 static inline void encode16(unsigned short i) {
558   encode((unsigned char)(i & 0xff));
559   encode((unsigned char)((i >> 8) & 0xff));
560 }
561
562 static void encode_var(unsigned int var, unsigned int count) {
563   unsigned int v = VAR_NUM(var);
564   if (v >= count) {
565     zend_bailout();
566   }
567   if (count < 0xff) {
568     encode((unsigned char)v);
569   } else if (count < 0xffff) {
570     encode16((unsigned short)v);
571   } else {
572     encode32(v);
573   }
574 }
575
576 static void encode_opline(unsigned int opline, unsigned int last) {
577   if (opline >= last && opline != (unsigned int)-1) {
578     zend_bailout();
579   }
580   if (last < 0xff-1) {
581     encode((unsigned char)opline);
582   } else if (last < 0xffff-1) {
583     encode16((unsigned short)opline);
584   } else {
585     encode32(opline);
586   }
587 }
588
589 static void encode_zstr(const char* str) {
590   if (str != NULL) {
591     int len = strlen(str);
592     ZEND_WRITE(str,len+1);
593   } else {
594     encode(0);
595   }
596 }
597
598 static void encode_lstr(const char* str, unsigned int len) {
599   if (str != NULL && len > 0) {
600     encode32(len);
601     ZEND_WRITE(str,len);
602   } else {
603     encode32(0);
604   }
605 }
606
607 static inline void encode_pstr(const unsigned char* str) {
608   if (str != NULL) {
609     unsigned int len = str[0];
610     ZEND_WRITE((const char*)str,len+1);
611   } else {
612     encode(0);
613   }
614 }
615
616 static void encode_double(double d) {
617   char sign = 0;
618   int  exp;
619   unsigned long i1, i2;
620
621   if (d < 0.0) {
622     sign = 1;
623     d = -d;
624   }
625   d = frexp(d, &exp);
626   d = d * 4294967296.0;
627   i1 = (unsigned long)floor(d);
628   d = (d - i1) * 4294967296.0;
629   i2 = (unsigned long)floor(d);
630
631   encode(sign);
632   encode32(exp);
633   encode32(i1);
634   encode32(i2);
635 }
636
637 typedef void (*encode_bucket_t)(void*);
638
639 #define encode_zval_hash(from) encode_hash(from, (encode_bucket_t)encode_zval_ptr)
640
641 static void encode_zval_ptr(zval** from);
642 static void encode_hash(HashTable* from, encode_bucket_t encode_bucket);
643
644 static void encode_zval(zval* from, int refs) {
645   encode(from->type);
646   if (refs) {
647     encode(from->is_ref);
648     encode32(from->refcount);
649   } else if (!from->is_ref || from->refcount != 2) {
650     zend_bailout();
651   }
652
653   switch (from->type & ~IS_CONSTANT_INDEX) {
654     case IS_NULL:
655       break;
656     case IS_BOOL:
657       encode((unsigned char)from->value.lval);
658       break;
659     case IS_LONG:
660       encode32(from->value.lval);
661       break;
662     case IS_DOUBLE:
663       encode_double(from->value.dval);
664       break;
665     case IS_CONSTANT:
666     case IS_STRING:
667 /*???    case FLAG_IS_BC:*/
668       encode_lstr(from->value.str.val, from->value.str.len);
669       break;
670     case IS_ARRAY:
671     case IS_CONSTANT_ARRAY:
672       encode_zval_hash(from->value.ht);
673       break;
674     case IS_OBJECT:
675     case IS_RESOURCE:
676       /*???*/
677     default:
678       zend_bailout();
679       break;
680   }
681 }
682
683 static void encode_znode(znode* from, unsigned int vars_count) {
684   encode((unsigned char)from->op_type);
685   if (from->op_type == IS_CONST) {
686     encode_zval(&from->u.constant, 0);
687   } else if (from->op_type == IS_VAR ||
688              from->op_type == IS_TMP_VAR) {
689     encode_var(from->u.var, vars_count);
690   } else if (from->op_type != IS_UNUSED) {
691     zend_bailout();
692   }
693 }
694
695
696 static void encode_zval_ptr(zval** from) {
697   encode_zval(*from, 1);
698 }
699
700 #ifdef ZEND_ENGINE_2
701 static void encode_property_info(zend_property_info* from) {
702   encode32(from->flags);
703   encode_lstr(from->name, from->name_length);
704 }
705
706 static void encode_class_entry(zend_class_entry* from);
707
708 static void encode_class_entry_ptr(zend_class_entry** from) {
709   encode_class_entry(*from);
710 }
711 #endif
712
713 static void encode_hash(HashTable* from, encode_bucket_t encode_bucket) {
714   if (from != NULL &&
715       from->nNumOfElements > 0) {
716     Bucket* p;
717     encode32(from->nNumOfElements);
718     p = from->pListHead;
719     while (p != NULL) {
720       encode_lstr(p->arKey, p->nKeyLength);
721       if (p->nKeyLength == 0) {
722         encode32(p->h);
723       }
724       encode_bucket(p->pData);
725       p = p->pListNext;
726     }
727   } else {
728     encode32(0);
729   }
730 }
731
732 #ifdef ZEND_ENGINE_2
733 #define encode_zval_hash_ex(from,p) encode_hash_ex(from, p, (encode_bucket_t)encode_zval_ptr)
734
735 static void encode_hash_ex(HashTable* from, Bucket* p, encode_bucket_t encode_bucket) {
736   if (from != NULL &&
737       from->nNumOfElements > 0) {
738     unsigned int n = 0;
739     Bucket* q = p;
740     while (q != NULL) {
741       ++n;
742       q = q->pListNext;
743     }
744     encode32(n);
745     while (p != NULL) {
746       encode_lstr(p->arKey, p->nKeyLength);
747       if (p->nKeyLength == 0) {
748         encode32(p->h);
749       }
750       encode_bucket(p->pData);
751       p = p->pListNext;
752     }
753   } else {
754     encode32(0);
755   }
756 }
757 #endif
758
759 static void encode_op_array(zend_op_array* from) {
760   zend_op *opline;
761   zend_op *end;
762
763   if (from->type == ZEND_INTERNAL_FUNCTION) {
764   } else if (from->type == ZEND_USER_FUNCTION) {
765   } else {
766     zend_bailout();
767   }
768   encode(from->type);
769 #ifdef ZEND_ENGINE_2
770   encode32(from->num_args);
771   if (from->num_args > 0) {
772     zend_uint i;
773     for (i = 0; i < from->num_args; i++) {
774       encode_lstr(from->arg_info[i].name,from->arg_info[i].name_len);
775       encode_lstr(from->arg_info[i].class_name,from->arg_info[i].class_name_len);
776       encode(from->arg_info[i].allow_null);
777       encode(from->arg_info[i].pass_by_reference);
778     }
779   }
780   encode(from->pass_rest_by_reference);
781 #else
782   encode_pstr(from->arg_types);
783 #endif
784   encode_zstr(from->function_name);
785 #ifdef ZEND_ENGINE_2
786   encode32(from->fn_flags);
787   if (from->scope != NULL) {
788     TSRMLS_FETCH();
789     {
790       Bucket* q = CG(class_table)->pListHead;
791       while (q != NULL) {
792         if (*(zend_class_entry**)q->pData == from->scope) {
793           encode_lstr(q->arKey, q->nKeyLength);
794           goto scope_stored;
795         }
796         q = q->pListNext;
797       }
798     }
799   }
800   encode32(0);
801 scope_stored:
802 #endif
803   if (from->type == ZEND_INTERNAL_FUNCTION) {
804     return;
805   }
806   encode32(from->T);
807 #ifdef ZEND_ENGINE_2
808   encode(from->uses_this);
809 #else
810   encode(from->uses_globals);
811 #endif
812   encode(from->return_reference);
813
814   if (from->opcodes != NULL && from->last > 0) {
815     encode32(from->last);
816     if (from->brk_cont_array != NULL && from->last_brk_cont > 0) {
817       zend_uint i;
818       encode32(from->last_brk_cont);
819       for (i = 0; i < from->last_brk_cont; i++) {
820         encode_opline(from->brk_cont_array[i].brk, from->last);
821         encode_opline(from->brk_cont_array[i].cont, from->last);
822         encode_opline(from->brk_cont_array[i].parent, from->last_brk_cont);
823       }
824     } else {
825       encode32(0);
826     }
827 #ifdef ZEND_ENGINE_2
828         if (from->try_catch_array != NULL && from->last_try_catch > 0)
829         {
830                 zend_uint i;
831                 encode32(from->last_try_catch);
832                 for (i = 0; i < from->last_try_catch; i++)
833                 {
834                         encode_opline(from->try_catch_array[i].try_op, from->last);
835                         encode_opline(from->try_catch_array[i].catch_op, from->last);
836 //                      encode_opline(from->try_catch_array[i].parent, from->last_try_catch);
837                 }
838         }
839         else
840         {
841                 encode32(0);
842         }
843 #endif
844         opline = from->opcodes;
845     end = opline + from->last;
846     for (;opline < end; opline++) {
847       const opcode_dsc* op_dsc = get_opcode_dsc(opline->opcode);
848       if (op_dsc == NULL) {
849         zend_bailout();
850       } else {
851         unsigned int ops = op_dsc->ops;
852         encode(opline->opcode);
853 #if MMC_ENCODER_VERSION < 2
854         encode32(opline->lineno);
855 #endif
856         switch (ops & EXT_MASK) {
857           case EXT_UNUSED:
858             break;
859           case EXT_STD:
860           case EXT_FCALL:
861           case EXT_ARG:
862           case EXT_IFACE:
863             encode32(opline->extended_value);
864             break;
865           case EXT_SEND:
866           case EXT_SEND_NOREF:
867           case EXT_INIT_FCALL:
868           case EXT_FETCH:
869           case EXT_CAST:
870           case EXT_DECLARE:
871           case EXT_FCLASS:
872           case EXT_BIT:
873           case EXT_ISSET:
874           case EXT_ASSIGN:
875             encode((unsigned char)opline->extended_value);
876             break;
877           case EXT_OPLINE:
878             encode_opline(opline->extended_value, from->last);
879             break;
880           case EXT_CLASS:
881             encode_var(opline->extended_value, from->T);
882             break;
883           default:
884             zend_bailout();
885             break;
886         }
887         switch (ops & RES_MASK) {
888           case RES_UNUSED:
889             break;
890           case RES_TMP:
891           case RES_CLASS:
892             encode_var(opline->result.u.var, from->T);
893             break;
894           case RES_VAR:
895             encode_var(opline->result.u.var, from->T);
896             if ((opline->result.u.EA.type & EXT_TYPE_UNUSED) != 0) {
897               encode(1);
898             } else {
899               encode(0);
900             }
901             break;
902           case RES_STD:
903             encode_znode(&opline->result, from->T);
904             if (opline->result.op_type == IS_VAR) {
905               if ((opline->result.u.EA.type & EXT_TYPE_UNUSED) != 0) {
906                 encode(1);
907               } else {
908                 encode(0);
909               }
910             }
911             break;
912           default:
913             zend_bailout();
914             break;
915         }
916         switch (ops & OP1_MASK) {
917           case OP1_UNUSED:
918             break;
919           case OP1_OPLINE:
920             encode_opline(opline->op1.u.opline_num,from->last);
921             break;
922           case OP1_BRK:
923           case OP1_CONT:
924             encode_opline(opline->op1.u.opline_num, from->last_brk_cont);
925             break;
926           case OP1_CLASS:
927           case OP1_TMP:
928           case OP1_VAR:
929             encode_var(opline->op1.u.var, from->T);
930             break;
931           case OP1_UCLASS:
932             encode((unsigned char)opline->op1.op_type);
933             if (opline->op1.op_type != IS_UNUSED) {
934               encode_var(opline->op1.u.var, from->T);
935             }
936             break;
937           case OP1_ARG:
938             encode32(opline->op1.u.constant.value.lval);
939             break;
940 #ifdef ZEND_ENGINE_2
941           case OP1_JMPADDR:
942             encode_opline(opline->op1.u.jmp_addr - from->opcodes, from->last);
943             break;
944 #endif
945           case OP1_STD:
946             encode_znode(&opline->op1, from->T);
947             break;
948           default:
949             zend_bailout();
950             break;
951         }
952         switch (ops & OP2_MASK) {
953           case OP2_UNUSED:
954             break;
955           case OP2_OPLINE:
956             encode_opline(opline->op2.u.opline_num, from->last);
957             break;
958           case OP2_ARG:
959             encode32(opline->op2.u.opline_num);
960             break;
961           case OP2_ISSET:
962           case OP2_INCLUDE:
963             encode((unsigned char)opline->op2.u.constant.value.lval);
964             break;
965           case OP2_FETCH:
966 #ifdef ZEND_ENGINE_2
967             encode((unsigned char)opline->op2.u.EA.type);
968             if (opline->op2.u.EA.type == ZEND_FETCH_STATIC_MEMBER) {
969               encode_var(opline->op2.u.var, from->T);
970             }
971 #else
972             encode((unsigned char)opline->op2.u.fetch_type);
973 #endif
974             break;
975           case OP2_CLASS:
976           case OP2_TMP:
977           case OP2_VAR:
978             encode_var(opline->op2.u.var, from->T);
979             break;
980 #ifdef ZEND_ENGINE_2
981           case OP2_JMPADDR:
982             encode_opline(opline->op2.u.jmp_addr - from->opcodes, from->last);
983             break;
984 #endif
985           case OP2_STD:
986             encode_znode(&opline->op2, from->T);
987             break;
988           default:
989             zend_bailout();
990             break;
991         }
992       }
993     }
994   } else {
995     encode32(0);
996   }
997   encode_zval_hash(from->static_variables);
998 #if MMC_ENCODER_VERSION < 2
999   encode_zstr(from->filename);
1000 #endif
1001 #ifdef ZEND_ENGINE_2
1002   encode32(from->line_start);
1003   encode32(from->line_end);
1004   encode_lstr(from->doc_comment, from->doc_comment_len);
1005 #endif
1006 }
1007
1008 static void encode_class_entry(zend_class_entry* from) {
1009   encode(from->type);
1010   encode_lstr(from->name,from->name_length);
1011 #ifdef ZEND_ENGINE_2
1012   encode32(from->ce_flags);
1013   encode32(from->num_interfaces);
1014 #endif
1015
1016   if (from->parent != NULL && from->parent->name) {
1017     encode_lstr(from->parent->name, from->parent->name_length);
1018   } else {
1019     encode32(0);
1020   }
1021
1022 #ifdef ZEND_ENGINE_2
1023 #if MMC_ENCODER_VERSION < 2
1024   encode32(from->line_start);
1025   encode32(from->line_end);
1026   encode_zstr(from->filename);
1027 #endif
1028   encode_lstr(from->doc_comment, from->doc_comment_len);
1029
1030   encode_zval_hash(&from->constants_table);
1031   encode_zval_hash(&from->default_properties);
1032   encode_hash(&from->properties_info, (encode_bucket_t)encode_property_info);
1033   encode_zval_hash(from->static_members);
1034 #else
1035   encode_zval_hash(&from->default_properties);
1036 #endif
1037   encode_hash(&from->function_table, (encode_bucket_t)encode_op_array);
1038 }
1039
1040 static int eaccelerator_encode(char* key, zend_op_array* op_array,
1041                           Bucket* f, Bucket *c) {
1042   encode_zstr("EACCELERATOR");
1043   encode32(MMC_ENCODER_VERSION);
1044 #ifdef ZEND_ENGINE_2
1045   encode(2);
1046 #else
1047   encode(1);
1048 #endif
1049   while (c != NULL) {
1050     zend_class_entry *ce;
1051 #ifdef ZEND_ENGINE_2
1052     ce = *(zend_class_entry**)c->pData;
1053     encode(MMC_ENCODER_CLASS);
1054     encode_lstr(c->arKey, c->nKeyLength);
1055     encode_class_entry(ce);
1056 #else
1057     encode(MMC_ENCODER_CLASS);
1058     encode_lstr(c->arKey, c->nKeyLength);
1059     ce = (zend_class_entry*)c->pData;
1060     encode_class_entry(ce);
1061 #endif
1062     c = c->pListNext;
1063   }
1064   encode(MMC_ENCODER_END);
1065
1066   while (f != NULL) {
1067     encode(MMC_ENCODER_FUNCTION);
1068     encode_lstr(f->arKey, f->nKeyLength);
1069     encode_op_array((zend_op_array*)f->pData);
1070     f = f->pListNext;
1071   }
1072   encode(MMC_ENCODER_END);
1073   encode_op_array(op_array);
1074   return 1;
1075 }
1076