使用Java将BinHex文件转换为普通文件

我有一个binhex文件。 应使用java代码将此文件转换为普通可读文件。 我在这里发现了类似的问题,

使用java代码解码Binhex

但答案是行不通的。

我尝试了Base64,该文件被转换为其他一些人类无法读取的格式。

请帮我解决这个问题。

我试过的代码如下

File f = new File("Sample.pdf"); Base64 base64 = new Base64(); byte[] b = base64.decode(getBytesFromFile(f)); FileOutputStream fos = new FileOutputStream("Dcode.pdf"); fos.write(b); fos.close(); public static byte[] getBytesFromFile(File file) throws IOException { InputStream is = new FileInputStream(file); long length = file.length(); byte[] bytes = new byte[(int)length]; int offset = 0; int numRead = 0; while (offset = 0) { offset += numRead; } if (offset < bytes.length) { throw new IOException("Could not completely read file "+file.getName()); } is.close(); return bytes; } 

Sample.pdf文件是BinHex ecoded。 我想要解码文件。

与Base64的区别

从我在网上找到的,有不同版本的BinHex格式。 它们都不是与Base64完全相同。 然而,有很多相似之处。 以BinHex 4.0规范为例,我们看到主要的二进制内容使用带有base 64的编码方案进行编码,从而将3个八位字节编码为4个字符。 但它使用不同的字母表:

 BinHex: !"#$%&'()*+,-012345689@ABCDEFGHIJKLMNPQRSTUVXYZ[`abcdefhijklmpqr Base64: ABCDEFGHIJKLMNOPQERTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ 

所以你要么必须从一组字符转换到另一组字符,要么自己进行解码。

除了大量的二进制内容之外,格式中还包含一些额外的元数据。 根据规范,它包括数据和资源分支内容,校验和以及其他一些信息之间的分隔符。

履行

以下代码将解码BinHex输入文件并将其数据分支写入输出文件。 应该很容易根据您的需要调整此代码。

 import java.io.*; import java.nio.charset.Charset; public class BinHexDec { private Charset charset; private String filename; private int dbegin, dend, rbegin, rend; public BinHexDec(String... args) throws IOException { InputStream in = System.in; OutputStream out = System.out; charset = Charset.defaultCharset(); if (args.length >= 1) in = new FileInputStream(args[0]); if (args.length >= 2) out = new FileOutputStream(args[1]); if (args.length >= 3) charset = Charset.forName(args[2]); Reader reader = new InputStreamReader(in, charset); byte[] data; data = unbase(reader); reader.close(); if (data.length < 27) throw new IOException("Too little data"); data = unrle(data); parse(data); out.write(data, dbegin, dend - dbegin); } private byte[] unbase(Reader in) throws IOException { String digits = "!\"#$%&'()*+,-012345689@ABCDEFGHIJKLMNPQRSTUVXYZ" + "[`abcdefhijklmpqr"; assert digits.length() == (1 << 6); int[] value = new int[128]; for (int i = 0; i < value.length; ++i) value[i] = -1; for (int i = 0; i < digits.length(); ++i) value[digits.charAt(i)] = i; int state = 0; int accum = 0; int alen = 0; ByteArrayOutputStream baos = new ByteArrayOutputStream(); while (true) { int chr = in.read(); if (chr == -1) throw new EOFException(); switch (state) { case 0: switch (chr) { case '\n': case '\r': case '\t': case ' ': state = 1; break; } break; case 1: switch (chr) { case '\n': case '\r': case '\t': case ' ': break; case ':': state = 2; break; default: state = 0; } break; case 2: int v = -1, c = chr & 0x7f; if (c == chr) { v = value[c]; if (v != -1) { accum = (accum << 6) | v; alen += 6; if (alen > 8) { alen -= 8; baos.write((byte)(accum >>> alen)); } break; } } if (chr == ':') { return baos.toByteArray(); } break; } } } private static final byte RLE_MARK = (byte)0x90; private byte[] unrle(byte[] in) throws IOException { int len = in.length; if (in[0] == 0x90) throw new IOException("Incomplete RLE at beginning"); for (int i = 0; i < in.length; ++i) { if (in[i] == RLE_MARK) { ++i; if (i == in.length) throw new IOException("Incomplete RLE at end"); int cnt = in[i] & 0xff; if (cnt == 0) len -= 1; else len += cnt - 3; } } byte[] out = new byte[len]; for (int i = 0, o = 0; i < in.length; ++i) { if (in[i] == RLE_MARK) { ++i; int cnt = in[i] & 0xff; if (cnt == 0) out[o++] = RLE_MARK; else { byte b = out[o - 1]; for (int c = 1; c < cnt; ++c) out[o++] = b; } } else { out[o++] = in[i]; } } return out; } private int get4(byte[] data, int offset) { return ((data[offset ] & 0xff) << 24) | ((data[offset + 1] & 0xff) << 16) | ((data[offset + 2] & 0xff) << 8) | ((data[offset + 3] & 0xff) ); } private int get2(byte[] data, int offset) { return ((data[offset] & 0xff) << 8) | ((data[offset + 1] & 0xff)); } private void crcCheck(byte[] data, int begin, int end) throws IOException { int crc = 0; for (int i = begin; i < end; ++i) { crc = ((crc << 4)&0xffff) ^ (crc >> 12)*0x1021; crc = ((crc << 4)&0xffff) ^ (crc >> 12)*0x1021; crc = crc ^ (data[i] & 0xff); } crc = ((crc << 4)&0xffff) ^ (crc >> 12)*0x1021; crc = ((crc << 4)&0xffff) ^ (crc >> 12)*0x1021; crc = ((crc << 4)&0xffff) ^ (crc >> 12)*0x1021; crc = ((crc << 4)&0xffff) ^ (crc >> 12)*0x1021; int expected = get2(data, end); if (expected != crc) throw new IOException("CRC mismatch"); } private void parse(byte[] in) throws IOException { int namelen = in[0] & 0xff; int headlen = namelen + 20; int dlen = get4(in, headlen - 8); int rlen = get4(in, headlen - 4); if (dlen < 0 || rlen < 0) throw new IOException("Unsigned data lenhgths not supported"); dbegin = headlen + 2; dend = dbegin + dlen; rbegin = dend + 2; rend = rbegin + rlen; if (in.length != rend + 2 && (in.length != rend + 3 || in[rend + 2] != 0)) throw new IOException("Incorrect data size:" + " expected " + (rend + 2) + " but got " + in.length + " bytes"); crcCheck(in, 0, headlen); crcCheck(in, dbegin, dend); crcCheck(in, rbegin, rend); filename = new String(in, 1, namelen, charset); System.err.println(filename); } public static void main(String[] args) throws IOException { new BinHexDec(args); } }