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);
        }
Beispiel #3
0
        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);
        }
Beispiel #5
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");
         }
     }
 }
Beispiel #6
0
        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);
        }
Beispiel #10
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);
        }
 public PatchingEventArgs(PatchPartContext part, PatchingState state)
     : this(part, state, 0)
 {
 }
Beispiel #12
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();
            }
        }
Beispiel #13
0
        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);
        }
Beispiel #14
0
        private void OnApplyFile(PatchPartContext part)
        {
            PatchingEventArgs e = new PatchingEventArgs(part, PatchingState.ApplyFile);

            OnPatchingStateChanged(e);
        }
Beispiel #15
0
        private void OnTempFileUpdated(PatchPartContext part, long filelen)
        {
            PatchingEventArgs e = new PatchingEventArgs(part, PatchingState.TempFileBuildProcessChanged, filelen);

            OnPatchingStateChanged(e);
        }
Beispiel #16
0
        /// <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);
        }
Beispiel #17
0
        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;
 }