All Downloads are FREE. Search and download functionalities are using the official Maven repository.

aQute.lib.putjar.DirectoryInputStream Maven / Gradle / Ivy

There is a newer version: 7.0.0
Show newest version
package aQute.lib.putjar;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.zip.CRC32;

import aQute.lib.io.IOConstants;
import aQute.libg.fileiterator.FileIterator;

public class DirectoryInputStream extends InputStream {
	static final int			BUFFER_SIZE	= IOConstants.PAGE_SIZE * 16;

	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;
		}
	}

	/**
	 * 
	 *  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)
	 * 
*/ 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: * *
	 *  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)
	 * 
*
*/ 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[BUFFER_SIZE]; int size = in.read(data); while (size > 0) { crc.update(data, 0, size); size = in.read(data); } } finally { in.close(); } return crc; } }



© 2015 - 2024 Weber Informatics LLC | Privacy Policy