3

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

サンプル.pdfファイルはBinHexecodeです。ファイルをデコードしたい。

4

1 に答える 1

3

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

}
于 2012-09-28T21:39:17.930 に答える