/// <summary> /// Writes a <see cref="VersionResource"/> object to the current <see cref="Stream"/>. /// </summary> /// <param name="resource"> /// The <see cref="VersionResource"/> to write. /// </param> public void Write(VersionResource resource) { if (resource == null) { throw new ArgumentNullException(nameof(resource)); } if (Stream.Length < resource.Size) { Stream.SetLength(resource.Size); } using (var stream = new SubStream(Stream, 0, Stream.Length, leaveParentOpen: true)) using (var writer = new BinaryWriter(stream, Encoding.Unicode)) { // Write the version resource header WriteHeader( writer, resource.Size, resource.FixedFileInfo == null ? 0 : Marshal.SizeOf(typeof(VS_FIXEDFILEINFO)), VersionDataType.Binary, "VS_VERSION_INFO"); if (resource.FixedFileInfo != null) { writer.WriteStruct(resource.FixedFileInfo.Value); } writer.Align(); if (resource.VarFileInfo != null) { WriteHeader(writer, resource.VarFileInfoSize, 0, VersionDataType.Text, "VarFileInfo"); WriteVarFileInfo(writer, resource); } if (resource.StringFileInfo != null) { WriteHeader(writer, resource.StringFileInfoSize, 0, VersionDataType.Text, "StringFileInfo"); WriteStringFileInfo(writer, resource); } } }
/// <summary> /// Reads a <see cref="VersionResource"/> object from the current <see cref="Stream"/>. /// </summary> /// <returns> /// A <see cref="VersionResource"/> object. /// </returns> public VersionResource Read() { Stream.Position = 0; var value = new VersionResource(); using (var stream = new SubStream(Stream, 0, Stream.Length, leaveParentOpen: true)) using (var reader = new BinaryReader(stream, Encoding.Default)) { var offset = Stream.Position; var versionInfo = reader.ReadVersionInfo(); var end = offset + versionInfo.Header.Length; // The root element MUST be a "VS_VERSION_INFO" element of binary type. // https://msdn.microsoft.com/en-us/library/windows/desktop/ms647001(v=vs.85).aspx // It contains at most three children - a VS_FIXEDFILEINFO object, a StringFileInfo struct // and a VarFileInfo struct. if (versionInfo.Key != "VS_VERSION_INFO") { throw new VersionResourceFormatException(); } if (versionInfo.Header.Type != VersionDataType.Binary) { throw new VersionResourceFormatException(); } // We know a VS_FIXEDFILEINFO struct is present if the ValueLength > 0 if (versionInfo.Header.ValueLength != 0) { // Read the file info value.FixedFileInfo = reader.ReadStruct<VS_FIXEDFILEINFO>(); reader.Align(); } // Read the children: At most one StringFileInfo and at most one VarFileInfo while (Stream.Position < end) { var childOffset = Stream.Position; var childInfo = reader.ReadVersionInfo(); var childEnd = childOffset + childInfo.Header.Length; switch (childInfo.Key) { case "VarFileInfo": if (childInfo.Header.Type != VersionDataType.Text) { throw new VersionResourceFormatException(); } value.VarFileInfo = ReadVarFileInfo(reader); break; case "StringFileInfo": if (childInfo.Header.Type != VersionDataType.Text) { throw new VersionResourceFormatException(); } value.StringFileInfo = ReadStringFileInfo(reader, childEnd); break; } } return value; } }