public static StringsFolderLookupOverlay?TypicalFactory(string referenceModPath, StringsReadParameters?instructions, ModKey modKey) { var ret = new StringsFolderLookupOverlay(); var stringsFolderPath = instructions?.StringsFolderOverride; var dir = Path.GetDirectoryName(referenceModPath); if (stringsFolderPath == null) { stringsFolderPath = Path.Combine(dir, "Strings"); } if (stringsFolderPath.Value.Exists) { foreach (var file in stringsFolderPath.Value.Info.EnumerateFiles($"{modKey.Name}*{StringsUtility.StringsFileExtension}")) { if (!StringsUtility.TryRetrieveInfoFromString(file.Name, out var type, out var lang, out _)) { continue; } var dict = ret.Get(type); dict[lang] = new Lazy <IStringsLookup>(() => new StringsLookupOverlay(file.FullName, type), LazyThreadSafetyMode.ExecutionAndPublication); } } foreach (var bsaFile in Directory.EnumerateFiles(dir, "*.bsa")) { var bsaReader = BSAReader.Load(new AbsolutePath(bsaFile, skipValidation: true)); foreach (var item in bsaReader.Files) { if (!StringsUtility.TryRetrieveInfoFromString(Path.GetFileName(item.Path.ToString()), out var type, out var lang, out var modName)) { continue; } if (!MemoryExtensions.Equals(modKey.Name, modName, StringComparison.OrdinalIgnoreCase)) { continue; } var dict = ret.Get(type); if (dict.ContainsKey(lang)) { continue; } dict[lang] = new Lazy <IStringsLookup>(() => { byte[] bytes = new byte[item.Size]; using var stream = new MemoryStream(bytes); item.CopyDataTo(stream).AsTask().Wait(); return(new StringsLookupOverlay(bytes, type)); }, LazyThreadSafetyMode.ExecutionAndPublication); } } return(ret); }
/// <summary> /// Reads all bytes from a file, and overlays them /// </summary> /// <param name="path">Path to read in</param> /// <param name="source">Source type</param> public StringsLookupOverlay(string path, StringsSource source) { Init(File.ReadAllBytes(path), StringsUtility.GetFormat(source)); }
/// <summary> /// Overlays onto a set of bytes assumed to be in Strings file format /// </summary> /// <param name="data">Data to wrap</param> /// <param name="source">Source type</param> public StringsLookupOverlay(ReadOnlyMemorySlice <byte> data, StringsSource source) { Init(data, StringsUtility.GetFormat(source)); }
private void WriteStrings(List <KeyValuePair <Language, string>[]> strs, StringsSource source) { if (strs.Count == 0) { return; } WriteDir.Create(); var subLists = new Dictionary <Language, List <(string String, int Index)> >(); for (int i = 0; i < strs.Count; i++) { var item = strs[i]; foreach (var lang in item) { if (!subLists.TryGetValue(lang.Key, out var list)) { list = new List <(string String, int Index)>(); subLists[lang.Key] = list; } list.Add((lang.Value, i + 1)); } } foreach (var language in subLists) { using var writer = new MutagenWriter( Path.Combine(WriteDir.Path, StringsUtility.GetFileName(_modKey, language.Key, source)), meta: null !); // Write count writer.Write(language.Value.Count); // Write filler for length later writer.WriteZeros(4); // Write Directory int size = 0; foreach (var item in language.Value) { writer.Write(item.Index); switch (source) { case StringsSource.Normal: writer.Write(size); size += item.String.Length + 1; break; case StringsSource.IL: case StringsSource.DL: writer.Write(size); size += item.String.Length + 5; break; default: throw new NotImplementedException(); } } // Go back and write content length; var pos = writer.Position; writer.Position = 4; writer.Write(size); writer.Position = pos; // Write strings foreach (var item in language.Value) { switch (source) { case StringsSource.Normal: writer.Write(item.String, StringBinaryType.NullTerminate); break; case StringsSource.IL: case StringsSource.DL: writer.Write(item.String.Length + 1); writer.Write(item.String, StringBinaryType.NullTerminate); break; default: throw new NotImplementedException(); } } } }