mirror of
https://github.com/adamhathcock/sharpcompress.git
synced 2026-09-24 16:05:27 +00:00
229 lines
7.8 KiB
C#
229 lines
7.8 KiB
C#
using System;
|
|
using System.IO;
|
|
using System.Text;
|
|
using SharpCompress.IO;
|
|
|
|
namespace SharpCompress.Common.Rar.Headers
|
|
{
|
|
internal class FileHeader : RarHeader
|
|
{
|
|
private const byte SALT_SIZE = 8;
|
|
|
|
private const byte NEWLHD_SIZE = 32;
|
|
|
|
protected override void ReadFromReader(MarkingBinaryReader reader)
|
|
{
|
|
uint lowUncompressedSize = reader.ReadUInt32();
|
|
|
|
HostOS = (HostOS) (int) reader.ReadByte();
|
|
|
|
FileCRC = reader.ReadUInt32();
|
|
|
|
FileLastModifiedTime = Utility.DosDateToDateTime(reader.ReadInt32());
|
|
|
|
RarVersion = reader.ReadByte();
|
|
PackingMethod = reader.ReadByte();
|
|
|
|
short nameSize = reader.ReadInt16();
|
|
|
|
FileAttributes = reader.ReadInt32();
|
|
|
|
uint highCompressedSize = 0;
|
|
uint highUncompressedkSize = 0;
|
|
if (FileFlags.HasFlag(FileFlags.LARGE))
|
|
{
|
|
highCompressedSize = reader.ReadUInt32();
|
|
highUncompressedkSize = reader.ReadUInt32();
|
|
}
|
|
else
|
|
{
|
|
if (lowUncompressedSize == 0xffffffff)
|
|
{
|
|
lowUncompressedSize = 0xffffffff;
|
|
highUncompressedkSize = int.MaxValue;
|
|
}
|
|
}
|
|
CompressedSize = UInt32To64(highCompressedSize, AdditionalSize);
|
|
UncompressedSize = UInt32To64(highUncompressedkSize, lowUncompressedSize);
|
|
|
|
nameSize = nameSize > 4*1024 ? (short) (4*1024) : nameSize;
|
|
|
|
byte[] fileNameBytes = reader.ReadBytes(nameSize);
|
|
|
|
switch (HeaderType)
|
|
{
|
|
case HeaderType.FileHeader:
|
|
{
|
|
if (FileFlags.HasFlag(FileFlags.UNICODE))
|
|
{
|
|
int length = 0;
|
|
while (length < fileNameBytes.Length
|
|
&& fileNameBytes[length] != 0)
|
|
{
|
|
length++;
|
|
}
|
|
if (length != nameSize)
|
|
{
|
|
length++;
|
|
FileName = FileNameDecoder.Decode(fileNameBytes, length);
|
|
}
|
|
else
|
|
{
|
|
FileName = DecodeDefault(fileNameBytes);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FileName = DecodeDefault(fileNameBytes);
|
|
}
|
|
FileName = ConvertPath(FileName, HostOS);
|
|
}
|
|
break;
|
|
case HeaderType.NewSubHeader:
|
|
{
|
|
int datasize = HeaderSize - NEWLHD_SIZE - nameSize;
|
|
if (FileFlags.HasFlag(FileFlags.SALT))
|
|
{
|
|
datasize -= SALT_SIZE;
|
|
}
|
|
if (datasize > 0)
|
|
{
|
|
SubData = reader.ReadBytes(datasize);
|
|
}
|
|
|
|
if (NewSubHeaderType.SUBHEAD_TYPE_RR.Equals(fileNameBytes))
|
|
{
|
|
RecoverySectors = SubData[8] + (SubData[9] << 8)
|
|
+ (SubData[10] << 16) + (SubData[11] << 24);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (FileFlags.HasFlag(FileFlags.SALT))
|
|
{
|
|
Salt = reader.ReadBytes(SALT_SIZE);
|
|
}
|
|
if (FileFlags.HasFlag(FileFlags.EXTTIME))
|
|
{
|
|
ushort extendedFlags = reader.ReadUInt16();
|
|
FileLastModifiedTime = ProcessExtendedTime(extendedFlags, FileLastModifiedTime, reader, 0);
|
|
FileCreatedTime = ProcessExtendedTime(extendedFlags, null, reader, 1);
|
|
FileLastAccessedTime = ProcessExtendedTime(extendedFlags, null, reader, 2);
|
|
FileArchivedTime = ProcessExtendedTime(extendedFlags, null, reader, 3);
|
|
}
|
|
}
|
|
|
|
//only the full .net framework will do other code pages than unicode/utf8
|
|
private string DecodeDefault(byte[] bytes)
|
|
{
|
|
return ArchiveEncoding.Default.GetString(bytes, 0, bytes.Length);
|
|
}
|
|
|
|
private long UInt32To64(uint x, uint y)
|
|
{
|
|
long l = x;
|
|
l <<= 32;
|
|
return l + y;
|
|
}
|
|
|
|
private static DateTime? ProcessExtendedTime(ushort extendedFlags, DateTime? time, MarkingBinaryReader reader,
|
|
int i)
|
|
{
|
|
uint rmode = (uint) extendedFlags >> (3 - i)*4;
|
|
if ((rmode & 8) == 0)
|
|
{
|
|
return null;
|
|
}
|
|
if (i != 0)
|
|
{
|
|
uint DosTime = reader.ReadUInt32();
|
|
time = Utility.DosDateToDateTime(DosTime);
|
|
}
|
|
if ((rmode & 4) == 0)
|
|
{
|
|
time = time.Value.AddSeconds(1);
|
|
}
|
|
uint nanosecondHundreds = 0;
|
|
int count = (int) rmode & 3;
|
|
for (int j = 0; j < count; j++)
|
|
{
|
|
byte b = reader.ReadByte();
|
|
nanosecondHundreds |= (((uint) b) << ((j + 3 - count)*8));
|
|
}
|
|
//10^-7 to 10^-3
|
|
return time.Value.AddMilliseconds(nanosecondHundreds*Math.Pow(10, -4));
|
|
}
|
|
|
|
private static string ConvertPath(string path, HostOS os)
|
|
{
|
|
#if PORTABLE || NETFX_CORE
|
|
return path.Replace('\\', '/');
|
|
#else
|
|
switch (os)
|
|
{
|
|
case HostOS.MacOS:
|
|
case HostOS.Unix:
|
|
{
|
|
if (Path.DirectorySeparatorChar == '\\')
|
|
{
|
|
return path.Replace('/', '\\');
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
if (Path.DirectorySeparatorChar == '/')
|
|
{
|
|
return path.Replace('\\', '/');
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
return path;
|
|
#endif
|
|
}
|
|
|
|
internal long DataStartPosition { get; set; }
|
|
internal HostOS HostOS { get; private set; }
|
|
|
|
internal uint FileCRC { get; private set; }
|
|
|
|
internal DateTime? FileLastModifiedTime { get; private set; }
|
|
|
|
internal DateTime? FileCreatedTime { get; private set; }
|
|
|
|
internal DateTime? FileLastAccessedTime { get; private set; }
|
|
|
|
internal DateTime? FileArchivedTime { get; private set; }
|
|
|
|
internal byte RarVersion { get; private set; }
|
|
|
|
internal byte PackingMethod { get; private set; }
|
|
|
|
internal int FileAttributes { get; private set; }
|
|
|
|
internal FileFlags FileFlags
|
|
{
|
|
get { return (FileFlags) base.Flags; }
|
|
}
|
|
|
|
internal long CompressedSize { get; private set; }
|
|
internal long UncompressedSize { get; private set; }
|
|
|
|
internal string FileName { get; private set; }
|
|
|
|
internal byte[] SubData { get; private set; }
|
|
|
|
internal int RecoverySectors { get; private set; }
|
|
|
|
internal byte[] Salt { get; private set; }
|
|
|
|
public override string ToString()
|
|
{
|
|
return FileName;
|
|
}
|
|
|
|
public Stream PackedStream { get; set; }
|
|
}
|
|
} |