various enhancements and improvements to WinRAR DataFormat

This commit is contained in:
Michael Becker 2020-05-03 13:43:40 -04:00
parent 0a47423f29
commit 420742e74b
No known key found for this signature in database
GPG Key ID: 506F54899E2BFED7
24 changed files with 1897 additions and 90 deletions

View File

@ -0,0 +1,44 @@
//
// RARArchiveHeaderV5.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// 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.FileSystem.WinRAR.Blocks
{
public class RARArchiveBlock : RARBlock
{
public V5.RARArchiveBlockFlagsV5 archiveFlags;
public long volumeNumber;
public override object Clone()
{
RARArchiveBlock clone = new RARArchiveBlock();
clone.crc = crc;
clone.size = size;
clone.headerType = headerType;
clone.headerFlags = headerFlags;
clone.extraAreaSize = extraAreaSize;
clone.dataSize = dataSize;
clone.archiveFlags = archiveFlags;
clone.volumeNumber = volumeNumber;
return clone;
}
}
}

View File

@ -0,0 +1,42 @@
//
// RAREndHeaderV5.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// 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.FileSystem.WinRAR.Blocks
{
public class RAREndBlock : RARBlock
{
public V5.RAREndBlockFlags endOfArchiveFlags;
public override object Clone()
{
RAREndBlock clone = new RAREndBlock();
clone.crc = crc;
clone.size = size;
clone.headerType = headerType;
clone.headerFlags = headerFlags;
clone.extraAreaSize = extraAreaSize;
clone.dataSize = dataSize;
clone.endOfArchiveFlags = endOfArchiveFlags;
return clone;
}
}
}

View File

@ -0,0 +1,63 @@
//
// RARFileHeaderV5.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// 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.FileSystem.WinRAR.Blocks
{
public class RARFileBlock : RARBlock
{
public V5.RARFileBlockFlags fileFlags;
public long unpackedSize;
public V5.RARFileAttributes attributes;
public uint mtime;
public uint dataCrc;
public long compressionFlags;
public RARHostOperatingSystem hostOperatingSystem;
public long fileNameLength;
public string fileName;
public long dataOffset;
public override object Clone()
{
RARFileBlock clone = new RARFileBlock();
clone.crc = crc;
clone.size = size;
clone.headerType = headerType;
clone.headerFlags = headerFlags;
clone.extraAreaSize = extraAreaSize;
clone.dataSize = dataSize;
clone.fileFlags = fileFlags;
clone.unpackedSize = unpackedSize;
clone.attributes = attributes;
clone.mtime = mtime;
clone.dataCrc = dataCrc;
clone.compressionFlags = compressionFlags;
clone.hostOperatingSystem = hostOperatingSystem;
clone.fileNameLength = fileNameLength;
clone.fileName = fileName;
clone.dataOffset = dataOffset;
return clone;
}
}
}

View File

@ -0,0 +1,59 @@
//
// RARBlockHeaderV5.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// 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;
namespace UniversalEditor.DataFormats.FileSystem.WinRAR
{
public abstract class RARBlock : ICloneable
{
public class RARBlockCollection
: System.Collections.ObjectModel.Collection<RARBlock>
{
}
/// <summary>
/// CRC32 of header data starting from Header size field and up to and including the optional extra area.
/// </summary>
public uint crc;
/// <summary>
/// Size of header data starting from Header type field and up to and including the optional extra area. This field must not be longer than 3 bytes in
/// current implementation, resulting in 2 MB maximum header size.
/// </summary>
public long size;
/// <summary>
/// Type of archive header.
/// </summary>
public RARBlockType headerType;
public RARBlockFlags headerFlags;
/// <summary>
/// Size of extra area. Optional field, present only if 0x0001 header flag is set.
/// </summary>
public long extraAreaSize;
/// <summary>
/// Size of data area.Optional field, present only if 0x0002 header flag is set.
/// </summary>
public long dataSize;
public abstract object Clone();
}
}

View File

@ -0,0 +1,306 @@
//
// RARBlockDataFormat.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// 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.FileSystem.WinRAR.Blocks;
using UniversalEditor.IO;
namespace UniversalEditor.DataFormats.FileSystem.WinRAR
{
public class RARBlockDataFormat : DataFormat
{
public RARFormatVersion FormatVersion { get; set; } = RARFormatVersion.Modern;
private long FindStartOfRar(Reader reader)
{
while (!reader.EndOfStream)
{
string Rar = reader.ReadFixedLengthString(4);
if (Rar == "\x52\x45\x7e\x5e")
{
FormatVersion = RARFormatVersion.Ancient;
return reader.Accessor.Position;
}
else if (Rar == "Rar!")
{
ushort a10 = reader.ReadUInt16();
if (a10 != 0x071A) throw new InvalidDataFormatException("Invalid block header");
byte a11 = reader.ReadByte(); // 01?
if (a11 == 1)
{
byte a12 = reader.ReadByte();
if (a12 != 0) throw new InvalidDataFormatException("Invalid block header");
FormatVersion = RARFormatVersion.Enhanced;
return reader.Accessor.Position;
}
else if (a11 == 0)
{
}
else
{
throw new InvalidDataFormatException("Invalid block header");
}
FormatVersion = RARFormatVersion.Modern;
return reader.Accessor.Position;
}
else
{
reader.Seek(-3, SeekOrigin.Current);
continue;
}
}
return -1;
}
protected override void LoadInternal(ref ObjectModel objectModel)
{
RARBlockObjectModel bom = (objectModel as RARBlockObjectModel);
Reader reader = Accessor.Reader;
long rarStart = FindStartOfRar(reader);
if (rarStart == -1)
throw new InvalidDataFormatException("could not find start of RAR data");
reader.Accessor.Seek(rarStart, SeekOrigin.Begin);
while (!reader.EndOfStream)
{
switch (FormatVersion)
{
case RARFormatVersion.Modern:
{
//RARv4
ushort head_crc = reader.ReadUInt16();
V4.RARBlockTypeV4 headerType = (V4.RARBlockTypeV4)reader.ReadByte();
V4.RARArchiveBlockFlagsV4 head_flags = (V4.RARArchiveBlockFlagsV4)reader.ReadUInt16();
ushort head_size = reader.ReadUInt16();
if (reader.EndOfStream) break;
switch (headerType)
{
case V4.RARBlockTypeV4.Archive:
{
RARArchiveBlock block = new RARArchiveBlock();
block.crc = head_crc;
block.headerType = RARBlockTypeV4ToRARBlockType(headerType);
block.size = head_size;
ushort reserved1 = reader.ReadUInt16();
uint reserved2 = reader.ReadUInt32();
bom.Blocks.Add(block);
break;
}
case V4.RARBlockTypeV4.File:
{
RARFileBlock block = new RARFileBlock();
block.crc = head_crc;
block.headerType = RARBlockTypeV4ToRARBlockType(headerType);
block.size = head_size;
block.dataSize = reader.ReadUInt32();
block.unpackedSize = reader.ReadUInt32();
block.hostOperatingSystem = (RARHostOperatingSystem)reader.ReadByte();
block.dataCrc = reader.ReadUInt32();
block.mtime = reader.ReadUInt32();
// Version number is encoded as 10 * Major version + minor version.
byte requiredVersionToUnpack = reader.ReadByte();
RARCompressionMethod compressionMethod = (RARCompressionMethod)reader.ReadByte();
block.fileNameLength = reader.ReadUInt16();
uint fileAttributes = reader.ReadUInt32();
if (((RARFileHeaderFlags)head_flags & RARFileHeaderFlags.SupportLargeFiles) == RARFileHeaderFlags.SupportLargeFiles)
{
// High 4 bytes of 64 bit value of compressed file size.
uint highPackSize = reader.ReadUInt32();
// High 4 bytes of 64 bit value of uncompressed file size.
uint highUnpackSize = reader.ReadUInt32();
}
block.fileName = reader.ReadFixedLengthString(block.fileNameLength);
byte nul = reader.ReadByte();
if (((RARFileHeaderFlags)head_flags & RARFileHeaderFlags.EncryptionSaltPresent) == RARFileHeaderFlags.EncryptionSaltPresent)
{
long salt = reader.ReadInt64();
}
if (((RARFileHeaderFlags)head_flags & RARFileHeaderFlags.ExtendedTimeFieldPresent) == RARFileHeaderFlags.ExtendedTimeFieldPresent)
{
uint exttime = reader.ReadUInt32();
}
long offset = reader.Accessor.Position;
block.dataOffset = offset;
reader.Seek(block.dataSize, SeekOrigin.Current);
if (!(block.unpackedSize == 0 && block.dataSize == 0))
{
// if both these fields are zero, we don't care - it's a folder record
// otherwise, it's a file record and we need to add it
bom.Blocks.Add(block);
}
break;
}
}
break;
}
case RARFormatVersion.Enhanced:
{
//RARv5
uint crc = reader.ReadUInt32();
long size = reader.Read7BitEncodedInt();
V5.RARBlockTypeV5 headerType = (V5.RARBlockTypeV5)reader.Read7BitEncodedInt();
RARBlockFlags headerFlags = (RARBlockFlags)reader.Read7BitEncodedInt();
long extraAreaSize = 0, dataSize = 0;
if ((headerFlags & RARBlockFlags.ExtraAreaPresent) == RARBlockFlags.ExtraAreaPresent)
{
extraAreaSize = reader.Read7BitEncodedInt();
}
if ((headerFlags & RARBlockFlags.DataAreaPresent) == RARBlockFlags.DataAreaPresent)
{
dataSize = reader.Read7BitEncodedInt();
}
switch (headerType)
{
case V5.RARBlockTypeV5.Main:
{
RARArchiveBlock header = new RARArchiveBlock();
header.crc = crc;
header.size = size;
header.headerType = RARBlockTypeV5ToRARBlockType(headerType);
header.headerFlags = headerFlags;
header.extraAreaSize = extraAreaSize;
header.dataSize = dataSize;
((RARArchiveBlock)header).archiveFlags = (V5.RARArchiveBlockFlagsV5)reader.Read7BitEncodedInt();
if ((((RARArchiveBlock)header).archiveFlags & V5.RARArchiveBlockFlagsV5.VolumeNumberFieldPresent) == V5.RARArchiveBlockFlagsV5.VolumeNumberFieldPresent)
{
((RARArchiveBlock)header).volumeNumber = reader.Read7BitEncodedInt();
}
bom.Blocks.Add(header);
break;
}
case V5.RARBlockTypeV5.File:
case V5.RARBlockTypeV5.Service:
{
RARFileBlock header = new RARFileBlock();
header.crc = crc;
header.size = size;
header.headerType = RARBlockTypeV5ToRARBlockType(headerType);
header.headerFlags = headerFlags;
header.extraAreaSize = extraAreaSize;
header.dataSize = dataSize;
((RARFileBlock)header).fileFlags = (V5.RARFileBlockFlags)reader.Read7BitEncodedInt();
((RARFileBlock)header).unpackedSize = reader.Read7BitEncodedInt();
((RARFileBlock)header).attributes = (V5.RARFileAttributes)reader.Read7BitEncodedInt();
if ((((RARFileBlock)header).fileFlags & V5.RARFileBlockFlags.TimeFieldPresent) == V5.RARFileBlockFlags.TimeFieldPresent)
{
((RARFileBlock)header).mtime = reader.ReadUInt32();
}
if ((((RARFileBlock)header).fileFlags & V5.RARFileBlockFlags.CRC32Present) == V5.RARFileBlockFlags.CRC32Present)
{
((RARFileBlock)header).dataCrc = reader.ReadUInt32();
}
((RARFileBlock)header).compressionFlags = reader.Read7BitEncodedInt();
((RARFileBlock)header).hostOperatingSystem = (RARHostOperatingSystem)reader.Read7BitEncodedInt();
((RARFileBlock)header).fileNameLength = reader.Read7BitEncodedInt();
((RARFileBlock)header).fileName = reader.ReadFixedLengthString(((RARFileBlock)header).fileNameLength);
((RARFileBlock)header).dataOffset = reader.Accessor.Position + extraAreaSize;
bom.Blocks.Add(header);
break;
}
case V5.RARBlockTypeV5.End:
{
RAREndBlock header = new RAREndBlock();
header.crc = crc;
header.size = size;
header.headerType = RARBlockTypeV5ToRARBlockType(headerType);
header.headerFlags = headerFlags;
((RAREndBlock)header).endOfArchiveFlags = (V5.RAREndBlockFlags)reader.Read7BitEncodedInt();
header.extraAreaSize = extraAreaSize;
header.dataSize = dataSize;
bom.Blocks.Add(header);
break;
}
}
// extra area...
reader.Seek(extraAreaSize, SeekOrigin.Current);
// data area...
reader.Seek(dataSize, SeekOrigin.Current);
break;
}
}
}
}
private RARBlockType RARBlockTypeV5ToRARBlockType(V5.RARBlockTypeV5 headerType)
{
switch (headerType)
{
case V5.RARBlockTypeV5.Encryption: return RARBlockType.Encryption;
case V5.RARBlockTypeV5.End: return RARBlockType.End;
case V5.RARBlockTypeV5.File: return RARBlockType.File;
case V5.RARBlockTypeV5.Main: return RARBlockType.Main;
case V5.RARBlockTypeV5.Service: return RARBlockType.Service;
}
return RARBlockType.Unknown;
}
private RARBlockType RARBlockTypeV4ToRARBlockType(V4.RARBlockTypeV4 headerType)
{
switch (headerType)
{
case V4.RARBlockTypeV4.Archive: return RARBlockType.Main;
case V4.RARBlockTypeV4.File: return RARBlockType.File;
case V4.RARBlockTypeV4.Marker: return RARBlockType.Marker;
case V4.RARBlockTypeV4.OldAuthenticity: return RARBlockType.OldAuthenticity;
case V4.RARBlockTypeV4.OldAuthenticity2:return RARBlockType.OldAuthenticity2;
case V4.RARBlockTypeV4.OldComment: return RARBlockType.OldComment;
case V4.RARBlockTypeV4.OldRecoveryRecord: return RARBlockType.OldRecoveryRecord;
case V4.RARBlockTypeV4.OldSubblock: return RARBlockType.OldSubblock;
case V4.RARBlockTypeV4.Subblock: return RARBlockType.Subblock;
}
return RARBlockType.Unknown;
}
protected override void SaveInternal(ObjectModel objectModel)
{
throw new NotImplementedException();
}
}
}

View File

@ -0,0 +1,57 @@
//
// RARHeaderFlagsV5.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// 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.FileSystem.WinRAR
{
[Flags()]
public enum RARBlockFlags
{
None = 0x0000,
/// <summary>
/// Extra area is present in the end of header.
/// </summary>
ExtraAreaPresent = 0x0001,
/// <summary>
/// Data area is present in the end of header.
/// </summary>
DataAreaPresent = 0x0002,
/// <summary>
/// Blocks with unknown type and this flag must be skipped when updating an archive.
/// </summary>
SkipUnknownBlocks = 0x0004,
/// <summary>
/// Data area is continuing from previous volume.
/// </summary>
ContinuedFromPrevious = 0x0008,
/// <summary>
/// Data area is continuing in next volume.
/// </summary>
ContinuedInNext = 0x0010,
/// <summary>
/// Block depends on preceding file block.
/// </summary>
DependentBlock = 0x0020,
/// <summary>
/// Preserve a child block if host block is modified.
/// </summary>
PreserveChild = 0x0040
}
}

View File

@ -0,0 +1,43 @@
//
// RARBlockObjectModel.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// 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.FileSystem.WinRAR
{
public class RARBlockObjectModel : ObjectModel
{
public RARBlock.RARBlockCollection Blocks { get; } = new RARBlock.RARBlockCollection();
public override void Clear()
{
Blocks.Clear();
}
public override void CopyTo(ObjectModel where)
{
RARBlockObjectModel clone = (where as RARBlockObjectModel);
if (clone == null) throw new ObjectModelNotSupportedException();
for (int i = 0; i < Blocks.Count; i++)
{
clone.Blocks.Add(Blocks[i].Clone() as RARBlock);
}
}
}
}

View File

@ -0,0 +1,56 @@
//
// RARBlockType.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// 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.FileSystem.WinRAR
{
public enum RARBlockType
{
Unknown = -1,
Marker,
/// <summary>
/// Main archive header
/// </summary>
Main,
/// <summary>
/// File header
/// </summary>
File,
/// <summary>
/// Service header
/// </summary>
Service,
/// <summary>
/// Archive encryption header
/// </summary>
Encryption,
/// <summary>
/// End of archive header
/// </summary>
End,
OldComment,
OldAuthenticity,
OldSubblock,
OldRecoveryRecord,
OldAuthenticity2,
Subblock
}
}

View File

@ -19,8 +19,9 @@
// 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 System.Collections.Generic;
using UniversalEditor.DataFormats.FileSystem.WinRAR.Blocks;
using UniversalEditor.IO;
using UniversalEditor.ObjectModels.FileSystem;
namespace UniversalEditor.DataFormats.FileSystem.WinRAR
@ -33,7 +34,7 @@ namespace UniversalEditor.DataFormats.FileSystem.WinRAR
/// published unrar source in the development of this <see cref="DataFormat" />. It may end up that this <see cref="DataFormat" /> is only able
/// to handle uncompressed (i.e. stored) RAR files, and until there exists a better solution to the unrar licensing problem, it will have to do.
/// </remarks>
public class RARDataFormat : DataFormat
public class RARDataFormat : RARBlockDataFormat
{
private static DataFormatReference _dfr = null;
protected override DataFormatReference MakeReferenceInternal()
@ -46,92 +47,83 @@ namespace UniversalEditor.DataFormats.FileSystem.WinRAR
return _dfr;
}
protected override void LoadInternal(ref ObjectModel objectModel)
void F_DataRequest(object sender, DataRequestEventArgs e)
{
FileSystemObjectModel fsom = (objectModel as FileSystemObjectModel);
File f = (File)sender;
Reader reader = (Reader)f.Properties["reader"];
long offset = (long)f.Properties["offset"];
long CompressedLength = (long)f.Properties["CompressedLength"];
long DecompressedLength = (long)f.Properties["DecompressedLength"];
IO.Reader br = base.Accessor.Reader;
br.Accessor.Position = 0;
#region marker block
string Rar = br.ReadFixedLengthString(4);
if (Rar != "Rar!") throw new InvalidDataFormatException("File does not begin with \"Rar!\"");
ushort a10 = br.ReadUInt16();
byte a11 = br.ReadByte();
if (a10 != 0x071A || a11 != 0x00) throw new InvalidDataFormatException("Invalid block header");
#endregion
#region archive header
{
ushort head_crc = br.ReadUInt16();
RARHeaderType head_type = (RARHeaderType)br.ReadByte();
RARHeaderFlags head_flags = (RARHeaderFlags)br.ReadUInt16();
ushort head_size = br.ReadUInt16();
ushort reserved1 = br.ReadUInt16();
uint reserved2 = br.ReadUInt32();
}
#endregion
#region File Entry
while (br.Accessor.Position + 3 < br.Accessor.Length)
{
ushort head_crc = br.ReadUInt16();
RARHeaderType head_type = (RARHeaderType)br.ReadByte();
RARFileHeaderFlags head_flags = (RARFileHeaderFlags)br.ReadUInt16();
ushort head_size = br.ReadUInt16();
if (br.EndOfStream) break;
uint compressedSize = br.ReadUInt32();
uint decompressedSize = br.ReadUInt32();
RARHostOperatingSystem hostOS = (RARHostOperatingSystem)br.ReadByte();
uint fileCRC = br.ReadUInt32();
uint dateTimeDOS = br.ReadUInt32();
// Version number is encoded as 10 * Major version + minor version.
byte requiredVersionToUnpack = br.ReadByte();
RARCompressionMethod compressionMethod = (RARCompressionMethod)br.ReadByte();
ushort fileNameSize = br.ReadUInt16();
uint fileAttributes = br.ReadUInt32();
if ((head_flags & RARFileHeaderFlags.SupportLargeFiles) == RARFileHeaderFlags.SupportLargeFiles)
{
// High 4 bytes of 64 bit value of compressed file size.
uint highPackSize = br.ReadUInt32();
// High 4 bytes of 64 bit value of uncompressed file size.
uint highUnpackSize = br.ReadUInt32();
}
string filename = br.ReadFixedLengthString(fileNameSize);
byte nul = br.ReadByte();
if ((head_flags & RARFileHeaderFlags.EncryptionSaltPresent) == RARFileHeaderFlags.EncryptionSaltPresent)
{
long salt = br.ReadInt64();
}
if ((head_flags & RARFileHeaderFlags.ExtendedTimeFieldPresent) == RARFileHeaderFlags.ExtendedTimeFieldPresent)
{
uint exttime = br.ReadUInt32();
}
byte[] compressedData = br.ReadBytes(compressedSize);
byte[] decompressedData = compressedData;
fsom.Files.Add(filename, decompressedData);
}
#endregion
reader.Seek(offset, SeekOrigin.Begin);
byte[] compressedData = reader.ReadBytes(CompressedLength);
byte[] decompressedData = compressedData;
e.Data = decompressedData;
}
protected override void SaveInternal(ObjectModel objectModel)
protected override void BeforeLoadInternal(Stack<ObjectModel> objectModels)
{
throw new NotImplementedException();
base.BeforeLoadInternal(objectModels);
objectModels.Push(new RARBlockObjectModel());
}
protected override void AfterLoadInternal(Stack<ObjectModel> objectModels)
{
base.AfterLoadInternal(objectModels);
RARBlockObjectModel bom = objectModels.Pop() as RARBlockObjectModel;
FileSystemObjectModel fsom = (objectModels.Pop() as FileSystemObjectModel);
if (fsom == null)
throw new ObjectModelNotSupportedException();
Reader reader = Accessor.Reader;
bool endOfArchiveReached = false;
for (int i = 0; i < bom.Blocks.Count; i++)
{
RARBlock header = bom.Blocks[i];
if (header is RARFileBlock fh)
{
if (fh.headerType == RARBlockType.File)
{
File f = fsom.AddFile(fh.fileName);
f.Properties["reader"] = reader;
f.Properties["offset"] = fh.dataOffset;
f.Properties["CompressedLength"] = fh.dataSize;
f.Properties["DecompressedLength"] = fh.unpackedSize;
f.Size = fh.unpackedSize;
f.DataRequest += F_DataRequest;
}
else if (fh.headerType == RARBlockType.Service)
{
if (fh.fileName == "CMT")
{
}
else if (fh.fileName == "QO")
{
}
}
}
else if (header is RAREndBlock eh)
{
endOfArchiveReached = true;
}
}
if (!endOfArchiveReached)
{
UserInterface.HostApplication.Messages.Add(UserInterface.HostApplicationMessageSeverity.Warning, "end of file reached before end of archive marker", Accessor.GetFileName());
}
}
protected override void BeforeSaveInternal(Stack<ObjectModel> objectModels)
{
base.BeforeSaveInternal(objectModels);
RARBlockObjectModel bom = new RARBlockObjectModel();
objectModels.Push(bom);
}
}
}

View File

@ -0,0 +1,42 @@
//
// RARFormatVersion.cs - indicates the format version for a RAR archive
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2011-2020 Mike Becker's Software
//
// 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/>.
namespace UniversalEditor.DataFormats.FileSystem.WinRAR
{
/// <summary>
/// Indicates the format version for a RAR archive.
/// </summary>
public enum RARFormatVersion
{
/// <summary>
/// The ancient RAR format beginning with "RE~".
/// </summary>
Ancient,
/// <summary>
/// The modern RAR format beginning with "Rar!".
/// </summary>
Modern,
/// <summary>
/// The modern RAR format beginning with "Rar!" and containing a V5 archive header signal.
/// </summary>
Enhanced
}
}

View File

@ -21,13 +21,13 @@
using System;
namespace UniversalEditor.DataFormats.FileSystem.WinRAR
namespace UniversalEditor.DataFormats.FileSystem.WinRAR.V4
{
/// <summary>
/// Indicates header attributes for a RAR archive.
/// </summary>
[Flags()]
public enum RARHeaderFlags
public enum RARArchiveBlockFlagsV4
{
ArchiveVolume = 0x0001,
/// <summary>

View File

@ -19,12 +19,12 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
namespace UniversalEditor.DataFormats.FileSystem.WinRAR
namespace UniversalEditor.DataFormats.FileSystem.WinRAR.V4
{
/// <summary>
/// Indicates the type of header in a RAR file.
/// </summary>
public enum RARHeaderType : byte
public enum RARBlockTypeV4 : byte
{
Marker = 0x72,
Archive = 0x73,

View File

@ -0,0 +1,51 @@
//
// RARArchiveHeaderFlagsV5.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// 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.FileSystem.WinRAR.V5
{
[Flags()]
public enum RARArchiveBlockFlagsV5
{
None = 0x0000,
/// <summary>
/// Volume. Archive is a part of multivolume set.
/// </summary>
Volume = 0x0001,
/// <summary>
/// Volume number field is present. This flag is present in all volumes except first.
/// </summary>
VolumeNumberFieldPresent = 0x0002,
/// <summary>
/// Solid archive.
/// </summary>
Solid = 0x0004,
/// <summary>
/// Recovery record is present.
/// </summary>
RecoveryRecordPresent = 0x0008,
/// <summary>
/// Locked archive.
/// </summary>
Locked = 0x0010
}
}

View File

@ -0,0 +1,47 @@
//
// RARHeaderTypeV5.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// 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.FileSystem.WinRAR.V5
{
public enum RARBlockTypeV5
{
/// <summary>
/// Main archive header
/// </summary>
Main = 0x01,
/// <summary>
/// File header
/// </summary>
File = 0x02,
/// <summary>
/// Service header
/// </summary>
Service = 0x03,
/// <summary>
/// Archive encryption header
/// </summary>
Encryption = 0x04,
/// <summary>
/// End of archive header
/// </summary>
End = 0x05
}
}

View File

@ -0,0 +1,32 @@
//
// RAREndHeaderFlagsV5.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// 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.FileSystem.WinRAR.V5
{
public enum RAREndBlockFlags
{
None = 0x0000,
/// <summary>
/// Archive is volume and is not the last volume in the set.
/// </summary>
Continued = 0x0001
}
}

View File

@ -0,0 +1,31 @@
//
// RARFileAttributesV5.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// 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.FileSystem.WinRAR.V5
{
[Flags()]
public enum RARFileAttributes
{
None = 0x0000
}
}

View File

@ -0,0 +1,49 @@
//
// V5RARFileFlags.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// 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.FileSystem.WinRAR.V5
{
[Flags()]
public enum RARFileBlockFlags
{
/// <summary>
/// Directory file system object (file header only).
/// </summary>
DirectoryFileSystemObject = 0x0001,
/// <summary>
/// Time field in Unix format is present.
/// </summary>
TimeFieldPresent = 0x0002,
/// <summary>
/// CRC32 field is present.
/// </summary>
CRC32Present = 0x0004,
/// <summary>
/// Unpacked size is unknown.
/// </summary>
/// <remarks>
/// If flag 0x0008 (<see cref="UnpackedSizeUnknown" />) is set, unpacked size field is still present, but must be ignored and extraction must be
/// performed until reaching the end of compression stream. This flag can be set if actual file size is larger than reported by OS or if file size is
/// unknown such as for all volumes except last when archiving from stdin to multivolume archive.
/// </remarks>
UnpackedSizeUnknown = 0x0008
}
}

View File

@ -0,0 +1,90 @@
//
// RAROpcode.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// 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.FileSystem.WinRAR.VM
{
public abstract class RAROpcode
{
public abstract RAROpcodeType Type { get; }
public uint value1;
public uint value2;
public bool bytemode;
public byte addressingmode1;
public byte addressingmode2;
public RARGetterFunction operand1getter;
public RARSetterFunction operand1setter;
public RARGetterFunction operand2getter;
public RARSetterFunction operand2setter;
public static readonly RAROpcodeFlags[] InstructionFlags = new RAROpcodeFlags[]
{
/*/*[RARMovInstruction]*/ RAROpcodeFlags.RAR2OperandsFlag | RAROpcodeFlags.RARHasByteModeFlag | RAROpcodeFlags.RARWritesFirstOperandFlag,
/*[RARCmpInstruction]*/ RAROpcodeFlags.RAR2OperandsFlag | RAROpcodeFlags.RARHasByteModeFlag | RAROpcodeFlags.RARWritesStatusFlag,
/*[RARAddInstruction]*/ RAROpcodeFlags.RAR2OperandsFlag | RAROpcodeFlags.RARHasByteModeFlag | RAROpcodeFlags.RARWritesFirstOperandFlag | RAROpcodeFlags.RARWritesStatusFlag,
/*[RARSubInstruction]*/ RAROpcodeFlags.RAR2OperandsFlag | RAROpcodeFlags.RARHasByteModeFlag | RAROpcodeFlags.RARWritesFirstOperandFlag | RAROpcodeFlags.RARWritesStatusFlag,
/*[RARJzInstruction]*/ RAROpcodeFlags.RAR1OperandFlag | RAROpcodeFlags.RARIsUnconditionalJumpFlag | RAROpcodeFlags.RARIsRelativeJumpFlag | RAROpcodeFlags.RARReadsStatusFlag,
/*[RARJnzInstruction]*/ RAROpcodeFlags.RAR1OperandFlag | RAROpcodeFlags.RARIsRelativeJumpFlag | RAROpcodeFlags.RARReadsStatusFlag,
/*[RARIncInstruction]*/ RAROpcodeFlags.RAR1OperandFlag | RAROpcodeFlags.RARHasByteModeFlag | RAROpcodeFlags.RARWritesFirstOperandFlag | RAROpcodeFlags.RARWritesStatusFlag,
/*[RARDecInstruction]*/ RAROpcodeFlags.RAR1OperandFlag | RAROpcodeFlags.RARHasByteModeFlag | RAROpcodeFlags.RARWritesFirstOperandFlag | RAROpcodeFlags.RARWritesStatusFlag,
/*[RARJmpInstruction]*/ RAROpcodeFlags.RAR1OperandFlag | RAROpcodeFlags.RARIsRelativeJumpFlag,
/*[RARXorInstruction]*/ RAROpcodeFlags.RAR2OperandsFlag | RAROpcodeFlags.RARHasByteModeFlag | RAROpcodeFlags.RARWritesFirstOperandFlag | RAROpcodeFlags.RARWritesStatusFlag,
/*[RARAndInstruction]*/ RAROpcodeFlags.RAR2OperandsFlag | RAROpcodeFlags.RARHasByteModeFlag | RAROpcodeFlags.RARWritesFirstOperandFlag | RAROpcodeFlags.RARWritesStatusFlag,
/*[RAROrInstruction]*/ RAROpcodeFlags.RAR2OperandsFlag | RAROpcodeFlags.RARHasByteModeFlag | RAROpcodeFlags.RARWritesFirstOperandFlag | RAROpcodeFlags.RARWritesStatusFlag,
/*[RARTestInstruction]*/ RAROpcodeFlags.RAR2OperandsFlag | RAROpcodeFlags.RARHasByteModeFlag | RAROpcodeFlags.RARWritesStatusFlag,
/*[RARJsInstruction]*/ RAROpcodeFlags.RAR1OperandFlag | RAROpcodeFlags.RARIsRelativeJumpFlag | RAROpcodeFlags.RARReadsStatusFlag,
/*[RARJnsInstruction]*/ RAROpcodeFlags.RAR1OperandFlag | RAROpcodeFlags.RARIsRelativeJumpFlag | RAROpcodeFlags.RARReadsStatusFlag,
/*[RARJbInstruction]*/ RAROpcodeFlags.RAR1OperandFlag | RAROpcodeFlags.RARIsRelativeJumpFlag | RAROpcodeFlags.RARReadsStatusFlag,
/*[RARJbeInstruction]*/ RAROpcodeFlags.RAR1OperandFlag | RAROpcodeFlags.RARIsRelativeJumpFlag | RAROpcodeFlags.RARReadsStatusFlag,
/*[RARJaInstruction]*/ RAROpcodeFlags.RAR1OperandFlag | RAROpcodeFlags.RARIsRelativeJumpFlag | RAROpcodeFlags.RARReadsStatusFlag,
/*[RARJaeInstruction]*/ RAROpcodeFlags.RAR1OperandFlag | RAROpcodeFlags.RARIsRelativeJumpFlag | RAROpcodeFlags.RARReadsStatusFlag,
/*[RARPushInstruction]*/ RAROpcodeFlags.RAR1OperandFlag,
/*[RARPopInstruction]*/ RAROpcodeFlags.RAR1OperandFlag,
/*[RARCallInstruction]*/ RAROpcodeFlags.RAR1OperandFlag | RAROpcodeFlags.RARIsRelativeJumpFlag,
/*[RARRetInstruction]*/ RAROpcodeFlags.RAR0OperandsFlag | RAROpcodeFlags.RARIsUnconditionalJumpFlag,
/*[RARNotInstruction]*/ RAROpcodeFlags.RAR1OperandFlag | RAROpcodeFlags.RARHasByteModeFlag | RAROpcodeFlags.RARWritesFirstOperandFlag,
/*[RARShlInstruction]*/ RAROpcodeFlags.RAR2OperandsFlag | RAROpcodeFlags.RARHasByteModeFlag | RAROpcodeFlags.RARWritesFirstOperandFlag | RAROpcodeFlags.RARWritesStatusFlag,
/*[RARShrInstruction]*/ RAROpcodeFlags.RAR2OperandsFlag | RAROpcodeFlags.RARHasByteModeFlag | RAROpcodeFlags.RARWritesFirstOperandFlag | RAROpcodeFlags.RARWritesStatusFlag,
/*[RARSarInstruction]*/ RAROpcodeFlags.RAR2OperandsFlag | RAROpcodeFlags.RARHasByteModeFlag | RAROpcodeFlags.RARWritesFirstOperandFlag | RAROpcodeFlags.RARWritesStatusFlag,
/*[RARNegInstruction]*/ RAROpcodeFlags.RAR1OperandFlag | RAROpcodeFlags.RARHasByteModeFlag | RAROpcodeFlags.RARWritesFirstOperandFlag | RAROpcodeFlags.RARWritesStatusFlag,
/*[RARPushaInstruction]*/ RAROpcodeFlags.RAR0OperandsFlag,
/*[RARPopaInstruction]*/ RAROpcodeFlags.RAR0OperandsFlag,
/*[RARPushfInstruction]*/ RAROpcodeFlags.RAR0OperandsFlag | RAROpcodeFlags.RARReadsStatusFlag,
/*[RARPopfInstruction]*/ RAROpcodeFlags.RAR0OperandsFlag | RAROpcodeFlags.RARWritesStatusFlag,
/*[RARMovzxInstruction]*/ RAROpcodeFlags.RAR2OperandsFlag | RAROpcodeFlags.RARWritesFirstOperandFlag,
/*[RARMovsxInstruction]*/ RAROpcodeFlags.RAR2OperandsFlag | RAROpcodeFlags.RARWritesFirstOperandFlag,
/*[RARXchgInstruction]*/ RAROpcodeFlags.RAR2OperandsFlag | RAROpcodeFlags.RARWritesFirstOperandFlag | RAROpcodeFlags.RARWritesSecondOperandFlag | RAROpcodeFlags.RARHasByteModeFlag,
/*[RARMulInstruction]*/ RAROpcodeFlags.RAR2OperandsFlag | RAROpcodeFlags.RARHasByteModeFlag | RAROpcodeFlags.RARWritesFirstOperandFlag,
/*[RARDivInstruction]*/ RAROpcodeFlags.RAR2OperandsFlag | RAROpcodeFlags.RARHasByteModeFlag | RAROpcodeFlags.RARWritesFirstOperandFlag,
/*[RARAdcInstruction]*/ RAROpcodeFlags.RAR2OperandsFlag | RAROpcodeFlags.RARHasByteModeFlag | RAROpcodeFlags.RARWritesFirstOperandFlag | RAROpcodeFlags.RARReadsStatusFlag | RAROpcodeFlags.RARWritesStatusFlag,
/*[RARSbbInstruction]*/ RAROpcodeFlags.RAR2OperandsFlag | RAROpcodeFlags.RARHasByteModeFlag | RAROpcodeFlags.RARWritesFirstOperandFlag | RAROpcodeFlags.RARReadsStatusFlag | RAROpcodeFlags.RARWritesStatusFlag,
/*[RARPrintInstruction]*/ RAROpcodeFlags.RAR0OperandsFlag
};
public bool RARInstructionWritesSecondOperand()
{
return ((RAROpcode.InstructionFlags[(int)Type] & RAROpcodeFlags.RARWritesSecondOperandFlag) == RAROpcodeFlags.RARWritesSecondOperandFlag);
}
}
}

View File

@ -0,0 +1,39 @@
//
// RAROpcodeFlags.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// 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.FileSystem.WinRAR.VM
{
[Flags()]
public enum RAROpcodeFlags
{
RAR0OperandsFlag = 0,
RAR1OperandFlag = 1,
RAR2OperandsFlag = 2,
RAROperandsFlag = 3,
RARHasByteModeFlag = 4,
RARIsUnconditionalJumpFlag = 8,
RARIsRelativeJumpFlag = 16,
RARWritesFirstOperandFlag = 32,
RARWritesSecondOperandFlag = 64,
RARReadsStatusFlag = 128,
RARWritesStatusFlag = 256
}
}

View File

@ -0,0 +1,67 @@
//
// RAROpcodeType.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// 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.FileSystem.WinRAR.VM
{
public enum RAROpcodeType : byte
{
Mov = 0,
Cmp = 1,
Add = 2,
Sub = 3,
Jz = 4,
Jnz = 5,
Inc = 6,
Dec = 7,
Jmp = 8,
Xor = 9,
And = 10,
Or = 11,
Test = 12,
Js = 13,
Jns = 14,
Jb = 15,
Jbe = 16,
Ja = 17,
Jae = 18,
Push = 19,
Pop = 20,
Call = 21,
Ret = 22,
Not = 23,
Shl = 24,
Shr = 25,
Sar = 26,
Neg = 27,
Pusha = 28,
Popa = 29,
Pushf = 30,
Popf = 31,
Movzx = 32,
Movsx = 33,
Xchg = 34,
Mul = 35,
Div = 36,
Adc = 37,
Sbb = 38,
Print = 39
}
}

View File

@ -0,0 +1,614 @@
//
// RARVM.cs - work in progress to implement WinRAR VM from the unarchiver
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// 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 System.Diagnostics.Contracts;
namespace UniversalEditor.DataFormats.FileSystem.WinRAR.VM
{
/// <summary>
/// Work in progress to implement WinRAR VM from the unarchiver.
/// </summary>
public class RARVM
{
private uint[] registers = new uint[8];
public void SetRegisters(uint[] registers)
{
Contract.Requires(registers.Length == 8);
this.registers = registers;
}
static int RARRegisterAddressingMode(int n)
{
return (0 + (n));
}
static int RARRegisterIndirectAddressingMode(int n)
{
return (8 + (n));
}
static int RARIndexedAbsoluteAddressingMode(int n)
{
return (16 + (n));
}
const int RARAbsoluteAddressingMode = 24;
const int RARImmediateAddressingMode = 25;
const int RARNumberOfAddressingModes = 26;
static RARGetterFunction[] OperandGetters_32 = new RARGetterFunction[RARNumberOfAddressingModes];
static RARGetterFunction[] OperandGetters_8 = new RARGetterFunction[RARNumberOfAddressingModes];
static RARSetterFunction[] OperandSetters_32 = new RARSetterFunction[RARNumberOfAddressingModes];
static RARSetterFunction[] OperandSetters_8 = new RARSetterFunction[RARNumberOfAddressingModes];
static readonly byte RARNumberOfInstructions = (byte)Enum.GetValues(typeof(RAROpcodeType)).Length;
int NumberOfRARInstructionOperands(RAROpcodeType instruction)
{
if ((int)instruction >= RARNumberOfInstructions) return 0;
return (int)(RAROpcode.InstructionFlags[(int)instruction] & RAROpcodeFlags.RAROperandsFlag);
}
bool RARInstructionHasByteMode(RAROpcodeType instruction)
{
if ((int)instruction >= RARNumberOfInstructions) return false;
return (RAROpcode.InstructionFlags[(int)instruction] & RAROpcodeFlags.RARHasByteModeFlag) != 0;
}
bool RARInstructionWritesFirstOperand(RAROpcodeType instruction)
{
if ((int)instruction >= RARNumberOfInstructions) return false;
return (RAROpcode.InstructionFlags[(int)instruction] & RAROpcodeFlags.RARWritesFirstOperandFlag) != 0;
}
public uint GetOperand1()
{
return _opcodes[_ip].operand1getter(this, _opcodes[_ip].value1);
}
public uint GetOperand2()
{
return _opcodes[_ip].operand2getter(this, _opcodes[_ip].value2);
}
public void SetOperand1(uint data)
{
_opcodes[_ip].operand1setter(this, _opcodes[_ip].value1, data);
}
public void SetOperand2(uint data)
{
_opcodes[_ip].operand2setter(this, _opcodes[_ip].value2, data);
}
private bool Init(RAROpcode[] opcodes)
{
for (int i = 0; i < opcodes.Length; i++)
{
if ((byte)opcodes[i].Type >= RARNumberOfInstructions) return false;
RARInstructionLabel[] instructionlabels;
RARInstructionLabel[] instructionlabels_32;
RARInstructionLabel[] instructionlabels_8;
RARSetterFunction[] setterfunctions;
RARGetterFunction[] getterfunctions;
if (opcodes[i].Type == RAROpcodeType.Movsx || opcodes[i].Type == RAROpcodeType.Movzx)
{
// instructionlabels = instructionlabels_32;
getterfunctions = OperandGetters_8;
setterfunctions = OperandSetters_32;
}
else if (opcodes[i].bytemode)
{
if (!RARInstructionHasByteMode(opcodes[i].Type)) return false;
// instructionlabels = instructionlabels_8;
getterfunctions = OperandGetters_8;
setterfunctions = OperandSetters_8;
}
else
{
// instructionlabels = instructionlabels_32;
getterfunctions = OperandGetters_32;
setterfunctions = OperandSetters_32;
}
// opcodes[i].instructionlabel = instructionlabels[opcodes[i].Type];
int numoperands = NumberOfRARInstructionOperands(opcodes[i].Type);
if (numoperands >= 1)
{
if (opcodes[i].addressingmode1 >= RARNumberOfAddressingModes) return false;
opcodes[i].operand1getter = getterfunctions[opcodes[i].addressingmode1];
opcodes[i].operand1setter = setterfunctions[opcodes[i].addressingmode1];
if (opcodes[i].addressingmode1 == RARImmediateAddressingMode)
{
if (RARInstructionWritesFirstOperand(opcodes[i].Type)) return false;
}
else if (opcodes[i].addressingmode1 == RARAbsoluteAddressingMode)
{
opcodes[i].value1 &= RARProgramMemoryMask;
}
}
if (numoperands == 2)
{
if (opcodes[i].addressingmode2 >= RARNumberOfAddressingModes) return false;
opcodes[i].operand2getter = getterfunctions[opcodes[i].addressingmode2];
opcodes[i].operand2setter = setterfunctions[opcodes[i].addressingmode2];
if (opcodes[i].addressingmode2 == RARImmediateAddressingMode)
{
if (opcodes[i].RARInstructionWritesSecondOperand()) return false;
}
else if (opcodes[i].addressingmode2 == RARAbsoluteAddressingMode)
{
opcodes[i].value2 &= RARProgramMemoryMask;
}
}
}
return true;
}
private RARVMFlags flags = RARVMFlags.None;
public void SetFlagsWithCarry(uint res, uint carry)
{
uint result = res;
flags = (RARVMFlags)((result == 0 ? (uint)RARVMFlags.ZeroFlag : (result & (uint)RARVMFlags.SignFlag)) | carry);
}
private RAROpcode[] _opcodes = new RAROpcode[0];
private int _ip = 0;
public void Run(RAROpcode[] opcodes)
{
_opcodes = opcodes;
_ip = -1;
NextInstruction();
}
public void NextInstruction()
{
_ip++;
// Debug();
Execute(_opcodes[_ip]); // goto *opcode->instructionlabel;
}
private uint _RARRead32(byte[] b, uint ofs)
{
return ((uint)b[ofs + 3] << 24) | ((uint)b[ofs + 2] << 16) | ((uint)b[ofs + 1] << 8) | (uint)b[ofs + 0];
}
private void _RARWrite32(byte[] b, uint ofs, uint n)
{
b[ofs + 3] = (byte)((n >> 24) & 0xff);
b[ofs + 2] = (byte)((n >> 16) & 0xff);
b[ofs + 1] = (byte)((n >> 8) & 0xff);
b[ofs + 0] = (byte)(n & 0xff);
}
private const int RARProgramMemorySize = 0x40000;
private const int RARProgramMemoryMask = (RARProgramMemorySize - 1);
private byte[] memory = new byte[0];
private uint RARVirtualMachineRead32(uint address)
{
return _RARRead32(memory, address & RARProgramMemoryMask);
}
private void RARVirtualMachineWrite32(uint address, uint val)
{
_RARWrite32(memory, address & RARProgramMemoryMask, val);
}
private uint SignExtend(uint a)
{
return ((uint)((byte)(a)));
}
private void SetByteFlagsWithCarry(uint res, uint carry)
{
uint result = (res);
flags = (RARVMFlags)((result == 0 ? (uint)RARVMFlags.ZeroFlag : (SignExtend(result) & (uint)RARVMFlags.SignFlag)) | (carry));
}
private void SetFlags(uint res)
{
SetFlagsWithCarry(res, 0);
}
private void SetOperand1AndFlagsWithCarry(uint res, uint carry)
{
uint r = (res);
SetFlagsWithCarry(r, carry);
SetOperand1(r);
}
private void SetOperand1AndByteFlagsWithCarry(uint res, uint carry)
{
uint r = (res);
SetByteFlagsWithCarry(r, carry);
SetOperand1(r);
}
private void SetOperand1AndFlags(uint res)
{
uint r = (res);
SetFlags(r);
SetOperand1(r);
}
public bool Jump(uint ofs)
{
uint o = ofs;
if (o >= _opcodes.Length) return false;
_ip = (int)o;
// Debug();
Execute(_opcodes[_ip]);
return true;
}
public void Execute(RAROpcode opcode)
{
/*
RAROpcode* opcode;
uint flags = self->flags;
Jump(0);
*/
switch (opcode.Type)
{
case RAROpcodeType.Mov:
{
SetOperand1(GetOperand2());
NextInstruction();
break;
}
case RAROpcodeType.Cmp:
{
uint term1 = GetOperand1();
uint result = term1 - GetOperand2();
SetFlagsWithCarry(result, (uint)(result > term1 ? 1 : 0));
NextInstruction();
break;
}
case RAROpcodeType.Add:
{
uint term1 = GetOperand1();
uint result = term1 + GetOperand2();
SetOperand1AndFlagsWithCarry(result, (uint)(result < term1 ? 1 : 0));
NextInstruction();
break;
}
/*
case RAROpcodeType.AddByte:
{
uint term1 = GetOperand1();
SetOperand1AndByteFlagsWithCarry(term1 + GetOperand2() & 0xff, result < term1);
NextInstruction();
break;
}
*/
case RAROpcodeType.Sub:
{
uint term1 = GetOperand1();
uint result = term1 - GetOperand2();
SetOperand1AndFlagsWithCarry(result, (uint)(result > term1 ? 1 : 0));
NextInstruction();
break;
}
/*
case RAROpcodeType.SubByte: // Not correctly implemented in the RAR VM
{
uint term1 = GetOperand1();
SetOperandAndByteFlagsWithCarry(term1-GetOperand2() & 0xFF, result > term1);
NextInstruction();
break;
}
*/
case RAROpcodeType.Jz:
{
if ((flags & RARVMFlags.ZeroFlag) == RARVMFlags.ZeroFlag) Jump(GetOperand1());
else NextInstruction();
break;
}
case RAROpcodeType.Jnz:
{
if ((flags & RARVMFlags.ZeroFlag) != RARVMFlags.ZeroFlag) Jump(GetOperand1());
else NextInstruction();
break;
}
case RAROpcodeType.Inc:
{
SetOperand1AndFlags(GetOperand1() + 1);
NextInstruction();
break;
}
/*
case RAROpcodeType.IncByte:
{
SetOperand1AndFlags(GetOperand1() + 1 & 0xff);
NextInstruction();
break;
}
*/
case RAROpcodeType.Dec:
{
SetOperand1AndFlags(GetOperand1() - 1);
NextInstruction();
break;
}
/*
case RAROpcodeType.DecByte:
{
SetOperand1AndFlags(GetOperand1() - 1 & 0xff);
NextInstruction();
break;
}
*/
case RAROpcodeType.Jmp:
{
Jump(GetOperand1());
break;
}
case RAROpcodeType.Xor:
{
SetOperand1AndFlags(GetOperand1() ^ GetOperand2());
NextInstruction();
break;
}
case RAROpcodeType.And:
{
SetOperand1AndFlags(GetOperand1() & GetOperand2());
NextInstruction();
break;
}
case RAROpcodeType.Or:
{
SetOperand1AndFlags(GetOperand1() | GetOperand2());
NextInstruction();
break;
}
case RAROpcodeType.Test:
{
SetFlags(GetOperand1() & GetOperand2());
NextInstruction();
break;
}
case RAROpcodeType.Js:
{
if ((flags & RARVMFlags.SignFlag) == RARVMFlags.SignFlag) Jump(GetOperand1());
else NextInstruction();
break;
}
case RAROpcodeType.Jns:
{
if ((flags & RARVMFlags.SignFlag) != RARVMFlags.SignFlag) Jump(GetOperand1());
else NextInstruction();
break;
}
case RAROpcodeType.Jb:
{
if ((flags & RARVMFlags.CarryFlag) == RARVMFlags.CarryFlag) Jump(GetOperand1());
else NextInstruction();
break;
}
case RAROpcodeType.Jbe:
{
if ((flags & (RARVMFlags.CarryFlag | RARVMFlags.ZeroFlag)) == (RARVMFlags.CarryFlag | RARVMFlags.ZeroFlag)) Jump(GetOperand1());
else NextInstruction();
break;
}
case RAROpcodeType.Ja:
{
if (!((flags & (RARVMFlags.CarryFlag | RARVMFlags.ZeroFlag)) == (RARVMFlags.CarryFlag | RARVMFlags.ZeroFlag))) Jump(GetOperand1());
else NextInstruction();
break;
}
case RAROpcodeType.Jae:
{
if ((flags & RARVMFlags.CarryFlag) != RARVMFlags.CarryFlag) Jump(GetOperand1());
else NextInstruction();
break;
}
case RAROpcodeType.Push:
{
registers[7] -= 4;
RARVirtualMachineWrite32(registers[7], GetOperand1());
NextInstruction();
break;
}
case RAROpcodeType.Pop:
{
SetOperand1(RARVirtualMachineRead32(registers[7]));
registers[7] += 4;
NextInstruction();
break;
}
case RAROpcodeType.Call:
{
registers[7] -= 4;
throw new NotImplementedException();
// RARVirtualMachineWrite32(registers[7], opcode - opcodes + 1);
Jump(GetOperand1());
break;
}
case RAROpcodeType.Ret:
{
if (registers[7] >= RARProgramMemorySize)
{
// this.flags = flags;
// return true;
return;
}
uint retaddr = RARVirtualMachineRead32(registers[7]);
registers[7] += 4;
Jump(retaddr);
break;
}
case RAROpcodeType.Not:
{
SetOperand1(~GetOperand1());
NextInstruction();
break;
}
case RAROpcodeType.Shl:
{
uint op1 = GetOperand1();
uint op2 = GetOperand2();
SetOperand1AndFlagsWithCarry(op1 << (ushort)op2, (uint)(((op1 << (ushort)(op2 - 1)) & 0x80000000) != 0 ? 1 : 0));
NextInstruction();
break;
}
case RAROpcodeType.Shr:
{
uint op1 = GetOperand1();
uint op2 = GetOperand2();
SetOperand1AndFlagsWithCarry(op1 >> (ushort)op2, (uint)(((op1 >> (ushort)(op2 - 1)) & 1) != 0 ? 1 : 0));
NextInstruction();
break;
}
case RAROpcodeType.Sar:
{
uint op1 = GetOperand1();
uint op2 = GetOperand2();
SetOperand1AndFlagsWithCarry(op1 >> (ushort)op2, (uint)((((op1 >> (ushort)(op2 - 1)) & 1) != 0) ? 1 : 0));
NextInstruction();
break;
}
case RAROpcodeType.Neg:
{
long result = -GetOperand1();
SetOperand1AndFlagsWithCarry((uint)result, (uint)(result != 0 ? 1 : 0));
NextInstruction();
break;
}
case RAROpcodeType.Pusha:
{
for (int i = 0; i < 8; i++) RARVirtualMachineWrite32((uint)(registers[7] - 4 - i * 4), registers[i]);
registers[7] -= 32;
NextInstruction();
break;
}
case RAROpcodeType.Popa:
{
for (int i = 0; i < 8; i++)
{
registers[i] = RARVirtualMachineRead32((uint)(registers[7] + 28 - i * 4));
}
NextInstruction();
break;
}
case RAROpcodeType.Pushf:
{
registers[7] -= 4;
RARVirtualMachineWrite32(registers[7], (uint)flags);
NextInstruction();
break;
}
case RAROpcodeType.Popf:
{
flags = (RARVMFlags)RARVirtualMachineRead32((uint)(registers[7]));
registers[7] += 4;
NextInstruction();
break;
}
case RAROpcodeType.Movzx:
{
SetOperand1(GetOperand2());
NextInstruction();
break;
}
case RAROpcodeType.Movsx:
{
SetOperand1(SignExtend(GetOperand2()));
NextInstruction();
break;
}
case RAROpcodeType.Xchg:
{
uint op1 = GetOperand1();
uint op2 = GetOperand2();
SetOperand1(op2);
SetOperand2(op1);
NextInstruction();
break;
}
case RAROpcodeType.Mul:
{
SetOperand1(GetOperand1() * GetOperand2());
NextInstruction();
break;
}
case RAROpcodeType.Div:
{
uint denominator = GetOperand2();
if (denominator != 0) SetOperand1(GetOperand1() / denominator);
NextInstruction();
break;
}
case RAROpcodeType.Adc:
{
uint term1 = GetOperand1();
uint carry = (uint)(flags & RARVMFlags.CarryFlag);
uint result = term1 + GetOperand2() + carry;
SetOperand1AndFlagsWithCarry(result, (uint)((result < term1 || (result == term1 && (carry != 0))) ? 1 : 0));
NextInstruction();
break;
}
/*
case RAROpcodeType.AdcByte:
{
uint term1 = GetOperand1();
uint carry = (uint)(flags & RARVMFlags.CarryFlag);
SetOperand1AndFlagsWithCarry(term1 + GetOperand2() + carry & 0xff, result < term1 || result == term1 && carry); // Does not correctly set sign bit.
NextInstruction();
break;
}
*/
case RAROpcodeType.Sbb:
{
uint term1 = GetOperand1();
uint carry = (uint)(flags & RARVMFlags.CarryFlag);
uint result = (term1 - GetOperand2() - carry);
SetOperand1AndFlagsWithCarry(result, (uint)((result > term1 || (result == term1 && (carry != 0))) ? 1 : 0));
NextInstruction();
break;
}
/*
case RAROpcodeType.SbbByte:
{
uint term1 = GetOperand1();
uint carry = (uint)(flags & RARVMFlags.CarryFlag);
uint result = (term1 - GetOperand2() - carry & 0xff);
SetOperand1AndFlagsWithCarry(result, (uint)(result > term1 || (result == term1 && (carry != 0)) ? 1 : 0)); // Does not correctly set sign bit.
NextInstruction();
break;
}
*/
case RAROpcodeType.Print:
{
NextInstruction();
break;
}
}
}
}
}

View File

@ -0,0 +1,32 @@
//
// RARVMFlags.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// 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.FileSystem.WinRAR.VM
{
[Flags()]
public enum RARVMFlags : uint
{
None = 0x00000000,
CarryFlag = 0x00000001,
ZeroFlag = 0x00000002,
SignFlag = 0x80000000
}
}

View File

@ -0,0 +1,27 @@
//
// RARVMFunctions.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// 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.FileSystem.WinRAR.VM
{
public delegate void RARInstructionLabel();
public delegate uint RARGetterFunction(RARVM vm, uint value);
public delegate void RARSetterFunction(RARVM vm, uint value, uint data);
}

View File

@ -199,8 +199,6 @@
<Compile Include="DataFormats\FileSystem\WinRAR\RARCompressionMethod.cs" />
<Compile Include="DataFormats\FileSystem\WinRAR\RARDataFormat.cs" />
<Compile Include="DataFormats\FileSystem\WinRAR\RARFileHeaderFlags.cs" />
<Compile Include="DataFormats\FileSystem\WinRAR\RARHeaderFlags.cs" />
<Compile Include="DataFormats\FileSystem\WinRAR\RARHeaderType.cs" />
<Compile Include="DataFormats\FileSystem\WinRAR\RARHostOperatingSystem.cs" />
<Compile Include="DataFormats\FileSystem\YZ1\YZ1DataFormat.cs" />
<Compile Include="DataFormats\FileSystem\ZipTV\BlakHole\BHCompressionMethod.cs" />
@ -240,6 +238,28 @@
<Compile Include="DataFormats\FileSystem\TexasInstruments\DSK\DSKDataFormat.cs" />
<Compile Include="DataFormats\FileSystem\TexasInstruments\DSK\DSKFileStatusFlags.cs" />
<Compile Include="DataFormats\FileSystem\KenSilverman\KenSilvermanGRPDataFormat.cs" />
<Compile Include="DataFormats\FileSystem\WinRAR\RARFormatVersion.cs" />
<Compile Include="DataFormats\FileSystem\WinRAR\V5\RARBlockTypeV5.cs" />
<Compile Include="DataFormats\FileSystem\WinRAR\V5\RAREndBlockFlags.cs" />
<Compile Include="DataFormats\FileSystem\WinRAR\V5\RARArchiveBlockFlagsV5.cs" />
<Compile Include="DataFormats\FileSystem\WinRAR\V5\RARFileAttributes.cs" />
<Compile Include="DataFormats\FileSystem\WinRAR\V5\RARFileBlockFlags.cs" />
<Compile Include="DataFormats\FileSystem\WinRAR\RARBlockType.cs" />
<Compile Include="DataFormats\FileSystem\WinRAR\V4\RARArchiveBlockFlagsV4.cs" />
<Compile Include="DataFormats\FileSystem\WinRAR\V4\RARBlockTypeV4.cs" />
<Compile Include="DataFormats\FileSystem\WinRAR\RARBlockObjectModel.cs" />
<Compile Include="DataFormats\FileSystem\WinRAR\RARBlock.cs" />
<Compile Include="DataFormats\FileSystem\WinRAR\Blocks\RARArchiveBlock.cs" />
<Compile Include="DataFormats\FileSystem\WinRAR\Blocks\RAREndBlock.cs" />
<Compile Include="DataFormats\FileSystem\WinRAR\Blocks\RARFileBlock.cs" />
<Compile Include="DataFormats\FileSystem\WinRAR\RARBlockDataFormat.cs" />
<Compile Include="DataFormats\FileSystem\WinRAR\RARBlockFlags.cs" />
<Compile Include="DataFormats\FileSystem\WinRAR\VM\RARVM.cs" />
<Compile Include="DataFormats\FileSystem\WinRAR\VM\RAROpcodeType.cs" />
<Compile Include="DataFormats\FileSystem\WinRAR\VM\RAROpcode.cs" />
<Compile Include="DataFormats\FileSystem\WinRAR\VM\RARVMFlags.cs" />
<Compile Include="DataFormats\FileSystem\WinRAR\VM\RAROpcodeFlags.cs" />
<Compile Include="DataFormats\FileSystem\WinRAR\VM\RARVMFunctions.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Libraries\UniversalEditor.Core\UniversalEditor.Core.csproj">
@ -282,6 +302,10 @@
<Folder Include="DataFormats\FileSystem\TexasInstruments\TIFiles\" />
<Folder Include="DataFormats\FileSystem\TexasInstruments\DSK\" />
<Folder Include="DataFormats\FileSystem\KenSilverman\" />
<Folder Include="DataFormats\FileSystem\WinRAR\V5\" />
<Folder Include="DataFormats\FileSystem\WinRAR\V4\" />
<Folder Include="DataFormats\FileSystem\WinRAR\Blocks\" />
<Folder Include="DataFormats\FileSystem\WinRAR\VM\" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.