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 @@
+
+
+
+
+
+
+
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 @@
+