2005-12-08 07:13:07 +00:00

778 lines
24 KiB
Java

/*
* 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;
/**
* The data packing class is a static class that is used to pack and unpack basic data types to/from
* network byte order and Intel byte order.
*/
public final class DataPacker
{
// Flag to indicate the byte order of the platform that we are currently
// running on.
private static boolean bigEndian = false;
/**
* Return the current endian setting.
*
* @return true if the system is big endian, else false.
*/
public final static boolean isBigEndian()
{
return bigEndian;
}
/**
* Unpack a null terminated data string from the data buffer.
*
* @param typ Data type, as specified by SMBDataType.
* @param bytarray Byte array to unpack the string value from.
* @param pos Offset to start unpacking the string value.
* @param maxlen Maximum length of data to be searched for a null character.
* @param uni String is Unicode if true, else ASCII
* @return String, else null if the terminating null character was not found.
*/
public final static String getDataString(char typ, byte[] bytarray, int pos, int maxlen, boolean uni)
{
// Check if the data string has the required data type
if (bytarray[pos++] == (byte) typ)
{
// Extract the null terminated string
if (uni == true)
return getUnicodeString(bytarray, wordAlign(pos), maxlen / 2);
else
return getString(bytarray, pos, maxlen - 1);
}
// Invalid data type
return null;
}
/**
* Unpack a 32-bit integer.
*
* @param buf Byte buffer containing the integer to be unpacked.
* @param pos Position within the buffer that the integer is stored.
* @return The unpacked 32-bit integer value.
* @exception java.lang.IndexOutOfBoundsException If there is not enough data in the buffer.
*/
public final static int getInt(byte[] buf, int pos) throws java.lang.IndexOutOfBoundsException
{
// Check if the byte array is long enough
if (buf.length < pos + 3)
throw new java.lang.IndexOutOfBoundsException();
// Unpack the 32-bit value
int i1 = (int) buf[pos] & 0xFF;
int i2 = (int) buf[pos + 1] & 0xFF;
int i3 = (int) buf[pos + 2] & 0xFF;
int i4 = (int) buf[pos + 3] & 0xFF;
int iVal = (i1 << 24) + (i2 << 16) + (i3 << 8) + i4;
// Return the unpacked value
return iVal;
}
/**
* Unpack a 32-bit integer that is stored in Intel format.
*
* @param bytarray Byte array containing the Intel integer to be unpacked.
* @param pos Offset that the Intel integer is stored within the byte array.
* @return Unpacked integer value.
* @exception java.lang.IndexOutOfBoundsException If there is not enough data in the buffer.
*/
public final static int getIntelInt(byte[] bytarray, int pos) throws java.lang.IndexOutOfBoundsException
{
// Check if the byte array is long enough to restore the int
if (bytarray.length < pos + 3)
throw new java.lang.IndexOutOfBoundsException();
// Determine the byte ordering for this platform, and restore the int
int iVal = 0;
// Restore the int value from the byte array
int i1 = (int) bytarray[pos + 3] & 0xFF;
int i2 = (int) bytarray[pos + 2] & 0xFF;
int i3 = (int) bytarray[pos + 1] & 0xFF;
int i4 = (int) bytarray[pos] & 0xFF;
iVal = (i1 << 24) + (i2 << 16) + (i3 << 8) + i4;
// Return the int value
return iVal;
}
/**
* Unpack a 64-bit long.
*
* @param buf Byte buffer containing the integer to be unpacked.
* @param pos Position within the buffer that the integer is stored.
* @return The unpacked 64-bit long value.
* @exception java.lang.IndexOutOfBoundsException If there is not enough data in the buffer.
*/
public final static long getLong(byte[] buf, int pos) throws java.lang.IndexOutOfBoundsException
{
// Check if the byte array is long enough to restore the long
if (buf.length < pos + 7)
throw new java.lang.IndexOutOfBoundsException();
// Restore the long value from the byte array
long lVal = 0L;
for (int i = 0; i < 8; i++)
{
// Get the current byte, shift the value and add to the return value
long curVal = (long) buf[pos + i] & 0xFF;
curVal = curVal << ((7 - i) * 8);
lVal += curVal;
}
// Return the long value
return lVal;
}
/**
* Unpack a 64-bit integer that is stored in Intel format.
*
* @param bytarray Byte array containing the Intel long to be unpacked.
* @param pos Offset that the Intel integer is stored within the byte array.
* @return Unpacked long value.
* @exception java.lang.IndexOutOfBoundsException If there is not enough data in the buffer.
*/
public final static long getIntelLong(byte[] bytarray, int pos) throws java.lang.IndexOutOfBoundsException
{
// Check if the byte array is long enough to restore the long
if (bytarray.length < pos + 7)
throw new java.lang.IndexOutOfBoundsException();
// Restore the long value from the byte array
long lVal = 0L;
for (int i = 0; i < 8; i++)
{
// Get the current byte, shift the value and add to the return value
long curVal = (long) bytarray[pos + i] & 0xFF;
curVal = curVal << (i * 8);
lVal += curVal;
}
// Return the long value
return lVal;
}
/**
* Unpack a 16-bit value that is stored in Intel format.
*
* @param bytarray Byte array containing the short value to be unpacked.
* @param pos Offset to start unpacking the short value.
* @return Unpacked short value.
* @exception java.lang.IndexOutOfBoiundsException If there is not enough data in the buffer.
*/
public final static int getIntelShort(byte[] bytarray, int pos) throws java.lang.IndexOutOfBoundsException
{
// Check if the byte array is long enough to restore the int
if (bytarray.length < pos)
throw new java.lang.IndexOutOfBoundsException();
// Restore the short value from the byte array
int sVal = (((int) bytarray[pos + 1] << 8) + ((int) bytarray[pos] & 0xFF));
// Return the short value
return sVal & 0xFFFF;
}
/**
* Unpack a 16-bit value.
*
* @param bytarray Byte array containing the short to be unpacked.
* @param pos Offset within the byte array that the short is stored.
* @return Unpacked short value.
* @exception java.lang.IndexOutOfBoundsException If there is not enough data in the buffer.
*/
public final static int getShort(byte[] bytarray, int pos) throws java.lang.IndexOutOfBoundsException
{
// Check if the byte array is long enough to restore the int
if (bytarray.length < pos)
throw new java.lang.IndexOutOfBoundsException();
// Determine the byte ordering for this platform, and restore the short
int sVal = 0;
if (bigEndian == true)
{
// Big endian
sVal = ((((int) bytarray[pos + 1]) << 8) + ((int) bytarray[pos] & 0xFF));
}
else
{
// Little endian
sVal = ((((int) bytarray[pos]) << 8) + ((int) bytarray[pos + 1] & 0xFF));
}
// Return the short value
return sVal & 0xFFFF;
}
/**
* Unpack a null terminated string from the data buffer.
*
* @param bytarray Byte array to unpack the string value from.
* @param pos Offset to start unpacking the string value.
* @param maxlen Maximum length of data to be searched for a null character.
* @return String, else null if the terminating null character was not found.
*/
public final static String getString(byte[] bytarray, int pos, int maxlen)
{
// Search for the trailing null
int maxpos = pos + maxlen;
int endpos = pos;
while (bytarray[endpos] != 0x00 && endpos < maxpos)
endpos++;
// Check if we reached the end of the buffer
if (endpos <= maxpos)
return new String(bytarray, pos, endpos - pos);
return null;
}
/**
* Unpack a null terminated string from the data buffer. The string may be ASCII or Unicode.
*
* @param bytarray Byte array to unpack the string value from.
* @param pos Offset to start unpacking the string value.
* @param maxlen Maximum length of data to be searched for a null character.
* @param isUni Unicode string if true, else ASCII string
* @return String, else null if the terminating null character was not found.
*/
public final static String getString(byte[] bytarray, int pos, int maxlen, boolean isUni)
{
// Get a string from the buffer
String str = null;
if (isUni)
str = getUnicodeString(bytarray, pos, maxlen);
else
str = getString(bytarray, pos, maxlen);
// return the string
return str;
}
/**
* Unpack a null terminated Unicode string from the data buffer.
*
* @param byt Byte array to unpack the string value from.
* @param pos Offset to start unpacking the string value.
* @param maxlen Maximum length of data to be searched for a null character.
* @return String, else null if the terminating null character was not found.
*/
public final static String getUnicodeString(byte[] byt, int pos, int maxlen)
{
// Check for an empty string
if (maxlen == 0)
return "";
// Search for the trailing null
int maxpos = pos + (maxlen * 2);
int endpos = pos;
char[] chars = new char[maxlen];
int cpos = 0;
char curChar;
do
{
// Get a Unicode character from the buffer
curChar = (char) (((byt[endpos + 1] & 0xFF) << 8) + (byt[endpos] & 0xFF));
// Add the character to the array
chars[cpos++] = curChar;
// Update the buffer pointer
endpos += 2;
} while (curChar != 0 && endpos < maxpos);
// Check if we reached the end of the buffer
if (endpos <= maxpos)
{
if (curChar == 0)
cpos--;
return new String(chars, 0, cpos);
}
return null;
}
/**
* Pack a 32-bit integer into the supplied byte buffer.
*
* @param val Integer value to be packed.
* @param bytarray Byte buffer to pack the integer value into.
* @param pos Offset to start packing the integer value.
* @exception java.lang.IndexOutOfBoundsException If the buffer does not have enough space.
*/
public final static void putInt(int val, byte[] bytarray, int pos) throws java.lang.IndexOutOfBoundsException
{
// Check if the byte array is long enough to store the int
if (bytarray.length < pos + 3)
throw new java.lang.IndexOutOfBoundsException();
// Pack the integer value
bytarray[pos] = (byte) ((val >> 24) & 0xFF);
bytarray[pos + 1] = (byte) ((val >> 16) & 0xFF);
bytarray[pos + 2] = (byte) ((val >> 8) & 0xFF);
bytarray[pos + 3] = (byte) (val & 0xFF);
}
/**
* Pack an 32-bit integer value in Intel format.
*
* @param val Integer value to be packed.
* @param bytarray Byte array to pack the value into.
* @param pos Offset to start packing the integer value.
* @exception java.lang.IndexOutOfBoundsException If there is not enough data in the buffer.
*/
public final static void putIntelInt(int val, byte[] bytarray, int pos) throws java.lang.IndexOutOfBoundsException
{
// Check if the byte array is long enough to store the int
if (bytarray.length < pos + 3)
throw new java.lang.IndexOutOfBoundsException();
// Store the int value in the byte array
bytarray[pos + 3] = (byte) ((val >> 24) & 0xFF);
bytarray[pos + 2] = (byte) ((val >> 16) & 0xFF);
bytarray[pos + 1] = (byte) ((val >> 8) & 0xFF);
bytarray[pos] = (byte) (val & 0xFF);
}
/**
* Pack a 64-bit integer value into the buffer
*
* @param val Integer value to be packed.
* @param bytarray Byte array to pack the value into.
* @param pos Offset to start packing the integer value.
* @exception java.lang.IndexOutOfBoundsException If there is not enough data in the buffer.
*/
public final static void putLong(long val, byte[] bytarray, int pos) throws java.lang.IndexOutOfBoundsException
{
// Check if the byte array is long enough to store the int
if (bytarray.length < pos + 7)
throw new java.lang.IndexOutOfBoundsException();
// Store the long value in the byte array
bytarray[pos] = (byte) ((val >> 56) & 0xFF);
bytarray[pos + 1] = (byte) ((val >> 48) & 0xFF);
bytarray[pos + 2] = (byte) ((val >> 40) & 0xFF);
bytarray[pos + 3] = (byte) ((val >> 32) & 0xFF);
bytarray[pos + 4] = (byte) ((val >> 24) & 0xFF);
bytarray[pos + 5] = (byte) ((val >> 16) & 0xFF);
bytarray[pos + 6] = (byte) ((val >> 8) & 0xFF);
bytarray[pos + 7] = (byte) (val & 0xFF);
}
/**
* Pack a 64-bit integer value in Intel format.
*
* @param val Integer value to be packed.
* @param bytarray Byte array to pack the value into.
* @param pos Offset to start packing the integer value.
* @exception java.lang.IndexOutOfBoundsException If there is not enough data in the buffer.
*/
public final static void putIntelLong(long val, byte[] bytarray, int pos)
throws java.lang.IndexOutOfBoundsException
{
// Check if the byte array is long enough to store the int
if (bytarray.length < pos + 7)
throw new java.lang.IndexOutOfBoundsException();
// Store the long value in the byte array
bytarray[pos + 7] = (byte) ((val >> 56) & 0xFF);
bytarray[pos + 6] = (byte) ((val >> 48) & 0xFF);
bytarray[pos + 5] = (byte) ((val >> 40) & 0xFF);
bytarray[pos + 4] = (byte) ((val >> 32) & 0xFF);
bytarray[pos + 3] = (byte) ((val >> 24) & 0xFF);
bytarray[pos + 2] = (byte) ((val >> 16) & 0xFF);
bytarray[pos + 1] = (byte) ((val >> 8) & 0xFF);
bytarray[pos] = (byte) (val & 0xFF);
}
/**
* Pack a 64-bit integer value in Intel format.
*
* @param val Integer value to be packed.
* @param bytarray Byte array to pack the value into.
* @param pos Offset to start packing the integer value.
* @exception java.lang.IndexOutOfBoundsException If there is not enough data in the buffer.
*/
public final static void putIntelLong(int val, byte[] bytarray, int pos) throws java.lang.IndexOutOfBoundsException
{
// Check if the byte array is long enough to store the int
if (bytarray.length < pos + 7)
throw new java.lang.IndexOutOfBoundsException();
// Store the int value in the byte array
bytarray[pos + 7] = (byte) 0;
bytarray[pos + 6] = (byte) 0;
bytarray[pos + 5] = (byte) 0;
bytarray[pos + 4] = (byte) 0;
bytarray[pos + 3] = (byte) ((val >> 24) & 0xFF);
bytarray[pos + 2] = (byte) ((val >> 16) & 0xFF);
bytarray[pos + 1] = (byte) ((val >> 8) & 0xFF);
bytarray[pos] = (byte) (val & 0xFF);
}
/**
* Pack a 16 bit value in Intel byte order.
*
* @param val Short value to be packed.
* @param bytarray Byte array to pack the short value into.
* @param pos Offset to start packing the short value.
* @exception java.lang.IndexOutOfBoundsException If there is not enough data in the buffer.
*/
public final static void putIntelShort(int val, byte[] bytarray, int pos)
throws java.lang.IndexOutOfBoundsException
{
// Check if the byte array is long enough to store the short
if (bytarray.length < pos)
throw new java.lang.IndexOutOfBoundsException();
// Pack the short value
bytarray[pos + 1] = (byte) ((val >> 8) & 0xFF);
bytarray[pos] = (byte) (val & 0xFF);
}
/**
* Pack a 16-bit value into the supplied byte buffer.
*
* @param val Short value to be packed.
* @param bytarray Byte array to pack the short value into.
* @param pos Offset to start packing the short value.
* @exception java.lang.IndexOutOfBoundsException If there is not enough data in the buffer.
*/
public final static void putShort(int val, byte[] bytarray, int pos) throws java.lang.IndexOutOfBoundsException
{
// Check if the byte array is long enough to store the short
if (bytarray.length < pos)
throw new java.lang.IndexOutOfBoundsException();
// Pack the short value
bytarray[pos] = (byte) ((val >> 8) & 0xFF);
bytarray[pos + 1] = (byte) (val & 0xFF);
}
/**
* Pack a string into a data buffer
*
* @param str String to be packed into the buffer
* @param bytarray Byte array to pack the string into
* @param pos Position to start packing the string
* @param nullterm true if the string should be null terminated, else false
* @return The ending buffer position
*/
public final static int putString(String str, byte[] bytarray, int pos, boolean nullterm)
{
// Get the string as a byte array
byte[] byts = str.getBytes();
// Pack the data bytes
int bufpos = pos;
for (int i = 0; i < byts.length; i++)
bytarray[bufpos++] = byts[i];
// Null terminate the string, if required
if (nullterm == true)
bytarray[bufpos++] = 0;
// Return the next free buffer position
return bufpos;
}
/**
* Pack a string into a data buffer
*
* @param str String to be packed into the buffer
* @param fldLen Field length, will be space padded if short
* @param bytarray Byte array to pack the string into
* @param pos Position to start packing the string
* @return The ending buffer position
*/
public final static int putString(String str, int fldLen, byte[] bytarray, int pos)
{
// Get the string as a byte array
byte[] byts = str.getBytes();
// Pack the data bytes
int bufpos = pos;
int idx = 0;
while (idx < fldLen)
{
if (idx < byts.length)
bytarray[bufpos++] = byts[idx];
else
bytarray[bufpos++] = (byte) 0;
idx++;
}
// Return the next free buffer position
return bufpos;
}
/**
* Pack a string into a data buffer. The string may be ASCII or Unicode.
*
* @param str String to be packed into the buffer
* @param bytarray Byte array to pack the string into
* @param pos Position to start packing the string
* @param nullterm true if the string should be null terminated, else false
* @param isUni true if the string should be packed as Unicode, false to pack as ASCII
* @return The ending buffer position
*/
public final static int putString(String str, byte[] bytarray, int pos, boolean nullterm, boolean isUni)
{
// Pack the string
int newpos = -1;
if (isUni)
newpos = putUnicodeString(str, bytarray, pos, nullterm);
else
newpos = putString(str, bytarray, pos, nullterm);
// Return the end of string buffer position
return newpos;
}
/**
* Pack a Unicode string into a data buffer
*
* @param str String to be packed into the buffer
* @param bytarray Byte array to pack the string into
* @param pos Position to start packing the string
* @param nullterm true if the string should be null terminated, else false
* @return The ending buffer position
*/
public final static int putUnicodeString(String str, byte[] bytarray, int pos, boolean nullterm)
{
// Pack the data bytes
int bufpos = pos;
for (int i = 0; i < str.length(); i++)
{
// Get the current character from the string
char ch = str.charAt(i);
// Pack the unicode character
bytarray[bufpos++] = (byte) (ch & 0xFF);
bytarray[bufpos++] = (byte) ((ch & 0xFF00) >> 8);
}
// Null terminate the string, if required
if (nullterm == true)
{
bytarray[bufpos++] = 0;
bytarray[bufpos++] = 0;
}
// Return the next free buffer position
return bufpos;
}
/**
* Pack nulls into the buffer.
*
* @param buf Buffer to pack data into.
* @param pos Position to start packing.
* @param cnt Number of nulls to pack.
* @exception java.lang.ArrayIndexOutOfBoundsException If the buffer does not have enough space.
*/
public final static void putZeros(byte[] buf, int pos, int cnt) throws java.lang.ArrayIndexOutOfBoundsException
{
// Check if the buffer is big enough
if (buf.length < (pos + cnt))
throw new java.lang.ArrayIndexOutOfBoundsException();
// Pack the nulls
for (int i = 0; i < cnt; i++)
buf[pos + i] = 0;
}
/**
* Align a buffer offset on a word boundary
*
* @param pos int
* @return int
*/
public final static int wordAlign(int pos)
{
return (pos + 1) & 0xFFFFFFFE;
}
/**
* Align a buffer offset on a longword boundary
*
* @param pos int
* @return int
*/
public final static int longwordAlign(int pos)
{
return (pos + 3) & 0xFFFFFFFC;
}
/**
* Calculate the string length in bytes
*
* @param str String
* @param uni boolean
* @param nul boolean
* @return int
*/
public final static int getStringLength(String str, boolean uni, boolean nul)
{
// Calculate the string length in bytes
int len = str.length();
if (nul)
len += 1;
if (uni)
len *= 2;
return len;
}
/**
* Calculate the new buffer position after the specified string and encoding (ASCII or Unicode)
*
* @param pos int
* @param str String
* @param uni boolean
* @param nul boolean
* @return int
*/
public final static int getBufferPosition(int pos, String str, boolean uni, boolean nul)
{
// Calculate the new buffer position
int len = str.length();
if (nul)
len += 1;
if (uni)
len *= 2;
return pos + len;
}
}