Example #1
0
        private static void CreateAssetPatch(Settings settings, IBSA original, Fo3File originalRecord, Fo3File resultRecord, RecordAction recordAction)
        {
            string patchName;
            string patchFile;

            // @todo: memory stream and name with md5
            using (var patchStream = new MemoryStream())
            {
                // @todo: lock
                byte[] originalRecordBytes;
                if (original != null)
                {
                    lock (original)
                    {
                        originalRecordBytes = originalRecord.GetData(original.Reader);
                    }
                }
                else
                {
                    originalRecordBytes = originalRecord.GetData();
                }
                var referenceBytes = resultRecord.GetData();
                BsDiff.Create(originalRecordBytes, referenceBytes, patchStream);

                patchStream.Seek(0, SeekOrigin.Begin);
                patchName = new Guid(MD5.Create().ComputeHash(patchStream)).ToString();
                recordAction.PatchName = patchName;
                patchFile = string.Format("{0}\\{1}.patch", settings.GetTempFolder("Patches"), patchName);

                try
                {
                    using (var fileStream = new FileStream(patchFile, FileMode.CreateNew))
                    {
                        patchStream.Seek(0, SeekOrigin.Begin);
                        patchStream.CopyTo(fileStream);
                    }
                }
                catch (IOException exc)
                {
                    // ignored
                }
            }
        }
Example #2
0
        private static void CreateTTWBSA(Recipe recipe, Settings settings, DirectoryInfo assetsDir, string name)
        {
            Console.Write("Creating {0} ... ", name);
            var filepair = new FilePair()
            {
                ResultName = name,
                Type       = ContentType.BSA,
            };

            var looseFiles = PrepareLooseFiles(assetsDir);
            var patchFile  = Path.Combine(assetsDir.FullName, "ttw.patch.txt");
            SortedDictionary <string, Tuple <string, string, string> > patches = null;

            if (File.Exists(patchFile))
            {
                patches = ReadPatchFile(patchFile);
            }

            foreach (var file in looseFiles)
            {
                if (patches != null && patches.ContainsKey(file.Key))
                {
                    var patch        = patches[file.Key];
                    var recordAction = new RecordAction
                    {
                        Origin  = patch.Item1,
                        Path    = patch.Item2.Substring(0, patch.Item2.LastIndexOf("\\", StringComparison.Ordinal)),
                        Name    = patch.Item2.Substring(patch.Item2.LastIndexOf("\\", StringComparison.Ordinal) + 1),
                        NewPath = patch.Item3.Substring(0, patch.Item3.LastIndexOf("\\", StringComparison.Ordinal)),
                        NewName = patch.Item3.Substring(patch.Item3.LastIndexOf("\\", StringComparison.Ordinal) + 1),
                        Type    = ActionType.Rename | ActionType.Patch
                    };

                    var referenceFile = $"{settings.CurrentDataPath}\\{patch.Item1}";
                    var referenceDir  = new DirectoryInfo(Path.ChangeExtension(referenceFile, null));

                    var reference = new SortedDictionary <string, Fo3File>();
                    Parallel.ForEach(referenceDir.EnumerateFiles("*.*", SearchOption.AllDirectories).AsParallel(), new ParallelOptions {
                        MaxDegreeOfParallelism = Environment.ProcessorCount
                    }, asset =>
                    {
                        var assetFile = new Fo3File(asset)
                        {
                            Path = asset.GetPathRelative(referenceDir.FullName).ToLower()
                        };
                        lock (reference)
                        {
                            reference.Add(asset.GetFullNameRelative(referenceDir.FullName).ToLower(), assetFile);
                        }
                    });

                    try
                    {
                        var originalRecord = reference[patch.Item2];
                        var resultRecord   = new Fo3File(new FileInfo(Path.Combine(assetsDir.FullName, patch.Item3)));

                        patchQueue.Enqueue(() => CreateAssetPatch(settings, null, originalRecord, resultRecord,
                                                                  recordAction));
                    }
                    catch (Exception e)
                    {
                        recordAction.Error = e.Message;
                    }

                    filepair.Actions.Add(recordAction);
                }
                else
                {
                    filepair.Actions.Add(new RecordAction
                    {
                        Path = file.Value.GetPathRelative(assetsDir.FullName).ToLower(),
                        Name = file.Value.Name.ToLower(),
                        Type = ActionType.New
                    });
                }
            }

            recipe.Files.Add(filepair);
            FlushRecipe(settings, recipe);
            Console.WriteLine("Done");
        }
Example #3
0
        private static void ProcessBSAs(Recipe recipe, Settings settings)
        {
            Console.WriteLine("Processing BSAs ...");
            foreach (var filepair in settings.Files.Where(fp => fp.Type == ContentType.BSA))
            {
                Console.Write("{0} => {1} .", filepair.OriginalName, filepair.ResultName);

                var before   = GC.GetTotalMemory(false);
                var original = BSA.Open(string.Format("{0}\\{1}", settings.Fo3DataPath, filepair.OriginalName));
                original.BuildIndex();
                var after = GC.GetTotalMemory(false);

                var referenceFile = string.Format("{0}\\{1}", settings.CurrentDataPath, filepair.ResultName);
                var referenceDir  = new DirectoryInfo(Path.ChangeExtension(referenceFile, null));

                Console.Write(".");
                SortedDictionary <string, Fo3File> reference = new SortedDictionary <string, Fo3File>();
                Parallel.ForEach(referenceDir.EnumerateFiles("*.*", SearchOption.AllDirectories).AsParallel(), new ParallelOptions {
                    MaxDegreeOfParallelism = Environment.ProcessorCount
                }, file =>
                {
                    var assetFile = new Fo3File(file)
                    {
                        Path = file.GetPathRelative(referenceDir.FullName).ToLower()
                    };
                    lock (reference)
                    {
                        reference.Add(file.GetFullNameRelative(referenceDir.FullName).ToLower(), assetFile);
                    }
                });
                Console.Write(". ");

                Parallel.ForEach(reference, new ParallelOptions {
                    MaxDegreeOfParallelism = 1                                               /* Environment.ProcessorCount */
                }, record =>
                {
                    Debug.Write(record.Key);
                    if (original.IndexFullPath.ContainsKey(record.Key))
                    {
                        if (!ByteArrayCompare(record.Value.Checksum, original.IndexFullPath[record.Key].Checksum))
                        {
                            var originalRecord = original.IndexFullPath[record.Key];
                            var resultRecord   = record.Value;

                            var recordAction = new RecordAction {
                                Path = record.Value.Path, Name = record.Value.Name, Type = ActionType.Copy | ActionType.Patch
                            };
                            patchQueue.Enqueue(() => CreateAssetPatch(settings, original, originalRecord, resultRecord, recordAction));
                            filepair.Actions.Add(recordAction);

                            Debug.WriteLine(" patch");
                        }
                        else
                        {
                            filepair.Actions.Add(new RecordAction {
                                Path = record.Value.Path, Name = record.Value.Name, Type = ActionType.Copy
                            });
                            Debug.WriteLine(" copy");
                        }
                        original.IndexFullPath.Remove(record.Key);
                    }
                    else if (original.IndexFileName.ContainsKey(BitConverter.ToString(record.Value.Checksum)))
                    {
                        var originalRecord = original.IndexFileName[BitConverter.ToString(record.Value.Checksum)];
                        if (original.IndexFullPath.ContainsKey(record.Key))
                        {
                            original.IndexFullPath.Remove(record.Key);
                        }

                        filepair.Actions.Add(new RecordAction {
                            Path = originalRecord.Path, Name = originalRecord.Name, Type = ActionType.Rename, NewPath = record.Value.Path, NewName = record.Value.Name
                        });
                        Debug.WriteLine(" rename");
                    }
                    else
                    {
                        filepair.Actions.Add(new RecordAction {
                            Path = record.Value.Path, Name = record.Value.Name, Type = ActionType.New
                        });
                        Debug.WriteLine(" new");
                    }

                    Console.Write("\r{0} => {1} ... {2}/{3}", filepair.OriginalName, filepair.ResultName, filepair.Actions.Count, reference.Count);
                });

                var i = 0;
                foreach (var newRecord in original.IndexFullPath)
                {
                    filepair.Actions.Add(new RecordAction {
                        Path = newRecord.Value.Path, Name = newRecord.Value.Name, Type = ActionType.Delete
                    });
                    Console.Write("\r{0} => {1} ... D{2}/{3}               ", filepair.OriginalName, filepair.ResultName, ++i, original.IndexFullPath.Count);
                    Debug.WriteLine(newRecord.Key);
                }

                recipe.Files.Add(filepair);

                Console.Write("\r{0} => {1} ... ", filepair.OriginalName, filepair.ResultName);
                Console.WriteLine("Done                               ");
#if DEBUG
                FlushRecipe(settings, recipe);
#endif
            }
            Console.WriteLine("BSAs completed");
        }