Use local copy of latest bndlib code for pre-release testing purposes
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1347815 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/bundleplugin/src/main/java/aQute/libg/classdump/ClassDumper.java b/bundleplugin/src/main/java/aQute/libg/classdump/ClassDumper.java
new file mode 100755
index 0000000..e45cd39
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/libg/classdump/ClassDumper.java
@@ -0,0 +1,698 @@
+/* Copyright 2006 aQute SARL
+ * Licensed under the Apache License, Version 2.0, see http://www.apache.org/licenses/LICENSE-2.0 */
+package aQute.libg.classdump;
+
+import java.io.*;
+import java.lang.reflect.*;
+
+public class ClassDumper {
+ /**
+ * <pre>
+ * ACC_PUBLIC 0x0001 Declared public; may be accessed from outside its
+ * package.
+ * ACC_FINAL 0x0010 Declared final; no subclasses allowed.
+ * ACC_SUPER 0x0020 Treat superclass methods specially when invoked by the
+ * invokespecial instruction.
+ * ACC_INTERFACE 0x0200 Is an interface, not a
+ * class.
+ * ACC_ABSTRACT 0x0400 Declared abstract; may not be instantiated.
+ * </pre>
+ *
+ * @param mod
+ */
+ final static int ACC_PUBLIC = 0x0001; // Declared public; may be accessed
+ // from outside its package.
+ final static int ACC_FINAL = 0x0010; // Declared final; no subclasses
+ // allowed.
+ final static int ACC_SUPER = 0x0020; // Treat superclass methods
+ // specially when invoked by the
+ // invokespecial instruction.
+ final static int ACC_INTERFACE = 0x0200; // Is an interface, not a classs
+ final static int ACC_ABSTRACT = 0x0400; // Declared abstract; may not be
+ // instantiated.
+
+ final static class Assoc {
+ Assoc(byte tag, int a, int b) {
+ this.tag = tag;
+ this.a = a;
+ this.b = b;
+ }
+
+ byte tag;
+ int a;
+ int b;
+
+ }
+
+ final String path;
+ final static String NUM_COLUMN = "%-30s %d\n";
+ final static String HEX_COLUMN = "%-30s %x\n";
+ final static String STR_COLUMN = "%-30s %s\n";
+
+ PrintStream ps = System.err;
+ Object[] pool;
+ InputStream in;
+
+ public ClassDumper(String path) throws Exception {
+ this(path, new FileInputStream(new File(path)));
+ }
+
+ public ClassDumper(String path, InputStream in) throws IOException {
+ this.path = path;
+ this.in = in;
+ }
+
+ public void dump(PrintStream ps) throws Exception {
+ if (ps != null)
+ this.ps = ps;
+ DataInputStream din = new DataInputStream(in);
+ parseClassFile(din);
+ din.close();
+ }
+
+ void parseClassFile(DataInputStream in) throws IOException {
+ int magic = in.readInt();
+ if (magic != 0xCAFEBABE)
+ throw new IOException("Not a valid class file (no CAFEBABE header)");
+
+ ps.printf(HEX_COLUMN, "magic", magic);
+ int minor = in.readUnsignedShort(); // minor version
+ int major = in.readUnsignedShort(); // major version
+ ps.printf(STR_COLUMN, "version", "" + major + "." + minor);
+ int pool_size = in.readUnsignedShort();
+ ps.printf(NUM_COLUMN, "pool size", pool_size);
+ pool = new Object[pool_size];
+
+ process: for (int poolIndex = 1; poolIndex < pool_size; poolIndex++) {
+ byte tag = in.readByte();
+
+ switch (tag) {
+ case 0:
+ ps.printf("%30d tag (0)\n", poolIndex);
+ break process;
+
+ case 1:
+ String name = in.readUTF();
+ pool[poolIndex] = name;
+ ps.printf("%30d tag(1) utf8 '%s'\n", poolIndex, name);
+ break;
+
+ case 2:
+ throw new IOException("Invalid tag " + tag);
+
+ case 3:
+ int i = in.readInt();
+ pool[poolIndex] = Integer.valueOf(i);
+ ps.printf("%30d tag(3) int %s\n", poolIndex, i);
+ break;
+
+ case 4:
+ float f = in.readFloat();
+ pool[poolIndex] = new Float(f);
+ ps.printf("%30d tag(4) float %s\n", poolIndex, f);
+ break;
+
+ // For some insane optimization reason are
+ // the long and the double two entries in the
+ // constant pool. See 4.4.5
+ case 5:
+ long l = in.readLong();
+ pool[poolIndex] = Long.valueOf(l);
+ ps.printf("%30d tag(5) long %s\n", poolIndex, l);
+ poolIndex++;
+ break;
+
+ case 6:
+ double d = in.readDouble();
+ pool[poolIndex] = new Double(d);
+ ps.printf("%30d tag(6) double %s\n", poolIndex, d);
+ poolIndex++;
+ break;
+
+ case 7:
+ int class_index = in.readUnsignedShort();
+ pool[poolIndex] = Integer.valueOf(class_index);
+ ps.printf("%30d tag(7) constant classs %d\n", poolIndex,
+ class_index);
+ break;
+
+ case 8:
+ int string_index = in.readUnsignedShort();
+ pool[poolIndex] = Integer.valueOf(string_index);
+ ps.printf("%30d tag(8) constant string %d\n", poolIndex,
+ string_index);
+ break;
+
+ case 9: // Field ref
+ class_index = in.readUnsignedShort();
+ int name_and_type_index = in.readUnsignedShort();
+ pool[poolIndex] = new Assoc((byte) 9, class_index,
+ name_and_type_index);
+ ps.printf("%30d tag(9) field ref %d/%d\n", poolIndex,
+ class_index, name_and_type_index);
+ break;
+
+ case 10: // Method ref
+ class_index = in.readUnsignedShort();
+ name_and_type_index = in.readUnsignedShort();
+ pool[poolIndex] = new Assoc((byte) 10, class_index,
+ name_and_type_index);
+ ps.printf("%30d tag(10) method ref %d/%d\n", poolIndex,
+ class_index, name_and_type_index);
+ break;
+
+ case 11: // Interface and Method ref
+ class_index = in.readUnsignedShort();
+ name_and_type_index = in.readUnsignedShort();
+ pool[poolIndex] = new Assoc((byte) 11, class_index,
+ name_and_type_index);
+ ps.printf("%30d tag(11) interface and method ref %d/%d\n",
+ poolIndex, class_index, name_and_type_index);
+ break;
+
+ // Name and Type
+ case 12:
+ int name_index = in.readUnsignedShort();
+ int descriptor_index = in.readUnsignedShort();
+ pool[poolIndex] = new Assoc(tag, name_index, descriptor_index);
+ ps.printf("%30d tag(12) name and type %d/%d\n", poolIndex,
+ name_index, descriptor_index);
+ break;
+
+ default:
+ throw new IllegalArgumentException("Unknown tag: " + tag);
+ }
+ }
+
+ int access = in.readUnsignedShort(); // access
+ printAccess(access);
+ int this_class = in.readUnsignedShort();
+ int super_class = in.readUnsignedShort();
+ ps.printf("%-30s %x %s(#%d)\n", "this_class", access, pool[this_class],
+ this_class);
+ ps.printf("%-30s %s(#%d)\n", "super_class", pool[super_class],
+ super_class);
+
+ int interfaces_count = in.readUnsignedShort();
+ ps.printf(NUM_COLUMN, "interface count", interfaces_count);
+ for (int i = 0; i < interfaces_count; i++) {
+ int interface_index = in.readUnsignedShort();
+ ps.printf("%-30s interface %s(#%d)", "interface count",
+ pool[interface_index], interfaces_count);
+ }
+
+ int field_count = in.readUnsignedShort();
+ ps.printf(NUM_COLUMN, "field count", field_count);
+ for (int i = 0; i < field_count; i++) {
+ access = in.readUnsignedShort(); // access
+ printAccess(access);
+ int name_index = in.readUnsignedShort();
+ int descriptor_index = in.readUnsignedShort();
+ ps.printf("%-30s %x %s(#%d) %s(#%d)\n", "field def", access,
+ pool[name_index], name_index, pool[descriptor_index],
+ descriptor_index);
+ doAttributes(in, " ");
+ }
+
+ int method_count = in.readUnsignedShort();
+ ps.printf(NUM_COLUMN, "method count", method_count);
+ for (int i = 0; i < method_count; i++) {
+ int access_flags = in.readUnsignedShort();
+ printAccess(access_flags);
+ int name_index = in.readUnsignedShort();
+ int descriptor_index = in.readUnsignedShort();
+ ps.printf("%-30s %x %s(#%d) %s(#%d)\n", "method def", access_flags,
+ pool[name_index], name_index, pool[descriptor_index],
+ descriptor_index);
+ doAttributes(in, " ");
+ }
+
+ doAttributes(in, "");
+ if (in.read() >= 0)
+ ps.printf("Extra bytes follow ...");
+ }
+
+ /**
+ * Called for each attribute in the class, field, or method.
+ *
+ * @param in
+ * The stream
+ * @throws IOException
+ */
+ private void doAttributes(DataInputStream in, String indent)
+ throws IOException {
+ int attribute_count = in.readUnsignedShort();
+ ps.printf(NUM_COLUMN, indent + "attribute count", attribute_count);
+ for (int j = 0; j < attribute_count; j++) {
+ doAttribute(in, indent + j + ": ");
+ }
+ }
+
+ /**
+ * Process a single attribute, if not recognized, skip it.
+ *
+ * @param in
+ * the data stream
+ * @throws IOException
+ */
+ private void doAttribute(DataInputStream in, String indent)
+ throws IOException {
+ int attribute_name_index = in.readUnsignedShort();
+ long attribute_length = in.readInt();
+ attribute_length &= 0xFFFF;
+ String attributeName = (String) pool[attribute_name_index];
+ ps.printf("%-30s %s(#%d)\n", indent + "attribute", attributeName,
+ attribute_name_index);
+ if ("RuntimeVisibleAnnotations".equals(attributeName))
+ doAnnotations(in, indent);
+ else if ("SourceFile".equals(attributeName))
+ doSourceFile(in, indent);
+ else if ("Code".equals(attributeName))
+ doCode(in, indent);
+ else if ("LineNumberTable".equals(attributeName))
+ doLineNumberTable(in, indent);
+ else if ("LocalVariableTable".equals(attributeName))
+ doLocalVariableTable(in, indent);
+ else if ("InnerClasses".equals(attributeName))
+ doInnerClasses(in, indent);
+ else if ("Exceptions".equals(attributeName))
+ doExceptions(in, indent);
+ else if ("EnclosingMethod".equals(attributeName))
+ doEnclosingMethod(in, indent);
+ else if ("Signature".equals(attributeName))
+ doSignature(in, indent);
+ else if ("Synthetic".equals(attributeName))
+ ; // Is empty!
+ else if ("Deprecated".equals(attributeName))
+ ; // Is Empty
+ else {
+ ps.printf("%-30s %d\n", indent + "Unknown attribute, skipping",
+ attribute_length);
+ if (attribute_length > 0x7FFFFFFF) {
+ throw new IllegalArgumentException("Attribute > 2Gb");
+ }
+ byte buffer[] = new byte[(int) attribute_length];
+ in.readFully(buffer);
+ printHex(buffer);
+ }
+ }
+
+ /**
+ * <pre>
+ * Signature_attribute {
+ * u2 attribute_name_index;
+ * u4 attribute_length;
+ * u2 signature_index;
+ * }
+ * </pre>
+ *
+ * @param in
+ * @param indent
+ */
+ void doSignature(DataInputStream in, String indent) throws IOException {
+ int signature_index = in.readUnsignedShort();
+ ps.printf("%-30s %s(#%d)\n", indent + "signature",
+ pool[signature_index], signature_index);
+ }
+
+ /**
+ * <pre>
+ * EnclosingMethod_attribute {
+ * u2 attribute_name_index;
+ * u4 attribute_length;
+ * u2 class_index
+ * u2 method_index;
+ * }
+ *
+ * </pre>
+ */
+ void doEnclosingMethod(DataInputStream in, String indent)
+ throws IOException {
+ int class_index = in.readUnsignedShort();
+ int method_index = in.readUnsignedShort();
+ ps.printf("%-30s %s(#%d/c) %s\n", //
+ indent + "enclosing method", //
+ pool[((Integer) pool[class_index]).intValue()], //
+ class_index, //
+ (method_index == 0 ? "<>" : pool[method_index]));
+ }
+
+ /**
+ * <pre>
+ * Exceptions_attribute {
+ * u2 attribute_name_index;
+ * u4 attribute_length;
+ * u2 number_of_exceptions;
+ * u2 exception_index_table[number_of_exceptions];
+ * }
+ * </pre>
+ *
+ * @param in
+ * @param indent
+ */
+ private void doExceptions(DataInputStream in, String indent)
+ throws IOException {
+ int number_of_exceptions = in.readUnsignedShort();
+ ps.printf(NUM_COLUMN, indent + "number of exceptions",
+ number_of_exceptions);
+ StringBuilder sb = new StringBuilder();
+ String del = "";
+ for (int i = 0; i < number_of_exceptions; i++) {
+ int exception_index_table = in.readUnsignedShort();
+ sb.append(del);
+ sb.append(pool[((Integer) pool[exception_index_table])]);
+ sb.append("(#");
+ sb.append(exception_index_table);
+ sb.append("/c)");
+ del = ", ";
+ }
+ ps.printf("%-30s %d: %s\n", indent + "exceptions",
+ number_of_exceptions, sb);
+ }
+
+ /**
+ * <pre>
+ * Code_attribute {
+ * u2 attribute_name_index;
+ * u4 attribute_length;
+ * u2 max_stack;
+ * u2 max_locals;
+ * u4 code_length;
+ * u1 code[code_length];
+ * u2 exception_table_length;
+ * { u2 start_pc;
+ * u2 end_pc;
+ * u2 handler_pc;
+ * u2 catch_type;
+ * } exception_table[exception_table_length];
+ * u2 attributes_count;
+ * attribute_info attributes[attributes_count];
+ * }
+ * </pre>
+ *
+ * @param in
+ * @param pool
+ * @throws IOException
+ */
+ private void doCode(DataInputStream in, String indent) throws IOException {
+ int max_stack = in.readUnsignedShort();
+ int max_locals = in.readUnsignedShort();
+ int code_length = in.readInt();
+ ps.printf(NUM_COLUMN, indent + "max_stack", max_stack);
+ ps.printf(NUM_COLUMN, indent + "max_locals", max_locals);
+ ps.printf(NUM_COLUMN, indent + "code_length", code_length);
+ byte code[] = new byte[code_length];
+ in.readFully(code);
+ printHex(code);
+ int exception_table_length = in.readUnsignedShort();
+ ps.printf(NUM_COLUMN, indent + "exception_table_length",
+ exception_table_length);
+
+ for (int i = 0; i < exception_table_length; i++) {
+ int start_pc = in.readUnsignedShort();
+ int end_pc = in.readUnsignedShort();
+ int handler_pc = in.readUnsignedShort();
+ int catch_type = in.readUnsignedShort();
+ ps.printf("%-30s %d/%d/%d/%d\n", indent + "exception_table",
+ start_pc, end_pc, handler_pc, catch_type);
+ }
+ doAttributes(in, indent + " ");
+ }
+
+ /**
+ * We must find Class.forName references ...
+ *
+ * @param code
+ */
+ protected void printHex(byte[] code) {
+ int index = 0;
+ while (index < code.length) {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < 16 && index < code.length; i++) {
+ String s = Integer.toHexString((0xFF & code[index++]))
+ .toUpperCase();
+ if (s.length() == 1)
+ sb.append("0");
+ sb.append(s);
+ sb.append(" ");
+ }
+ ps.printf(STR_COLUMN, "", sb.toString());
+ }
+ }
+
+ private void doSourceFile(DataInputStream in, String indent)
+ throws IOException {
+ int sourcefile_index = in.readUnsignedShort();
+ ps.printf("%-30s %s(#%d)\n", indent + "Source file",
+ pool[sourcefile_index], sourcefile_index);
+ }
+
+ private void doAnnotations(DataInputStream in, String indent)
+ throws IOException {
+ int num_annotations = in.readUnsignedShort(); // # of annotations
+ ps
+ .printf(NUM_COLUMN, indent + "Number of annotations",
+ num_annotations);
+ for (int a = 0; a < num_annotations; a++) {
+ doAnnotation(in, indent);
+ }
+ }
+
+ private void doAnnotation(DataInputStream in, String indent)
+ throws IOException {
+ int type_index = in.readUnsignedShort();
+ ps.printf("%-30s %s(#%d)", indent + "type", pool[type_index],
+ type_index);
+ int num_element_value_pairs = in.readUnsignedShort();
+ ps.printf(NUM_COLUMN, indent + "num_element_value_pairs",
+ num_element_value_pairs);
+ for (int v = 0; v < num_element_value_pairs; v++) {
+ int element_name_index = in.readUnsignedShort();
+ ps.printf(NUM_COLUMN, indent + "element_name_index",
+ element_name_index);
+ doElementValue(in, indent);
+ }
+ }
+
+ private void doElementValue(DataInputStream in, String indent)
+ throws IOException {
+ int tag = in.readUnsignedByte();
+ switch (tag) {
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'F':
+ case 'I':
+ case 'J':
+ case 'S':
+ case 'Z':
+ case 's':
+ int const_value_index = in.readUnsignedShort();
+ ps.printf("%-30s %c %s(#%d)\n", indent + "element value", tag,
+ pool[const_value_index], const_value_index);
+ break;
+
+ case 'e':
+ int type_name_index = in.readUnsignedShort();
+ int const_name_index = in.readUnsignedShort();
+ ps.printf("%-30s %c %s(#%d) %s(#%d)\n", indent + "type+const", tag,
+ pool[type_name_index], type_name_index,
+ pool[const_name_index], const_name_index);
+ break;
+
+ case 'c':
+ int class_info_index = in.readUnsignedShort();
+ ps.printf("%-30s %c %s(#%d)\n", indent + "element value", tag,
+ pool[class_info_index], class_info_index);
+ break;
+
+ case '@':
+ ps.printf("%-30s %c\n", indent + "sub annotation", tag);
+ doAnnotation(in, indent);
+ break;
+
+ case '[':
+ int num_values = in.readUnsignedShort();
+ ps.printf("%-30s %c num_values=%d\n", indent + "sub element value",
+ tag, num_values);
+ for (int i = 0; i < num_values; i++) {
+ doElementValue(in, indent);
+ }
+ break;
+
+ default:
+ throw new IllegalArgumentException(
+ "Invalid value for Annotation ElementValue tag " + tag);
+ }
+ }
+
+ /**
+ * <pre>
+ * LineNumberTable_attribute {
+ * u2 attribute_name_index;
+ * u4 attribute_length;
+ * u2 line_number_table_length;
+ * { u2 start_pc;
+ * u2 line_number;
+ * } line_number_table[line_number_table_length];
+ * }
+ *
+ * </pre>
+ */
+ void doLineNumberTable(DataInputStream in, String indent)
+ throws IOException {
+ int line_number_table_length = in.readUnsignedShort();
+ ps.printf(NUM_COLUMN, indent + "line number table length",
+ line_number_table_length);
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < line_number_table_length; i++) {
+ int start_pc = in.readUnsignedShort();
+ int line_number = in.readUnsignedShort();
+ sb.append(start_pc);
+ sb.append("/");
+ sb.append(line_number);
+ sb.append(" ");
+ }
+ ps.printf("%-30s %d: %s\n", indent + "line number table",
+ line_number_table_length, sb);
+ }
+
+ /**
+ *
+ * <pre>
+ * LocalVariableTable_attribute {
+ * u2 attribute_name_index;
+ * u4 attribute_length;
+ * u2 local_variable_table_length;
+ * { u2 start_pc;
+ * u2 length;
+ * u2 name_index;
+ * u2 descriptor_index;
+ * u2 index;
+ * } local_variable_table[local_variable_table_length];
+ * }
+ * </pre>
+ */
+
+ void doLocalVariableTable(DataInputStream in, String indent)
+ throws IOException {
+ int local_variable_table_length = in.readUnsignedShort();
+ ps.printf(NUM_COLUMN, indent + "local variable table length",
+ local_variable_table_length);
+ for (int i = 0; i < local_variable_table_length; i++) {
+ int start_pc = in.readUnsignedShort();
+ int length = in.readUnsignedShort();
+ int name_index = in.readUnsignedShort();
+ int descriptor_index = in.readUnsignedShort();
+ int index = in.readUnsignedShort();
+ ps.printf("%-30s %d: %d/%d %s(#%d) %s(#%d)\n", indent, index,
+ start_pc, length, pool[name_index], name_index,
+ pool[descriptor_index], descriptor_index);
+ }
+ }
+
+ /**
+ * <pre>
+ * InnerClasses_attribute {
+ * u2 attribute_name_index;
+ * u4 attribute_length;
+ * u2 number_of_classes;
+ * { u2 inner_class_info_index;
+ * u2 outer_class_info_index;
+ * u2 inner_name_index;
+ * u2 inner_class_access_flags;
+ * } classes[number_of_classes];
+ * }
+ * </pre>
+ *
+ */
+ void doInnerClasses(DataInputStream in, String indent) throws IOException {
+ int number_of_classes = in.readUnsignedShort();
+ ps.printf(NUM_COLUMN, indent + "number of classes", number_of_classes);
+ for (int i = 0; i < number_of_classes; i++) {
+ int inner_class_info_index = in.readUnsignedShort();
+ int outer_class_info_index = in.readUnsignedShort();
+ int inner_name_index = in.readUnsignedShort();
+ int inner_class_access_flags = in.readUnsignedShort();
+ printAccess(inner_class_access_flags);
+
+ String iname = "<>";
+ String oname = iname;
+
+ if (inner_class_info_index != 0)
+ iname = (String) pool[((Integer) pool[inner_class_info_index])
+ .intValue()];
+ if (outer_class_info_index != 0)
+ oname = (String) pool[((Integer) pool[outer_class_info_index])
+ .intValue()];
+
+ ps.printf("%-30s %d: %x %s(#%d/c) %s(#%d/c) %s(#%d) \n", indent, i,
+ inner_class_access_flags, iname, inner_class_info_index,
+ oname, outer_class_info_index, pool[inner_name_index],
+ inner_name_index);
+ }
+ }
+
+
+ void printClassAccess(int mod) {
+ ps.printf("%-30s", "Class Access");
+ if ((ACC_PUBLIC&mod)!= 0)
+ ps.print(" public");
+ if ((ACC_FINAL&mod)!= 0)
+ ps.print(" final");
+ if ((ACC_SUPER&mod)!= 0)
+ ps.print(" super");
+ if ((ACC_INTERFACE&mod)!= 0)
+ ps.print(" interface");
+ if ((ACC_ABSTRACT&mod)!= 0)
+ ps.print(" abstract");
+
+ ps.println();
+ }
+
+ void printAccess(int mod) {
+ ps.printf("%-30s", "Access");
+ if (Modifier.isStatic(mod))
+ ps.print(" static");
+ if (Modifier.isAbstract(mod))
+ ps.print(" abstract");
+ if (Modifier.isPublic(mod))
+ ps.print(" public");
+ if (Modifier.isFinal(mod))
+ ps.print(" final");
+ if (Modifier.isInterface(mod))
+ ps.print(" interface");
+ if (Modifier.isNative(mod))
+ ps.print(" native");
+ if (Modifier.isPrivate(mod))
+ ps.print(" private");
+ if (Modifier.isProtected(mod))
+ ps.print(" protected");
+ if (Modifier.isStrict(mod))
+ ps.print(" strict");
+ if (Modifier.isSynchronized(mod))
+ ps.print(" synchronized");
+ if (Modifier.isTransient(mod))
+ ps.print(" transient");
+ if (Modifier.isVolatile(mod))
+ ps.print(" volatile");
+
+ ps.println();
+ }
+
+ public static void main(String args[]) throws Exception {
+ if (args.length == 0) {
+ System.err.println("clsd <class file>+");
+ }
+ for (int i = 0; i < args.length; i++) {
+ File f = new File(args[i]);
+ if (!f.isFile())
+ System.err.println("File does not exist or is directory " + f);
+ else {
+ ClassDumper cd = new ClassDumper(args[i]);
+ cd.dump(null);
+ }
+ }
+ }
+
+}
diff --git a/bundleplugin/src/main/java/aQute/libg/classdump/packageinfo b/bundleplugin/src/main/java/aQute/libg/classdump/packageinfo
new file mode 100644
index 0000000..7c8de03
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/libg/classdump/packageinfo
@@ -0,0 +1 @@
+version 1.0