Ejemplo n.º 1
0
        /// <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);
        }
Ejemplo n.º 2
0
 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");
         }
     }
 }
Ejemplo n.º 3
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);

            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);
        }
Ejemplo n.º 4
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 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();
            }
        }