Esempio n. 1
0
        private static void BuildBsaPatch(string inBsaName, string outBsaName)
        {
            string outBSAFile = Path.ChangeExtension(outBsaName, ".bsa");
            string outBSAPath = Path.Combine(_dirTTWMain, outBSAFile);

            string inBSAFile = Path.ChangeExtension(inBsaName, ".bsa");
            string inBSAPath = Path.Combine(_dirFO3Data, inBSAFile);

            var renameDict = BuildRenameDict(outBsaName);

            Debug.Assert(renameDict != null);

            var patPath = Path.Combine(OutDir, Path.ChangeExtension(outBsaName, ".pat"));

            if (File.Exists(patPath))
            {
                return;
            }

            var prefix = Path.Combine(InDir, "TTW Patches", outBsaName);

            using (var inBSA = new BSA(inBSAPath))
                using (var outBSA = new BSA(outBSAPath))
                {
                    BsaDiff
                    .CreateRenameQuery(inBSA, renameDict)
                    .ToList(); // execute query

                    var oldFiles = inBSA.SelectMany(folder => folder).ToList();
                    var newFiles = outBSA.SelectMany(folder => folder).ToList();

                    var newChkDict = FileValidation.FromBSA(outBSA);

                    var joinedPatches = from patKvp in newChkDict
                                        join newBsaFile in newFiles on patKvp.Key equals newBsaFile.Filename
                                        select new
                    {
                        newBsaFile,
                        file  = patKvp.Key,
                        patch = patKvp.Value
                    };
                    var allJoinedPatches = joinedPatches.ToList();

                    var patchDict = new PatchDict(allJoinedPatches.Count);
                    foreach (var join in allJoinedPatches)
                    {
                        var oldBsaFile = oldFiles.SingleOrDefault(file => file.Filename == join.file);
                        Debug.Assert(oldBsaFile != null, "File not found: " + join.file);

                        var oldChk = FileValidation.FromBSAFile(oldBsaFile);
                        var newChk = join.patch;

                        var oldFilename = oldBsaFile.Filename;
                        if (oldFilename.StartsWith(TaleOfTwoWastelands.Properties.Resources.VoicePrefix))
                        {
                            patchDict.Add(join.file, new Patch(newChk, null));
                            continue;
                        }

                        var patches = new List <PatchInfo>();

                        var md5OldStr = Util.GetMD5String(oldBsaFile.GetContents(true));
                        var md5NewStr = Util.GetMD5String(join.newBsaFile.GetContents(true));

                        var diffPath = Path.Combine(prefix, oldFilename + "." + md5OldStr + "." + md5NewStr + ".diff");
                        var usedPath = Path.ChangeExtension(diffPath, ".used");
                        if (File.Exists(usedPath))
                        {
                            File.Move(usedPath, diffPath); //fixes moronic things
                        }
                        var altDiffs = Util.FindAlternateVersions(diffPath);
                        if (altDiffs != null)
                        {
                            foreach (var altDiff in altDiffs)
                            {
                                var altDiffBytes = GetDiff(altDiff.Item1, Diff.SIG_LZDIFF41);
                                patches.Add(new PatchInfo
                                {
                                    Metadata = new FileValidation(altDiff.Item2, 0, FileValidation.ChecksumType.Md5),
                                    Data     = altDiffBytes
                                });
                            }
                        }

                        if (newChk != oldChk)
                        {
                            byte[] diffData = GetDiff(diffPath, Diff.SIG_LZDIFF41);

                            var patchInfo = PatchInfo.FromOldDiff(diffData, oldChk);
                            Debug.Assert(patchInfo.Data != null);

                            patches.Add(patchInfo);
                        }

                        patchDict.Add(join.file, new Patch(newChk, patches.ToArray()));
                    }

                    using (var stream = File.OpenWrite(patPath))
                        patchDict.WriteAll(stream);
                }
        }
Esempio n. 2
0
        private static void BuildBsaPatch(string inBsaName, string outBsaName)
        {
            string outBSAFile = Path.ChangeExtension(outBsaName, ".bsa");
            string outBSAPath = Path.Combine(_dirTTWMain, outBSAFile);

            string inBSAFile = Path.ChangeExtension(inBsaName, ".bsa");
            string inBSAPath = Path.Combine(_dirFO3Data, inBSAFile);

            var renameDict = BuildRenameDict(outBsaName);
            Debug.Assert(renameDict != null);

            var patPath = Path.Combine(OutDir, Path.ChangeExtension(outBsaName, ".pat"));
            if (File.Exists(patPath))
                return;

            var prefix = Path.Combine(InDir, "TTW Patches", outBsaName);

            using (var inBSA = new BSA(inBSAPath))
            using (var outBSA = new BSA(outBSAPath))
            {
                BsaDiff
                    .CreateRenameQuery(inBSA, renameDict)
                    .ToList(); // execute query

                var oldFiles = inBSA.SelectMany(folder => folder).ToList();
                var newFiles = outBSA.SelectMany(folder => folder).ToList();

                var newChkDict = FileValidation.FromBSA(outBSA);

                var joinedPatches = from patKvp in newChkDict
                                    join newBsaFile in newFiles on patKvp.Key equals newBsaFile.Filename
                                    select new
                                    {
                                        newBsaFile,
                                        file = patKvp.Key,
                                        patch = patKvp.Value,
                                    };
                var allJoinedPatches = joinedPatches.ToList();

                var patchDict = new PatchDict(allJoinedPatches.Count);
                foreach (var join in allJoinedPatches)
                {
                    var oldBsaFile = oldFiles.SingleOrDefault(file => file.Filename == join.file);
                    Debug.Assert(oldBsaFile != null, "File not found: " + join.file);

                    var oldChk = FileValidation.FromBSAFile(oldBsaFile);
                    var newChk = join.patch;

                    var oldFilename = oldBsaFile.Filename;
                    if (oldFilename.StartsWith(Game.VoicePrefix))
                    {
                        patchDict.Add(join.file, new Patch(newChk, null));
                        continue;
                    }

                    var patches = new List<PatchInfo>();

                    var md5OldStr = Util.GetMD5String(oldBsaFile.GetContents(true));
                    var md5NewStr = Util.GetMD5String(join.newBsaFile.GetContents(true));

                    var diffPath = Path.Combine(prefix, oldFilename + "." + md5OldStr + "." + md5NewStr + ".diff");
                    var usedPath = Path.ChangeExtension(diffPath, ".used");
                    if (File.Exists(usedPath))
                        File.Move(usedPath, diffPath); //fixes moronic things

                    var altDiffs = Util.FindAlternateVersions(diffPath);
                    if (altDiffs != null)
                    {
                        foreach (var altDiff in altDiffs)
                        {
                            var altDiffBytes = GetDiff(altDiff.Item1, Diff.SIG_LZDIFF41);
                            patches.Add(new PatchInfo
                            {
                                Metadata = new FileValidation(altDiff.Item2, 0, FileValidation.ChecksumType.Md5),
                                Data = altDiffBytes
                            });
                        }
                    }

                    if (newChk != oldChk)
                    {
                        byte[] diffData = GetDiff(diffPath, Diff.SIG_LZDIFF41);

                        var patchInfo = PatchInfo.FromOldDiff(diffData, oldChk);
                        Debug.Assert(patchInfo.Data != null);

                        patches.Add(patchInfo);
                    }

                    patchDict.Add(join.file, new Patch(newChk, patches.ToArray()));
                }

                using (var stream = File.OpenWrite(patPath))
                    patchDict.WriteAll(stream);
            }
        }
Esempio n. 3
0
        public bool PatchBsa(CompressionOptions bsaOptions, string oldBSA, string newBSA, bool simulate = false)
        {
            var Op = new InstallStatus(Progress, Token) { ItemsTotal = 7 };

            var outBsaFilename = Path.GetFileNameWithoutExtension(newBSA);

            BSA bsa;
            try
            {
                Op.CurrentOperation = "Opening " + Path.GetFileName(oldBSA);

                bsa = new BSA(oldBSA, bsaOptions);
            }
            finally
            {
                Op.Step();
            }

            IDictionary<string, string> renameDict;
            try
            {
                Op.CurrentOperation = "Opening rename database";

#if LEGACY
                var renamePath = Path.Combine(Installer.PatchDir, outBsaFilename, "RenameFiles.dict");
#else
                var renamePath = Path.Combine(Installer.PatchDir, Path.ChangeExtension(outBsaFilename, ".ren"));
#endif
                if (File.Exists(renamePath))
                {
#if LEGACY
                    renameDict = new Dictionary<string, string>(Util.ReadOldDatabase(renamePath));
#else
                    using (var fileStream = File.OpenRead(renamePath))
                    using (var lzmaStream = new LzmaDecodeStream(fileStream))
                    using (var reader = new BinaryReader(lzmaStream))
                    {
                        var numPairs = reader.ReadInt32();
                        renameDict = new Dictionary<string, string>(numPairs);

                        while (numPairs-- > 0)
                            renameDict.Add(reader.ReadString(), reader.ReadString());
                    }
#endif
                }
                else
                    renameDict = new Dictionary<string, string>();
            }
            finally
            {
                Op.Step();
            }

            PatchDict patchDict;
            try
            {
                Op.CurrentOperation = "Opening patch database";

#if LEGACY
                var chkPrefix = Path.Combine(Installer.PatchDir, outBsaFilename);
                var chkPath = Path.Combine(chkPrefix, "CheckSums.dict");
                patchDict = PatchDict.FromOldDatabase(Util.ReadOldDatabase(chkPath), chkPrefix, b => b);
#else
                var patchPath = Path.Combine(Installer.PatchDir, Path.ChangeExtension(outBsaFilename, ".pat"));
                if (File.Exists(patchPath))
                {
                    patchDict = new PatchDict(patchPath);
                }
                else
                {
                    Log.Dual("\tNo patch database is available for: " + oldBSA);
                    return false;
                }
#endif
            }
            finally
            {
                Op.Step();
            }

            using (bsa)
            {
                try
                {
                    RenameFiles(bsa, renameDict);

                    if (renameDict.Count > 0)
                    {
                        foreach (var kvp in renameDict)
                        {
                            Log.Dual("File not found: " + kvp.Value);
                            Log.Dual("\tCannot create: " + kvp.Key);
                        }
                    }
                }
                finally
                {
                    Op.Step();
                }

                var allFiles = bsa.SelectMany(folder => folder).ToList();
                try
                {
                    var opChk = new InstallStatus(Progress, Token) { ItemsTotal = patchDict.Count };

                    var joinedPatches = from patKvp in patchDict
                                        //if the join is not grouped, this will exclude missing files, and we can't find and fail on them
                                        join oldFile in allFiles on patKvp.Key equals oldFile.Filename into foundOld
                                        join bsaFile in allFiles on patKvp.Key equals bsaFile.Filename
                                        select new PatchJoin(bsaFile, foundOld.SingleOrDefault(), patKvp.Value);

#if DEBUG
                    var watch = new Stopwatch();
                    try
                    {
                        watch.Start();
#endif
#if PARALLEL
                        Parallel.ForEach(joinedPatches, join =>
#else
                        foreach (var join in joinedPatches)
#endif
 HandleFile(opChk, join)
#if PARALLEL
)
#endif
;
#if DEBUG
                    }
                    finally
                    {
                        watch.Stop();
                        Debug.WriteLine(outBsaFilename + " HandleFile loop finished in " + watch.Elapsed);
                    }
#endif
                }
                finally
                {
                    Op.Step();
                }

                try
                {
                    Op.CurrentOperation = "Removing unnecessary files";

                    var notIncluded = allFiles.Where(file => !patchDict.ContainsKey(file.Filename));
                    var filesToRemove = new HashSet<BSAFile>(notIncluded);

                    foreach (BSAFolder folder in bsa)
                        folder.RemoveWhere(filesToRemove.Contains);

                    var emptyFolders = bsa.Where(folder => folder.Count == 0).ToList();
                    emptyFolders.ForEach(folder => bsa.Remove(folder));
                }
                finally
                {
                    Op.Step();
                }

                try
                {
                    Op.CurrentOperation = "Saving " + Path.GetFileName(newBSA);

                    if (!simulate)
                        bsa.Save(newBSA.ToLowerInvariant());
                }
                finally
                {
                    Op.Step();
                }
            }

            Op.Finish();

            return true;
        }
Esempio n. 4
0
 public static Dictionary <string, FileValidation> FromBSA(BSA bsa)
 {
     return(bsa
            .SelectMany(folder => folder)
            .ToDictionary(file => file.Filename, file => FromBSAFile(file)));
 }