/* * Copyright 2012 The Java HandlerSocket Connection Project * * https://github.com/komelgman/Java-HandlerSocket-Connection/ * * The Project licenses this file to you 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 kom.handlersocket.core; import java.io.IOException; import java.nio.charset.Charset; import java.util.List; public class SafeByteStream { private final int maximumBufferIncrement; private final int initialBufferSize; private final Charset charset; private int cursor; private byte[] buffer; private byte[] unsafeBuffer; public SafeByteStream(final int bufferSize, final int maximumBufferIncrement, Charset charset) { this.maximumBufferIncrement = maximumBufferIncrement; this.initialBufferSize = bufferSize; this.charset = charset; this.buffer = new byte[bufferSize]; this.unsafeBuffer = new byte[2]; this.unsafeBuffer[0] = HSProto.UNSAFE_BYTE_MARKER; } public synchronized void writeByte(byte b, boolean safe) { if (safe && /*unsigned*/ (0xFF & b) < 0x10) { unsafeBuffer[1] = (byte) (b ^ HSProto.UNSAFE_BYTE_MASK); _write(unsafeBuffer, 0, 2, false); } else { unsafeBuffer[1] = b; _write(unsafeBuffer, 1, 1, false); } } public synchronized void writeBytes(final byte[] b, boolean safe) { _write(b, 0, b.length, safe); } public synchronized void writeBytes(final byte[] b, final int offset, final int length, boolean safe) { _write(b, offset, length, safe); } public synchronized void writeString(String str, boolean safe) { final byte[] b = str.getBytes(charset); _write(b, 0, b.length, safe); } public synchronized void writeStrings(List<String> strings, byte[] delimiter, boolean safe) { int count = strings.size(); byte[] b; for (String str : strings) { b = str.getBytes(charset); _write(b, 0, b.length, safe); if (--count > 0) { _write(delimiter, 0, delimiter.length, false); } } } private void _write(final byte[] bytes, final int offset, final int length, boolean safe) { if (length < 0) { throw new IllegalArgumentException(); } if (offset < 0) { throw new IndexOutOfBoundsException(); } if (bytes == null) { throw new NullPointerException(); } if ((length + offset) > bytes.length) { throw new IndexOutOfBoundsException(); } if (safe) { if (cursor + 2 * length > this.buffer.length) { ensureSize(cursor + 2 * length); } for (int i = offset; i < offset + length; ++i) { byte b = bytes[i]; if (/*unsigned*/ (b & 0xFF) < 0x10) { buffer[cursor++] = HSProto.UNSAFE_BYTE_MARKER; buffer[cursor++] = (byte) (b ^ HSProto.UNSAFE_BYTE_MASK); } else { buffer[cursor++] = b; } } } else { if (cursor + length > this.buffer.length) { ensureSize(cursor + length); } System.arraycopy(bytes, offset, this.buffer, cursor, length); cursor += length; } } public synchronized void reset() { this.buffer = new byte[initialBufferSize]; cursor = 0; } private void ensureSize(final int size) { final int computedSize = (int) Math.min((this.buffer.length + 1) * 1.5, this.buffer.length + maximumBufferIncrement); final int newSize = Math.max(size, computedSize); final byte[] newBuffer = new byte[newSize]; System.arraycopy(this.buffer, 0, newBuffer, 0, cursor); this.buffer = newBuffer; } public synchronized byte[] toByteArray() { final byte[] result = new byte[cursor]; System.arraycopy(buffer, 0, result, 0, cursor); return result; } public int getLength() { return cursor; } public byte[] getRaw() { if ((buffer.length - cursor) > 50000) { System.out.println("WASTED: " + (buffer.length - cursor) + " Length: " + buffer.length); } return buffer; } }