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