From d29b197f72e6e72c228afc40680374cf99cc1184 Mon Sep 17 00:00:00 2001 From: Michael Becker Date: Thu, 30 Jul 2020 09:37:13 -0400 Subject: [PATCH] preliminary work on NTFS filesystem and OLE1 data formats --- .../NTFS/Attributes/NTFSDataAttribute.cs | 28 ++ .../NTFS/Attributes/NTFSFileNameAttribute.cs | 35 ++ .../NTFSStandardInformationAttribute.cs | 30 ++ .../Microsoft/NTFS/NTFSAttribute.cs | 30 ++ .../Microsoft/NTFS/NTFSDataFormat.cs | 344 ++++++++++++++++++ .../Microsoft/NTFS/NTFSMediaDescriptor.cs | 34 ++ .../Microsoft/NTFS/NTFSMftEntryFlags.cs | 31 ++ .../Microsoft/NTFS/NTFSMftKnownAttribute.cs | 33 ++ .../Microsoft/OLE/OLE1/OLE1ChunkType.cs | 38 ++ .../Microsoft/OLE/OLE1/OLE1DataFormat.cs | 187 ++++++++++ .../Microsoft/OLE/OLE1/OLE1ObjectHeader.cs | 34 ++ .../OLE/OLE1/OLE1PresentationObject.cs | 32 ++ .../UniversalEditor.Plugins.Microsoft.csproj | 16 + 13 files changed, 872 insertions(+) create mode 100644 Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/NTFS/Attributes/NTFSDataAttribute.cs create mode 100644 Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/NTFS/Attributes/NTFSFileNameAttribute.cs create mode 100644 Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/NTFS/Attributes/NTFSStandardInformationAttribute.cs create mode 100644 Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/NTFS/NTFSAttribute.cs create mode 100644 Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/NTFS/NTFSDataFormat.cs create mode 100644 Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/NTFS/NTFSMediaDescriptor.cs create mode 100644 Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/NTFS/NTFSMftEntryFlags.cs create mode 100644 Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/NTFS/NTFSMftKnownAttribute.cs create mode 100644 Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/OLE/OLE1/OLE1ChunkType.cs create mode 100644 Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/OLE/OLE1/OLE1DataFormat.cs create mode 100644 Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/OLE/OLE1/OLE1ObjectHeader.cs create mode 100644 Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/OLE/OLE1/OLE1PresentationObject.cs diff --git a/Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/NTFS/Attributes/NTFSDataAttribute.cs b/Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/NTFS/Attributes/NTFSDataAttribute.cs new file mode 100644 index 00000000..a07485e9 --- /dev/null +++ b/Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/NTFS/Attributes/NTFSDataAttribute.cs @@ -0,0 +1,28 @@ +// +// NTFSDataAttribute.cs +// +// Author: +// Michael Becker +// +// Copyright (c) 2020 Mike Becker's Software +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +using System; +namespace UniversalEditor.DataFormats.FileSystem.Microsoft.NTFS.Attributes +{ + public class NTFSDataAttribute : NTFSAttribute + { + public byte[] Data { get; set; } = null; + } +} diff --git a/Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/NTFS/Attributes/NTFSFileNameAttribute.cs b/Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/NTFS/Attributes/NTFSFileNameAttribute.cs new file mode 100644 index 00000000..74bf9136 --- /dev/null +++ b/Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/NTFS/Attributes/NTFSFileNameAttribute.cs @@ -0,0 +1,35 @@ +// +// NTFSFileNameAttribute.cs +// +// Author: +// Michael Becker +// +// Copyright (c) 2020 Mike Becker's Software +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +using System; +namespace UniversalEditor.DataFormats.FileSystem.Microsoft.NTFS.Attributes +{ + public class NTFSFileNameAttribute : NTFSAttribute + { + public DateTime CreationDateTime { get; set; } + public DateTime ModificationDateTime { get; set; } + public DateTime AccessDateTime { get; set; } + + public long AllocatedSize { get; set; } + public long ActualSize { get; set; } + + public string FileName { get; set; } = null; + } +} diff --git a/Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/NTFS/Attributes/NTFSStandardInformationAttribute.cs b/Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/NTFS/Attributes/NTFSStandardInformationAttribute.cs new file mode 100644 index 00000000..fb71a98b --- /dev/null +++ b/Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/NTFS/Attributes/NTFSStandardInformationAttribute.cs @@ -0,0 +1,30 @@ +// +// NTFSStandardInformationAttribute.cs +// +// Author: +// Michael Becker +// +// Copyright (c) 2020 Mike Becker's Software +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +using System; +namespace UniversalEditor.DataFormats.FileSystem.Microsoft.NTFS.Attributes +{ + public class NTFSStandardInformationAttribute : NTFSAttribute + { + public NTFSStandardInformationAttribute() + { + } + } +} diff --git a/Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/NTFS/NTFSAttribute.cs b/Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/NTFS/NTFSAttribute.cs new file mode 100644 index 00000000..6b85932d --- /dev/null +++ b/Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/NTFS/NTFSAttribute.cs @@ -0,0 +1,30 @@ +// +// NTFSAttribute.cs +// +// Author: +// Michael Becker +// +// Copyright (c) 2020 Mike Becker's Software +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +using System; +namespace UniversalEditor.DataFormats.FileSystem.Microsoft.NTFS +{ + public abstract class NTFSAttribute + { + public NTFSAttribute() + { + } + } +} diff --git a/Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/NTFS/NTFSDataFormat.cs b/Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/NTFS/NTFSDataFormat.cs new file mode 100644 index 00000000..4a7cff33 --- /dev/null +++ b/Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/NTFS/NTFSDataFormat.cs @@ -0,0 +1,344 @@ +// +// NTFSDataFormat.cs - provides a DataFormat for manipulating NTFS file systems +// +// Author: +// Michael Becker +// +// Copyright (c) 2020 Mike Becker's Software +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System; +using System.Collections.Generic; +using UniversalEditor.DataFormats.FileSystem.Microsoft.NTFS.Attributes; +using UniversalEditor.IO; +using UniversalEditor.ObjectModels.FileSystem; + +namespace UniversalEditor.DataFormats.FileSystem.Microsoft.NTFS +{ + /// + /// Provides a for manipulating NTFS file systems. + /// + public class NTFSDataFormat : DataFormat + { + private static DataFormatReference _dfr = null; + protected override DataFormatReference MakeReferenceInternal() + { + if (_dfr == null) + { + _dfr = base.MakeReferenceInternal(); + _dfr.Capabilities.Add(typeof(FileSystemObjectModel), DataFormatCapabilities.All); + } + return _dfr; + } + + protected override void LoadInternal(ref ObjectModel objectModel) + { + FileSystemObjectModel fsom = (objectModel as FileSystemObjectModel); + if (fsom == null) throw new ObjectModelNotSupportedException(); + + Reader reader = Accessor.Reader; + byte[] jump = reader.ReadBytes(3); + + string id = reader.ReadFixedLengthString(8); // 'NTFS ' + if (id != "NTFS ") throw new InvalidDataFormatException("file does not begin with 'NTFS '"); + + BytesPerSector = reader.ReadInt16(); + SectorsPerCluster = reader.ReadByte(); + + short reservedSectors = reader.ReadInt16(); // 0x0000 + byte[] reserved2 = reader.ReadBytes(3); // 00 00 00 + short reserved3 = reader.ReadInt16(); // 0x0000 + MediaDescriptor = (NTFSMediaDescriptor)reader.ReadByte(); + short reserved4 = reader.ReadInt16(); // 0x0000 + SectorsPerTrack = reader.ReadInt16(); + NumberOfHeads = reader.ReadInt16(); + HiddenSectors = reader.ReadInt32(); + int reserved5 = reader.ReadInt32(); // 0x00000000 + int reserved6 = reader.ReadInt32(); // 0x00800080 + long totalSectors = reader.ReadInt64(); // 0x00000000007FF54A + long masterFileTableClusterNumber = reader.ReadInt64(); // 0x0000000000000004 + long masterFileTableMirrorClusterNumber = reader.ReadInt64(); // 0x000000000007FF54 + + // A positive value denotes the number of clusters in a File Record Segment. A negative value denotes the amount of bytes in a File Record Segment, in which case the + // size is 2 to the power of the absolute value. (0xF6 = -10 → 210 = 1024). + sbyte bytesOrClustersPerFileRecordSegment = reader.ReadSByte(); + + byte[] reserved7 = reader.ReadBytes(3); + + // A positive value denotes the number of clusters in an Index Buffer. A negative value denotes the amount of bytes and it uses the same algorithm for negative + // numbers as the "Bytes or Clusters Per File Record Segment." + byte bytesOrClustersPerIndexBuffer = reader.ReadByte(); + + byte[] reserved8 = reader.ReadBytes(3); + long volumeSerialNumber = reader.ReadInt64(); // A unique random number assigned to this partition, to keep things organized. + + int checksum = reader.ReadInt32(); // checksum + + byte[] bootstrapCodeBlock = reader.ReadBytes(426); + + ushort endOfSectorMarker = reader.ReadUInt16(); + if (endOfSectorMarker != 0xAA55) + { + throw new InvalidDataFormatException("file does not contain end of sector marker"); + } + + SeekToCluster(masterFileTableClusterNumber); + + while (true) + { + bool retval = ReadFile(reader, out File file); + if (!retval) + break; + + if (file != null) + { + fsom.Files.Add(file); + } + } + } + + private bool ReadFile(Reader reader, out File file) + { + long thisoffset = reader.Accessor.Position; + + string signature = reader.ReadFixedLengthString(4); + if (signature != "FILE") + { + file = null; + return false; + } + + file = new File(); + + ushort offsetToUpdateSequence = reader.ReadUInt16(); + ushort fixupEntryCount = reader.ReadUInt16(); + long logFileSequenceNumber = reader.ReadInt64(); + ushort sequenceNumber = reader.ReadUInt16(); + ushort hardLinkCount = reader.ReadUInt16(); + ushort firstAttributeOffset = reader.ReadUInt16(); + NTFSMftEntryFlags flags = (NTFSMftEntryFlags)reader.ReadUInt16(); + + uint mftEntryUsedSize = reader.ReadUInt32(); + uint mftEntryAllocatedSize = reader.ReadUInt32(); + long baseFILErecordRef = reader.ReadInt64(); + ushort nextAttributeID = reader.ReadUInt16(); + ushort align = reader.ReadUInt16(); + uint mftRecordNumber = reader.ReadUInt32(); + + reader.Accessor.Seek(thisoffset + firstAttributeOffset, SeekOrigin.Begin); + + // read the attributes + while (true) + { + bool keepgoing = ReadAttribute(reader, out NTFSMftKnownAttribute type, out NTFSAttribute attr); + if (attr == null && type != NTFSMftKnownAttribute.End) + { + Console.WriteLine("ue: ntfs: WARNING: skipping unknown attribute {0}", type); + } + + if (type == NTFSMftKnownAttribute.Invalid) + { + Console.WriteLine("ue: ntfs: WARNING: caught 'invalid' attribute 0, panicking"); + break; + } + + if (attr is NTFSFileNameAttribute) + { + NTFSFileNameAttribute att = (attr as NTFSFileNameAttribute); + file.Name = att.FileName; + file.Size = att.AllocatedSize; + } + + if (!keepgoing) + break; + } + + // skip empty space + reader.Accessor.Seek(thisoffset + mftEntryAllocatedSize, SeekOrigin.Begin); + return true; + } + + private bool ReadAttribute(Reader reader, out NTFSMftKnownAttribute type, out NTFSAttribute attr) + { + long thisoffset = reader.Accessor.Position; + + NTFSMftKnownAttribute attributeId = (NTFSMftKnownAttribute)reader.ReadInt32(); + type = attributeId; + if (attributeId == NTFSMftKnownAttribute.End) + { + attr = null; + return false; + } + + uint attributeLength = reader.ReadUInt32(); + byte nonResidentFlag = reader.ReadByte(); + byte nameLength = reader.ReadByte(); + ushort nameOffset = reader.ReadUInt16(); + ushort flags = reader.ReadUInt16(); + + ushort attributeIdentifier = reader.ReadUInt16(); + if (nonResidentFlag == 0) + { + uint contentSize = reader.ReadUInt32(); + ushort contentOffset = reader.ReadUInt16(); + + reader.Seek(thisoffset + contentOffset, SeekOrigin.Begin); + switch (attributeId) + { + case NTFSMftKnownAttribute.StandardInformation: + { + NTFSStandardInformationAttribute att = new NTFSStandardInformationAttribute(); + long creationDateTime = reader.ReadInt64(); + long modificationDateTime = reader.ReadInt64(); + long mftModificationDateTime = reader.ReadInt64(); + long readDateTime = reader.ReadInt64(); + int dosFilePermissions = reader.ReadInt32(); + int maxVersionCount = reader.ReadInt32(); + int versionNumber = reader.ReadInt32(); + int classId = reader.ReadInt32(); + int ownerId = reader.ReadInt32(); + int securityId = reader.ReadInt32(); + long quotaCharged = reader.ReadInt64(); + long updateSequenceNumber = reader.ReadInt64(); + attr = att; + break; + } + case NTFSMftKnownAttribute.FileName: + { + NTFSFileNameAttribute att = new NTFSFileNameAttribute(); + long parentDirectoryFileref = reader.ReadInt64(); + long creationDateTime = reader.ReadInt64(); + att.CreationDateTime = new DateTime(creationDateTime); + long modificationDateTime = reader.ReadInt64(); + att.ModificationDateTime = new DateTime(modificationDateTime); + long mftModificationDateTime = reader.ReadInt64(); + long readDateTime = reader.ReadInt64(); + att.AccessDateTime = new DateTime(readDateTime); + att.AllocatedSize = reader.ReadInt64(); + att.ActualSize = reader.ReadInt64(); + int fileNameFlags = reader.ReadInt32(); + int reparse = reader.ReadInt32(); + // int securityId = reader.ReadInt32(); + byte fileNameLength = reader.ReadByte(); + byte fileNameNamespace = reader.ReadByte(); + string fileNameUnicode = reader.ReadFixedLengthString(fileNameLength * 2, Encoding.UTF16LittleEndian); + att.FileName = fileNameUnicode; + + attr = att; + break; + } + case NTFSMftKnownAttribute.Data: + { + NTFSDataAttribute att = new NTFSDataAttribute(); + att.Data = reader.ReadBytes(attributeLength); + attr = att; + break; + } + case NTFSMftKnownAttribute.UnknownB0: + { + attr = null; + break; + } + default: + { + attr = null; + break; + } + } + } + else + { + long runlistStartingVirtualClusterNumber = reader.ReadInt64(); + long runlistEndingVirtualClusterNumber = reader.ReadInt64(); + ushort runlistOffset = reader.ReadUInt16(); + ushort compressionUnitSize = reader.ReadUInt16(); + uint unused = reader.ReadUInt32(); + ulong attributeContentAllocatedSize = reader.ReadUInt64(); + ulong attributeContentActualSize = reader.ReadUInt64(); + ulong attributeContentInitializedSize = reader.ReadUInt64(); + + SeekToCluster(runlistStartingVirtualClusterNumber); + + attr = null; + } + + long remaining = (thisoffset + attributeLength) - reader.Accessor.Position; + if (remaining > 0) + { + reader.Seek(remaining, SeekOrigin.Current); + } + return true; + } + + private void SeekToCluster(long clusterNumber) + { + Accessor.Seek(clusterNumber * BytesPerSector * SectorsPerCluster, SeekOrigin.Begin); + } + + public short BytesPerSector { get; set; } = 0x0200; + public byte SectorsPerCluster { get; set; } = 0x08; + public NTFSMediaDescriptor MediaDescriptor { get; set; } = NTFSMediaDescriptor.HardDisk; + public short SectorsPerTrack { get; set; } = 0x003F; + public short NumberOfHeads { get; set; } = 0x00FF; + public int HiddenSectors { get; set; } = 0x0000003F; + + protected override void SaveInternal(ObjectModel objectModel) + { + FileSystemObjectModel fsom = (objectModel as FileSystemObjectModel); + if (fsom == null) throw new ObjectModelNotSupportedException(); + + Writer writer = Accessor.Writer; + writer.WriteBytes(new byte[] { 0xEB, 0x52, 0x90 }); + writer.WriteFixedLengthString("NTFS "); + + writer.WriteInt16(BytesPerSector); + writer.WriteByte(SectorsPerCluster); + writer.WriteInt16(0x0000); // reservedSectors + writer.WriteBytes(new byte[] { 0, 0, 0 }); + writer.WriteInt16(0x0000); + writer.WriteByte((byte)MediaDescriptor); + writer.WriteInt16(0x0000); + writer.WriteInt16(SectorsPerTrack); + writer.WriteInt16(NumberOfHeads); + writer.WriteInt32(HiddenSectors); + writer.WriteInt32(0x00000000); + writer.WriteInt32(0x00800080); // reserved6 + writer.WriteInt64(0x00000000007FF54A); // totalSectors + writer.WriteInt64(0x0000000000000004); // $MFT cluster number + writer.WriteInt64(0x000000000007FF54); // $MFTMirr cluster number + + // A positive value denotes the number of clusters in a File Record Segment. A negative value denotes the amount of bytes in a File Record Segment, in which case the + // size is 2 to the power of the absolute value. (0xF6 = -10 → 2^10 = 1024). + writer.WriteByte(0xF6); // bytesOrClustersPerFileRecordSegment + + writer.WriteBytes(new byte[] { 0x00, 0x00, 0x00 }); + + // A positive value denotes the number of clusters in an Index Buffer. A negative value denotes the amount of bytes and it uses the same algorithm for negative + // numbers as the "Bytes or Clusters Per File Record Segment." + writer.WriteByte(0x01); + + writer.WriteBytes(new byte[] { 0x00, 0x00, 0x00 }); + writer.WriteInt64(0x1C741BC9741BA514); // volumeSerialNumber + + writer.WriteInt32(0); // Checksum, unused + + byte[] bootstrapCodeBlock = new byte[426]; // The code that loads the rest of the operating system. This is pointed to by the first 3 bytes of this sector. + writer.WriteBytes(bootstrapCodeBlock); + + writer.WriteUInt16(0xAA55); // end-of-sector marker + } + + } +} \ No newline at end of file diff --git a/Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/NTFS/NTFSMediaDescriptor.cs b/Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/NTFS/NTFSMediaDescriptor.cs new file mode 100644 index 00000000..02c0c427 --- /dev/null +++ b/Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/NTFS/NTFSMediaDescriptor.cs @@ -0,0 +1,34 @@ +// +// NTFSMediaDescriptor.cs - indicates the type of drive hosting an NTFS file system +// +// Author: +// Michael Becker +// +// Copyright (c) 2020 Mike Becker's Software +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +namespace UniversalEditor.DataFormats.FileSystem.Microsoft.NTFS +{ + /// + /// Indicates the type of drive hosting an NTFS file system. + /// + public enum NTFSMediaDescriptor + { + /// + /// Used to denote a hard drive (in contrast to the several sizes of floppy). + /// + HardDisk = 0xF8 + } +} \ No newline at end of file diff --git a/Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/NTFS/NTFSMftEntryFlags.cs b/Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/NTFS/NTFSMftEntryFlags.cs new file mode 100644 index 00000000..eaae763a --- /dev/null +++ b/Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/NTFS/NTFSMftEntryFlags.cs @@ -0,0 +1,31 @@ +// +// NTFSMftEntryFlags.cs +// +// Author: +// Michael Becker +// +// Copyright (c) 2020 Mike Becker's Software +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +using System; +namespace UniversalEditor.DataFormats.FileSystem.Microsoft.NTFS +{ + [Flags()] + public enum NTFSMftEntryFlags + { + Deleted = 0x0000, + Allocated = 0x0001, + Directory = 0x0002 + } +} diff --git a/Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/NTFS/NTFSMftKnownAttribute.cs b/Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/NTFS/NTFSMftKnownAttribute.cs new file mode 100644 index 00000000..b8ea6b80 --- /dev/null +++ b/Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/NTFS/NTFSMftKnownAttribute.cs @@ -0,0 +1,33 @@ +// +// NTFSMftKnownAttribute.cs +// +// Author: +// Michael Becker +// +// Copyright (c) 2020 Mike Becker's Software +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +using System; +namespace UniversalEditor.DataFormats.FileSystem.Microsoft.NTFS +{ + public enum NTFSMftKnownAttribute + { + Invalid = 0x00, + StandardInformation = 0x10, + FileName = 0x30, + Data = 0x80, + UnknownB0 = 0xB0, + End = -1 + } +} diff --git a/Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/OLE/OLE1/OLE1ChunkType.cs b/Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/OLE/OLE1/OLE1ChunkType.cs new file mode 100644 index 00000000..4a7eed93 --- /dev/null +++ b/Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/OLE/OLE1/OLE1ChunkType.cs @@ -0,0 +1,38 @@ +// +// OLE1ChunkType.cs - indicates the type of chunk in an Object Linking and Embedding (OLE) version 1.0 file +// +// Author: +// Michael Becker +// +// Copyright (c) 2020 Mike Becker's Software +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System; +using System.Collections.Generic; + +using UniversalEditor.IO; +using UniversalEditor.ObjectModels.FileSystem; + +namespace UniversalEditor.DataFormats.FileSystem.Microsoft.OLE.OLE1 +{ + /// + /// Indicates the type of chunk in an Object Linking and Embedding (OLE) version 1.0 file. + /// + public enum OLE1ChunkType + { + LinkedObject = 0x00000001, + EmbeddedObject = 0x00000002 + } +} \ No newline at end of file diff --git a/Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/OLE/OLE1/OLE1DataFormat.cs b/Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/OLE/OLE1/OLE1DataFormat.cs new file mode 100644 index 00000000..95d806c1 --- /dev/null +++ b/Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/OLE/OLE1/OLE1DataFormat.cs @@ -0,0 +1,187 @@ +// +// OLE1DataFormat.cs - provides a DataFormat for manipulating Microsoft Object Linking and Embedding (OLE) version 1 files +// +// Author: +// Michael Becker +// +// Copyright (c) 2020 Mike Becker's Software +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System; +using System.Collections.Generic; + +using UniversalEditor.IO; +using UniversalEditor.ObjectModels.FileSystem; + +namespace UniversalEditor.DataFormats.FileSystem.Microsoft.OLE.OLE1 +{ + /// + /// Provides a for manipulating Microsoft Object Linking and Embedding (OLE) version 1 files. + /// + public class OLE1DataFormat : DataFormat + { + private static DataFormatReference _dfr = null; + protected override DataFormatReference MakeReferenceInternal() + { + if (_dfr == null) + { + _dfr = base.MakeReferenceInternal(); + _dfr.Capabilities.Add(typeof(FileSystemObjectModel), DataFormatCapabilities.All); + _dfr.ExportOptions.Add(new CustomOptionText(nameof(ProgramName), "_Program name")); + _dfr.ExportOptions.Add(new CustomOptionNumber(nameof(OriginalFileName), "Original file _name")); + } + return _dfr; + } + + public string ProgramName { get; set; } + public string OriginalFileName { get; set; } + + protected override void LoadInternal(ref ObjectModel objectModel) + { + FileSystemObjectModel fsom = (objectModel as FileSystemObjectModel); + if (fsom == null) throw new ObjectModelNotSupportedException(); + + Reader reader = base.Accessor.Reader; + + OLE1ObjectHeader chunk = ReadOLE1ObjectHeader(reader); + switch (chunk.Type) + { + case OLE1ChunkType.EmbeddedObject: + { + uint nativeDataSize = reader.ReadUInt32(); + + // blah? + ushort x0200 = reader.ReadUInt16(); + byte nul = reader.ReadByte(); + string w = reader.ReadNullTerminatedString(); + uint unkn2 = reader.ReadUInt32(); + uint originalFileNameLen = reader.ReadUInt32(); + string originalFileName = reader.ReadFixedLengthString(originalFileNameLen); + + uint nativeDataLen = reader.ReadUInt32(); + byte[] nativeData = reader.ReadBytes(nativeDataLen); + + reader.Seek(nativeDataSize + 40, SeekOrigin.Begin); + fsom.Files.Add("NATIVEDATA", nativeData); + break; + } + case OLE1ChunkType.LinkedObject: + { + // networkname + uint unknown4 = reader.ReadUInt32(); // 0 + + // reserved + uint unknown5 = reader.ReadUInt32(); // 0 + + // linkupdateoption + uint unknown6 = reader.ReadUInt32(); // 0 + break; + } + } + + OLE1PresentationObject chunk2 = ReadOLE1PresentationObject(reader); + fsom.Files.Add(System.IO.Path.GetFileName(chunk.TopicName.Replace('\\', System.IO.Path.DirectorySeparatorChar)), chunk2.Data); + } + + private OLE1ObjectHeader ReadOLE1ObjectHeader(Reader reader) + { + OLE1ObjectHeader header = new OLE1ObjectHeader(); + uint oleversion = reader.ReadUInt32(); // 1281 + header.Type = (OLE1ChunkType)reader.ReadUInt32(); // 01, 02, 05 + + uint classNameLength = reader.ReadUInt32(); // length of program name + null terminator + string className = reader.ReadFixedLengthString(classNameLength); + header.ClassName = className.TrimNull(); + + uint topicNameLength = reader.ReadUInt32(); // incl. null terminator + string topicName = reader.ReadFixedLengthString(topicNameLength); + header.TopicName = topicName.TrimNull(); + + uint itemNameLength = reader.ReadUInt32(); // 0 + string itemName = reader.ReadFixedLengthString(itemNameLength); + header.ItemName = itemName.TrimNull(); + return header; + } + private OLE1PresentationObject ReadOLE1PresentationObject(Reader reader) + { + OLE1PresentationObject header = new OLE1PresentationObject(); + uint oleversion = reader.ReadUInt32(); // 1281 + uint flags = reader.ReadUInt32(); + if (flags == 0x00000005) + { + uint classNameLength = reader.ReadUInt32(); + header.ClassName = reader.ReadFixedLengthString(classNameLength).TrimNull(); + } + else + { + header.ClassName = null; + } + + header.Width = reader.ReadUInt32(); + header.Height = (uint)(reader.ReadInt32() * -1); // the fuck? + + uint datasize = reader.ReadUInt32(); + if (header.ClassName == "METAFILEPICT") + { + datasize -= 8; + ushort reserved1 = reader.ReadUInt16(); + ushort reserved2 = reader.ReadUInt16(); + ushort reserved3 = reader.ReadUInt16(); + ushort reserved4 = reader.ReadUInt16(); + } + + header.Data = reader.ReadBytes(datasize); + return header; + } + + private void WriteOLE1ObjectHeader(Writer writer, OLE1ObjectHeader value) + { + writer.WriteUInt32(1281); // ole version + writer.WriteUInt32((uint)value.Type); + + writer.WriteUInt32((uint)(value.ClassName.Length + 1)); + writer.WriteNullTerminatedString(value.ClassName); + writer.WriteUInt32((uint)(value.TopicName.Length + 1)); + writer.WriteNullTerminatedString(value.TopicName); + writer.WriteUInt32((uint)(value.ItemName.Length + 1)); + writer.WriteNullTerminatedString(value.ItemName); + } + + protected override void SaveInternal(ObjectModel objectModel) + { + FileSystemObjectModel fsom = (objectModel as FileSystemObjectModel); + if (fsom == null) throw new ObjectModelNotSupportedException(); + + Writer writer = base.Accessor.Writer; + + OLE1ObjectHeader header = new OLE1ObjectHeader(); + WriteOLE1ObjectHeader(writer, header); + + switch (header.Type) + { + case OLE1ChunkType.LinkedObject: + { + // networkname + writer.WriteUInt32(0); + // reserved + writer.WriteUInt32(0); + // linkupdateoption + writer.WriteUInt32(0); + break; + } + } + } + } +} diff --git a/Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/OLE/OLE1/OLE1ObjectHeader.cs b/Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/OLE/OLE1/OLE1ObjectHeader.cs new file mode 100644 index 00000000..7bdf092e --- /dev/null +++ b/Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/OLE/OLE1/OLE1ObjectHeader.cs @@ -0,0 +1,34 @@ +// +// OLE1Chunk.cs - +// +// Author: +// Michael Becker +// +// Copyright (c) 2020 Mike Becker's Software +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using UniversalEditor.IO; +using UniversalEditor.ObjectModels.FileSystem; + +namespace UniversalEditor.DataFormats.FileSystem.Microsoft.OLE.OLE1 +{ + public class OLE1ObjectHeader + { + public OLE1ChunkType Type { get; set; } + public string ClassName { get; set; } + public string TopicName { get; set; } + public string ItemName { get; set; } + } +} \ No newline at end of file diff --git a/Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/OLE/OLE1/OLE1PresentationObject.cs b/Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/OLE/OLE1/OLE1PresentationObject.cs new file mode 100644 index 00000000..54f3c18d --- /dev/null +++ b/Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/OLE/OLE1/OLE1PresentationObject.cs @@ -0,0 +1,32 @@ +// +// OLE1PresentationObjectHeader.cs - +// +// Author: +// Michael Becker +// +// Copyright (c) 2020 Mike Becker's Software +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +namespace UniversalEditor.DataFormats.FileSystem.Microsoft.OLE.OLE1 +{ + public class OLE1PresentationObject + { + public string ClassName { get; set; } = null; + + public uint Width { get; set; } + public uint Height { get; set; } + public byte[] Data { get; set; } + } +} \ No newline at end of file diff --git a/Plugins/UniversalEditor.Plugins.Microsoft/UniversalEditor.Plugins.Microsoft.csproj b/Plugins/UniversalEditor.Plugins.Microsoft/UniversalEditor.Plugins.Microsoft.csproj index e0ba8179..529087dd 100644 --- a/Plugins/UniversalEditor.Plugins.Microsoft/UniversalEditor.Plugins.Microsoft.csproj +++ b/Plugins/UniversalEditor.Plugins.Microsoft/UniversalEditor.Plugins.Microsoft.csproj @@ -140,6 +140,18 @@ + + + + + + + + + + + + @@ -187,5 +199,9 @@ + + + + \ No newline at end of file