/* * Copyright © 2010-2011 Rebecca G. Bettencourt / Kreative Software * <p> * The contents of this file are subject to the Mozilla Public License * Version 1.1 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * <a href="http://www.mozilla.org/MPL/">http://www.mozilla.org/MPL/</a> * <p> * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the * License for the specific language governing rights and limitations * under the License. * <p> * Alternatively, the contents of this file may be used under the terms * of the GNU Lesser General Public License (the "LGPL License"), in which * case the provisions of LGPL License are applicable instead of those * above. If you wish to allow use of your version of this file only * under the terms of the LGPL License and not to allow others to use * your version of this file under the MPL, indicate your decision by * deleting the provisions above and replace them with the notice and * other provisions required by the LGPL License. If you do not delete * the provisions above, a recipient may use your version of this file * under either the MPL or the LGPL License. * @since KSFL 1.0 * @author Rebecca G. Bettencourt, Kreative Software */ package com.kreative.ksfl; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.io.DataInput; import java.io.DataOutput; import java.io.RandomAccessFile; import java.io.PrintStream; public class KSFLUtilities { private KSFLUtilities() {} /** * The maximum value of an unsigned 48-bit integer. */ public static final long UINT48_MAX_VALUE = (1L << 48L) - 1L; /** * Reverses the bytes of a 48-bit integer. * @param v a 48-bit integer. * @return a 48-bit integer with the bytes reversed. */ public static long reverseUInt48(long v) { return Long.reverseBytes(v) >>> 16L; } /** * Reads an unsigned 48-bit integer from a data input. * @param in a data input to read from. * @return an unsigned 48-bit integer. * @throws IOException */ public static long readUInt48(DataInput in) throws IOException { long l = ((long)in.readShort() & 0xFFFFL) << 32L; l |= ((long)in.readInt() & 0xFFFFFFFFL); return l; } /** * Writes an unsigned 48-bit integer to a data output. * @param out a data output to write to. * @param v an unsigned 48-bit integer. * @throws IOException */ public static void writeUInt48(DataOutput out, long v) throws IOException { out.writeShort((short)((v >>> 32L) & 0xFFFFL)); out.writeInt((int)(v & 0xFFFFFFFFL)); } /** * Creates a one-character constant, used for magic numbers, from an array of bytes. * Missing bytes are padded with spaces. * If the array is longer than one byte, only the first is used. * @param type An array of bytes. * @return The full type as a byte. */ public static byte occ(byte[] type) { if (type.length < 1) return 0x20; else return type[0]; } /** * Creates a one-character constant, used for magic numbers, from a string. * The string is converted to bytes using the ISO-Latin-1 encoding. * If the string is shorter than one character, it is padded with spaces. * If the string is longer than one character, only the first is used. * @param type The type as a string. * @return The same type as a byte. */ public static byte occ(String type) { if (type.length() < 1) return 0x20; else return (byte)type.charAt(0); } /** * Creates a one-character constant, used for magic numbers, from an array of characters. * The characters are converted to bytes using the ISO-Latin-1 encoding. * Missing characters are padded with spaces. * If the array is longer than one character, only the first is used. * @param type The type as an array of characters. * @return The same type as a byte. */ public static byte occ(char[] type) { if (type.length < 1) return 0x20; else return (byte)type[0]; } /** * Turns a resource type back into its string representation. * The bytes are converted to a string using the ISO-Latin-1 encoding. * @param type The type as a byte. * @return The same type as a string. */ public static String occs(byte type) { return Character.toString((char)(type & 0xFF)); } /** * Creates a two-character constant, used for magic numbers, from an array of bytes. * Missing bytes are padded with spaces. * If the array is longer than two bytes, only the first two are used. * @param type An array of bytes. * @return The full type as a short. */ public static short tcc(byte[] type) { switch (type.length) { case 0: return 0x2020; case 1: return (short)(((type[0] & 0xFF) << 8) | 0x20); default: return (short)(((type[0] & 0xFF) << 8) | (type[1] & 0xFF)); } } /** * Creates a two-character constant, used for magic numbers, from a string. * The string is converted to bytes using the ISO-Latin-1 encoding. * If the string is shorter than two characters, it is padded with spaces. * If the string is longer than two characters, only the first two are used. * @param type The type as a string. * @return The same type as a short. */ public static int tcc(String type) { try { return tcc(type.getBytes("ISO-8859-1")); } catch (UnsupportedEncodingException uee) { return tcc(type.getBytes()); } } /** * Creates a two-character constant, used for magic numbers, from an array of characters. * The characters are converted to bytes using the ISO-Latin-1 encoding. * Missing characters are padded with spaces. * If the array is longer than two characters, only the first two are used. * @param type The type as an array of characters. * @return The same type as a short. */ public static int tcc(char[] type) { return tcc(new String(type)); } /** * Turns a resource type back into its string representation. * The bytes are converted to a string using the ISO-Latin-1 encoding. * @param type The type as a short. * @return The same type as a string. */ public static String tccs(short type) { byte[] a = new byte[2]; a[0] = (byte)((type >>> 8) & 0xFF); a[1] = (byte)((type >>> 0) & 0xFF); try { return new String(a, "ISO-8859-1"); } catch (UnsupportedEncodingException uee) { return new String(a); } } /** * Creates a four-character constant, used for resource types, from an array of bytes. * Missing bytes are padded with spaces. In other words, * <code>fcc(new byte[] b = {0x73, 0x6E, 0x64})</code> returns 0x736E6420. * If the array is longer than four bytes, only the first four are used. * @param type An array of bytes. * @return The full type as an integer. */ public static int fcc(byte[] type) { switch (type.length) { case 0: return 0x20202020; case 1: return (((type[0] & 0xFF)<<24)|0x202020); case 2: return (((((type[0] & 0xFF)<<8)|(type[1] & 0xFF))<<16)|0x2020); case 3: return (((((((type[0] & 0xFF)<<8)|(type[1] & 0xFF))<<8)|(type[2] & 0xFF))<<8)|0x20); default: return (((((((type[0] & 0xFF)<<8)|(type[1] & 0xFF))<<8)|(type[2] & 0xFF))<<8)|(type[3] & 0xFF)); } } /** * Creates a four-character constant, used for resource types, from a string. * The string is converted to bytes using the MacRoman encoding. * If MacRoman is not supported, the default encoding is used instead. * If the string is shorter than four characters, it is padded with spaces. * In other words, <code>"STR"</code> is the same as <code>"STR "</code>. * If the string is longer than four characters, only the first four are used. * @param type The type as a string. * @return The same type as an integer. */ public static int fcc(String type) { try { return fcc(type.getBytes("MACROMAN")); } catch (UnsupportedEncodingException e) { return fcc(type.getBytes()); } } /** * Creates a four-character constant, used for resource types, from an array of characters. * The characters are converted to bytes using the MacRoman encoding. * If MacRoman is not supported, the default encoding is used instead. * Missing characters are padded with spaces. In other words, * <code>fcc(new char[] c = {'s', 'n', 'd'})</code> returns 0x736E6420. * If the array is longer than four characters, only the first four are used. * @param type The type as an array of characters. * @return The same type as an integer. */ public static int fcc(char[] type) { return fcc(new String(type)); } /** * Turns a resource type back into its string representation. * The bytes are converted to a string using the MacRoman encoding. * If MacRoman is not supported, the default encoding is used instead. * @param type The type as an integer. * @return The same type as a string. */ public static String fccs(int type) { byte[] a = new byte[4]; a[0] = (byte)((type>>24) & 0xFF); a[1] = (byte)((type>>16) & 0xFF); a[2] = (byte)((type>> 8) & 0xFF); a[3] = (byte)((type>> 0) & 0xFF); try { return new String(a,"MACROMAN"); } catch (UnsupportedEncodingException e) { return new String(a); } } /** * Creates a eight-character constant, used for DFF types, from an array of bytes. * Missing bytes are padded with spaces. In other words, * <code>ecc(new byte[] b = {0x73, 0x6E, 0x64})</code> returns 0x736E642020202020. * If the array is longer than eight bytes, only the first eight are used. * @param type An array of bytes. * @return The full type as a long. */ public static long ecc(byte[] type) { long l = 0l; int i = 0; while (i < type.length && i < 8) { l <<= 8; l |= (type[i] & 0xFFl); i++; } while (i < 8) { l <<= 8; l |= 0x20l; i++; } return l; } /** * Creates a eight-character constant, used for DFF types, from a string. * If the string is four or less characters in length, UTF-16 encoding is used. * Otherwise, ISO Latin 1 encoding is used. * Missing characters are padded with spaces. In other words, * "Img PNG" is encoded the same as "Img PNG ". * If the string is longer than eight characters, only the first eight are used. * @param type The type as a string. * @return The same type as a long. */ public static long ecc(String type) { try { if (type.length() > 4) return ecc(type.getBytes("ISO-8859-1")); else return ecc(type.getBytes("UTF-16BE")); } catch (UnsupportedEncodingException e) { return ecc(type.getBytes()); } } /** * Creates a eight-character constant, used for DFF types, from an array of characters. * If the array is four or less characters in length, UTF-16 encoding is used. * Otherwise, ISO Latin 1 encoding is used. * Missing characters are padded with spaces. In other words, * <code>ecc(new char[] c = {'I', 'm', 'g', ' ', 'B', 'M', 'P'})</code> returns 0x496D6720424D5020. * If the array is longer than eight characters, only the first eight are used. * @param type The type as an array of characters. * @return The same type as a long. */ public static long ecc(char[] type) { return ecc(new String(type)); } /** * Turns a Mac OS resource type into its DFF type representation. * @param type the Mac OS resource type. * @return a corresponding DFF type. */ public static long eccAdaptMacResType(int type) { return 0x4D61632000000000l | (type & 0xFFFFFFFFl); } /** * Turns a Mac OS resource type into its DFF type representation. * @param type the Mac OS resource type. * @return a corresponding DFF type. */ public static long eccAdaptMacResType(String type) { return ecc("Mac "+type); } /** * Turns a Palm OS resource type into its DFF type representation. * @param type the Palm OS resource type. * @return a corresponding DFF type. */ public static long eccAdaptPalmResType(int type) { return 0x50616C6D00000000l | (type & 0xFFFFFFFFl); } /** * Turns a Palm OS resource type into its DFF type representation. * @param type the Palm OS resource type. * @return a corresponding DFF type. */ public static long eccAdaptPalmResType(String type) { return ecc("Palm"+type); } /** * Turns a ProDOS file type and auxiliary type into its DFF type representation. * @param ftype the ProDOS file type. * @param atype the ProDOS auxiliary type. * @return a corresponding DFF type. */ public static long eccAdaptProDOSFileType(int ftype, int atype) { byte[] a = new byte[]{'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; return ecc(new byte[]{'P','D',a[(ftype>>4)&0xF],a[ftype&0xF],a[(atype>>12)&0xF],a[(atype>>8)&0xF],a[(atype>>4)&0xF],a[atype&0xF]}); } /** * Turns a file extension into its DFF type representation. * @param ext the file extension, with or without a preceding dot. * @return a corresponding DFF type. */ public static long eccAdaptFileExtension(String ext) { if (ext.contains(".")) { String[] ss = ext.split("\\."); ext = ss[ss.length-1]; } switch (ext.length()) { case 0: return ecc("Miscella"); case 1: return ecc("Miscell"+ext.toUpperCase()); case 2: case 3: return ecc("Misc "+ext.toUpperCase()); case 4: return ecc("Misc"+ext.toUpperCase()); case 5: return ecc("Msc"+ext.toUpperCase()); case 6: return ecc("Ms"+ext.toUpperCase()); default: return ecc(ext.toUpperCase()); } } /** * Turns a DFF type back into its string representation. * Text encoding is attempted to be determined by byte values. * If any bytes are in the ranges 0x00-0x1F or 0x7F-0x9F, * UTF-16 is assumed. Otherwise ISO Latin 1 is assumed. * @param type The type as an integer. * @return The same type as a string. */ public static String eccs(long type) { byte[] a = new byte[8]; a[0] = (byte)((type>>56) & 0xFF); a[1] = (byte)((type>>48) & 0xFF); a[2] = (byte)((type>>40) & 0xFF); a[3] = (byte)((type>>32) & 0xFF); a[4] = (byte)((type>>24) & 0xFF); a[5] = (byte)((type>>16) & 0xFF); a[6] = (byte)((type>> 8) & 0xFF); a[7] = (byte)((type>> 0) & 0xFF); boolean utf16 = ( ((a[0] >= (byte)0x00 && a[0] < (byte)0x20) || (a[0] == (byte)0x7F) || (a[0] >= (byte)0x80 && a[0] < (byte)0xA0)) || ((a[1] >= (byte)0x00 && a[1] < (byte)0x20) || (a[1] == (byte)0x7F) || (a[1] >= (byte)0x80 && a[1] < (byte)0xA0)) || ((a[2] >= (byte)0x00 && a[2] < (byte)0x20) || (a[2] == (byte)0x7F) || (a[2] >= (byte)0x80 && a[2] < (byte)0xA0)) || ((a[3] >= (byte)0x00 && a[3] < (byte)0x20) || (a[3] == (byte)0x7F) || (a[3] >= (byte)0x80 && a[3] < (byte)0xA0)) || ((a[4] >= (byte)0x00 && a[4] < (byte)0x20) || (a[4] == (byte)0x7F) || (a[4] >= (byte)0x80 && a[4] < (byte)0xA0)) || ((a[5] >= (byte)0x00 && a[5] < (byte)0x20) || (a[5] == (byte)0x7F) || (a[5] >= (byte)0x80 && a[5] < (byte)0xA0)) || ((a[6] >= (byte)0x00 && a[6] < (byte)0x20) || (a[6] == (byte)0x7F) || (a[6] >= (byte)0x80 && a[6] < (byte)0xA0)) || ((a[7] >= (byte)0x00 && a[7] < (byte)0x20) || (a[7] == (byte)0x7F) || (a[7] >= (byte)0x80 && a[7] < (byte)0xA0)) ); try { return new String(a,utf16?"UTF-16BE":"ISO-8859-1"); } catch (UnsupportedEncodingException e) { return new String(a); } } /** * Gets an 8-bit big-endian integer out of an array of bytes. * @param data The array of bytes to copy from. * @param i The index of the first byte of the integer. * @return The 8-bit big-endian integer at index <code>i</code>. */ public static byte getByte(byte[] data, int i) { return data[i+0]; } /** * Gets a 16-bit big-endian integer out of an array of bytes. * @param data The array of bytes to copy from. * @param i The index of the first byte of the integer. * @return The 16-bit big-endian integer at index <code>i</code>. */ public static short getShort(byte[] data, int i) { return (short)( ((data[i+0] & 0xFF) << 8) | ((data[i+1] & 0xFF) << 0) ); } /** * Gets a 32-bit big-endian integer out of an array of bytes. * @param data The array of bytes to copy from. * @param i The index of the first byte of the integer. * @return The 32-bit big-endian integer at index <code>i</code>. */ public static int getInt(byte[] data, int i) { return (int)( ((data[i+0] & 0xFF) << 24) | ((data[i+1] & 0xFF) << 16) | ((data[i+2] & 0xFF) << 8) | ((data[i+3] & 0xFF) << 0) ); } /** * Gets a 48-bit big-endian integer out of an array of bytes. * @param data The array of bytes to copy from. * @param i The index of the first byte of the integer. * @return The 48-bit big-endian integer at index <code>i</code>. */ public static long getUInt48(byte[] data, int i) { return (long)( (((long)data[i+0] & 0xFFl) << 40l) | (((long)data[i+1] & 0xFFl) << 32l) | (((long)data[i+2] & 0xFFl) << 24l) | (((long)data[i+3] & 0xFFl) << 16l) | (((long)data[i+4] & 0xFFl) << 8l) | (((long)data[i+5] & 0xFFl) << 0l) ); } /** * Gets a 64-bit big-endian integer out of an array of bytes. * @param data The array of bytes to copy from. * @param i The index of the first byte of the integer. * @return The 64-bit big-endian integer at index <code>i</code>. */ public static long getLong(byte[] data, int i) { return (long)( (((long)data[i+0] & 0xFFl) << 56l) | (((long)data[i+1] & 0xFFl) << 48l) | (((long)data[i+2] & 0xFFl) << 40l) | (((long)data[i+3] & 0xFFl) << 32l) | (((long)data[i+4] & 0xFFl) << 24l) | (((long)data[i+5] & 0xFFl) << 16l) | (((long)data[i+6] & 0xFFl) << 8l) | (((long)data[i+7] & 0xFFl) << 0l) ); } /** * Gets a 32-bit big-endian fixed-point number out of an array of bytes. * The radix point is fixed at the center, right between the middle two bytes. * @param data The array of bytes to copy from. * @param i The index of the first byte of the fixed-point number. * @return The fixed-point number at index <code>i</code>. */ public static double getFixed(byte[] data, int i) { return (double)getInt(data,i) / 65536.0; } /** * Gets an IEEE single-precision floating point number out of an array of bytes. * @param data The array of bytes to copy from. * @param i The index of the first byte of the float. * @return The float at index <code>i</code>. */ public static float getFloat(byte[] data, int i) { return Float.intBitsToFloat(getInt(data, i)); } /** * Gets an IEEE double-precision floating point number out of an array of bytes. * @param data The array of bytes to copy from. * @param i The index of the first byte of the double. * @return The double at index <code>i</code>. */ public static double getDouble(byte[] data, int i) { return Double.longBitsToDouble(getLong(data, i)); } /** * Gets a point out of an array of bytes. * A point is defined by two 16-bit big-endian integers, * the first representing the Y coordinate and the second * representing the X coordinate. * @param data The array of bytes to copy from. * @param i The index of the first byte of the point. * @return The point at index <code>i</code>. */ public static java.awt.Point getPoint(byte[] data, int i) { return new java.awt.Point( getShort(data, i+2), getShort(data, i+0) ); } /** * Gets a rectangle out of an array of bytes. * A rectangle is defined by four 16-bit big-endian integers, * representing the top, left, bottom, and right. * @param data The array of bytes to copy from. * @param i The index of the first byte of the rectangle. * @return The rectangle at index <code>i</code>. */ public static java.awt.Rectangle getRect(byte[] data, int i) { return new java.awt.Rectangle( getShort(data, i+2), getShort(data, i+0), getShort(data, i+6)-getShort(data, i+2), getShort(data, i+4)-getShort(data, i+0) ); } /** * Gets a 24-bit color out of an array of bytes. * The red byte comes first, then green, then blue. * @param data The array of bytes to copy from. * @param i The index of the first byte of the color. * @return The 24-bit color at index <code>i</code>. */ public static java.awt.Color getColor24(byte[] data, int i) { return new java.awt.Color( getByte(data, i+0) & 0xFF, getByte(data, i+1) & 0xFF, getByte(data, i+2) & 0xFF ); } /** * Gets a 32-bit color out of an array of bytes. * The alpha byte comes first, then red, then green, then blue. * @param data The array of bytes to copy from. * @param i The index of the first byte of the color. * @return The 32-bit color at index <code>i</code>. */ public static java.awt.Color getColor32(byte[] data, int i) { return new java.awt.Color( getByte(data, i+1) & 0xFF, getByte(data, i+2) & 0xFF, getByte(data, i+3) & 0xFF, getByte(data, i+0) & 0xFF ); } /** * Gets a 48-bit color out of an array of bytes. * The red short comes first, then green, then blue. * All shorts are big-endian. * @param data The array of bytes to copy from. * @param i The index of the first byte of the color. * @return The 48-bit color at index <code>i</code>. */ public static java.awt.Color getColor48(byte[] data, int i) { return new java.awt.Color( (getShort(data, i+0) & 0xFFFF) / 65535.0f, (getShort(data, i+2) & 0xFFFF) / 65535.0f, (getShort(data, i+4) & 0xFFFF) / 65535.0f ); } /** * Gets a 64-bit color out of an array of bytes. * The alpha short comes first, then red, then green, then blue. * All shorts are big-endian. * @param data The array of bytes to copy from. * @param i The index of the first byte of the color. * @return The 64-bit color at index <code>i</code>. */ public static java.awt.Color getColor64(byte[] data, int i) { return new java.awt.Color( (getShort(data, i+2) & 0xFFFF) / 65535.0f, (getShort(data, i+4) & 0xFFFF) / 65535.0f, (getShort(data, i+6) & 0xFFFF) / 65535.0f, (getShort(data, i+0) & 0xFFFF) / 65535.0f ); } /** * Gets an 8-bit little-endian integer out of an array of bytes. * @param data The array of bytes to copy from. * @param i The index of the first byte of the integer. * @return The 8-bit little-endian integer at index <code>i</code>. */ public static byte getByteLE(byte[] data, int i) { return data[i+0]; } /** * Gets a 16-bit little-endian integer out of an array of bytes. * @param data The array of bytes to copy from. * @param i The index of the first byte of the integer. * @return The 16-bit little-endian integer at index <code>i</code>. */ public static short getShortLE(byte[] data, int i) { return (short)( ((data[i+0] & 0xFF) << 0) | ((data[i+1] & 0xFF) << 8) ); } /** * Gets a 32-bit little-endian integer out of an array of bytes. * @param data The array of bytes to copy from. * @param i The index of the first byte of the integer. * @return The 32-bit little-endian integer at index <code>i</code>. */ public static int getIntLE(byte[] data, int i) { return (int)( ((data[i+0] & 0xFF) << 0) | ((data[i+1] & 0xFF) << 8) | ((data[i+2] & 0xFF) << 16) | ((data[i+3] & 0xFF) << 24) ); } /** * Gets a 48-bit little-endian integer out of an array of bytes. * @param data The array of bytes to copy from. * @param i The index of the first byte of the integer. * @return The 48-bit little-endian integer at index <code>i</code>. */ public static long getUInt48LE(byte[] data, int i) { return (long)( (((long)data[i+0] & 0xFFl) << 0l) | (((long)data[i+1] & 0xFFl) << 8l) | (((long)data[i+2] & 0xFFl) << 16l) | (((long)data[i+3] & 0xFFl) << 24l) | (((long)data[i+4] & 0xFFl) << 32l) | (((long)data[i+5] & 0xFFl) << 40l) ); } /** * Gets a 64-bit little-endian integer out of an array of bytes. * @param data The array of bytes to copy from. * @param i The index of the first byte of the integer. * @return The 64-bit little-endian integer at index <code>i</code>. */ public static long getLongLE(byte[] data, int i) { return (long)( (((long)data[i+0] & 0xFFl) << 0l) | (((long)data[i+1] & 0xFFl) << 8l) | (((long)data[i+2] & 0xFFl) << 16l) | (((long)data[i+3] & 0xFFl) << 24l) | (((long)data[i+4] & 0xFFl) << 32l) | (((long)data[i+5] & 0xFFl) << 40l) | (((long)data[i+6] & 0xFFl) << 48l) | (((long)data[i+7] & 0xFFl) << 56l) ); } /** * Gets a 32-bit little-endian fixed-point number out of an array of bytes. * The radix point is fixed at the center, right between the middle two bytes. * @param data The array of bytes to copy from. * @param i The index of the first byte of the fixed-point number. * @return The fixed-point number at index <code>i</code>. */ public static double getFixedLE(byte[] data, int i) { return (double)getIntLE(data,i) / 65536.0; } /** * Gets an IEEE single-precision floating point number out of an array of bytes. * @param data The array of bytes to copy from. * @param i The index of the first byte of the float. * @return The float at index <code>i</code>. */ public static float getFloatLE(byte[] data, int i) { return Float.intBitsToFloat(getIntLE(data, i)); } /** * Gets an IEEE double-precision floating point number out of an array of bytes. * @param data The array of bytes to copy from. * @param i The index of the first byte of the double. * @return The double at index <code>i</code>. */ public static double getDoubleLE(byte[] data, int i) { return Double.longBitsToDouble(getLongLE(data, i)); } /** * Gets a point out of an array of bytes. * A point is defined by two 16-bit little-endian integers, * the first representing the Y coordinate and the second * representing the X coordinate. * @param data The array of bytes to copy from. * @param i The index of the first byte of the point. * @return The point at index <code>i</code>. */ public static java.awt.Point getPointLE(byte[] data, int i) { return new java.awt.Point( getShortLE(data, i+2), getShortLE(data, i+0) ); } /** * Gets a rectangle out of an array of bytes. * A rectangle is defined by four 16-bit little-endian integers, * representing the top, left, bottom, and right. * @param data The array of bytes to copy from. * @param i The index of the first byte of the rectangle. * @return The rectangle at index <code>i</code>. */ public static java.awt.Rectangle getRectLE(byte[] data, int i) { return new java.awt.Rectangle( getShortLE(data, i+2), getShortLE(data, i+0), getShortLE(data, i+6)-getShortLE(data, i+2), getShortLE(data, i+4)-getShortLE(data, i+0) ); } /** * Gets a 24-bit color out of an array of bytes. * The red byte comes first, then green, then blue. * @param data The array of bytes to copy from. * @param i The index of the first byte of the color. * @return The 24-bit color at index <code>i</code>. */ public static java.awt.Color getColor24LE(byte[] data, int i) { return new java.awt.Color( getByteLE(data, i+0) & 0xFF, getByteLE(data, i+1) & 0xFF, getByteLE(data, i+2) & 0xFF ); } /** * Gets a 32-bit color out of an array of bytes. * The alpha byte comes first, then red, then green, then blue. * @param data The array of bytes to copy from. * @param i The index of the first byte of the color. * @return The 32-bit color at index <code>i</code>. */ public static java.awt.Color getColor32LE(byte[] data, int i) { return new java.awt.Color( getByteLE(data, i+1) & 0xFF, getByteLE(data, i+2) & 0xFF, getByteLE(data, i+3) & 0xFF, getByteLE(data, i+0) & 0xFF ); } /** * Gets a 48-bit color out of an array of bytes. * The red short comes first, then green, then blue. * All shorts are little-endian. * @param data The array of bytes to copy from. * @param i The index of the first byte of the color. * @return The 48-bit color at index <code>i</code>. */ public static java.awt.Color getColor48LE(byte[] data, int i) { return new java.awt.Color( (getShortLE(data, i+0) & 0xFFFF) / 65535.0f, (getShortLE(data, i+2) & 0xFFFF) / 65535.0f, (getShortLE(data, i+4) & 0xFFFF) / 65535.0f ); } /** * Gets a 64-bit color out of an array of bytes. * The alpha short comes first, then red, then green, then blue. * All shorts are little-endian. * @param data The array of bytes to copy from. * @param i The index of the first byte of the color. * @return The 64-bit color at index <code>i</code>. */ public static java.awt.Color getColor64LE(byte[] data, int i) { return new java.awt.Color( (getShortLE(data, i+2) & 0xFFFF) / 65535.0f, (getShortLE(data, i+4) & 0xFFFF) / 65535.0f, (getShortLE(data, i+6) & 0xFFFF) / 65535.0f, (getShortLE(data, i+0) & 0xFFFF) / 65535.0f ); } /** * Gets an 8-bit integer out of an array of bytes. * @param data The array of bytes to copy from. * @param i The index of the first byte of the integer. * @param le True if the value is little-endian, false if the value is big-endian. * @return The 8-bit integer at index <code>i</code>. */ public static byte getByte(byte[] data, int i, boolean le) { return le ? getByteLE(data, i) : getByte(data, i); } /** * Gets a 16-bit integer out of an array of bytes. * @param data The array of bytes to copy from. * @param i The index of the first byte of the integer. * @param le True if the value is little-endian, false if the value is big-endian. * @return The 16-bit integer at index <code>i</code>. */ public static short getShort(byte[] data, int i, boolean le) { return le ? getShortLE(data, i) : getShort(data, i); } /** * Gets a 32-bit integer out of an array of bytes. * @param data The array of bytes to copy from. * @param i The index of the first byte of the integer. * @param le True if the value is little-endian, false if the value is big-endian. * @return The 32-bit integer at index <code>i</code>. */ public static int getInt(byte[] data, int i, boolean le) { return le ? getIntLE(data, i) : getInt(data, i); } /** * Gets a 48-bit integer out of an array of bytes. * @param data The array of bytes to copy from. * @param i The index of the first byte of the integer. * @param le True if the value is little-endian, false if the value is big-endian. * @return The 48-bit integer at index <code>i</code>. */ public static long getUInt48(byte[] data, int i, boolean le) { return le ? getUInt48LE(data, i) : getUInt48(data, i); } /** * Gets a 64-bit integer out of an array of bytes. * @param data The array of bytes to copy from. * @param i The index of the first byte of the integer. * @param le True if the value is little-endian, false if the value is big-endian. * @return The 64-bit integer at index <code>i</code>. */ public static long getLong(byte[] data, int i, boolean le) { return le ? getLongLE(data, i) : getLong(data, i); } /** * Gets a 32-bit fixed-point number out of an array of bytes. * The radix point is fixed at the center, right between the middle two bytes. * @param data The array of bytes to copy from. * @param i The index of the first byte of the fixed-point number. * @param le True if the value is little-endian, false if the value is big-endian. * @return The fixed-point number at index <code>i</code>. */ public static double getFixed(byte[] data, int i, boolean le) { return le ? getFixedLE(data, i) : getFixed(data, i); } /** * Gets an IEEE single-precision floating point number out of an array of bytes. * @param data The array of bytes to copy from. * @param i The index of the first byte of the float. * @param le True if the value is little-endian, false if the value is big-endian. * @return The float at index <code>i</code>. */ public static float getFloat(byte[] data, int i, boolean le) { return le ? getFloatLE(data, i) : getFloat(data, i); } /** * Gets an IEEE double-precision floating point number out of an array of bytes. * @param data The array of bytes to copy from. * @param i The index of the first byte of the double. * @param le True if the value is little-endian, false if the value is big-endian. * @return The double at index <code>i</code>. */ public static double getDouble(byte[] data, int i, boolean le) { return le ? getDoubleLE(data, i) : getDouble(data, i); } /** * Gets a point out of an array of bytes. * A point is defined by two 16-bit integers, * the first representing the Y coordinate and the second * representing the X coordinate. * @param data The array of bytes to copy from. * @param i The index of the first byte of the point. * @param le True if the value is little-endian, false if the value is big-endian. * @return The point at index <code>i</code>. */ public static java.awt.Point getPoint(byte[] data, int i, boolean le) { return le ? getPointLE(data, i) : getPoint(data, i); } /** * Gets a rectangle out of an array of bytes. * A rectangle is defined by four 16-bit integers, * representing the top, left, bottom, and right. * @param data The array of bytes to copy from. * @param i The index of the first byte of the rectangle. * @param le True if the value is little-endian, false if the value is big-endian. * @return The rectangle at index <code>i</code>. */ public static java.awt.Rectangle getRect(byte[] data, int i, boolean le) { return le ? getRectLE(data, i) : getRect(data, i); } /** * Gets a 24-bit color out of an array of bytes. * The red byte comes first, then green, then blue. * @param data The array of bytes to copy from. * @param i The index of the first byte of the color. * @param le True if the value is little-endian, false if the value is big-endian. * @return The 24-bit color at index <code>i</code>. */ public static java.awt.Color getColor24(byte[] data, int i, boolean le) { return le ? getColor24LE(data, i) : getColor24(data, i); } /** * Gets a 32-bit color out of an array of bytes. * The alpha byte comes first, then red, then green, then blue. * @param data The array of bytes to copy from. * @param i The index of the first byte of the color. * @param le True if the value is little-endian, false if the value is big-endian. * @return The 32-bit color at index <code>i</code>. */ public static java.awt.Color getColor32(byte[] data, int i, boolean le) { return le ? getColor32LE(data, i) : getColor32(data, i); } /** * Gets a 48-bit color out of an array of bytes. * The red short comes first, then green, then blue. * All shorts are big-endian. * @param data The array of bytes to copy from. * @param i The index of the first byte of the color. * @param le True if the value is little-endian, false if the value is big-endian. * @return The 48-bit color at index <code>i</code>. */ public static java.awt.Color getColor48(byte[] data, int i, boolean le) { return le ? getColor48LE(data, i) : getColor48(data, i); } /** * Gets a 64-bit color out of an array of bytes. * The alpha short comes first, then red, then green, then blue. * All shorts are big-endian. * @param data The array of bytes to copy from. * @param i The index of the first byte of the color. * @param le True if the value is little-endian, false if the value is big-endian. * @return The 64-bit color at index <code>i</code>. */ public static java.awt.Color getColor64(byte[] data, int i, boolean le) { return le ? getColor64LE(data, i) : getColor64(data, i); } /** * Gets a Pascal string out of an array of bytes using the default text encoding. * @param data The array of bytes to copy from. * @param i The index of the first byte of the Pascal string, the length byte. * @return The Pascal string at index <code>i</code>. */ public static String getPString(byte[] data, int i) { return new String(data, i+1, data[i] & 0xFF); } /** * Gets a Pascal string out of an array of bytes using the specified text encoding. * @param data The array of bytes to copy from. * @param i The index of the first byte of the Pascal string, the length byte. * @param encoding The name of the text encoding to use. * @return The Pascal string at index <code>i</code>. * @throws UnsupportedEncodingException */ public static String getPString(byte[] data, int i, String encoding) throws UnsupportedEncodingException { return new String(data, i+1, data[i] & 0xFF, encoding); } /** * Gets a C string out of an array of bytes using the default text encoding. * @param data The array of bytes to copy from. * @param i The index of the first byte of the C string. * @return The C string at index <code>i</code>. */ public static String getCString(byte[] data, int i) { int j = i; while (j < data.length && data[j] != 0) j++; return new String(data, i, j-i); } /** * Gets a C string out of an array of bytes using the specified text encoding. * @param data The array of bytes to copy from. * @param i The index of the first byte of the C string. * @param encoding The name of the text encoding to use. * @return The C string at index <code>i</code>. * @throws UnsupportedEncodingException */ public static String getCString(byte[] data, int i, String encoding) throws UnsupportedEncodingException { int j = i; while (j < data.length && data[j] != 0) j++; return new String(data, i, j-i, encoding); } /** * Puts an 8-bit big-endian integer into an array of bytes. * @param data The array of bytes to insert into. * @param i The index of the first byte of the integer. * @param v The 8-bit big-endian integer at index <code>i</code>. */ public static void putByte(byte[] data, int i, byte v) { data[i+0] = v; } /** * Puts a 16-bit big-endian integer into an array of bytes. * @param data The array of bytes to insert into. * @param i The index of the first byte of the integer. * @param v The 16-bit big-endian integer at index <code>i</code>. */ public static void putShort(byte[] data, int i, short v) { data[i+0] = (byte)((v >>> 8) & 0xFF); data[i+1] = (byte)((v >>> 0) & 0xFF); } /** * Puts a 32-bit big-endian integer into an array of bytes. * @param data The array of bytes to insert into. * @param i The index of the first byte of the integer. * @param v The 32-bit big-endian integer at index <code>i</code>. */ public static void putInt(byte[] data, int i, int v) { data[i+0] = (byte)((v >>> 24) & 0xFF); data[i+1] = (byte)((v >>> 16) & 0xFF); data[i+2] = (byte)((v >>> 8) & 0xFF); data[i+3] = (byte)((v >>> 0) & 0xFF); } /** * Puts a 48-bit big-endian integer into an array of bytes. * @param data The array of bytes to insert into. * @param i The index of the first byte of the integer. * @param v The 48-bit big-endian integer at index <code>i</code>. */ public static void putUInt48(byte[] data, int i, long v) { data[i+0] = (byte)((v >>> 40l) & 0xFFl); data[i+1] = (byte)((v >>> 32l) & 0xFFl); data[i+2] = (byte)((v >>> 24l) & 0xFFl); data[i+3] = (byte)((v >>> 16l) & 0xFFl); data[i+4] = (byte)((v >>> 8l) & 0xFFl); data[i+5] = (byte)((v >>> 0l) & 0xFFl); } /** * Puts a 64-bit big-endian integer into an array of bytes. * @param data The array of bytes to insert into. * @param i The index of the first byte of the integer. * @param v The 64-bit big-endian integer at index <code>i</code>. */ public static void putLong(byte[] data, int i, long v) { data[i+0] = (byte)((v >>> 56l) & 0xFFl); data[i+1] = (byte)((v >>> 48l) & 0xFFl); data[i+2] = (byte)((v >>> 40l) & 0xFFl); data[i+3] = (byte)((v >>> 32l) & 0xFFl); data[i+4] = (byte)((v >>> 24l) & 0xFFl); data[i+5] = (byte)((v >>> 16l) & 0xFFl); data[i+6] = (byte)((v >>> 8l) & 0xFFl); data[i+7] = (byte)((v >>> 0l) & 0xFFl); } /** * Puts a 32-bit big-endian fixed-point number into an array of bytes. * The radix point is fixed at the center, right between the middle two bytes. * @param data The array of bytes to insert into. * @param i The index of the first byte of the fixed-point number. * @param v The fixed-point number at index <code>i</code>. */ public static void putFixed(byte[] data, int i, double v) { putInt(data, i, (int)(v * 65536.0)); } /** * Puts an IEEE single-precision floating point number into an array of bytes. * @param data The array of bytes to insert into. * @param i The index of the first byte of the float. * @param v The float at index <code>i</code>. */ public static void putFloat(byte[] data, int i, float v) { putInt(data, i, Float.floatToRawIntBits(v)); } /** * Puts an IEEE double-precision floating point number into an array of bytes. * @param data The array of bytes to insert into. * @param i The index of the first byte of the double. * @param v The double at index <code>i</code>. */ public static void putDouble(byte[] data, int i, double v) { putLong(data, i, Double.doubleToRawLongBits(v)); } /** * Puts a point into an array of bytes. * A point is defined by two 16-bit big-endian integers, * the first representing the Y coordinate and the second * representing the X coordinate. * @param data The array of bytes to insert into. * @param i The index of the first byte of the point. * @param v The point at index <code>i</code>. */ public static void putPoint(byte[] data, int i, java.awt.Point v) { putShort(data, i+2, (short)v.x); putShort(data, i+0, (short)v.y); } /** * Puts a rectangle into an array of bytes. * A rectangle is defined by four 16-bit big-endian integers, * representing the top, left, bottom, and right. * @param data The array of bytes to insert into. * @param i The index of the first byte of the rectangle. * @param v The rectangle at index <code>i</code>. */ public static void putRect(byte[] data, int i, java.awt.Rectangle v) { putShort(data, i+2, (short)v.x); putShort(data, i+0, (short)v.y); putShort(data, i+6, (short)(v.x+v.width)); putShort(data, i+4, (short)(v.y+v.height)); } /** * Puts a 24-bit color into an array of bytes. * The red byte comes first, then green, then blue. * @param data The array of bytes to insert into. * @param i The index of the first byte of the color. * @param v The 24-bit color at index <code>i</code>. */ public static void putColor24(byte[] data, int i, java.awt.Color v) { putByte(data, i+0, (byte)v.getRed()); putByte(data, i+1, (byte)v.getGreen()); putByte(data, i+2, (byte)v.getBlue()); } /** * Puts a 32-bit color into an array of bytes. * The alpha byte comes first, then red, then green, then blue. * @param data The array of bytes to insert into. * @param i The index of the first byte of the color. * @param v The 32-bit color at index <code>i</code>. */ public static void putColor32(byte[] data, int i, java.awt.Color v) { putByte(data, i+1, (byte)v.getRed()); putByte(data, i+2, (byte)v.getGreen()); putByte(data, i+3, (byte)v.getBlue()); putByte(data, i+0, (byte)v.getAlpha()); } /** * Puts a 48-bit color into an array of bytes. * The red short comes first, then green, then blue. * All shorts are big-endian. * @param data The array of bytes to insert into. * @param i The index of the first byte of the color. * @param v The 48-bit color at index <code>i</code>. */ public static void putColor48(byte[] data, int i, java.awt.Color v) { float[] rgb = v.getRGBComponents(null); putShort(data, i+0, (short)Math.round(rgb[0] * 65535.0f)); putShort(data, i+2, (short)Math.round(rgb[1] * 65535.0f)); putShort(data, i+4, (short)Math.round(rgb[2] * 65535.0f)); } /** * Puts a 64-bit color into an array of bytes. * The alpha short comes first, then red, then green, then blue. * All shorts are big-endian. * @param data The array of bytes to insert into. * @param i The index of the first byte of the color. * @param v The 64-bit color at index <code>i</code>. */ public static void putColor64(byte[] data, int i, java.awt.Color v) { float[] rgb = v.getRGBComponents(null); putShort(data, i+2, (short)Math.round(rgb[0] * 65535.0f)); putShort(data, i+4, (short)Math.round(rgb[1] * 65535.0f)); putShort(data, i+6, (short)Math.round(rgb[2] * 65535.0f)); putShort(data, i+0, (short)Math.round(rgb[3] * 65535.0f)); } /** * Puts an 8-bit little-endian integer into an array of bytes. * @param data The array of bytes to insert into. * @param i The index of the first byte of the integer. * @param v The 8-bit little-endian integer at index <code>i</code>. */ public static void putByteLE(byte[] data, int i, byte v) { data[i+0] = v; } /** * Puts a 16-bit little-endian integer into an array of bytes. * @param data The array of bytes to insert into. * @param i The index of the first byte of the integer. * @param v The 16-bit little-endian integer at index <code>i</code>. */ public static void putShortLE(byte[] data, int i, short v) { data[i+0] = (byte)((v >>> 0) & 0xFF); data[i+1] = (byte)((v >>> 8) & 0xFF); } /** * Puts a 32-bit little-endian integer into an array of bytes. * @param data The array of bytes to insert into. * @param i The index of the first byte of the integer. * @param v The 32-bit little-endian integer at index <code>i</code>. */ public static void putIntLE(byte[] data, int i, int v) { data[i+0] = (byte)((v >>> 0) & 0xFF); data[i+1] = (byte)((v >>> 8) & 0xFF); data[i+2] = (byte)((v >>> 16) & 0xFF); data[i+3] = (byte)((v >>> 24) & 0xFF); } /** * Puts a 48-bit little-endian integer into an array of bytes. * @param data The array of bytes to insert into. * @param i The index of the first byte of the integer. * @param v The 48-bit little-endian integer at index <code>i</code>. */ public static void putUInt48LE(byte[] data, int i, long v) { data[i+0] = (byte)((v >>> 0l) & 0xFFl); data[i+1] = (byte)((v >>> 8l) & 0xFFl); data[i+2] = (byte)((v >>> 16l) & 0xFFl); data[i+3] = (byte)((v >>> 24l) & 0xFFl); data[i+4] = (byte)((v >>> 32l) & 0xFFl); data[i+5] = (byte)((v >>> 40l) & 0xFFl); } /** * Puts a 64-bit little-endian integer into an array of bytes. * @param data The array of bytes to insert into. * @param i The index of the first byte of the integer. * @param v The 64-bit little-endian integer at index <code>i</code>. */ public static void putLongLE(byte[] data, int i, long v) { data[i+0] = (byte)((v >>> 0l) & 0xFFl); data[i+1] = (byte)((v >>> 8l) & 0xFFl); data[i+2] = (byte)((v >>> 16l) & 0xFFl); data[i+3] = (byte)((v >>> 24l) & 0xFFl); data[i+4] = (byte)((v >>> 32l) & 0xFFl); data[i+5] = (byte)((v >>> 40l) & 0xFFl); data[i+6] = (byte)((v >>> 48l) & 0xFFl); data[i+7] = (byte)((v >>> 56l) & 0xFFl); } /** * Puts a 32-bit little-endian fixed-point number into an array of bytes. * The radix point is fixed at the center, right between the middle two bytes. * @param data The array of bytes to insert into. * @param i The index of the first byte of the fixed-point number. * @param v The fixed-point number at index <code>i</code>. */ public static void putFixedLE(byte[] data, int i, double v) { putIntLE(data, i, (int)(v * 65536.0)); } /** * Puts an IEEE single-precision floating point number into an array of bytes. * @param data The array of bytes to insert into. * @param i The index of the first byte of the float. * @param v The float at index <code>i</code>. */ public static void putFloatLE(byte[] data, int i, float v) { putIntLE(data, i, Float.floatToRawIntBits(v)); } /** * Puts an IEEE double-precision floating point number into an array of bytes. * @param data The array of bytes to insert into. * @param i The index of the first byte of the double. * @param v The double at index <code>i</code>. */ public static void putDoubleLE(byte[] data, int i, double v) { putLongLE(data, i, Double.doubleToRawLongBits(v)); } /** * Puts a point into an array of bytes. * A point is defined by two 16-bit little-endian integers, * the first representing the Y coordinate and the second * representing the X coordinate. * @param data The array of bytes to insert into. * @param i The index of the first byte of the point. * @param v The point at index <code>i</code>. */ public static void putPointLE(byte[] data, int i, java.awt.Point v) { putShortLE(data, i+2, (short)v.x); putShortLE(data, i+0, (short)v.y); } /** * Puts a rectangle into an array of bytes. * A rectangle is defined by four 16-bit little-endian integers, * representing the top, left, bottom, and right. * @param data The array of bytes to insert into. * @param i The index of the first byte of the rectangle. * @param v The rectangle at index <code>i</code>. */ public static void putRectLE(byte[] data, int i, java.awt.Rectangle v) { putShortLE(data, i+2, (short)v.x); putShortLE(data, i+0, (short)v.y); putShortLE(data, i+6, (short)(v.x+v.width)); putShortLE(data, i+4, (short)(v.y+v.height)); } /** * Puts a 24-bit color into an array of bytes. * The red byte comes first, then green, then blue. * @param data The array of bytes to insert into. * @param i The index of the first byte of the color. * @param v The 24-bit color at index <code>i</code>. */ public static void putColor24LE(byte[] data, int i, java.awt.Color v) { putByteLE(data, i+0, (byte)v.getRed()); putByteLE(data, i+1, (byte)v.getGreen()); putByteLE(data, i+2, (byte)v.getBlue()); } /** * Puts a 32-bit color into an array of bytes. * The alpha byte comes first, then red, then green, then blue. * @param data The array of bytes to insert into. * @param i The index of the first byte of the color. * @param v The 32-bit color at index <code>i</code>. */ public static void putColor32LE(byte[] data, int i, java.awt.Color v) { putByteLE(data, i+1, (byte)v.getRed()); putByteLE(data, i+2, (byte)v.getGreen()); putByteLE(data, i+3, (byte)v.getBlue()); putByteLE(data, i+0, (byte)v.getAlpha()); } /** * Puts a 48-bit color into an array of bytes. * The red short comes first, then green, then blue. * All shorts are little-endian. * @param data The array of bytes to insert into. * @param i The index of the first byte of the color. * @param v The 48-bit color at index <code>i</code>. */ public static void putColor48LE(byte[] data, int i, java.awt.Color v) { float[] rgb = v.getRGBComponents(null); putShortLE(data, i+0, (short)Math.round(rgb[0] * 65535.0f)); putShortLE(data, i+2, (short)Math.round(rgb[1] * 65535.0f)); putShortLE(data, i+4, (short)Math.round(rgb[2] * 65535.0f)); } /** * Puts a 64-bit color into an array of bytes. * The alpha short comes first, then red, then green, then blue. * All shorts are little-endian. * @param data The array of bytes to insert into. * @param i The index of the first byte of the color. * @param v The 64-bit color at index <code>i</code>. */ public static void putColor64LE(byte[] data, int i, java.awt.Color v) { float[] rgb = v.getRGBComponents(null); putShortLE(data, i+2, (short)Math.round(rgb[0] * 65535.0f)); putShortLE(data, i+4, (short)Math.round(rgb[1] * 65535.0f)); putShortLE(data, i+6, (short)Math.round(rgb[2] * 65535.0f)); putShortLE(data, i+0, (short)Math.round(rgb[3] * 65535.0f)); } /** * Puts an 8-bit big-endian integer into an array of bytes. * @param data The array of bytes to insert into. * @param i The index of the first byte of the integer. * @param le True if the value is little-endian, false if the value is big-endian. * @param v The 8-bit big-endian integer at index <code>i</code>. */ public static void putByte(byte[] data, int i, boolean le, byte v) { if (le) putByteLE(data, i, v); else putByte(data, i, v); } /** * Puts a 16-bit big-endian integer into an array of bytes. * @param data The array of bytes to insert into. * @param i The index of the first byte of the integer. * @param le True if the value is little-endian, false if the value is big-endian. * @param v The 16-bit big-endian integer at index <code>i</code>. */ public static void putShort(byte[] data, int i, boolean le, short v) { if (le) putShortLE(data, i, v); else putShort(data, i, v); } /** * Puts a 32-bit big-endian integer into an array of bytes. * @param data The array of bytes to insert into. * @param i The index of the first byte of the integer. * @param le True if the value is little-endian, false if the value is big-endian. * @param v The 32-bit big-endian integer at index <code>i</code>. */ public static void putInt(byte[] data, int i, boolean le, int v) { if (le) putIntLE(data, i, v); else putInt(data, i, v); } /** * Puts a 48-bit big-endian integer into an array of bytes. * @param data The array of bytes to insert into. * @param i The index of the first byte of the integer. * @param le True if the value is little-endian, false if the value is big-endian. * @param v The 48-bit big-endian integer at index <code>i</code>. */ public static void putUInt48(byte[] data, int i, boolean le, long v) { if (le) putUInt48LE(data, i, v); else putUInt48(data, i, v); } /** * Puts a 64-bit big-endian integer into an array of bytes. * @param data The array of bytes to insert into. * @param i The index of the first byte of the integer. * @param le True if the value is little-endian, false if the value is big-endian. * @param v The 64-bit big-endian integer at index <code>i</code>. */ public static void putLong(byte[] data, int i, boolean le, long v) { if (le) putLongLE(data, i, v); else putLong(data, i, v); } /** * Puts a 32-bit big-endian fixed-point number into an array of bytes. * The radix point is fixed at the center, right between the middle two bytes. * @param data The array of bytes to insert into. * @param i The index of the first byte of the fixed-point number. * @param le True if the value is little-endian, false if the value is big-endian. * @param v The fixed-point number at index <code>i</code>. */ public static void putFixed(byte[] data, int i, boolean le, double v) { if (le) putFixedLE(data, i, v); else putFixed(data, i, v); } /** * Puts an IEEE single-precision floating point number into an array of bytes. * @param data The array of bytes to insert into. * @param i The index of the first byte of the float. * @param le True if the value is little-endian, false if the value is big-endian. * @param v The float at index <code>i</code>. */ public static void putFloat(byte[] data, int i, boolean le, float v) { if (le) putFloatLE(data, i, v); else putFloat(data, i, v); } /** * Puts an IEEE double-precision floating point number into an array of bytes. * @param data The array of bytes to insert into. * @param i The index of the first byte of the double. * @param le True if the value is little-endian, false if the value is big-endian. * @param v The double at index <code>i</code>. */ public static void putDouble(byte[] data, int i, boolean le, double v) { if (le) putDoubleLE(data, i, v); else putDouble(data, i, v); } /** * Puts a point into an array of bytes. * A point is defined by two 16-bit big-endian integers, * the first representing the Y coordinate and the second * representing the X coordinate. * @param data The array of bytes to insert into. * @param i The index of the first byte of the point. * @param le True if the value is little-endian, false if the value is big-endian. * @param v The point at index <code>i</code>. */ public static void putPoint(byte[] data, int i, boolean le, java.awt.Point v) { if (le) putPointLE(data, i, v); else putPoint(data, i, v); } /** * Puts a rectangle into an array of bytes. * A rectangle is defined by four 16-bit big-endian integers, * representing the top, left, bottom, and right. * @param data The array of bytes to insert into. * @param i The index of the first byte of the rectangle. * @param le True if the value is little-endian, false if the value is big-endian. * @param v The rectangle at index <code>i</code>. */ public static void putRect(byte[] data, int i, boolean le, java.awt.Rectangle v) { if (le) putRectLE(data, i, v); else putRect(data, i, v); } /** * Puts a 24-bit color into an array of bytes. * The red byte comes first, then green, then blue. * @param data The array of bytes to insert into. * @param i The index of the first byte of the color. * @param le True if the value is little-endian, false if the value is big-endian. * @param v The 24-bit color at index <code>i</code>. */ public static void putColor24(byte[] data, int i, boolean le, java.awt.Color v) { if (le) putColor24LE(data, i, v); else putColor24(data, i, v); } /** * Puts a 32-bit color into an array of bytes. * The alpha byte comes first, then red, then green, then blue. * @param data The array of bytes to insert into. * @param i The index of the first byte of the color. * @param le True if the value is little-endian, false if the value is big-endian. * @param v The 32-bit color at index <code>i</code>. */ public static void putColor32(byte[] data, int i, boolean le, java.awt.Color v) { if (le) putColor32LE(data, i, v); else putColor32(data, i, v); } /** * Puts a 48-bit color into an array of bytes. * The red short comes first, then green, then blue. * All shorts are big-endian. * @param data The array of bytes to insert into. * @param i The index of the first byte of the color. * @param le True if the value is little-endian, false if the value is big-endian. * @param v The 48-bit color at index <code>i</code>. */ public static void putColor48(byte[] data, int i, boolean le, java.awt.Color v) { if (le) putColor48LE(data, i, v); else putColor48(data, i, v); } /** * Puts a 64-bit color into an array of bytes. * The alpha short comes first, then red, then green, then blue. * All shorts are big-endian. * @param data The array of bytes to insert into. * @param i The index of the first byte of the color. * @param le True if the value is little-endian, false if the value is big-endian. * @param v The 64-bit color at index <code>i</code>. */ public static void putColor64(byte[] data, int i, boolean le, java.awt.Color v) { if (le) putColor64LE(data, i, v); else putColor64(data, i, v); } /** * Creates a duplicate of an array of bytes. * If <code>data</code> is <code>null</code>, * this returns a new <code>byte[]</code> with * no elements. * @param data The array of bytes to copy. * @return A copy of <code>data</code>. */ public static byte[] copy(byte[] data) { if (data == null) return new byte[0]; byte[] dd = new byte[data.length]; for (int i = 0; i < data.length; i++) dd[i] = data[i]; return dd; } /** * Creates a duplicate of part of an array of bytes. * @param data The array of bytes to copy from. * @param off The index of the first byte to copy. * @param len The number of bytes to copy. * @return A copy of elements <code>off</code> to <code>off+len-1</code> of <code>data</code>. */ public static byte[] copy(byte[] data, int off, int len) { byte[] dd = new byte[len]; for (int si = off, di = 0; si < data.length && di < dd.length; si++, di++) dd[di] = data[si]; return dd; } /** * Creates a duplicate of an array of bytes with part of the array removed. * @param data The array of bytes to copy from. * @param off The index of the first byte to remove. * @param len The number of bytes to remove. * @return A copy of elements <code>0</code> to <code>off-1</code> and <code>off+len</code> to <code>data.length-1</code> of <code>data</code>. */ public static byte[] cut(byte[] data, int off, int len) { byte[] dd = new byte[data.length - len]; for (int si = 0, di = 0; si < off && di < off && si < data.length && di < dd.length; si++, di++) dd[di] = data[si]; for (int si = off+len, di = off; si < data.length && di < dd.length; si++, di++) dd[di] = data[si]; return dd; } /** * Creates a duplicate of an array of bytes with additional bytes inserted. * @param data The array of bytes to copy from. * @param off The index where additional bytes will be inserted. * @param pasted The additional bytes to insert. * @return A copy of elements <code>0</code> to <code>off-1</code> of <code>data</code>, elements <code>0</code> to <code>pasted.length-1</code> of <code>pasted</code>, and elements <code>off</code> to <code>data.length-1</code> of <code>data</code>. */ public static byte[] paste(byte[] data, int off, byte[] pasted) { byte[] dd = new byte[data.length + pasted.length]; for (int si = 0, di = 0; si < off && di < off && si < data.length && di < dd.length; si++, di++) dd[di] = data[si]; for (int si = 0, di = off; si < pasted.length && di < dd.length; si++, di++) dd[di] = pasted[si]; for (int si = off, di = off+pasted.length; si < data.length && di < dd.length; si++, di++) dd[di] = data[si]; return dd; } /** * Creates a duplicate of an array of bytes with additional bytes inserted. * @param data The array of bytes to copy from. * @param off The index where additional bytes will be inserted. * @param pasted The number of additional bytes to insert. * @return A copy of elements <code>0</code> to <code>off-1</code> of <code>data</code> and elements <code>off</code> to <code>data.length-1</code> of <code>data</code>. */ public static byte[] paste(byte[] data, int off, int pasted) { byte[] dd = new byte[data.length + pasted]; for (int si = 0, di = 0; si < off && di < off && si < data.length && di < dd.length; si++, di++) dd[di] = data[si]; for (int si = off, di = off+pasted; si < data.length && di < dd.length; si++, di++) dd[di] = data[si]; return dd; } /** * Creates a duplicate of an array of bytes with a certain size. * @param data The array of bytes to copy from. * @param len The length of the resulting array. * @return A copy of elements <code>0</code> to <code>Math.min(len, data.length)-1</code> of <code>data</code>. */ public static byte[] resize(byte[] data, int len) { byte[] dd = new byte[len]; for (int si = 0, di = 0; si < data.length && di < dd.length; si++, di++) dd[di] = data[si]; return dd; } /** * Cuts a segment of data out of a random-access file. * The two parts of the file before and after the cut * are joined together. For instance, if your file is * <br><br> * <code>05 23 75 A8 FF 2E 09 DB 3C 01 A9 99 80</code> * <br><br> * then <code>fileCut(f, 4, 3)</code> will return * <br><br> * <code>FF 2E 09</code> * <br><br> * and the new contents of the file will be * <br><br> * <code>05 23 75 A8 DB 3C 01 A9 99 80</code> * <br><br> * Precondition: <code>offset</code> is between zero and the length of the file, inclusive. * Other values may give unexpected results. * @param f a <code>RandomAccessFile</code>. * @param offset the offset of the first byte of the cut. * @param bytesToCut the number of bytes to cut. * @return an array containing the cut bytes. * @throws IOException if an I/O error occurs during the cut process. */ public static byte[] cut(RandomAccessFile f, long offset, int bytesToCut) throws IOException { if (bytesToCut <= 0) return new byte[0]; byte[] stuff = new byte[bytesToCut]; f.seek(offset); f.read(stuff); long l = f.length(); byte[] junk = new byte[1048576]; for (long s = offset+bytesToCut, d = offset; s < l; d += 1048576, s += 1048576) { f.seek(s); f.read(junk); f.seek(d); f.write(junk); } f.setLength(Math.max(l-bytesToCut,offset)); return stuff; } /** * Cuts a segment of data out of a random-access file. * The two parts of the file before and after the cut * are joined together. For instance, if your file is * <br><br> * <code>05 23 75 A8 FF 2E 09 DB 3C 01 A9 99 80</code> * <br><br> * then <code>fileCut(f, 4L, 3L)</code> will return 3L * and the new contents of the file will be * <br><br> * <code>05 23 75 A8 DB 3C 01 A9 99 80</code> * <br><br> * Precondition: <code>offset</code> is between zero and the length of the file, inclusive. * Other values may give unexpected results. * @param f a <code>RandomAccessFile</code>. * @param offset the offset of the first byte of the cut. * @param bytesToCut the number of bytes to cut. * @return the number of bytes cut. * @throws IOException if an I/O error occurs during the cut process. */ public static long cut(RandomAccessFile f, long offset, long bytesToCut) throws IOException { if (bytesToCut <= 0l) return 0l; long l = f.length(); byte[] junk = new byte[1048576]; for (long s = offset+bytesToCut, d = offset; s < l; d += 1048576, s += 1048576) { f.seek(s); f.read(junk); f.seek(d); f.write(junk); } f.setLength(Math.max(l-bytesToCut,offset)); return Math.min(l-offset, bytesToCut); } /** * Copies a segment of data from a random-access file. * The file itself is not affected. For instance, if your file is * <br><br> * <code>05 23 75 A8 FF 2E 09 DB 3C 01 A9 99 80</code> * <br><br> * then <code>fileCopy(f, 4, 3)</code> will return * <br><br> * <code>FF 2E 09</code> * <br><br> * and the contents of the file will not change. * <br><br> * Precondition: <code>offset</code> is between zero and the length of the file, inclusive. * Other values may give unexpected results. * @param f a <code>RandomAccessFile</code>. * @param offset the offset of the first byte to copy. * @param bytesToCopy the number of bytes to copy. * @return an array containing the copied bytes. * @throws IOException if an I/O error occurs during the copy process. */ public static byte[] copy(RandomAccessFile f, long offset, int bytesToCopy) throws IOException { if (bytesToCopy <= 0) return new byte[0]; byte[] stuff = new byte[bytesToCopy]; f.seek(offset); f.read(stuff); return stuff; } /** * Pastes a segment of zero bytes into a random-access file. * The bytes after the specified offset will be moved to * later in the file. For instance, if your file is * <br><br> * <code>05 23 75 A8 FF 2E 09 DB 3C 01 A9 99 80</code> * <br><br> * then <code>filePaste(f, 4, 3)</code> will return * <br><br> * <code>00 00 00</code> * <br><br> * and the new contents of the file will be * <br><br> * <code>05 23 75 A8 00 00 00 FF 2E 09 DB 3C 01 A9 99 80</code> * <br><br> * Precondition: <code>offset</code> is between zero and the length of the file, inclusive. * Other values may give unexpected results. * @param f a <code>RandomAccessFile</code>. * @param offset the offset where the first byte of pasted data should be written. * @param bytesToPaste the number of zero bytes to paste. * @return an array containing the pasted bytes. * @throws IOException if an I/O error occurs during the paste process. */ public static byte[] paste(RandomAccessFile f, long offset, int bytesToPaste) throws IOException { if (bytesToPaste <= 0) return new byte[0]; byte[] stuff = new byte[bytesToPaste]; long l = f.length(); long btm = (l-offset-1) & (~0xFFFFFl); byte[] junk = new byte[1048576]; for (long s = offset+btm, d = offset+btm+bytesToPaste; s >= offset; d -= 1048576, s -= 1048576) { f.seek(s); f.read(junk); f.seek(d); f.write(junk); } f.seek(offset); f.write(stuff); f.setLength(l+bytesToPaste); return stuff; } /** * Pastes a segment of zero bytes into a random-access file. * The bytes after the specified offset will be moved to * later in the file. For instance, if your file is * <br><br> * <code>05 23 75 A8 FF 2E 09 DB 3C 01 A9 99 80</code> * <br><br> * then <code>filePaste(f, 4L, 3L)</code> will return 3L * and the new contents of the file will be * <br><br> * <code>05 23 75 A8 00 00 00 FF 2E 09 DB 3C 01 A9 99 80</code> * <br><br> * Precondition: <code>offset</code> is between zero and the length of the file, inclusive. * Other values may give unexpected results. * @param f a <code>RandomAccessFile</code>. * @param offset the offset where the first byte of pasted data should be written. * @param bytesToPaste the number of zero bytes to paste. * @return the number of bytes pasted. * @throws IOException if an I/O error occurs during the paste process. */ public static long paste(RandomAccessFile f, long offset, long bytesToPaste) throws IOException { if (bytesToPaste <= 0) return 0; long l = f.length(); long btm = (l-offset-1) & (~0xFFFFFl); byte[] junk = new byte[1048576]; for (long s = offset+btm, d = offset+btm+bytesToPaste; s >= offset; d -= 1048576, s -= 1048576) { f.seek(s); f.read(junk); f.seek(d); f.write(junk); } f.seek(offset); long w = bytesToPaste; byte[] stuff = new byte[1048576]; while (w >= 1048576l) { f.write(stuff); w -= 1048576l; } if (w > 0) { stuff = new byte[(int)w]; f.write(stuff); } f.setLength(l+bytesToPaste); return bytesToPaste; } /** * Pastes a segment of data into a random-access file. * The bytes after the specified offset will be moved to * later in the file. For instance, if your file is * <br><br> * <code>05 23 75 A8 FF 2E 09 DB 3C 01 A9 99 80</code> * <br><br> * then <code>filePaste(f, 4, new byte[]{0x55, 0xEE, 0xB4})</code> will return * <br><br> * <code>55 EE B4</code> * <br><br> * and the new contents of the file will be * <br><br> * <code>05 23 75 A8 55 EE B4 FF 2E 09 DB 3C 01 A9 99 80</code> * <br><br> * Precondition: <code>offset</code> is between zero and the length of the file, inclusive. * Other values may give unexpected results. * @param f a <code>RandomAccessFile</code>. * @param offset the offset where the first byte of pasted data should be written. * @param stuff the data to paste. * @return an array containing the pasted bytes. * @throws IOException if an I/O error occurs during the paste process. */ public static byte[] paste(RandomAccessFile f, long offset, byte[] stuff) throws IOException { if (stuff.length <= 0) return new byte[0]; long l = f.length(); long btm = (l-offset-1) & (~0xFFFFFl); byte[] junk = new byte[1048576]; for (long s = offset+btm, d = offset+btm+stuff.length; s >= offset; d -= 1048576, s -= 1048576) { f.seek(s); f.read(junk); f.seek(d); f.write(junk); } f.seek(offset); f.write(stuff); f.setLength(l+stuff.length); return stuff; } private static final String[] LOOKUP_HEX = new String[] { "00","01","02","03","04","05","06","07","08","09","0A","0B","0C","0D","0E","0F", "10","11","12","13","14","15","16","17","18","19","1A","1B","1C","1D","1E","1F", "20","21","22","23","24","25","26","27","28","29","2A","2B","2C","2D","2E","2F", "30","31","32","33","34","35","36","37","38","39","3A","3B","3C","3D","3E","3F", "40","41","42","43","44","45","46","47","48","49","4A","4B","4C","4D","4E","4F", "50","51","52","53","54","55","56","57","58","59","5A","5B","5C","5D","5E","5F", "60","61","62","63","64","65","66","67","68","69","6A","6B","6C","6D","6E","6F", "70","71","72","73","74","75","76","77","78","79","7A","7B","7C","7D","7E","7F", "80","81","82","83","84","85","86","87","88","89","8A","8B","8C","8D","8E","8F", "90","91","92","93","94","95","96","97","98","99","9A","9B","9C","9D","9E","9F", "A0","A1","A2","A3","A4","A5","A6","A7","A8","A9","AA","AB","AC","AD","AE","AF", "B0","B1","B2","B3","B4","B5","B6","B7","B8","B9","BA","BB","BC","BD","BE","BF", "C0","C1","C2","C3","C4","C5","C6","C7","C8","C9","CA","CB","CC","CD","CE","CF", "D0","D1","D2","D3","D4","D5","D6","D7","D8","D9","DA","DB","DC","DD","DE","DF", "E0","E1","E2","E3","E4","E5","E6","E7","E8","E9","EA","EB","EC","ED","EE","EF", "F0","F1","F2","F3","F4","F5","F6","F7","F8","F9","FA","FB","FC","FD","FE","FF" }; public static void printHexDump(PrintStream out, byte[] data) { for (int a = 0; a < data.length; a += 16) { String h = "00000000" + Integer.toHexString(a).toUpperCase(); out.print(h.substring(h.length()-8)+": "); for (int b = a, c = 0; c < 16; b++, c++) { out.print((b < data.length) ? LOOKUP_HEX[data[b] & 0xFF] : " "); if ((b & 1) == 1) out.print(" "); } out.print(" "); for (int b = a, c = 0; b < data.length && c < 16; b++, c++) { if (data[b] >= 0x20 && data[b] < 0x7F) out.print((char)data[b]); else out.print("."); } out.println(); } } }