📄 decoder.java
字号:
/**
*
*/
import java.io.*;
import java.io.BufferedReader;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.util.Calendar;
/**
* @author Slice
* @email licesh@gmail.com
*/
public class Decoder {
private long dl;
private Calendar c;
public Decoder() {
c = Calendar.getInstance();
c.set(1601, 0, 1, 8, 0, 0);// 取得1601-1-1
// 8:00:00的millisec值。结果为负,因为Calendar计算millisec是
// offset from the Epoch, January 1, 1970 00:00:00.000 GMT (Gregorian)
dl = c.getTimeInMillis();
}
private long hexBytes2Long(byte[] hexBytes) {// big endian 低地址放低位
int n = hexBytes.length;
String hex;
String s = "";
for (int i = n - 1; i >= 0; i--) {// 转成little endian
hex = Integer.toHexString(hexBytes[i] & 0XFF);// 在32位的电脑中数字都是以32格式存放的,如果是一个byte(8位)类型的数字,他的高24位里面都是随机数字,低8位
// 才是实际的数据。java.lang.Integer.toHexString()
// 方法的参数是int(32位)类型,如果输入一个byte(8位)类型的数字,这个
// 方法会把这个数字的高24为也看作有效位,这就必然导致错误,使用&
// 0XFF操作,可以把高24位置0以避免这样错误的发生。
if (hex.length() == 1) {
hex = '0' + hex;
}
s += hex;
}
return Long.parseLong(s, 16);
}
public void decodeSMSBak(File file) {
String decStr = new String();
byte[] b;
byte[] byteTime = new byte[8];
boolean type = true;// 标志信息类型 true为receive false 为send
int i = 0, j = i;
try {
b = readFileToBytes(file);
i = 4;// 前四个byte为文件头 暂且跳过
j = i;
while (i < b.length) {
// 根据两byte信息头判断是接收还是发送
if (b[j] == 11 && b[j + 1] == 1)// 0x0B 0x01
type = true;// receive
else if (b[j] == 22 && b[j + 1] == 33)// 0x16 0x21
type = false;// send
if (type) {// receive
i = j + 5;// 跳到8byte时间信息
// ////
for (j = i; j < i + 8; j++) {
byteTime[j - i] = b[j];
}
long oldl = hexBytes2Long(byteTime);// 万分之一毫秒数
long nowl = oldl / 10000 + dl;// 计算当前的时刻相对Epoch的millisec
c.setTimeInMillis(nowl);// 通过millisec设置Calendar,即可得到字符串表示
decStr += c.get(Calendar.YEAR) + "-"
+ (c.get(Calendar.MONTH) + 1) + "-"
+ c.get(Calendar.DAY_OF_MONTH) + " "
+ c.get(Calendar.HOUR_OF_DAY) + ":"
+ c.get(Calendar.MINUTE) + ":"
+ c.get(Calendar.SECOND) + " 周"
+ c.get(Calendar.DAY_OF_WEEK);
// /
i += 16;
for (j = i;; j += 2)
if (b[j] == 0 && b[j + 1] == 0)// 定位至XX 00 00(j) 00
break;
j -= 2;// j移动至XX处 即号码后
decStr += "\t发送人:";
decStr += decodeString(b, i, j);// 解析name 和 号码
j += 4;// j移动到XX 00 00 00后 即第二个name处
i = j;
for (;; j += 2)
if (b[j] == 0 && b[j + 1] == 0)// 定位至第二处XX 00 00(j) 00
break;
j -= 2;// j移动至第二XX处 即第二name后
// decStr += decodeString(b, i, j);// 解析第二name
j += 4;// j移动到MSG头处
i = j;
for (;; j += 2)
if (b[j] == 0 && b[j + 1] == 0 && b[j + 2] == 0
&& b[j + 3] == 0)// j定位至00 00 00 00处,即一条信息尾部
break;
decStr += "\t内容:" + decodeString(b, i, j);// 解析信息内容
decStr += "\r\n";
j += 4;// j移动至下一条信息头 即信息类型标志位
i = j;
} else {// send
i += 5;
// ////
for (j = i; j < i + 8; j++) {
byteTime[j - i] = b[j];
}
long oldl = hexBytes2Long(byteTime);// 万分之一毫秒数
long nowl = oldl / 10000 + dl;// 计算当前的时刻相对Epoch的millisec
c.setTimeInMillis(nowl);// 通过millisec设置Calendar,即可得到字符串表示
decStr += c.get(Calendar.YEAR) + "-"
+ (c.get(Calendar.MONTH) + 1) + "-"
+ c.get(Calendar.DAY_OF_MONTH) + " "
+ c.get(Calendar.HOUR_OF_DAY) + ":"
+ c.get(Calendar.MINUTE) + ":"
+ c.get(Calendar.SECOND) + " 周"
+ c.get(Calendar.DAY_OF_WEEK);
// /
i += 12;// 暂且跳过17byte时间等信息
for (j = i;; j += 2)
if (b[j] == 59 && b[j + 1] == 0)// 定位至0x3B(j) 00 00 00
// 00 00 00 00 00 00 XX
// 00 00 00处
break;
decStr += "\t接收人:";
decStr += decodeString(b, i, j);// 解析name
j += 14;// 跳过上述14未知类型的byte,至内容开头
i = j;
for (;; j += 2)
if (b[j] == 0 && b[j + 1] == 0 && b[j + 2] == 0
&& b[j + 3] == 0)// j定位至00 00 00 00处,即一条信息尾部
break;
decStr += "\t内容:" + decodeString(b, i, j);
decStr += "\r\n";
j += 4;// j移动至下一条信息头 即信息类型标志位
i = j;
}
}
// System.out.print(decStr);
writeFile("msgs.txt", decStr);
} catch (Exception e) {
e.printStackTrace();
// System.out.print(decStr);
try {
writeFile("msgs.txt", decStr);
} catch (Exception e2) {
e2.printStackTrace();
}
}
}
/**
* decode string from byte[]
*
* @param i
* start index
* @param j
* end index
* @return decoded string
*/
private static String decodeString(byte[] b, int i, int j) {
try {
byte[] temp = new byte[j - i];
for (int k = i, l = 0; k < j; k += 2, l += 2) {
temp[l + 1] = b[k];
temp[l] = b[k + 1];
}
return new String(temp, "Unicode");
} catch (Exception e) {
// e.printStackTrace();
System.out.print(Integer.toString(i) + "," + Integer.toString(j)
+ "\n");
return null;
}
}
public static void main(String[] args) {
// try {
// String s = new String(new byte[] { 0x01, 0x0b, 0x21, 0x16 },
// "Unicode");
// s += ";";
// } catch (Exception e) {
// e.printStackTrace();
// }
// System.out.println(c.getTime().toString());
// Timestamp ts = Timestamp.valueOf("2009-1-21 17:48:2");
Decoder de = new Decoder();
de.decodeSMSBak(new File("input.sms"));
}
/**
* read content from input file
*
* @param fileName
* input file name
* @return String file content
*/
private static String readFile(String fileName) {
try {
BufferedReader fr = new BufferedReader(new FileReader(fileName));
StringBuffer out = new StringBuffer();
String thisLine = new String();
while (thisLine != null) {
thisLine = fr.readLine();
if (thisLine != null) {
out.append(thisLine);
}
}
fr.close();
return out.toString();
} catch (Exception e) {
System.out.print(e.toString());
return null;
}
}
/**
* write content to output file
*
* @param fileName
* output file name
* @param content
* file content to write
*/
static boolean writeFile(String filePath, String content)
throws IOException {
File file = new File(filePath);
if (file.exists()) {
file.delete();
}
synchronized (file) {
FileWriter fw = new FileWriter(filePath, true);
fw.write(content);
fw.close();
}
return true;
}
/**
* /** 读文件到字节数组
*
* @param file
* @return
* @throws Exception
*/
static byte[] readFileToBytes(File file) throws Exception {
if (file.exists() && file.isFile()) {
long fileLength = file.length();
if (fileLength > 0L) {
BufferedInputStream fis = new BufferedInputStream(
new FileInputStream(file));
byte[] b = new byte[(int) fileLength];
while (fis.read(b) != -1) {
}
fis.close();
fis = null;
return b;
}
} else {
return null;
}
return null;
}
/**
* /** 将字节数组写入文件
*
* @param filePath
* @param content
* @return
* @throws IOException
*/
static boolean writeBytesToFile(String filePath, byte[] content)
throws IOException {
File file = new File(filePath);
synchronized (file) {
BufferedOutputStream fos = new BufferedOutputStream(
new FileOutputStream(filePath));
fos.write(content);
fos.flush();
fos.close();
}
return true;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -