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

net.dongliu.apk.parser.io.TellableInputStream Maven / Gradle / Ivy

The newest version!
package net.dongliu.apk.parser.io;

import net.dongliu.apk.parser.struct.ByteOrder;

import java.io.BufferedInputStream;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;

/**
 * Input stream which can tell it's current pos.
 *
 * @author dongliu
 */
public class TellableInputStream {
    private InputStream in;
    private ByteOrder byteOrder;
    private long pos;

    public TellableInputStream(InputStream in, ByteOrder byteOrder) {
        if (in instanceof BufferedInputStream) {
            this.in = in;
        } else {
            this.in = new BufferedInputStream(in);
        }
        this.byteOrder = byteOrder;
    }

    public int read() throws IOException {
        int ret = in.read();
        if (ret != -1) {
            pos++;
        }
        return ret;
    }

    private int read(byte b[]) throws IOException {
        int ret = in.read(b);
        if (ret != -1) {
            pos += ret;
        }
        return ret;
    }

    private int read(byte b[], int off, int len) throws IOException {
        int ret = in.read(b, off, len);
        if (ret != -1) {
            pos += ret;
        }
        return ret;
    }

    private long _skip(long n) throws IOException {
        long ret = this.in.skip(n);
        if (ret != -1) {
            pos += ret;
        }
        return ret;
    }

    public void close() throws IOException {
        in.close();
    }

    /**
     * the bytes have been readed
     *
     * @return
     */
    public long tell() {
        return this.pos;
    }

    /**
     * seek to pos.
     *
     * @param pos
     */
    public void advanceIfNotRearch(long pos) throws IOException {
        if (this.pos < pos) {
            skip((int) (pos - this.pos));
        } else if (this.pos > pos) {
            throw new IOException("target pos less the current");
        }
    }

    /**
     * read bytes from input stream, the bytes size equals with len param. if get EOF before
     * read enough data, throw IOException.
     */
    public byte[] readBytes(int len) throws IOException {
        byte[] bytes = new byte[len];
        int readed = 0;
        while (readed < len) {
            int read = read(bytes, readed, len - readed);
            if (read == -1) {
                throw new EOFException("UnExpected EOF");
            }
            readed += read;
        }
        return bytes;
    }

    /**
     * read one unsigned byte.
     *
     * @return
     * @throws IOException
     */
    public short readUByte() throws IOException {
        int ret = read();
        if (ret == -1) {
            throw new EOFException("UnExpected EOF");
        }
        return (short) ret;
    }

    /**
     * skip n bytes.
     *
     * @param len
     * @throws IOException
     */
    public void skip(int len) throws IOException {
        readBytes(len);
    }

    /**
     * read int from input stream. if get EOF before read enough data, throw IOException.
     */
    public int readInt() throws IOException {
        byte[] bytes = readBytes(4);
        if (byteOrder == ByteOrder.BIG) {
            return makeInt(bytes[0], bytes[1], bytes[2], bytes[3]);
        } else {
            return makeInt(bytes[3], bytes[2], bytes[1], bytes[0]);
        }
    }

    /**
     * read unsigned int from input stream. if get EOF before read enough data, throw IOException.
     */
    public long readUInt() throws IOException {
        byte[] bytes = readBytes(4);
        if (byteOrder == ByteOrder.BIG) {
            return makeUInt(bytes[0], bytes[1], bytes[2], bytes[3]);
        } else {
            return makeUInt(bytes[3], bytes[2], bytes[1], bytes[0]);
        }
    }

    /**
     * read unsigned short from input stream. if get EOF before read enough data, throw IOException.
     */
    public int readUShort() throws IOException {
        byte[] bytes = readBytes(2);
        if (byteOrder == ByteOrder.BIG) {
            return makeUShort(bytes[0], bytes[1]);
        } else {
            return makeUShort(bytes[1], bytes[0]);
        }
    }

    /**
     * read utf16 strings, use strLen, not ending 0 char.
     *
     * @param strLen
     * @return
     * @throws IOException
     */
    public String readStringUTF16(int strLen) throws IOException {
        byte[] bytes = readBytes(strLen * 2);
        if (byteOrder == ByteOrder.LITTLE) {
            for (int i = 0; i < strLen; i++) {
                swap(bytes, 2 * i, 2 * i + 1);
            }
        }
        return new String(bytes, "UTF-16");
    }

    private void swap(byte[] bytes, int i, int j) {
        byte temp = bytes[i];
        bytes[i] = bytes[j];
        bytes[j] = temp;
    }

    /**
     * read bytes as ascii chars.
     *
     * @param len
     * @return
     */
    public String readChars(int len) throws IOException {
        char[] chars = new char[len];
        for (int i = 0; i < len; i++) {
            chars[i] = (char) readUByte();
        }
        return new String(chars);
    }

    /**
     * bytes to unsigned int.
     */
    private long makeUInt(byte b3, byte b2, byte b1, byte b0) {
        long l = 0;
        l |= (long) (b3 & 0xff) << 24;
        l |= (b2 & 0xff) << 16;
        l |= (b1 & 0xff) << 8;
        l |= (b0 & 0xff);
        return l;
    }

    /**
     * bytes to unsigned int.
     */
    private int makeInt(byte b3, byte b2, byte b1, byte b0) {
        int i = 0;
        i |= (b3 & 0xff) << 24;
        i |= (b2 & 0xff) << 16;
        i |= (b1 & 0xff) << 8;
        i |= (b0 & 0xff);
        return i;
    }

    /**
     * bytes to unsigned short.
     */
    private int makeUShort(byte b1, byte b0) {
        int i = 0;
        i |= (b1 & 0xff) << 8;
        i |= (b0 & 0xff);
        return i;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy