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
=========