diff --git a/Content/UniversalEditor.Content.PlatformIndependent/Editors/PartitionedFileSystem/Commands.uexml b/Content/UniversalEditor.Content.PlatformIndependent/Editors/PartitionedFileSystem/Commands.uexml new file mode 100644 index 00000000..c26ae13c --- /dev/null +++ b/Content/UniversalEditor.Content.PlatformIndependent/Editors/PartitionedFileSystem/Commands.uexml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/Content/UniversalEditor.Content.PlatformIndependent/Editors/PartitionedFileSystem/PartitionedFileSystemEditor.glade b/Content/UniversalEditor.Content.PlatformIndependent/Editors/PartitionedFileSystem/PartitionedFileSystemEditor.glade new file mode 100644 index 00000000..8006fecd --- /dev/null +++ b/Content/UniversalEditor.Content.PlatformIndependent/Editors/PartitionedFileSystem/PartitionedFileSystemEditor.glade @@ -0,0 +1,198 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + False + + + True + False + vertical + + + MBS.Framework.UserInterface.CustomControl + 96 + True + False + + + False + True + 0 + + + + + True + True + in + + + True + True + tmPartitions + + + + + + True + Device + True + True + + + + 0 + + + + + + + True + Name + True + True + + + + 1 + + + + + + + True + File System + True + True + + + + 2 + + + + + + + True + Mount Point + True + True + + + + 3 + + + + + + + True + Label + True + True + + + + 4 + + + + + + + True + Size + True + True + + + + 5 + + + + + + + True + Used + True + True + + + + 6 + + + + + + + True + Unused + True + True + + + + 7 + + + + + + + True + Flags + True + True + + + + 8 + + + + + + + + + True + True + 1 + + + + + + diff --git a/Content/UniversalEditor.Content.PlatformIndependent/Editors/PropertyList/Commands.uexml b/Content/UniversalEditor.Content.PlatformIndependent/Editors/PropertyList/Commands.uexml index a29b791f..853882f1 100644 --- a/Content/UniversalEditor.Content.PlatformIndependent/Editors/PropertyList/Commands.uexml +++ b/Content/UniversalEditor.Content.PlatformIndependent/Editors/PropertyList/Commands.uexml @@ -11,11 +11,14 @@ + + + diff --git a/Content/UniversalEditor.Content.PlatformIndependent/UniversalEditor.Content.PlatformIndependent.csproj b/Content/UniversalEditor.Content.PlatformIndependent/UniversalEditor.Content.PlatformIndependent.csproj index 7c916147..b109865a 100644 --- a/Content/UniversalEditor.Content.PlatformIndependent/UniversalEditor.Content.PlatformIndependent.csproj +++ b/Content/UniversalEditor.Content.PlatformIndependent/UniversalEditor.Content.PlatformIndependent.csproj @@ -390,6 +390,8 @@ + + @@ -454,6 +456,7 @@ + diff --git a/Libraries/UniversalEditor.Essential/Associations/MBR.uexml b/Libraries/UniversalEditor.Essential/Associations/MBR.uexml new file mode 100644 index 00000000..b93ba150 --- /dev/null +++ b/Libraries/UniversalEditor.Essential/Associations/MBR.uexml @@ -0,0 +1,20 @@ + + + + + + + + *.mbr + + + + + + + + + + + + diff --git a/Libraries/UniversalEditor.Essential/DataFormats/PartitionedFileSystem/MBR/MBRDataFormat.cs b/Libraries/UniversalEditor.Essential/DataFormats/PartitionedFileSystem/MBR/MBRDataFormat.cs new file mode 100644 index 00000000..f6d3a3e7 --- /dev/null +++ b/Libraries/UniversalEditor.Essential/DataFormats/PartitionedFileSystem/MBR/MBRDataFormat.cs @@ -0,0 +1,179 @@ +// +// MBRDataFormat.cs +// +// Author: +// beckermj <> +// +// Copyright (c) 2023 ${CopyrightHolder} +// +// 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 UniversalEditor.IO; +using UniversalEditor.ObjectModels.PartitionedFileSystem; + +namespace UniversalEditor.DataFormats.PartitionedFileSystem.MBR +{ + public class MBRDataFormat : DataFormat + { + private static DataFormatReference _dfr = null; + protected override DataFormatReference MakeReferenceInternal() + { + if (_dfr == null) + { + _dfr = base.MakeReferenceInternal(); + _dfr.Capabilities.Add(typeof(PartitionedFileSystemObjectModel), DataFormatCapabilities.All); + } + return _dfr; + } + + protected override void LoadInternal(ref ObjectModel objectModel) + { + PartitionedFileSystemObjectModel disk = objectModel as PartitionedFileSystemObjectModel; + if (disk == null) + throw new ObjectModelNotSupportedException(); + + disk.PartitionDataRequest += Disk_PartitionDataRequest; + + Reader r = Accessor.Reader; + + ushort newldrRecordSize = r.ReadUInt16(); + string newldr = r.ReadFixedLengthString(6); + if (newldr.Equals("NEWLDR")) + { + // this is a NEWLDR MBR + } + else + { + // this is not a NEWLDR MBR + r.Accessor.Seek(-8, SeekOrigin.Current); + } + + byte[] bootstrapCodeAreaPart1 = r.ReadBytes(218); + ushort diskTimestampUnknown = r.ReadUInt16(); + byte originalPhysicalDrive = r.ReadByte(); + byte diskTimestampSeconds = r.ReadByte(); + byte diskTimestampMinutes = r.ReadByte(); + byte diskTimestampHours = r.ReadByte(); + + // wiki says also 222,but palimpsest writes 216 + byte[] bootstrapCodeAreaPart2 = r.ReadBytes(216); + + // Disk signature (optional; UEFI, Linux, Windows NT family and other OSes) + uint diskSignature = r.ReadUInt32(); + ushort copyProtectionFlag = r.ReadUInt16(); + if (copyProtectionFlag == 0x5A5A) + { + // lol + } + + MBRPartitionEntry partentry1 = ReadMBRPartitionEntry(r); + if (partentry1.PartitionType != MBRPartitionType.None) + { + AddPartition(disk, partentry1); + } + MBRPartitionEntry partentry2 = ReadMBRPartitionEntry(r); + if (partentry2.PartitionType != MBRPartitionType.None) + { + AddPartition(disk, partentry2); + } + MBRPartitionEntry partentry3 = ReadMBRPartitionEntry(r); + if (partentry3.PartitionType != MBRPartitionType.None) + { + AddPartition(disk, partentry3); + } + MBRPartitionEntry partentry4 = ReadMBRPartitionEntry(r); + if (partentry4.PartitionType != MBRPartitionType.None) + { + AddPartition(disk, partentry4); + } + + ushort bootSignature = r.ReadUInt16(); + if (bootSignature != 0xAA55) + { + Console.Error.WriteLine("ue: mbr: warning: not found 0xAA55 at offset 0x01FE"); + } + + } + + void Disk_PartitionDataRequest(object sender, PartitionDataRequestEventArgs e) + { + long offset = e.Disk.CalculatePartitionOffset(e.Partition); + long length = e.Disk.CalculatePartitionSize(e.Partition); + + Accessor.Seek(offset, SeekOrigin.Begin); + byte[] data = Accessor.Reader.ReadBytes(length); + e.Data = data; + } + + private void AddPartition(PartitionedFileSystemObjectModel disk, MBRPartitionEntry partentry1) + { + Partition part = new Partition(); + part.FirstAbsoluteSectorLBA = partentry1.FirstAbsoluteSectorLBA; + part.FirstAbsoluteSectorAddress = partentry1.FirstAbsoluteSectorAddress; + part.LastAbsoluteSectorAddress = partentry1.LastAbsoluteSectorAddress; + part.SectorCount = partentry1.SectorCount; + part.PartitionType = MBRPartitionTypeToPartitionType(partentry1.PartitionType); + + if ((partentry1.Status & MBRPartitionEntryStatus.Active) == MBRPartitionEntryStatus.Active) + { + part.IsBootable = true; + } + disk.Partitions.Add(part); + } + + private PartitionType MBRPartitionTypeToPartitionType(MBRPartitionType partitionType) + { + switch (partitionType) + { + case MBRPartitionType.FAT12: return PartitionType.FAT12; + case MBRPartitionType.FAT32LBA: return PartitionType.FAT32LBA; + case MBRPartitionType.IFS_HPFS_NTFS_exFAT_QNX: return PartitionType.IFS_HPFS_NTFS_exFAT_QNX; + case MBRPartitionType.None: return PartitionType.None; + case MBRPartitionType.XenixRoot: return PartitionType.XenixRoot; + case MBRPartitionType.XenixUsr: return PartitionType.XenixUsr; + } + throw new ArgumentOutOfRangeException(); + } + + private MBRPartitionEntry ReadMBRPartitionEntry(Reader r) + { + MBRPartitionEntry entry = new MBRPartitionEntry(); + entry.Status = (MBRPartitionEntryStatus)r.ReadByte(); + + entry.FirstAbsoluteSectorAddress = ReadCHSPartitionAddress(r); + entry.PartitionType = (MBRPartitionType)r.ReadByte(); + entry.LastAbsoluteSectorAddress = ReadCHSPartitionAddress(r); + entry.FirstAbsoluteSectorLBA = r.ReadUInt32(); + entry.SectorCount = r.ReadUInt32(); + return entry; + } + + private CHSPartitionAddress ReadCHSPartitionAddress(Reader r) + { + byte head = r.ReadByte(); + byte sectorAndCylinder1 = r.ReadByte(); + byte cylinder2 = r.ReadByte(); + return new CHSPartitionAddress(0, head, 0); + } + + protected override void SaveInternal(ObjectModel objectModel) + { + PartitionedFileSystemObjectModel part = objectModel as PartitionedFileSystemObjectModel; + if (part == null) + throw new ObjectModelNotSupportedException(); + + + } + } +} diff --git a/Libraries/UniversalEditor.Essential/DataFormats/PartitionedFileSystem/MBR/MBRPartitionEntry.cs b/Libraries/UniversalEditor.Essential/DataFormats/PartitionedFileSystem/MBR/MBRPartitionEntry.cs new file mode 100644 index 00000000..4b163edd --- /dev/null +++ b/Libraries/UniversalEditor.Essential/DataFormats/PartitionedFileSystem/MBR/MBRPartitionEntry.cs @@ -0,0 +1,35 @@ +// +// MBRPartitionEntry.cs +// +// Author: +// beckermj <> +// +// Copyright (c) 2023 ${CopyrightHolder} +// +// 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 UniversalEditor.ObjectModels.PartitionedFileSystem; + +namespace UniversalEditor.DataFormats.PartitionedFileSystem.MBR +{ + public struct MBRPartitionEntry + { + public MBRPartitionEntryStatus Status; + public CHSPartitionAddress FirstAbsoluteSectorAddress; + public MBRPartitionType PartitionType; + public CHSPartitionAddress LastAbsoluteSectorAddress; + public uint FirstAbsoluteSectorLBA; + public uint SectorCount; + } +} diff --git a/Libraries/UniversalEditor.Essential/DataFormats/PartitionedFileSystem/MBR/MBRPartitionEntryStatus.cs b/Libraries/UniversalEditor.Essential/DataFormats/PartitionedFileSystem/MBR/MBRPartitionEntryStatus.cs new file mode 100644 index 00000000..c9b05913 --- /dev/null +++ b/Libraries/UniversalEditor.Essential/DataFormats/PartitionedFileSystem/MBR/MBRPartitionEntryStatus.cs @@ -0,0 +1,30 @@ +// +// MBRPartitionEntryStatus.cs +// +// Author: +// beckermj <> +// +// Copyright (c) 2023 ${CopyrightHolder} +// +// 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.PartitionedFileSystem.MBR +{ + [Flags()] + public enum MBRPartitionEntryStatus : byte + { + Inactive = 0x00, + Active = 0x80 + } +} diff --git a/Libraries/UniversalEditor.Essential/DataFormats/PartitionedFileSystem/MBR/MBRPartitionType.cs b/Libraries/UniversalEditor.Essential/DataFormats/PartitionedFileSystem/MBR/MBRPartitionType.cs new file mode 100644 index 00000000..0e60f4b3 --- /dev/null +++ b/Libraries/UniversalEditor.Essential/DataFormats/PartitionedFileSystem/MBR/MBRPartitionType.cs @@ -0,0 +1,48 @@ +// +// MBRPartitionType.cs +// +// Author: +// beckermj <> +// +// Copyright (c) 2023 ${CopyrightHolder} +// +// 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.PartitionedFileSystem.MBR +{ + public enum MBRPartitionType : byte + { + None = 0x00, + /// + /// FAT12 as primary partition in first physical 32 MB of disk or as + /// logical drive anywhere on disk (else use 06h instead) + /// + FAT12 = 0x01, + /// + /// XENIX root + /// + XenixRoot = 0x02, + /// + /// XENIX usr + /// + XenixUsr = 0x03, + + IFS_HPFS_NTFS_exFAT_QNX = 0x07, + + /// + /// FAT32 with Logical Block Addressing (LBA) + /// + FAT32LBA = 0x0C + } +} diff --git a/Libraries/UniversalEditor.Essential/DataFormats/PropertyList/ExtensibleConfiguration/ExtensibleConfigurationDataFormat.cs b/Libraries/UniversalEditor.Essential/DataFormats/PropertyList/ExtensibleConfiguration/ExtensibleConfigurationDataFormat.cs index 9cd96d69..756bcf6a 100644 --- a/Libraries/UniversalEditor.Essential/DataFormats/PropertyList/ExtensibleConfiguration/ExtensibleConfigurationDataFormat.cs +++ b/Libraries/UniversalEditor.Essential/DataFormats/PropertyList/ExtensibleConfiguration/ExtensibleConfigurationDataFormat.cs @@ -69,12 +69,28 @@ namespace UniversalEditor.DataFormats.PropertyList.ExtensibleConfiguration if (nextString.StartsWith(Settings.SingleLineCommentStart)) { string comment = tr.ReadLine(); + if (nextGroup != null) + { + nextGroup.Items.Add(new Comment(comment)); + } + else + { + plom.Items.Add(new Comment(comment)); + } } if (nextString.StartsWith(Settings.MultiLineCommentStart)) { string comment = tr.ReadUntil(Settings.MultiLineCommentEnd); string cmntend = tr.ReadFixedLengthString(Settings.MultiLineCommentEnd.Length); nextString = String.Empty; + if (nextGroup != null) + { + nextGroup.Items.Add(new Comment(comment)); + } + else + { + plom.Items.Add(new Comment(comment)); + } continue; } @@ -193,13 +209,30 @@ namespace UniversalEditor.DataFormats.PropertyList.ExtensibleConfiguration tw.Write(Settings.PropertyNameSuffix); tw.Write(Settings.PropertyNameValueSeparator); tw.Write(Settings.PropertyValuePrefix); - tw.WriteFixedLengthString((p as Property).Value.ToString()); + tw.WriteFixedLengthString((p as Property).Value?.ToString()); tw.Write(Settings.PropertyValueSuffix); + tw.WriteLine(); } else if (p is Group) { this.WriteGroup(tw, (p as Group), 0); } + else if (p is Comment) + { + Comment c = (Comment)p; + if (c.Text.Contains("\r") || c.Text.Contains("\n")) + { + tw.WriteLine(Settings.MultiLineCommentStart); + tw.WriteLine(c.Text); + tw.WriteLine(Settings.MultiLineCommentEnd); + } + else + { + tw.Write(Settings.SingleLineCommentStart); + tw.Write(' '); + tw.WriteLine(c.Text); + } + } } tw.Flush(); tw.Close(); diff --git a/Libraries/UniversalEditor.Essential/ObjectModels/PartitionedFileSystem/CHSPartitionAddress.cs b/Libraries/UniversalEditor.Essential/ObjectModels/PartitionedFileSystem/CHSPartitionAddress.cs new file mode 100644 index 00000000..2005670d --- /dev/null +++ b/Libraries/UniversalEditor.Essential/ObjectModels/PartitionedFileSystem/CHSPartitionAddress.cs @@ -0,0 +1,37 @@ +// +// CHSPartitionAddress.cs +// +// Author: +// beckermj <> +// +// Copyright (c) 2023 ${CopyrightHolder} +// +// 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.ObjectModels.PartitionedFileSystem +{ + public struct CHSPartitionAddress + { + public byte Cylinder { get; } + public byte Head { get; } + public byte Sector { get; } + + public CHSPartitionAddress(byte cylinder, byte head, byte sector) + { + this.Cylinder = cylinder; + this.Head = head; + this.Sector = sector; + } + } +} diff --git a/Libraries/UniversalEditor.Essential/ObjectModels/PartitionedFileSystem/Partition.cs b/Libraries/UniversalEditor.Essential/ObjectModels/PartitionedFileSystem/Partition.cs new file mode 100644 index 00000000..028ade47 --- /dev/null +++ b/Libraries/UniversalEditor.Essential/ObjectModels/PartitionedFileSystem/Partition.cs @@ -0,0 +1,50 @@ +// +// Partition.cs +// +// Author: +// beckermj <> +// +// Copyright (c) 2023 ${CopyrightHolder} +// +// 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 UniversalEditor.DataFormats.PartitionedFileSystem.MBR; + +namespace UniversalEditor.ObjectModels.PartitionedFileSystem +{ + public class Partition : ICloneable + { + public class PartitionCollection + : System.Collections.ObjectModel.Collection + { + + } + + + public bool IsBootable { get; set; } = false; + + public long FirstAbsoluteSectorLBA { get; set; } + public CHSPartitionAddress FirstAbsoluteSectorAddress { get; set; } + public CHSPartitionAddress LastAbsoluteSectorAddress { get; set; } + public uint SectorCount { get; set; } + public PartitionType PartitionType { get; set; } + + public object Clone() + { + Partition clone = new Partition(); + clone.IsBootable = IsBootable; + return clone; + } + } +} diff --git a/Libraries/UniversalEditor.Essential/ObjectModels/PartitionedFileSystem/PartitionDataRequestEventArgs.cs b/Libraries/UniversalEditor.Essential/ObjectModels/PartitionedFileSystem/PartitionDataRequestEventArgs.cs new file mode 100644 index 00000000..6a93ba74 --- /dev/null +++ b/Libraries/UniversalEditor.Essential/ObjectModels/PartitionedFileSystem/PartitionDataRequestEventArgs.cs @@ -0,0 +1,37 @@ +// +// PartitionDataRequestEventArgs.cs +// +// Author: +// beckermj <> +// +// Copyright (c) 2023 ${CopyrightHolder} +// +// 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 UniversalEditor.ObjectModels.FileSystem; + +namespace UniversalEditor.ObjectModels.PartitionedFileSystem +{ + public class PartitionDataRequestEventArgs : DataRequestEventArgs + { + public PartitionedFileSystemObjectModel Disk { get; } + public Partition Partition { get; } + + public PartitionDataRequestEventArgs(PartitionedFileSystemObjectModel disk, Partition partition) + { + Disk = disk; + Partition = partition; + } + } +} diff --git a/Libraries/UniversalEditor.Essential/ObjectModels/PartitionedFileSystem/PartitionFlags.cs b/Libraries/UniversalEditor.Essential/ObjectModels/PartitionedFileSystem/PartitionFlags.cs new file mode 100644 index 00000000..8542e648 --- /dev/null +++ b/Libraries/UniversalEditor.Essential/ObjectModels/PartitionedFileSystem/PartitionFlags.cs @@ -0,0 +1,28 @@ +// +// PartitionFlags.cs +// +// Author: +// beckermj <> +// +// Copyright (c) 2023 ${CopyrightHolder} +// +// 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.ObjectModels.PartitionedFileSystem +{ + [Flags] + public enum PartitionFlags + { + } +} diff --git a/Libraries/UniversalEditor.Essential/ObjectModels/PartitionedFileSystem/PartitionType.cs b/Libraries/UniversalEditor.Essential/ObjectModels/PartitionedFileSystem/PartitionType.cs new file mode 100644 index 00000000..79f5c19e --- /dev/null +++ b/Libraries/UniversalEditor.Essential/ObjectModels/PartitionedFileSystem/PartitionType.cs @@ -0,0 +1,45 @@ +// +// PartitionType.cs +// +// Author: +// beckermj <> +// +// Copyright (c) 2023 ${CopyrightHolder} +// +// 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.ObjectModels.PartitionedFileSystem +{ + public enum PartitionType + { + None = 0, + /// + /// FAT12 as primary partition in first physical 32 MB of disk or as + /// logical drive anywhere on disk (else use 06h instead) + /// + FAT12, + /// + /// XENIX root + /// + XenixRoot, + /// + /// XENIX usr + /// + XenixUsr, + + IFS_HPFS_NTFS_exFAT_QNX, + + FAT32LBA + } +} diff --git a/Libraries/UniversalEditor.Essential/ObjectModels/PartitionedFileSystem/PartitionedFileSystemObjectModel.cs b/Libraries/UniversalEditor.Essential/ObjectModels/PartitionedFileSystem/PartitionedFileSystemObjectModel.cs new file mode 100644 index 00000000..bde5a741 --- /dev/null +++ b/Libraries/UniversalEditor.Essential/ObjectModels/PartitionedFileSystem/PartitionedFileSystemObjectModel.cs @@ -0,0 +1,86 @@ +// +// PartitionedFileSystemObjectModel.cs +// +// Author: +// beckermj <> +// +// Copyright (c) 2023 ${CopyrightHolder} +// +// 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 UniversalEditor.ObjectModels.FileSystem; + +namespace UniversalEditor.ObjectModels.PartitionedFileSystem +{ + public class PartitionedFileSystemObjectModel : ObjectModel + { + private static ObjectModelReference _omr = null; + + public int SectorSize { get; set; } = 512; + + public Partition.PartitionCollection Partitions { get; } = new Partition.PartitionCollection(); + + public long CalculatePartitionSize(Partition part) + { + return part.SectorCount * SectorSize; + } + + protected override ObjectModelReference MakeReferenceInternal() + { + if (_omr == null) + { + _omr = base.MakeReferenceInternal(); + _omr.Path = new string[] { "General", "Partitioned file system" }; + } + return _omr; + } + + public override void Clear() + { + Partitions.Clear(); + } + + public override void CopyTo(ObjectModel where) + { + PartitionedFileSystemObjectModel clone = where as PartitionedFileSystemObjectModel; + if (clone == null) + throw new ObjectModelNotSupportedException(); + + foreach (Partition p in Partitions) + { + clone.Partitions.Add(p.Clone() as Partition); + } + } + + public event EventHandler PartitionDataRequest; + protected virtual void OnPartitionDataRequest(PartitionDataRequestEventArgs e) + { + PartitionDataRequest?.Invoke(this, e); + } + + public byte[] GetPartitionData(Partition part) + { + PartitionDataRequestEventArgs e = new PartitionDataRequestEventArgs(this, part); + OnPartitionDataRequest(e); + + return e.Data; + } + + public long CalculatePartitionOffset(Partition partition) + { + long firstAbsoluteSectorLBA = partition.FirstAbsoluteSectorLBA; + return firstAbsoluteSectorLBA * SectorSize; + } + } +} diff --git a/Libraries/UniversalEditor.Essential/ObjectModels/PropertyList/Comment.cs b/Libraries/UniversalEditor.Essential/ObjectModels/PropertyList/Comment.cs new file mode 100644 index 00000000..b23a32af --- /dev/null +++ b/Libraries/UniversalEditor.Essential/ObjectModels/PropertyList/Comment.cs @@ -0,0 +1,48 @@ +// +// Comment.cs +// +// Author: +// beckermj <> +// +// Copyright (c) 2023 ${CopyrightHolder} +// +// 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.ObjectModels.PropertyList +{ + public class Comment : PropertyListItem + { + public string Text { get; set; } + + public override object Clone() + { + Comment clone = new Comment(); + clone.Text = Text; + return clone; + } + + public override void Combine(PropertyListItem item) + { + throw new NotImplementedException(); + } + + public Comment() + { + } + public Comment(string text) + { + Text = text; + } + } +} diff --git a/Libraries/UniversalEditor.Essential/UniversalEditor.Essential.csproj b/Libraries/UniversalEditor.Essential/UniversalEditor.Essential.csproj index e0a66d9a..73ab0d1a 100644 --- a/Libraries/UniversalEditor.Essential/UniversalEditor.Essential.csproj +++ b/Libraries/UniversalEditor.Essential/UniversalEditor.Essential.csproj @@ -228,6 +228,17 @@ + + + + + + + + + + + @@ -275,10 +286,14 @@ + + + + diff --git a/Libraries/UniversalEditor.UserInterface/Editors/PartitionedFileSystem/PartitionedFileSystemEditor.cs b/Libraries/UniversalEditor.UserInterface/Editors/PartitionedFileSystem/PartitionedFileSystemEditor.cs new file mode 100644 index 00000000..f74b647a --- /dev/null +++ b/Libraries/UniversalEditor.UserInterface/Editors/PartitionedFileSystem/PartitionedFileSystemEditor.cs @@ -0,0 +1,165 @@ +// +// PartitionedFileSystemEditor.cs +// +// Author: +// beckermj <> +// +// Copyright (c) 2023 ${CopyrightHolder} +// +// 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 MBS.Framework; +using MBS.Framework.UserInterface; +using MBS.Framework.UserInterface.Controls.ListView; +using MBS.Framework.UserInterface.Dialogs; +using UniversalEditor.ObjectModels.PartitionedFileSystem; +using UniversalEditor.UserInterface; + +namespace UniversalEditor.Editors.PartitionedFileSystem +{ + [ContainerLayout("~/Editors/PartitionedFileSystem/PartitionedFileSystemEditor.glade")] + public class PartitionedFileSystemEditor : Editor + { + private CustomControl cnvPartitions; + private ListViewControl tvPartitions; + + private static EditorReference _er = null; + public override EditorReference MakeReference() + { + if (_er == null) + { + _er = base.MakeReference(); + _er.SupportedObjectModels.Add(typeof(PartitionedFileSystemObjectModel)); + } + return _er; + } + + public override void UpdateSelections() + { + } + + protected override Selection CreateSelectionInternal(object content) + { + return null; + } + + protected override void OnCreated(EventArgs e) + { + base.OnCreated(e); + + OnObjectModelChanged(e); + + Context.AttachCommandEventHandler("PartitionedFileSystemEditor_tvPartitions_ContextMenu_CopyTo", PartitionedFileSystemEditor_tvPartitions_ContextMenu_CopyTo); + } + + private void PartitionedFileSystemEditor_tvPartitions_ContextMenu_CopyTo(object sender, EventArgs e) + { + PartitionedFileSystemObjectModel disk = ObjectModel as PartitionedFileSystemObjectModel; + if (disk == null) + return; + + if (tvPartitions.SelectedRows.Count == 1) + { + FileDialog dlg = new FileDialog(); + dlg.Mode = FileDialogMode.Save; + + if (dlg.ShowDialog() == DialogResult.OK) + { + Partition part = tvPartitions.SelectedRows[0].GetExtraData("part"); + byte[] data = disk.GetPartitionData(part); + + System.IO.File.WriteAllBytes(dlg.SelectedFileName, data); + } + } + else if (tvPartitions.SelectedRows.Count > 1) + { + FileDialog dlg = new FileDialog(); + dlg.Mode = FileDialogMode.SelectFolder; + if (dlg.ShowDialog() == DialogResult.OK) + { + string dirname = dlg.SelectedPath; + if (!System.IO.Directory.Exists(dirname)) + { + System.IO.Directory.CreateDirectory(dirname); + } + + Partition part = tvPartitions.SelectedRows[0].GetExtraData("part"); + byte[] data = disk.GetPartitionData(part); + + System.IO.File.WriteAllBytes(dlg.SelectedFileName, data); + } + } + } + + [EventHandler(nameof(tvPartitions), nameof(Control.BeforeContextMenu))] + private void tvPartitions_BeforeContextMenu(object sender, EventArgs e) + { + tvPartitions.ContextMenuCommandID = "PartitionedFileSystemEditor_tvPartitions_ContextMenu_Unselected"; + } + [EventHandler(nameof(tvPartitions), nameof(ListViewControl.SelectionChanged))] + private void tvPartitions_SelectionChanged(object sender, EventArgs e) + { + Context.Commands["PartitionedFileSystemEditor_tvPartitions_ContextMenu_CopyTo"].Enabled = (tvPartitions.SelectedRows.Count == 1); + } + + protected override void OnObjectModelChanged(EventArgs e) + { + if (!IsCreated) + { + return; + } + + PartitionedFileSystemObjectModel disk = ObjectModel as PartitionedFileSystemObjectModel; + if (disk == null) + return; + + for (int i = 0; i < disk.Partitions.Count; i++) + { + TreeModelRow rowPartition = new TreeModelRow(new TreeModelRowColumn[] + { + new TreeModelRowColumn(tvPartitions.Model.Columns[0], String.Format("@dev@{0}", i)), + new TreeModelRowColumn(tvPartitions.Model.Columns[1], String.Empty /* Name */), + new TreeModelRowColumn(tvPartitions.Model.Columns[2], String.Empty /* File System */), + new TreeModelRowColumn(tvPartitions.Model.Columns[3], String.Empty /* Mount Point */), + new TreeModelRowColumn(tvPartitions.Model.Columns[4], String.Empty /* Label */), + new TreeModelRowColumn(tvPartitions.Model.Columns[5], UserInterface.Common.FileInfo.FormatSize(disk.CalculatePartitionSize(disk.Partitions[i]))), + new TreeModelRowColumn(tvPartitions.Model.Columns[6], UserInterface.Common.FileInfo.FormatSize(0) /* Used */), + new TreeModelRowColumn(tvPartitions.Model.Columns[7], UserInterface.Common.FileInfo.FormatSize(0) /* Unused */), + new TreeModelRowColumn(tvPartitions.Model.Columns[8], Flagstr(disk.Partitions[i])) + + }); + rowPartition.SetExtraData("part", disk.Partitions[i]); + tvPartitions.Model.Rows.Add(rowPartition); + } + + + base.OnObjectModelChanged(e); + } + + private string Flagstr(Partition partition) + { + System.Text.StringBuilder sb = new System.Text.StringBuilder(); + + if (partition.IsBootable) + { + sb.Append("boot,"); + } + + string flagstr = sb.ToString(); + if (flagstr.EndsWith(",")) + flagstr = flagstr.Substring(0, flagstr.Length - 1); + return flagstr; + } + } +} diff --git a/Libraries/UniversalEditor.UserInterface/Editors/PropertyList/PropertyListEditor.cs b/Libraries/UniversalEditor.UserInterface/Editors/PropertyList/PropertyListEditor.cs index c71c5f37..d26e02f2 100644 --- a/Libraries/UniversalEditor.UserInterface/Editors/PropertyList/PropertyListEditor.cs +++ b/Libraries/UniversalEditor.UserInterface/Editors/PropertyList/PropertyListEditor.cs @@ -59,6 +59,7 @@ namespace UniversalEditor.Editors.PropertyList { Group group = row.GetExtraData("group"); Property property = row.GetExtraData("property"); + Comment comment = row.GetExtraData("comment"); if (group != null) { Selections.Add(new PropertyListSelection(ObjectModel as PropertyListObjectModel, group)); @@ -67,6 +68,10 @@ namespace UniversalEditor.Editors.PropertyList { Selections.Add(new PropertyListSelection(ObjectModel as PropertyListObjectModel, property)); } + else if (comment != null) + { + Selections.Add(new PropertyListSelection(ObjectModel as PropertyListObjectModel, comment)); + } } } @@ -74,8 +79,11 @@ namespace UniversalEditor.Editors.PropertyList { base.OnCreated(e); + tv.BeforeContextMenu += tv_BeforeContextMenu; + Context.AttachCommandEventHandler("PropertyListContextMenu_New_Property", PropertyListContextMenu_New_Property); Context.AttachCommandEventHandler("PropertyListContextMenu_New_Group", PropertyListContextMenu_New_Group); + Context.AttachCommandEventHandler("PropertyListContextMenu_New_Comment", PropertyListContextMenu_New_Comment); OnObjectModelChanged(EventArgs.Empty); } @@ -91,6 +99,7 @@ namespace UniversalEditor.Editors.PropertyList { Group group = e.Row.GetExtraData("group"); Property property = e.Row.GetExtraData("property"); + Comment comment = e.Row.GetExtraData("comment"); if (e.NewValue == e.OldValue) return; @@ -120,6 +129,10 @@ namespace UniversalEditor.Editors.PropertyList { property.Value = e.NewValue; } + else if (comment != null) + { + comment.Text = e.NewValue?.ToString(); + } } EndEdit(); @@ -149,17 +162,33 @@ namespace UniversalEditor.Editors.PropertyList return lastIndex + 1; } - private void PropertyListContextMenu_New_Property(object sender, EventArgs e) + private IPropertyListContainer GetSelectedParent(out TreeModelRow rowParent) { - Property p = new Property(); - - TreeModelRow rowParent = null; + rowParent = null; IPropertyListContainer parent = ObjectModel as PropertyListObjectModel; if (tv.SelectedRows.Count == 1) { rowParent = tv.SelectedRows[0]; parent = rowParent.GetExtraData("group"); + while (parent == null) + { + rowParent = rowParent.ParentRow; + if (rowParent == null) + { + parent = ObjectModel as PropertyListObjectModel; + break; + } + parent = rowParent.GetExtraData("group"); + } } + return parent; + } + + private void PropertyListContextMenu_New_Property(object sender, EventArgs e) + { + Property p = new Property(); + + IPropertyListContainer parent = GetSelectedParent(out TreeModelRow rowParent); p.Name = String.Format("New Property {0}", GetNextIndex()); parent.Items.Add(p); @@ -169,18 +198,22 @@ namespace UniversalEditor.Editors.PropertyList { Group p = new Group(); - TreeModelRow rowParent = null; - IPropertyListContainer parent = ObjectModel as PropertyListObjectModel; - if (tv.SelectedRows.Count == 1) - { - rowParent = tv.SelectedRows[0]; - parent = rowParent.GetExtraData("group"); - } + IPropertyListContainer parent = GetSelectedParent(out TreeModelRow rowParent); p.Name = String.Format("New Group {0}", GetNextIndex()); parent.Items.Add(p); RecursiveAddGroup(p, rowParent); } + private void PropertyListContextMenu_New_Comment(object sender, EventArgs e) + { + Comment p = new Comment(); + + IPropertyListContainer parent = GetSelectedParent(out TreeModelRow rowParent); + + p.Text = "Your comment here"; + parent.Items.Add(p); + RecursiveAddComment(p, rowParent); + } [EventHandler(nameof(tv), nameof(ListViewControl.SelectionChanged))] private void tv_SelectionChanged(object sender, EventArgs e) @@ -277,5 +310,24 @@ namespace UniversalEditor.Editors.PropertyList } row.SetExtraData("group", g); } + private void RecursiveAddComment(Comment p, TreeModelRow parent = null) + { + TreeModelRow row = new TreeModelRow(new TreeModelRowColumn[] + { + new TreeModelRowColumn(tm.Columns[0], "//"), + new TreeModelRowColumn(tm.Columns[1], p.Text), + new TreeModelRowColumn(tm.Columns[2], Image.FromStock(StockType.Info, 16)) + }); + + if (parent == null) + { + tm.Rows.Add(row); + } + else + { + parent.Rows.Add(row); + } + row.SetExtraData("comment", p); + } } } diff --git a/Libraries/UniversalEditor.UserInterface/UniversalEditor.UserInterface.csproj b/Libraries/UniversalEditor.UserInterface/UniversalEditor.UserInterface.csproj index ff3eb5fc..8ba5fd4c 100644 --- a/Libraries/UniversalEditor.UserInterface/UniversalEditor.UserInterface.csproj +++ b/Libraries/UniversalEditor.UserInterface/UniversalEditor.UserInterface.csproj @@ -141,6 +141,7 @@ + @@ -201,6 +202,7 @@ +