001: package net.sourceforge.squirrel_sql.fw.datasetviewer.cellcomponent;
002:
003: /*
004: * Copyright (C) 2001-2003 Colin Bell
005: * colbell@users.sourceforge.net
006: *
007: * This library is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU Lesser General Public
009: * License as published by the Free Software Foundation; either
010: * version 2.1 of the License, or (at your option) any later version.
011: *
012: * This library is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this library; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020: */
021:
022: /**
023: * @author gwg
024: *
025: * This encapsulates the functions of converting binary data
026: * (held as an array of Bytes)
027: * into a string for display, and converting a string from a display
028: * into an array of Bytes.
029: * Both operations allow for the string to be "<null>".
030: * Both operations allow for hex, octal, decimal or binary representation.
031: * Both operations allow for individual bytes that represent ascii characters
032: * to be displayed as that ascii char rather than as the binary representation.
033: * <P>
034: * These functions are entirely static since all parameters are handed in
035: * each time they are called, so there is no need for any instances of this
036: * class to ever be created.
037: */
038: public class BinaryDisplayConverter {
039:
040: /**
041: * Use Hexidecimal representation
042: */
043: public static final int HEX = 16;
044:
045: /**
046: * Use decimal representation.
047: */
048: public static final int DECIMAL = 10;
049:
050: /**
051: * Use Octal representation.
052: */
053: public static final int OCTAL = 8;
054:
055: /**
056: * Use Binary representation.
057: */
058: public static final int BINARY = 2;
059:
060: /*
061: * Conversion Constants
062: */
063: static class ConversionConstants {
064: int width; // number of chars used to represent byte
065: int radix; // the base radix
066:
067: ConversionConstants(int w, int r) {
068: width = w;
069: radix = r;
070: }
071: }
072:
073: static ConversionConstants hex = new ConversionConstants(2, 16);
074: static ConversionConstants decimal = new ConversionConstants(3, 10);
075: private static ConversionConstants octal = new ConversionConstants(
076: 3, 8);
077: private static ConversionConstants binary = new ConversionConstants(
078: 8, 2);
079:
080: /**
081: * List of characters considered "printable".
082: */
083: private static String printable = "0123456789abcdefghijklmnopqrstuvwxyz"
084: + "ABCDEFGHIJKLMNOPQRSTUVWXYZ`~!@#$%^&*()-_=+[{]}\\|;:'\",<.>/?";
085:
086: /**
087: * Do not allow any instances to be created.
088: */
089: private BinaryDisplayConverter() {
090: }
091:
092: /**
093: * Convert from an array of Bytes into a string.
094: */
095: public static String convertToString(Byte[] data, int base,
096: boolean showAscii) {
097:
098: // handle null
099: if (data == null)
100: return null;
101:
102: StringBuffer buf = new StringBuffer();
103:
104: ConversionConstants convConst = getConstants(base);
105:
106: // Convert each byte and put into string buffer
107: for (int i = 0; i < data.length; i++) {
108: int value = data[i].byteValue();
109: String s = null;
110:
111: // if user wants to see ASCII chars as characters,
112: // see if this is one that should be displayed that way
113: if (showAscii) {
114: if (printable.indexOf((char) value) > -1) {
115: s = Character.valueOf((char) value)
116: + " "
117: .substring(10 - (convConst.width - 1));
118: }
119: }
120:
121: // if use is not looking for ASCII chars, or if this one is one that
122: // is not printable, then convert it into numeric form
123: if (s == null) {
124: switch (base) {
125: case DECIMAL:
126: // convert signed to unsigned
127: if (value < 0)
128: value = 256 + value;
129: s = Integer.toString(value);
130: break;
131: case OCTAL:
132: s = Integer.toOctalString(value);
133: break;
134: case BINARY:
135: s = Integer.toBinaryString(value);
136: break;
137: case HEX: // fall through to default
138: default:
139: s = Integer.toHexString(value);
140: }
141: // some formats (e.g. hex & octal) extend a negative number to multiple places
142: // (e.g. FC becomes FFFC), so chop off extra stuff in front
143: if (s.length() > convConst.width)
144: s = s.substring(s.length() - convConst.width);
145:
146: // front pad with zeros and add to output
147: if (s.length() < convConst.width)
148: buf.append("00000000"
149: .substring(8 - (convConst.width - s
150: .length())));
151: }
152: buf.append(s);
153: buf.append(" "); // always add spaces at end for consistancy
154: }
155: return buf.toString();
156: }
157:
158: /**
159: * Convert a string into Bytes. The string is assumed to be in
160: * the form generated by the convertToString function, with each
161: * byte's data space separated from each other byte's.
162: */
163: public static Byte[] convertToBytes(String data, int base,
164: boolean showAscii) throws NumberFormatException {
165:
166: ConversionConstants convConst = getConstants(base);
167:
168: if (data == null)
169: return null;
170:
171: if (data.length() == 0)
172: return new Byte[0];
173:
174: if (data.equals("<null>"))
175: return null;
176:
177: int stringIndex = 0;
178: int byteIndex = 0;
179: Byte[] bytes = new Byte[(data.length() + 2)
180: / (convConst.width + 2)];
181: while (stringIndex < data.length()) {
182: // get the text to be converted
183: String s = data.substring(stringIndex, stringIndex
184: + convConst.width);
185:
186: // handle ASCII chars
187: // Irrespective of the radix, the second byte will always
188: // be a space when the data is displayed as a single ASCII character.
189: if (showAscii && s.charAt(1) == ' ') {
190: // convert the char into its numeric value
191: bytes[byteIndex++] = Byte.valueOf((byte) s.charAt(0));
192: } else {
193:
194: // The following ugly conversion from text to Byte is necessary because
195: // the Byte class is inconsistant. When asked to output as Hex, it does
196: // so as an UNSIGNED byte, but when asked to read back the same thing
197: // using the Hex radix, it insists that the input must be SIGNED.
198: // To get around this, we up-size the conversion to Integer, then
199: // truncate that to a byte, and finally convert the byte to a Byte. Yech.
200: bytes[byteIndex++] = Byte.valueOf((byte) (Integer
201: .valueOf(s, convConst.radix)).intValue());
202: }
203:
204: stringIndex += convConst.width + 2;
205: }
206:
207: return bytes;
208: }
209:
210: /**
211: * Get the constants to use for the given base.
212: */
213: private static ConversionConstants getConstants(int base) {
214: if (base == HEX)
215: return hex;
216: if (base == DECIMAL)
217: return decimal;
218: if (base == OCTAL)
219: return octal;
220: if (base == BINARY)
221: return binary;
222: return hex; // default to hex if unknown base passed in
223: }
224: }
|