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

io.hotmoka.marshalling.internal.UnmarshallingContextImpl Maven / Gradle / Ivy

/*
Copyright 2023 Fausto Spoto

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 io.hotmoka.marshalling.internal;

import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;

import io.hotmoka.marshalling.api.Marshallable;
import io.hotmoka.marshalling.api.ObjectUnmarshaller;
import io.hotmoka.marshalling.api.Unmarshaller;
import io.hotmoka.marshalling.api.UnmarshallingContext;

/**
 * Implementation of a context used during bytes unmarshalling into objects.
 */
public class UnmarshallingContextImpl implements UnmarshallingContext {
	private final DataInputStream dis;

	/**
	 * A memory to avoid duplicated strings in the marshalled bytes.
	 */
	private final Map memoryString = new HashMap<>();

	/**
	 * Object marshallers for specific classes, if any.
	 */
	private final Map, ObjectUnmarshaller> objectUnmarshallers = new HashMap<>();

	/**
	 * Creates an unmarshalling context.
	 * 
	 * @param is the input stream of the context
	 */
	public UnmarshallingContextImpl(InputStream is) {
		this.dis = new DataInputStream(new BufferedInputStream(is));
	}

	/**
	 * Registers an object unmarshaller. It will be used to unmarshall its class.
	 * 
	 * @param om the object unmarhaller
	 */
	protected void registerObjectUnmarshaller(ObjectUnmarshaller ou) {
		objectUnmarshallers.put(ou.clazz(), ou);
	}

	@Override
	public int available() throws IOException {
		return dis.available();
	}

	@Override
	public  C readObject(Class clazz) throws IOException {
		@SuppressWarnings("unchecked")
		var ou = (ObjectUnmarshaller) objectUnmarshallers.get(clazz);
		Objects.requireNonNull(ou, "Missing object unmarshaller for class " + clazz.getName());

		return ou.read(this);
	}

	@Override
	public  T[] readLengthAndArray(Unmarshaller unmarshaller, Function supplier) throws IOException {
		int length = readCompactInt();
		T[] result = supplier.apply(length);
		for (int pos = 0; pos < length; pos++)
			result[pos] = unmarshaller.from(this);

		return result;
	}

	@Override
	public byte[] readLengthAndBytes(String mismatchErrorMessage) throws IOException {
		return readBytes(readCompactInt(), mismatchErrorMessage);
	}

	@Override
	public byte readByte() throws IOException {
		return dis.readByte();
	}

	@Override
	public char readChar() throws IOException {
		return dis.readChar();
	}

	@Override
	public boolean readBoolean() throws IOException {
		return dis.readBoolean();
	}

	@Override
	public int readInt() throws IOException {
		return dis.readInt();
	}

	@Override
	public int readCompactInt() throws IOException {
		int i = readByte();
		if (i < 0)
			i += 256;

		switch (i) {
		case 255: return readInt();
		case 254: return readShort();
		default: return i;
		}
	}

	@Override
	public short readShort() throws IOException {
		return dis.readShort();
	}

	@Override
	public long readLong() throws IOException {
		return dis.readLong();
	}

	@Override
	public long readCompactLong() throws IOException {
		int i = readByte();
		if (i < 0)
			i += 256;

		switch (i) {
		case 255: return readLong();
		case 254: return readInt();
		case 253: return readShort();
		default: return i;
		}
	}

	@Override
	public float readFloat() throws IOException {
		return dis.readFloat();
	}

	@Override
	public double readDouble() throws IOException {
		return dis.readDouble();
	}

	@Override
	public String readStringUnshared() throws IOException {
		return dis.readUTF();
	}

	@Override
	public byte[] readBytes(int length, String mismatchErrorMessage) throws IOException {
		var bytes = new byte[length];
		if (length != dis.readNBytes(bytes, 0, length))
			throw new IOException(mismatchErrorMessage);

		return bytes;
	}

	@Override
	public byte[] readAllBytes() throws IOException {
		return dis.readAllBytes();
	}

	/**
	 * Reads the requested number of bytes into the given byte array.
	 *
	 * @param  b the byte array into which the data is read
	 * @param  off the start offset in {@code b} at which the data is written
	 * @param  len the maximum number of bytes to read
	 * @return the actual number of bytes read into the buffer
	 * @throws IOException if an I/O error occurs
	 * @throws IndexOutOfBoundsException If {@code off} is negative, {@code len}
	 *         is negative, or {@code len} is greater than {@code b.length - off}
	 */
	public int readNBytes(byte[] b, int off, int len) throws IOException {
		return dis.readNBytes(b, off, len);
	}

	@Override
	public String readStringShared() throws IOException {
		int selector = readByte();
		if (selector < 0)
			selector = 256 + selector;

		if (selector == 255) {
			String s = readStringUnshared();
			memoryString.put(memoryString.size(), s);
			return s;
		}
		else if (selector == 254)
			return memoryString.get(readInt());
		else
			return memoryString.get(selector);
	}

	@Override
	public BigInteger readBigInteger() throws IOException {
		byte selector = readByte();
		switch (selector) {
		case 0: return BigInteger.valueOf(readShort());
		case 1: return BigInteger.valueOf(readInt());
		case 2: return BigInteger.valueOf(readLong());
		case 3: {
			int numBytes = readCompactInt();
			return new BigInteger(new String(readBytes(numBytes, "BigInteger length mismatch")));
		}
		default: {
			if (selector - 4 < 0)
				return BigInteger.valueOf(selector + 252);
			else
				return BigInteger.valueOf(selector - 4);
		}
		}
	}

	@Override
	public void close() throws IOException {
		dis.close();
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy