/// <summary> /// 验证并初始化补丁解压流。 /// </summary> public void OpenDecompress() { this.patchBlock = TrySplit(this.patchFile); if (this.patchBlock == null) { throw new Exception("Decompress Error, cannot find patch block from the stream."); } BinaryReader r = new BinaryReader(patchBlock); patchBlock.Seek(8, SeekOrigin.Begin); int ver = r.ReadInt32(); uint checkSum0 = r.ReadUInt32(); uint checkSum1 = CheckSum.ComputeHash(patchBlock, (int)patchBlock.Length - 0x10); VerifyCheckSum(checkSum0, checkSum1, "PatchFile", "0"); patchBlock.Seek(16, SeekOrigin.Begin); byte lb = r.ReadByte(), hb = r.ReadByte(); if (!(lb == 0x78 && (lb * 0x100 + hb) % 31 == 0)) // zlib头标识 没有就把这两字节都当数据段好了.. { patchBlock.Seek(-2, SeekOrigin.Current); } this.inflateStream = new InflateStream(patchBlock); }
private void ValidateFileHash(string msDir) { if (this.OldFileHash != null && this.OldFileHash.Count > 0) { foreach (var kv in this.OldFileHash) { var part = new PatchPartContext(kv.Key, -1, -1) { OldFilePath = Path.Combine(msDir, kv.Key) }; uint oldCheckSum1; this.OnPrepareVerifyOldChecksumBegin(part); using (var fs = new FileStream(part.OldFilePath, FileMode.Open, FileAccess.Read, FileShare.Read)) { oldCheckSum1 = CheckSum.ComputeHash(fs, fs.Length); } this.OnPrepareVerifyOldChecksumEnd(part); VerifyCheckSum(kv.Value, oldCheckSum1, part.FileName, "origin"); } } }
public void RebuildFile(PatchPartContext part, string tempDir, string msDir) { this.OnPatchStart(part); string tempFileName = Path.Combine(tempDir, part.FileName); EnsureDirExists(tempFileName); part.OldFilePath = Path.Combine(msDir, part.FileName); this.OnVerifyOldChecksumBegin(part); FileStream oldWzFile = new FileStream(part.OldFilePath, FileMode.Open, FileAccess.Read, FileShare.Read, 0x4000, FileOptions.Asynchronous | FileOptions.RandomAccess); uint oldCheckSum1 = CheckSum.ComputeHash(oldWzFile, (int)oldWzFile.Length); //旧版本文件实际hash this.OnVerifyOldChecksumEnd(part); try { VerifyCheckSum(part.OldChecksum, oldCheckSum1, part.FileName, "origin"); } catch { if (oldWzFile.Length == part.NewFileLength && oldCheckSum1 == part.NewChecksum) //文件已更新的场合 { oldWzFile.Close(); return; } else { throw; } } int cmd; //int blockLength; FileStream tempFileStream = new FileStream(tempFileName, FileMode.Create, FileAccess.ReadWrite, FileShare.Read, 0x4000); part.TempFilePath = tempFileName; if (part.NewFileLength > 0) //预申请硬盘空间 似乎可以加快读写速度 { tempFileStream.SetLength(part.NewFileLength); tempFileStream.Seek(0, SeekOrigin.Begin); } this.OnTempFileCreated(part); uint newCheckSum1 = 0; this.InflateStreamSeek(part.Offset); BinaryReader r = new BinaryReader(this.inflateStream); double patchProc = 0; const double patchProcReportInverval = 0.005; //v3新增读缓冲 List <RebuildFileOperation> operList = new List <RebuildFileOperation>(32768); List <RebuildFileOperation> readFileOperList = new List <RebuildFileOperation>(operList.Capacity); MemoryStream msBuffer = new MemoryStream(1024 * 1024 * 64); int preLoadByteCount = 0; while (true) { cmd = r.ReadInt32(); RebuildFileOperation op = null; if (cmd != 0) { switch ((uint)cmd >> 0x1C) { case 0x08: op = new RebuildFileOperation(0); op.Length = cmd & 0x0fffffff; break; case 0x0c: op = new RebuildFileOperation(1); op.FillByte = (byte)(cmd & 0xff); op.Length = (cmd & 0x0fffff00) >> 8; break; default: op = new RebuildFileOperation(2); op.Length = cmd; op.StartPosition = r.ReadInt32(); break; } } //如果大于 先处理当前所有预读操作 if (cmd == 0 || (operList.Count >= operList.Capacity - 1) || (op.OperType != 1 && (op.Length + preLoadByteCount > msBuffer.Capacity))) { //排序预读原文件 readFileOperList.Sort((first, second) => first.StartPosition.CompareTo(second.StartPosition)); foreach (var readFileOp in readFileOperList) { int position = (int)msBuffer.Position; readFileOp.Flush(oldWzFile, null, null, msBuffer); readFileOp.bufferStartIndex = position; } //向新文件输出 foreach (var tempOp in operList) { newCheckSum1 = tempOp.Flush(oldWzFile, r.BaseStream, msBuffer, tempFileStream, newCheckSum1); //计算更新进度 if (part.NewFileLength > 0) { double curProc = 1.0 * tempFileStream.Position / part.NewFileLength; if (curProc - patchProc >= patchProcReportInverval) // || curProc >= 1 - patchProcReportInverval) { this.OnTempFileUpdated(part, tempFileStream.Position); //更新进度改变 patchProc = curProc; } } else { if (tempFileStream.Position - patchProc > 1024 * 1024 * 10) { this.OnTempFileUpdated(part, tempFileStream.Position);//更新进度改变 patchProc = tempFileStream.Position; } } } //重置缓冲区 msBuffer.SetLength(0); preLoadByteCount = 0; operList.Clear(); readFileOperList.Clear(); if (cmd == 0) // 更新结束 这里是出口无误 { break; } } if (op.OperType != 1 && op.Length >= msBuffer.Capacity) //还是大于的话 单独执行 { newCheckSum1 = op.Flush(oldWzFile, r.BaseStream, null, tempFileStream, newCheckSum1); } else //直接放进缓冲区里 { op.Index = (ushort)operList.Count; operList.Add(op); switch (op.OperType) { case 0: int position = (int)msBuffer.Position; op.Flush(null, r.BaseStream, null, msBuffer); op.bufferStartIndex = position; break; case 1: continue; case 2: readFileOperList.Add(op); break; } preLoadByteCount += op.Length; } } msBuffer.Dispose(); msBuffer = null; tempFileStream.Flush(); tempFileStream.SetLength(tempFileStream.Position); //设置文件大小为当前长度 this.OnVerifyNewChecksumBegin(part); tempFileStream.Seek(0, SeekOrigin.Begin); //uint _newCheckSum1 = CheckSum.ComputeHash(tempFileStream, (int)tempFileStream.Length); //新生成文件的hash VerifyCheckSum(part.NewChecksum, newCheckSum1, part.FileName, "new"); this.OnVerifyNewChecksumEnd(part); oldWzFile.Close(); tempFileStream.Flush(); tempFileStream.Close(); this.OnTempFileClosed(part); }
public void RebuildFile(PatchPartContext part, string tempDir, string msDir) { this.OnPatchStart(part); string tempFileName = Path.Combine(tempDir, part.FileName); EnsureDirExists(tempFileName); part.OldFilePath = Path.Combine(msDir, part.FileName); var oldWzFiles = new Dictionary <string, FileStream>(); FileStream tempFileStream = null; FileStream openFile(string fileName) { if (string.IsNullOrEmpty(fileName)) { return(null); } if (!oldWzFiles.TryGetValue(fileName, out var fs)) { fs = new FileStream(Path.Combine(msDir, fileName), FileMode.Open, FileAccess.Read, FileShare.Read); oldWzFiles.Add(fileName, fs); } return(fs); } void closeAllFiles() { foreach (var fs in oldWzFiles.Values) { fs.Close(); } tempFileStream?.Close(); } try { if (this.IsKMST1125Format == true) { // skip old file checking } else if (part.OldChecksum != null) { var oldWzFile = openFile(part.FileName); this.OnVerifyOldChecksumBegin(part); uint oldCheckSum1 = CheckSum.ComputeHash(oldWzFile, oldWzFile.Length); //旧版本文件实际hash this.OnVerifyOldChecksumEnd(part); try { VerifyCheckSum(part.OldChecksum.Value, oldCheckSum1, part.FileName, "origin"); } catch { if (oldWzFile.Length == part.NewFileLength && oldCheckSum1 == part.NewChecksum) //文件已更新的场合 { oldWzFile.Close(); return; } else { throw; } } } int cmd; //int blockLength; tempFileStream = new FileStream(tempFileName, FileMode.Create, FileAccess.ReadWrite, FileShare.Read, 0x4000); part.TempFilePath = tempFileName; if (part.NewFileLength > 0) //预申请硬盘空间 似乎可以加快读写速度 { tempFileStream.SetLength(part.NewFileLength); tempFileStream.Seek(0, SeekOrigin.Begin); } this.OnTempFileCreated(part); uint newCheckSum1 = 0; this.InflateStreamSeek(part.Offset); BinaryReader r = new BinaryReader(this.inflateStream); double patchProc = 0; const double patchProcReportInverval = 0.005; //v3新增读缓冲 List <RebuildFileOperation> operList = new List <RebuildFileOperation>(32768); List <RebuildFileOperation> readFileOperList = new List <RebuildFileOperation>(operList.Capacity); MemoryStream msBuffer = new MemoryStream(1024 * 1024 * 64); int preLoadByteCount = 0; while (true) { cmd = r.ReadInt32(); RebuildFileOperation op = null; if (cmd != 0) { switch ((uint)cmd >> 0x1C) { case 0x08: op = new RebuildFileOperation(0); op.Length = cmd & 0x0fffffff; break; case 0x0c: op = new RebuildFileOperation(1); op.FillByte = (byte)(cmd & 0xff); op.Length = (cmd & 0x0fffff00) >> 8; break; default: op = new RebuildFileOperation(2); op.Length = cmd; op.StartPosition = r.ReadInt32(); op.FromFileName = this.IsKMST1125Format.Value ? this.ReadStringWithLength(r) : part.FileName; break; } } //如果大于 先处理当前所有预读操作 if (cmd == 0 || (operList.Count >= operList.Capacity - 1) || (op.OperType != 1 && (op.Length + preLoadByteCount > msBuffer.Capacity))) { //排序预读原文件 readFileOperList.Sort((left, right) => { int cmp; if ((cmp = string.Compare(left.FromFileName, right.FromFileName, StringComparison.OrdinalIgnoreCase)) != 0) { return(cmp); } return(left.StartPosition.CompareTo(right.StartPosition)); }); foreach (var readFileOp in readFileOperList) { int position = (int)msBuffer.Position; readFileOp.Flush(openFile(readFileOp.FromFileName), null, null, msBuffer); readFileOp.bufferStartIndex = position; } //向新文件输出 foreach (var tempOp in operList) { newCheckSum1 = tempOp.Flush(openFile(tempOp.FromFileName), r.BaseStream, msBuffer, tempFileStream, newCheckSum1); //计算更新进度 if (part.NewFileLength > 0) { double curProc = 1.0 * tempFileStream.Position / part.NewFileLength; if (curProc - patchProc >= patchProcReportInverval) // || curProc >= 1 - patchProcReportInverval) { this.OnTempFileUpdated(part, tempFileStream.Position); //更新进度改变 patchProc = curProc; } } else { if (tempFileStream.Position - patchProc > 1024 * 1024 * 10) { this.OnTempFileUpdated(part, tempFileStream.Position);//更新进度改变 patchProc = tempFileStream.Position; } } } //重置缓冲区 msBuffer.SetLength(0); preLoadByteCount = 0; operList.Clear(); readFileOperList.Clear(); if (cmd == 0) // 更新结束 这里是出口无误 { break; } } if (op.OperType != 1 && op.Length >= msBuffer.Capacity) //还是大于的话 单独执行 { newCheckSum1 = op.Flush(openFile(op.FromFileName), r.BaseStream, null, tempFileStream, newCheckSum1); } else //直接放进缓冲区里 { op.Index = (ushort)operList.Count; operList.Add(op); switch (op.OperType) { case 0: int position = (int)msBuffer.Position; op.Flush(null, r.BaseStream, null, msBuffer); op.bufferStartIndex = position; break; case 1: continue; case 2: readFileOperList.Add(op); break; } preLoadByteCount += op.Length; } } msBuffer.Dispose(); msBuffer = null; tempFileStream.Flush(); tempFileStream.SetLength(tempFileStream.Position); //设置文件大小为当前长度 closeAllFiles(); this.OnVerifyNewChecksumBegin(part); //tempFileStream.Seek(0, SeekOrigin.Begin); //uint _newCheckSum1 = CheckSum.ComputeHash(tempFileStream, (int)tempFileStream.Length); //新生成文件的hash VerifyCheckSum(part.NewChecksum, newCheckSum1, part.FileName, "new"); this.OnVerifyNewChecksumEnd(part); this.OnTempFileClosed(part); } finally { closeAllFiles(); } }
public void Build() { List <FileReversePart> preReverse = new List <FileReversePart>(); using (FileStream fs = new FileStream(patchFileName, FileMode.Open, FileAccess.Read)) { fs.Position = 18; InflateStream stream = new InflateStream(fs, true); WzPatcherReader reader = new WzPatcherReader(stream); PatchPart filePart; PatchPart reversePart; while ((filePart = reader.ReadPart()) != null) { switch (filePart.Type) { case PatchType.Create: if (filePart.FileLength > 0) { stream.Seek(filePart.FileLength, SeekOrigin.Current); //在原文件夹寻找同名文件 string oldFile = Path.Combine(msDir, filePart.FileName); if (File.Exists(oldFile)) { reversePart = new PatchPart() { Type = PatchType.Create }; reversePart.FileName = filePart.FileName; reversePart.FileLength = (int)new FileInfo(oldFile).Length; preReverse.Add(new FileReversePart(reversePart)); } else { reversePart = new PatchPart() { Type = PatchType.Delete }; reversePart.FileName = filePart.FileName; preReverse.Add(new FileReversePart(reversePart)); } } break; case PatchType.Rebuild: reversePart = new PatchPart() { Type = PatchType.Rebuild, OldChecksum = filePart.Checksum, Checksum = filePart.OldChecksum, FileName = filePart.FileName }; List <FileReverseInst> instList = new List <FileReverseInst>(); BuildInstruction inst; int filePos = 0; while ((inst = reader.ReadInst()).Type != null) { if (inst.Type == BuildType.Ending) { break; } switch (inst.Type) { case BuildType.FromPatcher: stream.Seek(inst.Length, SeekOrigin.Current); break; case BuildType.FillBytes: break; case BuildType.FromOldFile: instList.Add(new FileReverseInst() { Inst = inst, NewFilePosition = filePos }); break; } filePos += inst.Length; } preReverse.Add(new FileReversePart(reversePart) { InstList = instList }); break; case PatchType.Delete: { string oldFile = Path.Combine(msDir, filePart.FileName); if (File.Exists(oldFile)) { reversePart = new PatchPart() { Type = PatchType.Create }; reversePart.FileName = filePart.FileName; reversePart.FileLength = (int)new FileInfo(oldFile).Length; preReverse.Add(new FileReversePart(reversePart)); } } break; } } //end while } //end using preReverse.Sort(); using (FileStream dest = new FileStream(outputFileName, FileMode.Create)) { WzPatcherWriter writer = new WzPatcherWriter(dest); writer.Begin(); foreach (var part in preReverse) { string oldFileName = Path.Combine(msDir, part.Part.FileName); switch (part.Part.Type) { case PatchType.Create: //计算hash copy文件 using (FileStream oldFs = new FileStream(oldFileName, FileMode.Open, FileAccess.Read, FileShare.Read)) { part.Part.FileLength = (int)oldFs.Length; part.Part.Checksum = CheckSum.ComputeHash(oldFs, part.Part.FileLength); oldFs.Position = 0; writer.WritePart(part.Part); writer.WriteContent(oldFs, part.Part.FileLength); } break; case PatchType.Rebuild: writer.WritePart(part.Part); using (FileStream oldFs = new FileStream(oldFileName, FileMode.Open, FileAccess.Read, FileShare.Read)) { //计算指令 var instList = Work(part.InstList, (int)oldFs.Length); //开始执行 foreach (var inst in instList) { switch (inst.Inst.Type) { case BuildType.FromOldFile: //参数反转 inst.Inst.OldFilePosition = inst.NewFilePosition; writer.WriteInst(inst.Inst); break; case BuildType.FromPatcher: //go 待优化 writer.WriteInst(inst.Inst); oldFs.Position = inst.NewFilePosition; writer.WriteContent(oldFs, inst.Inst.Length); break; } } //结束执行 writer.WriteInst(new BuildInstruction(BuildType.Ending)); } break; case PatchType.Delete: writer.WritePart(part.Part); break; } } writer.End(); } }