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

com.davfx.ninio.snmp.BerWriter Maven / Gradle / Ivy

package com.davfx.ninio.snmp;

import java.nio.ByteBuffer;
import java.util.Deque;
import java.util.LinkedList;

public final class BerWriter {
	public static final int BUFFER_SIZE = 8 * 1024; // 8 KiB MAX

	private ByteBuffer buffer;
	private final Deque buffers = new LinkedList();

	// private final Deque toWriteLengthPositions = new LinkedList();

	public BerWriter(ByteBuffer buffer) {
		this.buffer = buffer;
	}

	private void pushBuffer() {
		ByteBuffer b = ByteBuffer.allocate(BUFFER_SIZE);
		buffers.addFirst(buffer);
		buffer = b;
	}

	private void popBuffer() {
		buffer = buffers.removeFirst();
	}

	// Could be encoded on less bytes than 4 but may complicate the algorithm a lot
	private void willWriteLength() {
		/*
		buffer.put((byte) (4 | BerConstants.ASN_BIT8)); // High bit to identify long length
		toWriteLengthPositions.addFirst(buffer.position());
		buffer.putInt(0);
		*/

		pushBuffer();
	}

	private void doWriteLength() {
		/*
		int old = buffer.position();
		int position = toWriteLengthPositions.removeFirst();
		int length = old - position - 4;
		buffer.position(position);
		buffer.order(ByteOrder.BIG_ENDIAN);
		buffer.putInt(length);
		*/

		ByteBuffer toWrite = buffer;
		popBuffer();
		int length = toWrite.position();
		if (length < 0x80) {
			buffer.put((byte) length);
		} else {
			int mask = 0xFF;
			int bits = 0;
			int count = 0;

			while (true) {
				mask <<= 8;
				count++;
				if ((length & mask) == 0) {
					break;
				}
				bits += 8;
			}

			buffer.put((byte) (BerConstants.ASN_BIT8 | count)); // Number of bytes

			while (bits >= 0) {
				int b = (length >>> bits) & 0xFF;
				buffer.put((byte) b);
				bits -= 8;
			}
		}

		// Not very optimal... but avoid to calculate length before writing something
		buffer.put(toWrite.array(), 0, toWrite.position());
	}

	public void writeInteger(int value) {
		buffer.put((byte) BerConstants.INTEGER);
		willWriteLength();

		int mask = 0x1FF << ((8 * 3) - 1);
		int intsize = 4;
		while ((((value & mask) == 0) || ((value & mask) == mask)) && intsize > 1) {
			intsize--;
			value <<= 8;
		}
		mask = 0xFF << (8 * 3);
		while (intsize > 0) {
			buffer.put((byte) ((value & mask) >>> (8 * 3)));
			value <<= 8;
			intsize--;
		}

		/*
		buffer.order(ByteOrder.BIG_ENDIAN);
		buffer.putInt(value);
		*/

		doWriteLength();
	}

	public void writeOid(Oid oid) {
		buffer.put((byte) BerConstants.OID);
		willWriteLength();

		int[] raw = oid.getRaw();

		if (raw.length < 2) {
			throw new IllegalArgumentException();
		}

		buffer.put((byte) ((raw[1] + (raw[0] * 40)) & 0xFF));

		for (int i = 2; i < raw.length; i++) {
			int value = raw[i];

			int mask = ~0x80;
			int bits = 0;

			while (true) {
				mask <<= 7;
				if ((value & mask) == 0) {
					break;
				}
				bits += 7;
			}

			while (bits >= 0) {
				int b = (value >>> bits) & ~0x80;
				if (bits > 0) {
					b |= 0x80; // Continuation bit
				}
				buffer.put((byte) b);
				bits -= 7;
			}
		}

		doWriteLength();
	}

	public void writeString(ByteBuffer s) {
		buffer.put((byte) BerConstants.OCTETSTRING);
		willWriteLength();
		buffer.put(s);
		doWriteLength();
	}

	public void beginWriteSequence() {
		buffer.put((byte) BerConstants.SEQUENCE);
		willWriteLength();
	}

	public void endWriteSequence() {
		doWriteLength();
	}

	public void beginWriteRequestPdu(int type) {
		buffer.put((byte) type);
		willWriteLength();
	}

	public void endWriteRequestPdu() {
		doWriteLength();
	}

	public void beginWriteResponsePdu() {
		buffer.put((byte) BerConstants.RESPONSE);
		willWriteLength();
	}

	public void endWriteResponsePdu() {
		doWriteLength();
	}

	public void writeNull() {
		buffer.put((byte) BerConstants.NULL);
		willWriteLength();
		doWriteLength();
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy