diff --git a/CSharp/Content/UniversalEditor.Content.PlatformIndependent/Extensions/FileSystem/Associations/Microsoft/Cabinet.xml b/CSharp/Content/UniversalEditor.Content.PlatformIndependent/Extensions/FileSystem/Associations/Microsoft/Cabinet.xml
new file mode 100644
index 00000000..fedf314a
--- /dev/null
+++ b/CSharp/Content/UniversalEditor.Content.PlatformIndependent/Extensions/FileSystem/Associations/Microsoft/Cabinet.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+ *.cab
+
+
+
+ MSCF
+
+
+
+
+
+
+
+
+
+
+
+
+
\ 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 b194f046..34a7c02c 100644
--- a/CSharp/Content/UniversalEditor.Content.PlatformIndependent/UniversalEditor.Content.PlatformIndependent.csproj
+++ b/CSharp/Content/UniversalEditor.Content.PlatformIndependent/UniversalEditor.Content.PlatformIndependent.csproj
@@ -111,6 +111,7 @@
+
diff --git a/CSharp/Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/Cabinet/CABCompressionMethod.cs b/CSharp/Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/Cabinet/CABCompressionMethod.cs
new file mode 100644
index 00000000..87991a5f
--- /dev/null
+++ b/CSharp/Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/Cabinet/CABCompressionMethod.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace UniversalEditor.DataFormats.FileSystem.Microsoft.Cabinet
+{
+ public enum CABCompressionMethod : ushort
+ {
+ None = 0,
+ MSZIP = 1,
+ LZX = 5379
+ }
+}
diff --git a/CSharp/Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/Cabinet/CABDataFormat.cs b/CSharp/Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/Cabinet/CABDataFormat.cs
new file mode 100644
index 00000000..599daf84
--- /dev/null
+++ b/CSharp/Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/Cabinet/CABDataFormat.cs
@@ -0,0 +1,375 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using UniversalEditor.Accessors;
+using UniversalEditor.Compression;
+using UniversalEditor.IO;
+using UniversalEditor.ObjectModels.FileSystem;
+
+namespace UniversalEditor.DataFormats.FileSystem.Microsoft.Cabinet
+{
+ public class CABDataFormat : DataFormat
+ {
+ private static DataFormatReference _dfr = null;
+ protected override DataFormatReference MakeReferenceInternal()
+ {
+ if (_dfr == null)
+ {
+ _dfr = base.MakeReferenceInternal();
+ _dfr.Capabilities.Add(typeof(FileSystemObjectModel), DataFormatCapabilities.All);
+ _dfr.Sources.Add("http://msdn.microsoft.com/en-us/library/bb267310.aspx#struct_spec");
+
+ _dfr.ExportOptions.Add(new CustomOptionNumber("CabinetReservedAreaSize", "Per-&cabinet reserved area size:", 0, 0, UInt16.MaxValue));
+ _dfr.ExportOptions.Add(new CustomOptionNumber("FolderReservedAreaSize", "Per-&folder reserved area size:", 0, 0, Byte.MaxValue));
+ _dfr.ExportOptions.Add(new CustomOptionNumber("DatablockReservedAreaSize", "Per-&datablock reserved area size:", 0, 0, Byte.MaxValue));
+
+ _dfr.ExportOptions.Add(new CustomOptionText("NextCabinetName", "&Next cabinet file name:"));
+ _dfr.ExportOptions.Add(new CustomOptionText("NextDiskName", "Ne&xt cabinet disk name:"));
+ _dfr.ExportOptions.Add(new CustomOptionText("PreviousCabinetName", "&Previous cabinet file name:"));
+ _dfr.ExportOptions.Add(new CustomOptionText("PreviousDiskName", "Pre&vious cabinet disk name:"));
+ }
+ return _dfr;
+ }
+
+ private ushort mvarCabinetReservedAreaSize = 0;
+ public ushort CabinetReservedAreaSize { get { return mvarCabinetReservedAreaSize; } set { mvarCabinetReservedAreaSize = value; } }
+
+ private byte mvarFolderReservedAreaSize = 0;
+ public byte FolderReservedAreaSize { get { return mvarFolderReservedAreaSize; } set { mvarFolderReservedAreaSize = value; } }
+
+ private byte mvarDatablockReservedAreaSize = 0;
+ public byte DatablockReservedAreaSize { get { return mvarDatablockReservedAreaSize; } set { mvarDatablockReservedAreaSize = value; } }
+
+ private string mvarNextCabinetName = String.Empty;
+ public string NextCabinetName { get { return mvarNextCabinetName; } set { mvarNextCabinetName = value; } }
+
+ private string mvarNextDiskName = String.Empty;
+ public string NextDiskName { get { return mvarNextDiskName; } set { mvarNextDiskName = value; } }
+
+ private string mvarPreviousCabinetName = String.Empty;
+ public string PreviousCabinetName { get { return mvarPreviousCabinetName; } set { mvarPreviousCabinetName = value; } }
+
+ private string mvarPreviousDiskName = String.Empty;
+ public string PreviousDiskName { get { return mvarPreviousDiskName; } set { mvarPreviousDiskName = value; } }
+
+ protected override void LoadInternal(ref ObjectModel objectModel)
+ {
+ FileSystemObjectModel fsom = (objectModel as FileSystemObjectModel);
+
+ Reader br = base.Accessor.Reader;
+
+ Internal.CFHEADER cfheader = ReadCFHEADER(br);
+ mvarCabinetReservedAreaSize = cfheader.cabinetReservedAreaSize;
+ mvarDatablockReservedAreaSize = cfheader.datablockReservedAreaSize;
+ mvarFolderReservedAreaSize = cfheader.folderReservedAreaSize;
+
+ List folders = new List();
+ for (ushort cfFolderID = 0; cfFolderID < cfheader.folderCount; cfFolderID++)
+ {
+ Internal.CFFOLDER cffolder = ReadCFFOLDER(br, cfheader);
+ folders.Add(cffolder);
+ }
+ for (ushort cfFileID = 0; cfFileID < cfheader.fileCount; cfFileID++)
+ {
+ Internal.CFFILE cffile = ReadCFFILE(br);
+ File file = fsom.AddFile(cffile.name);
+ file.Size = cffile.decompressedSize;
+ file.Properties.Add("DecompressedSize", cffile.decompressedSize);
+ file.Properties.Add("offset", cffile.offset);
+ file.Properties.Add("folder", folders[cffile.folderIndex]);
+ file.Properties.Add("reader", br);
+ file.DataRequest += file_DataRequest;
+ }
+ }
+
+ private Internal.CFHEADER ReadCFHEADER(Reader br)
+ {
+ Internal.CFHEADER cfheader = new Internal.CFHEADER();
+ cfheader.signature = br.ReadFixedLengthString(4); // cabinet file signature
+ if (cfheader.signature != "MSCF") throw new InvalidDataFormatException("File does not begin with \"MSCF\"");
+
+ cfheader.reserved1 = br.ReadUInt32(); // reserved
+ cfheader.cabinetFileSize = br.ReadUInt32(); // size of this cabinet file in bytes
+ if (br.Accessor.Length != cfheader.cabinetFileSize) throw new DataCorruptedException("Stored cabinet length does not match actual file length");
+
+ cfheader.reserved2 = br.ReadUInt32(); // reserved
+ cfheader.firstFileOffset = br.ReadUInt32(); // offset of the first CFFILE entry
+ cfheader.reserved3 = br.ReadUInt32(); // reserved
+
+ cfheader.versionMinor = br.ReadByte(); // cabinet file format version, minor
+ cfheader.versionMajor = br.ReadByte(); // cabinet file format version, major
+
+ cfheader.folderCount = br.ReadUInt16(); // number of CFFOLDER entries in this cabinet
+ cfheader.fileCount = br.ReadUInt16(); // number of CFFILE entries in this cabinet
+
+ cfheader.flags = (CABFlags)br.ReadUInt16(); // cabinet file option indicators:
+
+ cfheader.setID = br.ReadUInt16(); // must be the same for all cabinets in a set
+ cfheader.iCabinet = br.ReadUInt16(); // number of this cabinet file in a set
+
+ if ((cfheader.flags & CABFlags.HasReservedArea) == CABFlags.HasReservedArea)
+ {
+ cfheader.cabinetReservedAreaSize = br.ReadUInt16(); // (optional) size of per-cabinet reserved area
+ cfheader.folderReservedAreaSize = br.ReadByte(); // (optional) size of per-folder reserved area
+ cfheader.datablockReservedAreaSize = br.ReadByte(); // (optional) size of per-datablock reserved area
+ }
+
+ cfheader.reservedArea = br.ReadBytes(mvarCabinetReservedAreaSize); // (optional) per-cabinet reserved area
+
+ if ((cfheader.flags & CABFlags.HasPreviousCabinet) == CABFlags.HasPreviousCabinet)
+ {
+ cfheader.previousCabinetName = br.ReadNullTerminatedString(); /* (optional) name of previous cabinet file */
+ cfheader.previousDiskName = br.ReadNullTerminatedString(); /* (optional) name of previous disk */
+ }
+ if ((cfheader.flags & CABFlags.HasNextCabinet) == CABFlags.HasNextCabinet)
+ {
+ cfheader.nextCabinetName = br.ReadNullTerminatedString(); /* (optional) name of next cabinet file */
+ cfheader.nextDiskName = br.ReadNullTerminatedString(); /* (optional) name of next disk */
+ }
+ return cfheader;
+ }
+ private Internal.CFFILE ReadCFFILE(Reader br)
+ {
+ Internal.CFFILE cffile = new Internal.CFFILE();
+
+ cffile.decompressedSize = br.ReadUInt32();
+ cffile.offset = br.ReadUInt32();
+ cffile.folderIndex = br.ReadUInt16();
+
+ cffile.date = br.ReadUInt16();
+ cffile.time = br.ReadUInt16();
+
+ cffile.attribs = br.ReadUInt16();
+ cffile.name = br.ReadNullTerminatedString();
+ return cffile;
+ }
+ private Internal.CFFOLDER ReadCFFOLDER(Reader br, Internal.CFHEADER cfheader)
+ {
+ Internal.CFFOLDER cffolder = new Internal.CFFOLDER();
+ cffolder.firstDataBlockOffset = br.ReadUInt32(); // offset of the first CFDATA block in this folder
+ cffolder.dataBlockCount = br.ReadUInt16(); // number of CFDATA blocks in this folder
+ cffolder.compressionMethod = (CABCompressionMethod)br.ReadUInt16(); // compression type indicator
+ if ((cfheader.flags & CABFlags.HasReservedArea) == CABFlags.HasReservedArea)
+ {
+ cffolder.reservedArea = br.ReadBytes(mvarFolderReservedAreaSize); // (optional) per-folder reserved area
+ }
+ return cffolder;
+ }
+ private Internal.CFDATA ReadCFDATA(Reader br)
+ {
+ Internal.CFDATA data = new Internal.CFDATA();
+ data.checksum = br.ReadUInt32();
+ data.compressedLength = br.ReadUInt16();
+ data.decompressedLength = br.ReadUInt16();
+ data.reservedArea = br.ReadBytes(mvarDatablockReservedAreaSize);
+ data.data = br.ReadBytes(data.compressedLength);
+ return data;
+ }
+
+ private void file_DataRequest(object sender, DataRequestEventArgs e)
+ {
+ File file = (sender as File);
+ uint decompressedSize = (uint)file.Properties["DecompressedSize"];
+ uint offset = (uint)file.Properties["offset"];
+ Reader br = (Reader)file.Properties["reader"];
+
+ Internal.CFFOLDER cffolder = (Internal.CFFOLDER)file.Properties["folder"];
+ br.Accessor.Position = cffolder.firstDataBlockOffset;
+
+ byte[] decompressedData = new byte[decompressedSize];
+ int j = 0;
+ for (int i = 0; i < cffolder.dataBlockCount; i++)
+ {
+ Internal.CFDATA data = ReadCFDATA(br);
+ switch (cffolder.compressionMethod)
+ {
+ case CABCompressionMethod.None:
+ {
+ // no compression
+ file.Properties["CompressionMethod"] = CompressionMethod.None;
+ Array.Copy(data.data, offset, decompressedData, j, decompressedData.Length);
+ j += decompressedData.Length;
+ break;
+ }
+ case CABCompressionMethod.MSZIP:
+ {
+ Reader br1 = new Reader(new MemoryAccessor(data.data));
+ byte mszipSig1 = br1.ReadByte();
+ byte mszipSig2 = br1.ReadByte();
+
+ byte[] rest = br1.ReadToEnd();
+ byte[] decompressedDataLocal = CompressionModule.FromKnownCompressionMethod(CompressionMethod.Deflate).Decompress(rest);
+ Array.Copy(decompressedDataLocal, offset, decompressedData, j, decompressedData.Length);
+ j += decompressedDataLocal.Length;
+ break;
+ }
+ case CABCompressionMethod.LZX:
+ {
+ file.Properties["CompressionMethod"] = Compression.CompressionMethod.LZX;
+ decompressedData = CompressionModule.FromKnownCompressionMethod(CompressionMethod.LZX).Decompress(data.data);
+
+ // no compression
+ Array.Copy(data.data, 0, decompressedData, j, data.data.Length);
+ j += data.data.Length;
+ break;
+ }
+ default:
+ {
+ throw new InvalidOperationException("unknown compression method");
+ }
+ }
+ }
+
+ e.Data = decompressedData;
+ }
+
+
+
+ #region Save
+ private ushort PackDate(DateTime value)
+ {
+ return (ushort)(((value.Year - 1980) << 9) + (value.Month << 5) + value.Day);
+ }
+ private ushort PackTime(DateTime value)
+ {
+ return (ushort)((value.Hour << 11) + (value.Minute << 5) + (value.Second / 2));
+ }
+
+
+ private void WriteCFHEADER(Writer bw, Internal.CFHEADER cfheader)
+ {
+ bw.WriteFixedLengthString(cfheader.signature, 4);
+
+ bw.WriteUInt32(cfheader.reserved1); // reserved
+ bw.WriteUInt32(cfheader.cabinetFileSize); // size of this cabinet file in bytes
+
+ bw.WriteUInt32(cfheader.reserved2); // reserved
+ bw.WriteUInt32(cfheader.firstFileOffset); // offset of the first CFFILE entry
+ bw.WriteUInt32(cfheader.reserved3); // reserved
+
+ bw.WriteByte(cfheader.versionMinor); // cabinet file format version, minor
+ bw.WriteByte(cfheader.versionMajor); // cabinet file format version, major
+
+ bw.WriteUInt16(cfheader.folderCount); // number of CFFOLDER entries in this cabinet
+ bw.WriteUInt16(cfheader.fileCount); // number of CFFILE entries in this cabinet
+
+ bw.WriteUInt16((ushort)cfheader.flags); // cabinet file option indicators
+
+ bw.WriteUInt16(cfheader.setID); // must be the same for all cabinets in a set
+ bw.WriteUInt16(cfheader.iCabinet); // number of this cabinet file in a set
+
+ if ((cfheader.flags & CABFlags.HasReservedArea) == CABFlags.HasReservedArea)
+ {
+ bw.WriteUInt16(cfheader.cabinetReservedAreaSize); // (optional) size of per-cabinet reserved area
+ bw.WriteByte(cfheader.folderReservedAreaSize); // (optional) size of per-folder reserved area
+ bw.WriteByte(cfheader.datablockReservedAreaSize); // (optional) size of per-datablock reserved area
+ }
+
+ bw.WriteFixedLengthBytes(cfheader.reservedArea, cfheader.cabinetReservedAreaSize);
+
+ if ((cfheader.flags & CABFlags.HasPreviousCabinet) == CABFlags.HasPreviousCabinet)
+ {
+ bw.WriteNullTerminatedString(cfheader.previousCabinetName); // (optional) name of previous cabinet file
+ bw.WriteNullTerminatedString(cfheader.previousDiskName); // (optional) name of previous disk
+ }
+ if ((cfheader.flags & CABFlags.HasNextCabinet) == CABFlags.HasNextCabinet)
+ {
+ bw.WriteNullTerminatedString(cfheader.nextCabinetName); // (optional) name of next cabinet file
+ bw.WriteNullTerminatedString(cfheader.nextDiskName); // (optional) name of next disk
+ }
+ }
+ private void WriteCFFILE(Writer bw, Internal.CFFILE cffile)
+ {
+ bw.WriteUInt32(cffile.decompressedSize);
+ bw.WriteUInt32(cffile.offset);
+ bw.WriteUInt16(cffile.folderIndex);
+ bw.WriteUInt16(cffile.date);
+ bw.WriteUInt16(cffile.time);
+ bw.WriteUInt16(cffile.attribs);
+ bw.WriteNullTerminatedString(cffile.name);
+ }
+ private void WriteCFFOLDER(Writer bw, Internal.CFFOLDER cffolder, Internal.CFHEADER cfheader)
+ {
+ bw.WriteUInt32(cffolder.firstDataBlockOffset);
+ bw.WriteUInt16(cffolder.dataBlockCount);
+ bw.WriteUInt16((ushort)cffolder.compressionMethod);
+ if ((cfheader.flags & CABFlags.HasReservedArea) == CABFlags.HasReservedArea)
+ {
+ bw.WriteFixedLengthBytes(cffolder.reservedArea, cfheader.folderReservedAreaSize);
+ }
+ }
+
+ protected override void SaveInternal(ObjectModel objectModel)
+ {
+ FileSystemObjectModel fsom = (objectModel as FileSystemObjectModel);
+ Writer bw = base.Accessor.Writer;
+
+ // go through and build a list of files
+ File[] files = fsom.GetAllFiles();
+
+ List cffiles = new List();
+ List cffolders = new List();
+
+ Internal.CFHEADER cfheader = new Internal.CFHEADER();
+ cfheader.signature = "MSCF";
+ cfheader.cabinetFileSize = 0;
+
+ foreach (File file in files)
+ {
+ Internal.CFFILE cffile = new Internal.CFFILE();
+ cffile.name = file.Name;
+ cffile.decompressedSize = (uint)file.Size;
+ cffile.offset = 0; // TODO: how to get the offset of the file?
+ cffile.folderIndex = 0;
+ cfheader.cabinetFileSize += cffile.decompressedSize;
+ cffiles.Add(cffile);
+ }
+
+ #region cffolder
+ {
+ Internal.CFFOLDER cffolder = new Internal.CFFOLDER();
+ cffolder.compressionMethod = CABCompressionMethod.None;
+ cffolder.dataBlockCount = 1;
+ cffolder.firstDataBlockOffset = 0;
+ cffolders.Add(cffolder);
+ }
+ #endregion
+
+ cfheader.firstFileOffset = 0;
+
+ cfheader.versionMajor = 3;
+ cfheader.versionMinor = 1;
+
+ cfheader.folderCount = (ushort)cffolders.Count;
+ cfheader.fileCount = (ushort)cffiles.Count;
+
+ cfheader.setID = 12345;
+ cfheader.iCabinet = 0;
+
+ cfheader.cabinetReservedAreaSize = mvarCabinetReservedAreaSize;
+ cfheader.folderReservedAreaSize = mvarFolderReservedAreaSize;
+ cfheader.datablockReservedAreaSize = mvarDatablockReservedAreaSize;
+
+ cfheader.nextCabinetName = mvarNextCabinetName;
+ cfheader.nextDiskName = mvarNextDiskName;
+ cfheader.previousCabinetName = mvarPreviousCabinetName;
+ cfheader.previousDiskName = mvarPreviousDiskName;
+
+ if (cfheader.cabinetReservedAreaSize != 0 || cfheader.folderReservedAreaSize != 0 || cfheader.datablockReservedAreaSize != 0) cfheader.flags |= CABFlags.HasReservedArea;
+ if (!String.IsNullOrEmpty(cfheader.nextCabinetName) || !String.IsNullOrEmpty(cfheader.nextDiskName)) cfheader.flags |= CABFlags.HasNextCabinet;
+ if (!String.IsNullOrEmpty(cfheader.previousCabinetName) || !String.IsNullOrEmpty(cfheader.previousCabinetName)) cfheader.flags |= CABFlags.HasPreviousCabinet;
+
+ WriteCFHEADER(bw, cfheader);
+
+ foreach (Internal.CFFOLDER cffolder in cffolders)
+ {
+ WriteCFFOLDER(bw, cffolder, cfheader);
+ }
+ foreach (Internal.CFFILE cffile in cffiles)
+ {
+ WriteCFFILE(bw, cffile);
+ }
+ }
+ #endregion
+ }
+}
diff --git a/CSharp/Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/Cabinet/CABFlags.cs b/CSharp/Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/Cabinet/CABFlags.cs
new file mode 100644
index 00000000..3a53fbbf
--- /dev/null
+++ b/CSharp/Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/Cabinet/CABFlags.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace UniversalEditor.DataFormats.FileSystem.Microsoft.Cabinet
+{
+ [Flags()]
+ public enum CABFlags
+ {
+ HasPreviousCabinet = 0x0001,
+ HasNextCabinet = 0x0002,
+ HasReservedArea = 0x0004
+ }
+}
diff --git a/CSharp/Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/Cabinet/Internal/CFDATA.cs b/CSharp/Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/Cabinet/Internal/CFDATA.cs
new file mode 100644
index 00000000..73a43ecb
--- /dev/null
+++ b/CSharp/Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/Cabinet/Internal/CFDATA.cs
@@ -0,0 +1,31 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace UniversalEditor.DataFormats.FileSystem.Microsoft.Cabinet.Internal
+{
+ internal struct CFDATA
+ {
+ ///
+ /// checksum of this CFDATA entry
+ ///
+ public uint checksum;
+ ///
+ /// number of compressed bytes in this block
+ ///
+ public ushort compressedLength;
+ ///
+ /// number of uncompressed bytes in this block
+ ///
+ public ushort decompressedLength;
+ ///
+ /// (optional) per-datablock reserved area
+ ///
+ public byte[] reservedArea;
+ ///
+ /// compressed data bytes
+ ///
+ public byte[] data;
+ }
+}
diff --git a/CSharp/Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/Cabinet/Internal/CFFILE.cs b/CSharp/Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/Cabinet/Internal/CFFILE.cs
new file mode 100644
index 00000000..6a9b577b
--- /dev/null
+++ b/CSharp/Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/Cabinet/Internal/CFFILE.cs
@@ -0,0 +1,39 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace UniversalEditor.DataFormats.FileSystem.Microsoft.Cabinet.Internal
+{
+ internal struct CFFILE
+ {
+ ///
+ /// uncompressed size of this file in bytes
+ ///
+ public uint decompressedSize;
+ ///
+ /// uncompressed offset of this file in the folder
+ ///
+ public uint offset;
+ ///
+ /// index into the CFFOLDER area
+ ///
+ public ushort folderIndex;
+ ///
+ /// date stamp for this file
+ ///
+ public ushort date;
+ ///
+ /// time stamp for this file
+ ///
+ public ushort time;
+ ///
+ /// attribute flags for this file
+ ///
+ public ushort attribs;
+ ///
+ /// name of this file
+ ///
+ public string name;
+ }
+}
diff --git a/CSharp/Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/Cabinet/Internal/CFFOLDER.cs b/CSharp/Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/Cabinet/Internal/CFFOLDER.cs
new file mode 100644
index 00000000..be60f5cf
--- /dev/null
+++ b/CSharp/Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/Cabinet/Internal/CFFOLDER.cs
@@ -0,0 +1,27 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace UniversalEditor.DataFormats.FileSystem.Microsoft.Cabinet.Internal
+{
+ internal struct CFFOLDER
+ {
+ ///
+ /// offset of the first CFDATA block in this folder
+ ///
+ public uint firstDataBlockOffset;
+ ///
+ /// number of CFDATA blocks in this folder
+ ///
+ public ushort dataBlockCount;
+ ///
+ /// compression type indicator
+ ///
+ public CABCompressionMethod compressionMethod;
+ ///
+ /// (optional) per-folder reserved area
+ ///
+ public byte[] reservedArea;
+ }
+}
diff --git a/CSharp/Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/Cabinet/Internal/CFHEADER.cs b/CSharp/Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/Cabinet/Internal/CFHEADER.cs
new file mode 100644
index 00000000..6b831fd5
--- /dev/null
+++ b/CSharp/Plugins/UniversalEditor.Plugins.Microsoft/DataFormats/FileSystem/Microsoft/Cabinet/Internal/CFHEADER.cs
@@ -0,0 +1,38 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace UniversalEditor.DataFormats.FileSystem.Microsoft.Cabinet.Internal
+{
+ internal struct CFHEADER
+ {
+ public string signature;
+ public uint reserved1;
+ public uint cabinetFileSize;
+ public uint reserved2;
+ public uint firstFileOffset;
+ public uint reserved3;
+ public byte versionMinor;
+ public byte versionMajor;
+
+ public ushort folderCount;
+ public ushort fileCount;
+ public CABFlags flags;
+
+ public ushort setID;
+ public ushort iCabinet;
+
+ public ushort cabinetReservedAreaSize;
+ public byte folderReservedAreaSize;
+ public byte datablockReservedAreaSize;
+
+ public byte[] reservedArea;
+
+ public string previousCabinetName;
+ public string previousDiskName;
+
+ public string nextCabinetName;
+ public string nextDiskName;
+ }
+}
diff --git a/CSharp/Plugins/UniversalEditor.Plugins.Microsoft/UniversalEditor.Plugins.Microsoft.csproj b/CSharp/Plugins/UniversalEditor.Plugins.Microsoft/UniversalEditor.Plugins.Microsoft.csproj
index 35cadf56..16af1a2c 100644
--- a/CSharp/Plugins/UniversalEditor.Plugins.Microsoft/UniversalEditor.Plugins.Microsoft.csproj
+++ b/CSharp/Plugins/UniversalEditor.Plugins.Microsoft/UniversalEditor.Plugins.Microsoft.csproj
@@ -37,6 +37,13 @@
+
+
+
+
+
+
+
@@ -53,6 +60,10 @@
+
+ {3f664673-7e22-4486-9ad0-fc81861d0b78}
+ UniversalEditor.Compression
+
{2D4737E6-6D95-408A-90DB-8DFF38147E85}
UniversalEditor.Core