package com.idega.core.ldap.client.cbutil; import java.awt.Component; import java.awt.Cursor; import java.awt.Dimension; import java.awt.Frame; import java.awt.Point; import java.awt.Rectangle; import java.awt.Toolkit; import java.awt.Window; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileReader; import java.io.FileWriter; import java.io.FilenameFilter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.URL; import java.util.Comparator; import java.util.Date; import java.util.Enumeration; import java.util.Locale; import java.util.Properties; import javax.swing.JFileChooser; import javax.swing.JOptionPane; /** * This is a grab bag of useful classes and static functions that are * not important enough to merit being top level entities. Most of them * are concerned with string handling, file handling, and i18n issues. * */ public class CBUtility { private static Cursor savedCursor; private static FileWriter logfile; private static int loggingStyle = -1; private static int debugLevel = 0; private static Frame displayFrame = null; private static final int NOLOG = 0; private static final int CONSOLE = 1; private static final int FILE = 2; private static final int CONSOLEANDFILE = 3; // = CONSOLE (bitwise and) FILE private CBUtility () {} /** * A utility ftn used to make a closing window shut down * the current application. Useful for small test progs. */ public static class BasicWindowMonitor extends WindowAdapter { public void windowClosing(WindowEvent e) { Window w = e.getWindow(); w.setVisible(false); w.dispose(); //System.exit(0); } } /** * Returns the raw text (i.e. with tags as "\<...\>" strings) of a web page * * @param url the url of the web age to read as plain text. * @return a StringBuffer containing the raw html text */ public static StringBuffer readURLText(URL url) { return readURLText(url, new StringBuffer("error: can't read URL " + url.toString())); } /** * Returns the raw text (i.e. with tags as "\<...\>" strings) of a web page * * @param url the url of the web age to read as plain text. * @param errorText a custom message to return if something goes wrong. * @return a StringBuffer containing the raw html text */ public static StringBuffer readURLText(URL url, StringBuffer errorText) { StringBuffer page = new StringBuffer(""); String thisLine; try { BufferedReader source = new BufferedReader(new InputStreamReader(url.openStream())); while ((thisLine = source.readLine()) != null) { page.append(thisLine + "\n"); } return page; } catch (Exception e) { return errorText; } } /** * Reads an input stream into a byte array. */ public static byte[] readStream(InputStream is) throws IOException { byte[] data = null; byte[] buffer = new byte[16384]; int blockSize = 0; int size = 0; while ((blockSize = is.read(buffer)) != -1) // kinda clumsy, reallocating { // memory like this I guess, byte[] temp = new byte[size + blockSize]; // but since we don't know if (size != 0) { System.arraycopy(data, 0, temp, 0, size); // else can we do? (?) } System.arraycopy(buffer, 0, temp, size, blockSize); data = temp; size += blockSize; } return data; } /** * Reads a text file, and returns the result as a String. Not * Recommended for large (say > 100k) files. * * @param file the ascii file to read from. */ public static String readTextFile(File file) throws IOException { // special handling for file reading in non-english locales... if (Locale.getDefault().getLanguage().equals("en")==false) { return readI18NFile(file); } // Read File into String Buffer FileReader in = new FileReader(file); int size = (int) file.length(); char[] data = new char[size]; int chars_read = 0; while (chars_read < size) { chars_read += in.read(data, chars_read, size - chars_read); } return new String(data); // use default locale encoding... } /** * Reads a text file, and returns the result as a StringBuffer. Not * Recommended for large (say > 100k) files.<p> * * This function attempts to automatically determine the encoding * of the file it is to read, as either UTF-16, UTF-8, or default * locale encoding, based on 1) whether the first two bytes are * Unicode byte-ordering markers ('FFFE' or 'FEFF'), UTF-8 (based * on whether the file is a valid UTF8 string) or, * failing this, the default locale encoding. * * @param file the local encoding/unicode/utf8 file to read from. */ public static String readI18NFile(File file) throws IOException { // Read File into String Buffer FileInputStream in = new FileInputStream(file); int size = (int) file.length(); byte[] data = new byte[size]; int bytes_read = 0; while (bytes_read < size) { bytes_read += in.read(data, bytes_read, size - bytes_read); } return readI18NByteArray(data); } public static String readI18NByteArray(byte[] data) { // Try to work out whether this is unicode double bytes (utf-16), // unicode (or *cough* 7 bit ascii) in utf-8 format, or local // encoding... try { if (isUnicode(data)) { log("reading unicode 16 bit text", 7); String text = new String(data, "UTF-16"); // return as 16 bit unicode if (text.length() > 0) { return text; } return new String(data); // something went wrong - try again with default encoding... } else { byte[] test = new byte[250]; // grab the start of the file to test... if (data.length<250) { test = data; } else { System.arraycopy(data,0,test,0,250); } if (isNonAsciiUTF8(test)) { log("reading utf8 text", 7); String text = new String(data, "UTF-8"); // return as UTF-8 if (text.length() > 0 ) { return text; } return (new String(data)); // something went wrong - try again with default encoding } else { log("reading local encoding text", 7); String newString = new String(data); if (newString.indexOf("\\u") == -1) { return newString; // no need for special processing. } // MANUALLY (!) decode \ u java unicode escape strings... // (Why? Because someone may be in a foreign locale, but // still using broken java unicode escape syntax from standard // property files.) StringBuffer buffer = new StringBuffer(newString); int pos = 0; while (pos+6 < buffer.length()) { if (buffer.charAt(pos) != '\\') { pos++; } else if (buffer.charAt(pos+1) != 'u') { pos += 2; } else { String unicode = buffer.substring(pos+2,pos+6); int uni = Integer.parseInt(unicode, 16); buffer = buffer.delete(pos, pos+6); buffer = buffer.insert(pos, (char) uni); pos ++; } } return buffer.toString(); // return as default locale encoding } } } /* If anything goes wrong (UnsupportedEncodingException, or hopefully if * the utf-8 string turns out not to be) fall back on using the * default encoding. */ catch (Exception e) { CBUtility.log("Confused Reading File: " + e.toString() + "\n -> reverting to default encoding"); return new String(data); // return as default locale encoding } } /** * Reads an array of strings from a file * (via a property file, 'cause I'm lazy). * @param fileName the file to read from */ public static String[] readStringArrayFile(String fileName) { Properties props = readPropertyFile(fileName); String[] values = new String[props.size()]; Enumeration enumer = props.elements(); int count = 0; while (enumer.hasMoreElements()) { values[count++] = enumer.nextElement().toString(); } return values; } /** * Reads a java Properties list from a file. * * @param fileName the full path and file name of the properties file * to read in. */ public static Properties readPropertyFile(String fileName) { Properties propertyList = new Properties(); try { File propertyFile = new File (fileName); if (propertyFile == null || propertyFile.exists() == false) { log("No property list:\n"+fileName, 1); return propertyList; // return empty properties list } FileInputStream in = new FileInputStream(propertyFile); propertyList.load(in); return propertyList; } catch (java.lang.Exception e) { CBUtility.log("Can't read property list:\n" + fileName + "\n" + e); return propertyList; } } /** * Writes an array of strings into a file * (via a property file, 'cause I'm lazy). * (XXX Warning - will only write unique values; doubles will be lost). * @param fileName the file to read to * @param strings the array of strings */ public static void writeStringArrayFile(String fileName, String[] strings) { Properties props = new Properties(); for (int i=0; i<strings.length; i++) { props.put(strings[i], strings[i]); // so it's redundant. sue me. } writePropertyFile(fileName, props, "generated string array list"); } /** * Writes a java Properties list to a file. * * @param fileName the full path and file name of the properties file * to read in. */ public static void writePropertyFile(String fileName, Properties propertyList, String comments) { try { File propertyFile = new File (fileName); FileOutputStream out = new FileOutputStream(propertyFile); propertyList.store(out, "Generated Property List " + fileName + "\n" + ((comments!=null)?comments:"")); } catch (java.lang.Exception e) { CBUtility.log("Can't write property list:\n" + fileName + "\n" + e); } } /** * Turns a string into HTML displayable text by escaping * special characters ('<','&' etc...). * * ... add new ones as required; or see if an existing ftn somewhere * does this already... */ public static String toHTML(String rawText) { String test; if (rawText.length()>14) { test = rawText.substring(0,14).toLowerCase(); } else { test = rawText.toLowerCase(); } if (test.startsWith("<html>") || test.startsWith("<!doctype html>")) { // XXX this was commented out, but it seems to be necessaary/desirable? if (test.startsWith("<html>")) { rawText = rawText.substring(6); } else if (test.startsWith("<!doctype html>")) { rawText = rawText.substring(15); } if (rawText.toLowerCase().endsWith("</html>")) { rawText = rawText.substring(0,rawText.length()-7); } // END XXX return rawText; } char C; StringBuffer temp = new StringBuffer(rawText); for (int pos = 0; pos < temp.length(); pos++) { C = temp.charAt(pos); switch (C) { case '<' : replaceChar(temp, pos,"<"); break; case '>' : replaceChar(temp, pos,">"); break; case '&' : replaceChar(temp, pos,"&"); break; case '\"': replaceChar(temp, pos,"""); break; } } return temp.toString(); } /** * Deletes a character in <i>text</i> at position <i>pos<i> and replaces * it with the string <i>replacement</i>. * * @param text the text to be modified * @param pos the position of the character to be deleted * @param replacement the string the character is to be replaced with. */ public static int replaceChar(StringBuffer text, int pos, String replacement) { text.deleteCharAt(pos); text.insert(pos,replacement); return (pos+replacement.length()); } /** * Deletes all characters <i>c</i> in <i>text</i> replaces * it with the string <i>replacement</i>. * * @param text the text to be modified * @param replacement the string the character is to be replaced with. */ public static String replaceAllChar(StringBuffer text, char c, String replacement) { return replaceAllBufferChar(text,c,replacement).toString(); } /** * Deletes all characters <i>c</i> in <i>text</i> replaces * it with the string <i>replacement</i>. * * @param text the text to be modified * @param replacement the string the character is to be replaced with. */ public static StringBuffer replaceAllBufferChar(StringBuffer text, char c, String replacement) { int pos = 0; while (pos != -1) { pos = text.toString().indexOf(c,pos); if (pos!=-1) { pos = replaceChar(text, pos, replacement); } } return text; } /** * Deletes a substring in <i>text</i> at position <i>pos<i>, of length <i>len</i> and replaces * it with the string <i>replacement</i>. * * @param text the text to be modified * @param pos the position of the character to be deleted * @param replacement the string the character is to be replaced with. */ public static int replaceString(StringBuffer text, int pos, int len, String replacement) { text.replace(pos, pos+len, replacement); //text.delete(pos, pos+len); //text.insert(pos, replacement); return (pos+replacement.length()); } /** * Deletes all characters <i>orig</i> in <i>text</i> and replaces * it with the string <i>replacement</i>. * * @param text the text to be modified * @param orig the original text substring to be changed * @param replacement the string the original substring is to be replaced with. */ public static String replaceAllString(StringBuffer text, String orig, String replacement) { return replaceAllBufferString(text,orig,replacement).toString(); } /** * Deletes all characters <i>orig</i> in <i>text</i> replaces * it with the string <i>replacement</i>. * * @param text the text to be modified * @param orig the original text substring to be changed * @param replacement the string the original substring is to be replaced with. */ public static StringBuffer replaceAllBufferString(StringBuffer text, String orig, String replacement) { int pos = 0; while (pos != -1) { pos = text.toString().indexOf(orig,pos); if (pos!=-1) { pos = replaceString(text, pos, orig.length(), replacement); } } return text; } /** * Utility for micro-parser. Gets the next character pos in a string * after an initial offset that either matches, or does not match, <i>any</i> * of a set of comparison characters. * * @param pos the position to start searching from * @param searchMe the string to search * @param compare a string containing characters to compare against * @param whether the match is for characters in the compare string (true) * or <i>not</i> in the compare string (false) * * @return the position found, or -1 if no position is found. */ public static int nextCharIn(int pos, String searchMe, String compare, boolean match) { char test; int length = searchMe.length(); while (pos < length) { test = searchMe.charAt(pos); if ((compare.indexOf(test) != -1) == match) { return pos; } pos++; } return -1; } /** * Reads a directory, returning all file names of the given extension. * * @param dirPath directory to read * @param extension the file extension to filter files with. * @return list of full file names */ public static String[] readFilteredDirectory(String dirPath, String extension) { String[] extensions = new String[1]; extensions[0] = extension; return readFilteredDirectory(dirPath, extensions); } /** * Reads a directory, returning all file names of the given extensions * * @param dirPath directory to read * @param extension a list of file extensions to filter files with. * @return list of full file names */ public static String[] readFilteredDirectory(String dirPath, String [] fileExtensions) { final String[] extensions = fileExtensions; File dir = new File(dirPath); //XXX Could use CBFileFilter here? String[] templates = dir.list(new FilenameFilter() { public boolean accept(File dir, String name) { for (int i=0; i<extensions.length;i++) { if (name.endsWith(extensions[i])) { return true; } } return false; } }); return templates; } /** * Sets the cursor to the wait cursor. * @param c the owning component. */ public static void setWaitCursor(Component C) { C.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); } /** * Sets the cursor to the normal cursor. * @param c the owning component. */ public static void setNormalCursor(Component C) { C.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); } /** * Sets the cursor to the hand cursor. * @param c the owning component. * @author Trudi */ public static void setHandCursor(Component C) { C.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); } /** * Saves a cursor. One cursor. That's all. Just one. Try to * save another one, it'll overwrite this one. So don't. * @param c the owning component. */ public static void saveCursor(Component C) { savedCursor = C.getCursor(); } /** * Gets the cursor back that you just saved. Probably better * make sure it's the same component you saved it from. Wouldn't * care to guess what happens if it isn't... */ public static void restoreCursor(Component C) { if (savedCursor != null) { C.setCursor(savedCursor); } else { log("can't restore cursor; no cursor saved...",1); } } /** * Sets the level of logging on a scale of 0 (none) to 10 (everything). * @param L the log level. */ public static void setLogDebugLevel(int L) { debugLevel = L; } /** * Returns the global debug level. */ public static int getLogDebugLevel() { return debugLevel; } /** * Sets the type of logging, using the strings 'none', 'console' or 'file'. * @param logType the type of logging to use. */ public static void setLogType(String logType) {setLogType(logType, null);} /** * Sets the type of logging, using the strings 'none', 'console' or 'file'. * @param logType the type of logging to use. * @param the name of the log file to use, (unused if logType != 'file') */ public static void setLogType(String logType, String fileName) { if (logType.equalsIgnoreCase("none")) { loggingStyle = NOLOG; } else if (logType.equalsIgnoreCase("console")) { loggingStyle = CONSOLE; } else if (logType.equalsIgnoreCase("file") || logType.equalsIgnoreCase("both")) { String logFileName = (fileName==null)?"jxplorer.log":fileName; try { logfile = new FileWriter(logFileName); if (logType.equalsIgnoreCase("both")) { loggingStyle=CONSOLEANDFILE; } else { loggingStyle = FILE; } } catch (Exception e) { CBUtility.log("unable to open log file " + logFileName + "\nreverting to console logging"); loggingStyle = CONSOLE; } } else { loggingStyle = CONSOLE; // console is default... } log("Logging Initialised to " + logType, 1); } /** * Closes the log file. */ public static void closeLog() { try { if (logfile != null) { logfile.close(); } } catch (Exception e) { CBUtility.log("error shutting log file " + e.toString()); } } /** * logs if the global debug level equal to or greater than the * passed int value.<p> * * <b>Log Levels</b><br> * <ul> * <li>0 - error logging only * <li>1 * <li>2 * <li>3 * <li>4 - entry level logging of all delete/copy/move operations * <li>5 * <li>6 * <li>7 * <li>8 * <li>9 - full BER logging * </ul> * * * @param S the string to log * @param level the debug level at which the string starts * being printed */ public static void log(String S, int level) { if (debugLevel >= level) { log(S); } } /** * Simple logging utility. Writes log data to a file or console, * or ignores it, depending on the value of the logging and logfile * property (defaults set in JXplorer.java, user sets in dxconfig.txt) */ public static void log(String S) { S = (new Date(System.currentTimeMillis())).toString() + ": " + S; switch (loggingStyle) { case NOLOG: break; // do nothing case CONSOLEANDFILE: // log file and console... case FILE: try // log file only { logfile.write(S + "\n"); logfile.flush(); } catch (Exception e) { CBUtility.log("unable to write to log file\nreverting to console\n" + e + "\n"+S); loggingStyle = CONSOLE; } if (loggingStyle == FILE) { break; } case CONSOLE: // console default: System.out.println(S); break; // echo to console } } public static void initDefaultDisplay(Frame owner) { displayFrame = owner; } public static Frame getDefaultDisplay() { return displayFrame; } /** * utility ftn; prints error message to user, and echos to the log ftn. * * @return returns false for easy chaining. */ public static boolean error(Component owner, String Msg) { return error(getParentFrame(owner), Msg, null); } /** * utility ftn; prints error message to user, and echos to the log ftn. * * @return returns false for easy chaining. */ public static boolean error(Frame owner, String Msg) { if (displayFrame == null) // no default display registered { log("error display not initialised! (error was: " + Msg + ")", 0); return false; } return error(owner, Msg, null); } /** * utility ftn; prints error message to user, and echos to the log ftn. * * @return returns false for easy chaining. */ public static boolean error(String Msg) { if (displayFrame == null) // no default display registered { log("error display not initialised! (error was: " + Msg + ")", 0); return false; } return error(displayFrame, Msg, null); } /** * wrapper for the JFrame version of error. * * @param caller the component (from which the parent Frame will be derived) * @param Msg a short one line message to display to the user * @param e the exception to log * @return returns false for easy chaining. */ public static boolean error(String Msg, java.lang.Exception e) { return error(displayFrame, Msg, e); } /** * wrapper for the JFrame version of error. * * @param caller the component (from which the parent Frame will be derived) * @param Msg a short one line message to display to the user * @param e the exception to log * @return returns false for easy chaining. */ public static boolean error(Component owner, String Msg, java.lang.Exception e) { return error(getParentFrame(owner), Msg, e); } /** * utility ftn; prints error message and the error to the user, * and echos to the log ftn. * * @param caller the parent Frame (required for dialog box drawing) * @param Msg a short one line message to display to the user * @param e the exception to log * @return returns false for easy chaining. */ public static boolean error(Frame owner, String Msg, java.lang.Exception e) { if (owner==null) //TE: added this check basically so that I can centre the error window...i.e if there is no owner - there is nothing to centre upon! { if (displayFrame == null) // no default display registered { log("error display not initialised! (error was: " + Msg + ")", 0); return false; } else { owner = displayFrame; } } // CBErrorWin errWin = new CBErrorWin(owner, Msg, e); log("error " + Msg + "\n" + ((e==null)?"":e.toString())); //DEBUG if ((debugLevel>8)&&(e!=null)) { System.out.println("printing stack trace"); e.printStackTrace(); } return false; } /** * Utility function. Opens a dialog with a confirmation message. * @param Msg the confirmation message to be displayed. * @author Trudi. */ public static void confirm(String Msg) { if (displayFrame == null) // no default display registered { System.out.println("error display not initialised! (error was: " + Msg + ")"); return; } // CBErrorWin errWin = new CBErrorWin(displayFrame, Msg, "Confirmation Message"); } /** * utility ftn; prints warning dialog message to the user, * *without* echoing to the log ftn. Basically wrapper to JOptionPane * * @param caller the GUI component calling (required for dialog box drawing) * @param Msg a short one line message to display to the user * @return returns false for easy chaining. */ public static boolean warning(Component caller, String Msg, String Title) { JOptionPane.showMessageDialog (caller, Msg, Title, JOptionPane.WARNING_MESSAGE ); return false; // for chaining } /** * Short version of warning method - uses default frame, and has the * title 'Warning'. * @param Msg the warning message to display. */ public static boolean warning(String Msg) { if (displayFrame == null) // no default display registered { System.out.println("warning display not initialised! (error was: " + Msg + ")"); return false; } return warning(displayFrame, Msg, "Warning"); } /** * prints an enumeration... */ public static void printEnumeration(Enumeration e) { while (e.hasMoreElements()) { Object raw = e.nextElement(); String value = (raw==null)?"*null*":raw.toString(); System.out.println(" " + value); } } /** * Iterates through a components parents until it finds the * root frame. Useful for initing JDialogs etc. that require * a root frame to work properly. */ public static Frame getParentFrame(Component c) { if (c==null) { return null; } Component parent = c.getParent(); while (!(parent instanceof Frame)&& (parent != null)) { parent = parent.getParent(); } return (parent==null)?null:(Frame) parent; } /** * Converts a 'dos' style file path to a unix style file path * by exchanging '\' characters for for '/' characters. * * */ public static String convertPathToUnix(String dosPath) { //System.out.println("converting '" + dosPath + "'"); String ret = dosPath.replace('\\','/'); //System.out.println("to '" + ret + "'"); return ret; } /** * This positions a component to the center of another component. * If both components are showing on the sceen, it uses absolute * screen co-ordinates, otherwise if only the positioner component * is showing, it uses relative co-ordinates (since it is unable to * obtain screen co-ords). If the components share a reference * frame, these two actions are equivalent (i.e. if they both have * the same parent). If nothing is showing, the component is unchanged. * NOTE: if the X & Y coordinates are off the screen, the component to * center will be centered in the middle of the screen. * * @param centreMe the component to center * @param positioner the component used as the reference center. If null, * the component will be centered on the screen */ public static void center(Component centerMe, Component positioner) { if (centerMe == null) { return; } if (positioner != null && positioner.isShowing()) { Rectangle pos = positioner.getBounds(); // relative info. Point absPos = positioner.getLocationOnScreen(); // absolute info. int centerX = absPos.x + (pos.width/2); // center x pos, in screen co-ords int centerY = absPos.y + (pos.height/2); // center y pos, in screen co-ords pos = centerMe.getBounds(); // relative info; int x = 0; int y = 0; if (centerMe.isShowing()) // if centerMe is showing, center it using screen co-ords (no possibility of error) { absPos = centerMe.getLocationOnScreen(); // absolute info; int currentX = absPos.x + (pos.width/2); // center of centerMe x pos, in screen co-ords int currentY = absPos.y + (pos.height/2); // center of centerMe y pos, in screen co-ords int deltaX = centerX - currentX ; // amount to move X int deltaY = centerY - currentY ; // amount to move Y x = pos.x + deltaX; y = pos.y + deltaY; } else // centerMe isn't showing - can't use screen co-ords, so *assume* both positioner and centerMe have same reference frame { // (i.e. components share a common parent...) x = centerX - (pos.width/2); y = centerY - (pos.height/2); } Toolkit toolKit = Toolkit.getDefaultToolkit(); if((x-100)<0 || (x+100)>toolKit.getScreenSize().width || (y-100)<0 || (y+100)>toolKit.getScreenSize().height) { centerOnScreen(centerMe); //TE: center in middle of screen (bug 2926). } else { centerMe.setLocation(x, y); // move, using local co-ordinates. } } else { centerOnScreen(centerMe); } } /** * Centers a component on the middle of the screen. * @param centerMe the component to center. */ private static void centerOnScreen(Component centerMe) { Dimension screen = centerMe.getToolkit().getScreenSize(); Dimension object = centerMe.getSize(); centerMe.setLocation((int)(screen.getWidth() - object.getWidth())/2, (int)(screen.getHeight() - object.getHeight())/2); } public static String bytes2Hex(byte[] bytes) { StringBuffer ret = new StringBuffer(bytes.length*2); for (int i=0; i<bytes.length; i++) { ret.append(byte2Hex(bytes[i])); } return ret.toString(); } public static String string2Hex(String orig) { StringBuffer ret = new StringBuffer(orig.length()*2); char[] c = orig.toCharArray(); for (int i=0; i<c.length; i++) { ret.append(char2Hex(c[i])); } return ret.toString(); } static public String byte2Hex(byte b) { // Returns hex String representation of byte b final char hexDigit[] = {'0', '1', '2', '3', '4', '5', '6', '7','8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; char[] array = { hexDigit[(b >> 4) & 0x0f], hexDigit[b & 0x0f] }; return new String(array); } static public String char2Hex(char c) { // Returns hex String representation of char c byte hi = (byte) (c >>> 8); byte lo = (byte) (c & 0xff); return byte2Hex(hi) + byte2Hex(lo); } static public byte hex2Byte(char hex1, char hex2) { byte a = hexChar2Byte(hex1); byte b = hexChar2Byte(hex2); return (byte) ((a << 4) + b); } /** * Convert a single character to a byte... */ static public byte hexChar2Byte(char hex) { if (hex <= '9') { return ((byte)(hex-48)); // ('0' -> '9') } else if (hex <= 'F') { return ((byte)(hex-55)); // ('A' -> 'F') } else { return ((byte)(hex-87)); // ('a' -> 'f') } } /** * From Van Bui - prints out a hex string formatted with * spaces between each hex word of length wordlength. * * @param in input array of bytes to convert * @param wordlength the length of hex words to print otu. */ public static String bytes2HexSplit(byte[] in, int wordlength) { String hex = bytes2Hex(in); StringBuffer buff = new StringBuffer(); for (int i = 0; i < hex.length(); i++) { buff.append(hex.charAt(i)); if ((i+1) % wordlength == 0) { buff.append(" "); } } return buff.toString(); } /** * From Van Bui - prints out a hex string formatted with * spaces between each hex word of length wordlength, and * new lines every linelength. * * @param in input array of bytes to convert * @param wordlength the length of hex words to print otu. * @param linelength the length of a line to print before inserting * a line feed. */ public static String bytes2HexSplit(byte[] in, int wordlength, int linelength) { String hex = bytes2Hex(in); StringBuffer buff = new StringBuffer(); for (int i = 0; i < hex.length(); i++) { buff.append(hex.charAt(i)); if ((i+1) % wordlength == 0) { buff.append(" "); } if ((i+1) % linelength == 0) { buff.append("\n"); } } return buff.toString(); } /** * Determines whether a given byte sequence is a valid utf-8 * encoding. While this does not mean that the byte *is* a * utf-8 encoded string, the chance of a random byte sequence * happening to be utf8 is roughly (1/2 ** (byte array length)).<p> * Note that '7 bit ascii' is *always* a valid utf-8 string...<p> * see rfc 2279 */ public static boolean isUTF8(byte[] sequence) { boolean debug = true; if (debug) { System.out.println("\n\n Starting UTF8 Check\n\n"); } int numberBytesInChar; for (int i=0; i< sequence.length; i++) { byte b = sequence[i]; if (debug) { System.out.println("testing byte: " + byte2Hex(b)); } if (((b >> 6) & 0x03) == 2) { if (debug) { System.out.println("start byte is invalid utf8 - has 10... start"); } return false; } byte test = b; numberBytesInChar = 0; while ((test & 0x80)>0) { test <<= 1; numberBytesInChar ++; } if (numberBytesInChar > 1) // check that extended bytes are also good... { for (int j=1; j< numberBytesInChar; j++) { if (i+j >= sequence.length) { if (debug) { System.out.println("following byte length is invalid - overruns end... "); } return false; // not a character encoding - probably random bytes } if (debug) { System.out.println("testing byte: " + byte2Hex(sequence[i+j])); } if (((sequence[i+j] >> 6) & 0x03) != 2) { if (debug) { System.out.println("following byte is invalid utf8 - does *not* have 10... start"); } return false; } } i += numberBytesInChar - 1; // increment i to the next utf8 character start position. } } return true; } /** * Determines whether a given byte sequence is a valid utf-8 * encoding, encoding (at least in part) something *other* than * normal Ascii (i.e. * it is utf-8 encoding something that is not just 7-bit ascii, * which in utf-8 is indistinguishable from the original text).<p> * * While this does not mean that the bytes *are* a * utf-8 encoded string, the chance of a random byte sequence * (containing bytes with the high-bit set) * happening to be utf8 is roughly (1/2 ** (byte array length)).<p> * see rfc 2279 */ public static boolean isNonAsciiUTF8(byte[] sequence) { log("testing sequence for utf8: " + bytes2Hex(sequence) + "\n", 8); boolean nonAsciiDetected = false; int numberBytesInChar; for (int i=0; i< sequence.length-3; i++) { byte b = sequence[i]; if (((b >> 6) & 0x03) == 2) { return false; } byte test = b; numberBytesInChar = 0; while ((test & 0x80)>0) { test <<= 1; numberBytesInChar ++; } // check if multi-byte utf8 sequence found if (numberBytesInChar > 1) // check that extended bytes are also good... { nonAsciiDetected = true; for (int j=1; j< numberBytesInChar; j++) { if (((sequence[i+j] >> 6) & 0x03) != 2) { return false; } } i += numberBytesInChar - 1; // increment i to the next utf8 character start position. } } return nonAsciiDetected; } /** * This uses the implicit 'unicode marker' at the start of a * Unicode file to determine whether a file is a unicode file. * At the beginning of every unicode file is a two byte code * indicating the endien-ness of the file (either FFFE or FEFF). * If either of these sequences is found, this function returns * true, otherwise it returns false. <i>Technically</i> this isn't * a sure test, since a) something else could have this signiture, * and b) unicode files are not absolutely required to have this * signiture (but most do). */ public static boolean isUnicode(byte[] sequence) { if (sequence.length>=2) { if (sequence[0] == (byte)0xFF && sequence[1] == (byte)0xFE) { return true; } if (sequence[0] == (byte)0xFE && sequence[1] == (byte)0xFF) { return true; } } return false; } /* * Some refugees from com.ca.pki.util.StaticUtil */ /** * Show file chooser to get a file location for saving data. */ public static String chooseFileToSave(Component parent, String title, String[] filter, String fileType) { JFileChooser chooser = new JFileChooser(System.getProperty("PKIHOME")); chooser.setToolTipText(title); chooser.setDialogTitle(title); if (filter != null && fileType != null) { CBFileFilter filt = new CBFileFilter(filter, fileType); chooser.setFileFilter(filt); } int returnVal = chooser.showSaveDialog(parent); if (returnVal == JFileChooser.APPROVE_OPTION) { if (chooser.getSelectedFile() != null) { return chooser.getSelectedFile().toString(); } } return null; } public static boolean okToWriteFile(Frame parent, String fileName) { File f = new File(fileName); if (f.isDirectory()) { JOptionPane.showMessageDialog(parent, fileName + " is a directory.", "Error!", JOptionPane.ERROR_MESSAGE); return false; } else if (f.exists()) { int saveAnswer = JOptionPane.showConfirmDialog(parent, "File " + fileName + " already exists.\nDo you want to overwrite?", "Question", JOptionPane.OK_CANCEL_OPTION); if (saveAnswer == JOptionPane.OK_OPTION) { return true; } else { return false; } } return true; } /** * This Comparator compares two strings, ignoring case. * @author Trudi. */ public static class IgnoreCaseStringComparator implements Comparator { /** * This Comparator compares two strings, ignoring case. * @param o1 one of the two items to be compared. * @param o2 the other of the items to be compared. * @return the result of the compare (0 if o1 & o2 are equal, -1 if o1 < o2, 1 if o1 > o2). * NOTE: if o1 is null and o2 is not null, 1 is returned. If o2 is null and o1 is not null, -1 is returned. * If both o1 and o2 are null, 0 is returned. If an error occurs trying to cast either o1 or o2, 0 is returned. */ public int compare(Object o1, Object o2) { if (o1 == null && o2 != null) { return 1; } else if (o2 == null && o1 != null) { return -1; } else if (o1 == null && o2 == null) { return 0; } try { return (o1.toString().toLowerCase()).compareTo(o2.toString().toLowerCase()); } catch(ClassCastException e) { System.out.println("Error sorting values - invalid string in sort." + e); return 0; } } } }