diff --git a/CSharp/Content/UniversalEditor.Content.PlatformIndependent/Extensions/FileSystem/Associations/TexasInstruments/DSK.uexml b/CSharp/Content/UniversalEditor.Content.PlatformIndependent/Extensions/FileSystem/Associations/TexasInstruments/DSK.uexml new file mode 100644 index 00000000..29f9fd44 --- /dev/null +++ b/CSharp/Content/UniversalEditor.Content.PlatformIndependent/Extensions/FileSystem/Associations/TexasInstruments/DSK.uexml @@ -0,0 +1,25 @@ + + + + + + + + *.dsk + + + + DSK + + + + + + + + + + + + + \ No newline at end of file diff --git a/CSharp/Content/UniversalEditor.Content.PlatformIndependent/Extensions/FileSystem/Associations/TexasInstruments/TIFiles.uexml b/CSharp/Content/UniversalEditor.Content.PlatformIndependent/Extensions/FileSystem/Associations/TexasInstruments/TIFiles.uexml new file mode 100644 index 00000000..fd9eb143 --- /dev/null +++ b/CSharp/Content/UniversalEditor.Content.PlatformIndependent/Extensions/FileSystem/Associations/TexasInstruments/TIFiles.uexml @@ -0,0 +1,26 @@ + + + + + + + + *.tfi + + + + 07 + TIFILES + + + + + + + + + + + + + \ No newline at end of file diff --git a/CSharp/Content/UniversalEditor.Content.PlatformIndependent/UniversalEditor.Content.PlatformIndependent.csproj b/CSharp/Content/UniversalEditor.Content.PlatformIndependent/UniversalEditor.Content.PlatformIndependent.csproj index e1a3a8c1..e8f3e3c6 100644 --- a/CSharp/Content/UniversalEditor.Content.PlatformIndependent/UniversalEditor.Content.PlatformIndependent.csproj +++ b/CSharp/Content/UniversalEditor.Content.PlatformIndependent/UniversalEditor.Content.PlatformIndependent.csproj @@ -663,6 +663,8 @@ + + @@ -691,6 +693,7 @@ + diff --git a/CSharp/Plugins/UniversalEditor.Plugins.FileSystem/DataFormats/FileSystem/TexasInstruments/DSK/DSKDataFormat.cs b/CSharp/Plugins/UniversalEditor.Plugins.FileSystem/DataFormats/FileSystem/TexasInstruments/DSK/DSKDataFormat.cs new file mode 100644 index 00000000..55d1285a --- /dev/null +++ b/CSharp/Plugins/UniversalEditor.Plugins.FileSystem/DataFormats/FileSystem/TexasInstruments/DSK/DSKDataFormat.cs @@ -0,0 +1,197 @@ +using System; +using UniversalEditor.IO; +using UniversalEditor.ObjectModels.FileSystem; + +namespace UniversalEditor.DataFormats.FileSystem.TexasInstruments.DSK +{ + public class DSKDataFormat : DataFormat + { + private static DataFormatReference _dfr = null; + protected override DataFormatReference MakeReferenceInternal() + { + if (_dfr == null) + { + _dfr = base.MakeReferenceInternal(); + _dfr.Capabilities.Add(typeof(FileSystemObjectModel), DataFormatCapabilities.All); + } + return _dfr; + } + + /// + /// Gets or sets the name of the volume. The volume name must have at least one non-space character, and can be any combination of ten ASCII characters except for space, '.', or NULL. + /// + /// The name of the volume. + [CustomOptionText("_Volume name")] + public string VolumeName { get; set; } = null; + /// + /// Gets or sets the total number of allocation units on the volume. + /// + /// The total number of allocation units on the volume. + public short TotalAllocationUnits { get; set; } = 360; + /// + /// Gets or sets the sectors per track. + /// + /// The sectors per track. + public byte SectorsPerTrack { get; set; } = 9; + /// + /// Gets or sets a value indicating whether this is Proprietary Protected. + /// + /// true if protected; otherwise, false. + [CustomOptionBoolean("_Proprietary protected")] + public bool Protected { get; set; } = false; + + public byte TracksPerSide { get; set; } = 40; + public byte NumberOfFormattedSides { get; set; } = 1; + public byte Density { get; set; } = 1; + + public int SectorSize { get; set; } = 256; + private long start = 0; + + protected override void LoadInternal(ref ObjectModel objectModel) + { + FileSystemObjectModel fsom = (objectModel as FileSystemObjectModel); + if (fsom == null) + throw new ObjectModelNotSupportedException(); + + Reader reader = Accessor.Reader; + start = Accessor.Position; + reader.Endianness = Endianness.BigEndian; + + string volumeName = reader.ReadFixedLengthString(10); + volumeName = volumeName.Trim(); // it is space-filled to the right + + VolumeName = volumeName; + TotalAllocationUnits = reader.ReadInt16(); + SectorsPerTrack = reader.ReadByte(); + + string signature = reader.ReadFixedLengthString(3); + if (signature != "DSK") + throw new InvalidDataFormatException("file does not contain 'DSK' signature"); + + char protection = reader.ReadChar(); + if (protection == 'P') + Protected = true; + + TracksPerSide = reader.ReadByte(); + NumberOfFormattedSides = reader.ReadByte(); + Density = reader.ReadByte(); + + reader.Seek(start + 56, SeekOrigin.Begin); + byte[] allocationBitmap = reader.ReadBytes(200); // The map can control up to 1600 256-byte sectors + + // ===== FILE DESCRIPTOR INDEX RECORD, (Sector l) ===== + // + // This sector contains up to 127 two-byte entries. Each of these points to a File Descriptor Record, and are alphabetically sorted according + // to the file name in the File Descriptor Record. The list starts at the beginning of the block, and ends with a zero entry. + // + // As the file descriptors are alphabetically sorted, a binary search can be used to find any given filename. This limits the maximum number + // of searches to 7 if more than 63 files are defined. Generally if between 2 * *(N - 1) and 2 * *n files are defined, a file search will take + // at the most N disc searches. To obtain faster directory response times, data blocks are normally allocated in the area above sector 222, the + // area below this being used for file descriptors and only used for file data when there are no more sectors available above > 22. + SeekToSector(1); + + int totalIndices = 0; + short[] indices = new short[127]; + for (int i = 0; i < 127; i++) + { + short index = reader.ReadInt16(); + indices[i] = index; + + if (index == 0) + break; + + totalIndices++; + } + + // we should be at offset 256 by now + for (int i = 0; i < totalIndices; i++) + { + SeekToSector(indices[i]); + + string filename = reader.ReadFixedLengthString(10); + filename = filename.Trim(); + + // reserved for an extension of the number of data chain pointers - never implemented, so always 0. + ushort reserved1 = reader.ReadUInt16(); + + DSKFileStatusFlags flags = (DSKFileStatusFlags)reader.ReadByte(); + byte nRecordsPerAU = reader.ReadByte(); + ushort nL2RecordsAllocated = reader.ReadUInt16(); + byte eofOffset = reader.ReadByte(); + byte logicalRecordSize = reader.ReadByte(); + ushort nL3RecordsAllocated = reader.ReadUInt16(); + + reader.Seek(8, SeekOrigin.Current); // reserved + + long offset = 0; + long length = 0; + + for (int j = 0; j < 76; j++) + { + byte b1 = reader.ReadByte(); + byte b2 = reader.ReadByte(); + + long sectorOffset = (long)b1 | (byte)((long)b2 << 4); + if (offset == 0) + offset = sectorOffset; + + byte b3 = reader.ReadByte(); + + if (b1 == 0 && b2 == 0 && b3 == 0) + break; + + long sectorCount = (long)((byte)(b3 << 4) | b2 >> 4) + 1; + Console.WriteLine("adding file {0} : start {1} length {2} end {3}", filename, sectorOffset, sectorCount, sectorOffset + sectorCount); + + length = sectorCount; + } + + File file = fsom.AddFile(filename); + file.Size = (length * 256); + file.Properties.Add("reader", reader); + file.Properties.Add("offset", offset * 256); + file.Properties.Add("length", length * 256); + file.DataRequest += File_DataRequest; + } + } + + void File_DataRequest(object sender, DataRequestEventArgs e) + { + File file = (sender as File); + long offset = (long)file.Properties["offset"]; + long length = (long)file.Properties["length"]; + Reader reader = (Reader)file.Properties["reader"]; + + reader.Seek(offset, SeekOrigin.Begin); + e.Data = reader.ReadBytes(length); + } + + + private void SeekToSector(long sector) + { + Accessor.Seek(start + (sector * SectorSize), SeekOrigin.Begin); + } + + protected override void SaveInternal(ObjectModel objectModel) + { + FileSystemObjectModel fsom = (objectModel as FileSystemObjectModel); + if (fsom == null) + throw new ObjectModelNotSupportedException(); + + Writer writer = Accessor.Writer; + writer.Endianness = Endianness.BigEndian; + + writer.WriteFixedLengthString(VolumeName, 10, ' '); + writer.WriteInt16(TotalAllocationUnits); + writer.WriteByte(SectorsPerTrack); + writer.WriteFixedLengthString("DSK"); + + if (Protected) + writer.WriteChar('P'); + else + writer.WriteChar(' '); + + writer.WriteByte(TracksPerSide); + } + } +} diff --git a/CSharp/Plugins/UniversalEditor.Plugins.FileSystem/DataFormats/FileSystem/TexasInstruments/DSK/DSKFileStatusFlags.cs b/CSharp/Plugins/UniversalEditor.Plugins.FileSystem/DataFormats/FileSystem/TexasInstruments/DSK/DSKFileStatusFlags.cs new file mode 100644 index 00000000..a246fd30 --- /dev/null +++ b/CSharp/Plugins/UniversalEditor.Plugins.FileSystem/DataFormats/FileSystem/TexasInstruments/DSK/DSKFileStatusFlags.cs @@ -0,0 +1,37 @@ +using System; +namespace UniversalEditor.DataFormats.FileSystem.TexasInstruments.DSK +{ + [Flags()] + public enum DSKFileStatusFlags + { + /* + * Bit No. Description +0 ... File type indicator. + ........ 0 = Data file + ........ 1 = Program file +1 ... Data type indicator + ........ 0 = ASCII data (DISPLAY file) + ........ 1 = Binary data (INTERNAL or PROGRAM file) +2 ... This bit was reserved for expansion of the data + ... type indicator. +3 ... PROTECT FLAG + ........ 0 = NOT protected + ........ 1 = Protected +4,5 and 6 These bits were reserved for expansion of ???? +7 .... Fixed/variable flag + ........ 0 = Fixed record lengths + ........ 1 = Variable record lengths + */ + + None = 0x00, + Program = 0x01, + Binary = 0x02, + Protected = 0x08, + /* + Reserved1 = 0x10, + Reserved2 = 0x20, + Reserved3 = 0x40, + */ + Variable = 0x80 + } +} diff --git a/CSharp/Plugins/UniversalEditor.Plugins.FileSystem/DataFormats/FileSystem/TexasInstruments/TIFiles/TIFilesDataFormat.cs b/CSharp/Plugins/UniversalEditor.Plugins.FileSystem/DataFormats/FileSystem/TexasInstruments/TIFiles/TIFilesDataFormat.cs new file mode 100644 index 00000000..9d21feff --- /dev/null +++ b/CSharp/Plugins/UniversalEditor.Plugins.FileSystem/DataFormats/FileSystem/TexasInstruments/TIFiles/TIFilesDataFormat.cs @@ -0,0 +1,90 @@ +using System; +using UniversalEditor.IO; +using UniversalEditor.ObjectModels.FileSystem; + +namespace UniversalEditor.DataFormats.FileSystem.TexasInstruments +{ + public class TIFilesDataFormat : DataFormat + { + private static DataFormatReference _dfr = null; + protected override DataFormatReference MakeReferenceInternal() + { + if (_dfr == null) + { + _dfr = base.MakeReferenceInternal(); + _dfr.Capabilities.Add(typeof(FileSystemObjectModel), DataFormatCapabilities.All); + } + return _dfr; + } + + protected override void LoadInternal(ref ObjectModel objectModel) + { + FileSystemObjectModel fsom = (objectModel as FileSystemObjectModel); + if (fsom == null) + throw new ObjectModelNotSupportedException(); + + Reader reader = Accessor.Reader; + reader.Endianness = Endianness.BigEndian; + + byte isMultiTransfer = reader.ReadByte(); + string signature = reader.ReadFixedLengthString(7); + if (signature != "TIFILES") + throw new InvalidDataFormatException("file does not contain 'TIFILES' signature"); + + + if (isMultiTransfer == 0x07) + { + } + else if (isMultiTransfer == 0x08) + { + throw new InvalidDataFormatException("MXT YModem multiple file transfer not supported"); + } + else + { + throw new InvalidDataFormatException("first byte of file unrecognized (0x07 = normal, 0x08 = MXT YModem multiple file transfer)"); + } + + ushort sectorCount = reader.ReadUInt16(); + TIFilesFlags flags = (TIFilesFlags) reader.ReadByte(); + byte recordsPerSector = reader.ReadByte(); + byte eofOffset = reader.ReadByte(); + byte recordLength = reader.ReadByte(); + ushort level3RecordCount = reader.ReadUInt16(); + string fileName = reader.ReadFixedLengthString(10); + fileName = fileName.TrimNull(); + if (String.IsNullOrEmpty(fileName)) + { + fileName = System.IO.Path.GetFileNameWithoutExtension(Accessor.GetFileName()).ToUpper(); + } + + byte mxt = reader.ReadByte(); + byte reserved1 = reader.ReadByte(); + ushort extendedHeader = reader.ReadUInt16(); + uint creationTimestamp = reader.ReadUInt32(); + uint modificationTimestamp = reader.ReadUInt32(); + + File f = fsom.AddFile(fileName); + f.DataRequest += F_DataRequest; + f.Properties.Add("offset", reader.Accessor.Position); + f.Properties.Add("reader", reader); + } + + void F_DataRequest(object sender, DataRequestEventArgs e) + { + File f = (sender as File); + Reader reader = (Reader)f.Properties["reader"]; + long offset = (long)f.Properties["offset"]; + reader.Seek(offset, SeekOrigin.Begin); + e.Data = reader.ReadToEnd(); + } + + + protected override void SaveInternal(ObjectModel objectModel) + { + FileSystemObjectModel fsom = (objectModel as FileSystemObjectModel); + if (fsom == null) + throw new ObjectModelNotSupportedException(); + + } + } +} diff --git a/CSharp/Plugins/UniversalEditor.Plugins.FileSystem/DataFormats/FileSystem/TexasInstruments/TIFiles/TIFilesFlags.cs b/CSharp/Plugins/UniversalEditor.Plugins.FileSystem/DataFormats/FileSystem/TexasInstruments/TIFiles/TIFilesFlags.cs new file mode 100644 index 00000000..305647c3 --- /dev/null +++ b/CSharp/Plugins/UniversalEditor.Plugins.FileSystem/DataFormats/FileSystem/TexasInstruments/TIFiles/TIFilesFlags.cs @@ -0,0 +1,8 @@ +using System; +namespace UniversalEditor.DataFormats.FileSystem.TexasInstruments +{ + public enum TIFilesFlags : byte + { + None = 0x00 + } +} diff --git a/CSharp/Plugins/UniversalEditor.Plugins.FileSystem/UniversalEditor.Plugins.FileSystem.csproj b/CSharp/Plugins/UniversalEditor.Plugins.FileSystem/UniversalEditor.Plugins.FileSystem.csproj index fc43008c..f8f39554 100644 --- a/CSharp/Plugins/UniversalEditor.Plugins.FileSystem/UniversalEditor.Plugins.FileSystem.csproj +++ b/CSharp/Plugins/UniversalEditor.Plugins.FileSystem/UniversalEditor.Plugins.FileSystem.csproj @@ -233,6 +233,10 @@ + + + + @@ -271,6 +275,9 @@ + + +