2004-04-09 09:05:39 -04:00
|
|
|
|
|
|
|
/* ====================================================================
|
|
|
|
Copyright 2002-2004 Apache Software Foundation
|
|
|
|
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
you may not use this file except in compliance with the License.
|
|
|
|
You may obtain a copy of the License at
|
|
|
|
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
See the License for the specific language governing permissions and
|
|
|
|
limitations under the License.
|
|
|
|
==================================================================== */
|
|
|
|
|
2002-02-13 23:00:59 -05:00
|
|
|
package org.apache.poi.hpsf;
|
|
|
|
|
2003-09-04 16:15:24 -04:00
|
|
|
import java.io.IOException;
|
|
|
|
import java.io.PrintWriter;
|
|
|
|
import java.io.StringWriter;
|
2003-08-03 16:16:46 -04:00
|
|
|
import java.util.Collection;
|
2003-08-02 15:02:28 -04:00
|
|
|
import java.util.Date;
|
2002-02-13 23:00:59 -05:00
|
|
|
|
|
|
|
/**
|
2003-02-01 08:28:28 -05:00
|
|
|
* <p>Provides various static utility methods.</p>
|
2002-05-11 10:47:24 -04:00
|
|
|
*
|
2003-02-01 08:28:28 -05:00
|
|
|
* @author Rainer Klute (klute@rainer-klute.de)
|
|
|
|
* @version $Id$
|
|
|
|
* @since 2002-02-09
|
2002-02-13 23:00:59 -05:00
|
|
|
*/
|
2003-02-01 08:28:28 -05:00
|
|
|
public class Util
|
|
|
|
{
|
2002-02-13 23:00:59 -05:00
|
|
|
|
|
|
|
/**
|
2003-02-01 08:28:28 -05:00
|
|
|
* <p>Checks whether two byte arrays <var>a</var> and <var>b</var>
|
|
|
|
* are equal. They are equal</p>
|
2002-05-11 10:47:24 -04:00
|
|
|
*
|
2003-02-01 08:28:28 -05:00
|
|
|
* <ul>
|
2002-05-11 10:47:24 -04:00
|
|
|
*
|
2003-02-01 08:28:28 -05:00
|
|
|
* <li><p>if they have the same length and</p></li>
|
2002-05-11 10:47:24 -04:00
|
|
|
*
|
2003-02-01 08:28:28 -05:00
|
|
|
* <li><p>if for each <var>i</var> with
|
|
|
|
* <var>i</var> >= 0 and
|
|
|
|
* <var>i</var> < <var>a.length</var> holds
|
2003-08-30 05:13:53 -04:00
|
|
|
* <var>a</var>[<var>i</var>] == <var>b</var>[<var>i</var>].</p></li>
|
2002-02-13 23:00:59 -05:00
|
|
|
*
|
2003-02-01 08:28:28 -05:00
|
|
|
* </ul>
|
2002-02-13 23:00:59 -05:00
|
|
|
*
|
2003-02-01 08:28:28 -05:00
|
|
|
* @param a The first byte array
|
|
|
|
* @param b The first byte array
|
|
|
|
* @return <code>true</code> if the byte arrays are equal, else
|
|
|
|
* <code>false</code>
|
2002-02-13 23:00:59 -05:00
|
|
|
*/
|
2003-02-01 08:28:28 -05:00
|
|
|
public static boolean equal(final byte[] a, final byte[] b)
|
|
|
|
{
|
|
|
|
if (a.length != b.length)
|
2002-02-13 23:00:59 -05:00
|
|
|
return false;
|
2003-08-02 15:02:28 -04:00
|
|
|
for (int i = 0; i < a.length; i++)
|
2003-02-01 08:28:28 -05:00
|
|
|
if (a[i] != b[i])
|
2002-02-13 23:00:59 -05:00
|
|
|
return false;
|
2003-08-02 15:02:28 -04:00
|
|
|
return true;
|
2002-02-13 23:00:59 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2003-02-01 08:28:28 -05:00
|
|
|
* <p>Copies a part of a byte array into another byte array.</p>
|
2002-05-11 10:47:24 -04:00
|
|
|
*
|
2003-02-01 08:28:28 -05:00
|
|
|
* @param src The source byte array.
|
|
|
|
* @param srcOffset Offset in the source byte array.
|
|
|
|
* @param length The number of bytes to copy.
|
|
|
|
* @param dst The destination byte array.
|
|
|
|
* @param dstOffset Offset in the destination byte array.
|
2002-02-13 23:00:59 -05:00
|
|
|
*/
|
|
|
|
public static void copy(final byte[] src, final int srcOffset,
|
2003-08-02 15:02:28 -04:00
|
|
|
final int length, final byte[] dst,
|
|
|
|
final int dstOffset)
|
2003-02-01 08:28:28 -05:00
|
|
|
{
|
|
|
|
for (int i = 0; i < length; i++)
|
2002-02-13 23:00:59 -05:00
|
|
|
dst[dstOffset + i] = src[srcOffset + i];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2003-02-01 08:28:28 -05:00
|
|
|
* <p>Concatenates the contents of several byte arrays into a
|
|
|
|
* single one.</p>
|
2002-02-13 23:00:59 -05:00
|
|
|
*
|
2003-02-01 08:28:28 -05:00
|
|
|
* @param byteArrays The byte arrays to be concatened.
|
|
|
|
* @return A new byte array containing the concatenated byte
|
|
|
|
* arrays.
|
2002-02-13 23:00:59 -05:00
|
|
|
*/
|
2003-02-01 08:28:28 -05:00
|
|
|
public static byte[] cat(final byte[][] byteArrays)
|
|
|
|
{
|
2002-02-13 23:00:59 -05:00
|
|
|
int capacity = 0;
|
2003-02-01 08:28:28 -05:00
|
|
|
for (int i = 0; i < byteArrays.length; i++)
|
2002-02-13 23:00:59 -05:00
|
|
|
capacity += byteArrays[i].length;
|
2003-08-02 15:02:28 -04:00
|
|
|
final byte[] result = new byte[capacity];
|
2002-02-13 23:00:59 -05:00
|
|
|
int r = 0;
|
2003-02-01 08:28:28 -05:00
|
|
|
for (int i = 0; i < byteArrays.length; i++)
|
|
|
|
for (int j = 0; j < byteArrays[i].length; j++)
|
2002-02-13 23:00:59 -05:00
|
|
|
result[r++] = byteArrays[i][j];
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2003-02-01 08:28:28 -05:00
|
|
|
* <p>Copies bytes from a source byte array into a new byte
|
|
|
|
* array.</p>
|
2002-02-13 23:00:59 -05:00
|
|
|
*
|
2003-02-01 08:28:28 -05:00
|
|
|
* @param src Copy from this byte array.
|
|
|
|
* @param offset Start copying here.
|
|
|
|
* @param length Copy this many bytes.
|
|
|
|
* @return The new byte array. Its length is number of copied bytes.
|
2002-02-13 23:00:59 -05:00
|
|
|
*/
|
|
|
|
public static byte[] copy(final byte[] src, final int offset,
|
2003-08-02 15:02:28 -04:00
|
|
|
final int length)
|
2003-02-01 08:28:28 -05:00
|
|
|
{
|
2002-02-13 23:00:59 -05:00
|
|
|
final byte[] result = new byte[length];
|
|
|
|
copy(src, offset, length, result, 0);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2003-02-01 08:28:28 -05:00
|
|
|
* <p>The difference between the Windows epoch (1601-01-01
|
|
|
|
* 00:00:00) and the Unix epoch (1970-01-01 00:00:00) in
|
|
|
|
* milliseconds: 11644473600000L. (Use your favorite spreadsheet
|
|
|
|
* program to verify the correctness of this value. By the way,
|
|
|
|
* did you notice that you can tell from the epochs which
|
|
|
|
* operating system is the modern one? :-))</p>
|
2002-02-13 23:00:59 -05:00
|
|
|
*/
|
2003-08-02 15:02:28 -04:00
|
|
|
public static final long EPOCH_DIFF = 11644473600000L;
|
2002-02-13 23:00:59 -05:00
|
|
|
|
2002-05-11 10:47:24 -04:00
|
|
|
|
2002-02-13 23:00:59 -05:00
|
|
|
/**
|
2003-02-01 08:28:28 -05:00
|
|
|
* <p>Converts a Windows FILETIME into a {@link Date}. The Windows
|
|
|
|
* FILETIME structure holds a date and time associated with a
|
|
|
|
* file. The structure identifies a 64-bit integer specifying the
|
|
|
|
* number of 100-nanosecond intervals which have passed since
|
|
|
|
* January 1, 1601. This 64-bit value is split into the two double
|
2003-02-13 11:57:39 -05:00
|
|
|
* words stored in the structure.</p>
|
2002-02-13 23:00:59 -05:00
|
|
|
*
|
2003-02-01 08:28:28 -05:00
|
|
|
* @param high The higher double word of the FILETIME structure.
|
|
|
|
* @param low The lower double word of the FILETIME structure.
|
|
|
|
* @return The Windows FILETIME as a {@link Date}.
|
2002-02-13 23:00:59 -05:00
|
|
|
*/
|
2003-02-01 08:28:28 -05:00
|
|
|
public static Date filetimeToDate(final int high, final int low)
|
|
|
|
{
|
2003-02-13 11:57:39 -05:00
|
|
|
final long filetime = ((long) high) << 32 | (low & 0xffffffffL);
|
2002-02-13 23:00:59 -05:00
|
|
|
final long ms_since_16010101 = filetime / (1000 * 10);
|
|
|
|
final long ms_since_19700101 = ms_since_16010101 - EPOCH_DIFF;
|
|
|
|
return new Date(ms_since_19700101);
|
|
|
|
}
|
|
|
|
|
2003-08-30 05:13:53 -04:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* <p>Converts a {@link Date} into a filetime.</p>
|
|
|
|
*
|
|
|
|
* @param date The date to be converted
|
|
|
|
* @return The filetime
|
|
|
|
*
|
|
|
|
* @see #filetimeToDate
|
|
|
|
*/
|
2003-08-23 11:12:22 -04:00
|
|
|
public static long dateToFileTime(final Date date)
|
|
|
|
{
|
|
|
|
long ms_since_19700101 = date.getTime();
|
|
|
|
long ms_since_16010101 = ms_since_19700101 + EPOCH_DIFF;
|
|
|
|
return ms_since_16010101 * (1000 * 10);
|
|
|
|
}
|
2003-08-03 16:16:46 -04:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* <p>Checks whether two collections are equal. Two collections
|
|
|
|
* C<sub>1</sub> and C<sub>2</sub> are equal, if the following conditions
|
|
|
|
* are true:</p>
|
|
|
|
*
|
|
|
|
* <ul>
|
|
|
|
*
|
|
|
|
* <li><p>For each c<sub>1<em>i</em></sub> (element of C<sub>1</sub>) there
|
|
|
|
* is a c<sub>2<em>j</em></sub> (element of C<sub>2</sub>), and
|
|
|
|
* c<sub>1<em>i</em></sub> equals c<sub>2<em>j</em></sub>.</p></li>
|
|
|
|
*
|
|
|
|
* <li><p>For each c<sub>2<em>i</em></sub> (element of C<sub>2</sub>) there
|
|
|
|
* is a c<sub>1<em>j</em></sub> (element of C<sub>1</sub>) and
|
|
|
|
* c<sub>2<em>i</em></sub> equals c<sub>1<em>j</em></sub>.</p></li>
|
|
|
|
*
|
|
|
|
* </ul>
|
|
|
|
*
|
|
|
|
* @param c1 the first collection
|
|
|
|
* @param c2 the second collection
|
|
|
|
* @return <code>true</code> if the collections are equal, else
|
|
|
|
* <code>false</code>.
|
|
|
|
*/
|
|
|
|
public static boolean equals(final Collection c1, final Collection c2)
|
|
|
|
{
|
|
|
|
final Object[] o1 = c1.toArray();
|
|
|
|
final Object[] o2 = c2.toArray();
|
|
|
|
return internalEquals(o1, o2);
|
|
|
|
}
|
|
|
|
|
2003-08-30 05:13:53 -04:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* <p>Compares to object arrays with regarding the objects' order. For
|
|
|
|
* example, [1, 2, 3] and [2, 1, 3] are equal.</p>
|
|
|
|
*
|
|
|
|
* @param c1 The first object array.
|
|
|
|
* @param c2 The second object array.
|
|
|
|
* @return <code>true</code> if the object arrays are equal,
|
|
|
|
* <code>false</code> if they are not.
|
|
|
|
*/
|
2003-08-03 16:16:46 -04:00
|
|
|
public static boolean equals(final Object[] c1, final Object[] c2)
|
|
|
|
{
|
|
|
|
final Object[] o1 = (Object[]) c1.clone();
|
|
|
|
final Object[] o2 = (Object[]) c2.clone();
|
|
|
|
return internalEquals(o1, o2);
|
|
|
|
}
|
|
|
|
|
|
|
|
private static boolean internalEquals(final Object[] o1, final Object[] o2)
|
|
|
|
{
|
|
|
|
for (int i1 = 0; i1 < o1.length; i1++)
|
|
|
|
{
|
2003-09-20 11:43:08 -04:00
|
|
|
final Object obj1 = o1[i1];
|
2003-08-03 16:16:46 -04:00
|
|
|
boolean matchFound = false;
|
|
|
|
for (int i2 = 0; !matchFound && i2 < o1.length; i2++)
|
2003-09-20 11:43:08 -04:00
|
|
|
{
|
|
|
|
final Object obj2 = o2[i2];
|
|
|
|
if (obj1.equals(obj2))
|
2003-08-03 16:16:46 -04:00
|
|
|
{
|
|
|
|
matchFound = true;
|
|
|
|
o2[i2] = null;
|
|
|
|
}
|
2003-09-20 11:43:08 -04:00
|
|
|
}
|
2003-08-03 16:16:46 -04:00
|
|
|
if (!matchFound)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2003-08-30 05:13:53 -04:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* <p>Pads a byte array with 0x00 bytes so that its length is a multiple of
|
|
|
|
* 4.</p>
|
|
|
|
*
|
|
|
|
* @param ba The byte array to pad.
|
|
|
|
* @return The padded byte array.
|
|
|
|
*/
|
|
|
|
public static byte[] pad4(final byte[] ba)
|
|
|
|
{
|
|
|
|
final int PAD = 4;
|
|
|
|
final byte[] result;
|
|
|
|
int l = ba.length % PAD;
|
|
|
|
if (l == 0)
|
|
|
|
result = ba;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
l = PAD - l;
|
|
|
|
result = new byte[ba.length + l];
|
|
|
|
System.arraycopy(ba, 0, result, 0, ba.length);
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* <p>Pads a character array with 0x0000 characters so that its length is a
|
|
|
|
* multiple of 4.</p>
|
|
|
|
*
|
|
|
|
* @param ca The character array to pad.
|
|
|
|
* @return The padded character array.
|
|
|
|
*/
|
|
|
|
public static char[] pad4(final char[] ca)
|
|
|
|
{
|
|
|
|
final int PAD = 4;
|
|
|
|
final char[] result;
|
|
|
|
int l = ca.length % PAD;
|
|
|
|
if (l == 0)
|
|
|
|
result = ca;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
l = PAD - l;
|
|
|
|
result = new char[ca.length + l];
|
|
|
|
System.arraycopy(ca, 0, result, 0, ca.length);
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* <p>Pads a string with 0x0000 characters so that its length is a
|
|
|
|
* multiple of 4.</p>
|
|
|
|
*
|
|
|
|
* @param s The string to pad.
|
|
|
|
* @return The padded string as a character array.
|
|
|
|
*/
|
|
|
|
public static char[] pad4(final String s)
|
|
|
|
{
|
|
|
|
return pad4(s.toCharArray());
|
|
|
|
}
|
|
|
|
|
2003-09-04 16:15:24 -04:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* <p>Returns a textual representation of a {@link Throwable}, including a
|
|
|
|
* stacktrace.</p>
|
|
|
|
*
|
|
|
|
* @param t The {@link Throwable}
|
|
|
|
*
|
|
|
|
* @return a string containing the output of a call to
|
|
|
|
* <code>t.printStacktrace()</code>.
|
|
|
|
*/
|
|
|
|
public static String toString(final Throwable t)
|
|
|
|
{
|
|
|
|
final StringWriter sw = new StringWriter();
|
|
|
|
final PrintWriter pw = new PrintWriter(sw);
|
|
|
|
t.printStackTrace(pw);
|
|
|
|
pw.close();
|
|
|
|
try
|
|
|
|
{
|
|
|
|
sw.close();
|
|
|
|
return sw.toString();
|
|
|
|
}
|
|
|
|
catch (IOException e)
|
|
|
|
{
|
|
|
|
final StringBuffer b = new StringBuffer(t.getMessage());
|
|
|
|
b.append("\n");
|
|
|
|
b.append("Could not create a stacktrace. Reason: ");
|
|
|
|
b.append(e.getMessage());
|
|
|
|
return b.toString();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-02-13 23:00:59 -05:00
|
|
|
}
|