// // Util.java // /* VisAD system for interactive analysis and visualization of numerical data. Copyright (C) 1996 - 2017 Bill Hibbard, Curtis Rueden, Tom Rink, Dave Glowacki, Steve Emmerson, Tom Whittaker, Don Murray, and Tommy Jasmin. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ package visad.util; import java.awt.Color; import java.awt.Dimension; import java.awt.Point; import java.awt.Toolkit; import java.awt.Window; import java.awt.image.BufferedImage; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.PrintStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Calendar; import java.util.Enumeration; import java.util.Iterator; import java.util.Map; import java.util.Vector; import javax.imageio.IIOImage; import javax.imageio.ImageIO; import javax.imageio.ImageWriteParam; import javax.imageio.ImageWriter; import javax.media.j3d.Canvas3D; import javax.media.j3d.Group; import javax.media.j3d.Node; import javax.media.j3d.SceneGraphObject; import javax.media.j3d.VirtualUniverse; import javax.swing.JComboBox; import javax.swing.JFileChooser; import javax.swing.JTextField; import javax.swing.SwingUtilities; import javax.swing.filechooser.FileFilter; import ncsa.hdf.hdf5lib.H5; import visad.ConstantMap; import visad.Display; import visad.DisplayImpl; import visad.VisADException; import visad.data.bio.LociForm; import visad.data.mcidas.AreaForm; import visad.data.mcidas.MapForm; import com.sun.j3d.utils.universe.SimpleUniverse; import java.util.logging.Formatter; import java.util.logging.ConsoleHandler; import java.util.logging.Handler; import java.util.logging.Level; import java.util.logging.LogRecord; import java.util.logging.Logger; /** * A hodge-podge of general utility methods. */ public class Util { /** * Determine whether two numbers are roughly the same. * * @param a First number * @param b Second number * @param epsilon Absolute amount by which they can differ. * * @return <TT>true</TT> if they're approximately equal. */ public static boolean isApproximatelyEqual(float a, float b, float epsilon) { // deal with NaNs first if (Float.isNaN(a)) { return Float.isNaN(b); } else if (Float.isNaN(b)) { return false; } if (Float.isInfinite(a)) { if (Float.isInfinite(b)) { return ((a < 0.0 && b < 0.0) || (a > 0.0 && b > 0.0)); } return false; } else if (Float.isInfinite(b)) { return false; } if (Math.abs(a - b) < epsilon) { return true; } if (a == 0.0 || b == 0.0) { return false; } final float FLT_EPSILON = 1.192092896E-07F; return Math.abs(1 - a / b) < FLT_EPSILON; } /** * Determine whether two numbers are roughly the same. * * @param a First number * @param b Second number * * @return <TT>true</TT> if they're approximately equal. */ public static boolean isApproximatelyEqual(float a, float b) { return isApproximatelyEqual(a, b, 0.00001); } /** * Determine whether two numbers are roughly the same. * * @param a First number * @param b Second number * @param epsilon Absolute amount by which they can differ. * * @return <TT>true</TT> if they're approximately equal. */ public static boolean isApproximatelyEqual(double a, double b, double epsilon) { // deal with NaNs first if (Double.isNaN(a)) { return Double.isNaN(b); } else if (Double.isNaN(b)) { return false; } if (Double.isInfinite(a)) { if (Double.isInfinite(b)) { return ((a < 0.0 && b < 0.0) || (a > 0.0 && b > 0.0)); } return false; } else if (Double.isInfinite(b)) { return false; } if (Math.abs(a - b) < epsilon) { return true; } if (a == 0.0 || b == 0.0) { return false; } final double DBL_EPSILON = 2.2204460492503131E-16; return Math.abs(1 - a / b) < DBL_EPSILON; } /** * Determine whether two numbers are roughly the same. * * @param a First number * @param b Second number * * @return <TT>true</TT> if they're approximately equal. */ public static boolean isApproximatelyEqual(double a, double b) { return isApproximatelyEqual(a, b, 0.000000001); } /** * Return a string representation of VisAD's build date and time. * * @return VisAD build date and time */ public static String getVersionDate() { try { InputStream is = Util.class.getResourceAsStream("/DATE"); BufferedReader in = new BufferedReader(new InputStreamReader(is)); String date = in.readLine(); in.close(); return date; } catch (IOException exc) { return null; } } /** * Print Java3D properties. * @param str Where to print properties. * @param canvas The Canvas3D to get properties from. If null Canvas3D * properties are skipped. * * @see #printJ3DProperties(Canvas3D) */ public static void printJ3DProperties(PrintStream str, Canvas3D canvas) { Map map = VirtualUniverse.getProperties(); for (Object key : map.keySet()) { str.println(String.format("%s=%s", key, map.get(key))); } if (canvas == null) { canvas = new Canvas3D(SimpleUniverse.getPreferredConfiguration()); } str.println("== Canvas3D properties =="); map = canvas.queryProperties(); for (Object key : map.keySet()) { str.println(String.format("%s=%s", key, map.get(key).toString())); } } /** * Print Java3D global and Canvas3D properties to <code>System.err</code>. * @param canvas The Canvas3D to get properties from. If null Canvas3D * properties are skipped. * * @see javax.media.j3d.VirtualUniverse#getProperties() * @see javax.media.j3d.Canvas3D#queryProperties() */ public static void printJ3DProperties(Canvas3D canvas) { printJ3DProperties(System.err, canvas); } /** * * * @param node */ public static void printSceneGraph(Node node) { if (node == null) return; printSceneGraph(node, 0); } /** * * * @param node * @param lvl */ private static void printSceneGraph(Node node, int lvl) { StringBuffer buf = new StringBuffer(); for (int i = 0; i < lvl; i++) { buf.append(" "); } lvl++; System.err.println(buf.toString() + node.toString()); if (node instanceof Group) { Group group = (Group)node; Enumeration children = group.getAllChildren(); while(children.hasMoreElements()) { printSceneGraph((Node)children.nextElement(), lvl); } } } // Map<SceneGraphObject, String> //private static final Map SGO_NAMES = new HashMap(); private static final Method SGO_GET_NAME; private static final Method SGO_SET_NAME; static { Method sgoGetName = null, sgoSetName = null; try { sgoGetName = SceneGraphObject.class.getDeclaredMethod("getName", new Class[0]); sgoSetName = SceneGraphObject.class.getDeclaredMethod("setName", new Class[] {String.class}); } catch (SecurityException e) { } catch (NoSuchMethodException e) { } SGO_GET_NAME = sgoGetName; SGO_SET_NAME = sgoSetName; } /** * Gets the name of the given {@link SceneGraphObject}. * * This method exists to avoid a compile-time * dependency on Java3D 1.4+. */ public static String getName(SceneGraphObject obj) { if (SGO_GET_NAME != null) { try { return (String) SGO_GET_NAME.invoke(obj); } catch (IllegalAccessException exc) { } catch (InvocationTargetException exc) { } } else { // no SceneGraphObject.getName method; retrieve name from Map instead //return (String) SGO_NAMES.get(obj); } return null; } /** * Sets the name of the given {@link SceneGraphObject}. * * This method exists to avoid a compile-time * dependency on Java3D 1.4+. */ public static void setName(SceneGraphObject obj, String name) { if (SGO_SET_NAME != null) { try { SGO_SET_NAME.invoke(obj, name); } catch (IllegalAccessException exc) { } catch (InvocationTargetException exc) { } } else { // no SceneGraphObject.setName method; save name to Map instead //SGO_NAMES.put(obj, name); } } /** * Convert 10-bit data to 2-byte data * @param input * @param output * @return 0 if no errors */ public static int tenBitToTwoByte(byte [] input, short [] output) { int total = output.length; int index = 0; int temp = 0; int skip = 0; int outputIndex = 0; index = skip / 8; skip = skip % 8; //input = (unsigned char *) inp; while (total > 0) { total--; /* * enumerated to avoid the more general need * to always access 3 bytes * which in reality is needed only for case 7 */ switch (skip) { case 0: temp = 4 * (int) (input[index] & 0xFF) + (int) (input[index + 1] & 0xFF) / 64; break; case 1: temp = 8 * (int) (input[index] & 0xFF) + (int) (input[index + 1] & 0xFF) / 32; break; case 2: temp = 16 * (int) (input[index] & 0xFF) + (int) (input[index + 1] & 0xFF) / 16; break; case 3: temp = 32 * (int) (input[index] & 0xFF) + (int) (input[index + 1] & 0xFF) / 8; break; case 4: temp = 64 * (int) (input[index] & 0xFF) + (int) (input[index + 1] & 0xFF) / 4; break; case 5: temp = 128 * (int) (input[index] & 0xFF) + (int) (input[index + 1] & 0xFF) / 2; break; case 6: temp = 256 * (int) (input[index] & 0xFF) + (int) (input[index + 1] & 0xFF); break; case 7: temp = 512 *(1& (int) (input[index] & 0xFF)) + 2 * (int) (input[index + 1] & 0xFF) + ( (int) (input[index + 2] & 0xFF) > 127 ? 1 : 0); break; } output[outputIndex] = (short) (temp & 0x3ff); outputIndex++; /* * these two statements together increment 10 bits on the input */ index++; skip += 2; /* * now normalize skip */ if (skip > 7) { index++; skip -= 8; } } return 0; } /** * Return a string representation of the current date and time. * * @return string timestamp for current time */ public static String getTimestamp() { StringBuffer sb = new StringBuffer(); Calendar cal = Calendar.getInstance(); int year = cal.get(Calendar.YEAR); int month = cal.get(Calendar.MONTH); int day = cal.get(Calendar.DAY_OF_MONTH); int hour = cal.get(Calendar.HOUR_OF_DAY); int min = cal.get(Calendar.MINUTE); int sec = cal.get(Calendar.SECOND); int milli = cal.get(Calendar.MILLISECOND); sb.append(year); sb.append("/"); if (month < 9) sb.append("0"); sb.append(month + 1); sb.append("/"); if (day < 10) sb.append("0"); sb.append(day); sb.append(", "); if (hour < 10) sb.append("0"); sb.append(hour); sb.append(":"); if (min < 10) sb.append("0"); sb.append(min); sb.append(":"); if (sec < 10) sb.append("0"); sb.append(sec); sb.append("."); if (milli < 100) sb.append("0"); if (milli < 10) sb.append("0"); sb.append(milli); return sb.toString(); } /** * Return a JFileChooser that recognizes supported VisAD file types. * * @return file chooser which recognizes supported VisAD file types */ public static JFileChooser getVisADFileChooser() { JFileChooser dialog = new JFileChooser(System.getProperty("user.dir")); Vector filters = new Vector(); boolean jai = canDoJAI(); // Amanda F2000 - amanda/F2000Form FileFilter f2000 = new ExtensionFileFilter("r", "Amanda F2000"); filters.add(f2000); // ASCII text - text/TextForm FileFilter text = new ExtensionFileFilter(new String[] {"csv", "tsv", "bsv", "txt"}, "ASCII text"); filters.add(text); // DEM - gis/DemFamily FileFilter dem = new ExtensionFileFilter("dem", "Digital Elevation Model"); filters.add(dem); // FITS - fits/FitsForm FileFilter fits = new ExtensionFileFilter("fits", "Flexible Image Transport System"); filters.add(fits); // FlashPix - jai/JAIForm if (jai) { FileFilter flashpix = new ExtensionFileFilter("flashpix", "FlashPix"); filters.add(flashpix); } // HDF-5 - hdf5/HDF5Form if (canDoHDF5()) { FileFilter hdf5 = new ExtensionFileFilter(new String[] {"hdf", "hdf5"}, "HDF-5"); filters.add(hdf5); } // HDF-EOS - hdfeos/HdfeosForm FileFilter hdfeos = new ExtensionFileFilter(new String[] {"hdf", "hdfeos"}, "HDF-EOS"); filters.add(hdfeos); // McIDAS area - mcidas/AreaForm FormFileFilter mcidasArea = new FormFileFilter(new AreaForm(), "McIDAS area (AREA*, *area)"); filters.add(mcidasArea); // McIDAS map - mcidas/MapForm FormFileFilter mcidasMap = new FormFileFilter(new MapForm(), "McIDAS map (OUTL*)"); filters.add(mcidasMap); // netCDF - netcdf/Plain FileFilter netcdf = new ExtensionFileFilter("nc", "NetCDF"); filters.add(netcdf); // PNM - jai/JAIForm if (jai) { FileFilter pnm = new ExtensionFileFilter("pnm", "PNM"); filters.add(pnm); } // VisAD binary/serialized - visad/VisADForm FileFilter visad = new ExtensionFileFilter("vad", "Binary or serialized VisAD"); filters.add(visad); // Vis5D - vis5d/Vis5DForm FileFilter vis5d = new ExtensionFileFilter("v5d", "Vis5D"); filters.add(vis5d); // biology-related formats - LociForm FileFilter[] lociFilters = new LociForm().getReaderFilters(); for (int i = 0; i < lociFilters.length; i++) filters.add(lociFilters[i]); // sort and combine filters alphanumerically FileFilter[] ff = ComboFileFilter.sortFilters(filters); // combination filter FileFilter combo = new ComboFileFilter(ff, "All VisAD file types"); // add filters to chooser dialog.addChoosableFileFilter(combo); for (int i = 0; i < ff.length; i++) dialog.addChoosableFileFilter(ff[i]); dialog.setFileFilter(combo); return dialog; } /** * Limit the given text field to one line in height. * * @param field */ public static void adjustTextField(JTextField field) { Dimension msize = field.getMaximumSize(); Dimension psize = field.getPreferredSize(); msize.height = psize.height; field.setMaximumSize(msize); } /** * Limit the given combo box to one line in height. * * @param combo */ public static void adjustComboBox(JComboBox combo) { Dimension msize = combo.getMaximumSize(); Dimension psize = combo.getPreferredSize(); msize.height = psize.height; combo.setMaximumSize(msize); } /** * Center the given window on the screen. * * @param window */ public static void centerWindow(Window window) { Dimension s = Toolkit.getDefaultToolkit().getScreenSize(); Dimension w = window.getSize(); window.setLocation((s.width - w.width) / 2, (s.height - w.height) / 2); int x = (s.width - w.width) / 2; int y = (s.height - w.height) / 2; if (x < 0) x = 0; if (y < 0) y = 0; window.setLocation(x, y); } /** * Center the given window within the specified parent window. * * @param parent * @param window */ public static void centerWindow(Window parent, Window window) { Point loc = parent.getLocation(); Dimension p = parent.getSize(); Dimension w = window.getSize(); int x = loc.x + (p.width - w.width) / 2; int y = loc.y + (p.height - w.height) / 2; if (x < 0) x = 0; if (y < 0) y = 0; window.setLocation(x, y); } /** * Test whether HDF-5 native code is present in this JVM. * @return true if found, otherwise false */ public static boolean canDoHDF5() { boolean success = false; try { H5.J2C(0); // HDF-5 call initializes HDF-5 native library success = true; } catch (NoClassDefFoundError err) { } catch (UnsatisfiedLinkError err) { } catch (Exception exc) { } return success; } /** * Test whether ImageJ is present in this JVM. * @return true if found, otherwise false */ public static boolean canDoImageJ() { return canDoClass("ij.IJ") != null; } /** * Test whether <code>javax.imageio</code> can write JPEGs. * @return true if found, otherwise false */ public static boolean canDoJPEG() { Iterator<ImageWriter> iter = ImageIO.getImageWritersByFormatName("jpeg"); return iter.hasNext(); } /** * Test whether Java Advanced Imaging is present in this JVM. * @return true if found, otherwise false */ public static boolean canDoJAI() { return canDoClass("javax.media.jai.JAI") != null; } /** * Test whether Jython is present in this JVM. * @return true if found, otherwise false */ public static boolean canDoPython() { return canDoClass("org.python.util.PythonInterpreter") != null; } /** * Test whether QuickTime for Java is present in this JVM. * @return true if found, otherwise false */ public static boolean canDoQuickTime() { return canDoClass("quicktime.QTSession") != null; } /** * Test whether Java3D is present in this JVM. * @return true if found, otherwise false */ public static boolean canDoJava3D() { return canDoJava3D("1.0"); } /** * Check to see if the version of Java3D being used is compatible * with the desired specification version. * @param version version to check. Needs to conform to the dotted format * of specification version numbers (e.g., 1.2) * @return true if the Java3D version being used is greater than or * equal to the desired version number */ public static boolean canDoJava3D(String version) { Class testClass = canDoClass("javax.vecmath.Point3d"); boolean b = (testClass != null) ? (canDoClass("javax.media.j3d.SceneGraphObject") != null) : false; if (b) { Package p = testClass.getPackage(); if (p != null) { try { b = p.isCompatibleWith(version); } catch (NumberFormatException nfe) { b = false; } } } return b; } /** * General classloader tester. * @param classname name of class to test * @return the class or null if class can't be loaded. */ private static Class canDoClass(String classname) { Class c = null; try { c = Class.forName(classname); } catch (ClassNotFoundException exc) { } return c; } /** * Capture a DisplayImpl into a JPEG file * * @param display the DisplayImpl to capture * @param filename the name of the file to write into * */ public static void captureDisplay(DisplayImpl display, String filename) { captureDisplay(display, filename, false); } /** * Capture a DisplayImpl into a JPEG file * * @param display the DisplayImpl to capture * @param filename the name of the file to write into * @param sync ensure the display is "done" if true * */ public static void captureDisplay(DisplayImpl display, String filename, boolean sync) { final DisplayImpl disp = display; final File fn = new File(filename); final boolean wait = sync; Runnable savedisp = new Runnable() { public void run() { BufferedImage image = disp.getImage(wait); try { Iterator<ImageWriter> iter = ImageIO.getImageWritersByFormatName("jpeg"); ImageWriter writer = iter.next(); ImageWriteParam param = writer.getDefaultWriteParam(); param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); param.setCompressionQuality(1.0f); FileOutputStream fout = new FileOutputStream(fn); writer.setOutput(fout); IIOImage iio = new IIOImage(image, null, null); writer.write(null, iio, param); fout.close(); } catch (Exception err) { System.err.println("Error whilst saving JPEG: " + err); } } }; Thread t = new Thread(savedisp); t.start(); } /** * Tests whether two arrays are component-wise equal. * * @param o1 * @param o2 * * @return true if the arrays are equal */ public static boolean arraysEqual(Object[] o1, Object[] o2) { // test for null if (o1 == null && o2 == null) return true; if (o1 == null || o2 == null) return false; // test for differing lengths if (o1.length != o2.length) return false; // test each component for (int i = 0; i < o1.length; i++) { //if (!o1[i].equals(o2[i])) return false; Object a1 = o1[i]; Object a2 = o2[i]; if (!(a1 == null ? a2 == null : a1.equals(a2))) return false; } return true; } /** * Create a string representation of the given array * * @param prefix * @param array array to print * */ public static void printArray(String prefix, Object[] array) { StringBuffer buf = new StringBuffer(); buf.append(prefix); buf.append(": "); if (array == null) { buf.append(" null "); } else { for (int i = 0; i < array.length; i++) { buf.append("["); buf.append(i); buf.append("]: "); buf.append((array[i] == null) ? "null" : array[i]); buf.append(" "); } } System.out.println(buf.toString()); } /** * Print out the values in a double array. * * @param prefix prefix string * @param array array to print */ public static void printArray(String prefix, double[] array) { StringBuffer buf = new StringBuffer(); buf.append(prefix); buf.append(": "); if (array == null) { buf.append(" null "); } else { for (int i = 0; i < array.length; i++) { buf.append("["); buf.append(i); buf.append("]: "); buf.append(array[i]); buf.append(" "); } } System.out.println(buf.toString()); } /** * Executes the given Runnable object with the Swing event handling thread. * * @param wait <tt>true</tt> if method should block until Runnable code * finishes execution. * @param r Runnable object to execute using the event handling thread. */ public static void invoke(boolean wait, Runnable r) { invoke(wait, false, r); } /** * Executes the given Runnable object with the Swing event handling thread. * * @param wait <tt>true</tt> if method should block until Runnable code * finishes execution. * @param printStackTraces <tt>true</tt> if the stack trace for * any exception should be printed. * @param r Runnable object to execute using the event handling thread. */ public static void invoke(boolean wait, boolean printStackTraces, Runnable r) { if (wait) { // use invokeAndWait if (Thread.currentThread().getName().startsWith("AWT-EventQueue")) { // current thread is the AWT event queue thread; just execute the code r.run(); } else { // execute the code with the AWT event thread try { SwingUtilities.invokeAndWait(r); } catch (InterruptedException exc) { if (printStackTraces) exc.printStackTrace(); } catch (InvocationTargetException exc) { if (printStackTraces) exc.getTargetException().printStackTrace(); } } } else { // use invokeLater SwingUtilities.invokeLater(r); } } /** * Create a ConstantMap array of colors for use with * {@link Display#addReference(DataReference, ConstantMap[])} * * @param color color to encode * * @return an array containing either 3 colors or, if the <tt>color</tt> * parameter included an alpha component, a 4 element array * with 3 colors and an @{link Display.Alpha alpha} component. * * @throws VisADException */ public static ConstantMap[] getColorMaps(Color color) throws VisADException { final int alpha = color.getAlpha(); ConstantMap[] maps = new ConstantMap[alpha == 255 ? 3 : 4]; maps[0] = new ConstantMap((float)color.getRed() / 255.0f, Display.Red); maps[1] = new ConstantMap((float)color.getGreen() / 255.0f, Display.Green); maps[2] = new ConstantMap((float)color.getBlue() / 255.0f, Display.Blue); if (alpha != 255) { maps[3] = new ConstantMap((float)color.getAlpha() / 255f, Display.Alpha); } return maps; } /** * Configure basic logging for the visad package. In a production * environment the preferred way to configure logging is using the * logging.properties file. This is intended only as a convenience method * for configuring console logging for the purposes of testing. * * @param verbosity 0 is <code>Level.WARNING</code> and progresses to a * maximum of <code>Level.ALL</code>. * @param pkg Name of the java package to configure logging for. * @return The <code>Level</code> logging was set to. */ public static Level configureLogging(int verbosity, String pkg) { Level lvl = Level.WARNING; switch (verbosity) { case 1: lvl = Level.INFO; break; case 2: lvl = Level.FINE; break; case 3: lvl = Level.FINER; break; case 4: lvl = Level.FINEST; break; case 5: lvl = Level.ALL; break; default: lvl = Level.WARNING; } Logger logger = Logger.getLogger(pkg); logger.setLevel(lvl); logger.setUseParentHandlers(false); Handler console = new ConsoleHandler(); console.setLevel(lvl); console.setFormatter(new Formatter() { public String format(LogRecord r) { return String.format( "[%s] %s\n", r.getLevel().getName(), r.getMessage()); } }); logger.addHandler(console); return lvl; } /** * @see #configureLogging(int, java.lang.String) * * @param verbosity * * @return logging level */ public static Level configureLogging(int verbosity) { return configureLogging(verbosity, "visad"); } /** * Utility method to return the stack trace * * @return The stack trace */ public static String getStackTrace() { ByteArrayOutputStream baos = new ByteArrayOutputStream(); (new IllegalArgumentException("stack trace")).printStackTrace( new PrintStream(baos)); return baos.toString(); } /** * do a deep clone * * @param input the array * * @return cloned array */ public static float[][] clone(float[][] input) { float[][] output = (float[][])input.clone(); for (int i = 0; i < input.length; i++) { output[i] = (float[])input[i].clone(); } return output; } /** * do a deep clone * * @param input the array * * @return cloned array */ public static double[][] clone(double[][] input) { double[][] output = (double[][])input.clone(); for (int i = 0; i < input.length; i++) { output[i] = (double[])input[i].clone(); } return output; } /** * Converts an (unsigned) byte to an unsigned int. * Since Java doesn't have an unsigned * byte type, this requires some foolery. * This solution based on information and code from * http://www.rgagnon.com/javadetails/java-0026.html * @param s The unsigned short to convert * @return the unsigned int equivalent */ public static int unsignedShortToInt(short s) { return (int) s & 0xFFFF; } /** * Converts an (unsigned) byte to an unsigned int. * Since Java doesn't have an unsigned * byte type, this requires some foolery. * This solution based on information and code from * http://www.rgagnon.com/javadetails/java-0026.html * @param b The unsigned byte to convert * @return the unsigned int equivalent */ public static int unsignedByteToInt(byte b) { return (int) b & 0xFF; } /** * Converts an (unsigned) byte to an unsigned long. * Since Java doesn't have an unsigned * byte type, this requires some foolery. * This solution based on information and code from * http://www.rgagnon.com/javadetails/java-0026.html * @param b The unsigned byte to convert * @return the unsigned long equivalent */ public static long unsignedByteToLong(byte b) { return (long) b & 0xFF; } }