Files
2013-04-28 13:01:29 +01:00

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; }
}
}