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/lib/putjar/DirectoryInputStream.java b/bundleplugin/src/main/java/aQute/lib/putjar/DirectoryInputStream.java
new file mode 100644
index 0000000..5bd8178
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/lib/putjar/DirectoryInputStream.java
@@ -0,0 +1,281 @@
+package aQute.lib.putjar;
+
+import java.io.*;
+import java.util.zip.*;
+
+import aQute.libg.fileiterator.*;
+
+public class DirectoryInputStream extends InputStream {
+ final File root;
+ final FileIterator fi;
+ File element;
+ int entries = 0;
+ int state = START;
+ long where = 0;
+
+ final static int START = 0;
+ final static int HEADER = 1;
+ final static int DATA = 2;
+ final static int DIRECTORY = 4;
+ final static int EOF = 5;
+
+ final static InputStream eof = new ByteArrayInputStream(new byte[0]);
+ ByteArrayOutputStream directory = new ByteArrayOutputStream();
+ InputStream current = eof;
+
+ public DirectoryInputStream(File dir) {
+ root = dir;
+ fi = new FileIterator(dir);
+ }
+
+ @Override
+ public int read() throws IOException {
+ if (fi == null)
+ return -1;
+
+ int c = current.read();
+ if (c < 0) {
+ next();
+ c = current.read();
+ }
+ if (c >= 0)
+ where++;
+
+ return c;
+ }
+
+ void next() throws IOException {
+ switch (state) {
+ case START:
+ case DATA:
+ nextHeader();
+ break;
+
+ case HEADER:
+ if (element.isFile() && element.length() > 0) {
+ current = new FileInputStream(element);
+ state = DATA;
+ } else
+ nextHeader();
+ break;
+
+ case DIRECTORY:
+ state = EOF;
+ current = eof;
+ break;
+
+ case EOF:
+ break;
+ }
+ }
+
+ private void nextHeader() throws IOException {
+ if (fi.hasNext()) {
+ element = fi.next();
+ state = HEADER;
+ current = getHeader(root, element);
+ entries++;
+ } else {
+ current = getDirectory();
+ state = DIRECTORY;
+ }
+ }
+
+ /**
+ * <pre>
+ * end of central dir signature 4 bytes (0x06054b50)
+ * number of this disk 2 bytes
+ * number of the disk with the
+ * start of the central directory 2 bytes
+ * total number of entries in the
+ * central directory on this disk 2 bytes
+ * total number of entries in
+ * the central directory 2 bytes
+ * size of the central directory 4 bytes
+ * offset of start of central
+ * directory with respect to
+ * the starting disk number 4 bytes
+ * .ZIP file comment length 2 bytes
+ * .ZIP file comment (variable size)
+ * </pre>
+ *
+ * @return
+ */
+ InputStream getDirectory() throws IOException {
+ long where = this.where;
+ int sizeDirectory = directory.size();
+
+ writeInt(directory, 0x504b0506); // Signature
+ writeShort(directory, 0); // # of disk
+ writeShort(directory, 0); // # of the disk with start of the central
+ // dir
+ writeShort(directory, entries); // # of entries
+ writeInt(directory, sizeDirectory); // Size of central dir
+ writeInt(directory, (int) where);
+ writeShort(directory, 0);
+
+ directory.close();
+
+ byte[] data = directory.toByteArray();
+ return new ByteArrayInputStream(data);
+ }
+
+ private void writeShort(OutputStream out, int v) throws IOException {
+ for (int i = 0; i < 2; i++) {
+ out.write((byte) (v & 0xFF));
+ v = v >> 8;
+ }
+ }
+
+ private void writeInt(OutputStream out, int v) throws IOException {
+ for (int i = 0; i < 4; i++) {
+ out.write((byte) (v & 0xFF));
+ v = v >> 8;
+ }
+ }
+
+ /**
+ * Local file header:
+ *
+ * <pre>
+ *
+ * local file header signature 4 bytes (0x04034b50)
+ * version needed to extract 2 bytes
+ * general purpose bit flag 2 bytes
+ * compression method 2 bytes
+ * last mod file time 2 bytes
+ * last mod file date 2 bytes
+ * crc-32 4 bytes
+ * compressed size 4 bytes
+ * uncompressed size 4 bytes
+ * file name length 2 bytes
+ * extra field length 2 bytes
+ *
+ * file name (variable size)
+ * extra field (variable size)
+ *
+ * central file header signature 4 bytes (0x02014b50)
+ * version made by 2 bytes
+ * version needed to extract 2 bytes
+ * general purpose bit flag 2 bytes
+ * compression method 2 bytes
+ * last mod file time 2 bytes
+ * last mod file date 2 bytes
+ * crc-32 4 bytes
+ * compressed size 4 bytes
+ * uncompressed size 4 bytes
+ * file name length 2 bytes
+ * extra field length 2 bytes
+ * file comment length 2 bytes
+ * disk number start 2 bytes
+ * internal file attributes 2 bytes
+ * external file attributes 4 bytes
+ * relative offset of local header 4 bytes
+ *
+ * file name (variable size)
+ * extra field (variable size)
+ * file comment (variable size)
+ * </pre>
+ * </pre>
+ *
+ * @param file
+ * @return
+ */
+ private InputStream getHeader(File root, File file) throws IOException {
+ long where = this.where;
+ ByteArrayOutputStream bout = new ByteArrayOutputStream();
+ // Signature
+ writeInt(bout, 0x04034b50);
+ writeInt(directory, 0x504b0102);
+
+ // Version needed to extract
+ writeShort(directory, 0);
+
+ // Version needed to extract
+ writeShort(bout, 10);
+ writeShort(directory, 10);
+
+ // General purpose bit flag (use descriptor)
+ writeShort(bout, 0); // descriptor follows data
+ writeShort(directory, 0); // descriptor follows data
+
+ // Compresson method (stored)
+ writeShort(bout, 0);
+ writeShort(directory, 0);
+
+ // Mod time
+ writeInt(bout, 0);
+ writeInt(directory, 0);
+
+ if (file.isDirectory()) {
+ writeInt(bout, 0); // CRC
+ writeInt(bout, 0); // Compressed size
+ writeInt(bout, 0); // Uncompressed Size
+ writeInt(directory, 0);
+ writeInt(directory, 0);
+ writeInt(directory, 0);
+ } else {
+ CRC32 crc = getCRC(file);
+ writeInt(bout, (int) crc.getValue());
+ writeInt(bout, (int) file.length());
+ writeInt(bout, (int) file.length());
+ writeInt(directory, (int) crc.getValue());
+ writeInt(directory, (int) file.length());
+ writeInt(directory, (int) file.length());
+ }
+
+ String p = getPath(root, file);
+ if (file.isDirectory())
+ p = p + "/";
+ byte[] path = p.getBytes("UTF-8");
+ writeShort(bout, path.length);
+ writeShort(directory, path.length);
+
+ writeShort(bout, 0); // extra length
+ writeShort(directory, 0);
+
+ bout.write(path);
+
+ writeShort(directory, 0); // File comment length
+ writeShort(directory, 0); // disk number start 2 bytes
+ writeShort(directory, 0); // internal file attributes 2 bytes
+ writeInt(directory, 0); // external file attributes 4 bytes
+ writeInt(directory, (int) where); // relative offset of local header 4
+ // bytes
+
+ directory.write(path);
+
+ byte[] bytes = bout.toByteArray();
+ return new ByteArrayInputStream(bytes);
+ }
+
+ private String getPath(File root, File file) {
+ if (file.equals(root))
+ return "";
+
+ String p = getPath(root, file.getParentFile());
+ if (p.length() == 0)
+ p = file.getName();
+ else {
+ p = p + "/" + file.getName();
+ }
+ return p;
+ }
+
+ private CRC32 getCRC(File file) throws IOException {
+ CRC32 crc = new CRC32();
+ FileInputStream in = new FileInputStream(file);
+ try {
+ byte data[] = new byte[10000];
+ int size = in.read(data);
+ while (size > 0) {
+ crc.update(data, 0, size);
+ size = in.read(data);
+ }
+ } finally {
+ in.close();
+ }
+ return crc;
+ }
+
+}
diff --git a/bundleplugin/src/main/java/aQute/lib/putjar/packageinfo b/bundleplugin/src/main/java/aQute/lib/putjar/packageinfo
new file mode 100644
index 0000000..7c8de03
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/lib/putjar/packageinfo
@@ -0,0 +1 @@
+version 1.0