com.swirlds.common.io.streams.AugmentedDataInputStream Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of swirlds-common Show documentation
Show all versions of swirlds-common Show documentation
Swirlds is a software platform designed to build fully-distributed applications that harness the power of the cloud without servers. Now you can develop applications with fairness in decision making, speed, trust and reliability, at a fraction of the cost of traditional server-based platforms.
/*
* Copyright (C) 2016-2024 Hedera Hashgraph, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License 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.swirlds.common.io.streams;
import static com.swirlds.common.io.streams.SerializableStreamConstants.DEFAULT_CHECKSUM;
import static com.swirlds.common.io.streams.SerializableStreamConstants.NULL_INSTANT_EPOCH_SECOND;
import static com.swirlds.common.io.streams.SerializableStreamConstants.NULL_LIST_ARRAY_LENGTH;
import com.swirlds.common.io.exceptions.BadIOException;
import com.swirlds.common.utility.CommonUtils;
import java.io.DataInput;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
/**
* This data input stream provides additional functionality for deserializing various basic data structures.
*/
public class AugmentedDataInputStream extends InputStream implements DataInput {
private final DataInputStream baseStream;
/**
* Create an input stream capable of deserializing a variety of useful objects.
*
* @param in
* the base input stream
*/
public AugmentedDataInputStream(final InputStream in) {
baseStream = new DataInputStream(in);
}
/**
* Corresponds to {@link DataInputStream#available()}.
*/
@Override
public int available() throws IOException {
return baseStream.available();
}
/**
* Closes the stream.
*/
@Override
public void close() throws IOException {
baseStream.close();
}
/**
* Corresponds to {@link DataInputStream#read()}.
*/
@Override
public int read() throws IOException {
return baseStream.read();
}
/**
* Corresponds to {@link DataInputStream#read(byte[], int, int)}.
*/
@Override
public int read(final byte[] b, final int off, final int len) throws IOException {
return baseStream.read(b, off, len);
}
/**
* Corresponds to {@link DataInputStream#skip(long)}.
*/
@Override
public long skip(final long n) throws IOException {
return baseStream.skip(n);
}
/**
* Corresponds to {@link DataInputStream#readAllBytes()}.
*/
@Override
public byte[] readAllBytes() throws IOException {
return baseStream.readAllBytes();
}
/**
* Corresponds to {@link DataInputStream#readNBytes(int)}.
*/
@Override
public byte[] readNBytes(final int len) throws IOException {
return baseStream.readNBytes(len);
}
/**
* Corresponds to {@link DataInputStream#readNBytes(byte[], int, int)}.
*/
@Override
public int readNBytes(final byte[] b, final int off, final int len) throws IOException {
return baseStream.readNBytes(b, off, len);
}
/**
* Corresponds to {@link DataInputStream#skipNBytes(long)}.
*/
@Override
public void skipNBytes(final long n) throws IOException {
baseStream.skipNBytes(n);
}
@Override
public void readFully(final byte[] b) throws IOException {
baseStream.readFully(b);
}
@Override
public void readFully(final byte[] b, final int off, final int len) throws IOException {
baseStream.readFully(b, off, len);
}
@Override
public int skipBytes(final int n) throws IOException {
return baseStream.skipBytes(n);
}
@Override
public boolean readBoolean() throws IOException {
return baseStream.readBoolean();
}
@Override
public byte readByte() throws IOException {
return baseStream.readByte();
}
@Override
public int readUnsignedByte() throws IOException {
return baseStream.readUnsignedByte();
}
@Override
public short readShort() throws IOException {
return baseStream.readShort();
}
@Override
public int readUnsignedShort() throws IOException {
return baseStream.readUnsignedShort();
}
@Override
public char readChar() throws IOException {
return baseStream.readChar();
}
@Override
public int readInt() throws IOException {
return baseStream.readInt();
}
@Override
public long readLong() throws IOException {
return baseStream.readLong();
}
@Override
public float readFloat() throws IOException {
return baseStream.readFloat();
}
@Override
public double readDouble() throws IOException {
return baseStream.readDouble();
}
@Override
public String readUTF() throws IOException {
return baseStream.readUTF();
}
@Override
@Deprecated
public String readLine() throws IOException {
return baseStream.readLine();
}
/**
* Reads a byte array from the stream.
*
* @param maxLength
* the maximum expected length of the array
* @param readChecksum
* whether to read the checksum or not
* @return the byte[] read or null if null was written
* @throws IOException
* thrown if any problems occur
*/
public byte[] readByteArray(final int maxLength, final boolean readChecksum) throws IOException {
int len = this.readInt();
if (len < 0) {
// if length is negative, it's a null value
return null;
}
if (readChecksum) {
int checksum = readInt();
if (checksum != (101 - len)) { // must be at wrong place in the stream
throw new BadIOException(
"SerializableDataInputStream tried to create array of length " + len + " with wrong checksum.");
}
}
byte[] bytes;
checkLengthLimit(len, maxLength);
bytes = new byte[len];
this.readFully(bytes);
return bytes;
}
/**
* Reads a byte array from the stream.
* Same as {@link #readByteArray(int, boolean)} with {@code readChecksum} set to false
*
* @param maxLength
* the maximum expected length of the array
* @return the byte[] read or null if null was written
* @throws IOException
* thrown if any problems occur
*/
public byte[] readByteArray(final int maxLength) throws IOException {
return readByteArray(maxLength, DEFAULT_CHECKSUM);
}
/**
* Reads an int array from the stream.
*
* @param maxLength
* the maximum expected length of the array
* @return the int[] read or null if null was written
* @throws IOException
* thrown if any problems occur
*/
public int[] readIntArray(final int maxLength) throws IOException {
int len = readInt();
if (len == NULL_LIST_ARRAY_LENGTH) {
// if length is negative, it's a null value
return null;
}
checkLengthLimit(len, maxLength);
int[] data = new int[len];
for (int i = 0; i < len; i++) {
data[i] = readInt();
}
return data;
}
/**
* Reads an int list from the stream.
*
* @param maxLength
* the maximum expected length of the list
* @return the list read or null if null was written
* @throws IOException
* thrown if any problems occur
*/
public List readIntList(final int maxLength) throws IOException {
int len = readInt();
if (len == NULL_LIST_ARRAY_LENGTH) {
// if length is negative, it's a null value
return null;
}
checkLengthLimit(len, maxLength);
List data = new ArrayList<>(len);
for (int i = 0; i < len; i++) {
data.add(readInt());
}
return data;
}
/**
* Reads a long array from the stream.
*
* @param maxLength
* the maximum expected length of the array
* @return the long[] read or null if null was written
* @throws IOException
* thrown if any problems occur
*/
public long[] readLongArray(final int maxLength) throws IOException {
int len = readInt();
if (len == NULL_LIST_ARRAY_LENGTH) {
// if length is negative, it's a null value
return null;
}
checkLengthLimit(len, maxLength);
long[] data = new long[len];
for (int i = 0; i < len; i++) {
data[i] = readLong();
}
return data;
}
/**
* Reads an long list from the stream.
*
* @param maxLength
* the maximum expected length of the list
* @return the list read or null if null was written
* @throws IOException
* thrown if any problems occur
*/
public List readLongList(final int maxLength) throws IOException {
int len = readInt();
if (len == NULL_LIST_ARRAY_LENGTH) {
// if length is negative, it's a null value
return null;
}
checkLengthLimit(len, maxLength);
List data = new ArrayList<>(len);
for (int i = 0; i < len; i++) {
data.add(readLong());
}
return data;
}
/**
* Reads an boolean list from the stream.
*
* @param maxLength
* the maximum expected length of the list
* @return the list read or null if null was written
* @throws IOException
* thrown if any problems occur
*/
public List readBooleanList(final int maxLength) throws IOException {
int len = readInt();
if (len == NULL_LIST_ARRAY_LENGTH) {
// if length is negative, it's a null value
return null;
}
checkLengthLimit(len, maxLength);
List data = new ArrayList<>(len);
for (int i = 0; i < len; i++) {
data.add(readBoolean());
}
return data;
}
/**
* Reads a float array from the stream.
*
* @param maxLength
* the maximum expected length of the array
* @return the float[] read or null if null was written
* @throws IOException
* thrown if any problems occur
*/
public float[] readFloatArray(final int maxLength) throws IOException {
int len = readInt();
if (len == NULL_LIST_ARRAY_LENGTH) {
// if length is negative, it's a null value
return null;
}
checkLengthLimit(len, maxLength);
float[] data = new float[len];
for (int i = 0; i < len; i++) {
data[i] = readFloat();
}
return data;
}
/**
* Reads an float list from the stream.
*
* @param maxLength
* the maximum expected length of the list
* @return the list read or null if null was written
* @throws IOException
* thrown if any problems occur
*/
public List readFloatList(final int maxLength) throws IOException {
int len = readInt();
if (len == NULL_LIST_ARRAY_LENGTH) {
// if length is negative, it's a null value
return null;
}
checkLengthLimit(len, maxLength);
List data = new ArrayList<>(len);
for (int i = 0; i < len; i++) {
data.add(readFloat());
}
return data;
}
/**
* Reads a double array from the stream.
*
* @param maxLength
* the maximum expected length of the array
* @return the double[] read or null if null was written
* @throws IOException
* thrown if any problems occur
*/
public double[] readDoubleArray(final int maxLength) throws IOException {
int len = readInt();
if (len == NULL_LIST_ARRAY_LENGTH) {
// if length is negative, it's a null value
return null;
}
checkLengthLimit(len, maxLength);
double[] data = new double[len];
for (int i = 0; i < len; i++) {
data[i] = readDouble();
}
return data;
}
/**
* Reads an double list from the stream.
*
* @param maxLength
* the maximum expected length of the list
* @return the list read or null if null was written
* @throws IOException
* thrown if any problems occur
*/
public List readDoubleList(final int maxLength) throws IOException {
int len = readInt();
if (len == NULL_LIST_ARRAY_LENGTH) {
// if length is negative, it's a null value
return null;
}
checkLengthLimit(len, maxLength);
List data = new ArrayList<>(len);
for (int i = 0; i < len; i++) {
data.add(readDouble());
}
return data;
}
/**
* Reads a String array from the stream.
*
* @param maxLength
* the maximum expected length of the array
* @param maxStringLength
* The maximum expected length of a string in the array.
* @return the String[] read or null if null was written
* @throws IOException
* thrown if any problems occur
*/
public String[] readStringArray(final int maxLength, final int maxStringLength) throws IOException {
int len = readInt();
if (len == NULL_LIST_ARRAY_LENGTH) {
// if length is negative, it's a null value
return null;
}
checkLengthLimit(len, maxLength);
String[] data = new String[len];
for (int i = 0; i < len; i++) {
data[i] = readNormalisedString(maxStringLength);
}
return data;
}
/**
* Reads an String list from the stream.
*
* @param maxLength
* the maximum expected length of the list
* @param maxStringLength
* The maximum expected length of a string in the array.
* @return the list read or null if null was written
* @throws IOException
* thrown if any problems occur
*/
public List readStringList(final int maxLength, final int maxStringLength) throws IOException {
int len = readInt();
if (len == NULL_LIST_ARRAY_LENGTH) {
// if length is negative, it's a null value
return null;
}
checkLengthLimit(len, maxLength);
List data = new ArrayList<>(len);
for (int i = 0; i < len; i++) {
data.add(readNormalisedString(maxStringLength));
}
return data;
}
/**
* Read an Instant from the stream
*
* @return the Instant that was read
* @throws IOException
* thrown if there are any problems during the operation
*/
public Instant readInstant() throws IOException {
long epochSecond = this.readLong(); // from getEpochSecond()
if (epochSecond == NULL_INSTANT_EPOCH_SECOND) {
return null;
}
long nanos = this.readLong();
if (nanos < 0 || nanos > 999_999_999) {
throw new IOException("Instant.nanosecond is not within the allowed range!");
}
return Instant.ofEpochSecond(epochSecond, nanos);
}
/**
* Reads a String encoded in the Swirlds default charset (UTF8) from the input stream
*
* @param maxLength
* the maximum length of the String in bytes
* @return the String read
* @throws IOException
* thrown if there are any problems during the operation
*/
public String readNormalisedString(final int maxLength) throws IOException {
byte[] data = readByteArray(maxLength);
if (data == null) {
return null;
}
return CommonUtils.getNormalisedStringFromBytes(data);
}
protected void checkLengthLimit(final int length, final int maxLength) throws IOException {
if (length > maxLength) {
throw new IOException(String.format(
"The input stream provided a length of %d for the list/array "
+ "which exceeds the maxLength of %d",
length, maxLength));
}
}
}