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

net.razorvine.pickle.PickleUtils Maven / Gradle / Ivy

package net.razorvine.pickle;

import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;

/**
 * Utility stuff for dealing with pickle data streams.
 * 
 * @author Irmen de Jong ([email protected])
 */
public abstract class PickleUtils {

	/**
	 * read a line of text, excluding the terminating LF char
	 */
	public static String readline(InputStream input) throws IOException {
		return readline(input, false);
	}

	/**
	 * read a line of text, possibly including the terminating LF char
	 */
	public static String readline(InputStream input, boolean includeLF) throws IOException {
		StringBuilder sb = new StringBuilder();
		while (true) {
			int c = input.read();
			if (c == -1) {
				if (sb.length() == 0)
					throw new IOException("premature end of file");
				break;
			}
			if (c != '\n' || includeLF)
				sb.append((char) c);
			if (c == '\n')
				break;
		}
		return sb.toString();
	}

	/**
	 * read a single unsigned byte
	 */
	public static short readbyte(InputStream input) throws IOException {
		int b = input.read();
		return (short) b;
	}

	/**
	 * read a number of signed bytes
	 */
	public static byte[] readbytes(InputStream input, int n) throws IOException {
		byte[] buffer = new byte[n];
		readbytes_into(input, buffer, 0, n);
		return buffer;
	}

	/**
	 * read a number of signed bytes into the specified location in an existing byte array
	 */
	public static void readbytes_into(InputStream input, byte[] buffer, int offset, int length) throws IOException {
		while (length > 0) {
			int read = input.read(buffer, offset, length);
			if (read == -1)
				throw new IOException("expected more bytes in input stream");
			offset += read;
			length -= read;
		}
	}

	/**
	 * Convert a couple of bytes into the corresponding integer number.
	 * Can deal with 2-bytes unsigned int and 4-bytes signed int.
	 */
	public static int bytes_to_integer(byte[] bytes) {
		return bytes_to_integer(bytes, 0, bytes.length);
	}
	public static int bytes_to_integer(byte[] bytes, int offset, int size) {
		// this operates on little-endian bytes
		if (size==2) {
			// 2-bytes unsigned int
			int i = bytes[1+offset] & 0xff;
			i <<= 8;
			i |= bytes[0+offset] & 0xff;
			return i;
		} else if (size==4) {
			// 4-bytes signed int
			int i = bytes[3+offset];
			i <<= 8;
			i |= bytes[2+offset] & 0xff;
			i <<= 8;
			i |= bytes[1+offset] & 0xff;
			i <<= 8;
			i |= bytes[0+offset] & 0xff;
			return i;
		} else
			throw new PickleException("invalid amount of bytes to convert to int: " + size);
	}

	/**
	 * Convert 8 little endian bytes into a long
	 */
	public static long bytes_to_long(byte[] bytes, int offset) {
		if(bytes.length-offset<8)
			throw new PickleException("too few bytes to convert to long");
		long i = bytes[7+offset] & 0xff;
		i <<= 8;
		i |= bytes[6+offset] & 0xff;
		i <<= 8;
		i |= bytes[5+offset] & 0xff;
		i <<= 8;
		i |= bytes[4+offset] & 0xff;
		i <<= 8;
		i |= bytes[3+offset] & 0xff;
		i <<= 8;
		i |= bytes[2+offset] & 0xff;
		i <<= 8;
		i |= bytes[1+offset] & 0xff;
		i <<= 8;
		i |= bytes[offset] & 0xff;
		return i;
	}	

	/**
	 * Convert 4 little endian bytes into an unsigned int (as a long)
	 */
	public static long bytes_to_uint(byte[] bytes, int offset) {
		if(bytes.length-offset<4)
			throw new PickleException("too few bytes to convert to long");
		long i = bytes[3+offset] & 0xff;
		i <<= 8;
		i |= bytes[2+offset] & 0xff;
		i <<= 8;
		i |= bytes[1+offset] & 0xff;
		i <<= 8;
		i |= bytes[0+offset] & 0xff;
		return i;
	}	
	
	/**
	 * Convert a signed integer to its 4-byte representation. (little endian)
	 */
	public static byte[] integer_to_bytes(int i) {
		final byte[] b = new byte[4];
		b[0] = (byte) (i & 0xff);
		i >>= 8;
		b[1] = (byte) (i & 0xff);
		i >>= 8;
		b[2] = (byte) (i & 0xff);
		i >>= 8;
		b[3] = (byte) (i & 0xff);
		return b;
	}

	/**
	 * Convert a double to its 8-byte representation (big endian).
	 */
	public static byte[] double_to_bytes(double d) {
		long bits = Double.doubleToRawLongBits(d);
		final byte[] b = new byte[8];
		b[7] = (byte) (bits & 0xff);
		bits >>= 8;
		b[6] = (byte) (bits & 0xff);
		bits >>= 8;
		b[5] = (byte) (bits & 0xff);
		bits >>= 8;
		b[4] = (byte) (bits & 0xff);
		bits >>= 8;
		b[3] = (byte) (bits & 0xff);
		bits >>= 8;
		b[2] = (byte) (bits & 0xff);
		bits >>= 8;
		b[1] = (byte) (bits & 0xff);
		bits >>= 8;
		b[0] = (byte) (bits & 0xff);
		return b;
	}

	/**
	 * Convert a big endian 8-byte to a double. 
	 */
	public static double bytes_to_double(byte[] bytes, int offset) {
		try {
			long result = bytes[0+offset] & 0xff;
			result <<= 8;
			result |= bytes[1+offset] & 0xff;
			result <<= 8;
			result |= bytes[2+offset] & 0xff;
			result <<= 8;
			result |= bytes[3+offset] & 0xff;
			result <<= 8;
			result |= bytes[4+offset] & 0xff;
			result <<= 8;
			result |= bytes[5+offset] & 0xff;
			result <<= 8;
			result |= bytes[6+offset] & 0xff;
			result <<= 8;
			result |= bytes[7+offset] & 0xff;
			return Double.longBitsToDouble(result);
		} catch (ArrayIndexOutOfBoundsException x) {
			throw new PickleException("decoding double: too few bytes");
		}
	}

	/**
	 * Convert a big endian 4-byte to a float. 
	 */
	public static float bytes_to_float(byte[] bytes, int offset) {
		try {
			int result = bytes[0+offset] & 0xff;
			result <<= 8;
			result |= bytes[1+offset] & 0xff;
			result <<= 8;
			result |= bytes[2+offset] & 0xff;
			result <<= 8;
			result |= bytes[3+offset] & 0xff;
			return Float.intBitsToFloat(result);
		} catch (ArrayIndexOutOfBoundsException x) {
			throw new PickleException("decoding float: too few bytes");
		}
	}	
	/**
	 * read an arbitrary 'long' number. Returns an int/long/BigInteger as appropriate to hold the number.
	 */
	public static Number decode_long(byte[] data) {
		if (data.length == 0)
			return 0L;
		// first reverse the byte array because pickle stores it little-endian
		byte[] data2 = new byte[data.length];
		for (int i = 0; i < data.length; ++i)
			data2[data.length - i - 1] = data[i];
		BigInteger bigint = new BigInteger(data2);
		return optimizeBigint(bigint);
	}
	
	/**
	 * encode an arbitrary long number into a byte array (little endian).
	 */
	public static byte[] encode_long(BigInteger big) {
		byte[] data=big.toByteArray();
		// reverse the byte array because pickle uses little endian
		byte[] data2=new byte[data.length];
		for (int i = 0; i < data.length; ++i)
			data2[data.length - i - 1] = data[i];
		return data2;
	}
	

	/**
	 * Optimize a biginteger, if possible return a long primitive datatype.
	 */
	public static Number optimizeBigint(BigInteger bigint) {
		// final BigInteger MAXINT=BigInteger.valueOf(Integer.MAX_VALUE);
		// final BigInteger MININT=BigInteger.valueOf(Integer.MIN_VALUE);
		final BigInteger MAXLONG = BigInteger.valueOf(Long.MAX_VALUE);
		final BigInteger MINLONG = BigInteger.valueOf(Long.MIN_VALUE);
		switch (bigint.signum()) {
		case 0:
			return 0L;
		case 1: // >0
			// if(bigint.compareTo(MAXINT)<=0) return bigint.intValue();
			if (bigint.compareTo(MAXLONG) <= 0)
				return bigint.longValue();
			break;
		case -1: // <0
			// if(bigint.compareTo(MININT)>=0) return bigint.intValue();
			if (bigint.compareTo(MINLONG) >= 0)
				return bigint.longValue();
			break;
		}
		return bigint;
	}

	/**
	 * Construct a String from the given bytes where these are directly
	 * converted to the corresponding chars, without using a given character
	 * encoding
	 */
	public static String rawStringFromBytes(byte[] data) {
		StringBuilder str = new StringBuilder(data.length);
		for (byte b : data) {
			str.append((char) (b & 0xff));
		}
		return str.toString();
	}

	/**
	 * Convert a string to a byte array, no encoding is used. String must only contain characters <256.
	 */
	public static byte[] str2bytes(String str) throws IOException {
		byte[] b=new byte[str.length()];
		for(int i=0; i255) throw new UnsupportedEncodingException("string contained a char > 255, cannot convert to bytes");
			b[i]=(byte)c;
		}
		return b;
	}

	/**
	 * Decode a string with possible escaped char sequences in it (\x??).
	 */
	public static String decode_escaped(String str) {
		if(str.indexOf('\\')==-1)
			return str;
		StringBuilder sb=new StringBuilder(str.length());
		for(int i=0; i '\'
						sb.append(c);
						break;
					case 'x':
						// hex escaped "\x??"
						char h1=str.charAt(++i);
						char h2=str.charAt(++i);
						c2=(char)Integer.parseInt(""+h1+h2, 16);
						sb.append(c2);
						break;
					default:
						throw new PickleException("invalid escape sequence in string");
				}
			} else {
				sb.append(str.charAt(i));
			}
		}
        return sb.toString();
	}

	/**
	 * Decode a string with possible escaped unicode in it (\u20ac)
	 */
	public static String decode_unicode_escaped(String str) {
		if(str.indexOf('\\')==-1)
			return str;
		StringBuilder sb=new StringBuilder(str.length());
		for(int i=0; i '\'
						sb.append(c);
						break;
					case 'u':
						// hex escaped unicode "\u20ac"
						char h1=str.charAt(++i);
						char h2=str.charAt(++i);
						char h3=str.charAt(++i);
						char h4=str.charAt(++i);
						c2=(char)Integer.parseInt(""+h1+h2+h3+h4, 16);
						sb.append(c2);
						break;
					default:
						throw new PickleException("invalid escape sequence in string");
				}
			} else {
				sb.append(str.charAt(i));
			}
		}
        return sb.toString();
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy