Util.java
// <editor-fold defaultstate="collapsed" desc="license">
/*
* Copyright (c) 2009, Karl H. Beckers
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of the <ORGANIZATION> nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
**/
// </editor-fold>
package net.jarre_de_the.griffin;
import java.math.BigInteger;
import java.nio.charset.Charset;
import net.jarre_de_the.griffin.exception.ValueTooLargeException;
import net.jarre_de_the.griffin.types.data.DWordData;
import net.jarre_de_the.griffin.types.field.AbstractField;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Various static utility methods.
*
* @todo implement the rest of the file types and writing them, too (special
* implementations of GFF files)
*
* @todo equals on files is semantically, now ... consider making that more
* strict and adding a method to normalize file objects (incl. recalculating
* offsets etc.)
* <p>
* @author charly4711
*/
public class Util {
private static final Logger LOGGER = LoggerFactory.getLogger(Util.class);
public static final Charset CHARSET_US_ASCII = Charset.forName("US-ASCII");
/**
* @see getNullTerminatedString(byte[], Charset) This version defaults to
* US-ASCII
*
* @param buf
* @return
*/
public static String getNullTerminatedString(byte[] buf) {
return getNullTerminatedString(buf, Util.CHARSET_US_ASCII);
}
/**
* Returns a String from a byte array that's supposed to be character data
* terminated by a zero-byte.(as e. g. in field labels)
* <p>
* @param buf The byte array with character data
* @param charSet character set to use
* @return A string that has all the bytes buf has up to the first zero-byte
* read into characters. (or null if buff is null)
*/
public static String getNullTerminatedString(byte[] buf, Charset charSet) {
if (buf != null) {
String l = new String(buf, charSet);
int pos = l.indexOf(0);
if (pos >= 0) {
return l.substring(0, pos);
} else {
return l;
}
} else {
return null;
}
}
/**
* Determines the number of bytes used for the type of number in question.
*
* @param clazz
* @return
*/
public static int getByteLength(Class<? extends Number> clazz) {
int length = 0;
if (null != clazz) {
if (BigInteger.class.isAssignableFrom(clazz)) {
length = Long.BYTES + 1;
} else if (Long.class.isAssignableFrom(clazz)) {
length = Long.BYTES;
} else if (Double.class.isAssignableFrom(clazz)) {
length = Double.BYTES;
} else if (Float.class.isAssignableFrom(clazz)) {
length = Float.BYTES;
} else if (Integer.class.isAssignableFrom(clazz)) {
length = Integer.BYTES;
} else if (Short.class.isAssignableFrom(clazz)) {
length = Short.BYTES;
} else if (Byte.class.isAssignableFrom(clazz)) {
// Byte
length = Byte.BYTES;
}
}
return length;
}
public static <T extends Number> int getUnsignedInt(T source) {
if (null != source) {
if (Float.class.isAssignableFrom(source.getClass())) {
return Float.floatToIntBits((Float) source);
} else if (Integer.class.isAssignableFrom(source.getClass())) {
Integer intSource = (Integer) source;
return intSource;
} else if (Short.class.isAssignableFrom(source.getClass())) {
int i = 0;
i |= ((Short) source);
return i;
} else if (Byte.class.isAssignableFrom(source.getClass())) {
int i = 0;
i |= ((Byte) source);
return i;
} else {
throw new ValueTooLargeException(4, 8);
}
} else {
return 0;
}
}
/**
* Converts a String into its binary DWordData representation.
*
* @param s
* @return
*/
public static int stringToBitField(String s) {
int result = 0;
if (null != s) {
if (s.length() > DWordData.LENGTH) {
throw new ValueTooLargeException(DWordData.LENGTH, s.length());
}
char[] cBuf = s.toCharArray();
for (int i = 24, n = cBuf.length - 1; n >= 0; n--, i -= 8) {
byte b = (byte) (cBuf[n] & 0xFF);
result |= (b << i);
}
}
return result;
}
/**
* Creates a byte array as used for a label from a String. Labels are always
* treated as 7-bit ASCII.
*
* @param labelString the String to convert
* @return a byte[] array of AbstractField.LABEL_LENGTH length
*/
public static byte[] stringToLabelArray(String labelString) {
byte[] result = new byte[AbstractField.LABEL_LENGTH];
if (null != labelString) {
byte[] stringToBytes = labelString.getBytes(Util.CHARSET_US_ASCII);
if (stringToBytes.length > AbstractField.LABEL_LENGTH) {
throw new ValueTooLargeException(AbstractField.LABEL_LENGTH,
stringToBytes.length);
}
System.arraycopy(stringToBytes, 0, result, 0, stringToBytes.length);
}
return result;
}
}