001: /*
002: Copyright (c) 2005 Health Market Science, Inc.
003:
004: This library is free software; you can redistribute it and/or
005: modify it under the terms of the GNU Lesser General Public
006: License as published by the Free Software Foundation; either
007: version 2.1 of the License, or (at your option) any later version.
008:
009: This library is distributed in the hope that it will be useful,
010: but WITHOUT ANY WARRANTY; without even the implied warranty of
011: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012: Lesser General Public License for more details.
013:
014: You should have received a copy of the GNU Lesser General Public
015: License along with this library; if not, write to the Free Software
016: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
017: USA
018:
019: You can contact Health Market Science at info@healthmarketscience.com
020: or at the following address:
021:
022: Health Market Science
023: 2700 Horizon Drive
024: Suite 200
025: King of Prussia, PA 19406
026: */
027:
028: package com.healthmarketscience.jackcess;
029:
030: import java.io.FileWriter;
031: import java.io.IOException;
032: import java.io.PrintWriter;
033: import java.nio.ByteBuffer;
034: import java.nio.ByteOrder;
035:
036: /**
037: * Byte manipulation and display utilities
038: * @author Tim McCune
039: */
040: public final class ByteUtil {
041:
042: private static final String[] HEX_CHARS = new String[] { "0", "1",
043: "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D",
044: "E", "F" };
045:
046: private ByteUtil() {
047: }
048:
049: /**
050: * Put an integer into the given buffer at the given offset as a 3-byte
051: * integer.
052: * @param buffer buffer into which to insert the int
053: * @param val Int to convert
054: */
055: public static void put3ByteInt(ByteBuffer buffer, int val) {
056: put3ByteInt(buffer, val, buffer.order());
057: }
058:
059: /**
060: * Put an integer into the given buffer at the given offset as a 3-byte
061: * integer.
062: * @param buffer buffer into which to insert the int
063: * @param val Int to convert
064: * @param order the order to insert the bytes of the int
065: */
066: public static void put3ByteInt(ByteBuffer buffer, int val,
067: ByteOrder order) {
068: int pos = buffer.position();
069: put3ByteInt(buffer, val, pos, order);
070: buffer.position(pos + 3);
071: }
072:
073: /**
074: * Put an integer into the given buffer at the given offset as a 3-byte
075: * integer.
076: * @param buffer buffer into which to insert the int
077: * @param val Int to convert
078: * @param offset offset at which to insert the int
079: * @param order the order to insert the bytes of the int
080: */
081: public static void put3ByteInt(ByteBuffer buffer, int val,
082: int offset, ByteOrder order) {
083:
084: int offInc = 1;
085: if (order == ByteOrder.BIG_ENDIAN) {
086: offInc = -1;
087: offset += 2;
088: }
089:
090: buffer.put(offset, (byte) (val & 0xFF));
091: buffer.put(offset + (1 * offInc), (byte) ((val >>> 8) & 0xFF));
092: buffer.put(offset + (2 * offInc), (byte) ((val >>> 16) & 0xFF));
093: }
094:
095: /**
096: * Read a 3 byte int from a buffer
097: * @param buffer Buffer containing the bytes
098: * @return The int
099: */
100: public static int get3ByteInt(ByteBuffer buffer) {
101: return get3ByteInt(buffer, buffer.order());
102: }
103:
104: /**
105: * Read a 3 byte int from a buffer
106: * @param buffer Buffer containing the bytes
107: * @param order the order of the bytes of the int
108: * @return The int
109: */
110: public static int get3ByteInt(ByteBuffer buffer, ByteOrder order) {
111: int pos = buffer.position();
112: int rtn = get3ByteInt(buffer, pos, order);
113: buffer.position(pos + 3);
114: return rtn;
115: }
116:
117: /**
118: * Read a 3 byte int from a buffer
119: * @param buffer Buffer containing the bytes
120: * @param offset Offset at which to start reading the int
121: * @return The int
122: */
123: public static int get3ByteInt(ByteBuffer buffer, int offset) {
124: return get3ByteInt(buffer, offset, buffer.order());
125: }
126:
127: /**
128: * Read a 3 byte int from a buffer
129: * @param buffer Buffer containing the bytes
130: * @param offset Offset at which to start reading the int
131: * @param order the order of the bytes of the int
132: * @return The int
133: */
134: public static int get3ByteInt(ByteBuffer buffer, int offset,
135: ByteOrder order) {
136:
137: int offInc = 1;
138: if (order == ByteOrder.BIG_ENDIAN) {
139: offInc = -1;
140: offset += 2;
141: }
142:
143: int rtn = getUnsignedByte(buffer, offset);
144: rtn += (getUnsignedByte(buffer, offset + (1 * offInc)) << 8);
145: rtn += (getUnsignedByte(buffer, offset + (2 * offInc)) << 16);
146: return rtn;
147: }
148:
149: /**
150: * Read a 3 byte int from a buffer
151: * @param buffer Buffer containing the bytes
152: * @return The int
153: */
154: public static int getUnsignedByte(ByteBuffer buffer) {
155: int pos = buffer.position();
156: int rtn = getUnsignedByte(buffer, pos);
157: buffer.position(pos + 1);
158: return rtn;
159: }
160:
161: /**
162: * Read a 3 byte int from a buffer
163: * @param buffer Buffer containing the bytes
164: * @param offset Offset at which to read the byte
165: * @return The int
166: */
167: public static int getUnsignedByte(ByteBuffer buffer, int offset) {
168: return asUnsignedByte(buffer.get(offset));
169: }
170:
171: /**
172: * @param buffer Buffer containing the bytes
173: * @param order the order of the bytes of the int
174: * @return an int from the current position in the given buffer, read using
175: * the given ByteOrder
176: */
177: public static int getInt(ByteBuffer buffer, ByteOrder order) {
178: int offset = buffer.position();
179: int rtn = getInt(buffer, offset, order);
180: buffer.position(offset + 4);
181: return rtn;
182: }
183:
184: /**
185: * @param buffer Buffer containing the bytes
186: * @param offset Offset at which to start reading the int
187: * @param order the order of the bytes of the int
188: * @return an int from the given position in the given buffer, read using
189: * the given ByteOrder
190: */
191: public static int getInt(ByteBuffer buffer, int offset,
192: ByteOrder order) {
193: ByteOrder origOrder = buffer.order();
194: try {
195: return buffer.order(order).getInt(offset);
196: } finally {
197: buffer.order(origOrder);
198: }
199: }
200:
201: /**
202: * Writes an int at the current position in the given buffer, using the
203: * given ByteOrder
204: * @param buffer buffer into which to insert the int
205: * @param val Int to insert
206: * @param order the order to insert the bytes of the int
207: */
208: public static void putInt(ByteBuffer buffer, int val,
209: ByteOrder order) {
210: int offset = buffer.position();
211: putInt(buffer, val, offset, order);
212: buffer.position(offset + 4);
213: }
214:
215: /**
216: * Writes an int at the given position in the given buffer, using the
217: * given ByteOrder
218: * @param buffer buffer into which to insert the int
219: * @param val Int to insert
220: * @param offset offset at which to insert the int
221: * @param order the order to insert the bytes of the int
222: */
223: public static void putInt(ByteBuffer buffer, int val, int offset,
224: ByteOrder order) {
225: ByteOrder origOrder = buffer.order();
226: try {
227: buffer.order(order).putInt(offset, val);
228: } finally {
229: buffer.order(origOrder);
230: }
231: }
232:
233: /**
234: * Sets all bits in the given byte range to 0.
235: */
236: public static void clearRange(ByteBuffer buffer, int start, int end) {
237: putRange(buffer, start, end, (byte) 0x00);
238: }
239:
240: /**
241: * Sets all bits in the given byte range to 1.
242: */
243: public static void fillRange(ByteBuffer buffer, int start, int end) {
244: putRange(buffer, start, end, (byte) 0xff);
245: }
246:
247: /**
248: * Sets all bytes in the given byte range to the given byte value.
249: */
250: public static void putRange(ByteBuffer buffer, int start, int end,
251: byte b) {
252: for (int i = start; i < end; ++i) {
253: buffer.put(i, b);
254: }
255: }
256:
257: /**
258: * Matches a pattern of bytes against the given buffer starting at the given
259: * offset.
260: */
261: public static boolean matchesRange(ByteBuffer buffer, int start,
262: byte[] pattern) {
263: for (int i = 0; i < pattern.length; ++i) {
264: if (pattern[i] != buffer.get(start + i)) {
265: return false;
266: }
267: }
268: return true;
269: }
270:
271: /**
272: * Convert a byte buffer to a hexadecimal string for display
273: * @param buffer Buffer to display, starting at offset 0
274: * @param size Number of bytes to read from the buffer
275: * @return The display String
276: */
277: public static String toHexString(ByteBuffer buffer, int size) {
278: return toHexString(buffer, 0, size);
279: }
280:
281: /**
282: * Convert a byte array to a hexadecimal string for display
283: * @param buffer Buffer to display, starting at offset 0
284: * @return The display String
285: */
286: public static String toHexString(byte[] array) {
287: return toHexString(ByteBuffer.wrap(array), 0, array.length);
288: }
289:
290: /**
291: * Convert a byte buffer to a hexadecimal string for display
292: * @param buffer Buffer to display, starting at offset 0
293: * @param offset Offset at which to start reading the buffer
294: * @param size Number of bytes to read from the buffer
295: * @return The display String
296: */
297: public static String toHexString(ByteBuffer buffer, int offset,
298: int size) {
299: return toHexString(buffer, offset, size, true);
300: }
301:
302: /**
303: * Convert a byte buffer to a hexadecimal string for display
304: * @param buffer Buffer to display, starting at offset 0
305: * @param offset Offset at which to start reading the buffer
306: * @param size Number of bytes to read from the buffer
307: * @param formatted flag indicating if formatting is required
308: * @return The display String
309: */
310: public static String toHexString(ByteBuffer buffer, int offset,
311: int size, boolean formatted) {
312:
313: StringBuilder rtn = new StringBuilder();
314: int position = buffer.position();
315: buffer.position(offset);
316:
317: for (int i = 0; i < size; i++) {
318: byte b = buffer.get();
319: byte h = (byte) (b & 0xF0);
320: h = (byte) (h >>> 4);
321: h = (byte) (h & 0x0F);
322: rtn.append(HEX_CHARS[h]);
323: h = (byte) (b & 0x0F);
324: rtn.append(HEX_CHARS[h]);
325:
326: if (formatted == true) {
327: rtn.append(" ");
328:
329: if ((i + 1) % 4 == 0) {
330: rtn.append(" ");
331: }
332: if ((i + 1) % 24 == 0) {
333: rtn.append("\n");
334: }
335: }
336: }
337:
338: buffer.position(position);
339: return rtn.toString();
340: }
341:
342: /**
343: * Writes a sequence of hexidecimal values into the given buffer, where
344: * every two characters represent one byte value.
345: */
346: public static void writeHexString(ByteBuffer buffer, String hexStr)
347: throws IOException {
348: char[] hexChars = hexStr.toCharArray();
349: if ((hexChars.length % 2) != 0) {
350: throw new IOException("Hex string length must be even");
351: }
352: for (int i = 0; i < hexChars.length; i += 2) {
353: String tmpStr = new String(hexChars, i, 2);
354: buffer.put((byte) Long.parseLong(tmpStr, 16));
355: }
356: }
357:
358: /**
359: * Writes a chunk of data to a file in pretty printed hexidecimal.
360: */
361: public static void toHexFile(String fileName, ByteBuffer buffer,
362: int offset, int size) throws IOException {
363: PrintWriter writer = new PrintWriter(new FileWriter(fileName));
364: try {
365: writer.println(toHexString(buffer, offset, size));
366: } finally {
367: writer.close();
368: }
369: }
370:
371: /**
372: * @return the byte value converted to an unsigned int value
373: */
374: public static int asUnsignedByte(byte b) {
375: return b & 0xFF;
376: }
377:
378: }
|