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