// // Copyright (c) 2008-2011, Kenneth Bell // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal in the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. // using System; using System.IO; using System.Text; using DiscUtils.Streams; namespace DiscUtils.Fat { internal class DirectoryEntry { private readonly FatType _fatVariant; private readonly FatFileSystemOptions _options; private byte _attr; private ushort _creationDate; private ushort _creationTime; private byte _creationTimeTenth; private uint _fileSize; private ushort _firstClusterHi; private ushort _firstClusterLo; private ushort _lastAccessDate; private ushort _lastWriteDate; private ushort _lastWriteTime; internal DirectoryEntry(FatFileSystemOptions options, Stream stream, FatType fatVariant) { _options = options; _fatVariant = fatVariant; byte[] buffer = StreamUtilities.ReadExact(stream, 32); Load(buffer, 0, options.FileNameEncoding); } internal DirectoryEntry(FatFileSystemOptions options, FileName name, FatAttributes attrs, FatType fatVariant) { _options = options; _fatVariant = fatVariant; Name = name; _attr = (byte)attrs; } internal DirectoryEntry(DirectoryEntry toCopy) { _options = toCopy._options; _fatVariant = toCopy._fatVariant; Name = toCopy.Name; _attr = toCopy._attr; _creationTimeTenth = toCopy._creationTimeTenth; _creationTime = toCopy._creationTime; _creationDate = toCopy._creationDate; _lastAccessDate = toCopy._lastAccessDate; _firstClusterHi = toCopy._firstClusterHi; _lastWriteTime = toCopy._lastWriteTime; _firstClusterLo = toCopy._firstClusterLo; _fileSize = toCopy._fileSize; } public FatAttributes Attributes { get { return (FatAttributes)_attr; } set { _attr = (byte)value; } } public DateTime CreationTime { get { return FileTimeToDateTime(_creationDate, _creationTime, _creationTimeTenth); } set { DateTimeToFileTime(value, out _creationDate, out _creationTime, out _creationTimeTenth); } } public int FileSize { get { return (int)_fileSize; } set { _fileSize = (uint)value; } } public uint FirstCluster { get { if (_fatVariant == FatType.Fat32) { return (uint)(_firstClusterHi << 16) | _firstClusterLo; } return _firstClusterLo; } set { if (_fatVariant == FatType.Fat32) { _firstClusterHi = (ushort)((value >> 16) & 0xFFFF); } _firstClusterLo = (ushort)(value & 0xFFFF); } } public DateTime LastAccessTime { get { return FileTimeToDateTime(_lastAccessDate, 0, 0); } set { DateTimeToFileTime(value, out _lastAccessDate); } } public DateTime LastWriteTime { get { return FileTimeToDateTime(_lastWriteDate, _lastWriteTime, 0); } set { DateTimeToFileTime(value, out _lastWriteDate, out _lastWriteTime); } } public FileName Name { get; set; } internal void WriteTo(Stream stream) { byte[] buffer = new byte[32]; Name.GetBytes(buffer, 0); buffer[11] = _attr; buffer[13] = _creationTimeTenth; EndianUtilities.WriteBytesLittleEndian(_creationTime, buffer, 14); EndianUtilities.WriteBytesLittleEndian(_creationDate, buffer, 16); EndianUtilities.WriteBytesLittleEndian(_lastAccessDate, buffer, 18); EndianUtilities.WriteBytesLittleEndian(_firstClusterHi, buffer, 20); EndianUtilities.WriteBytesLittleEndian(_lastWriteTime, buffer, 22); EndianUtilities.WriteBytesLittleEndian(_lastWriteDate, buffer, 24); EndianUtilities.WriteBytesLittleEndian(_firstClusterLo, buffer, 26); EndianUtilities.WriteBytesLittleEndian(_fileSize, buffer, 28); stream.Write(buffer, 0, buffer.Length); } private static DateTime FileTimeToDateTime(ushort date, ushort time, byte tenths) { if (date == 0 || date == 0xFFFF) { // Return Epoch - this is an invalid date return FatFileSystem.Epoch; } int year = 1980 + ((date & 0xFE00) >> 9); int month = (date & 0x01E0) >> 5; int day = date & 0x001F; int hour = (time & 0xF800) >> 11; int minute = (time & 0x07E0) >> 5; int second = (time & 0x001F) * 2 + tenths / 100; int millis = tenths % 100 * 10; return new DateTime(year, month, day, hour, minute, second, millis); } private static void DateTimeToFileTime(DateTime value, out ushort date) { byte tenths; ushort time; DateTimeToFileTime(value, out date, out time, out tenths); } private static void DateTimeToFileTime(DateTime value, out ushort date, out ushort time) { byte tenths; DateTimeToFileTime(value, out date, out time, out tenths); } private static void DateTimeToFileTime(DateTime value, out ushort date, out ushort time, out byte tenths) { if (value.Year < 1980) { value = FatFileSystem.Epoch; } date = (ushort)((((value.Year - 1980) << 9) & 0xFE00) | ((value.Month << 5) & 0x01E0) | (value.Day & 0x001F)); time = (ushort)(((value.Hour << 11) & 0xF800) | ((value.Minute << 5) & 0x07E0) | ((value.Second / 2) & 0x001F)); tenths = (byte)(value.Second % 2 * 100 + value.Millisecond / 10); } private void Load(byte[] data, int offset, Encoding encoding) { Name = new FileName(data, offset, encoding); _attr = data[offset + 11]; _creationTimeTenth = data[offset + 13]; _creationTime = EndianUtilities.ToUInt16LittleEndian(data, offset + 14); _creationDate = EndianUtilities.ToUInt16LittleEndian(data, offset + 16); _lastAccessDate = EndianUtilities.ToUInt16LittleEndian(data, offset + 18); _firstClusterHi = EndianUtilities.ToUInt16LittleEndian(data, offset + 20); _lastWriteTime = EndianUtilities.ToUInt16LittleEndian(data, offset + 22); _lastWriteDate = EndianUtilities.ToUInt16LittleEndian(data, offset + 24); _firstClusterLo = EndianUtilities.ToUInt16LittleEndian(data, offset + 26); _fileSize = EndianUtilities.ToUInt32LittleEndian(data, offset + 28); } } }