public LocResFile(BinaryReader reader) { FGuid MagicNumber = default; if (reader.BaseStream.Length >= Marshal.SizeOf <FGuid>()) { MagicNumber = new FGuid(reader); } LocResVersion VersionNumber = LocResVersion.LEGACY; if (MagicNumber == LocResMagic) { VersionNumber = (LocResVersion)reader.ReadByte(); } else { // Legacy LocRes files lack the magic number, assume that's what we're dealing with, and seek back to the start of the file reader.BaseStream.Seek(0, SeekOrigin.Begin); } if (VersionNumber > LocResVersion.LATEST) { throw new IOException($"LocRes file is too new to be loaded! (File Version: {(byte)VersionNumber}, Loader Version: {(byte)LocMetaVersion.LATEST})"); } // Read the localized string array FTextLocalizationResourceString[] LocalizedStringArray = new FTextLocalizationResourceString[0]; if (VersionNumber >= LocResVersion.COMPACT) { long LocalizedStringArrayOffset = -1; // INDEX_NONE LocalizedStringArrayOffset = reader.ReadInt64(); if (LocalizedStringArrayOffset != -1) { if (VersionNumber >= LocResVersion.OPTIMIZED) { long CurrentFileOffset = reader.BaseStream.Position; reader.BaseStream.Seek(LocalizedStringArrayOffset, SeekOrigin.Begin); LocalizedStringArray = reader.ReadTArray(() => new FTextLocalizationResourceString(reader)); reader.BaseStream.Seek(CurrentFileOffset, SeekOrigin.Begin); } else { string[] TmpLocalizedStringArray; long CurrentFileOffset = reader.BaseStream.Position; reader.BaseStream.Seek(LocalizedStringArrayOffset, SeekOrigin.Begin); TmpLocalizedStringArray = reader.ReadTArray(() => CleanString(AssetReader.read_string(reader))); reader.BaseStream.Seek(CurrentFileOffset, SeekOrigin.Begin); LocalizedStringArray = new FTextLocalizationResourceString[TmpLocalizedStringArray.Length]; for (int i = 0; i < TmpLocalizedStringArray.Length; i++) { LocalizedStringArray[i] = new FTextLocalizationResourceString() { String = TmpLocalizedStringArray[i], RefCount = -1 }; } } } } // Read entries count if (VersionNumber >= LocResVersion.OPTIMIZED) { uint EntriesCount = reader.ReadUInt32(); // No need for initializer // Link: https://github.com/EpicGames/UnrealEngine/blob/7d9919ac7bfd80b7483012eab342cb427d60e8c9/Engine/Source/Runtime/Core/Private/Internationalization/TextLocalizationResource.cpp#L266 } // Read namespace count uint NamespaceCount = reader.ReadUInt32(); for (uint i = 0; i < NamespaceCount; i++) { // Read namespace FTextKey Namespace; if (VersionNumber >= LocResVersion.OPTIMIZED) { Namespace = new FTextKey(reader); } else { Namespace = new FTextKey(CleanString(AssetReader.read_string(reader))); } var Entries = new Dictionary <string, string>(); // Read key count uint KeyCount = reader.ReadUInt32(); for (uint j = 0; j < KeyCount; j++) { // Read key FTextKey Key; if (VersionNumber >= LocResVersion.OPTIMIZED) { Key = new FTextKey(reader); } else { Key = new FTextKey(CleanString(AssetReader.read_string(reader))); } FEntry NewEntry; NewEntry.SourceStringHash = reader.ReadUInt32(); if (VersionNumber >= LocResVersion.COMPACT) { int LocalizedStringIndex = reader.ReadInt32(); if (LocalizedStringArray.Length > LocalizedStringIndex) { // Steal the string if possible FTextLocalizationResourceString LocalizedString = LocalizedStringArray[LocalizedStringIndex]; if (LocalizedString.RefCount == 1) { NewEntry.LocalizedString = LocalizedString.String; LocalizedString.RefCount--; } else { NewEntry.LocalizedString = LocalizedString.String; if (LocalizedString.RefCount != -1) { LocalizedString.RefCount--; } } } else { throw new IOException($"LocRes has an invalid localized string index for namespace '{Namespace}' and key '{Key}'. This entry will have no translation."); } } else { NewEntry.LocalizedString = CleanString(AssetReader.read_string(reader)); } Entries.Add(Key.String, NewEntry.LocalizedString); } this.Entries.Add(Namespace.String, Entries); } }
public LocResReader(BinaryReader reader) { var MagicNumber = new FGuid(reader); var VersionNumber = Version.LEGACY; if (MagicNumber == Magic) { VersionNumber = (Version)reader.ReadByte(); } else { // Legacy LocRes files lack the magic number, assume that's what we're dealing with, and seek back to the start of the file reader.BaseStream.Seek(0, SeekOrigin.Begin); } if (VersionNumber > Version.LATEST) { throw new IOException($"LocRes file is too new to be loaded! (File Version: {(byte)VersionNumber}, Loader Version: {(byte)LocMetaReader.Version.LATEST})"); } // Read the localized string array FTextLocalizationResourceString[] LocalizedStringArray = Array.Empty <FTextLocalizationResourceString>(); if (VersionNumber >= Version.COMPACT) { long LocalizedStringArrayOffset = -1; // INDEX_NONE LocalizedStringArrayOffset = reader.ReadInt64(); if (LocalizedStringArrayOffset != -1) { if (VersionNumber >= Version.OPTIMIZED) { long CurrentFileOffset = reader.BaseStream.Position; reader.BaseStream.Seek(LocalizedStringArrayOffset, SeekOrigin.Begin); LocalizedStringArray = reader.ReadTArray(() => new FTextLocalizationResourceString(reader)); reader.BaseStream.Seek(CurrentFileOffset, SeekOrigin.Begin); } else { string[] TmpLocalizedStringArray; long CurrentFileOffset = reader.BaseStream.Position; reader.BaseStream.Seek(LocalizedStringArrayOffset, SeekOrigin.Begin); TmpLocalizedStringArray = reader.ReadTArray(() => reader.ReadFString()); reader.BaseStream.Seek(CurrentFileOffset, SeekOrigin.Begin); LocalizedStringArray = new FTextLocalizationResourceString[TmpLocalizedStringArray.Length]; for (int i = 0; i < TmpLocalizedStringArray.Length; i++) { LocalizedStringArray[i] = new FTextLocalizationResourceString(TmpLocalizedStringArray[i], -1); } } } } // Read entries count if (VersionNumber >= Version.OPTIMIZED) { uint EntriesCount = reader.ReadUInt32(); // No need for initializer // Link: https://github.com/EpicGames/UnrealEngine/blob/7d9919ac7bfd80b7483012eab342cb427d60e8c9/Engine/Source/Runtime/Core/Private/Internationalization/TextLocalizationResource.cpp#L266 } // Read namespace count uint NamespaceCount = reader.ReadUInt32(); for (uint i = 0; i < NamespaceCount; i++) { // Read namespace if (VersionNumber >= Version.OPTIMIZED) { reader.ReadUInt32(); // StrHash } var Namespace = reader.ReadFString(); var Entries = new Dictionary <string, string>(); // Read key count uint KeyCount = reader.ReadUInt32(); for (uint j = 0; j < KeyCount; j++) { // Read key if (VersionNumber >= Version.OPTIMIZED) { reader.ReadUInt32(); // StrHash } var Key = reader.ReadFString(); reader.ReadUInt32(); // SourceStringHash string EntryLocalizedString; if (VersionNumber >= Version.COMPACT) { int LocalizedStringIndex = reader.ReadInt32(); if (LocalizedStringArray.Length > LocalizedStringIndex) { // Steal the string if possible ref var LocalizedString = ref LocalizedStringArray[LocalizedStringIndex]; if (LocalizedString.RefCount == 1) { EntryLocalizedString = LocalizedString.String; LocalizedString.RefCount--; } else { EntryLocalizedString = LocalizedString.String; if (LocalizedString.RefCount != -1) { LocalizedString.RefCount--; } } } else { throw new IOException($"LocRes has an invalid localized string index for namespace '{Namespace}' and key '{Key}'. This entry will have no translation."); } }
public LocResReader(BinaryReader reader) { var MagicNumber = new FGuid(reader); var VersionNumber = Version.Legacy; if (MagicNumber == Magic) { VersionNumber = (Version)reader.ReadByte(); } else { // Legacy LocRes files lack the magic number, assume that's what we're dealing with, and seek back to the start of the file reader.BaseStream.Seek(0, SeekOrigin.Begin); } if (VersionNumber > Version.Latest) { throw new IOException($"LocRes file is too new to be loaded! (File Version: {(byte)VersionNumber}, Loader Version: {(byte)LocMetaReader.Version.LATEST})"); } // Read the localized string array FTextLocalizationResourceString[] LocalizedStringArray = Array.Empty <FTextLocalizationResourceString>(); if (VersionNumber >= Version.Compact) { long LocalizedStringArrayOffset = -1; // INDEX_NONE LocalizedStringArrayOffset = reader.ReadInt64(); if (LocalizedStringArrayOffset != -1) { long CurrentFileOffset = reader.BaseStream.Position; reader.BaseStream.Seek(LocalizedStringArrayOffset, SeekOrigin.Begin); if (VersionNumber >= Version.Optimized_CRC32) { LocalizedStringArray = reader.ReadTArray(() => new FTextLocalizationResourceString(reader)); reader.BaseStream.Seek(CurrentFileOffset, SeekOrigin.Begin); } else { string[] TmpLocalizedStringArray; TmpLocalizedStringArray = reader.ReadTArray(() => reader.ReadFString()); reader.BaseStream.Seek(CurrentFileOffset, SeekOrigin.Begin); LocalizedStringArray = new FTextLocalizationResourceString[TmpLocalizedStringArray.Length]; for (int i = 0; i < TmpLocalizedStringArray.Length; i++) { LocalizedStringArray[i] = new FTextLocalizationResourceString(TmpLocalizedStringArray[i], -1); } } } } if (VersionNumber >= Version.Optimized_CRC32) { reader.ReadUInt32(); // EntriesCount } // Read namespace count uint NamespaceCount = reader.ReadUInt32(); for (uint i = 0; i < NamespaceCount; i++) { if (VersionNumber >= Version.Optimized_CRC32) { reader.ReadUInt32(); // StrHash } string Namespace = reader.ReadFString(); uint KeyCount = reader.ReadUInt32(); Dictionary <string, string> Entries = new Dictionary <string, string>((int)KeyCount); for (uint j = 0; j < KeyCount; j++) { // Read key if (VersionNumber >= Version.Optimized_CRC32) { reader.ReadUInt32(); // StrHash } string Key = reader.ReadFString(); reader.ReadUInt32(); // SourceStringHash string EntryLocalizedString; if (VersionNumber >= Version.Compact) { int LocalizedStringIndex = reader.ReadInt32(); if (LocalizedStringArray.Length > LocalizedStringIndex) { // Steal the string if possible ref var LocalizedString = ref LocalizedStringArray[LocalizedStringIndex]; if (LocalizedString.RefCount == 1) { EntryLocalizedString = LocalizedString.String; LocalizedString.RefCount--; } else { EntryLocalizedString = LocalizedString.String; if (LocalizedString.RefCount != -1) { LocalizedString.RefCount--; } } } else { throw new IOException($"LocRes has an invalid localized string index for namespace '{Namespace}' and key '{Key}'. This entry will have no translation."); } }