/* * Copyright 2015 the original author or authors. * * 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.atomix.catalyst.buffer; import java.nio.BufferOverflowException; import java.nio.BufferUnderflowException; import java.nio.ByteOrder; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; /** * Abstract bytes implementation. * <p> * This class provides common state and bounds checking functionality for all {@link Bytes} implementations. * * @author <a href="http://github.com/kuujo">Jordan Halterman</a> */ public abstract class AbstractBytes implements Bytes { private boolean open = true; private SwappedBytes swap; /** * Checks whether the block is open. */ protected void checkOpen() { if (!open) throw new IllegalStateException("bytes not open"); } /** * Checks that the offset is within the bounds of the buffer. */ protected void checkOffset(long offset) { checkOpen(); if (offset < 0 || offset > size()) throw new IndexOutOfBoundsException(); } /** * Checks bounds for a read. */ protected long checkRead(long offset, long length) { checkOffset(offset); long position = offset + length; if (position > size()) throw new BufferUnderflowException(); return position; } /** * Checks bounds for a write. */ protected long checkWrite(long offset, long length) { checkOffset(offset); long position = offset + length; if (position > size()) throw new BufferOverflowException(); return position; } @Override public boolean isDirect() { return false; } @Override public boolean isFile() { return false; } @Override public ByteOrder order() { return ByteOrder.BIG_ENDIAN; } @Override public Bytes order(ByteOrder order) { if (order == null) throw new NullPointerException("order cannot be null"); if (order == order()) return this; if (swap != null) return swap; swap = new SwappedBytes(this); return swap; } @Override public boolean readBoolean(long offset) { return readByte(offset) == 1; } @Override public int readUnsignedByte(long offset) { return readByte(offset) & 0xFF; } @Override public int readUnsignedShort(long offset) { return readShort(offset) & 0xFFFF; } @Override public int readMedium(long offset) { return (readByte(offset)) << 16 | (readByte(offset + 1) & 0xff) << 8 | (readByte(offset + 2) & 0xff); } @Override public int readUnsignedMedium(long offset) { return (readByte(offset) & 0xff) << 16 | (readByte(offset + 1) & 0xff) << 8 | (readByte(offset + 2) & 0xff); } @Override public long readUnsignedInt(long offset) { return readInt(offset) & 0xFFFFFFFFL; } @Override public String readString(long offset) { return readString(offset, Charset.defaultCharset()); } @Override public String readString(long offset, Charset charset) { if (readBoolean(offset)) { byte[] bytes = new byte[readUnsignedShort(offset + BYTE)]; read(offset + BYTE + SHORT, bytes, 0, bytes.length); return new String(bytes, charset); } return null; } @Override public String readUTF8(long offset) { return readString(offset, StandardCharsets.UTF_8); } @Override public Bytes writeBoolean(long offset, boolean b) { return writeByte(offset, b ? 1 : 0); } @Override public Bytes writeUnsignedByte(long offset, int b) { return writeByte(offset, (byte) b); } @Override public Bytes writeUnsignedShort(long offset, int s) { return writeShort(offset, (short) s); } @Override public Bytes writeMedium(long offset, int m) { writeByte(offset, (byte) (m >>> 16)); writeByte(offset + 1, (byte) (m >>> 8)); writeByte(offset + 2, (byte) m); return this; } @Override public Bytes writeUnsignedMedium(long offset, int m) { return writeMedium(offset, m); } @Override public Bytes writeUnsignedInt(long offset, long i) { return writeInt(offset, (int) i); } @Override public Bytes writeString(long offset, String s) { return writeString(offset, s, Charset.defaultCharset()); } @Override public Bytes writeString(long offset, String s, Charset charset) { if (s == null) { return writeBoolean(offset, Boolean.FALSE); } else { writeBoolean(offset, Boolean.TRUE); byte[] bytes = s.getBytes(charset); return writeUnsignedShort(offset + BYTE, bytes.length) .write(offset + BYTE + SHORT, bytes, 0, bytes.length); } } @Override public Bytes writeUTF8(long offset, String s) { return writeString(offset, s, StandardCharsets.UTF_8); } @Override public Bytes flush() { return this; } @Override public void close() { open = false; } }