package com.javaxyq.tools; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.ByteArrayInputStream; import java.io.DataInput; import java.io.DataInputStream; import java.io.EOFException; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.RandomAccessFile; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Scanner; import java.util.Set; import java.util.Map.Entry; import org.apache.commons.lang.StringUtils; import com.javaxyq.core.Toolkit; import com.javaxyq.util.Utils; /** * .WDF�ļ��� * * @author ����ΰ * @history 2008-6-10 ����ΰ �½� */ public class WdfFile implements FileSystem { /** �ļ���� */ private RandomAccessFile fileHandler; /** ������2/�λ�����/�������� WDF�ļ���� */ private static final String WDFP_FILE = "PFDW"; /** ��3/���⴫ */ private static final String WDFX_FILE = "XFDW"; /** ��3/���⴫ */ private static final String WDFH_FILE = "HFDW"; /** ���ڽ����� */ private int fileNodeCount; /** �ļ�ȫ�� */ private String filename; /** ���ӳ��� */ private Map<Long, WdfFileNode> fileNodeMap = new HashMap<Long, WdfFileNode>(); private FileObject rootNode; private String fileTag; private long[] dh3Keys; public WdfFile(String filename, boolean resovePath) throws Exception { loadWdf(filename, resovePath); } public WdfFile(String filename) throws Exception { loadWdf(filename, true); } private void loadWdf(String filename, boolean resovePath) throws Exception { try { filename = StringUtils.replaceChars(filename, '\\', '/'); this.filename = filename; fileHandler = new RandomAccessFile(filename, "r"); if (!isWdfFile(fileHandler)) { throw new IllegalArgumentException("�������WDF��ʽ���ļ���path=" + filename + ",tag=" + fileTag); } //init key if (WDFX_FILE.equals(fileTag) || WDFH_FILE.equals(fileTag)) { loadDH3Key("dh3.dat"); } //read fileNodeCount = readInt(fileHandler); if(fileNodeCount==0) {//�����ǡ�������������ʽ(���ֽ�00) fileNodeCount = readInt(fileHandler); } int headerSize = readInt(fileHandler); fileHandler.seek(headerSize); fileNodeMap.clear(); //�Ƿ���Ҫ������㣬��ԭidֵ(��3��Դ) boolean xor = WDFX_FILE.equals(fileTag) || WDFH_FILE.equals(fileTag); int dh3i = 0; for (int i = 0; i < fileNodeCount; i++) { WdfFileNode node = new WdfFileNode(); long id = readUnsignInt(fileHandler); node.setId(xor ? id ^ dh3Keys[dh3i] : id); int offset = readInt(fileHandler); node.setOffset((int) (xor ? offset ^ dh3Keys[dh3i + 1] : offset)); int size = readInt(fileHandler); node.setSize((int) (xor ? size ^ dh3Keys[dh3i + 2] : size)); int space = readInt(fileHandler); node.setSpace((int) (xor ? space ^ dh3Keys[dh3i + 3] : space)); dh3i += 4; dh3i %= 0x40; node.setFileSystem(this); fileNodeMap.put(node.getId(), node); } rootNode = new WdfDirectoryObject(this); if(resovePath) { //load description load(null); //restore path String name = StringUtils.substringAfterLast(filename, "/"); restorePaths(name); } } catch (Exception e) { System.err.println("��WDF�ļ�����" + filename); e.printStackTrace(); throw new Exception("��WDF�ļ�����" + filename, e); } System.out.printf("nodeCount=%s, total find:%s\n", fileNodeCount, fileNodes().size()); } /** * �жϴ򿪵��ļ��Ƿ�ΪWDF�ļ� * * @param raf * @return * @throws IOException */ private boolean isWdfFile(RandomAccessFile raf) throws IOException { byte[] buf = new byte[4]; raf.seek(0); raf.read(buf); fileTag = new String(buf); return fileTag.equals(WDFP_FILE) || fileTag.equals(WDFX_FILE) || fileTag.equals(WDFH_FILE); } private Map<Long, String> buildPaths(String filename) { String cmtfile ="resources/names/"+ filename.replaceAll("\\.wd.*", ".cmt"); Map<Long, String> map = new HashMap<Long, String>(); InputStream is = Utils.getResourceAsStream(cmtfile); if (is != null) { BufferedReader br = new BufferedReader(new InputStreamReader(is)); String strPath = null; try { while ((strPath = br.readLine()) != null) { try { strPath = strPath.trim(); if(strPath.length()>0) { String[] strs = strPath.split("="); if(strs!=null && strs.length>1) { map.put(Long.parseLong(strs[0],16), strs[1]); } } } catch (Exception e) { System.out.println("������Դӳ��ʧ�ܣ�"+strPath); //e.printStackTrace(); } } } catch (Throwable e) { System.err.println("��ԭ�ļ����б�ʧ��: " + cmtfile); e.printStackTrace(); } } else { System.err.println("��ȡ��Դʧ��: " + cmtfile); } return map; } private void restorePaths(String name) { Map<Long, String> id2PathMap = buildPaths(name); // Map<Long, String> id2PathMap = HashUtil.createId2PathMap("resources/names/" // + name.replaceAll("\\.wd.*", ".lst")); Set<Entry<Long, WdfFileNode>> entryset = fileNodeMap.entrySet(); int iCount =0; for (Entry<Long, WdfFileNode> entry : entryset) { WdfFileNode node = entry.getValue(); String path = id2PathMap.get(entry.getKey()); path = StringUtils.replaceChars(path, '\\', '/'); if (path != null) { //System.out.printf("ƥ��: %s=%s\n", strId, path); //start with '/' if (path.charAt(0) != '/') { path = "/" + path; } node.setPath(path); node.setName(StringUtils.substringAfterLast(path, "/")); iCount ++; } else {//�Ҳ���path String strId = Long.toHexString(entry.getKey()); node.setPath("/" + strId); //System.err.printf("��ƥ����: id=%s\n", strId); } } System.out.printf("�����ļ�%d����ƥ���ļ�%d������ƥ���ļ�%d��\n",fileNodeCount,iCount,(fileNodeCount-iCount)); } private void loadDH3Key(String file) { InputStream is = Toolkit.getInputStream("/com/javaxyq/tools/" + file); DataInputStream dis = new DataInputStream(is); try { System.out.println("size=" + dis.available()); dh3Keys = new long[0x40]; for (int i = 0; i < dh3Keys.length; i++) { dh3Keys[i] = readUnsignInt(dis); } } catch (IOException e) { System.err.println("loadDH3Key error!"); e.printStackTrace(); } } public void close() throws IOException { if (this.fileHandler != null) { this.fileHandler.close(); } this.fileNodeMap.clear(); } private int readInt(DataInput di) throws IOException { int ch1, ch2, ch3, ch4; ch1 = di.readUnsignedByte(); ch2 = di.readUnsignedByte(); ch3 = di.readUnsignedByte(); ch4 = di.readUnsignedByte(); if ((ch1 | ch2 | ch3 | ch4) < 0) throw new EOFException(); return ((ch4 << 24) + (ch3 << 16) + (ch2 << 8) + (ch1 << 0)); } private long readUnsignInt(DataInput di) throws IOException { long ch1, ch2, ch3, ch4; ch1 = di.readUnsignedByte(); ch2 = di.readUnsignedByte(); ch3 = di.readUnsignedByte(); ch4 = di.readUnsignedByte(); if ((ch1 | ch2 | ch3 | ch4) < 0) throw new EOFException(); return ((ch4 << 24) + (ch3 << 16) + (ch2 << 8) + (ch1 << 0)); } /** * ��ȡWdfFile�������ļ���㼯�� * * @return */ public Collection<WdfFileNode> fileNodes() { return fileNodeMap.values(); } public int getFileNodeCount() { return fileNodeCount; } /** * ����id��ȡ��Ӧ������ * * @param nid ���id * @return ����һ�������� * @throws IOException */ public InputStream getNodeAsStream(long nodeId) throws IOException { return new ByteArrayInputStream(this.getNodeData(nodeId)); } /** * ����id��ȡ��Ӧ������ * * @param nid * @return * @throws IOException */ public byte[] getNodeData(long nodeId) throws IOException { //���������� WdfFileNode fnode = fileNodeMap.get(nodeId); byte[] data = null; if (fnode != null) { data = new byte[(int) fnode.getSize()]; //ƫ�Ƶ�������ݶ�λ�� fileHandler.seek(fnode.getOffset()); //��ȡ������� fileHandler.readFully(data); } return data; } @Override public String toString() { return "[wdf name=" + filename + "]"; } public String getName() { return filename; } public WdfFileNode findNode(long nodeId) { return fileNodeMap.get(nodeId); } public WdfFileNode findNode(String nodeId) { return fileNodeMap.get(Long.parseLong(nodeId, 16)); } /** * ���������ļ� * * @param filename * @throws Exception */ public void loadDescription(InputStream is) { if (is != null) { Scanner scanner = new Scanner(is); scanner.useDelimiter("(\r\n)|(\n\r)|[\n\r=]"); String tag = scanner.next(); long uid; String str=null, alias = null; int iCount = 0; if (tag.startsWith("[Resource]")) { while (scanner.hasNext()) { WdfFileNode node = null; try { scanner.skip("(\r\n)|(\n\r)|[\n\r=]"); str = scanner.next(); uid = Long.parseLong(str, 16); scanner.skip("(\r\n)|(\n\r)|[\n\r=]"); alias = scanner.next().trim(); node = fileNodeMap.get(uid); } catch (NumberFormatException e) { e.printStackTrace(); } if (node != null) { node.setDescription(alias.replace('\\', '/')); //System.out.println("��Դ:" + Long.toHexString(uid) + "=" + alias); } else { System.out.println("�Ҳ������ڵ���Դ:" + str + "=" + alias); } iCount++; } } System.out.println("total : " + iCount); scanner.close(); } } /** * ȡpath����Ľ���б� * * @param path ·�� * @param subpath �Ƿ������Ŀ¼ * @return */ public List<WdfFileNode> getNodesUnderPath(String path, boolean subpath) { return null; } /** * ������Դ�����ļ� * * @param filename */ public void saveDescription(FileOutputStream os) { BufferedWriter writer = null; try { writer = new BufferedWriter(new OutputStreamWriter(os)); writer.write("[Resource]\r\n"); List<WdfFileNode> nodeList = getNodesUnderPath("/", false); for (WdfFileNode node : nodeList) { if (node.getName() != null && node.getName().length() > 0) { writer.write(Long.toHexString(node.getId()).toUpperCase()); writer.write('='); writer.write(node.getName()); writer.write("\r\n"); } } } catch (Exception ex) { ex.printStackTrace(); } finally { try { writer.close(); } catch (IOException e) { } } } /** * �����Դ������Ϣ */ public void clearDescription() { Collection<WdfFileNode> nodes = fileNodes(); for (WdfFileNode node : nodes) { node.setDescription(null); } } public FileObject getRoot() { return rootNode; } public String getType() { return "wdf"; } public void load(String descfile) { if(descfile==null) { descfile = "resources/desc/" + new File(this.filename).getName() + ".ini"; } this.loadDescription(Utils.getResourceAsStream(descfile)); } public void save(String filename) { try { this.saveDescription(new FileOutputStream(filename)); } catch (FileNotFoundException e) { System.out.println("save description failed! filename=" + filename); e.printStackTrace(); } } /** * ��offset��ʼ��ȡ����Ϊlen�����ݿ� * * @param data * @param offset * @param len * @throws IOException */ public void read(byte[] data, int offset, int len) throws IOException { fileHandler.seek(offset); fileHandler.readFully(data, 0, len); } }