public void Open(string path) { string filename = Path.GetFileName(path); string filenameNoExt = Path.GetFileNameWithoutExtension(path); string parentFolder = Path.GetDirectoryName(path); parentFolder ??= ""; if (filename is null || filenameNoExt is null) { throw new ArgumentNullException(nameof(path)); } // Prepend data fork name with "R." string proDosAppleDouble = Path.Combine(parentFolder, "R." + filename); // Prepend data fork name with '%' string unixAppleDouble = Path.Combine(parentFolder, "%" + filename); // Change file extension to ADF string dosAppleDouble = Path.Combine(parentFolder, filenameNoExt + ".ADF"); // Change file extension to adf string dosAppleDoubleLower = Path.Combine(parentFolder, filenameNoExt + ".adf"); // Store AppleDouble header file in ".AppleDouble" folder with same name string netatalkAppleDouble = Path.Combine(parentFolder, ".AppleDouble", filename); // Store AppleDouble header file in "resource.frk" folder with same name string daveAppleDouble = Path.Combine(parentFolder, "resource.frk", filename); // Prepend data fork name with "._" string osxAppleDouble = Path.Combine(parentFolder, "._" + filename); // Adds ".rsrc" extension string unArAppleDouble = Path.Combine(parentFolder, filename + ".rsrc"); // Check AppleDouble created by A/UX in ProDOS filesystem if (File.Exists(proDosAppleDouble)) { var prodosStream = new FileStream(proDosAppleDouble, FileMode.Open, FileAccess.Read); if (prodosStream.Length > 26) { byte[] prodosB = new byte[26]; prodosStream.Read(prodosB, 0, 26); _header = Marshal.ByteArrayToStructureBigEndian <AppleDoubleHeader>(prodosB); prodosStream.Close(); if (_header.magic == MAGIC && (_header.version == VERSION || _header.version == VERSION2)) { _headerPath = proDosAppleDouble; } } } // Check AppleDouble created by A/UX in UFS filesystem if (File.Exists(unixAppleDouble)) { var unixStream = new FileStream(unixAppleDouble, FileMode.Open, FileAccess.Read); if (unixStream.Length > 26) { byte[] unixB = new byte[26]; unixStream.Read(unixB, 0, 26); _header = Marshal.ByteArrayToStructureBigEndian <AppleDoubleHeader>(unixB); unixStream.Close(); if (_header.magic == MAGIC && (_header.version == VERSION || _header.version == VERSION2)) { _headerPath = unixAppleDouble; } } } // Check AppleDouble created by A/UX in FAT filesystem if (File.Exists(dosAppleDouble)) { var dosStream = new FileStream(dosAppleDouble, FileMode.Open, FileAccess.Read); if (dosStream.Length > 26) { byte[] dosB = new byte[26]; dosStream.Read(dosB, 0, 26); _header = Marshal.ByteArrayToStructureBigEndian <AppleDoubleHeader>(dosB); dosStream.Close(); if (_header.magic == MAGIC && (_header.version == VERSION || _header.version == VERSION2)) { _headerPath = dosAppleDouble; } } } // Check AppleDouble created by A/UX in case preserving FAT filesystem if (File.Exists(dosAppleDoubleLower)) { var doslStream = new FileStream(dosAppleDoubleLower, FileMode.Open, FileAccess.Read); if (doslStream.Length > 26) { byte[] doslB = new byte[26]; doslStream.Read(doslB, 0, 26); _header = Marshal.ByteArrayToStructureBigEndian <AppleDoubleHeader>(doslB); doslStream.Close(); if (_header.magic == MAGIC && (_header.version == VERSION || _header.version == VERSION2)) { _headerPath = dosAppleDoubleLower; } } } // Check AppleDouble created by Netatalk if (File.Exists(netatalkAppleDouble)) { var netatalkStream = new FileStream(netatalkAppleDouble, FileMode.Open, FileAccess.Read); if (netatalkStream.Length > 26) { byte[] netatalkB = new byte[26]; netatalkStream.Read(netatalkB, 0, 26); _header = Marshal.ByteArrayToStructureBigEndian <AppleDoubleHeader>(netatalkB); netatalkStream.Close(); if (_header.magic == MAGIC && (_header.version == VERSION || _header.version == VERSION2)) { _headerPath = netatalkAppleDouble; } } } // Check AppleDouble created by DAVE if (File.Exists(daveAppleDouble)) { var daveStream = new FileStream(daveAppleDouble, FileMode.Open, FileAccess.Read); if (daveStream.Length > 26) { byte[] daveB = new byte[26]; daveStream.Read(daveB, 0, 26); _header = Marshal.ByteArrayToStructureBigEndian <AppleDoubleHeader>(daveB); daveStream.Close(); if (_header.magic == MAGIC && (_header.version == VERSION || _header.version == VERSION2)) { _headerPath = daveAppleDouble; } } } // Check AppleDouble created by Mac OS X if (File.Exists(osxAppleDouble)) { var osxStream = new FileStream(osxAppleDouble, FileMode.Open, FileAccess.Read); if (osxStream.Length > 26) { byte[] osxB = new byte[26]; osxStream.Read(osxB, 0, 26); _header = Marshal.ByteArrayToStructureBigEndian <AppleDoubleHeader>(osxB); osxStream.Close(); if (_header.magic == MAGIC && (_header.version == VERSION || _header.version == VERSION2)) { _headerPath = osxAppleDouble; } } } // Check AppleDouble created by UnAr (from The Unarchiver) if (File.Exists(unArAppleDouble)) { var unarStream = new FileStream(unArAppleDouble, FileMode.Open, FileAccess.Read); if (unarStream.Length > 26) { byte[] unarB = new byte[26]; unarStream.Read(unarB, 0, 26); _header = Marshal.ByteArrayToStructureBigEndian <AppleDoubleHeader>(unarB); unarStream.Close(); if (_header.magic == MAGIC && (_header.version == VERSION || _header.version == VERSION2)) { _headerPath = unArAppleDouble; } } } var fs = new FileStream(_headerPath, FileMode.Open, FileAccess.Read); fs.Seek(0, SeekOrigin.Begin); byte[] hdrB = new byte[26]; fs.Read(hdrB, 0, 26); _header = Marshal.ByteArrayToStructureBigEndian <AppleDoubleHeader>(hdrB); AppleDoubleEntry[] entries = new AppleDoubleEntry[_header.entries]; for (int i = 0; i < _header.entries; i++) { byte[] entry = new byte[12]; fs.Read(entry, 0, 12); entries[i] = Marshal.ByteArrayToStructureBigEndian <AppleDoubleEntry>(entry); } _creationTime = DateTime.UtcNow; _lastWriteTime = _creationTime; foreach (AppleDoubleEntry entry in entries) { switch ((AppleDoubleEntryID)entry.id) { case AppleDoubleEntryID.DataFork: // AppleDouble have datafork in separated file break; case AppleDoubleEntryID.FileDates: fs.Seek(entry.offset, SeekOrigin.Begin); byte[] datesB = new byte[16]; fs.Read(datesB, 0, 16); AppleDoubleFileDates dates = Marshal.ByteArrayToStructureBigEndian <AppleDoubleFileDates>(datesB); _creationTime = DateHandlers.UnixUnsignedToDateTime(dates.creationDate); _lastWriteTime = DateHandlers.UnixUnsignedToDateTime(dates.modificationDate); break; case AppleDoubleEntryID.FileInfo: fs.Seek(entry.offset, SeekOrigin.Begin); byte[] finfo = new byte[entry.length]; fs.Read(finfo, 0, finfo.Length); if (_macintoshHome.SequenceEqual(_header.homeFilesystem)) { AppleDoubleMacFileInfo macinfo = Marshal.ByteArrayToStructureBigEndian <AppleDoubleMacFileInfo>(finfo); _creationTime = DateHandlers.MacToDateTime(macinfo.creationDate); _lastWriteTime = DateHandlers.MacToDateTime(macinfo.modificationDate); } else if (_proDosHome.SequenceEqual(_header.homeFilesystem)) { AppleDoubleProDOSFileInfo prodosinfo = Marshal.ByteArrayToStructureBigEndian <AppleDoubleProDOSFileInfo>(finfo); _creationTime = DateHandlers.MacToDateTime(prodosinfo.creationDate); _lastWriteTime = DateHandlers.MacToDateTime(prodosinfo.modificationDate); } else if (_unixHome.SequenceEqual(_header.homeFilesystem)) { AppleDoubleUnixFileInfo unixinfo = Marshal.ByteArrayToStructureBigEndian <AppleDoubleUnixFileInfo>(finfo); _creationTime = DateHandlers.UnixUnsignedToDateTime(unixinfo.creationDate); _lastWriteTime = DateHandlers.UnixUnsignedToDateTime(unixinfo.modificationDate); } else if (_dosHome.SequenceEqual(_header.homeFilesystem)) { AppleDoubleDOSFileInfo dosinfo = Marshal.ByteArrayToStructureBigEndian <AppleDoubleDOSFileInfo>(finfo); _lastWriteTime = DateHandlers.DosToDateTime(dosinfo.modificationDate, dosinfo.modificationTime); } break; case AppleDoubleEntryID.ResourceFork: _rsrcFork = entry; break; } } _dataFork = new AppleDoubleEntry { id = (uint)AppleDoubleEntryID.DataFork }; if (File.Exists(path)) { var dataFs = new FileStream(path, FileMode.Open, FileAccess.Read); _dataFork.length = (uint)dataFs.Length; dataFs.Close(); } fs.Close(); _opened = true; _basePath = path; }
public void Open(string path) { string filename = Path.GetFileName(path); string filenameNoExt = Path.GetFileNameWithoutExtension(path); string parentFolder = Path.GetDirectoryName(path); // Prepend data fork name with "R." string ProDosAppleDouble = Path.Combine(parentFolder ?? throw new InvalidOperationException(), "R." + filename); // Prepend data fork name with '%' string UNIXAppleDouble = Path.Combine(parentFolder, "%" + filename); // Change file extension to ADF string DOSAppleDouble = Path.Combine(parentFolder, filenameNoExt + ".ADF"); // Change file extension to adf string DOSAppleDoubleLower = Path.Combine(parentFolder, filenameNoExt + ".adf"); // Store AppleDouble header file in ".AppleDouble" folder with same name string NetatalkAppleDouble = Path.Combine(parentFolder, ".AppleDouble", filename ?? throw new InvalidOperationException()); // Store AppleDouble header file in "resource.frk" folder with same name string DAVEAppleDouble = Path.Combine(parentFolder, "resource.frk", filename); // Prepend data fork name with "._" string OSXAppleDouble = Path.Combine(parentFolder, "._" + filename); // Adds ".rsrc" extension string UnArAppleDouble = Path.Combine(parentFolder, filename + ".rsrc"); // Check AppleDouble created by A/UX in ProDOS filesystem if (File.Exists(ProDosAppleDouble)) { FileStream prodosStream = new FileStream(ProDosAppleDouble, FileMode.Open, FileAccess.Read); if (prodosStream.Length > 26) { byte[] prodos_b = new byte[26]; prodosStream.Read(prodos_b, 0, 26); header = BigEndianMarshal.ByteArrayToStructureBigEndian <AppleDoubleHeader>(prodos_b); prodosStream.Close(); if (header.magic == AppleDoubleMagic && (header.version == AppleDoubleVersion || header.version == AppleDoubleVersion2)) { headerPath = ProDosAppleDouble; } } } // Check AppleDouble created by A/UX in UFS filesystem if (File.Exists(UNIXAppleDouble)) { FileStream unixStream = new FileStream(UNIXAppleDouble, FileMode.Open, FileAccess.Read); if (unixStream.Length > 26) { byte[] unix_b = new byte[26]; unixStream.Read(unix_b, 0, 26); header = BigEndianMarshal.ByteArrayToStructureBigEndian <AppleDoubleHeader>(unix_b); unixStream.Close(); if (header.magic == AppleDoubleMagic && (header.version == AppleDoubleVersion || header.version == AppleDoubleVersion2)) { headerPath = UNIXAppleDouble; } } } // Check AppleDouble created by A/UX in FAT filesystem if (File.Exists(DOSAppleDouble)) { FileStream dosStream = new FileStream(DOSAppleDouble, FileMode.Open, FileAccess.Read); if (dosStream.Length > 26) { byte[] dos_b = new byte[26]; dosStream.Read(dos_b, 0, 26); header = BigEndianMarshal.ByteArrayToStructureBigEndian <AppleDoubleHeader>(dos_b); dosStream.Close(); if (header.magic == AppleDoubleMagic && (header.version == AppleDoubleVersion || header.version == AppleDoubleVersion2)) { headerPath = DOSAppleDouble; } } } // Check AppleDouble created by A/UX in case preserving FAT filesystem if (File.Exists(DOSAppleDoubleLower)) { FileStream doslStream = new FileStream(DOSAppleDoubleLower, FileMode.Open, FileAccess.Read); if (doslStream.Length > 26) { byte[] dosl_b = new byte[26]; doslStream.Read(dosl_b, 0, 26); header = BigEndianMarshal.ByteArrayToStructureBigEndian <AppleDoubleHeader>(dosl_b); doslStream.Close(); if (header.magic == AppleDoubleMagic && (header.version == AppleDoubleVersion || header.version == AppleDoubleVersion2)) { headerPath = DOSAppleDoubleLower; } } } // Check AppleDouble created by Netatalk if (File.Exists(NetatalkAppleDouble)) { FileStream netatalkStream = new FileStream(NetatalkAppleDouble, FileMode.Open, FileAccess.Read); if (netatalkStream.Length > 26) { byte[] netatalk_b = new byte[26]; netatalkStream.Read(netatalk_b, 0, 26); header = BigEndianMarshal.ByteArrayToStructureBigEndian <AppleDoubleHeader>(netatalk_b); netatalkStream.Close(); if (header.magic == AppleDoubleMagic && (header.version == AppleDoubleVersion || header.version == AppleDoubleVersion2)) { headerPath = NetatalkAppleDouble; } } } // Check AppleDouble created by DAVE if (File.Exists(DAVEAppleDouble)) { FileStream daveStream = new FileStream(DAVEAppleDouble, FileMode.Open, FileAccess.Read); if (daveStream.Length > 26) { byte[] dave_b = new byte[26]; daveStream.Read(dave_b, 0, 26); header = BigEndianMarshal.ByteArrayToStructureBigEndian <AppleDoubleHeader>(dave_b); daveStream.Close(); if (header.magic == AppleDoubleMagic && (header.version == AppleDoubleVersion || header.version == AppleDoubleVersion2)) { headerPath = DAVEAppleDouble; } } } // Check AppleDouble created by Mac OS X if (File.Exists(OSXAppleDouble)) { FileStream osxStream = new FileStream(OSXAppleDouble, FileMode.Open, FileAccess.Read); if (osxStream.Length > 26) { byte[] osx_b = new byte[26]; osxStream.Read(osx_b, 0, 26); header = BigEndianMarshal.ByteArrayToStructureBigEndian <AppleDoubleHeader>(osx_b); osxStream.Close(); if (header.magic == AppleDoubleMagic && (header.version == AppleDoubleVersion || header.version == AppleDoubleVersion2)) { headerPath = OSXAppleDouble; } } } // Check AppleDouble created by UnAr (from The Unarchiver) if (File.Exists(UnArAppleDouble)) { FileStream unarStream = new FileStream(UnArAppleDouble, FileMode.Open, FileAccess.Read); if (unarStream.Length > 26) { byte[] unar_b = new byte[26]; unarStream.Read(unar_b, 0, 26); header = BigEndianMarshal.ByteArrayToStructureBigEndian <AppleDoubleHeader>(unar_b); unarStream.Close(); if (header.magic == AppleDoubleMagic && (header.version == AppleDoubleVersion || header.version == AppleDoubleVersion2)) { headerPath = UnArAppleDouble; } } } FileStream fs = new FileStream(headerPath, FileMode.Open, FileAccess.Read); fs.Seek(0, SeekOrigin.Begin); byte[] hdr_b = new byte[26]; fs.Read(hdr_b, 0, 26); header = BigEndianMarshal.ByteArrayToStructureBigEndian <AppleDoubleHeader>(hdr_b); AppleDoubleEntry[] entries = new AppleDoubleEntry[header.entries]; for (int i = 0; i < header.entries; i++) { byte[] entry = new byte[12]; fs.Read(entry, 0, 12); entries[i] = BigEndianMarshal.ByteArrayToStructureBigEndian <AppleDoubleEntry>(entry); } creationTime = DateTime.UtcNow; lastWriteTime = creationTime; foreach (AppleDoubleEntry entry in entries) { switch ((AppleDoubleEntryID)entry.id) { case AppleDoubleEntryID.DataFork: // AppleDouble have datafork in separated file break; case AppleDoubleEntryID.FileDates: fs.Seek(entry.offset, SeekOrigin.Begin); byte[] dates_b = new byte[16]; fs.Read(dates_b, 0, 16); AppleDoubleFileDates dates = BigEndianMarshal.ByteArrayToStructureBigEndian <AppleDoubleFileDates>(dates_b); creationTime = DateHandlers.UnixUnsignedToDateTime(dates.creationDate); lastWriteTime = DateHandlers.UnixUnsignedToDateTime(dates.modificationDate); break; case AppleDoubleEntryID.FileInfo: fs.Seek(entry.offset, SeekOrigin.Begin); byte[] finfo = new byte[entry.length]; fs.Read(finfo, 0, finfo.Length); if (MacintoshHome.SequenceEqual(header.homeFilesystem)) { AppleDoubleMacFileInfo macinfo = BigEndianMarshal.ByteArrayToStructureBigEndian <AppleDoubleMacFileInfo>(finfo); creationTime = DateHandlers.MacToDateTime(macinfo.creationDate); lastWriteTime = DateHandlers.MacToDateTime(macinfo.modificationDate); } else if (ProDOSHome.SequenceEqual(header.homeFilesystem)) { AppleDoubleProDOSFileInfo prodosinfo = BigEndianMarshal.ByteArrayToStructureBigEndian <AppleDoubleProDOSFileInfo>(finfo); creationTime = DateHandlers.MacToDateTime(prodosinfo.creationDate); lastWriteTime = DateHandlers.MacToDateTime(prodosinfo.modificationDate); } else if (UNIXHome.SequenceEqual(header.homeFilesystem)) { AppleDoubleUNIXFileInfo unixinfo = BigEndianMarshal.ByteArrayToStructureBigEndian <AppleDoubleUNIXFileInfo>(finfo); creationTime = DateHandlers.UnixUnsignedToDateTime(unixinfo.creationDate); lastWriteTime = DateHandlers.UnixUnsignedToDateTime(unixinfo.modificationDate); } else if (DOSHome.SequenceEqual(header.homeFilesystem)) { AppleDoubleDOSFileInfo dosinfo = BigEndianMarshal.ByteArrayToStructureBigEndian <AppleDoubleDOSFileInfo>(finfo); lastWriteTime = DateHandlers.DosToDateTime(dosinfo.modificationDate, dosinfo.modificationTime); } break; case AppleDoubleEntryID.ResourceFork: rsrcFork = entry; break; } } dataFork = new AppleDoubleEntry { id = (uint)AppleDoubleEntryID.DataFork }; if (File.Exists(path)) { FileStream dataFs = new FileStream(path, FileMode.Open, FileAccess.Read); dataFork.length = (uint)dataFs.Length; dataFs.Close(); } fs.Close(); opened = true; basePath = path; }