various enhancements and improvements to WinRAR DataFormat
This commit is contained in:
parent
0a47423f29
commit
420742e74b
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
@ -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>
|
||||
@ -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,
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
@ -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.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user