com.amazonaws.encryptionsdk.internal.PrimitivesParser Maven / Gradle / Ivy
/*
* Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except
* in compliance with the License. A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package com.amazonaws.encryptionsdk.internal;
import java.io.DataOutput;
import java.io.IOException;
import com.amazonaws.encryptionsdk.exception.ParseException;
/**
* This class implements methods for parsing the primitives (
* {@code byte, short, int, long}) in Java from a byte array.
*/
//@ non_null_by_default
public class PrimitivesParser {
/**
* Construct a long value using 8 bytes starting at the specified offset.
*
* @param b
* the byte array to parse.
* @param off
* the offset in the byte array to use when parsing.
* @return the parsed long value.
*/
//@ private normal_behavior
//@ requires 0 <= off && off <= b.length - Long.BYTES;
//@ ensures \result == Long.asLong(b[off],b[off+1],b[off+2],b[off+3],b[off+4],b[off+5],b[off+6],b[off+7]);
//@ pure spec_public
private static long getLong(final byte[] b, final int off) {
return ((b[off + 7] & 0xFFL)) + ((b[off + 6] & 0xFFL) << 8) + ((b[off + 5] & 0xFFL) << 16)
+ ((b[off + 4] & 0xFFL) << 24) + ((b[off + 3] & 0xFFL) << 32) + ((b[off + 2] & 0xFFL) << 40)
+ ((b[off + 1] & 0xFFL) << 48) + (((long) b[off]) << 56);
}
/**
* Construct an integer value using 4 bytes starting at the specified offset.
*
* @param b
* the byte array containing the integer value.
* @param off
* the offset in the byte array to use when parsing.
* @return the constructed integer value.
*/
//@ private normal_behavior
//@ requires 0 <= off && off <= b.length - Integer.BYTES;
//@ ensures \result == Integer.asInt(b[off],b[off+1],b[off+2],b[off+3]);
//@ pure spec_public
private static int getInt(final byte[] b, final int off) {
return ((b[off + 3] & 0xFF)) + ((b[off + 2] & 0xFF) << 8) + ((b[off + 1] & 0xFF) << 16)
+ ((b[off] & 0xFF) << 24);
}
/**
* Construct a short value using 4 bytes starting at the specified offset.
*
* @param b
* the byte array containing the short value.
* @param off
* the offset in the byte array to use when parsing.
* @return the constructed short value.
*/
//@ private normal_behavior
//@ requires 0 <= off && off <= b.length - Short.BYTES;
//@ ensures \result == Short.asShort(b[off],b[off+1]);
//@ pure spec_public
private static short getShort(final byte[] b, final int off) {
return (short) ((b[off + 1] & 0xFF) + ((b[off] & 0xFF) << 8));
}
/**
* Parse a long primitive type in the provided bytes. It looks for
* 8 bytes in the provided bytes starting at the specified off.
*
*
* If successful, it returns the value of the parsed long type. On failure,
* it throws a parse exception.
*
* @param b
* the byte array to parse.
* @param off
* the offset in the byte array to use when parsing.
* @return
* the parsed long value.
* @throws ParseException
* if there are not sufficient bytes.
*/
//@ public normal_behavior
//@ requires 0 <= off && off <= b.length - Long.BYTES;
//@ ensures \result == Long.asLong(b[off],b[off+1],b[off+2],b[off+3],b[off+4],b[off+5],b[off+6],b[off+7]);
//@ also private exceptional_behavior
//@ requires b.length - Long.BYTES < off;
//@ signals_only ParseException;
//@ pure
public static long parseLong(final byte[] b, final int off) throws ParseException {
final int size = Long.SIZE / Byte.SIZE;
final int len = b.length - off;
if (len >= size) {
return getLong(b, off);
} else {
throw new ParseException("Not enough bytes to parse a long.");
}
}
/**
* Parse an integer primitive type in the provided bytes. It looks for
* 4 bytes in the provided bytes starting at the specified off.
*
*
* If successful, it returns the value of the parsed integer type. On
* failure, it throws a parse exception.
*
* @param b
* the byte array to parse.
* @param off
* the offset in the byte array to use when parsing.
* @return
* the parsed integer value.
* @throws ParseException
* if there are not sufficient bytes.
*/
//@ public normal_behavior
//@ requires 0 <= off && off <= b.length - Integer.BYTES;
//@ ensures \result == Integer.asInt(b[off],b[off+1],b[off+2],b[off+3]);
//@ also private exceptional_behavior
//@ requires b.length - Integer.BYTES < off;
//@ signals_only ParseException;
//@ pure
public static int parseInt(final byte[] b, final int off) throws ParseException {
final int size = Integer.SIZE / Byte.SIZE;
final int len = b.length - off;
if (len >= size) {
return getInt(b, off);
} else {
throw new ParseException("Not enough bytes to parse an integer.");
}
}
/**
* Parse a short primitive type in the provided bytes. It looks for 2 bytes
* in the provided bytes starting at the specified off.
*
*
* If successful, it returns the value of the parsed short type. On failure,
* it throws a parse exception.
*
* @param b
* the byte array to parse.
* @param off
* the offset in the byte array to use when parsing.
* @return
* the parsed short value.
* @throws ParseException
* if there are not sufficient bytes.
*/
//@ public normal_behavior
//@ requires 0 <= off && off <= b.length - Short.BYTES;
//@ ensures \result == Short.asShort(b[off],b[off+1]);
//@ also private exceptional_behavior
//@ requires b.length - Short.BYTES < off;
//@ signals_only ParseException;
//@ pure
public static short parseShort(final byte[] b, final int off) {
final short size = Short.SIZE / Byte.SIZE;
final int len = b.length - off;
if (len >= size) {
return getShort(b, off);
} else {
throw new ParseException("Not enough bytes to parse a short.");
}
}
/**
* Equivalent to {@link #parseShort(byte[], int)} except the 2 bytes are treated as an unsigned
* value (and thus returned as an into to avoid overflow).
*/
//@ public normal_behavior
//@ requires 0 <= off && off <= b.length - Short.BYTES;
//@ ensures \result == Short.asUnsignedToInt(Short.asShort(b[off], b[off+1]));
//@ ensures \result >= 0 && \result <= Constants.UNSIGNED_SHORT_MAX_VAL;
//@ also private exceptional_behavior
//@ requires b.length - Short.BYTES < off;
//@ signals_only ParseException;
//@ pure
public static int parseUnsignedShort(final byte[] b, final int off) {
final int signedResult = parseShort(b, off);
if (signedResult >= 0) {
return signedResult;
} else {
return Constants.UNSIGNED_SHORT_MAX_VAL + 1 + signedResult;
}
}
/**
* Writes 2 bytes containing the unsigned value {@code uShort} to {@code out}.
*/
//@ // left as TODO because OpenJML/Specs does not have sufficiently detailed
//@ // specs for java.io.DataOutput
//@ public normal_behavior
//@ requires 0 <= uShort && uShort < -Short.MIN_VALUE-Short.MIN_VALUE;
//@// assignable TODO ...
//@// ensures TODO ...
public static void writeUnsignedShort(final DataOutput out, final int uShort) throws IOException {
if (uShort < 0 || uShort > Constants.UNSIGNED_SHORT_MAX_VAL) {
throw new IllegalArgumentException("Unsigned shorts must be between 0 and "
+ Constants.UNSIGNED_SHORT_MAX_VAL);
}
if (uShort < Short.MAX_VALUE) {
out.writeShort(uShort);
} else {
out.writeShort(uShort - Constants.UNSIGNED_SHORT_MAX_VAL - 1);
}
}
/**
* Parse a single byte in the provided bytes. It looks for a byte in the
* provided bytes starting at the specified off.
*
*
* If successful, it returns the value of the parsed byte. On failure, it
* throws a parse exception.
*
* @param b
* the byte array to parse.
* @param off
* the offset in the byte array to use when parsing.
* @return
* the parsed byte value.
* @throws ParseException
* if there are not sufficient bytes.
*/
//@ public normal_behavior
//@ requires 0 <= off && off <= b.length - Byte.BYTES;
//@ ensures \result == b[off];
//@ also private exceptional_behavior
//@ requires b.length - Byte.BYTES < off;
//@ signals_only ParseException;
//@ pure
public static byte parseByte(final byte[] b, final int off) {
final int size = 1;
final int len = b.length - off;
if (len >= size) {
return b[off];
} else {
throw new ParseException("Not enough bytes to parse a byte.");
}
}
}