`
RednaxelaFX
  • 浏览: 3052605 次
  • 性别: Icon_minigender_1
  • 来自: 海外
社区版块
存档分类
最新评论

桃華月憚体験版的解压缩程序 (Java)

阅读更多
这是差不多一年前写的程序了……有人说想看于是发出来。
当时也是为了求快,代码结构乱七八糟的。不过现在也没什么时间把这代码重构一次,就这么原样发出来吧。嗯,好歹应该把LZSS、文件IO之类的方法扔到外面去的……后来在处理ケータイ少女啊之类的东西的时候就没这么乱了,不过文件一时找不到了 T T
如果没记错的话当时是直接从BlowfishJ里拿了BinConverter.java来,然后加了些方法进去。因此以下代码以LGPL许可证发布。

哦,对了。解图片出来的时候我偷懒了。32位的BMP图我就这么直接写到文件里了而没做处理——意味着图片是“正向BMP”,有些图片浏览程序打开的时候可能会不太正常……

Extract.java:
import java.io.*;
import java.util.*;

class Extract {
    
    ///////////////////////////
    // Common constants
    ///////////////////////////
    private static final int WINDOW_LENGTH = 4096;
    
    ///////////////////////////
    // Signature constants
    ///////////////////////////
    
    //-------------------------
    // Scr.pak
    //-------------------------
    private static final byte[] scwSig = {
        (byte)'S', (byte)'c', (byte)'w', (byte)'5', (byte)'.', (byte)'x', (byte)0, (byte)0, 
        (byte)0, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0
    };
    
    private static final byte[] unknownSig = {
        (byte)0, (byte)0, (byte)0, (byte)5, (byte)0x0FF, (byte)0x0FF, (byte)0x0FF, (byte)0x0FF
    };
    
    //-------------------------
    // Graphic.pak
    //-------------------------
    private static final byte[] grpSig = {
        (byte)0, (byte)0, (byte)4, (byte)0
    };
    
    //-------------------------
    // BGM.pak, SE.pak
    //-------------------------
    private static final byte[] oggSig = {
        (byte)'O', (byte)'g', (byte)'g', (byte)'S'
    };
    
    
    ///////////////////////////
    // Global variables
    ///////////////////////////
    private static RandomAccessFile raf = null;
    private static BufferedWriter writer = null;
    private static Header header = null;
    private static IndexEntry[] index = null;
    
    ///////////////////////////
    // Program entry point
    ///////////////////////////
    public static void main(String[] args) throws Exception {
        String srcFilename = args[0];
        
        if (srcFilename == null || srcFilename.trim().length() == 0)
            warnAndExit("Usage: java Extract srcFile\nwhere srcFile is the filename of the file to be extracted.");
        
        // read archive header
        FileInputStream tempFis = new FileInputStream(srcFilename);
        byte[] headerBytes = new byte[Header.BUFFER_SIZE];
        tempFis.read(headerBytes);
        tempFis.close();
        tempFis = null; // dispose this input stream
        
        // parse archive header
        parseHeader(headerBytes);
        
        // open source archive file
        raf = new RandomAccessFile(srcFilename, "r");
        
        // read file index
        raf.seek(header.getIndexBaseOffset());
        byte[] indexBytes = new byte[header.getIndexCompSize()];
        raf.read(indexBytes);
        
        // DEBUG ONLY!
        System.err.println("indexCompSize   =0x" + Integer.toHexString(header.getIndexCompSize()).toUpperCase());
        System.err.println("fileCount       =0x" + Integer.toHexString(header.getFileCount()).toUpperCase());
        System.err.println("indexOrigSize   =0x" + Integer.toHexString(IndexEntry.LENGTH_IN_FILE * header.getFileCount()).toUpperCase());
        System.err.println("dataBaseOffset  =0x" + Long.toHexString(header.getDataBaseOffset()).toUpperCase());
        System.err.println("indexBaseOffset =0x" + Long.toHexString(header.getIndexBaseOffset()).toUpperCase());
        System.err.println();
        
        // decompress file index
        indexBytes = lzssDecompress(indexBytes, header.getIndexCompSize(),
            null, IndexEntry.LENGTH_IN_FILE * header.getFileCount());
        
        // parse file index
        parseIndex(indexBytes);
        
        // extract files from archive
        byte[] bytes16 = new byte[16];
        for (IndexEntry entry : index) {
            
            System.err.print("Extracting file " + entry.getFilename()
                + " at 0x" + Long.toHexString(header.getDataBaseOffset() + entry.getOffset()).toUpperCase()
                + "...");
            
            // set file pointer
            raf.seek(header.getDataBaseOffset() + entry.getOffset());
            
            // read signature
            raf.read(bytes16);
            
            // reset file pointer
            raf.seek(header.getDataBaseOffset() + entry.getOffset());
            
            // match known signatures
            if (match(bytes16, scwSig)) { // script file
                writeScriptFile(entry);
            } else if (BinConverter.byteArrayToInt(bytes16, 0) == 0x00000400) { // graphic file
                writeGraphicFile(entry);
            } else if (BinConverter.byteArrayToInt(bytes16, 0) == 0x4F676753) { // Ogg file
                writeOggFile(entry);
            } else {
                warnAndExit("Unsupported file format found in archive, 0x"
                    + Long.toHexString(
                        header.getDataBaseOffset() + entry.getOffset()).toUpperCase());
            }
            
            System.err.println("done");
        }
        
        raf.close();
    }
    
    private static void parseHeader(byte[] buf) throws IOException {
        header = new Header();
        
        byte[] temp = null;
        
        // check against archive signature
        temp = extractArray(buf, Header.ARCHIVE_SIG_OFS, Header.ARCHIVE_SIG_LEN);
        if (!match(temp, Header.dataPackSig)) warnAndExit("Unsupported archive type");
        
        // check against archive subtype signature
        temp = extractArray(buf, Header.SUBTYPE_SIG_OFS, Header.SUBTYPE_SIG_LEN);
        if (!match(temp, Header.momoSig)) warnAndExit("Unsupported archive subtype");
        
        // check against magic value
        temp = extractArray(buf, Header.MAGIC_OFS, Header.MAGIC_LEN);
        if (!match(temp, Header.magic)) warnAndExit("Unexpected magic value");
        
        header.setIndexCompSize(
            BinConverter.byteArrayToIntLE(buf, Header.INDEX_COMPSIZE_OFS));
        header.setFileCount(
            BinConverter.byteArrayToIntLE(buf, Header.FILE_COUNT_OFS));
        header.setDataBaseOffset(
            BinConverter.byteArrayToIntLE(buf, Header.DATA_BASEOFFSET_OFS) & 0x0FFFFFFFFL);
        header.setIndexBaseOffset(
            BinConverter.byteArrayToIntLE(buf, Header.INDEX_BASEOFFSET_OFS) & 0x0FFFFFFFFL);
    }
    
    private static void parseIndex(byte[] buf) throws IOException {
        index = new IndexEntry[header.getFileCount()];
        
        int baseOfs = 0;
        for (int i = 0; i < index.length; ++i) {
            index[i] = new IndexEntry();
            IndexEntry current = index[i];
            
            current.setFilename(
                readCString(
                    new ByteArrayInputStream(buf, baseOfs + IndexEntry.FILENAME_OFS, IndexEntry.FILENAME_LEN)));
            current.setOffset(BinConverter.byteArrayToIntLE(buf, baseOfs + IndexEntry.OFFSET_OFS));
            current.setSize(BinConverter.byteArrayToIntLE(buf, baseOfs + IndexEntry.SIZE_OFS));
            
            baseOfs += IndexEntry.LENGTH_IN_FILE;
        }
    }
    
    private static byte[] extractArray(byte[] src, int srcPos, int len) {
        byte[] result = new byte[len];
        Arrays.fill(result, (byte)0);
        System.arraycopy(src, srcPos, result, 0, len);
        
        return result;
    }
    
    private static boolean match(byte[] b1, byte[] b2) {
        return Arrays.equals(b1, b2);
    }
    
    private static void exit(int back) throws IOException {
        writer.write("Error at: 0x" + Long.toHexString(raf.getFilePointer() - back));
        writer.newLine();
        System.exit(1);
    }
    
    private static void warnAndExit(String mes) {
        System.err.println(mes);
        System.exit(1);
    }
    
    private static void xorDecode(byte[] b) {
        for (int offset = 0; offset < b.length; ++offset) {
            b[offset] = (byte)(b[offset] ^ offset);
        }
    }
    
    private static byte[] lzssDecompress(byte[] from, int compLen, byte[] to, int origLen) {
        return lzssDecompress(from, compLen, to, 0, origLen);
    }
    
    private static byte[] lzssDecompress(byte[] from, int compLen, byte[] to, int pos, int origLen) {
        if (to == null) to = new byte[origLen];
        
        byte[] window = new byte[WINDOW_LENGTH];
        int readOffset = 0;
        int writeOffset = pos;
        int marker = 0; // read marker, 8-bits, 1 for raw byte, 0 for back ref
        int windowWriteOffset = 0x0FEE;
        int windowReadOffset = 0;
        int backRefLength = 0;
        int current = 0;
                
        while (readOffset != from.length) {
            marker >>= 1;
            
            if ((marker & 0x0100) == 0) {
                current = from[readOffset++] & 0x0FF;
                marker = 0x0FF00 | current;
            }
            
            if(readOffset == from.length) break;
            if ((marker & 0x01) == 1) { // copy raw bytes
                current = from[readOffset++] & 0x0FF;
                to[writeOffset++] = (byte)current;
                window[windowWriteOffset++] = (byte)current;
                windowWriteOffset &= 0x0FFF;
            } else { // copy from slide window
                windowReadOffset = from[readOffset++] & 0x0FF;
                if(readOffset == from.length) break;
                current = from[readOffset++] & 0x0FF;
                windowReadOffset |= (current & 0x0F0) << 4;
                backRefLength = (current & 0x0F) + 2;
                if (backRefLength < 0) continue;
                
                int addOffset = 0;
                while (addOffset <= backRefLength) {
                    int curOfs = (windowReadOffset + addOffset++) & 0x0FFF;
                    current = window[curOfs] & 0x0FF;
                    windowReadOffset &= 0x0FFF;
                    to[writeOffset++] = (byte)current;
                    window[windowWriteOffset++] = (byte)current;
                    windowWriteOffset &= 0x0FFF;
                } // while
            } // if-else    
        } // while
        
        return to;
    }
    
    private static String readCString(InputStream in) throws IOException {
        ArrayList<Byte> list = new ArrayList<Byte>();
        int i = in.read();
        while (i != 0) {
            list.add((byte)i);
            i = in.read();
        }
        int size = list.size();
        byte[] b = new byte[size];
        for (i = 0; i < size; ++i)
            b[i] = list.get(i);
        
        return new String(b);
    }
    
    private static void writeGraphicFile(IndexEntry entry) throws IOException {
        // initialize some constants for Windows Bitmap header
        int bitmapDataOffset = 0x036;
        int bitmapHeaderSize = 0x028;
        int width = 0; // dummy value
        int height = 0; // dummy value
        int planes = 1; // locked value for a standard Windows Bitmap
        int depth = 0; // dummy value
        int compression = 0; // we're not gonna use compression here
        int dataSize = 0; // dummy value
        int hRes = 0; // 0x0B12; // 72?
        int vRes = 0; // 0x0B12; // 72?
        int colorsUsed = 0; // set to zero, indicating it's same as depth
        int colorsImportant = 0; // no palette used here        
            
        // check against graphic file signature
        if (raf.readInt() != 0x00000400) exit(4);
        
        // get size info
        int compSize  = BinConverter.reverseEndian(raf.readInt());
        int origSize  = BinConverter.reverseEndian(raf.readInt());
        int headerLen = BinConverter.reverseEndian(raf.readInt());
        if (raf.readInt() != 0) exit(4); // what's this? seems like it's always zero
        
        width         = BinConverter.reverseEndian(raf.readInt());
        height        = BinConverter.reverseEndian(raf.readInt());
        depth         = BinConverter.reverseEndianShort(raf.readShort());
        dataSize      = origSize;
        
        // fine tune a few values
        colorsUsed = depth <= 8 ? (1 << depth) : 0;
        int actPaletteLen = depth <= 8 ? (1 << depth) * 4 : 0;
        
        // skip a few bytes...
        // raf.skip();
        raf.seek(header.getDataBaseOffset() + entry.getOffset() + headerLen);
        
        // read the compressed data
        byte[] readBuffer = new byte[compSize];
        raf.read(readBuffer);
        
        // build BMP header
        byte[] writeBuffer = new byte[origSize + 0x036];
        writeBuffer[0] = (byte)'B';
        writeBuffer[1] = (byte)'M';
        BinConverter.intToByteArrayLE(origSize + bitmapDataOffset, writeBuffer, 0x02);
        BinConverter.intToByteArrayLE(0, writeBuffer, 0x06);
        BinConverter.intToByteArrayLE(bitmapDataOffset + actPaletteLen, writeBuffer, 0x0A);
        BinConverter.intToByteArrayLE(bitmapHeaderSize, writeBuffer, 0x0E);
        BinConverter.intToByteArrayLE(width, writeBuffer, 0x012);
        BinConverter.intToByteArrayLE(-height, writeBuffer, 0x016); // negative height value for "not-reversed" bitmap
        BinConverter.shortToByteArrayLE(planes, writeBuffer, 0x01A);
        BinConverter.shortToByteArrayLE(depth, writeBuffer, 0x01C);
        BinConverter.intToByteArrayLE(compression, writeBuffer, 0x01E);
        BinConverter.intToByteArrayLE(dataSize - actPaletteLen, writeBuffer, 0x022);
        BinConverter.intToByteArrayLE(hRes, writeBuffer, 0x026);
        BinConverter.intToByteArrayLE(vRes, writeBuffer, 0x02A);
        BinConverter.intToByteArrayLE(colorsUsed, writeBuffer, 0x02E);
        BinConverter.intToByteArrayLE(colorsImportant, writeBuffer, 0x032);
        
        // LZSS decompress
        lzssDecompress(readBuffer, compSize,  writeBuffer, bitmapDataOffset, origSize);
        
        // write out the bitmap file
        writeFile(writeBuffer, entry.getFilename() + ".bmp");
    }
    
    private static void writeOggFile(IndexEntry entry) throws IOException {
        // read the compressed and encrypted data
        byte[] readBuffer = new byte[entry.getSize()];
        raf.read(readBuffer);
        
        writeFile(readBuffer, entry.getFilename() + ".ogg");
    }
    
    private static void writeScriptFile(IndexEntry entry) throws IOException {
        final int headerLen = 456;
        
        // check against script file signature
        byte[] bytes16 = new byte[16];
        raf.read(bytes16);
        if (!match(bytes16, scwSig)) exit(16);
        
        // check against script file magic value
        byte[] bytes8 = new byte[8];
        raf.read(bytes8);
        if (!match(bytes8, unknownSig)) exit(8);
        
        // get size info
        int origSize = BinConverter.reverseEndian(raf.readInt());
        int compSize = BinConverter.reverseEndian(raf.readInt());
        
        // skip a few bytes...
        // raf.skipBytes(424); // do something about this...
        raf.seek(header.getDataBaseOffset() + entry.getOffset() + headerLen);
        
        // read the compressed and encrypted data
        byte[] readBuffer = new byte[compSize];
        raf.read(readBuffer);
        
        // XOR decrypt
        xorDecode(readBuffer);
        
        // LZSS decompress
        byte[] writeBuffer = lzssDecompress(readBuffer, compSize,  null, origSize);
        
        writeFile(writeBuffer, entry.getFilename() + ".scw");
    }
    
    private static void writeFile(byte[] buf, String name) throws IOException {
        File dir = new File("./data/");
        if (!dir.exists()) dir.mkdirs();
        
        FileOutputStream fos = new FileOutputStream("./data/" + name);
        fos.write(buf);
        fos.flush();
        fos.close();
    }
}


Header.java:
public class Header {
    
    public static final int BUFFER_SIZE = 4096;
    
    public static final int ARCHIVE_SIG_OFS = 0;
    public static final int ARCHIVE_SIG_LEN = 16;
    public static final int SUBTYPE_SIG_OFS = 16;
    public static final int SUBTYPE_SIG_LEN = 32;
    public static final int MAGIC_OFS = 48;
    public static final int MAGIC_LEN = 4;
    public static final int INDEX_COMPSIZE_OFS = 52;
    public static final int FILE_COUNT_OFS = 60;
    public static final int DATA_BASEOFFSET_OFS = 64;
    public static final int INDEX_BASEOFFSET_OFS = 68;
    
    public static final byte[] dataPackSig = {
        (byte)'D', (byte)'a', (byte)'t', (byte)'a', (byte)'P', (byte)'a', (byte)'c', (byte)'k',
        (byte)'5', (byte)0, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0
    };
    
    public static final byte[] momoSig = {
        (byte)'M', (byte)'O', (byte)'M', (byte)'O', (byte)0, (byte)0, (byte)0, (byte)0,
        (byte)0, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0,
        (byte)0, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0,
        (byte)0, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0
    };
    
    public static final byte[] magic = {
        (byte)1, (byte)0, (byte)5, (byte)0
    };
    
    private int indexCompSize;
    private int fileCount;
    private long dataBaseOffset;
    private long indexBaseOffset;
    
    public int getIndexCompSize() {
        return indexCompSize;
    }
    
    public void setIndexCompSize(int size) {
        this.indexCompSize = size;
    }
    
    public int getFileCount() {
        return fileCount;
    }
    
    public void setFileCount(int count) {
        this.fileCount = count;
    }
    
    public long getDataBaseOffset() {
        return dataBaseOffset;
    }
    
    public void setDataBaseOffset(long offset) {
        this.dataBaseOffset = offset;
    }
    
    public long getIndexBaseOffset() {
        return indexBaseOffset;
    }
    
    public void setIndexBaseOffset(long offset) {
        this.indexBaseOffset = offset;
    }
}


IndexEntry.java:
public class IndexEntry {
    
    public static final int LENGTH_IN_FILE = 104;
    
    public static final int FILENAME_OFS = 0;
    public static final int FILENAME_LEN = 64;
    public static final int OFFSET_OFS = 64;
    public static final int SIZE_OFS = 68;
    
    private String filename;
    private int offset; // actual offset = base + offset
    private int size;
    
    public String getFilename() {
        return filename;
    }
    
    public void setFilename(String name) {
        this.filename = name;
    }
    
    public int getOffset() {
        return offset;
    }
    
    public void setOffset(int offset) {
        this.offset = offset;
    }
    
    public int getSize() {
        return size;
    }
    
    public void setSize(int size) {
        this.size = size;
    }
}


BinConverter.java:
/**
 * Some helper routines for data conversion, data is treated in network
 * byte order except the ones with LE postfix.
 */
public class BinConverter
{
    /**
     * Gets bytes from an array into an integer.
     * @param buf where to get the bytes
     * @param ofs index from where to read the data
     * @return the 32bit integer
     */
    public final static int byteArrayToInt(
        byte[] buf,
        int ofs)
    {
        return (buf[ofs    ]          << 24)
            | ((buf[ofs + 1] & 0x0ff) << 16)
            | ((buf[ofs + 2] & 0x0ff) <<  8 )
            | ( buf[ofs + 3] & 0x0ff);
    }
    
    // Little Endian
    public final static int byteArrayToIntLE(
        byte[] buf,
        int ofs)
    {
        return (buf[ofs + 3]          << 24)
            | ((buf[ofs + 2] & 0x0ff) << 16)
            | ((buf[ofs + 1] & 0x0ff) <<  8 )
            | ( buf[ofs    ] & 0x0ff);
    }

    ///////////////////////////////////////////////////////////////////////////

    /**
     * Converts an integer to bytes, which are put into an array.
     * @param value the 32bit integer to convert
     * @param buf the target buf
     * @param ofs where to place the bytes in the buf
     */
    public final static void intToByteArray(
        int value,
        byte[] buf,
        int ofs)
    {
        buf[ofs    ] = (byte)((value >>> 24) & 0x0ff);
        buf[ofs + 1] = (byte)((value >>> 16) & 0x0ff);
        buf[ofs + 2] = (byte)((value >>>  8 ) & 0x0ff);
        buf[ofs + 3] = (byte)  value;
    }
    
    // Little endian
    public final static void intToByteArrayLE(
        int value,
        byte[] buf,
        int ofs)
    {
        buf[ofs + 3] = (byte)((value >>> 24) & 0x0ff);
        buf[ofs + 2] = (byte)((value >>> 16) & 0x0ff);
        buf[ofs + 1] = (byte)((value >>>  8 ) & 0x0ff);
        buf[ofs    ] = (byte)  value;
    }
    
    public final static void shortToByteArrayLE(
        int value,
        byte[] buf,
        int ofs)
    {
        buf[ofs + 1] = (byte)((value >>>  8 ) & 0x0ff);
        buf[ofs    ] = (byte)  value;
    }

    ///////////////////////////////////////////////////////////////////////////

    /**
     * Gets bytes from an array into a long.
     * @param buf where to get the bytes
     * @param ofs index from where to read the data
     * @return the 64bit integer
     */
    public final static long byteArrayToLong(
        byte[] buf,
        int ofs)
    {
        // Looks more complex - but it is faster (at least on 32bit platforms).

        return
            ((long)(( buf[ofs    ]          << 24) |
                    ((buf[ofs + 1] & 0x0ff) << 16) |
                    ((buf[ofs + 2] & 0x0ff) <<  8 ) |
                    ( buf[ofs + 3] & 0x0ff       )) << 32) |
            ((long)(( buf[ofs + 4]          << 24) |
                    ((buf[ofs + 5] & 0x0ff) << 16) |
                    ((buf[ofs + 6] & 0x0ff) <<  8 ) |
                    ( buf[ofs + 7] & 0x0ff       )) & 0x0ffffffffL);
    }

    ///////////////////////////////////////////////////////////////////////////

    /**
     * Converts a long to bytes, which are put into an array.
     * @param value the 64bit integer to convert
     * @param buf the target buf
     * @param ofs where to place the bytes in the buf
     */
    public final static void longToByteArray(
        long value,
        byte[] buf,
        int ofs)
    {
        int tmp = (int)(value >>> 32);

        buf[ofs    ] = (byte) (tmp >>> 24);
        buf[ofs + 1] = (byte)((tmp >>> 16) & 0x0ff);
        buf[ofs + 2] = (byte)((tmp >>>  8 ) & 0x0ff);
        buf[ofs + 3] = (byte)  tmp;

        tmp = (int)value;

        buf[ofs + 4] = (byte) (tmp >>> 24);
        buf[ofs + 5] = (byte)((tmp >>> 16) & 0x0ff);
        buf[ofs + 6] = (byte)((tmp >>>  8 ) & 0x0ff);
        buf[ofs + 7] = (byte)  tmp;
    }

    ///////////////////////////////////////////////////////////////////////////

    /**
     * Converts values from an integer array to a long.
     * @param buf where to get the bytes
     * @param ofs index from where to read the data
     * @return the 64bit integer
     */
    public final static long intArrayToLong(
        int[] buf,
        int ofs)
    {
        return (((long) buf[ofs    ]) << 32) |
               (((long) buf[ofs + 1]) & 0x0ffffffffL);
    }

    ///////////////////////////////////////////////////////////////////////////

    /**
     * Converts a long to integers which are put into an array.
     * @param value the 64bit integer to convert
     * @param buf the target buf
     * @param ofs where to place the bytes in the buf
     */
    public final static void longToIntArray(
        long value,
        int[] buf,
        int ofs)
    {
        buf[ofs    ] = (int)(value >>> 32);
        buf[ofs + 1] = (int) value;
    }

    ///////////////////////////////////////////////////////////////////////////

    /**
     * Makes a long from two integers (treated unsigned).
     * @param lo lower 32bits
     * @param hi higher 32bits
     * @return the built long
     */
    public final static long makeLong(
        int lo,
        int hi)
    {
        return (((long) hi << 32) |
                ((long) lo & 0x00000000ffffffffL));
    }

    ///////////////////////////////////////////////////////////////////////////

    /**
     * Gets the lower 32 bits of a long.
     * @param val the long integer
     * @return lower 32 bits
     */
    public final static int longLo32(
        long val)
    {
        return (int)val;
    }

    ///////////////////////////////////////////////////////////////////////////

    /**
     * Gets the higher 32 bits of a long.
     * @param val the long integer
     * @return higher 32 bits
     */
    public final static int longHi32(
        long val)
    {
        return (int)(val >>> 32);
    }

    ///////////////////////////////////////////////////////////////////////////

    // our table for hex conversion
    final static char[] HEXTAB =
    {
        '0', '1', '2', '3', '4', '5', '6', '7',
        '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
    };

    /**
     * Converts a byte array to a hex string.
     * @param data the byte array
     * @return the hex string
     */
    public final static String bytesToHexStr(
        byte[] data)
    {
        return bytesToHexStr(data, 0, data.length);
    }

    ///////////////////////////////////////////////////////////////////////////

    /**
     * Converts a byte array to a hex string.
     * @param data the byte array
     * @param ofs start index where to get the bytes
     * @param len number of bytes to convert
     * @return the hex string
     */
    public final static String bytesToHexStr(
        byte[] data,
        int ofs,
        int len)
    {
        int pos, c;
        StringBuffer sbuf;


        sbuf = new StringBuffer();
        sbuf.setLength(len << 1);

        pos = 0;
        c = ofs + len;

        while (ofs < c)
        {
            sbuf.setCharAt(pos++, HEXTAB[(data[ofs  ] >> 4) & 0x0f]);
            sbuf.setCharAt(pos++, HEXTAB[ data[ofs++]       & 0x0f]);
        }
        return sbuf.toString();
    }

    ///////////////////////////////////////////////////////////////////////////

    /**
     * Converts a hex string back into a byte array (invalid codes will be
     * skipped).
     * @param hex hex string
     * @param data the target array
     * @param srcofs from which character in the string the conversion should
     * begin, remember that (nSrcPos modulo 2) should equals 0 normally
     * @param dstofs to store the bytes from which position in the array
     * @param len number of bytes to extract
     * @return number of extracted bytes
     */
    public final static int hexStrToBytes(
        String hex,
        byte[] data,
        int srcofs,
        int dstofs,
        int len)
    {
        int i, j, strlen, avail_bytes, dstofs_bak;
        byte abyte;
        boolean convertOK;


        // check for correct ranges
        strlen = hex.length();

        avail_bytes = (strlen - srcofs) >> 1;
        if (avail_bytes < len) {
            len = avail_bytes;
        }

        int nOutputCapacity = data.length - dstofs;
        if (len > nOutputCapacity) {
            len = nOutputCapacity;
        }

        // convert now

        dstofs_bak = dstofs;

        for (i = 0; i < len; i++) {
            abyte = 0;
            convertOK = true;

            for (j = 0; j < 2; ++j) {
                abyte <<= 4;
                char cActChar = hex.charAt(srcofs++);

                if ((cActChar >= 'a') && (cActChar <= 'f')) {
                    abyte |= (byte) (cActChar - 'a') + 10;
                }
                else {
                    if ((cActChar >= '0') && (cActChar <= '9')) {
                        abyte |= (byte) (cActChar - '0');
                    }
                    else {
                        convertOK = false;
                    }
                }
            }
            if (convertOK) {
                data[dstofs++] = abyte;
            }
        }

        return (dstofs - dstofs_bak);
    }

    ///////////////////////////////////////////////////////////////////////////

    /**
     * Converts a byte array into a Unicode string.
     * @param data the byte array
     * @param ofs where to begin the conversion
     * @param len number of bytes to handle
     * @return the string
     */
    public final static String byteArrayToStr(
        byte[] data,
        int ofs,
        int len)
    {
        int avail_capacity, sbuf_pos;
        StringBuffer sbuf;


        // we need two bytes for every character
        len &= ~1;

        // enough bytes in the buf?
        avail_capacity = data.length - ofs;

        if (avail_capacity < len) {
            len = avail_capacity;
        }

        sbuf = new StringBuffer();
        sbuf.setLength(len >> 1);

        sbuf_pos = 0;

        while (0 < len) {
            sbuf.setCharAt(
                sbuf_pos++,
                (char)((data[ofs    ] << 8 )
                    |  (data[ofs + 1] & 0x0ff)));
            ofs += 2;
            len -= 2;
        }

        return sbuf.toString();
    }
    
    ///////////////////////////////////////////////////////////////////////////
    
    /**
     * Reverses between endians for integers
     * @param i the integer to convert endian
     * @return integer of reversed endian
     */
    public final static int reverseEndian(int i) {
        byte[] temp = new byte[4];
        temp[0] = (byte)(i >> 24);
        temp[1] = (byte)(i >> 16);
        temp[2] = (byte)(i >> 8 );
        temp[3] = (byte)i;
        
        return (temp[3] << 24) & 0xFF000000
            |  (temp[2] << 16) & 0x00FF0000
            |  (temp[1] << 8 ) & 0x0000FF00
            |   temp[0]        & 0x000000FF;
    }
    
    /**
     * Reverses between endians for integers
     * @param i the integer to convert endian
     * @return integer of reversed endian
     */
    public final static short reverseEndianShort(short s) {
        byte[] temp = new byte[2];
        temp[0] = (byte)(s >> 8 );
        temp[1] = (byte)s;
        
        return (short)((temp[1] << 8 ) & 0x0FF00
            |           temp[0]        & 0x000FF);
    }
}
分享到:
评论

相关推荐

    libzplay音频模块2.0

    音频模块2.0。1.删除部分命令。2.优化部分命令。3.修复针对1.0版部分命令功能。4.修正部分命令无效功能。5.对命令重新整理分类。6.针对1.0版模块增加功能。媒体音量。媒体效果。媒体功能。...@易华月妆。

    丹参酮ⅡA乳剂对NB4细胞的诱导分化与凋亡作用

    丹参酮ⅡA乳剂对NB4细胞的诱导分化与凋亡作用,李慧,石华月,目的 探讨丹参酮ⅡA乳剂对人早幼粒细胞白血病NB4细胞的诱导分化与凋亡作用。方法 将丹参酮ⅡA乳剂与NB4细胞在体外共同培养5天,观�

    springMVC技术概述

    springMVC相关技术配置使用注解的HandlerMapping和HandlerAdapter使用&lt;mvc:annotation-driver&gt; 不过springBoot已经省略了这些配置 配置使用注解的Handler和Service...@RequestBody,@ResponseBody--json与java对象转换

    基于51单片机数字温度显示系统设计

    总结来说,这是一个完整的嵌入式系统设计案例,涵盖了硬件设计(原理图和PCB)、软件编程(程序)、电路仿真和实际应用等多个环节,对于学习51单片机和数字温度计设计的初学者来说,是一份宝贵的参考资料。...

    DS18B20测温模块 温度传感器模块 DS18B20传感器测温模块.zip

    用户可以通过编写相应的控制程序,读取DS18B20输出的温度数据。由于其独特的单线通信方式,需要正确配置微控制器的输入输出引脚,以便正确识别和解析DS18B20发送的数据。 描述中提到的“DS18B20测温模块 温度传感器...

    EDA技术数字钟控制器设计

    EDA(Electronic Design Automation)技术是电子设计自动化领域的核心技术,它涵盖了集成电路设计、系统级设计、硬件描述语言(HDL)、仿真验证、综合优化、布局布线等多方面的内容。在这个“EDA技术数字钟控制器...

Global site tag (gtag.js) - Google Analytics