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

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

哦,对了。解图片出来的时候我偷懒了。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);
}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值