docs: public void accept(final ClassVisitor classVisitor,
              final Attribute[] attrs, final int flags) {
          int u = header; // current offset in the class file
          char[] c = new char[maxStringLength]; // buffer used to read strings
  
          Context context = new Context();
          context.attrs = attrs;
          context.flags = flags;
          context.buffer = c;
  
          // reads the class declaration
          int access = readUnsignedShort(u);
          String name = readClass(u + 2, c);
          String superClass = readClass(u + 4, c);
          String[] interfaces = new String[readUnsignedShort(u + 6)];
          u += 8;
          for (int i = 0; i < interfaces.length; ++i) {
              interfaces[i] = readClass(u, c);
              u += 2;
          }
  
          // reads the class attributes
          String signature = null;
          String sourceFile = null;
          String sourceDebug = null;
          String enclosingOwner = null;
          String enclosingName = null;
          String enclosingDesc = null;
          String moduleMainClass = null;
          int anns = 0;
          int ianns = 0;
          int tanns = 0;
          int itanns = 0;
          int innerClasses = 0;
          int module = 0;
          int packages = 0;
          Attribute attributes = null;
  
          u = getAttributes();
          for (int i = readUnsignedShort(u); i > 0; --i) {
              String attrName = readUTF8(u + 2, c);
              // tests are sorted in decreasing frequency order
              // (based on frequencies observed on typical classes)
              if ("SourceFile".equals(attrName)) {
                  sourceFile = readUTF8(u + 8, c);
              } else if ("InnerClasses".equals(attrName)) {
                  innerClasses = u + 8;
              } else if ("EnclosingMethod".equals(attrName)) {
                  enclosingOwner = readClass(u + 8, c);
                  int item = readUnsignedShort(u + 10);
                  if (item != 0) {
                      enclosingName = readUTF8(items[item], c);
                      enclosingDesc = readUTF8(items[item] + 2, c);
                  }
              } else if ("Signature".equals(attrName)) {
                  signature = readUTF8(u + 8, c);
              } else if ("RuntimeVisibleAnnotations".equals(attrName)) {
                  anns = u + 8;
              } else if ("RuntimeVisibleTypeAnnotations".equals(attrName)) {
                  tanns = u + 8;
              } else if ("Deprecated".equals(attrName)) {
                  access |= Opcodes.ACC_DEPRECATED;
              } else if ("Synthetic".equals(attrName)) {
                  access |= Opcodes.ACC_SYNTHETIC
                          | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE;
              } else if ("SourceDebugExtension".equals(attrName)) {
                  int len = readInt(u + 4);
                  sourceDebug = readUTF(u + 8, len, new char[len]);
              } else if ("RuntimeInvisibleAnnotations".equals(attrName)) {
                  ianns = u + 8;
              } else if ("RuntimeInvisibleTypeAnnotations".equals(attrName)) {
                  itanns = u + 8;
              } else if ("Module".equals(attrName)) {
                  module = u + 8;
              } else if ("ModuleMainClass".equals(attrName)) {
                  moduleMainClass = readClass(u + 8, c);
              } else if ("ModulePackages".equals(attrName)) {
                  packages = u + 10;
              } else if ("BootstrapMethods".equals(attrName)) {
                  int[] bootstrapMethods = new int[readUnsignedShort(u + 8)];
                  for (int j = 0, v = u + 10; j < bootstrapMethods.length; j++) {
                      bootstrapMethods[j] = v;
                      v += 2 + readUnsignedShort(v + 2) << 1;
                  }
                  context.bootstrapMethods = bootstrapMethods;
              } else {
                  Attribute attr = readAttribute(attrs, attrName, u + 8,
                          readInt(u + 4), c, -1, null);
                  if (attr != null) {
                      attr.next = attributes;
                      attributes = attr;
                  }
              }
              u += 6 + readInt(u + 4);
          }
  
          // visits the class declaration
          classVisitor.visit(readInt(items[1] - 7), access, name, signature,
                  superClass, interfaces);
  
          // visits the source and debug info
          if ((flags & SKIP_DEBUG) == 0
                  && (sourceFile != null || sourceDebug != null)) {
              classVisitor.visitSource(sourceFile, sourceDebug);
          }
  
          // visits the module info and associated attributes
          if (module != 0) {
              readModule(classVisitor, context, module,
                      moduleMainClass, packages);
          }
  
          // visits the outer class
          if (enclosingOwner != null) {
              classVisitor.visitOuterClass(enclosingOwner, enclosingName,
                      enclosingDesc);
          }
  
          // visits the class annotations and type annotations
          if (anns != 0) {
              for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) {
                  v = readAnnotationValues(v + 2, c, true,
                          classVisitor.visitAnnotation(readUTF8(v, c), true));
              }
          }
          if (ianns != 0) {
              for (int i = readUnsignedShort(ianns), v = ianns + 2; i > 0; --i) {
                  v = readAnnotationValues(v + 2, c, true,
                          classVisitor.visitAnnotation(readUTF8(v, c), false));
              }
          }
          if (tanns != 0) {
              for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) {
                  v = readAnnotationTarget(context, v);
                  v = readAnnotationValues(v + 2, c, true,
                          classVisitor.visitTypeAnnotation(context.typeRef,
                                  context.typePath, readUTF8(v, c), true));
              }
          }
          if (itanns != 0) {
              for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) {
                  v = readAnnotationTarget(context, v);
                  v = readAnnotationValues(v + 2, c, true,
                          classVisitor.visitTypeAnnotation(context.typeRef,
                                  context.typePath, readUTF8(v, c), false));
              }
          }
  
          // visits the attributes
          while (attributes != null) {
              Attribute attr = attributes.next;
              attributes.next = null;
              classVisitor.visitAttribute(attributes);
              attributes = attr;
          }
  
          // visits the inner classes
          if (innerClasses != 0) {
              int v = innerClasses + 2;
              for (int i = readUnsignedShort(innerClasses); i > 0; --i) {
                  classVisitor.visitInnerClass(readClass(v, c),
                          readClass(v + 2, c), readUTF8(v + 4, c),
                          readUnsignedShort(v + 6));
                  v += 8;
              }
          }
  
          // visits the fields and methods
          u = header + 10 + 2 * interfaces.length;
          for (int i = readUnsignedShort(u - 2); i > 0; --i) {
              u = readField(classVisitor, context, u);
          }
          u += 2;
          for (int i = readUnsignedShort(u - 2); i > 0; --i) {
              u = readMethod(classVisitor, context, u);
          }
  
          // visits the end of the class
          classVisitor.visitEnd();
      }