DEADSOFTWARE

Patched for Linux
[mp3cc.git] / MPC.3.5.LINUX / classgen / classgen.c
1 /********************************************************************
3 classgen.c - methods for creating the .class binary file
5 Niksa Orlic, 2004-05-16
7 ********************************************************************/
9 //#include "../util/message.h"
10 #include "../util/error.h"
11 #include "../util/strings.h"
12 #include "../structures/type_list.h"
13 #include "../structures/string_list.h"
14 #include "../structures/type.h"
15 #include "../structures/identifier.h"
16 #include "../structures/name_table.h"
17 #include "../classgen/bytecode.h"
18 #include "../structures/block.h"
19 #include "../classgen/constant_pool.h"
20 #include "../classgen/preverify.h"
21 #include "../util/memory.h"
23 #include <stdio.h>
24 #include <string.h>
25 #include <stdlib.h>
27 #include "classgen.h"
29 extern char* output_path;
30 extern int linenum;
32 extern int detect_units_only;
34 extern constant_pool *constants;
35 extern int constant_pool_size;
37 //extern int usesFloat;
38 extern int mathType;
40 char class_name[16];
42 /*
43 Creates a class file for pascal record.
44 */
45 void create_record_class(type *record)
46 {
47 char class_file_name[16];
48 char *output_file_name;
49 char copy_sig[64];
51 FILE *record_file;
53 bytecode *init_method;
54 bytecode *copy_method;
56 /* save the previous constant pool state */
57 constant_pool *global_cp;
58 int global_cp_count;
60 global_cp = constants;
61 global_cp_count = constant_pool_size;
63 constants = NULL;
64 constant_pool_size = 0;
66 /* check for consistency */
67 if (record->type_class != record_type)
68 die(12);
70 sprintf(class_name, "R_%d", record->unique_record_ID);
71 sprintf(class_file_name, "%s.class", class_name);
73 if (!detect_units_only)
74 requires(3, class_file_name);
76 output_file_name = (char*) mem_alloc(strlen(output_path) +
77 strlen(class_file_name) + 5);
78 if (output_file_name == NULL)
79 die (1);
81 #ifdef WIN32
82 sprintf(output_file_name, "%s\\%s", output_path, class_file_name);
83 #endif
84 #ifdef UNIX
85 sprintf(output_file_name, "%s/%s", output_path, class_file_name);
86 #endif
87 record_file = fopen(output_file_name, "wb");
88 mem_free(output_file_name);
90 if (record_file == NULL)
91 die(3);
93 /* write the class file header */
94 create_class_file_header(record_file);
96 /* add some stuff into the constant pool */
97 cp_add_class(class_name);
98 cp_add_class("java/lang/Object");
99 cp_add_utf8("<init>");
100 cp_add_utf8("()V");
101 cp_add_utf8("Code");
102 cp_add_utf8("Copy");
103 sprintf(copy_sig, "(LR_%d;)LR_%d;", record->unique_record_ID, record->unique_record_ID);
104 cp_add_utf8(copy_sig);
106 create_record_fields(record);
108 /* create the bytecode for the init method */
109 init_method = bytecode_create();
110 create_init_method(record, init_method);
112 /* create the bytecode for the copy method */
113 copy_method = bytecode_create();
114 create_copy_method(record, copy_method);
116 /* write the constant pool into the file */
117 write_constant_pool(record_file);
119 /* write the access flags, set to ACC_PUBLIC and ACC_SUPER */
120 write_short_int(record_file, 0x0021);
122 /* write the index to constat pool with this class description */
123 write_short_int(record_file, cp_add_class(class_name));
125 /* write the index to constant pool with the super class description */
126 write_short_int(record_file, cp_add_class("java/lang/Object"));
128 /* we have no interfaces */
129 write_short_int(record_file, 0);
131 /* write the fields */
132 write_short_int(record_file, (short) type_list_length(record->elements_type_list));
133 write_record_fields(record_file, record);
135 /* we have <init> and Copy method */
136 write_short_int(record_file, 2);
138 /* write the init method */
139 write_init_method(record_file, init_method);
141 /* write the copy method */
142 write_copy_method(record, record_file, copy_method);
144 /* we have no attributes */
145 write_short_int(record_file, 0);
147 fclose(record_file);
150 /* restore the constant pool */
151 constants = global_cp;
152 constant_pool_size = global_cp_count;
156 /*
157 Writes a class file header into the output file
158 */
159 void create_class_file_header(FILE *class_file)
161 char magic[4] = { (char)0xCA, (char)0xFE, (char)0xBA, (char)0xBE };
163 fwrite(magic, 1, 4, class_file);
165 /* Write the minor version number 3 */
166 write_short_int(class_file, 0x0003);
168 /* Wrte the major version number 45 */
169 write_short_int(class_file, 0x002d);
173 /*
174 Creates entries into constant pool with names and types of
175 the elements of the structure.
176 */
177 void create_record_fields(type *record)
179 string_list *names;
180 type_list *types;
181 char descriptor[128];
183 names = record->elements_name_list;
184 types = record->elements_type_list;
186 while (names != NULL)
188 if (names->data != NULL)
190 lowercase(names->data->cstr);
191 get_field_descriptor(types->data, descriptor);
192 cp_add_nameandtype(names->data->cstr, descriptor);
195 names = names->next;
196 types = types->next;
201 /*
202 Writes the fields from the record into the
203 class file.
204 */
205 void write_record_fields(FILE *class_file, type *record)
207 string_list *names;
208 type_list *types;
209 char descriptor[128];
210 int field_num = 0;
212 names = record->elements_name_list;
213 types = record->elements_type_list;
215 while (names != NULL)
217 if (names->data != NULL)
219 /* write the access flags: ACC_PUBLIC */
220 write_short_int(class_file, 0x0001);
222 /* write the name index */
223 lowercase(names->data->cstr);
224 write_short_int(class_file, cp_add_utf8(names->data->cstr));
226 /* write the descriptor index */
227 get_field_descriptor(types->data, descriptor);
228 write_short_int(class_file, cp_add_utf8(descriptor));
230 /* we have no attributes */
231 write_short_int(class_file, 0);
234 names = names->next;
235 types = types->next;
236 field_num ++;
241 /*
242 Writes a short int in bigendian format. If
243 class_file is NULL, does nothing.
244 */
245 void write_short_int(FILE *class_file, short int num)
247 char ch;
249 if (class_file == NULL)
250 return;
252 ch = (char) (num >> 8);
253 fwrite(&ch, 1, 1, class_file);
255 ch = (char) num;
256 fwrite(&ch, 1, 1, class_file);
259 void write_long_int(FILE *class_file, long int num)
261 char ch;
263 if (class_file == NULL)
264 return;
266 ch = (char) (num >> 24);
267 fwrite(&ch, 1, 1, class_file);
269 ch = (char) (num >> 16);
270 fwrite(&ch, 1, 1, class_file);
272 ch = (char) (num >> 8);
273 fwrite(&ch, 1, 1, class_file);
275 ch = (char) num;
276 fwrite(&ch, 1, 1, class_file);
280 short int read_short_int(FILE *class_file)
282 short int return_value = 0;
284 return_value = fgetc(class_file) << 8;
285 return_value |= (fgetc(class_file) & 0x00FF);
287 return return_value;
290 long int read_long_int(FILE *class_file)
292 long int return_value = 0;
294 return_value = fgetc(class_file) << 24;
295 return_value |= (fgetc(class_file) & 0x00FF) << 16;
296 return_value |= (fgetc(class_file) & 0x00FF) << 8;
297 return_value |= (fgetc(class_file) & 0x00FF);
299 return return_value;
302 /*
303 Construct a valid Java field descriptor for a given type.
304 */
305 void get_field_descriptor(type *field_type, char *descriptor)
307 switch (field_type->type_class)
309 case void_type:
310 sprintf(descriptor, "V");
311 break;
313 case integer_type:
314 case char_type:
315 case boolean_type:
316 sprintf(descriptor, "I");
317 break;
319 case real_type:
320 if (mathType == 1)
321 sprintf(descriptor, "I");
322 else
323 sprintf(descriptor, "LReal;");
324 break;
326 case string_type:
327 sprintf(descriptor, "Ljava/lang/String;");
328 break;
330 case command_type:
331 sprintf(descriptor, "Ljavax/microedition/lcdui/Command;");
332 break;
334 case stream_type:
335 sprintf(descriptor, "Ljava/io/InputStream;");
336 break;
338 case record_store_type:
339 sprintf(descriptor, "Ljavax/microedition/rms/RecordStore;");
340 break;
342 case http_type:
343 sprintf(descriptor, "LH;");
344 break;
346 case alert_type:
347 sprintf(descriptor, "Ljavax/microedition/lcdui/AlertType;");
348 break;
350 case image_type:
351 sprintf(descriptor, "Ljavax/microedition/lcdui/Image;");
352 break;
354 case array_type:
356 char element_type[128];
357 int i, len;
359 get_field_descriptor(field_type->element_type, element_type);
361 len = type_list_length(field_type->dimensions_list);
362 for(i=0; i < len; i++)
364 descriptor[i] = '[';
367 descriptor[len] = '\0';
369 sprintf(descriptor + len, "%s", element_type);
371 break;
373 case record_type:
374 sprintf(descriptor, "LR_%d;", field_type->unique_record_ID);
376 break;
378 case error_type:
379 break;
381 default:
382 die(13);
386 /*
387 Creates the <init> method for records.
388 */
389 void create_init_method(type *record, bytecode *code)
391 type_list *type_it;
392 string_list *name_it;
393 int counter = 0;
395 if (code == NULL)
396 die(1);
398 /* create the code */
399 type_it = record->elements_type_list;
400 name_it = record->elements_name_list;
402 bytecode_append(code, aload_0$);
403 bytecode_append(code, invokespecial$);
404 bytecode_append_short_int(code, cp_add_methodref("java/lang/Object", "<init>", "()V"));
407 while (type_it != NULL)
409 if ((type_it->data != NULL) && (name_it->data != NULL))
411 block *code_wrapper;
412 identifier *type_wrapper;
414 code_wrapper = block_create(NULL, string_create());
415 code_wrapper->code = code;
417 type_wrapper = identifier_create();
418 type_wrapper->identifier_class = variable_name;
419 type_wrapper->variable_type = type_it->data;
420 type_wrapper->belongs_to_program_block = 1;
422 /* put 'this' to the stack */
423 bytecode_append(code, aload_0$);
425 /* create the code to initialize the variable */
426 initialize_variable(code_wrapper, type_wrapper, name_it->data->cstr, 0, class_name);
428 if (type_it->data->type_class == array_type)
429 add_error_message(446, name_it->data->cstr, "");
431 code_wrapper->code = bytecode_create();
432 block_destroy(code_wrapper);
434 type_wrapper->variable_type = type_create();
435 identifier_destroy(type_wrapper);
438 type_it = type_it->next;
439 if (name_it != NULL)
440 name_it = name_it->next;
442 counter ++;
445 bytecode_append(code, return$);
448 /*
449 Creates the Copy method for records.
450 */
451 void create_copy_method(type *record, bytecode *code)
453 char type_name[64];
455 type_list *type_it;
456 string_list *name_it;
457 int counter = 0;
459 if (code == NULL)
460 die(1);
462 sprintf(type_name, "R_%d", record->unique_record_ID);
464 /* create the code */
465 type_it = record->elements_type_list;
466 name_it = record->elements_name_list;
468 while (type_it != NULL)
470 if ((type_it->data != NULL) && (name_it->data != NULL))
472 lowercase(name_it->data->cstr);
474 if (type_it->data->type_class == record_type)
476 char copy_sig[64];
477 char type_descriptor[128];
478 get_field_descriptor(type_it->data, type_descriptor);
480 sprintf(copy_sig, "(LR_%d;)LR_%d;", record->unique_record_ID, record->unique_record_ID);
482 bytecode_append(code, aload_0$);
483 bytecode_append(code, getfield$);
484 bytecode_append_short_int(code, cp_add_fieldref(type_name, name_it->data->cstr, type_descriptor));
486 bytecode_append(code, aload_1$);
487 bytecode_append(code, getfield$);
488 bytecode_append_short_int(code, cp_add_fieldref(type_name, name_it->data->cstr, type_descriptor));
490 bytecode_append(code, invokevirtual$);
491 bytecode_append_short_int(code, cp_add_methodref(type_name, "Copy", copy_sig));
494 else if (type_it->data->type_class == string_type)
496 bytecode_append(code, aload_0$);
498 bytecode_append(code, aload_1$);
499 bytecode_append(code, getfield$);
500 bytecode_append_short_int(code, cp_add_fieldref(type_name, name_it->data->cstr, "Ljava/lang/String;"));
502 bytecode_append(code, new$);
503 bytecode_append_short_int(code, cp_add_class("java/lang/String"));
504 bytecode_append(code, dup_x1$);
505 bytecode_append(code, swap$);
506 bytecode_append(code, invokespecial$);
507 bytecode_append_short_int(code, cp_add_methodref("java/lang/String", "<init>", "(Ljava/lang/String;)V"));
509 bytecode_append(code, putfield$);
510 bytecode_append_short_int(code, cp_add_fieldref(type_name, name_it->data->cstr, "Ljava/lang/String;"));
512 else if ((type_it->data->type_class == real_type) && (mathType != 1))
514 bytecode_append(code, aload_0$);
516 bytecode_append(code, aload_1$);
517 bytecode_append(code, getfield$);
518 bytecode_append_short_int(code, cp_add_fieldref(type_name, name_it->data->cstr, "LReal;"));
520 bytecode_append(code, new$);
521 bytecode_append_short_int(code, cp_add_class("Real"));
522 bytecode_append(code, dup_x1$);
523 bytecode_append(code, swap$);
524 bytecode_append(code, invokespecial$);
525 bytecode_append_short_int(code, cp_add_methodref("Real", "<init>", "(LReal;)V"));
527 bytecode_append(code, putfield$);
528 bytecode_append_short_int(code, cp_add_fieldref(type_name, name_it->data->cstr, "LReal;"));
531 else
533 char type_descriptor[128];
534 get_field_descriptor(type_it->data, type_descriptor);
536 bytecode_append(code, aload_0$);
537 bytecode_append(code, aload_1$);
539 bytecode_append(code, getfield$);
540 bytecode_append_short_int(code, cp_add_fieldref(type_name, name_it->data->cstr, type_descriptor));
542 bytecode_append(code, putfield$);
543 bytecode_append_short_int(code, cp_add_fieldref(type_name, name_it->data->cstr, type_descriptor));
547 type_it = type_it->next;
548 if (name_it != NULL)
549 name_it = name_it->next;
551 counter ++;
554 // return this
555 bytecode_append(code, aload_0$);
556 bytecode_append(code, areturn$);
560 /*
561 Writes the <init> method to the file.
562 */
563 void write_init_method(FILE *fp, bytecode *code)
565 /* write the method headers */
567 /* write access flags, ACC_PUBLIC */
568 write_short_int(fp, 0x0001);
570 /* write method name '<init>' */
571 write_short_int(fp, cp_add_utf8("<init>"));
573 /* write method descriptor '()V' */
574 write_short_int(fp, cp_add_utf8("()V"));
576 /* write 1 attribute */
577 write_short_int(fp, 1);
579 /* write the Code attribute 'Code' */
580 write_short_int(fp, cp_add_utf8("Code"));
581 write_long_int(fp, code->bytecode_pos + 12);
583 /* write the max stack */
584 write_short_int(fp, 10);
586 /* max locals for program block */
587 write_short_int(fp, 2);
589 /* code length */
590 write_long_int(fp, code->bytecode_pos);
592 /* write the code itself */
593 if (fp != NULL)
594 fwrite(code->bytecode, 1, code->bytecode_pos, fp);
596 bytecode_destroy(code);
598 write_short_int(fp, 0);
599 write_short_int(fp, 0);
602 /*
603 Writes the Copy method to the file.
604 */
605 void write_copy_method(type* record, FILE *fp, bytecode *code)
607 char method_sig[64];
609 /* write the method headers */
611 /* write access flags, ACC_PUBLIC */
612 write_short_int(fp, 0x0001);
614 /* write method name '<init>' */
615 write_short_int(fp, cp_add_utf8("Copy"));
617 /* write method descriptor (record)record */
618 sprintf(method_sig, "(LR_%d;)LR_%d;", record->unique_record_ID, record->unique_record_ID);
619 write_short_int(fp, cp_add_utf8(method_sig));
621 /* write 1 attribute */
622 write_short_int(fp, 1);
624 /* write the Code attribute 'Code' */
625 write_short_int(fp, cp_add_utf8("Code"));
626 write_long_int(fp, code->bytecode_pos + 12);
628 /* write the max stack */
629 write_short_int(fp, 10);
631 /* max locals for program block */
632 write_short_int(fp, 2);
634 /* code length */
635 write_long_int(fp, code->bytecode_pos);
637 /* write the code itself */
638 if (fp != NULL)
639 fwrite(code->bytecode, 1, code->bytecode_pos, fp);
641 bytecode_destroy(code);
643 write_short_int(fp, 0);
644 write_short_int(fp, 0);