public void parse() throws IOException {
    setDexOptimizationData(dexSignatureBlock.getDexOptimizationData());
    int classSize = (int) dexPointerBlock.getClassDefsSize();
    file.seek(dexPointerBlock.getClassDefsOffset());
    classMap = new HashMap<Integer, ClassHolder>();
    HashMap<Integer, TempClassHolder> tempClassMap = new HashMap<Integer, TempClassHolder>();
    for (int i = 0; i < classSize; ++i) {
      int classIdx = (int) read32Bit();
      ClassHolder classHolder = new ClassHolder();
      TempClassHolder tempClassHolder = new TempClassHolder();
      classHolder.access = (int) read32Bit();
      classHolder.superclassTypeId = (int) read32Bit();
      tempClassHolder.interfacesOffset = readFileOffset();
      classHolder.sourceFileNameStringId = (int) read32Bit();
      tempClassHolder.annotationsOffset = readFileOffset();
      tempClassHolder.classDataOffset = readFileOffset();
      tempClassHolder.staticValuesOffset = readFileOffset();
      Integer mapKey = new Integer(classIdx);
      classMap.put(mapKey, classHolder);
      tempClassMap.put(mapKey, tempClassHolder);
      dump(
          accessFlagsToString(classHolder.access, ItemType.CLASS)
              + dexTypeIdsBlock.getClassName(classIdx));
    }
    // Now process the auxiliary data blocks according to the offsets stored
    // in TempClassHolder instances
    for (Iterator<Integer> it = classMap.keySet().iterator(); it.hasNext(); ) {

      Integer key = it.next();

      // if(dexTypeIdsBlock.getClassName(key.intValue()).startsWith("es/ugr/decsai/lazy/Metauser")){
      System.out.println("---------->" + dexTypeIdsBlock.getClassName(key.intValue()));
      ClassHolder classHolder = classMap.get(key);
      dump(
          "// "
              + accessFlagsToString(classHolder.access, ItemType.CLASS)
              + " class "
              + dexTypeIdsBlock.getClassName(key.intValue())
              + ":");
      if (classHolder.superclassTypeId >= 0)
        dump("// super: " + dexTypeIdsBlock.getClassName(classHolder.superclassTypeId));
      if (classHolder.sourceFileNameStringId >= 0)
        dump("// source: " + dexStringIdsBlock.getString(classHolder.sourceFileNameStringId));
      TempClassHolder tempClassHolder = tempClassMap.get(key);
      // Build the interface type table for the class
      if (tempClassHolder.interfacesOffset != 0L) {
        file.seek(tempClassHolder.interfacesOffset);
        int interfacesSize = (int) read32Bit();
        classHolder.interfaceTypes = new int[interfacesSize];
        for (int i = 0; i < interfacesSize; ++i) {
          classHolder.interfaceTypes[i] = read16Bit();
          dump("// implements " + dexTypeIdsBlock.getType(classHolder.interfaceTypes[i]));
        }
      }
      // Build the class data table
      if (tempClassHolder.classDataOffset != 0L) {
        file.seek(tempClassHolder.classDataOffset);
        int staticFieldsSize = (int) readVLN();
        dump("static fields size: " + staticFieldsSize);
        int instanceFieldsSize = (int) readVLN();
        dump("instance fields size: " + instanceFieldsSize);
        int directMethodsSize = (int) readVLN();
        dump("direct methods size: " + directMethodsSize);
        int virtualMethodsSize = (int) readVLN();
        dump("virtual methods size: " + virtualMethodsSize);
        // Process the static fields
        if (staticFieldsSize > 0) {
          classHolder.staticFields = new FieldHolder[staticFieldsSize];
          int fieldIdCounter = 0;
          for (int i = 0; i < staticFieldsSize; ++i) {
            FieldHolder staticFieldHolder = new FieldHolder();
            fieldIdCounter += (int) readVLN();
            staticFieldHolder.fieldId = fieldIdCounter;
            staticFieldHolder.access = (int) readVLN();
            classHolder.staticFields[i] = staticFieldHolder;
            dump(
                "// static field["
                    + i
                    + "]: "
                    + dexFieldIdsBlock.getFieldShortName(staticFieldHolder.fieldId));
          }
        }
        // Process the instance fields
        if (instanceFieldsSize > 0) {
          classHolder.instanceFields = new FieldHolder[instanceFieldsSize];
          int fieldIdCounter = 0;
          for (int i = 0; i < instanceFieldsSize; ++i) {
            FieldHolder instanceFieldHolder = new FieldHolder();
            fieldIdCounter += (int) readVLN();
            instanceFieldHolder.fieldId = fieldIdCounter;
            instanceFieldHolder.access = (int) readVLN();
            classHolder.instanceFields[i] = instanceFieldHolder;
            dump(
                "// instance field["
                    + i
                    + "]: "
                    + dexFieldIdsBlock.getFieldShortName(instanceFieldHolder.fieldId));
          }
        }
        // Process the direct methods
        if (directMethodsSize > 0) {
          classHolder.directMethods = new MethodHolder[directMethodsSize];
          int methodIdCounter = 0;
          for (int i = 0; i < directMethodsSize; ++i) {
            MethodHolder directMethodHolder = new MethodHolder();
            methodIdCounter += (int) readVLN();
            directMethodHolder.methodId = methodIdCounter;
            directMethodHolder.access = (int) readVLN();
            directMethodHolder.offset = readFileOffsetVLN();
            classHolder.directMethods[i] = directMethodHolder;
            dump(
                "// direct method["
                    + i
                    + "]: "
                    + dexMethodIdsBlock.getProto(directMethodHolder.methodId));
          }
        }
        // Process the virtual methods
        if (virtualMethodsSize > 0) {
          classHolder.virtualMethods = new MethodHolder[virtualMethodsSize];
          int methodIdCounter = 0;
          for (int i = 0; i < virtualMethodsSize; ++i) {
            MethodHolder virtualMethodHolder = new MethodHolder();
            methodIdCounter += (int) readVLN();
            virtualMethodHolder.methodId = methodIdCounter;
            virtualMethodHolder.access = (int) readVLN();
            virtualMethodHolder.offset = readFileOffsetVLN();
            classHolder.virtualMethods[i] = virtualMethodHolder;
            dump(
                "// virtual method["
                    + i
                    + "]: "
                    + dexMethodIdsBlock.getProto(virtualMethodHolder.methodId));
          }
        }
      }
      if (tempClassHolder.staticValuesOffset != 0L) {
        DexEncodedArrayParser deap = new DexEncodedArrayParser();
        deap.setRandomAccessFile(file);
        deap.setDumpFile(dump);
        deap.setDexStringIdsBlock(dexStringIdsBlock);
        deap.setDexTypeIdsBlock(dexTypeIdsBlock);
        deap.setDexFieldIdsBlock(dexFieldIdsBlock);
        deap.setDexMethodIdsBlock(dexMethodIdsBlock);
        deap.setFilePosition(tempClassHolder.staticValuesOffset);
        deap.parse();
        for (int i = 0; i < deap.getArraySize(); ++i) {
          if (i < classHolder.staticFields.length) { // paranoia, it has to be smaller
            FieldHolder fieldHolder = classHolder.staticFields[i];
            fieldHolder.initialValue = deap.getArrayElement(i);
          }
        }
      }
      if (tempClassHolder.annotationsOffset != 0L) {
        DexAnnotationParser dexAnnotationParser = new DexAnnotationParser();
        dexAnnotationParser.setRandomAccessFile(file);
        dexAnnotationParser.setDumpFile(dump);
        dexAnnotationParser.setDexTypeIdsBlock(dexTypeIdsBlock);
        dexAnnotationParser.setDexStringIdsBlock(dexStringIdsBlock);
        dexAnnotationParser.setDexFieldIdsBlock(dexFieldIdsBlock);
        dexAnnotationParser.setDexMethodIdsBlock(dexMethodIdsBlock);
        dexAnnotationParser.setDexSignatureBlock(dexSignatureBlock);
        try {
          dexAnnotationParser.parse(tempClassHolder.annotationsOffset);
        } catch (UnknownInstructionException ex) {
        } // can't happen
        classHolder.annotationParser = dexAnnotationParser;
      }
      // }
    }
  }