/*
 * Class: DataReader
 *
 * Author: Alex Usun
 *
 * Date: 1/9/2005
 */
package com.jscape.inet.ssh.util.keyreader.vandyke;

import com.jscape.util.Assert;

import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;

/**
 * VanDyke format data reader.
 *
 * @author Alex Usun
 * @version 1.0
 * @see <a href="DataReader.java.html">Source code</a>
 */
public class DataReader {

    private final DataInputStream in;

    /**
     * Creates a new reader instance.
     *
     * @param in underlayed input stream
     */
    public DataReader(InputStream in) {
        Assert.notNull(in);
        this.in = new DataInputStream(in);
    }

    /**
     * Reads integer value.
     *
     * @return readed value
     *
     * @throws IOException if an I/O error occurs
     */
    public int readInt()
            throws IOException {
        return this.in.readInt();
    }

    /**
     * Reads string value as byte array.
     *
     * @return readed value
     *
     * @throws IOException if an I/O error occurs
     */
    public byte[] readStringAsByteArray()
            throws IOException {
        try {
            int length = readInt();
            byte[] data = new byte[length];
            this.in.readFully(data);

            return data;
        } catch (NegativeArraySizeException e) {
            throw new IOException("file corrupted or bad passphrase");
        } catch (OutOfMemoryError e) {
            throw new IOException("file corrupted or bad passphrase");
        }
    }

    /**
     * Reads string value.
     *
     * @return readed value
     *
     * @throws IOException if an I/O error occurs
     */
    public String readString()
            throws IOException {
        return new String(readStringAsByteArray(), StandardCharsets.US_ASCII);
    }

    /**
     * Reads big integer value.
     *
     * @return readed value
     *
     * @throws IOException if an I/O error occurs
     */
    public BigInteger readMpint()
            throws IOException {
        byte[] data = readStringAsByteArray();
        return new BigInteger(convertToPositive(data));
    }

    /**
     * Converts incoming mpint data to positive value.
     *
     * @param data mpint data
     *
     * @return converted positive value
     */
    private byte[] convertToPositive(byte[] data) {
        if (data[0] >= 0) {
            return data;
        }

        byte[] tmp = new byte[data.length + 1];
        System.arraycopy(data, 0, tmp, 1, data.length);

        return tmp;
    }

}
