public void CreateNewFile(PatchPartContext part, string tempDir) { this.OnPatchStart(part); string tempFileName = Path.Combine(tempDir, part.FileName); EnsureDirExists(tempFileName); if (part.NewFileLength <= 0) { return; } this.InflateStreamSeek(part.Offset); FileStream tempFileStream = new FileStream(tempFileName, FileMode.Create, FileAccess.ReadWrite); part.TempFilePath = tempFileName; this.OnTempFileCreated(part); //创建文件同时计算checksum uint checkSum1 = StreamUtils.MoveStreamWithCrc32(this.inflateStream, tempFileStream, part.NewFileLength, 0U); tempFileStream.Flush(); this.OnVerifyNewChecksumBegin(part); VerifyCheckSum(part.NewChecksum, checkSum1, part.FileName, "0"); this.OnVerifyNewChecksumEnd(part); tempFileStream.Close(); this.OnTempFileClosed(part); }
private int CalcNewFileLength(PatchPartContext patchPart, BinaryReader reader) { patchPart.Action0 = patchPart.Action1 = patchPart.Action2 = 0; int length = 0; int cmd; int blockLength; while ((cmd = reader.ReadInt32()) != 0) { switch (((uint)cmd) >> 0x1C) { case 0x08: blockLength = cmd & 0x0fffffff; reader.BaseStream.Seek(blockLength, SeekOrigin.Current); patchPart.Action0++; break; case 0x0c: blockLength = (cmd & 0x0fffff00) >> 8; patchPart.Action1++; break; default: blockLength = cmd; reader.BaseStream.Seek(4, SeekOrigin.Current); patchPart.Action2++; break; } length += blockLength; } return(length); }
private PatchPartContext ReadPatchPart(BinaryReader r) { string fileName; int patchType = GetFileName(r, out fileName); PatchPartContext part; switch (patchType) { case 0: if (string.IsNullOrEmpty(Path.GetExtension(fileName))) { part = new PatchPartContext(fileName, -1, 0); } else { int fileLength = r.ReadInt32(); uint checkSum0 = r.ReadUInt32(); part = new PatchPartContext(fileName, this.inflateStream.Position, patchType); part.NewChecksum = checkSum0; part.NewFileLength = fileLength; } break; case 1: { uint?oldCheckSum0 = null; if (!this.IsKMST1125Format.Value) { oldCheckSum0 = r.ReadUInt32(); } uint newCheckSum0 = r.ReadUInt32(); part = new PatchPartContext(fileName, this.inflateStream.Position, patchType); part.OldChecksum = oldCheckSum0; part.NewChecksum = newCheckSum0; } break; case 2: { part = new PatchPartContext(fileName, -1, patchType); } break; case -1: return(null); default: throw new Exception("Unknown patch type " + patchType + "."); } return(part); }
public long PrePatch() { if (this.inflateStream == null) { this.OpenDecompress(); } else if (this.inflateStream.Position > 0) //重置到初始化 { this.inflateStream = new InflateStream(this.inflateStream); } List <PatchPartContext> patchParts = new List <PatchPartContext>(); BinaryReader r = new BinaryReader(this.inflateStream); while (true) { PatchPartContext part = ReadPatchPart(r); if (part == null) { break; } patchParts.Add(part); //跳过当前段 switch (part.Type) { case 0: if (part.NewFileLength > 0) { this.inflateStream.Seek(part.NewFileLength, SeekOrigin.Current); } break; case 1: { part.NewFileLength = CalcNewFileLength(part, r); } break; case 2: break; } } this.patchParts = patchParts; return(this.inflateStream.Position); }
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"); } } }
private int CalcNewFileLength(PatchPartContext patchPart, BinaryReader reader) { patchPart.Action0 = patchPart.Action1 = patchPart.Action2 = 0; int length = 0; int cmd; int blockLength; while ((cmd = reader.ReadInt32()) != 0) { switch (((uint)cmd) >> 0x1C) { case 0x08: blockLength = cmd & 0x0fffffff; reader.BaseStream.Seek(blockLength, SeekOrigin.Current); // skip len patchPart.Action0++; break; case 0x0c: blockLength = (cmd & 0x0fffff00) >> 8; patchPart.Action1++; break; default: blockLength = cmd; reader.BaseStream.Seek(4, SeekOrigin.Current); // skip content if (this.IsKMST1125Format == true) { // skip old file name var fromFile = ReadStringWithLength(reader, MAX_PATH); patchPart.DependencyFiles.Add(fromFile); } patchPart.Action2++; break; } length += blockLength; } return(length); }
private void OnVerifyNewChecksumEnd(PatchPartContext part) { PatchingEventArgs e = new PatchingEventArgs(part, PatchingState.VerifyNewChecksumEnd); OnPatchingStateChanged(e); }
private void OnVerifyOldChecksumBegin(PatchPartContext part) { PatchingEventArgs e = new PatchingEventArgs(part, PatchingState.VerifyOldChecksumBegin); OnPatchingStateChanged(e); }
private void OnPatchStart(PatchPartContext part) { PatchingEventArgs e = new PatchingEventArgs(part, PatchingState.PatchStart); OnPatchingStateChanged(e); }
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 PatchingEventArgs(PatchPartContext part, PatchingState state) : this(part, state, 0) { }
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 long PrePatch() { if (this.inflateStream == null) { this.OpenDecompress(); } else if (this.inflateStream.Position > 0) //重置到初始化 { this.inflateStream = new InflateStream(this.inflateStream); } var patchParts = new List <PatchPartContext>(); var r = new BinaryReader(this.inflateStream); if (this.TryReadKMST1125FileHashList(r, out var fileHash)) { this.oldFileHash = fileHash; this.IsKMST1125Format = true; } else { this.IsKMST1125Format = false; // reset file cursor this.inflateStream = new InflateStream(this.inflateStream); r = new BinaryReader(this.inflateStream); } while (true) { PatchPartContext part = ReadPatchPart(r); if (part == null) { break; } patchParts.Add(part); //跳过当前段 switch (part.Type) { case 0: if (part.NewFileLength > 0) { this.inflateStream.Seek(part.NewFileLength, SeekOrigin.Current); } break; case 1: { part.NewFileLength = CalcNewFileLength(part, r); } break; case 2: break; } } this.patchParts = patchParts; return(this.inflateStream.Position); }
private void OnApplyFile(PatchPartContext part) { PatchingEventArgs e = new PatchingEventArgs(part, PatchingState.ApplyFile); OnPatchingStateChanged(e); }
private void OnTempFileUpdated(PatchPartContext part, long filelen) { PatchingEventArgs e = new PatchingEventArgs(part, PatchingState.TempFileBuildProcessChanged, filelen); OnPatchingStateChanged(e); }
/// <summary> /// 对于已经解压的patch文件,向客户端执行更新过程,可以自己指定临时文件的文件夹。 /// </summary> /// <param Name="mapleStoryFolder">冒险岛客户端所在文件夹。</param> /// <param Name="tempFileFolder">生成临时文件的文件夹。</param> public void Patch(string mapleStoryFolder, string tempFileFolder) { string tempDir = CreateRandomDir(tempFileFolder); if (this.inflateStream.Position > 0) //重置到初始化 { this.inflateStream = new InflateStream(this.inflateStream); } if (this.patchParts == null) //边读取边执行 { this.patchParts = new List <PatchPartContext>(); BinaryReader r = new BinaryReader(this.inflateStream); while (true) { PatchPartContext part = ReadPatchPart(r); if (part == null) { break; } patchParts.Add(part); //跳过当前段 switch (part.Type) { case 0: CreateNewFile(part, tempDir); break; case 1: RebuildFile(part, tempDir, mapleStoryFolder); break; case 2: break; } } } else //按照调整后顺序执行 { foreach (PatchPartContext part in this.patchParts) { switch (part.Type) { case 0: CreateNewFile(part, tempDir); break; case 1: RebuildFile(part, tempDir, mapleStoryFolder); break; case 2: break; } } } foreach (PatchPartContext part in this.patchParts) { if (part.Type != 2 && !string.IsNullOrEmpty(part.TempFilePath)) { SafeMove(part.TempFilePath, Path.Combine(mapleStoryFolder, part.FileName)); } else if (part.Type == 2) { if (part.FileName.EndsWith("\\")) { SafeDeleteDirectory(Path.Combine(mapleStoryFolder, part.FileName)); } else { SafeDeleteFile(Path.Combine(mapleStoryFolder, part.FileName)); } } } SafeDeleteDirectory(tempDir); }
private void OnTempFileClosed(PatchPartContext part) { PatchingEventArgs e = new PatchingEventArgs(part, PatchingState.TempFileClosed); OnPatchingStateChanged(e); }
public PatchingEventArgs(PatchPartContext part, PatchingState state, long currentFileLength) { this.part = part; this.state = state; this.currentFileLen = currentFileLength; }