support storing comments in PropertyList, add preliminary support for reading Master Boot Record (MBR) disk images

This commit is contained in:
Michael Becker 2023-06-29 22:00:39 -04:00
parent d8dd8d993e
commit 1a793c3f38
21 changed files with 1147 additions and 12 deletions

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8" ?>
<UniversalEditor Version="5.0">
<Editors>
<Editor ID="{1a47fee2-eb61-4ce8-a297-4d6988b1680c}" TypeName="UniversalEditor.Editors.PartitionedFileSystem.PartitionedFileSystemEditor" Title="Partitioned File System Editor">
<Contexts>
<Context ID="{7a21bf07-b17d-4c2f-9ac5-9760ab0aec33}" Name="Tree View - File System Editor" />
</Contexts>
<Commands>
<Command ID="PartitionedFileSystemEditor_tvPartitions_ContextMenu_CopyTo" Title="_Copy To..." />
<Command ID="PartitionedFileSystemEditor_tvPartitions_ContextMenu_Unselected" Title="PartitionedFileSystemEditor tvPartitions ContextMenu Unselected">
<Items>
<CommandReference CommandID="PartitionedFileSystemEditor_tvPartitions_ContextMenu_CopyTo" />
<Separator />
<CommandReference CommandID="FileProperties" />
</Items>
</Command>
</Commands>
</Editor>
</Editors>
</UniversalEditor>

View File

@ -0,0 +1,198 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.40.0 -->
<interface>
<requires lib="gtk+" version="3.24"/>
<object class="GtkTreeStore" id="tmPartitions">
<columns>
<!-- column-name colPartitionDevice -->
<column type="gchararray"/>
<!-- column-name colPartitionName -->
<column type="gchararray"/>
<!-- column-name colPartitionFileSystem -->
<column type="gchararray"/>
<!-- column-name colPartitionMountPoint -->
<column type="gchararray"/>
<!-- column-name colPartitionLabel -->
<column type="gchararray"/>
<!-- column-name colPartitionSize -->
<column type="gchararray"/>
<!-- column-name colPartitionSizeUsed -->
<column type="gchararray"/>
<!-- column-name colPartitionSizeUnused -->
<column type="gchararray"/>
<!-- column-name colPartitionFlags -->
<column type="gchararray"/>
</columns>
</object>
<object class="GtkWindow">
<property name="can-focus">False</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkDrawingArea" id="cnvPartitions">
<property name="name">MBS.Framework.UserInterface.CustomControl</property>
<property name="height-request">96</property>
<property name="visible">True</property>
<property name="can-focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="shadow-type">in</property>
<child>
<object class="GtkTreeView" id="tvPartitions">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="model">tmPartitions</property>
<child internal-child="selection">
<object class="GtkTreeSelection"/>
</child>
<child>
<object class="GtkTreeViewColumn" id="tvcPartitionDevice">
<property name="resizable">True</property>
<property name="title" translatable="yes">Device</property>
<property name="clickable">True</property>
<property name="reorderable">True</property>
<child>
<object class="GtkCellRendererText"/>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="tvcPartitionName">
<property name="resizable">True</property>
<property name="title" translatable="yes">Name</property>
<property name="clickable">True</property>
<property name="reorderable">True</property>
<child>
<object class="GtkCellRendererText"/>
<attributes>
<attribute name="text">1</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="tvcPartitionFileSystem">
<property name="resizable">True</property>
<property name="title" translatable="yes">File System</property>
<property name="clickable">True</property>
<property name="reorderable">True</property>
<child>
<object class="GtkCellRendererText"/>
<attributes>
<attribute name="text">2</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="tvcPartitionMountPoint">
<property name="resizable">True</property>
<property name="title" translatable="yes">Mount Point</property>
<property name="clickable">True</property>
<property name="reorderable">True</property>
<child>
<object class="GtkCellRendererText"/>
<attributes>
<attribute name="text">3</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="tvcPartitionLabel">
<property name="resizable">True</property>
<property name="title" translatable="yes">Label</property>
<property name="clickable">True</property>
<property name="reorderable">True</property>
<child>
<object class="GtkCellRendererText"/>
<attributes>
<attribute name="text">4</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="tvcPartitionSize">
<property name="resizable">True</property>
<property name="title" translatable="yes">Size</property>
<property name="clickable">True</property>
<property name="reorderable">True</property>
<child>
<object class="GtkCellRendererText"/>
<attributes>
<attribute name="text">5</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="tvcPartitionSizeUsed">
<property name="resizable">True</property>
<property name="title" translatable="yes">Used</property>
<property name="clickable">True</property>
<property name="reorderable">True</property>
<child>
<object class="GtkCellRendererText"/>
<attributes>
<attribute name="text">6</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="tvcPartitionSizeUnused">
<property name="resizable">True</property>
<property name="title" translatable="yes">Unused</property>
<property name="clickable">True</property>
<property name="reorderable">True</property>
<child>
<object class="GtkCellRendererText"/>
<attributes>
<attribute name="text">7</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="tvcPartitionFlags">
<property name="resizable">True</property>
<property name="title" translatable="yes">Flags</property>
<property name="clickable">True</property>
<property name="reorderable">True</property>
<child>
<object class="GtkCellRendererText"/>
<attributes>
<attribute name="text">8</attribute>
</attributes>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
</interface>

View File

@ -11,11 +11,14 @@
<Commands>
<Command ID="PropertyListContextMenu_New_Property" Title="_Property" />
<Command ID="PropertyListContextMenu_New_Group" Title="_Group" />
<Command ID="PropertyListContextMenu_New_Comment" Title="_Comment" />
<Command ID="PropertyListContextMenu_New" Title="_New">
<Items>
<CommandReference CommandID="PropertyListContextMenu_New_Property" />
<CommandReference CommandID="PropertyListContextMenu_New_Group" />
<Separator />
<CommandReference CommandID="PropertyListContextMenu_New_Comment" />
</Items>
</Command>

View File

@ -390,6 +390,8 @@
<Content Include="Editors\Roland\VDrumKit\TD20\Sounds\Tom\TR808.uexml" />
<Content Include="Editors\Roland\VDrumKit\TD20\Sounds\Tom\TR909.uexml" />
<Content Include="Editors\Multimedia\Font\Bitmap\BitmapFontEditor.glade" />
<Content Include="Editors\PartitionedFileSystem\PartitionedFileSystemEditor.glade" />
<Content Include="Editors\PartitionedFileSystem\Commands.uexml" />
</ItemGroup>
<ItemGroup>
<Content Include="Configuration\Application.upl" />
@ -454,6 +456,7 @@
<Folder Include="Editors\Roland\VDrumKit\TD12\" />
<Folder Include="Editors\Roland\VDrumKit\TD17\" />
<Folder Include="Editors\Roland\VDrumKit\TD20EXP\" />
<Folder Include="Editors\PartitionedFileSystem\" />
</ItemGroup>
<ItemGroup>
<Content Include="Templates\Project\Concertroid\Images\Concert.xcf" />

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8" ?>
<UniversalEditor Version="4.0">
<Associations>
<Association>
<Filters>
<Filter Title="Master Boot Record (MBR) partitioned file system" HintComparison="FilterOnly">
<FileNameFilters>
<FileNameFilter>*.mbr</FileNameFilter>
</FileNameFilters>
</Filter>
</Filters>
<ObjectModels>
<ObjectModel TypeName="UniversalEditor.ObjectModels.PartitionedFileSystem.PartitionedFileSystemObjectModel" />
</ObjectModels>
<DataFormats>
<DataFormat TypeName="UniversalEditor.DataFormats.PartitionedFileSystem.MBR.MBRDataFormat" />
</DataFormats>
</Association>
</Associations>
</UniversalEditor>

View File

@ -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 <http://www.gnu.org/licenses/>.
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();
}
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
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;
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
using System;
namespace UniversalEditor.DataFormats.PartitionedFileSystem.MBR
{
[Flags()]
public enum MBRPartitionEntryStatus : byte
{
Inactive = 0x00,
Active = 0x80
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
using System;
namespace UniversalEditor.DataFormats.PartitionedFileSystem.MBR
{
public enum MBRPartitionType : byte
{
None = 0x00,
/// <summary>
/// FAT12 as primary partition in first physical 32 MB of disk or as
/// logical drive anywhere on disk (else use 06h instead)
/// </summary>
FAT12 = 0x01,
/// <summary>
/// XENIX root
/// </summary>
XenixRoot = 0x02,
/// <summary>
/// XENIX usr
/// </summary>
XenixUsr = 0x03,
IFS_HPFS_NTFS_exFAT_QNX = 0x07,
/// <summary>
/// FAT32 with Logical Block Addressing (LBA)
/// </summary>
FAT32LBA = 0x0C
}
}

View File

@ -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();

View File

@ -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 <http://www.gnu.org/licenses/>.
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;
}
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
using System;
using UniversalEditor.DataFormats.PartitionedFileSystem.MBR;
namespace UniversalEditor.ObjectModels.PartitionedFileSystem
{
public class Partition : ICloneable
{
public class PartitionCollection
: System.Collections.ObjectModel.Collection<Partition>
{
}
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;
}
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
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;
}
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
using System;
namespace UniversalEditor.ObjectModels.PartitionedFileSystem
{
[Flags]
public enum PartitionFlags
{
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
using System;
namespace UniversalEditor.ObjectModels.PartitionedFileSystem
{
public enum PartitionType
{
None = 0,
/// <summary>
/// FAT12 as primary partition in first physical 32 MB of disk or as
/// logical drive anywhere on disk (else use 06h instead)
/// </summary>
FAT12,
/// <summary>
/// XENIX root
/// </summary>
XenixRoot,
/// <summary>
/// XENIX usr
/// </summary>
XenixUsr,
IFS_HPFS_NTFS_exFAT_QNX,
FAT32LBA
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
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<PartitionDataRequestEventArgs> 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;
}
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
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;
}
}
}

View File

@ -228,6 +228,17 @@
<Compile Include="ObjectModels\Markup\IMarkupElementContainer.cs" />
<Compile Include="ObjectModels\Markup\MarkupDefinition.cs" />
<Compile Include="ObjectModels\FileSystem\FileSources\ObjectModelFileSource.cs" />
<Compile Include="ObjectModels\PropertyList\Comment.cs" />
<Compile Include="DataFormats\PartitionedFileSystem\MBR\MBRDataFormat.cs" />
<Compile Include="ObjectModels\PartitionedFileSystem\PartitionedFileSystemObjectModel.cs" />
<Compile Include="DataFormats\PartitionedFileSystem\MBR\MBRPartitionEntry.cs" />
<Compile Include="DataFormats\PartitionedFileSystem\MBR\MBRPartitionEntryStatus.cs" />
<Compile Include="DataFormats\PartitionedFileSystem\MBR\MBRPartitionType.cs" />
<Compile Include="ObjectModels\PartitionedFileSystem\Partition.cs" />
<Compile Include="ObjectModels\PartitionedFileSystem\PartitionFlags.cs" />
<Compile Include="ObjectModels\PartitionedFileSystem\CHSPartitionAddress.cs" />
<Compile Include="ObjectModels\PartitionedFileSystem\PartitionType.cs" />
<Compile Include="ObjectModels\PartitionedFileSystem\PartitionDataRequestEventArgs.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\UniversalEditor.Core\UniversalEditor.Core.csproj">
@ -275,10 +286,14 @@
<Folder Include="DataFormats\Package\OpenDocument\Internal\ManifestXML\" />
<Folder Include="DataFormats\Markup\BML\" />
<Folder Include="DataFormats\Markup\BML\Internal\" />
<Folder Include="DataFormats\PartitionedFileSystem\" />
<Folder Include="DataFormats\PartitionedFileSystem\MBR\" />
<Folder Include="ObjectModels\PartitionedFileSystem\" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Associations\PlainText.uexml" />
<EmbeddedResource Include="Associations\BML.uexml" />
<EmbeddedResource Include="Associations\MBR.uexml" />
</ItemGroup>
<ItemGroup>
<None Include="ObjectModels\Chunked\RIFFMetadata.cs">

View File

@ -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 <http://www.gnu.org/licenses/>.
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<Partition>("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<Partition>("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<Partition>("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;
}
}
}

View File

@ -59,6 +59,7 @@ namespace UniversalEditor.Editors.PropertyList
{
Group group = row.GetExtraData<Group>("group");
Property property = row.GetExtraData<Property>("property");
Comment comment = row.GetExtraData<Comment>("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>("group");
Property property = e.Row.GetExtraData<Property>("property");
Comment comment = e.Row.GetExtraData<Comment>("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>("group");
while (parent == null)
{
rowParent = rowParent.ParentRow;
if (rowParent == null)
{
parent = ObjectModel as PropertyListObjectModel;
break;
}
parent = rowParent.GetExtraData<Group>("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<Property>());
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>("group");
}
IPropertyListContainer parent = GetSelectedParent(out TreeModelRow rowParent);
p.Name = String.Format("New Group {0}", GetNextIndex<Group>());
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>("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>("comment", p);
}
}
}

View File

@ -141,6 +141,7 @@
<Compile Include="PanelReference.cs" />
<Compile Include="Editors\Text\Formatted\FormattedTextEditor.cs" />
<Compile Include="Panels\OutputWindowPanel.cs" />
<Compile Include="Editors\PartitionedFileSystem\PartitionedFileSystemEditor.cs" />
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">
@ -201,6 +202,7 @@
<Folder Include="SettingsProviders\" />
<Folder Include="Editors\Database\Dialogs\" />
<Folder Include="Editors\Text\Formatted\" />
<Folder Include="Editors\PartitionedFileSystem\" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="SettingsProviders\DefaultSettingsProvider.xml" />