使用Java将BinHex文件转换为普通文件 [英] Converting BinHex file to normal file using Java

查看:273
本文介绍了使用Java将BinHex文件转换为普通文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个Binhex文件。该文件应使用Java代码转换为普通可读文件。
我在这里找到了类似的问题,

I have a binhex file. This file should be converted to normal readable file using java code. I found a similar question here,

使用Java代码进行Binhex解码

但是答案不起作用。

我尝试使用Base64,文件被转换为其他人类无法读取的格式。

I tried Base64, the file is converted to some other format which is not human readable.

请帮助我要解决此问题。

Please help me to resolve this issue.

我尝试过的代码如下

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 < bytes.length && (numRead=is.read(bytes, offset, bytes.length-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。我希望文件被解码。

The file Sample.pdf is BinHex ecoded. I want the file to be decoded.

推荐答案

与Base64的区别



根据我在网上找到的内容,可以使用 BinHex 格式的不同版本。它们都不与 Base64 完全相同。但是,有很多相似之处。以 BinHex 4.0规范为例,我们发现二进制内容使用以64为底的编码方案进行编码,因此将3个八位位组编码为4个字符。

Difference to Base64

From what I find online, there are different versions of the BinHex format. None of them is exactly the same as Base64. There are however major similarities. Taking for example the BinHex 4.0 specs, we see that the major binary content is encoded using an encoding scheme with base 64, thus encoing 3 octets to 4 characters. It uses a different alphabet, though:

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

$要么必须将一组字符转换为另一组字符,要么自己解码。

So you'd either have to translate from one set of characters to the other, or do the decoding yourself.

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

Apart from the bulk of the binary content, there is some additional meta data included in the format. According to the spec, that includes delimiters between data and resource fork content, checksums, and some other bits of information.

以下代码将解码BinHex输入文件并将其数据派生到输出文件中。应该很容易地根据您的需要调整此代码。

The following code will decode a BinHex input file and write its data fork to an output file. It should be easy enough to adjust this code to your needs.

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);
    }

}

这篇关于使用Java将BinHex文件转换为普通文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆