public static void ReadCsf(Csf csf, Stream stream, SageGame game) { using (var reader = new BinaryReader(stream, Encoding.ASCII, true)) { var magic = reader.ReadInt32(); if (magic != _magicCsf) { throw new InvalidDataException("Error parsing csf (Magic: CSF expected)."); } var version = reader.ReadInt32(); var numLabels = reader.ReadInt32(); var numStrings = reader.ReadInt32(); if (numLabels != numStrings) { // throw new NotSupportedException("Csf substrings are not supported."); logger.Warn("[CSF] Number of labels and strings mismatch."); } csf._numStrings = numStrings; reader.ReadUInt32(); // reserved var languageCode = reader.ReadUInt32(); string language; switch (game) { case SageGame.CncGenerals: case SageGame.CncGeneralsZeroHour: language = ((LanguageGenerals)languageCode).GetName(); break; case SageGame.Bfme: case SageGame.Bfme2: case SageGame.Bfme2Rotwk: language = ((LanguageBFME)languageCode).GetName(); break; case SageGame.Cnc3: case SageGame.Cnc3KanesWrath: language = ((LanguageCnC3)languageCode).GetName(); break; default: language = "en-US"; break; } if (language is null) { language = "en-US"; logger.Warn($"Unknown language id {languageCode} for game {game}."); } csf._language = language; string label; int strCount; string str; int colonIdx; string categoryLabel; for (var idx = 0; idx < numLabels; ++idx) { magic = reader.ReadInt32(); if (magic != _magicLabel) { throw new InvalidDataException("Error parsing csf (Magic: LBL expected)."); } strCount = reader.ReadInt32(); label = reader.ReadUInt32PrefixedAsciiString(); for (var idy = 0; idy < strCount; ++idy) { magic = reader.ReadInt32(); if (magic != _magicLString && magic != _magicLWideString) { throw new InvalidDataException("Error parsing csf (Magic: STR/STRW expected)."); } if (idy == 0) { str = reader.ReadUInt32PrefixedNegatedUnicodeString(); if (magic == _magicLWideString) { str += reader.ReadUInt32PrefixedAsciiString(); } colonIdx = label.IndexOf(':'); if (colonIdx == -1) { categoryLabel = string.Empty; logger.Warn($"Empty category found for {label}."); } else { categoryLabel = label.Substring(0, colonIdx).ToUpperInvariant(); } if (!csf._strings.TryGetValue(categoryLabel, out var category)) { category = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase); csf._strings.Add(categoryLabel, category); } label = label.Substring(colonIdx + 1); if (category.ContainsKey(label)) { logger.Warn($"[CSF] String duplication: '{categoryLabel}:{label}' -> '{category[label]}', new value: '{str}'"); } else { category.Add(label, str); } } else { if (magic == _magicLString) { logger.Info($"[CSF] Skipping substring '{reader.ReadUInt32PrefixedNegatedUnicodeString()}' from {label}."); } else { logger.Info($"[CSF] Skipping substring '{reader.ReadUInt32PrefixedNegatedUnicodeString()}{reader.ReadUInt32PrefixedAsciiString()}' from {label}."); } } } } } }
public CsfTranslationProvider(Stream stream, SageGame game) { Debug.Assert(!(stream is null), $"{nameof(stream)} is null"); _csf = new Csf(); Csf.ReadCsf(_csf, stream, game); }