root/eaccelerator/branches/0.9.4/encoder.c

Revision 124, 37.4 kB (checked in by zoeloelip, 3 years ago)

* ea_store.c and ea_restore.c functions clean up
* extraced restore_class_parent and restore_class_methods from

restore_class_entry to share code with loader.c

* extracted opcode handling in encode/decode_op_array into

encode/decode_op to make code more readable

* make decode_class_entry use new functions in ea_restore.c
* readded line-number encoding
* bumped up encoder version to 4 until new loader is in place

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