diff --git a/DiscImageChef.Filters/DiscImageChef.Filters.csproj b/DiscImageChef.Filters/DiscImageChef.Filters.csproj index 41c49355..e6e90123 100644 --- a/DiscImageChef.Filters/DiscImageChef.Filters.csproj +++ b/DiscImageChef.Filters/DiscImageChef.Filters.csproj @@ -46,6 +46,7 @@ + diff --git a/DiscImageChef.Filters/Filters.cs b/DiscImageChef.Filters/Filters.cs index 24a9c00c..fec045e6 100644 --- a/DiscImageChef.Filters/Filters.cs +++ b/DiscImageChef.Filters/Filters.cs @@ -67,19 +67,27 @@ namespace DiscImageChef.Filters public Filter GetFilter(string path) { + Filter noFilter = null; + foreach(Filter filter in filtersList.Values) { - if(filter.Identify(path)) + if(filter.UUID != new Guid("12345678-AAAA-BBBB-CCCC-123456789000")) { - Filter foundFilter = (Filter)filter.GetType().GetConstructor(Type.EmptyTypes).Invoke(new object[] { }); - foundFilter.Open(path); + System.Console.WriteLine("Trying filter {0}", filter.Name); + if(filter.Identify(path)) + { + Filter foundFilter = (Filter)filter.GetType().GetConstructor(Type.EmptyTypes).Invoke(new object[] { }); + foundFilter.Open(path); - if(foundFilter.IsOpened()) - return foundFilter; + if(foundFilter.IsOpened()) + return foundFilter; + } } + else + noFilter = filter; } - return null; + return noFilter; } public SortedDictionary GetFiltersList() diff --git a/DiscImageChef.Filters/PCExchange.cs b/DiscImageChef.Filters/PCExchange.cs new file mode 100644 index 00000000..36e2b71b --- /dev/null +++ b/DiscImageChef.Filters/PCExchange.cs @@ -0,0 +1,327 @@ +// /*************************************************************************** +// The Disc Image Chef +// ---------------------------------------------------------------------------- +// +// Filename : PCExchange.cs +// Author(s) : Natalia Portillo +// +// Component : Component +// +// --[ Description ] ---------------------------------------------------------- +// +// Provides a filter to open handle files written by PCExchange in FAT +// volumes +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2016 Natalia Portillo +// ****************************************************************************/ +using System; +using System.Globalization; +using System.IO; +using System.Runtime.InteropServices; +using System.Text; + +namespace DiscImageChef.Filters +{ + public class PCExchange : Filter + { + const string FileId = "FILEID.DAT"; + const string FinderInfo = "FINDER.DAT"; + const string Resources = "RESOURCE.FRK"; + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct PCExchangeEntry + { + /// + /// Name in Macintosh. If PCExchange version supports FAT's LFN they are the same. + /// Illegal characters for FAT get substituted with '_' both here and in FAT's LFN entry. + /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] + public byte[] macName; + /// + /// File type + /// + public uint type; + /// + /// File creator + /// + public uint creator; + /// + /// Finder flags + /// + public ushort fdFlags; + /// + /// File's icon vertical position within its window + /// + public ushort verticalPosition; + /// + /// File's icon horizontal position within its window + /// + public ushort horizontalPosition; + /// + /// Unknown, all bytes are empty but last, except in volume's label entry + /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 18)] + public byte[] unknown1; + /// + /// File's creation date + /// + public uint creationDate; + /// + /// File's modification date + /// + public uint modificationDate; + /// + /// File's last backup date + /// + public uint backupDate; + /// + /// Unknown, but is unique, starts 0x7FFFFFFF and counts in reverse. + /// Probably file ID for alias look up? + /// + public uint unknown2; + /// + /// Name as in FAT entry (not LFN). + /// Resource fork file is always using this name, never LFN. + /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)] + public byte[] dosName; + /// + /// Unknown, flags? + /// + public byte unknown3; + } + + bool opened; + string basePath; + string dataPath; + string rsrcPath; + DateTime lastWriteTime; + DateTime creationTime; + long dataLen; + long rsrcLen; + + public PCExchange() + { + Name = "PCExchange"; + UUID = new Guid("9264EB9F-D634-4F9B-BE12-C24CD44988C6"); + } + + public override void Close() + { + opened = false; + } + + public override string GetBasePath() + { + return basePath; + } + + public override DateTime GetCreationTime() + { + return creationTime; + } + + public override long GetDataForkLength() + { + return dataLen; + } + + public override Stream GetDataForkStream() + { + return new FileStream(dataPath, FileMode.Open, FileAccess.Read); + } + + public override string GetFilename() + { + return basePath != null ? Path.GetFileName(basePath) : null; + } + + public override DateTime GetLastWriteTime() + { + return lastWriteTime; + } + + public override long GetLength() + { + return dataLen + rsrcLen; + } + + public override string GetParentFolder() + { + return Path.GetDirectoryName(basePath); + } + + public override string GetPath() + { + return basePath; + } + + public override long GetResourceForkLength() + { + return rsrcLen; + } + + public override Stream GetResourceForkStream() + { + return new FileStream(rsrcPath, FileMode.Open, FileAccess.Read); + } + + public override bool HasResourceFork() + { + return rsrcPath != null; + } + + public override bool Identify(byte[] buffer) + { + System.Console.WriteLine("parentFolder"); + return false; + } + + public override bool Identify(Stream stream) + { + System.Console.WriteLine("parentFolder"); + return false; + } + + public override bool Identify(string path) + { + System.Console.WriteLine("parentFolder"); + string parentFolder = Path.GetDirectoryName(path); + + System.Console.WriteLine("parentFolder {0}", parentFolder); + + if(!File.Exists(Path.Combine(parentFolder, FinderInfo))) + return false; + + if(!Directory.Exists(Path.Combine(parentFolder, Resources))) + return false; + + string baseFilename = Path.GetFileName(path); + + bool dataFound = false; + bool rsrcFound = false; + + FileStream finderDatStream = new FileStream(Path.Combine(parentFolder, FinderInfo), FileMode.Open, FileAccess.Read); + + while(finderDatStream.Position + 0x5C < finderDatStream.Length) + { + PCExchangeEntry datEntry = new PCExchangeEntry(); + byte[] datEntry_b = new byte[Marshal.SizeOf(datEntry)]; + finderDatStream.Read(datEntry_b, 0, Marshal.SizeOf(datEntry)); + datEntry = BigEndianMarshal.ByteArrayToStructureBigEndian(datEntry_b); + string macName = StringHandlers.PascalToString(datEntry.macName); + byte[] tmpDosName_b = new byte[8]; + byte[] tmpDosExt_b = new byte[3]; + Array.Copy(datEntry.dosName, 0, tmpDosName_b, 0, 8); + Array.Copy(datEntry.dosName, 8, tmpDosExt_b, 0, 3); + string dosName = (Encoding.ASCII.GetString(tmpDosName_b).Trim() + "." + Encoding.ASCII.GetString(tmpDosExt_b).Trim()); + string dosNameLow = dosName.ToLower(CultureInfo.CurrentCulture); + + if(baseFilename == macName || baseFilename == dosName || baseFilename == dosNameLow) + { + dataFound |= File.Exists(Path.Combine(parentFolder, macName)) || File.Exists(Path.Combine(parentFolder, dosName)) || + File.Exists(Path.Combine(parentFolder, dosNameLow)); + + rsrcFound |= File.Exists(Path.Combine(parentFolder, Resources, dosName)) || + File.Exists(Path.Combine(parentFolder, Resources, dosNameLow)); + + break; + } + } + + finderDatStream.Close(); + + return dataFound && rsrcFound; + } + + public override bool IsOpened() + { + return opened; + } + + public override void Open(byte[] buffer) + { + throw new NotSupportedException(); + } + + public override void Open(Stream stream) + { + throw new NotSupportedException(); + } + + public override void Open(string path) + { + string parentFolder = Path.GetDirectoryName(path); + string baseFilename = Path.GetFileName(path); + + FileStream finderDatStream = new FileStream(Path.Combine(parentFolder, FinderInfo), FileMode.Open, FileAccess.Read); + + while(finderDatStream.Position + 0x5C < finderDatStream.Length) + { + PCExchangeEntry datEntry = new PCExchangeEntry(); + byte[] datEntry_b = new byte[Marshal.SizeOf(datEntry)]; + finderDatStream.Read(datEntry_b, 0, Marshal.SizeOf(datEntry)); + datEntry = BigEndianMarshal.ByteArrayToStructureBigEndian(datEntry_b); + string macName = StringHandlers.PascalToString(datEntry.macName); + byte[] tmpDosName_b = new byte[8]; + byte[] tmpDosExt_b = new byte[3]; + Array.Copy(datEntry.dosName, 0, tmpDosName_b, 0, 8); + Array.Copy(datEntry.dosName, 8, tmpDosExt_b, 0, 3); + string dosName = (Encoding.ASCII.GetString(tmpDosName_b).Trim() + "." + Encoding.ASCII.GetString(tmpDosExt_b).Trim()); + string dosNameLow = dosName.ToLower(CultureInfo.CurrentCulture); + + if(baseFilename == macName || baseFilename == dosName || baseFilename == dosNameLow) + { + if(File.Exists(Path.Combine(parentFolder, macName))) + dataPath = Path.Combine(parentFolder, macName); + else if(File.Exists(Path.Combine(parentFolder, dosName))) + dataPath = Path.Combine(parentFolder, dosName); + else if(File.Exists(Path.Combine(parentFolder, dosNameLow))) + dataPath = Path.Combine(parentFolder, dosNameLow); + else + dataPath = null; + + if(File.Exists(Path.Combine(parentFolder, Resources, dosName))) + rsrcPath = Path.Combine(parentFolder, Resources, dosName); + else if(File.Exists(Path.Combine(parentFolder, Resources, dosNameLow))) + rsrcPath = Path.Combine(parentFolder, Resources, dosNameLow); + else + rsrcPath = null; + + lastWriteTime = DateHandlers.MacToDateTime(datEntry.modificationDate); + creationTime = DateHandlers.MacToDateTime(datEntry.creationDate); + + break; + } + } + + dataLen = new FileInfo(dataPath).Length; + rsrcLen = new FileInfo(rsrcPath).Length; + + System.Console.WriteLine("dataPath = {0}", dataPath); + System.Console.WriteLine("rsrcPath = {0}", rsrcPath); + System.Console.WriteLine("dataLen = {0}", dataLen); + System.Console.WriteLine("rsrcLen = {0}", rsrcLen); + System.Console.WriteLine("basePath = {0}", basePath); + + basePath = path; + opened = true; + } + } +} diff --git a/README.md b/README.md index 2bc36af7..b1d847e3 100644 --- a/README.md +++ b/README.md @@ -153,6 +153,7 @@ Supported filters * AppleSingle * MacBinary I, II, III * BZip2 +* Apple PCExchange (FINDER.DAT & RESOURCE.FRK) Changelog =========