花了几天时间 解释UMD文件,文本内容的基本搞定 保存下来,免得又忘记 以后有时间把代码整理整理 /** * */ package cn.leaves.umd.io; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.RandomAccessFile; import java.io.StringWriter; import java.util.zip.InflaterOutputStream; import cn.leaves.umd.Content; import cn.leaves.umd.Umd; /** * @author leaves * */ public class UmdReader { private String umdfilepath; private File umdfile; private RandomAccessFile in; public final int UMD = 0xde9a9b89; public int PICTURE = 0x02; public int TEXT = 0x01; private final Umd umd = new Umd(); private long contentOffset = 0; public UmdReader() { } public UmdReader(String umdfilepath) { init(umdfilepath, "r"); } public UmdReader(String umdfilepath, String mode) { init(umdfilepath, mode); } private void init(String umdfilepath, String mode) { byte[] buffer; this.umdfilepath = umdfilepath; umdfile = new File(this.umdfilepath); try { close(); in = new RandomAccessFile(umdfile, mode); buffer = new byte[4]; in.read(buffer); int type = bytes2Int(buffer); if (type == UMD) { umd.validate = true; } umd.title = this.baseInfoToString(12); umd.author = this.baseInfoToString(4); umd.year = this.baseInfoToString(4); umd.month = this.baseInfoToString(4); umd.day = this.baseInfoToString(4); umd.gender = this.baseInfoToString(4); umd.publisher = this.baseInfoToString(4); umd.vendor = this.baseInfoToString(4); umd.contentLength = this.baseInfo4ByteToInt(5); umd.chaperOffLength = (this.baseInfo4ByteToInt(14) - 9) / 4; int[] chaperOff = new int[umd.chaperOffLength]; for (int i = 0; i < chaperOff.length; i++) { chaperOff[i] = this.baseInfo4ByteToInt(0); } umd.chaperOff = chaperOff; String[] chaper = new String[umd.chaperOffLength]; int chaperLen = this.baseInfo4ByteToInt(14) - 10; for (int i = 0; i < chaper.length; i++) { int length = this.baseInfo1ByteToInt(0); chaper[i] = this.baseInfoToString(0, length); } umd.chaper = chaper; this.contentOffset = in.getFilePointer(); int no = 0; while (true) { int contentLength = this.baseInfo4ByteToInt(5) - 9; umd.content.put(no, new Content(in.getFilePointer(), contentLength, "", false)); in.skipBytes(contentLength); byte[] b = new byte[5]; in.read(b); if (this.readUnicodeByte2Hex(b).equals("23f1000015")) { in.skipBytes(16); contentOffset = in.getFilePointer(); } else if (this.readUnicodeByte2Hex(b).equals("230a000009")) { in.skipBytes(4); contentOffset = in.getFilePointer(); } else if (this.readUnicodeByte2Hex(b).equals("2381000109")) { contentOffset = in.getFilePointer(); break; } else { in.seek(in.getFilePointer() - 5); } no++; } } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public String chaperContent(int _index) { try { int index = _index; in.seek(((Content) umd.content.get(index)).offset); String str = this.ZLIBDecoding(this.baseInfo2Bytes(0, ((Content) umd.content.get(index)).length)); return str; } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return ""; } public RandomAccessFile getInputStream() { return in; } public String getUmdfilepath() { return umdfilepath; } public void setUmdfilepath(String umdfilepath) { this.umdfilepath = umdfilepath; } public boolean isUmd() { return umd.validate; } public int umdType() { try { in.seek(9); byte[] buffer = new byte[1]; in.read(buffer); switch (byte2Int(buffer[0])) { case 0x02: return PICTURE; case 0x01: return TEXT; } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); return 0; } return 0; } public Umd getUmd() { return umd; } public void close() throws IOException { if (in != null) { in.close(); } } private int bytes2Int(byte[] bytes) { int num = bytes[0] & 0xFF; num |= ((bytes[1] << 8) & 0xFF00); num |= ((bytes[2] << 16) & 0xFF0000); num |= ((bytes[3] << 24) & 0xFF000000); return num; } private int bytes2Int2Byte(byte[] bytes) { int num = bytes[0] & 0xFF; num |= ((bytes[1] << 8) & 0xFF00); return num; } private int byte2Int(byte b) { int num = b & 0xff; return num; } private String readUnicodeByte2Hex(byte[] temp) throws IOException { StringWriter sw = new StringWriter(); for (int index = 0; index < temp.length; index++) { if (temp[index] > 0xf && temp[index] <= 0xff) { sw.write(Integer.toHexString(temp[index])); } else if (temp[index] >= 0x0 && temp[index] <= 0xf) {// 对于只有1位的16进制数前边补“0” sw.write("0" + Integer.toHexString(temp[index])); } else { // 对于int<0的位转化为16进制的特殊处理,因为Java没有Unsigned // int,所以这个int可能为负数 sw.write(Integer.toHexString(temp[index]).substring(6)); } } return sw.toString(); } private String decodeHexToChinese(String hex) { StringBuffer sb = new StringBuffer(""); for (int i = 0; i < hex.length(); i = i + 4) { String temp = hex.substring(i, i + 4); // if (temp.equalsIgnoreCase("0000")) // break; String temp2 = "" + temp.charAt(2) + temp.charAt(3) + temp.charAt(0) + temp.charAt(1); char t = (char) Integer.parseInt(temp2, 16); sb.append(t); } return sb.toString(); } private String baseInfoToString(int skipBytes) throws IOException { in.skipBytes(skipBytes); byte[] b = new byte[1]; in.read(b); int length = byte2Int(b[0]) - 5; b = new byte[length]; in.read(b); return this.decodeHexToChinese(this.readUnicodeByte2Hex(b)); } private String baseInfoToString(int skipBytes, int length) throws IOException { in.skipBytes(skipBytes); byte[] b = new byte[length]; in.read(b); return this.decodeHexToChinese(this.readUnicodeByte2Hex(b)); } private byte[] baseInfo2Bytes(int skipBytes, int length) throws IOException { in.skipBytes(skipBytes); byte[] b = new byte[length]; int i = 0; while (i != length) { int bl=204800; if(length-i<bl) { bl=length-i; } byte[] t = new byte[bl]; in.read(t); System.arraycopy(t, 0, b, i, bl); i += bl; } return b; } private int baseInfo4ByteToInt(int skipBytes) throws IOException { in.skipBytes(skipBytes); byte[] b = new byte[4]; in.read(b); return this.bytes2Int(b); } private int baseInfo2ByteToInt(int skipBytes) throws IOException { in.skipBytes(skipBytes); byte[] b = new byte[2]; in.read(b); return this.bytes2Int2Byte(b); } private int baseInfo1ByteToInt(int skipBytes) throws IOException { in.skipBytes(skipBytes); byte[] b = new byte[1]; in.read(b); return this.byte2Int(b[0]); } private void showHex(int length) { try { byte[] bytes = new byte[length]; in.read(bytes); System.out.println(); String s = this.readUnicodeByte2Hex(bytes); for (int i = 0; i < s.length(); i++) { System.out.print("0x" + s.charAt(i) + s.charAt(++i)); System.out.print(" "); } System.out.println(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public byte[] decompressData(byte[] bytes) { try { ByteArrayOutputStream bos = new ByteArrayOutputStream(); InflaterOutputStream zos = new InflaterOutputStream(bos); zos.write(bytes); zos.close(); byte[] b = bos.toByteArray(); bos.close(); return b; } catch (Exception ex) { ex.printStackTrace(); return null; } } public String ZLIBDecoding(byte[] b) throws IOException { byte[] temp = this.decompressData(b); if (temp != null) { return this.decodeHexToChinese(this.readUnicodeByte2Hex(temp)) .replace("/u2029", "/r/n"); } return ""; } } /** * */ package cn.leaves.umd; import java.util.Hashtable; /** * @author leaves * */ public class Umd { public static final int UMD = 0xde9a9b89; public static int PICTURE = 0x02; public static int TEXT = 0x01; public boolean validate = false; public String title; public String author; public String year; public String month; public String day; public String gender;// 类别 public String publisher; public String vendor; public int contentLength; public int chaperOffLength; public int[] chaperOff; public int chaperLength; public String[] chaper; public int lziplength; public Hashtable<Integer,Content> content=new Hashtable(0); } package cn.leaves.umd; public class Content{ public Content(long offset,int length,String content,boolean buffered) { this.offset=offset; this.length=length; this.content=content; this.buffered=buffered; } public long offset; public int length; public String content; public boolean buffered=false; }