private void CommitToNew() { // don't unload this instance since it needs to read from it first // NOTE: this method does not preserve custom ResourceHeader fields like Characteristics and MemoryFlags var tempFileName = Path.GetTempFileName(); using (var o = new FileStream(tempFileName, FileMode.Open, FileAccess.Write)) { var wtr = new BinaryWriter(o, Encoding.Unicode); foreach (var lang in AllLangs) { if (lang.Action == ResourceDataAction.Delete) { continue; // skip langs to delete, which means they'll get deleted } // the actual data will be lazy-loaded on each write ResResourceHeader.WriteResource(lang, wtr); } } // close the current input stream Unload(); // and overwrite the file FileInfo.Delete(); File.Move(tempFileName, FileInfo.FullName); Reload(); }
private void CommitAddChanges() { Unload(); _stream = new FileStream(FileInfo.FullName, FileMode.Open, FileAccess.Write); _stream.Seek(0, SeekOrigin.End); // seek to end var wtr = new BinaryWriter(_stream, Encoding.Unicode); wtr.Align4(); foreach (var lang in AllActiveLangs) { ResResourceHeader.WriteResource(lang, wtr); } _stream.Close(); Reload(); }
public override void Reload() { UnderlyingClear(); _stream?.Close(); // consequtive calls to .Close() is safe _stream = new FileStream(FileInfo.FullName, FileMode.Open); if (!_stream.CanSeek) { throw new AnolisException("RES FileStream must support seeking"); } _resources.Clear(); // the RES format is quite simple, it's just a concatenated list of Resource Data instances, all with their header info _stream.Seek(0, SeekOrigin.Begin); var rdr = new BinaryReader(_stream, Encoding.Unicode); while (rdr.BaseStream.Position < rdr.BaseStream.Length) { /////////////////////////////// // Read the RESOURCEHEADER var start = rdr.BaseStream.Position; var header = new ResResourceHeader(rdr); if (header.DataSize == 0 && rdr.BaseStream.Position == rdr.BaseStream.Length) { break; } var stop = rdr.BaseStream.Position; var headerSize = (int)(stop - start); var res = new ResResource { DataOffset = rdr.BaseStream.Position, // HACK: this might cause problems for resources larger than 2GB DataLength = (int)header.DataSize, HeaderOffset = start, HeaderLength = header.HeaderSize }; // Read past the Resource data _stream.Seek(header.DataSize, SeekOrigin.Current); // don't do anything if it's empty if (!(header.Type is string)) { var headerType = Convert.ToInt32(header.Type, CultureInfo.InvariantCulture); if (headerType == 0) { rdr.Align4(); continue; } } /////////////////////////////// // Create ResourceType, Name, and Lang instance var typeId = header.Type is string s ? new ResourceTypeIdentifier(s) : new ResourceTypeIdentifier(Convert.ToInt32(header.Type, CultureInfo.InvariantCulture)); var type = UnderlyingFind(t => t.Identifier.Equals(typeId)); if (type == null) { type = new ResourceType(typeId, this); UnderlyingAdd(type); } /////////////////////////////////////////////////////////// var nameId = header.Name is string headerName ? new ResourceIdentifier(headerName) : new ResourceIdentifier(Convert.ToInt32(header.Name, CultureInfo.InvariantCulture)); var name = UnderlyingFind(type, n => n.Identifier.Equals(nameId)); if (name == null) { name = new ResourceName(nameId, type); UnderlyingAdd(type, name); } /////////////////////////////////////////////////////////// // TODO: Maybe do some validation to ensure the same lang hasn't been added twice? var lang = new ResourceLang(header.LanguageId, name); UnderlyingAdd(name, lang); /////////////////////////////////////////////////////////// res.Lang = lang; _resources.Add(res); rdr.Align4(); } }