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

io.datakernel.csp.binary.ByteBufsParser Maven / Gradle / Ivy

Go to download

Communicating sequential process via channels, similar to Golang's channels. A channel could be imagine as a pipe which connects some processes.

The newest version!
/*
 * Copyright (C) 2015-2018 SoftIndex 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 io.datakernel.csp.binary;

import io.datakernel.bytebuf.ByteBuf;
import io.datakernel.bytebuf.ByteBufQueue;
import io.datakernel.codec.StructuredDecoder;
import io.datakernel.codec.binary.BinaryUtils;
import io.datakernel.common.parse.InvalidSizeException;
import io.datakernel.common.parse.ParseException;
import io.datakernel.common.parse.ParserFunction;
import org.jetbrains.annotations.Nullable;

import static io.datakernel.bytebuf.ByteBufStrings.CR;
import static io.datakernel.bytebuf.ByteBufStrings.LF;
import static io.datakernel.csp.binary.Utils.parseUntilTerminatorByte;
import static java.lang.Math.min;

@FunctionalInterface
public interface ByteBufsParser {
	ParseException SIZE_EXCEEDS_MAX_SIZE = new InvalidSizeException(ByteBufsParser.class, "Size exceeds max size");
	ParseException NEGATIVE_SIZE = new InvalidSizeException(ByteBufsParser.class, "Invalid size of bytes to be read, should be greater than 0");

	@Nullable
	T tryParse(ByteBufQueue bufs) throws ParseException;

	default  ByteBufsParser andThen(ParserFunction after) {
		return bufs -> {
			T maybeResult = tryParse(bufs);
			if (maybeResult == null) return null;
			return after.parse(maybeResult);
		};
	}

	static ByteBufsParser assertBytes(byte[] data) {
		return bufs -> {
			if (!bufs.hasRemainingBytes(data.length)) return null;
			for (int i = 0; i < data.length; i++) {
				if (data[i] != bufs.peekByte(i)) {
					throw new ParseException(ByteBufsParser.class, "Array of bytes differs at index " + i +
							"[Expected: " + data[i] + ", actual: " + bufs.peekByte(i) + ']');
				}
			}
			bufs.skip(data.length);
			return data;
		};
	}

	static ByteBufsParser ofFixedSize(int length) {
		return bufs -> {
			if (!bufs.hasRemainingBytes(length)) return null;
			return bufs.takeExactSize(length);
		};
	}

	static ByteBufsParser ofNullTerminatedBytes() {
		return ofNullTerminatedBytes(Integer.MAX_VALUE);
	}

	static ByteBufsParser ofNullTerminatedBytes(int maxSize) {
		return parseUntilTerminatorByte((byte) 0, maxSize);
	}

	static ByteBufsParser ofCrTerminatedBytes() {
		return ofCrTerminatedBytes(Integer.MAX_VALUE);
	}

	static ByteBufsParser ofCrTerminatedBytes(int maxSize) {
		return parseUntilTerminatorByte(CR, maxSize);
	}

	static ByteBufsParser ofCrlfTerminatedBytes() {
		return ofCrlfTerminatedBytes(Integer.MAX_VALUE);
	}

	static ByteBufsParser ofCrlfTerminatedBytes(int maxSize) {
		return bufs -> {
			for (int i = 0; i < min(bufs.remainingBytes() - 1, maxSize); i++) {
				if (bufs.peekByte(i) == CR && bufs.peekByte(i + 1) == LF) {
					ByteBuf buf = bufs.takeExactSize(i);
					bufs.skip(2);
					return buf;
				}
			}
			if (bufs.remainingBytes() >= maxSize) {
				throw new ParseException(ByteBufsParser.class, "No CRLF is found in " + maxSize + " bytes");
			}
			return null;
		};
	}

	static ByteBufsParser ofIntSizePrefixedBytes() {
		return ofIntSizePrefixedBytes(Integer.MAX_VALUE);
	}

	static ByteBufsParser ofIntSizePrefixedBytes(int maxSize) {
		return bufs -> {
			if (!bufs.hasRemainingBytes(4)) return null;
			int size = (bufs.peekByte(0) & 0xFF) << 24
					| (bufs.peekByte(1) & 0xFF) << 16
					| (bufs.peekByte(2) & 0xFF) << 8
					| (bufs.peekByte(3) & 0xFF);
			if (size < 0 || size > maxSize) {
				throw new InvalidSizeException(ByteBufsParser.class,
						"Size is either less than 0 or greater than maxSize. Parsed size: " + size);
			}
			if (!bufs.hasRemainingBytes(4 + size)) return null;
			bufs.skip(4);
			return bufs.takeExactSize(size);
		};
	}

	static ByteBufsParser ofShortSizePrefixedBytes() {
		return ofShortSizePrefixedBytes(Integer.MAX_VALUE);
	}

	static ByteBufsParser ofShortSizePrefixedBytes(int maxSize) {
		return bufs -> {
			if (!bufs.hasRemainingBytes(2)) return null;
			int size = (bufs.peekByte(0) & 0xFF) << 8
					| (bufs.peekByte(1) & 0xFF);
			if (size > maxSize) throw SIZE_EXCEEDS_MAX_SIZE;
			if (!bufs.hasRemainingBytes(2 + size)) return null;
			bufs.skip(2);
			return bufs.takeExactSize(size);
		};
	}

	static ByteBufsParser ofByteSizePrefixedBytes() {
		return ofByteSizePrefixedBytes(Integer.MAX_VALUE);
	}

	static ByteBufsParser ofByteSizePrefixedBytes(int maxSize) {
		return bufs -> {
			if (!bufs.hasRemaining()) return null;
			int size = bufs.peekByte(0) & 0xFF;
			if (size > maxSize) throw SIZE_EXCEEDS_MAX_SIZE;
			if (!bufs.hasRemainingBytes(1 + size)) return null;
			bufs.skip(1);
			return bufs.takeExactSize(size);
		};
	}

	static ByteBufsParser ofVarIntSizePrefixedBytes() {
		return ofVarIntSizePrefixedBytes(Integer.MAX_VALUE);
	}

	static ByteBufsParser ofVarIntSizePrefixedBytes(int maxSize) {
		return bufs -> {
			int size;
			int prefixSize;
			if (!bufs.hasRemainingBytes(1)) return null;
			byte b = bufs.peekByte(0);
			if (b >= 0) {
				size = b;
				prefixSize = 1;
			} else {
				if (!bufs.hasRemainingBytes(2)) return null;
				size = b & 0x7f;
				if ((b = bufs.peekByte(1)) >= 0) {
					size |= b << 7;
					prefixSize = 2;
				} else {
					if (!bufs.hasRemainingBytes(3)) return null;
					size |= (b & 0x7f) << 7;
					if ((b = bufs.peekByte(2)) >= 0) {
						size |= b << 14;
						prefixSize = 3;
					} else {
						if (!bufs.hasRemainingBytes(4)) return null;
						size |= (b & 0x7f) << 14;
						if ((b = bufs.peekByte(3)) >= 0) {
							size |= b << 21;
							prefixSize = 4;
						} else {
							if (!bufs.hasRemainingBytes(5)) return null;
							size |= (b & 0x7f) << 21;
							if ((b = bufs.peekByte(4)) >= 0) {
								size |= b << 28;
								prefixSize = 5;
							} else {
								throw new ParseException(ByteBufsParser.class, "Varint is too long for 32-bit integer");
							}
						}
					}
				}
			}
			if (size < 0) throw NEGATIVE_SIZE;
			if (size > maxSize) throw SIZE_EXCEEDS_MAX_SIZE;
			if (!bufs.hasRemainingBytes(prefixSize + size)) return null;
			bufs.skip(prefixSize);
			return bufs.takeExactSize(size);
		};
	}

	static  ByteBufsParser ofDecoder(StructuredDecoder decoder) {
		return ofVarIntSizePrefixedBytes().andThen(buf -> BinaryUtils.decode(decoder, buf));
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy