/ src / classloader.c
classloader.c
  1  /*
  2   *  Bean Java VM
  3   *  Copyright (C) 2005-2025 Christian Lins <christian@lins.me>
  4   *
  5   *  Licensed under the Apache License, Version 2.0 (the "License");
  6   *  you may not use this file except in compliance with the License.
  7   *  You may obtain a copy of the License at
  8   *
  9   *     http://www.apache.org/licenses/LICENSE-2.0
 10   *
 11   *  Unless required by applicable law or agreed to in writing, software
 12   *  distributed under the License is distributed on an "AS IS" BASIS,
 13   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14   *  See the License for the specific language governing permissions and
 15   *  limitations under the License.
 16   */
 17  
 18  #include <debug.h>
 19  #include <platform.h>
 20  #include <vm.h>
 21  
 22  extern VM* vm;
 23  
 24  Class* Class_new()
 25  {
 26      /* Create class struct */
 27      vm->classloader->loaded_classes_num++;
 28      vm->classloader->loaded_classes = (Class*)realloc(
 29              vm->classloader->loaded_classes,
 30              sizeof(Class) * vm->classloader->loaded_classes_num);
 31  
 32      Class* class = &vm->classloader->loaded_classes[vm->classloader->loaded_classes_num - 1];
 33  
 34      return class;
 35  }
 36  
 37  /**
 38   * Looks for cinit method and - if available - runs it on current thread.
 39   */
 40  void Class_init(Class* obj) {
 41      
 42  }
 43  
 44  Classloader* Classloader_new() {
 45      Classloader* classloader = (Classloader*)malloc(sizeof(Classloader));
 46  
 47  	classloader->loaded_classes = NULL;
 48  	classloader->loaded_classes_num = 0;
 49  
 50  	return classloader;
 51  }
 52  
 53  void Classloader_destroy(Classloader* ptr) {
 54      free(ptr);
 55  }
 56  
 57  static
 58  void _freadb(unsigned char* buf, int count, FILE* file) {
 59      if (fread(buf, 1, count, file) != count) {
 60          printf("WARNING: fread returned unexpected byte count\n");
 61      }
 62  }
 63  
 64  static
 65  void _read_constant_fieldref(int n, FILE* classfile, Class* class) {
 66      unsigned char buffer2[2] = { 0, 0 };
 67  
 68      // Allocating memory for REF_INFO
 69      class->ConstantPool[n - 1].Data = malloc(sizeof(struct CONSTANT_REF_INFO));
 70  
 71      // Read class index
 72      _freadb(buffer2, 2, classfile);
 73      ((struct CONSTANT_REF_INFO*)class->ConstantPool[n - 1].Data)->ClassIndex 
 74          = BufferToShort(buffer2);
 75  
 76      // Read name and type index
 77      _freadb(buffer2, 2, classfile);
 78      ((struct CONSTANT_REF_INFO*)class->ConstantPool[n - 1].Data)->NameAndTypeIndex 
 79          = BufferToShort(buffer2);
 80  
 81      dmsg("CONSTANTPOOL_FIELDREF");
 82  }
 83  
 84  static
 85  void _read_constant_methodref(int n, FILE* classfile, Class* class) {
 86      unsigned char buffer2[2] = { 0, 0 };    
 87      
 88      // Allocating memory for REF_INFO
 89      class->ConstantPool[n - 1].Data = malloc(sizeof(struct CONSTANT_REF_INFO));
 90  
 91      // Read class index
 92      _freadb(buffer2, 2, classfile);
 93      ((struct CONSTANT_REF_INFO*)class->ConstantPool[n - 1].Data)->ClassIndex =
 94          BufferToShort(buffer2);
 95  
 96      // Read name and type index
 97      _freadb(buffer2, 2, classfile);
 98      ((struct CONSTANT_REF_INFO *) class->ConstantPool[n - 1].
 99          Data)->NameAndTypeIndex = BufferToShort(buffer2);
100  
101      dmsg("CONSTANTPOOL_METHODREF");
102  }
103  
104  static
105  void _read_constant_interfacemethodref(int n, FILE* classfile, Class* class) {
106      unsigned char buffer2[2] = { 0, 0 }; 
107  
108      // Allocating memory for REF_INFO
109      class->ConstantPool[n - 1].Data = malloc(sizeof(struct CONSTANT_REF_INFO));
110  
111      // Read class index
112      _freadb(buffer2, 2, classfile);
113      ((struct CONSTANT_REF_INFO*)class->ConstantPool[n - 1].Data)->ClassIndex =
114          BufferToShort(buffer2);
115  
116      // Read name and type index
117      _freadb(buffer2, 2, classfile);
118      ((struct CONSTANT_REF_INFO *) class->ConstantPool[n - 1].
119          Data)->NameAndTypeIndex = BufferToShort(buffer2);
120  
121      dmsg("CONSTANTPOOL_INTERFACEMETHODREF");
122  }
123  
124  static
125  void _read_constant_string(int n, FILE* classfile, Class* class) {
126      unsigned char buffer2[2] = { 0, 0 };
127  
128      // Allocating memory for STRING_INFO
129      class->ConstantPool[n - 1].Data = malloc(sizeof(struct CONSTANT_STRING_INFO));
130  
131      // Read string index
132      _freadb(buffer2, 2, classfile);
133      ((struct CONSTANT_STRING_INFO *) class->ConstantPool[n - 1].Data)->StringIndex =
134          BufferToShort(buffer2);
135  
136      dmsg("CONSTANTPOOL_STRING");
137  }
138  
139  static
140  void _read_constant_utf8(int n, FILE* classfile, Class* class, int* attributeCodeIndex) {
141      unsigned char buffer2[2] = { 0, 0 };
142      n = n - 1; // ConstantPool starts at index 0
143  
144      // Allocating memory for UTF8_INFO
145      class->ConstantPool[n].Data = malloc(sizeof(struct CONSTANT_UTF8_INFO));
146  
147      // Read string length
148      _freadb(buffer2, 2, classfile);
149      uint16_t len = BufferToShort(buffer2);
150      ((struct CONSTANT_UTF8_INFO*)class->ConstantPool[n].Data)->Length = len;
151  
152      // Allocating memory for string
153      ((struct CONSTANT_UTF8_INFO*)class->ConstantPool[n].Data)->Text 
154          = (char*)malloc(len * sizeof(char) + 1);
155  
156      // Read string
157      _freadb(
158          (unsigned char*)((struct CONSTANT_UTF8_INFO*)class->ConstantPool[n].Data)->Text, 
159          len, classfile);
160  
161      // Terminating zero character
162      ((struct CONSTANT_UTF8_INFO*)class->ConstantPool[n].Data)->Text[
163          ((struct CONSTANT_UTF8_INFO*)class->ConstantPool[n].Data)->Length] = 0;
164  
165  #ifdef DEBUG
166      printf("CONSTANTPOOL_UTF8 -> %s (len=%d)\n",
167          ((struct CONSTANT_UTF8_INFO *)class->ConstantPool[n].Data)->Text,
168          ((struct CONSTANT_UTF8_INFO *)class->ConstantPool[n].Data)->Length);
169  #endif
170  
171      // Check for default attribute names
172      if (strcmp(((struct CONSTANT_UTF8_INFO*)class->ConstantPool[n].Data)->Text, "Code") == 0) {
173          *attributeCodeIndex = n + 1; // From zero-based index to class file index
174      }
175  }
176  
177  static
178  void _read_constant_integer(int n, FILE* classfile, Class* class) {
179      unsigned char buffer4[4] = { 0, 0, 0, 0 };
180      class->ConstantPool[n - 1].Data = malloc(sizeof(struct CONSTANT_INTEGER_INFO));
181  
182      // Read integer of four bytes
183      _freadb(buffer4, 4, classfile);
184      ((struct CONSTANT_INTEGER_INFO *)class->ConstantPool[n - 1].Data)->Value =
185          BufferToInt(buffer4);
186  
187      dmsg("CONSTANTPOOL_INTEGER");
188  }
189  
190  static
191  void _read_constant_long(int n, FILE* classfile, Class* class) {
192      uint64_t buffer8 = 0;
193  
194      class->ConstantPool[n - 1].Data = malloc(sizeof(struct CONSTANT_LONG_INFO));
195      _freadb((void*)&buffer8, 8, classfile);
196      buffer8 = bswp64(buffer8);
197      ((struct CONSTANT_LONG_INFO *)class->ConstantPool[n - 1].Data)->Value = buffer8;
198      dmsg("CONSTANTPOOL_LONG");   
199  }
200  
201  static
202  void _read_constant_float(int n, FILE* classfile, Class* class) {
203      unsigned char buffer4[4] = { 0, 0, 0, 0 };
204      class->ConstantPool[n - 1].Data = malloc(sizeof(struct CONSTANT_FLOAT_INFO));
205  
206      // Read float
207      _freadb(buffer4, 4, classfile);
208      ((struct CONSTANT_FLOAT_INFO *)class->ConstantPool[n - 1].Data)->Value =
209          (float)BufferToInt(buffer4);
210  
211      dmsg("CONSTANTPOOL_FLOAT");
212  }
213  
214  static
215  void _read_constant_double(int n, FILE* classfile, Class* class) {
216      double buf = 0;
217  
218      class->ConstantPool[n - 1].Data = malloc(sizeof(struct CONSTANT_DOUBLE_INFO));
219  
220      // TODO: Check if this really works
221      _freadb((void*)&buf, 8, classfile);
222      ((struct CONSTANT_DOUBLE_INFO*)class->ConstantPool[n-1].Data)->Value = buf;
223  
224      dmsg("CONSTANTPOOL_DOUBLE");
225  }
226  
227  static
228  void _read_constant_nameandtype(int n, FILE* classfile, Class* class) {
229      unsigned char buffer2[2] = { 0, 0 };
230  
231      // Allocating memory for NAMEANDTYPE_INFO
232      class->ConstantPool[n - 1].Data =
233          malloc(sizeof(struct CONSTANT_NAMETYPE_INFO));
234  
235      // Read name index
236      _freadb(buffer2, 2, classfile);
237      ((struct CONSTANT_NAMETYPE_INFO *)class->ConstantPool[n - 1].Data)->NameIndex 
238          = BufferToShort(buffer2);
239  
240      // Read descriptor index
241      _freadb(buffer2, 2, classfile);
242      ((struct CONSTANT_NAMETYPE_INFO *)class->ConstantPool[n - 1].Data)->DescriptorIndex 
243          = BufferToShort(buffer2);
244  
245      dmsg("CONSTANTPOOL_NAMETYPE");
246  }
247  
248  static
249  void _read_constant_class(int n, FILE* classfile, Class* class) {
250      unsigned char buffer2[2] = { 0, 0 };
251  
252      // Allocating memory for CLASS_INFO
253      class->ConstantPool[n - 1].Data = malloc(sizeof(struct CONSTANT_CLASS_INFO));
254  
255      // Read name index
256      _freadb(buffer2, 2, classfile);
257      ((struct CONSTANT_CLASS_INFO *)class->ConstantPool[n - 1].Data)->NameIndex =
258          BufferToShort(buffer2);
259  
260  #ifdef DEBUG
261      printf("CONSTANTPOOL_CLASS (NameIndex=%d) read.\n", ((struct CONSTANT_CLASS_INFO *)
262          class->ConstantPool[n - 1].Data)->NameIndex);
263  #endif
264  }
265  
266  static
267  void _read_field(int n, FILE* classfile, Class* class) {
268      unsigned char buffer2[2] = { 0, 0 };
269      unsigned char buffer4[4] = { 0, 0, 0, 0 };
270  
271      // Read access flags
272      _freadb(buffer2, 2, classfile);
273      class->fieldInfos[n].AccessFlags = BufferToShort(buffer2);
274  
275      // Read name index
276      _freadb(buffer2, 2, classfile);
277      class->fieldInfos[n].NameIndex = BufferToShort(buffer2);
278  
279      // Read descriptor index
280      _freadb(buffer2, 2, classfile);
281      class->fieldInfos[n].DescriptorIndex = BufferToShort(buffer2);
282  
283      // Read attributes count
284      _freadb(buffer2, 2, classfile);
285      class->fieldInfos[n].AttributesNum = BufferToShort(buffer2);
286  
287      // Read attributes
288      class->fieldInfos[n].Attributes = (struct ATTRIBUTE_INFO *)
289          malloc(sizeof(struct ATTRIBUTE_INFO) * class->fieldInfos[n].AttributesNum);
290      for (int m = 0; m < class->fieldInfos[n].AttributesNum; m++) {
291          // Read attribute name index
292          _freadb(buffer2, 2, classfile);
293          class->fieldInfos[n].Attributes[m].AttributeNameIndex = BufferToShort(buffer2);
294  
295          // Read length of info array
296          _freadb(buffer4, 4, classfile);
297          class->fieldInfos[n].Attributes[m].AttributeLength = BufferToInt(buffer4);
298  
299          // Allocate space for infos
300          class->fieldInfos[n].Attributes[m].Info = 
301              (unsigned char*) malloc(class->fieldInfos[n].Attributes[m].AttributeLength);
302              _freadb(class->fieldInfos[n].Attributes[m].Info,
303                      class->fieldInfos[n].Attributes[m].AttributeLength,
304                      classfile);
305      }
306  }
307  
308  void _read_attribute_info(struct ATTRIBUTE_INFO * attributeInfo, FILE* classfile)
309  {
310      unsigned char buffer2[2];
311      unsigned char buffer4[4];
312  
313      // Read attribute name index
314      _freadb(buffer2, 2, classfile);
315      attributeInfo->AttributeNameIndex = BufferToShort(buffer2);
316  
317      // Read length of info array
318      _freadb(buffer4, 4, classfile);
319      attributeInfo->AttributeLength = BufferToInt(buffer4);
320  
321      // Allocate space for infos
322      attributeInfo->Info = (unsigned char*) malloc(sizeof(unsigned char) *
323                                      attributeInfo->AttributeLength);
324  
325      if (attributeInfo->Info == NULL) {
326          printf("malloc failed\n");
327          return;
328      }
329  
330      _freadb(attributeInfo->Info, attributeInfo->AttributeLength, classfile);
331  }
332  
333  static
334  void _read_method_info(Class * class, FILE* classfile, int mainIndex, 
335                          int attributeCodeIndex)
336  {
337      unsigned char buffer2[2];
338      dbgmsg("Begin reading method_info_t...\n");
339  
340      // Read methods count
341      _freadb(buffer2, 2, classfile);
342      class->MethodsNum = BufferToShort(buffer2);
343  
344      // Read methods
345      class->Methods = (Method*)malloc(sizeof(Method) * class->MethodsNum);
346  
347      if (class->Methods == NULL) {
348          printf("malloc failed\n");
349          return;
350      }
351  
352      for (int n = 0; n < class->MethodsNum; n++) {
353          // Read access flags
354          _freadb(buffer2, 2, classfile);
355          class->Methods[n].AccessFlags = BufferToShort(buffer2);
356  
357          // Read name index
358          _freadb(buffer2, 2, classfile);
359          class->Methods[n].NameIndex = BufferToShort(buffer2);
360          if (class->Methods[n].NameIndex == mainIndex) {
361              class->MainMethodIndex = n + 1;
362          }
363  
364          // Read descriptor index
365          _freadb(buffer2, 2, classfile);
366          class->Methods[n].DescriptorIndex = BufferToShort(buffer2);
367  
368          // Read attributes count
369          _freadb(buffer2, 2, classfile);
370          class->Methods[n].AttributesNum = BufferToShort(buffer2);
371  
372          // Read attributes
373          class->Methods[n].Attributes = (struct ATTRIBUTE_INFO *)
374              malloc(sizeof(struct ATTRIBUTE_INFO) * class->Methods[n].AttributesNum);
375  
376          for (int m = 0; m < class->Methods[n].AttributesNum; m++) {
377              // Read standard attribute
378              _read_attribute_info(class->Methods[n].Attributes + m, classfile);
379  
380              // Check for special attributes
381              if (class->Methods[n].Attributes[m].AttributeNameIndex == attributeCodeIndex) {
382                  dbgmsg("Code Info detected\n");
383  
384                  class->Methods[n].CodeInfo = (struct ATTRIBUTE_INFO_CODE *)
385                      malloc(sizeof(struct ATTRIBUTE_INFO_CODE));
386                  class->Methods[n].CodeInfo->AttributeNameIndex = attributeCodeIndex;
387  
388                  // Attribute length
389                  class->Methods[n].CodeInfo->AttributeLength
390                      = class->Methods[n].Attributes[m].AttributeLength;
391  
392                  // Read max. stack (2 Byte) */
393                  class->Methods[n].operandStackSize =
394                      BufferToShort(class->Methods[n].Attributes[m].Info + 0);
395  
396                  /* Allocate operand stack */
397                  /*vmclass->Methods[n].StackFrameRef.OperandStack
398                     = (struct OperandStackFrame*)malloc(sizeof(struct OperandStackFrame) * vmclass->Methods[n].StackFrameRef.OperandStackSize);
399                   */
400                  // Read max locals (2 Byte)
401                  class->Methods[n].localVarsLen = 
402                      BufferToShort(class->Methods[n].Attributes[m].Info + 2);
403                  /* Where is StackFrameRef.localVars initialized?
404                   * Does it make sense to store the localVarsLen in a stackframe?
405                   * */
406  
407                  // Read code length (4 Byte)
408                  class->Methods[n].CodeInfo->CodeLength =
409                      BufferToInt(class->Methods[n].Attributes[m].Info + 4);
410  #ifdef DEBUG
411                  printf("Code Length %d\n", class->Methods[n].CodeInfo->CodeLength);
412  #endif
413  
414                  // Code
415                  class->Methods[n].CodeInfo->Code = malloc(sizeof(unsigned char) *
416                      class->Methods[n].CodeInfo->CodeLength);
417                  for (int i = 0; i < (int)class->Methods[n].CodeInfo->CodeLength; i++)
418                      class->Methods[n].CodeInfo->Code[i] = *(class->Methods[n].Attributes[m].Info + 8 + i);
419  
420                  // Exception table length (2 Byte)
421                  class->Methods[n].CodeInfo->ExceptionTableLength =
422                      BufferToShort(class->Methods[n].Attributes[m].Info + 8 +
423                                    class->Methods[n].CodeInfo->CodeLength);
424  #ifdef DEBUG
425                  printf("Exception Table Length: %d\n",
426                         class->Methods[n].CodeInfo->ExceptionTableLength);
427  #endif
428  
429                  // Exception Table
430                  // TODO
431  
432                  // Attributes num
433                  class->Methods[n].CodeInfo->AttributesNum =
434                      BufferToShort(class->Methods[n].Attributes[m].Info +
435                                    10 +
436                                    class->Methods[n].
437                                    CodeInfo->CodeLength +
438                                    class->Methods[n].
439                                    CodeInfo->ExceptionTableLength * 8);
440  #ifdef DEBUG
441                  printf("AttributesNum: %d\n", class->Methods[n].CodeInfo->AttributesNum);
442  #endif
443  
444                  // Attribute Infos
445                  class->Methods[n].CodeInfo->Attributes = (struct ATTRIBUTE_INFO *)
446                      malloc(sizeof(struct ATTRIBUTE_INFO) *
447                          class->Methods[n].CodeInfo->AttributesNum);
448              }
449          }
450      }
451  
452      // Set fully qualified name
453      class->QualifiedName = ""; // TODO
454  }
455  
456  bool Classloader_loadClass(FILE* classfile, Class* class) {
457      if (classfile == nullptr) {
458  #ifdef DEBUG
459          printf("IO-Error: %u\n", ferror(classfile));
460  #endif
461          return false;
462      }
463  
464      int attributeCodeIndex = 0;
465      int mainIndex = 0;
466      unsigned char buffer1 = 0;
467      unsigned char buffer2[2] = { 0, 0 };
468      unsigned char buffer4[4] = { 0, 0, 0, 0 };
469  
470      // Set init values
471      class->AccessFlags = 0x0000;
472  
473      dbgmsg("Class file opened.");
474  
475      // Read Magic
476      _freadb(buffer4, 4, classfile);
477      if (memcmp(buffer4, "\xCA\xFE\xBA\xBE", 4) != 0) {
478          printf("Class file has invalid magic! Read: %x %x %x %x\n", buffer4[0], buffer4[1], buffer4[2], buffer4[3]);
479          return false;
480      }
481  
482      // Read minor version
483      _freadb(buffer2, 2, classfile);
484      class->Version.Minor = BufferToShort(buffer2);
485  
486      // Read major version
487      _freadb(buffer2, 2, classfile);
488      class->Version.Major = BufferToShort(buffer2);
489  #ifdef DEBUG
490      printf("Class Version: %d.%d\n", class->Version.Major, class->Version.Minor);
491  #endif
492  
493      // Read constant pool count
494      _freadb(buffer2, 2, classfile);
495      class->ConstantPoolNum = BufferToShort(buffer2);
496  #ifdef DEBUG
497      printf("Constant pool count: %d\n", class->ConstantPoolNum);
498  #endif
499  
500      // Allocate memory for constant pool
501      class->ConstantPool = (struct CONSTANTPOOL*)malloc(
502          class->ConstantPoolNum * sizeof(struct CONSTANTPOOL));
503  
504      // Read constants from pool
505      for (int n = 1; n < class->ConstantPoolNum; n++) {
506          _freadb(&buffer1, 1, classfile);
507          class->ConstantPool[n - 1].Tag = buffer1;
508  
509  #ifdef DEBUG
510          printf("%d: Constant Type %d\t", n, buffer1);
511  #endif
512  
513          switch (class->ConstantPool[n - 1].Tag) {
514              case CONSTANTPOOL_FIELDREF: {
515                  _read_constant_fieldref(n, classfile, class);
516                  break;
517              }
518              case CONSTANTPOOL_CLASS: {
519                  _read_constant_class(n, classfile, class);
520                  break;
521              }
522              case CONSTANTPOOL_METHODREF: {
523                  _read_constant_methodref(n, classfile, class);
524                  break;
525              }
526              case CONSTANTPOOL_INTERFACEMETHODREF: {
527                  _read_constant_interfacemethodref(n, classfile, class);
528                  break;
529              }
530              case CONSTANTPOOL_STRING: {
531                  _read_constant_string(n, classfile, class);
532                  break;
533              }
534              case CONSTANTPOOL_INTEGER: {
535                  _read_constant_integer(n, classfile, class);
536                  break;
537              }
538              case CONSTANTPOOL_FLOAT: {
539                  _read_constant_float(n, classfile, class);
540                  break;
541              }
542              case CONSTANTPOOL_LONG: {
543                  _read_constant_long(n, classfile, class);
544                  break;
545              }
546              case CONSTANTPOOL_DOUBLE: {
547                  _read_constant_double(n, classfile, class);
548                  break;
549              }
550              case CONSTANTPOOL_NAMEANDTYPE: {
551                  _read_constant_nameandtype(n, classfile, class);
552                  break;
553              }
554              case CONSTANTPOOL_UTF8: {
555                  _read_constant_utf8(n, classfile, class, &attributeCodeIndex);
556                  break;
557              }
558              default: {
559                  printf("Unknown constant type: %d!\n", class->ConstantPool[n - 1].Tag);
560                  fclose(classfile);
561                  return false;
562              }
563          } // end switch
564      } // end for
565  
566      // Read access flags
567      _freadb(buffer2, 2, classfile);
568      class->AccessFlags = BufferToShort(buffer2);
569  
570      // Read this class index
571      _freadb(buffer2, 2, classfile);
572      class->ThisClassIndex = BufferToShort(buffer2);
573  
574      // Read super class index
575      _freadb(buffer2, 2, classfile);
576      class->SuperClassIndex = BufferToShort(buffer2);
577  
578      // Read interface count
579      _freadb(buffer2, 2, classfile);
580      class->InterfacesNum = BufferToShort(buffer2);
581  
582      // Read interface indices
583      class->Interfaces =
584          (unsigned short*)malloc(sizeof(unsigned short) * class->InterfacesNum);
585      for (int n = 0; n < class->InterfacesNum; n++) {
586          _freadb(buffer2, 2, classfile);
587          class->Interfaces[n] = BufferToShort(buffer2);
588      }
589  
590      // Read fields count
591      _freadb(buffer2, 2, classfile);
592      class->fieldsNum = BufferToShort(buffer2);
593  
594      // Read field infos
595      class->fieldInfos = (FieldInfo*)malloc(sizeof(FieldInfo) * class->fieldsNum);
596      class->fieldValues = (Varframe*)malloc(sizeof(Varframe) * class->fieldsNum);
597  
598      for (int n = 0; n < class->fieldsNum; n++) {
599          _read_field(n, classfile, class);
600      }
601  
602      // Read methods
603      _read_method_info(class, classfile, mainIndex, attributeCodeIndex);
604  
605      // Read attributes count
606      _freadb(buffer2, 2, classfile);
607      class->AttributesNum = BufferToShort(buffer2);
608  
609      // Read attributes
610      class->Attributes = (struct ATTRIBUTE_INFO *)
611              malloc(sizeof(struct ATTRIBUTE_INFO) * class->AttributesNum);
612      for (int m = 0; m < class->AttributesNum; m++) {
613          // Read attribute name index
614          _freadb(buffer2, 2, classfile);
615          class->Attributes[m].AttributeNameIndex = BufferToShort(buffer2);
616  
617          // Read length of info array
618          _freadb(buffer4, 4, classfile);
619          class->Attributes[m].AttributeLength = BufferToInt(buffer4);
620  
621          // Allocate space for infos
622          class->Attributes[m].Info = (unsigned char*)malloc(sizeof(struct ATTRIBUTE_INFO) *
623                            class->Attributes[m].AttributeLength);
624          _freadb(class->Attributes[m].Info, class->Attributes[m].AttributeLength, classfile);
625      }
626  
627      // Trigger EOF
628      fgetc(classfile);
629  
630      if (!feof(classfile)) {
631          printf("Class not wellformed: unused data at end of file!\n");
632  #ifdef DEBUG
633          while(!feof(classfile)) {
634              unsigned char buf = 0;
635              _freadb(&buf, 1, classfile);
636              printf("0x%X ", buf);
637          }
638          printf("\n");
639  #endif
640      }
641  
642      fclose(classfile);
643  
644      return true;
645  }
646  
647  FILE* find_class_file(const char* class)
648  {
649  #ifdef ATMEGA
650      // TODO FIXME
651      return NULL;
652  #endif
653  
654  #ifdef DEBUG
655      printf("Using %s as classpath\n", vm->classpath);
656  #endif
657      
658      // Argument class is the Java class name with slashes as separator
659      // instead of points, e.g. "java/lang/System".
660      char* class_file = malloc(sizeof(char) * (sizeof(class) + sizeof(".class")));
661      strcpy(class_file, class);
662  
663      // At first we add ".class", 7 is length of str plus '\0'
664      strncat(class_file, ".class", 7);
665  
666      // Then we try all classpaths for the given class file
667      // (currently there is only one classpath (and "."))
668      FILE* file = fopen(class_file, "rb");
669  #ifdef DEBUG
670      printf("Trying '%s'\n", class_file);
671  #endif
672      if (file != NULL) {
673          free(class_file);
674          return file;
675      }
676  
677      // FIXME
678      char* class_file_path = malloc(sizeof(char) *
679          (strlen(class_file) + strlen(vm->classpath) + 1));
680      strcpy(class_file_path, vm->classpath);
681      class_file_path = strncat(class_file_path, class_file, strlen(class_file));
682      file = fopen(class_file_path, "rb");
683  #ifdef DEBUG
684      printf("Trying '%s'\n", class_file_path);
685  #endif    
686  
687      // If we found it, we return the FILE handle to it
688      free(class_file);
689      return file;
690  }