/// <summary> /// Add string with key to the end of the list, unless an index is given. /// If an index is given the key/value will be added at that index, and all keys/values after that index will be moved one slot /// </summary> /// <param name="key"></param> /// <param name="value"></param> public void AddString(string key, string value, int index = -1) { GMD_Entry newEntry = new GMD_Entry { Key = key, Value = value }; if (index == -1) { Entries.Add(newEntry); } else { Entries.Insert(index, newEntry); } }
public GMD(string path) : base(path) { log.Info($"Loading '{path}'"); using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read)) using (BinaryReader br = new BinaryReader(fs)) { // Header _header = br.ReadStruct <GMD_Header>(); if (_header.MagicString != "GMD") { throw new Exception("Not a GMD file!"); } // Log some info about the GMD language if (Enum.IsDefined(typeof(EmLanguage), _header.Language)) { EmLanguage language = (EmLanguage)_header.Language; log.Info("Language: " + language); } else { log.Warn($"Unknown language: 0x{_header.Language:X04} ({_header.Language})"); } // Filename Filename = br.ReadStringZero(ExEncoding.ASCII); // Set Entries initial capacity Entries = new List <IGMD_Entry>(_header.StringCount); // Info Table for (int i = 0; i < _header.KeyCount; i++) { GMD_Entry entry = new GMD_Entry { InfoTableEntry = br.ReadStruct <GMD_InfoTableEntry>() }; int lastStringIndex = 0; if (Entries.OfType <GMD_Entry>().Count() > 0) { lastStringIndex = Entries.OfType <GMD_Entry>().Last().InfoTableEntry.StringIndex; } for (int j = lastStringIndex + 1; j < entry.InfoTableEntry.StringIndex; j++) { Entries.Add(new GMD_EntryWithoutKey()); } Entries.Add(entry); } // If there are "Invalid Message" entries after the last valid entry then the above code won't add GMD_EntryWithoutKey's for those entries // So here we add GMD_EntryWithoutKey entries till we have {StringCount} amount of them for (int i = Entries.Count; i < _header.StringCount; i++) { Entries.Add(new GMD_EntryWithoutKey()); } // Block with unknown data _unk1 = br.ReadBytes(0x800); // Keys, this skips over the GMD_EntryWithoutKey entries foreach (GMD_Entry entry in Entries.OfType <GMD_Entry>()) { entry.Key = br.ReadStringZero(ExEncoding.UTF8); } // Strings string[] strings = new string[_header.StringCount]; long startOfStringBlock = fs.Position; for (int i = 0; i < _header.StringCount; i++) { if (fs.Position == fs.Length) { log.Warn($"Expected to read {_header.StringCount - i} more strings (for a total of {_header.StringCount}). But we already are at the end of the stream!"); break; } strings[i] = br.ReadStringZero(ExEncoding.UTF8); } log.Info("Expected StringBlockSize = " + _header.StringBlockSize); log.Info("Actual StringBlockSize = " + (fs.Position - startOfStringBlock)); if (_header.StringBlockSize != (fs.Position - startOfStringBlock)) { log.Warn("Actual StringBlockSize is not the same as the expected StringBlockSize!"); } for (int i = 0; i < _header.StringCount; i++) { Entries[i].Value = strings[i]; } } }