Set parseClassFileData()

in framework/src/main/java/org/apache/felix/framework/util/ClassParser.java [785:1054]


        Set<String> parseClassFileData(DataInput in) throws Exception
        {

            ++depth;

            boolean crawl = false; // Crawl the byte code if we have a
            // collector
            int magic = in.readInt();
            if (magic != 0xCAFEBABE)
            {
                throw new IOException("Not a valid class file (no CAFEBABE header)");
            }

            minor = in.readUnsignedShort(); // minor version
            major = in.readUnsignedShort(); // major version
            int count = in.readUnsignedShort();
            pool = new Object[count];
            intPool = new int[count];

            CONSTANT[] tags = CONSTANT.values();
            process:
            for (int poolIndex = 1; poolIndex < count; poolIndex++)
            {
                int tagValue = in.readUnsignedByte();
                if (tagValue >= tags.length)
                {
                    throw new IOException("Unrecognized constant pool tag value " + tagValue);
                }
                CONSTANT tag = tags[tagValue];
                switch (tag)
                {
                    case Zero:
                        break process;
                    case Utf8:
                        constantUtf8(in, poolIndex);
                        break;
                    case Integer:
                        constantInteger(in, poolIndex);
                        break;
                    case Float:
                        constantFloat(in, poolIndex);
                        break;
                    // For some insane optimization reason,
                    // the long and double entries take two slots in the
                    // constant pool. See 4.4.5
                    case Long:
                        constantLong(in, poolIndex);
                        poolIndex++;
                        break;
                    case Double:
                        constantDouble(in, poolIndex);
                        poolIndex++;
                        break;
                    case Class:
                        constantClass(in, poolIndex);
                        break;
                    case String:
                        constantString(in, poolIndex);
                        break;
                    case Fieldref:
                    case Methodref:
                    case InterfaceMethodref:
                        ref(in, poolIndex);
                        break;
                    case NameAndType:
                        nameAndType(in, poolIndex, tag);
                        break;
                    case MethodHandle:
                        methodHandle(in, poolIndex, tag);
                        break;
                    case MethodType:
                        methodType(in, poolIndex, tag);
                        break;
                    case InvokeDynamic:
                        invokeDynamic(in, poolIndex, tag);
                        break;
                    default:
                        int skip = tag.skip();
                        if (skip == -1)
                        {
                            throw new IOException("Invalid tag " + tag);
                        }
                        in.skipBytes(skip);
                        break;
                }
            }

            pool(pool, intPool);

            // All name& type and class constant records contain classParser we must
            // treat
            // as references, though not API
            for (Object o : pool)
            {
                if (o == null)
                {
                    continue;
                }

                if (o instanceof Assoc)
                {
                    Assoc assoc = (Assoc) o;
                    switch (assoc.tag)
                    {
                        case Fieldref:
                        case Methodref:
                        case InterfaceMethodref:
                            classConstRef(assoc.a);
                            break;

                        case NameAndType:
                        case MethodType:
                            referTo(assoc.b, 0); // Descriptor
                            break;
                        default:
                            break;
                    }
                }
            }

            //
            // There is a bug in J8 compiler that leaves an
            // orphan class constant. So when we have a CC that
            // is not referenced by fieldrefs, method refs, or other
            // refs then we need to crawl the byte code.
            //
            for (Object o : pool)
            {
                if (o instanceof ClassConstant)
                {
                    ClassConstant cc = (ClassConstant) o;
                    if (!cc.referred)
                    {
                        detectLdc = true;
                    }
                }
            }

            /*
             * Parse after the constant pool, code thanks to Hans Christian
             * Falkenberg
             */

            accessx = in.readUnsignedShort(); // access

            int this_class = in.readUnsignedShort();
            className = classParser.getTypeRef((String) pool[intPool[this_class]]);
            if (!isModule())
            {
                referTo(className, Modifier.PUBLIC);
            }

            int super_class = in.readUnsignedShort();
            String superName = (String) pool[intPool[super_class]];
            if (superName != null)
            {
                zuper = classParser.getTypeRef(superName);
            }

            if (zuper != null)
            {
                referTo(zuper, accessx);
            }

            int interfacesCount = in.readUnsignedShort();
            if (interfacesCount > 0)
            {
                interfaces = new TypeRef[interfacesCount];
                for (int i = 0; i < interfacesCount; i++)
                {
                    interfaces[i] = classParser.getTypeRef((String) pool[intPool[in.readUnsignedShort()]]);
                    referTo(interfaces[i], accessx);
                }
            }

            int fieldsCount = in.readUnsignedShort();
            for (int i = 0; i < fieldsCount; i++)
            {
                int access_flags = in.readUnsignedShort(); // skip access flags
                int name_index = in.readUnsignedShort();
                int descriptor_index = in.readUnsignedShort();

                // Java prior to 1.5 used a weird
                // static variable to hold the com.X.class
                // result construct. If it did not find it
                // it would create a variable class$com$X
                // that would be used to hold the class
                // object gotten with Class.forName ...
                // Stupidly, they did not actively use the
                // class name for the field type, so bnd
                // would not see a reference. We detect
                // this case and add an artificial descriptor
                String name = pool[name_index].toString(); // name_index
                if (name.startsWith("class$") || name.startsWith("$class$"))
                {
                    crawl = true;
                }

                referTo(descriptor_index, access_flags);
                doAttributes(in, ElementType.FIELD, false, access_flags);
            }

            //
            // Check if we have to crawl the code to find
            // the ldc(_w) <string constant> invokestatic Class.forName
            // if so, calculate the method ref index so we
            // can do this efficiently
            //
            if (crawl)
            {
                forName = findMethodReference("java/lang/Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;");
                class$ = findMethodReference(className.getBinary(), "class$", "(Ljava/lang/String;)Ljava/lang/Class;");
            }
            else if (major == 48)
            {
                forName = findMethodReference("java/lang/Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;");
                if (forName > 0)
                {
                    crawl = true;
                    class$ = findMethodReference(className.getBinary(), "class$",
                        "(Ljava/lang/String;)Ljava/lang/Class;");
                }
            }

            // There are some serious changes in the
            // class file format. So we do not do any crawling
            // it has also become less important
            // however, jDK8 has a bug that leaves an orphan ClassConstnat
            // so if we have those, we need to also crawl the byte codes.
            // if (major >= JAVA.OpenJDK7.major)

            crawl |= detectLdc;

            //
            // Handle the methods
            //
            int methodCount = in.readUnsignedShort();
            for (int i = 0; i < methodCount; i++)
            {
                int access_flags = in.readUnsignedShort();
                int name_index = in.readUnsignedShort();
                int descriptor_index = in.readUnsignedShort();
                String name = pool[name_index].toString();
                String descriptor = pool[descriptor_index].toString();
                MethodDef mdef = null;
                referTo(descriptor_index, access_flags);

                if ("<init>".equals(name))
                {
                    if (Modifier.isPublic(access_flags) && "()V".equals(descriptor))
                    {
                        hasDefaultConstructor = true;
                    }
                    doAttributes(in, ElementType.CONSTRUCTOR, crawl, access_flags);
                }
                else
                {
                    doAttributes(in, ElementType.METHOD, crawl, access_flags);
                }
            }
            last = null;

            doAttributes(in, ElementType.TYPE, false, accessx);

            //
            // Parse all the classParser we found
            //
            reset();
            return imports;
        }