public Dictionary <string, string> nStringMap = new Dictionary <string, string>(); //n_string.lst文件的索引键值关系,键值均为字符串 /* * pvf共分三部分:Header头,Tree文件索引头,文件内容数据,本类中: * 使用struct PvfHeader{}来存储Header头,在本类中为header对象 * 使用Dictionary<string, HeaderTreeNode> headerTreeCache来存储Tree文件索引头,键为文件索引的文件名,值为索引对象 * 使用HeaderTreeNode的索引对象存储文件内容,详情请看本类构造方法。 */ public Pvf(string file) //本构造方法使用后需dispose释放内存,构造过程请放到线程中异步调用。 { fs = new FileStream(file, FileMode.Open); //打开文件 header = (PvfHeader)Util.readFileAsType(fs, typeof(PvfHeader)); //读取pvf文件头结构体到header变量 int headLength = header.dirTreeLength; //获取文件索引列表字节总大小 byte[] decryptedTree = new byte[header.dirTreeLength]; //分配内存 fs.Read(decryptedTree, 0, header.dirTreeLength); //读取文件索引列表 Util.unpackHeaderTree(ref decryptedTree, header.dirTreeLength, (uint)header.dirTreeChecksum); //解密,解密后的字节数组为decryptedTree int pos = 0; //模拟读取字节数组的指针 for (int i = 0; i < header.numFilesInDirTree; i++) { HeaderTreeNode item = new HeaderTreeNode(); int a = item.readNodeFromBitArrStream(header, fs, decryptedTree, pos);//从pos位置开始读取HeaderTreeNode对象,返回值为指针应该偏移的字节数 if (a < 0) { throw new Exception("读取错误,格式非法"); //读取错误直接报错 } pos += a; //指针后移 headerTreeCache[item.filePathName] = item; //把对象放入字典,以文件名为键 } loadStringTableBin(headerTreeCache["stringtable.bin"].unpackedFileByteArr); //读取stringtable.bin文件创建stringtable索引 loadNStringLst(headerTreeCache["n_string.lst"].unpackedFileByteArr); //读取n_string.lst文件创建n_string索引 return; }
public string getPvfFileByPath(HeaderTreeNode node, Encoding encoding) //根据文件索引对象返回文件内容 { byte[] unpackedStrBytes = node.unpackedFileByteArr; //直接取解密内容 //byte[] numArray = new byte[52428800]; int strpos = 0; //导出文本的偏移指针 Dictionary <int, byte[]> arr = new Dictionary <int, byte[]>(); //导出文本的字典,键为偏移,值为字符串的字节形式,如0=>字符串AAA,3=>字符串BBB,整个字符串为AAABBB,AAA的基址为0,BBB的基址为3 var bts = encoding.GetBytes("#PVF_File\r\n"); arr.Add(strpos, bts); //开头加上一行#PVF_File strpos = bts.Length; //指针向后移动 //文件结构为:byte[2](0xb0,0xd0打开好多文件这里都是这个值,猜测应该是固定的)byte[1]int[1]byte[1]int[1]byte[1]...以此循环,byte[1]为指示符,int[1]占四位为一个数字,具体意义需要看指示位 if (unpackedStrBytes.Length >= 7) //如果总字节长度>=7 { for (int i = 2; i < unpackedStrBytes.Length; i += 5) //以5为单步从第二位开始遍历字节 { //string s = encoding.GetString(numArray).TrimEnd(new char[1]); if (unpackedStrBytes.Length - i >= 5) //到最后了就不处理了防止内存越界 { byte currentByte = unpackedStrBytes[i]; //猜测应该是内容指示位 if (currentByte == 2 || currentByte == 4 || currentByte == 5 || currentByte == 6 || currentByte == 7 || currentByte == 8 || currentByte == 10) //如果这个字节是这些中的一个进行对应的特殊处理,如果不是那就没有字符串 { int after1 = BitConverter.ToInt32(unpackedStrBytes, i + 1); //取该指示位后面的整数 if (currentByte == 10) //这个字符是10时 { int before1 = BitConverter.ToInt32(unpackedStrBytes, i - 4); //取指示位前面的整数 //解释字符串内容的方法已集成到unpackSpecialChr(指示位,后一位整数,前一位整数)中 bts = Encoding.UTF8.GetBytes(string.Concat(unpackSpecialChr(currentByte, after1, before1), "\r\n")); //获取该指示位代表的字符串 arr.Add(strpos, bts); strpos += bts.Length; } else if (currentByte == 7) //这个字符是7时 { bts = Encoding.UTF8.GetBytes(string.Concat("`", unpackSpecialChr(currentByte, after1, 0), "`\r\n")); //7不需要前一位整数,外面要套上“``” arr.Add(strpos, bts); strpos += bts.Length; } else if (currentByte == 2 || currentByte == 4)//这个字符是2或者4时,末尾不是换行而是制表符\t { bts = Encoding.UTF8.GetBytes(string.Concat(unpackSpecialChr(currentByte, after1, 0), "\t")); arr.Add(strpos, bts); strpos += bts.Length; } else if (currentByte == 6 || currentByte == 8)//{指示位=`stringbin[后面的整数]`} { string[] str = new string[] { "{", currentByte.ToString(), "=`", unpackSpecialChr(currentByte, after1, 0), "`}\r\n" }; bts = encoding.GetBytes(string.Concat(str)); arr.Add(strpos, bts); strpos += bts.Length; } else if (currentByte == 5) //是5的情况,stringbin[后面的整数] { bts = Encoding.UTF8.GetBytes(string.Concat("\r\n", unpackSpecialChr(currentByte, after1, 0), "\r\n")); arr.Add(strpos, bts); strpos += bts.Length; } } } } bts = encoding.GetBytes("\r\n");//末尾添个换行符 arr.Add(strpos, bts); strpos += bts.Length; } byte[] bytes = new byte[strpos];//创建一个正好大小的字节数组 foreach (int pos in arr.Keys) { for (int i = 0; i < arr[pos].Length; i++) { bytes[i + pos] = arr[pos][i];//使用导出文本的字典填充字节数组 } } arr.Clear(); //释放内存 string str1 = encoding.GetString(bytes).TrimEnd(new char[1]); //转换成文本 return(str1); }