/* * Copyright (C) 2005 Alfresco, Inc. * * Licensed under the Mozilla Public License version 1.1 * with a permitted attribution clause. You may obtain a * copy of the License at * * http://www.alfresco.org/legal/license.txt * * 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 org.alfresco.filesys.util; /** * Data Buffer Class *

* Dynamic buffer for getting/setting data blocks. */ public class DataBuffer { // Constants private static final int DefaultBufferSize = 256; // Data buffer, current position and offset private byte[] m_data; private int m_pos; private int m_endpos; private int m_offset; /** * Default constructor */ public DataBuffer() { m_data = new byte[DefaultBufferSize]; m_pos = 0; m_offset = 0; } /** * Create a data buffer to write data to * * @param siz int */ public DataBuffer(int siz) { m_data = new byte[siz]; m_pos = 0; m_offset = 0; } /** * Create a data buffer to read data from * * @param buf byte[] * @param off int * @param len int */ public DataBuffer(byte[] buf, int off, int len) { m_data = buf; m_offset = off; m_pos = off; m_endpos = off + len; } /** * Return the data buffer * * @return byte[] */ public final byte[] getBuffer() { return m_data; } /** * Return the data length * * @return int */ public final int getLength() { if (m_endpos != 0) return m_endpos - m_offset; return m_pos - m_offset; } /** * Return the data length in words * * @return int */ public final int getLengthInWords() { return getLength() / 2; } /** * Return the available data length * * @return int */ public final int getAvailableLength() { if (m_endpos == 0) return -1; return m_endpos - m_pos; } /** * Return the displacement from the start of the buffer to the current buffer position * * @return int */ public final int getDisplacement() { return m_pos - m_offset; } /** * Return the buffer base offset * * @return int */ public final int getOffset() { return m_offset; } /** * Get a byte from the buffer * * @return int */ public final int getByte() { // Check if there is enough data in the buffer if (m_data.length - m_pos < 1) throw new ArrayIndexOutOfBoundsException("End of data buffer"); // Unpack the byte value int bval = (int) (m_data[m_pos] & 0xFF); m_pos++; return bval; } /** * Get a short from the buffer * * @return int */ public final int getShort() { // Check if there is enough data in the buffer if (m_data.length - m_pos < 2) throw new ArrayIndexOutOfBoundsException("End of data buffer"); // Unpack the integer value int sval = (int) DataPacker.getIntelShort(m_data, m_pos); m_pos += 2; return sval; } /** * Get an integer from the buffer * * @return int */ public final int getInt() { // Check if there is enough data in the buffer if (m_data.length - m_pos < 4) throw new ArrayIndexOutOfBoundsException("End of data buffer"); // Unpack the integer value int ival = DataPacker.getIntelInt(m_data, m_pos); m_pos += 4; return ival; } /** * Get a long (64 bit) value from the buffer * * @return long */ public final long getLong() { // Check if there is enough data in the buffer if (m_data.length - m_pos < 8) throw new ArrayIndexOutOfBoundsException("End of data buffer"); // Unpack the long value long lval = DataPacker.getIntelLong(m_data, m_pos); m_pos += 8; return lval; } /** * Get a string from the buffer * * @param uni boolean * @return String */ public final String getString(boolean uni) { return getString(255, uni); } /** * Get a string from the buffer * * @param maxlen int * @param uni boolean * @return String */ public final String getString(int maxlen, boolean uni) { // Check for Unicode or ASCII String ret = null; int availLen = -1; if (uni) { // Word align the current buffer position, calculate the available // length m_pos = DataPacker.wordAlign(m_pos); availLen = (m_endpos - m_pos) / 2; if (availLen < maxlen) maxlen = availLen; ret = DataPacker.getUnicodeString(m_data, m_pos, maxlen); if (ret != null) m_pos += (ret.length() * 2) + 2; } else { // Calculate the available length availLen = m_endpos - m_pos; if (availLen < maxlen) maxlen = availLen; // Unpack the ASCII string ret = DataPacker.getString(m_data, m_pos, maxlen); if (ret != null) m_pos += ret.length() + 1; } // Return the string return ret; } /** * Get a short from the buffer at the specified index * * @param idx int * @return int */ public final int getShortAt(int idx) { // Check if there is enough data in the buffer int pos = m_offset + (idx * 2); if (m_data.length - pos < 2) throw new ArrayIndexOutOfBoundsException("End of data buffer"); // Unpack the integer value int sval = (int) DataPacker.getIntelShort(m_data, pos) & 0xFFFF; return sval; } /** * Get an integer from the buffer at the specified index * * @param idx int * @return int */ public final int getIntAt(int idx) { // Check if there is enough data in the buffer int pos = m_offset + (idx * 2); if (m_data.length - pos < 4) throw new ArrayIndexOutOfBoundsException("End of data buffer"); // Unpack the integer value int ival = DataPacker.getIntelInt(m_data, pos); return ival; } /** * Get a long (64 bit) value from the buffer at the specified index * * @param idx int * @return long */ public final long getLongAt(int idx) { // Check if there is enough data in the buffer int pos = m_offset + (idx * 2); if (m_data.length - pos < 8) throw new ArrayIndexOutOfBoundsException("End of data buffer"); // Unpack the long value long lval = DataPacker.getIntelLong(m_data, pos); return lval; } /** * Skip over a number of bytes * * @param cnt int */ public final void skipBytes(int cnt) { // Check if there is enough data in the buffer if (m_data.length - m_pos < cnt) throw new ArrayIndexOutOfBoundsException("End of data buffer"); // Skip bytes m_pos += cnt; } /** * Return the data position * * @return int */ public final int getPosition() { return m_pos; } /** * Set the read/write buffer position * * @param pos int */ public final void setPosition(int pos) { m_pos = pos; } /** * Set the end of buffer position, and reset the read position to the beginning of the buffer */ public final void setEndOfBuffer() { m_endpos = m_pos; m_pos = m_offset; } /** * Set the data length * * @param len int */ public final void setLength(int len) { m_pos = m_offset + len; } /** * Append a byte value to the buffer * * @param bval int */ public final void putByte(int bval) { // Check if there is enough space in the buffer if (m_data.length - m_pos < 1) extendBuffer(); // Pack the byte value m_data[m_pos++] = (byte) (bval & 0xFF); } /** * Append a short value to the buffer * * @param sval int */ public final void putShort(int sval) { // Check if there is enough space in the buffer if (m_data.length - m_pos < 2) extendBuffer(); // Pack the short value DataPacker.putIntelShort(sval, m_data, m_pos); m_pos += 2; } /** * Append an integer to the buffer * * @param ival int */ public final void putInt(int ival) { // Check if there is enough space in the buffer if (m_data.length - m_pos < 4) extendBuffer(); // Pack the integer value DataPacker.putIntelInt(ival, m_data, m_pos); m_pos += 4; } /** * Append a long to the buffer * * @param lval long */ public final void putLong(long lval) { // Check if there is enough space in the buffer if (m_data.length - m_pos < 8) extendBuffer(); // Pack the long value DataPacker.putIntelLong(lval, m_data, m_pos); m_pos += 8; } /** * Append a short value to the buffer at the specified index * * @param idx int * @param sval int */ public final void putShortAt(int idx, int sval) { // Check if there is enough space in the buffer int pos = m_offset + (idx * 2); if (m_data.length - pos < 2) extendBuffer(); // Pack the short value DataPacker.putIntelShort(sval, m_data, pos); } /** * Append an integer to the buffer at the specified index * * @param idx int * @param ival int */ public final void putIntAt(int idx, int ival) { // Check if there is enough space in the buffer int pos = m_offset = (idx * 2); if (m_data.length - pos < 4) extendBuffer(); // Pack the integer value DataPacker.putIntelInt(ival, m_data, pos); } /** * Append a long to the buffer at the specified index * * @param idx int * @param lval long */ public final void putLongAt(int idx, int lval) { // Check if there is enough space in the buffer int pos = m_offset = (idx * 2); if (m_data.length - pos < 8) extendBuffer(); // Pack the long value DataPacker.putIntelLong(lval, m_data, pos); } /** * Append a string to the buffer * * @param str String * @param uni boolean */ public final void putString(String str, boolean uni) { putString(str, uni, true); } /** * Append a string to the buffer * * @param str String * @param uni boolean * @param nulTerm boolean */ public final void putString(String str, boolean uni, boolean nulTerm) { // Check for Unicode or ASCII if (uni) { // Check if there is enough space in the buffer int bytLen = str.length() * 2; if (m_data.length - m_pos < bytLen) extendBuffer(bytLen + 4); // Word align the buffer position, pack the Unicode string m_pos = DataPacker.wordAlign(m_pos); DataPacker.putUnicodeString(str, m_data, m_pos, nulTerm); m_pos += (str.length() * 2); if (nulTerm) m_pos += 2; } else { // Check if there is enough space in the buffer if (m_data.length - m_pos < str.length()) extendBuffer(str.length() + 2); // Pack the ASCII string DataPacker.putString(str, m_data, m_pos, nulTerm); m_pos += str.length(); if (nulTerm) m_pos++; } } /** * Append a fixed length string to the buffer * * @param str String * @param len int */ public final void putFixedString(String str, int len) { // Check if there is enough space in the buffer if (m_data.length - m_pos < str.length()) extendBuffer(str.length() + 2); // Pack the ASCII string DataPacker.putString(str, len, m_data, m_pos); m_pos += len; } /** * Append a string to the buffer at the specified buffer position * * @param str String * @param pos int * @param uni boolean * @param nulTerm boolean * @return int */ public final int putStringAt(String str, int pos, boolean uni, boolean nulTerm) { // Check for Unicode or ASCII int retPos = -1; if (uni) { // Check if there is enough space in the buffer int bytLen = str.length() * 2; if (m_data.length - pos < bytLen) extendBuffer(bytLen + 4); // Word align the buffer position, pack the Unicode string pos = DataPacker.wordAlign(pos); retPos = DataPacker.putUnicodeString(str, m_data, pos, nulTerm); } else { // Check if there is enough space in the buffer if (m_data.length - pos < str.length()) extendBuffer(str.length() + 2); // Pack the ASCII string retPos = DataPacker.putString(str, m_data, pos, nulTerm); } // Return the end of string buffer position return retPos; } /** * Append a fixed length string to the buffer at the specified position * * @param str String * @param len int * @param pos int * @return int */ public final int putFixedStringAt(String str, int len, int pos) { // Check if there is enough space in the buffer if (m_data.length - pos < str.length()) extendBuffer(str.length() + 2); // Pack the ASCII string return DataPacker.putString(str, len, m_data, pos); } /** * Append a string pointer to the specified buffer offset * * @param off int */ public final void putStringPointer(int off) { // Calculate the offset from the start of the data buffer to the string // position DataPacker.putIntelInt(off - m_offset, m_data, m_pos); m_pos += 4; } /** * Append zero bytes to the buffer * * @param cnt int */ public final void putZeros(int cnt) { // Check if there is enough space in the buffer if (m_data.length - m_pos < cnt) extendBuffer(cnt); // Pack the zero bytes for (int i = 0; i < cnt; i++) m_data[m_pos++] = 0; } /** * Word align the buffer position */ public final void wordAlign() { m_pos = DataPacker.wordAlign(m_pos); } /** * Longword align the buffer position */ public final void longwordAlign() { m_pos = DataPacker.longwordAlign(m_pos); } /** * Append a raw data block to the data buffer * * @param buf byte[] * @param off int * @param len int */ public final void appendData(byte[] buf, int off, int len) { // Check if there is enough space in the buffer if (m_data.length - m_pos < len) extendBuffer(len); // Copy the data to the buffer and update the current write position System.arraycopy(buf, off, m_data, m_pos, len); m_pos += len; } /** * Copy all data from the data buffer to the user buffer, and update the read position * * @param buf byte[] * @param off int * @return int */ public final int copyData(byte[] buf, int off) { return copyData(buf, off, getLength()); } /** * Copy data from the data buffer to the user buffer, and update the current read position. * * @param buf byte[] * @param off int * @param cnt int * @return int */ public final int copyData(byte[] buf, int off, int cnt) { // Check if there is any more data to copy if (m_pos == m_endpos) return 0; // Calculate the amount of data to copy int siz = m_endpos - m_pos; if (siz > cnt) siz = cnt; // Copy the data to the user buffer and update the current read position System.arraycopy(m_data, m_pos, buf, off, siz); m_pos += siz; // Return the amount of data copied return siz; } /** * Extend the data buffer by the specified amount * * @param ext int */ private final void extendBuffer(int ext) { // Create a new buffer of the required size byte[] newBuf = new byte[m_data.length + ext]; // Copy the data from the current buffer to the new buffer System.arraycopy(m_data, 0, newBuf, 0, m_data.length); // Set the new buffer to be the main buffer m_data = newBuf; } /** * Extend the data buffer, double the currently allocated buffer size */ private final void extendBuffer() { extendBuffer(m_data.length * 2); } /** * Return the data buffer details as a string * * @return String */ public String toString() { StringBuffer str = new StringBuffer(); str.append("[data="); str.append(m_data); str.append(","); str.append(m_pos); str.append("/"); str.append(m_offset); str.append("/"); str.append(getLength()); str.append("]"); return str.toString(); } }