diff --git a/DiscImageChef.DiscImages/DiscImageChef.DiscImages.csproj b/DiscImageChef.DiscImages/DiscImageChef.DiscImages.csproj
index 8f55d81ed..77380f522 100644
--- a/DiscImageChef.DiscImages/DiscImageChef.DiscImages.csproj
+++ b/DiscImageChef.DiscImages/DiscImageChef.DiscImages.csproj
@@ -31,6 +31,9 @@
false
+
+ ..\packages\Claunia.Encoding.1.4.0\lib\portable40-net40+sl5+win8+wp8\Claunia.Encoding.dll
+
..\packages\SharpCompress.0.19.2\lib\net35\SharpCompress.dll
diff --git a/DiscImageChef.DiscImages/DiskCopy42.cs b/DiscImageChef.DiscImages/DiskCopy42.cs
index ab8a1dc12..c0a3db5e3 100644
--- a/DiscImageChef.DiscImages/DiskCopy42.cs
+++ b/DiscImageChef.DiscImages/DiskCopy42.cs
@@ -34,19 +34,20 @@ using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
-using System.Text;
using System.Text.RegularExpressions;
+using Claunia.Encoding;
using Claunia.RsrcFork;
using DiscImageChef.CommonTypes;
using DiscImageChef.Console;
using DiscImageChef.Filters;
+using Encoding = System.Text.Encoding;
using Version = Resources.Version;
namespace DiscImageChef.DiscImages
{
// Checked using several images and strings inside Apple's DiskImages.framework
[SuppressMessage("ReSharper", "InconsistentNaming")]
- public class DiskCopy42 : IMediaImage
+ public class DiskCopy42 : IWritableImage
{
// format byte
/// 3.5", single side, double density, GCR
@@ -72,8 +73,8 @@ namespace DiscImageChef.DiscImages
/// Defined by Sigma Seven's BLU
const byte kSigmaFmtByteTwiggy = 0x01;
/// 3.5" single side double density GCR and MFM all use same code
- const byte kSonyFmtByte400K = 0x02;
- const byte kSonyFmtByte720K = kSonyFmtByte400K;
+ const byte kSonyFmtByte400K = 0x02;
+ const byte kSonyFmtByte720K = kSonyFmtByte400K;
const byte kSonyFmtByte1440K = kSonyFmtByte400K;
const byte kSonyFmtByte1680K = kSonyFmtByte400K;
/// 3.5" double side double density GCR, 512 bytes/sector, interleave 2:1
@@ -90,7 +91,8 @@ namespace DiscImageChef.DiscImages
/// Defined by LisaEm
const byte kFmtNotStandard = 0x93;
/// Used incorrectly by Mac OS X with certaing disk images
- const byte kMacOSXFmtByte = 0x00;
+ const byte kMacOSXFmtByte = 0x00;
+ const string REGEX_DCPY = @"(?\S+)\s(?\S+)\rData checksum=\$(?\S+)$";
/// Bytes per tag, should be 12
uint bptag;
@@ -100,49 +102,54 @@ namespace DiscImageChef.DiscImages
IFilter dc42ImageFilter;
/// Header of opened image
Dc42Header header;
+ ImageInfo imageInfo;
+ ulong sectorsToWrite;
/// Start of tags in disk image, after data sectors
- uint tagOffset;
- bool twiggy;
- byte[] twiggyCache;
- byte[] twiggyCacheTags;
- ImageInfo imageInfo;
- public ImageInfo Info => imageInfo;
+ uint tagOffset;
+ bool twiggy;
+ byte[] twiggyCache;
+ byte[] twiggyCacheTags;
+ MemoryStream twiggyDataCache;
+ MemoryStream twiggyTagCache;
- public string Name => "Apple DiskCopy 4.2";
- public Guid Id => new Guid("0240B7B1-E959-4CDC-B0BD-386D6E467B88");
+ FileStream writingStream;
public DiskCopy42()
{
imageInfo = new ImageInfo
{
- ReadableSectorTags = new List(),
- ReadableMediaTags = new List(),
- HasPartitions = false,
- HasSessions = false,
- Version = "4.2",
- Application = "Apple DiskCopy",
- ApplicationVersion = "4.2",
- Creator = null,
- Comments = null,
- MediaManufacturer = null,
- MediaModel = null,
- MediaSerialNumber = null,
- MediaBarcode = null,
- MediaPartNumber = null,
- MediaSequence = 0,
- LastMediaSequence = 0,
- DriveManufacturer = null,
- DriveModel = null,
- DriveSerialNumber = null,
+ ReadableSectorTags = new List(),
+ ReadableMediaTags = new List(),
+ HasPartitions = false,
+ HasSessions = false,
+ Version = "4.2",
+ Application = "Apple DiskCopy",
+ ApplicationVersion = "4.2",
+ Creator = null,
+ Comments = null,
+ MediaManufacturer = null,
+ MediaModel = null,
+ MediaSerialNumber = null,
+ MediaBarcode = null,
+ MediaPartNumber = null,
+ MediaSequence = 0,
+ LastMediaSequence = 0,
+ DriveManufacturer = null,
+ DriveModel = null,
+ DriveSerialNumber = null,
DriveFirmwareRevision = null
};
}
+ public ImageInfo Info => imageInfo;
+ public string Name => "Apple DiskCopy 4.2";
+ public Guid Id => new Guid("0240B7B1-E959-4CDC-B0BD-386D6E467B88");
+
public bool Identify(IFilter imageFilter)
{
Stream stream = imageFilter.GetDataForkStream();
stream.Seek(0, SeekOrigin.Begin);
- byte[] buffer = new byte[0x58];
+ byte[] buffer = new byte[0x58];
byte[] pString = new byte[64];
stream.Read(buffer, 0, 0x58);
@@ -155,43 +162,43 @@ namespace DiscImageChef.DiscImages
BigEndianBitConverter.IsLittleEndian = BitConverter.IsLittleEndian;
- tmpHeader.DiskName = StringHandlers.PascalToString(pString, Encoding.GetEncoding("macintosh"));
- tmpHeader.DataSize = BigEndianBitConverter.ToUInt32(buffer, 0x40);
- tmpHeader.TagSize = BigEndianBitConverter.ToUInt32(buffer, 0x44);
+ tmpHeader.DiskName = StringHandlers.PascalToString(pString, Encoding.GetEncoding("macintosh"));
+ tmpHeader.DataSize = BigEndianBitConverter.ToUInt32(buffer, 0x40);
+ tmpHeader.TagSize = BigEndianBitConverter.ToUInt32(buffer, 0x44);
tmpHeader.DataChecksum = BigEndianBitConverter.ToUInt32(buffer, 0x48);
- tmpHeader.TagChecksum = BigEndianBitConverter.ToUInt32(buffer, 0x4C);
- tmpHeader.Format = buffer[0x50];
- tmpHeader.FmtByte = buffer[0x51];
- tmpHeader.Valid = buffer[0x52];
- tmpHeader.Reserved = buffer[0x53];
+ tmpHeader.TagChecksum = BigEndianBitConverter.ToUInt32(buffer, 0x4C);
+ tmpHeader.Format = buffer[0x50];
+ tmpHeader.FmtByte = buffer[0x51];
+ tmpHeader.Valid = buffer[0x52];
+ tmpHeader.Reserved = buffer[0x53];
- DicConsole.DebugWriteLine("DC42 plugin", "tmp_header.diskName = \"{0}\"", tmpHeader.DiskName);
- DicConsole.DebugWriteLine("DC42 plugin", "tmp_header.dataSize = {0} bytes", tmpHeader.DataSize);
- DicConsole.DebugWriteLine("DC42 plugin", "tmp_header.tagSize = {0} bytes", tmpHeader.TagSize);
+ DicConsole.DebugWriteLine("DC42 plugin", "tmp_header.diskName = \"{0}\"", tmpHeader.DiskName);
+ DicConsole.DebugWriteLine("DC42 plugin", "tmp_header.dataSize = {0} bytes", tmpHeader.DataSize);
+ DicConsole.DebugWriteLine("DC42 plugin", "tmp_header.tagSize = {0} bytes", tmpHeader.TagSize);
DicConsole.DebugWriteLine("DC42 plugin", "tmp_header.dataChecksum = 0x{0:X8}", tmpHeader.DataChecksum);
- DicConsole.DebugWriteLine("DC42 plugin", "tmp_header.tagChecksum = 0x{0:X8}", tmpHeader.TagChecksum);
- DicConsole.DebugWriteLine("DC42 plugin", "tmp_header.format = 0x{0:X2}", tmpHeader.Format);
- DicConsole.DebugWriteLine("DC42 plugin", "tmp_header.fmtByte = 0x{0:X2}", tmpHeader.FmtByte);
- DicConsole.DebugWriteLine("DC42 plugin", "tmp_header.valid = {0}", tmpHeader.Valid);
- DicConsole.DebugWriteLine("DC42 plugin", "tmp_header.reserved = {0}", tmpHeader.Reserved);
+ DicConsole.DebugWriteLine("DC42 plugin", "tmp_header.tagChecksum = 0x{0:X8}", tmpHeader.TagChecksum);
+ DicConsole.DebugWriteLine("DC42 plugin", "tmp_header.format = 0x{0:X2}", tmpHeader.Format);
+ DicConsole.DebugWriteLine("DC42 plugin", "tmp_header.fmtByte = 0x{0:X2}", tmpHeader.FmtByte);
+ DicConsole.DebugWriteLine("DC42 plugin", "tmp_header.valid = {0}", tmpHeader.Valid);
+ DicConsole.DebugWriteLine("DC42 plugin", "tmp_header.reserved = {0}", tmpHeader.Reserved);
if(tmpHeader.Valid != 1 || tmpHeader.Reserved != 0) return false;
// Some versions seem to incorrectly create little endian fields
if(tmpHeader.DataSize + tmpHeader.TagSize + 0x54 != imageFilter.GetDataForkLength() &&
- tmpHeader.Format != kSigmaFormatTwiggy)
+ tmpHeader.Format != kSigmaFormatTwiggy)
{
- tmpHeader.DataSize = BitConverter.ToUInt32(buffer, 0x40);
- tmpHeader.TagSize = BitConverter.ToUInt32(buffer, 0x44);
+ tmpHeader.DataSize = BitConverter.ToUInt32(buffer, 0x40);
+ tmpHeader.TagSize = BitConverter.ToUInt32(buffer, 0x44);
tmpHeader.DataChecksum = BitConverter.ToUInt32(buffer, 0x48);
- tmpHeader.TagChecksum = BitConverter.ToUInt32(buffer, 0x4C);
+ tmpHeader.TagChecksum = BitConverter.ToUInt32(buffer, 0x4C);
if(tmpHeader.DataSize + tmpHeader.TagSize + 0x54 != imageFilter.GetDataForkLength() &&
- tmpHeader.Format != kSigmaFormatTwiggy) return false;
+ tmpHeader.Format != kSigmaFormatTwiggy) return false;
}
- if(tmpHeader.Format != kSonyFormat400K && tmpHeader.Format != kSonyFormat800K &&
- tmpHeader.Format != kSonyFormat720K && tmpHeader.Format != kSonyFormat1440K &&
+ if(tmpHeader.Format != kSonyFormat400K && tmpHeader.Format != kSonyFormat800K &&
+ tmpHeader.Format != kSonyFormat720K && tmpHeader.Format != kSonyFormat1440K &&
tmpHeader.Format != kSonyFormat1680K && tmpHeader.Format != kSigmaFormatTwiggy &&
tmpHeader.Format != kNotStandardFormat)
{
@@ -201,10 +208,10 @@ namespace DiscImageChef.DiscImages
return false;
}
- if(tmpHeader.FmtByte != kSonyFmtByte400K && tmpHeader.FmtByte != kSonyFmtByte800K &&
- tmpHeader.FmtByte != kSonyFmtByte800KIncorrect && tmpHeader.FmtByte != kSonyFmtByteProDos &&
- tmpHeader.FmtByte != kInvalidFmtByte && tmpHeader.FmtByte != kSigmaFmtByteTwiggy &&
- tmpHeader.FmtByte != kFmtNotStandard && tmpHeader.FmtByte != kMacOSXFmtByte)
+ if(tmpHeader.FmtByte != kSonyFmtByte400K && tmpHeader.FmtByte != kSonyFmtByte800K &&
+ tmpHeader.FmtByte != kSonyFmtByte800KIncorrect && tmpHeader.FmtByte != kSonyFmtByteProDos &&
+ tmpHeader.FmtByte != kInvalidFmtByte && tmpHeader.FmtByte != kSigmaFmtByteTwiggy &&
+ tmpHeader.FmtByte != kFmtNotStandard && tmpHeader.FmtByte != kMacOSXFmtByte)
{
DicConsole.DebugWriteLine("DC42 plugin", "Unknown tmp_header.fmtByte = 0x{0:X2} value",
tmpHeader.FmtByte);
@@ -223,54 +230,55 @@ namespace DiscImageChef.DiscImages
{
Stream stream = imageFilter.GetDataForkStream();
stream.Seek(0, SeekOrigin.Begin);
- byte[] buffer = new byte[0x58];
+ byte[] buffer = new byte[0x58];
byte[] pString = new byte[64];
stream.Read(buffer, 0, 0x58);
+ IsWriting = false;
// Incorrect pascal string length, not DC42
if(buffer[0] > 63) return false;
- header = new Dc42Header();
+ header = new Dc42Header();
BigEndianBitConverter.IsLittleEndian = BitConverter.IsLittleEndian;
Array.Copy(buffer, 0, pString, 0, 64);
- header.DiskName = StringHandlers.PascalToString(pString, Encoding.GetEncoding("macintosh"));
- header.DataSize = BigEndianBitConverter.ToUInt32(buffer, 0x40);
- header.TagSize = BigEndianBitConverter.ToUInt32(buffer, 0x44);
+ header.DiskName = StringHandlers.PascalToString(pString, Encoding.GetEncoding("macintosh"));
+ header.DataSize = BigEndianBitConverter.ToUInt32(buffer, 0x40);
+ header.TagSize = BigEndianBitConverter.ToUInt32(buffer, 0x44);
header.DataChecksum = BigEndianBitConverter.ToUInt32(buffer, 0x48);
- header.TagChecksum = BigEndianBitConverter.ToUInt32(buffer, 0x4C);
- header.Format = buffer[0x50];
- header.FmtByte = buffer[0x51];
- header.Valid = buffer[0x52];
- header.Reserved = buffer[0x53];
+ header.TagChecksum = BigEndianBitConverter.ToUInt32(buffer, 0x4C);
+ header.Format = buffer[0x50];
+ header.FmtByte = buffer[0x51];
+ header.Valid = buffer[0x52];
+ header.Reserved = buffer[0x53];
- DicConsole.DebugWriteLine("DC42 plugin", "header.diskName = \"{0}\"", header.DiskName);
- DicConsole.DebugWriteLine("DC42 plugin", "header.dataSize = {0} bytes", header.DataSize);
- DicConsole.DebugWriteLine("DC42 plugin", "header.tagSize = {0} bytes", header.TagSize);
+ DicConsole.DebugWriteLine("DC42 plugin", "header.diskName = \"{0}\"", header.DiskName);
+ DicConsole.DebugWriteLine("DC42 plugin", "header.dataSize = {0} bytes", header.DataSize);
+ DicConsole.DebugWriteLine("DC42 plugin", "header.tagSize = {0} bytes", header.TagSize);
DicConsole.DebugWriteLine("DC42 plugin", "header.dataChecksum = 0x{0:X8}", header.DataChecksum);
- DicConsole.DebugWriteLine("DC42 plugin", "header.tagChecksum = 0x{0:X8}", header.TagChecksum);
- DicConsole.DebugWriteLine("DC42 plugin", "header.format = 0x{0:X2}", header.Format);
- DicConsole.DebugWriteLine("DC42 plugin", "header.fmtByte = 0x{0:X2}", header.FmtByte);
- DicConsole.DebugWriteLine("DC42 plugin", "header.valid = {0}", header.Valid);
- DicConsole.DebugWriteLine("DC42 plugin", "header.reserved = {0}", header.Reserved);
+ DicConsole.DebugWriteLine("DC42 plugin", "header.tagChecksum = 0x{0:X8}", header.TagChecksum);
+ DicConsole.DebugWriteLine("DC42 plugin", "header.format = 0x{0:X2}", header.Format);
+ DicConsole.DebugWriteLine("DC42 plugin", "header.fmtByte = 0x{0:X2}", header.FmtByte);
+ DicConsole.DebugWriteLine("DC42 plugin", "header.valid = {0}", header.Valid);
+ DicConsole.DebugWriteLine("DC42 plugin", "header.reserved = {0}", header.Reserved);
if(header.Valid != 1 || header.Reserved != 0) return false;
// Some versions seem to incorrectly create little endian fields
if(header.DataSize + header.TagSize + 0x54 != imageFilter.GetDataForkLength() &&
- header.Format != kSigmaFormatTwiggy)
+ header.Format != kSigmaFormatTwiggy)
{
- header.DataSize = BitConverter.ToUInt32(buffer, 0x40);
- header.TagSize = BitConverter.ToUInt32(buffer, 0x44);
+ header.DataSize = BitConverter.ToUInt32(buffer, 0x40);
+ header.TagSize = BitConverter.ToUInt32(buffer, 0x44);
header.DataChecksum = BitConverter.ToUInt32(buffer, 0x48);
- header.TagChecksum = BitConverter.ToUInt32(buffer, 0x4C);
+ header.TagChecksum = BitConverter.ToUInt32(buffer, 0x4C);
if(header.DataSize + header.TagSize + 0x54 != imageFilter.GetDataForkLength() &&
- header.Format != kSigmaFormatTwiggy) return false;
+ header.Format != kSigmaFormatTwiggy) return false;
}
- if(header.Format != kSonyFormat400K && header.Format != kSonyFormat800K &&
- header.Format != kSonyFormat720K && header.Format != kSonyFormat1440K &&
+ if(header.Format != kSonyFormat400K && header.Format != kSonyFormat800K &&
+ header.Format != kSonyFormat720K && header.Format != kSonyFormat1440K &&
header.Format != kSonyFormat1680K && header.Format != kSigmaFormatTwiggy &&
header.Format != kNotStandardFormat)
{
@@ -279,10 +287,10 @@ namespace DiscImageChef.DiscImages
return false;
}
- if(header.FmtByte != kSonyFmtByte400K && header.FmtByte != kSonyFmtByte800K &&
- header.FmtByte != kSonyFmtByte800KIncorrect && header.FmtByte != kSonyFmtByteProDos &&
- header.FmtByte != kInvalidFmtByte && header.FmtByte != kSigmaFmtByteTwiggy &&
- header.FmtByte != kFmtNotStandard && header.FmtByte != kMacOSXFmtByte)
+ if(header.FmtByte != kSonyFmtByte400K && header.FmtByte != kSonyFmtByte800K &&
+ header.FmtByte != kSonyFmtByte800KIncorrect && header.FmtByte != kSonyFmtByteProDos &&
+ header.FmtByte != kInvalidFmtByte && header.FmtByte != kSigmaFmtByteTwiggy &&
+ header.FmtByte != kFmtNotStandard && header.FmtByte != kMacOSXFmtByte)
{
DicConsole.DebugWriteLine("DC42 plugin", "Unknown tmp_header.fmtByte = 0x{0:X2} value", header.FmtByte);
@@ -296,11 +304,11 @@ namespace DiscImageChef.DiscImages
return false;
}
- dataOffset = 0x54;
- tagOffset = header.TagSize != 0 ? 0x54 + header.DataSize : 0;
+ dataOffset = 0x54;
+ tagOffset = header.TagSize != 0 ? 0x54 + header.DataSize : 0;
imageInfo.SectorSize = 512;
- bptag = (uint)(header.TagSize != 0 ? 12 : 0);
- dc42ImageFilter = imageFilter;
+ bptag = (uint)(header.TagSize != 0 ? 12 : 0);
+ dc42ImageFilter = imageFilter;
imageInfo.Sectors = header.DataSize / 512;
@@ -318,10 +326,10 @@ namespace DiscImageChef.DiscImages
imageInfo.ReadableSectorTags.Add(SectorTagType.AppleSectorTag);
}
- imageInfo.ImageSize = imageInfo.Sectors * imageInfo.SectorSize + imageInfo.Sectors * bptag;
- imageInfo.CreationTime = imageFilter.GetCreationTime();
+ imageInfo.ImageSize = imageInfo.Sectors * imageInfo.SectorSize + imageInfo.Sectors * bptag;
+ imageInfo.CreationTime = imageFilter.GetCreationTime();
imageInfo.LastModificationTime = imageFilter.GetLastWriteTime();
- imageInfo.MediaTitle = header.DiskName;
+ imageInfo.MediaTitle = header.DiskName;
switch(header.Format)
{
@@ -374,9 +382,9 @@ namespace DiscImageChef.DiscImages
byte[] data = new byte[header.DataSize];
byte[] tags = new byte[header.TagSize];
- twiggyCache = new byte[header.DataSize];
+ twiggyCache = new byte[header.DataSize];
twiggyCacheTags = new byte[header.TagSize];
- twiggy = true;
+ twiggy = true;
Stream datastream = imageFilter.GetDataForkStream();
datastream.Seek(dataOffset, SeekOrigin.Begin);
@@ -386,31 +394,31 @@ namespace DiscImageChef.DiscImages
tagstream.Seek(tagOffset, SeekOrigin.Begin);
tagstream.Read(tags, 0, (int)header.TagSize);
- ushort mfsMagic = BigEndianBitConverter.ToUInt16(data, data.Length / 2 + 0x400);
+ ushort mfsMagic = BigEndianBitConverter.ToUInt16(data, data.Length / 2 + 0x400);
ushort mfsAllBlocks = BigEndianBitConverter.ToUInt16(data, data.Length / 2 + 0x412);
// Detect a Macintosh Twiggy
if(mfsMagic == 0xD2D7 && mfsAllBlocks == 422)
{
DicConsole.DebugWriteLine("DC42 plugin", "Macintosh Twiggy detected, reversing disk sides");
- Array.Copy(data, header.DataSize / 2, twiggyCache, 0, header.DataSize / 2);
- Array.Copy(tags, header.TagSize / 2, twiggyCacheTags, 0, header.TagSize / 2);
- Array.Copy(data, 0, twiggyCache, header.DataSize / 2, header.DataSize / 2);
- Array.Copy(tags, 0, twiggyCacheTags, header.TagSize / 2, header.TagSize / 2);
+ Array.Copy(data, header.DataSize / 2, twiggyCache, 0, header.DataSize / 2);
+ Array.Copy(tags, header.TagSize / 2, twiggyCacheTags, 0, header.TagSize / 2);
+ Array.Copy(data, 0, twiggyCache, header.DataSize / 2, header.DataSize / 2);
+ Array.Copy(tags, 0, twiggyCacheTags, header.TagSize / 2, header.TagSize / 2);
}
else
{
DicConsole.DebugWriteLine("DC42 plugin", "Lisa Twiggy detected, reversing second half of disk");
- Array.Copy(data, 0, twiggyCache, 0, header.DataSize / 2);
- Array.Copy(tags, 0, twiggyCacheTags, 0, header.TagSize / 2);
+ Array.Copy(data, 0, twiggyCache, 0, header.DataSize / 2);
+ Array.Copy(tags, 0, twiggyCacheTags, 0, header.TagSize / 2);
int copiedSectors = 0;
int sectorsToCopy = 0;
for(int i = 0; i < 46; i++)
{
- if(i >= 0 && i <= 3) sectorsToCopy = 22;
- if(i >= 4 && i <= 10) sectorsToCopy = 21;
+ if(i >= 0 && i <= 3) sectorsToCopy = 22;
+ if(i >= 4 && i <= 10) sectorsToCopy = 21;
if(i >= 11 && i <= 16) sectorsToCopy = 20;
if(i >= 17 && i <= 22) sectorsToCopy = 19;
if(i >= 23 && i <= 28) sectorsToCopy = 18;
@@ -419,10 +427,13 @@ namespace DiscImageChef.DiscImages
if(i >= 42 && i <= 45) sectorsToCopy = 15;
Array.Copy(data, header.DataSize / 2 + copiedSectors * 512, twiggyCache,
- twiggyCache.Length - copiedSectors * 512 - sectorsToCopy * 512, sectorsToCopy * 512);
- Array.Copy(tags, header.TagSize / 2 + copiedSectors * bptag, twiggyCacheTags,
- twiggyCacheTags.Length - copiedSectors * bptag - sectorsToCopy * bptag,
- sectorsToCopy * bptag);
+ twiggyCache.Length - copiedSectors * 512 - sectorsToCopy * 512,
+ sectorsToCopy * 512);
+ Array.Copy(tags, header.TagSize / 2 + copiedSectors * bptag,
+ twiggyCacheTags,
+ twiggyCacheTags.Length - copiedSectors * bptag -
+ sectorsToCopy * bptag,
+ sectorsToCopy * bptag);
copiedSectors += sectorsToCopy;
}
@@ -445,12 +456,12 @@ namespace DiscImageChef.DiscImages
Version version = new Version(vers);
string release = null;
- string dev = null;
- string pre = null;
+ string dev = null;
+ string pre = null;
string major = $"{version.MajorVersion}";
string minor = $".{version.MinorVersion / 10}";
- if(version.MinorVersion % 10 > 0) release = $".{version.MinorVersion % 10}";
+ if(version.MinorVersion % 10 > 0) release = $".{version.MinorVersion % 10}";
switch(version.DevStage)
{
case Version.DevelopmentStage.Alpha:
@@ -469,8 +480,8 @@ namespace DiscImageChef.DiscImages
if(dev != null) pre = $"{version.PreReleaseVersion}";
imageInfo.ApplicationVersion = $"{major}{minor}{release}{dev}{pre}";
- imageInfo.Application = version.VersionString;
- imageInfo.Comments = version.VersionMessage;
+ imageInfo.Application = version.VersionString;
+ imageInfo.Comments = version.VersionMessage;
}
}
@@ -481,18 +492,13 @@ namespace DiscImageChef.DiscImages
{
string dCpy = StringHandlers.PascalToString(dCpyRsrc.GetResource(dCpyRsrc.GetIds()[0]),
Encoding.GetEncoding("macintosh"));
- string dCpyRegEx =
- @"(?\S+)\s(?\S+)\rData checksum=\$(?\S+)$";
- Regex dCpyEx = new Regex(dCpyRegEx);
+ Regex dCpyEx = new Regex(REGEX_DCPY);
Match dCpyMatch = dCpyEx.Match(dCpy);
if(dCpyMatch.Success)
{
- imageInfo.Application = dCpyMatch.Groups["application"].Value;
+ imageInfo.Application = dCpyMatch.Groups["application"].Value;
imageInfo.ApplicationVersion = dCpyMatch.Groups["version"].Value;
-
- // Until MacRoman is implemented
- if(imageInfo.Application == "ShrinkWrap?") imageInfo.Application = "ShrinkWrap™";
}
}
}
@@ -509,28 +515,28 @@ namespace DiscImageChef.DiscImages
switch(imageInfo.MediaType)
{
case MediaType.AppleSonySS:
- imageInfo.Cylinders = 80;
- imageInfo.Heads = 1;
+ imageInfo.Cylinders = 80;
+ imageInfo.Heads = 1;
imageInfo.SectorsPerTrack = 10;
break;
case MediaType.AppleSonyDS:
- imageInfo.Cylinders = 80;
- imageInfo.Heads = 2;
+ imageInfo.Cylinders = 80;
+ imageInfo.Heads = 2;
imageInfo.SectorsPerTrack = 10;
break;
case MediaType.DOS_35_DS_DD_9:
- imageInfo.Cylinders = 80;
- imageInfo.Heads = 2;
+ imageInfo.Cylinders = 80;
+ imageInfo.Heads = 2;
imageInfo.SectorsPerTrack = 9;
break;
case MediaType.DOS_35_HD:
- imageInfo.Cylinders = 80;
- imageInfo.Heads = 2;
+ imageInfo.Cylinders = 80;
+ imageInfo.Heads = 2;
imageInfo.SectorsPerTrack = 18;
break;
case MediaType.DMF:
- imageInfo.Cylinders = 80;
- imageInfo.Heads = 2;
+ imageInfo.Cylinders = 80;
+ imageInfo.Heads = 2;
imageInfo.SectorsPerTrack = 21;
break;
case MediaType.AppleProfile:
@@ -544,22 +550,22 @@ namespace DiscImageChef.DiscImages
break;
}
- imageInfo.Heads = 4;
+ imageInfo.Heads = 4;
imageInfo.SectorsPerTrack = 16;
break;
case MediaType.AppleWidget:
- imageInfo.Cylinders = 608;
- imageInfo.Heads = 2;
+ imageInfo.Cylinders = 608;
+ imageInfo.Heads = 2;
imageInfo.SectorsPerTrack = 16;
break;
case MediaType.AppleHD20:
- imageInfo.Cylinders = 610;
- imageInfo.Heads = 2;
+ imageInfo.Cylinders = 610;
+ imageInfo.Heads = 2;
imageInfo.SectorsPerTrack = 16;
break;
default:
- imageInfo.Cylinders = (uint)(imageInfo.Sectors / 16 / 63);
- imageInfo.Heads = 16;
+ imageInfo.Cylinders = (uint)(imageInfo.Sectors / 16 / 63);
+ imageInfo.Heads = 16;
imageInfo.SectorsPerTrack = 63;
break;
}
@@ -578,7 +584,7 @@ namespace DiscImageChef.DiscImages
}
public bool? VerifySectors(ulong sectorAddress, uint length, out List failingLbas,
- out List unknownLbas)
+ out List unknownLbas)
{
failingLbas = new List();
unknownLbas = new List();
@@ -589,7 +595,7 @@ namespace DiscImageChef.DiscImages
}
public bool? VerifySectors(ulong sectorAddress, uint length, uint track, out List failingLbas,
- out List unknownLbas)
+ out List unknownLbas)
{
failingLbas = new List();
unknownLbas = new List();
@@ -601,10 +607,9 @@ namespace DiscImageChef.DiscImages
public bool? VerifyMediaImage()
{
- byte[] data = new byte[header.DataSize];
- byte[] tags = new byte[header.TagSize];
- uint dataChk;
- uint tagsChk = 0;
+ byte[] data = new byte[header.DataSize];
+ byte[] tags = new byte[header.TagSize];
+ uint tagsChk = 0;
DicConsole.DebugWriteLine("DC42 plugin", "Reading data");
Stream datastream = dc42ImageFilter.GetDataForkStream();
@@ -612,9 +617,9 @@ namespace DiscImageChef.DiscImages
datastream.Read(data, 0, (int)header.DataSize);
DicConsole.DebugWriteLine("DC42 plugin", "Calculating data checksum");
- dataChk = DC42CheckSum(data);
+ uint dataChk = DC42CheckSum(data);
DicConsole.DebugWriteLine("DC42 plugin", "Calculated data checksum = 0x{0:X8}", dataChk);
- DicConsole.DebugWriteLine("DC42 plugin", "Stored data checksum = 0x{0:X8}", header.DataChecksum);
+ DicConsole.DebugWriteLine("DC42 plugin", "Stored data checksum = 0x{0:X8}", header.DataChecksum);
if(header.TagSize <= 0) return dataChk == header.DataChecksum && tagsChk == header.TagChecksum;
@@ -626,7 +631,7 @@ namespace DiscImageChef.DiscImages
DicConsole.DebugWriteLine("DC42 plugin", "Calculating tag checksum");
tagsChk = DC42CheckSum(tags);
DicConsole.DebugWriteLine("DC42 plugin", "Calculated tag checksum = 0x{0:X8}", tagsChk);
- DicConsole.DebugWriteLine("DC42 plugin", "Stored tag checksum = 0x{0:X8}", header.TagChecksum);
+ DicConsole.DebugWriteLine("DC42 plugin", "Stored tag checksum = 0x{0:X8}", header.TagChecksum);
return dataChk == header.DataChecksum && tagsChk == header.TagChecksum;
}
@@ -653,12 +658,12 @@ namespace DiscImageChef.DiscImages
if(twiggy)
Array.Copy(twiggyCache, (int)sectorAddress * imageInfo.SectorSize, buffer, 0,
- length * imageInfo.SectorSize);
+ length * imageInfo.SectorSize);
else
{
Stream stream = dc42ImageFilter.GetDataForkStream();
stream.Seek((long)(dataOffset + sectorAddress * imageInfo.SectorSize), SeekOrigin.Begin);
- stream.Read(buffer, 0, (int)(length * imageInfo.SectorSize));
+ stream.Read(buffer, 0, (int)(length * imageInfo.SectorSize));
}
return buffer;
@@ -684,7 +689,7 @@ namespace DiscImageChef.DiscImages
{
Stream stream = dc42ImageFilter.GetDataForkStream();
stream.Seek((long)(tagOffset + sectorAddress * bptag), SeekOrigin.Begin);
- stream.Read(buffer, 0, (int)(length * bptag));
+ stream.Read(buffer, 0, (int)(length * bptag));
}
return buffer;
@@ -703,8 +708,8 @@ namespace DiscImageChef.DiscImages
if(sectorAddress + length > imageInfo.Sectors)
throw new ArgumentOutOfRangeException(nameof(length), "Requested more sectors than available");
- byte[] data = ReadSectors(sectorAddress, length);
- byte[] tags = ReadSectorsTag(sectorAddress, length, SectorTagType.AppleSectorTag);
+ byte[] data = ReadSectors(sectorAddress, length);
+ byte[] tags = ReadSectorsTag(sectorAddress, length, SectorTagType.AppleSectorTag);
byte[] buffer = new byte[data.Length + tags.Length];
for(uint i = 0; i < length; i++)
@@ -773,6 +778,333 @@ namespace DiscImageChef.DiscImages
throw new FeatureUnsupportedImageException("Feature not supported by image format");
}
+ public IEnumerable SupportedMediaTags => new MediaTagType[] { };
+ public IEnumerable SupportedSectorTags => new[] {SectorTagType.AppleSectorTag};
+ public IEnumerable SupportedMediaTypes =>
+ new[]
+ {
+ MediaType.AppleFileWare, MediaType.AppleHD20, MediaType.AppleProfile, MediaType.AppleSonyDS,
+ MediaType.AppleSonySS, MediaType.AppleWidget, MediaType.DOS_35_DS_DD_9, MediaType.DOS_35_HD,
+ MediaType.DMF
+ };
+ public IEnumerable<(string name, Type type, string description)> SupportedOptions =>
+ new[] {("macosx", typeof(bool), "Use Mac OS X format byte")};
+ public IEnumerable KnownExtensions => new[] {".dc42", ".diskcopy42", ".image"};
+ public bool IsWriting { get; private set; }
+ public string ErrorMessage { get; private set; }
+
+ public bool Create(string path, MediaType mediaType, Dictionary options, ulong sectors)
+ {
+ header = new Dc42Header();
+ bool tags = false;
+ bool macosx;
+
+ if(options != null && options.TryGetValue("macosx", out string tmpOption))
+ bool.TryParse(tmpOption, out macosx);
+
+ switch(mediaType)
+ {
+ case MediaType.AppleFileWare:
+ header.FmtByte = kSigmaFmtByteTwiggy;
+ header.Format = kSigmaFormatTwiggy;
+ twiggy = true;
+ tags = true;
+ twiggyDataCache = new MemoryStream();
+ twiggyTagCache = new MemoryStream();
+
+ // TODO
+ ErrorMessage = "Twiggy write support not yet implemented";
+ return false;
+ case MediaType.AppleHD20:
+ if(sectors != 39040)
+ {
+ ErrorMessage = "Incorrect number of sectors for Apple HD20 image";
+ return false;
+ }
+
+ header.FmtByte = kFmtNotStandard;
+ header.Format = kNotStandardFormat;
+ tags = true;
+ break;
+ case MediaType.AppleProfile:
+ if(sectors != 9728 && sectors != 19456)
+ {
+ ErrorMessage = "Incorrect number of sectors for Apple Profile image";
+ return false;
+ }
+
+ header.FmtByte = kFmtNotStandard;
+ header.Format = kNotStandardFormat;
+ tags = true;
+ break;
+ case MediaType.AppleSonyDS:
+ if(sectors != 1600)
+ {
+ ErrorMessage = "Incorrect number of sectors for Apple MF2DD image";
+ return false;
+ }
+
+ header.FmtByte = macosx ? kMacOSXFmtByte : kSonyFmtByte800K;
+ header.Format = kSonyFormat800K;
+ tags = true;
+ break;
+ case MediaType.AppleSonySS:
+ if(sectors != 800)
+ {
+ ErrorMessage = "Incorrect number of sectors for Apple MF1DD image";
+ return false;
+ }
+
+ header.FmtByte = macosx ? kMacOSXFmtByte : kSonyFmtByte400K;
+ header.Format = kSonyFormat400K;
+ tags = true;
+ break;
+ case MediaType.AppleWidget:
+ if(sectors != 39040)
+ {
+ ErrorMessage = "Incorrect number of sectors for Apple Widget image";
+ return false;
+ }
+
+ header.FmtByte = kFmtNotStandard;
+ header.Format = kNotStandardFormat;
+ tags = true;
+ break;
+ case MediaType.DOS_35_DS_DD_9:
+ if(sectors != 1440)
+ {
+ ErrorMessage = "Incorrect number of sectors for MF2DD image";
+ return false;
+ }
+
+ header.FmtByte = macosx ? kMacOSXFmtByte : kSonyFmtByte720K;
+ header.Format = kSonyFormat720K;
+ break;
+ case MediaType.DOS_35_HD:
+ if(sectors != 2880)
+ {
+ ErrorMessage = "Incorrect number of sectors for MF2HD image";
+ return false;
+ }
+
+ header.Format = kSonyFmtByte1440K;
+ header.FmtByte = macosx ? kMacOSXFmtByte : kSonyFmtByte1440K;
+ break;
+ case MediaType.DMF:
+ if(sectors != 3360)
+ {
+ ErrorMessage = "Incorrect number of sectors for DMF image";
+ return false;
+ }
+
+ header.FmtByte = macosx ? kMacOSXFmtByte : kSonyFmtByte1680K;
+ header.Format = kSonyFormat1680K;
+ break;
+ default:
+ ErrorMessage = $"Unsupport media format {mediaType}";
+ return false;
+ }
+
+ dataOffset = 0x54;
+ tagOffset = header.TagSize != 0 ? 0x54 + header.DataSize : 0;
+ header.DiskName = "-DiscImageChef converted image-";
+ header.Valid = 1;
+ header.DataSize = (uint)(sectors * 512);
+ if(tags) header.TagSize = (uint)(sectors * 12);
+ sectorsToWrite = sectors;
+
+ try { writingStream = new FileStream(path, FileMode.CreateNew, FileAccess.ReadWrite, FileShare.None); }
+ catch(IOException e)
+ {
+ ErrorMessage = $"Could not create new image file, exception {e.Message}";
+ return false;
+ }
+
+ ErrorMessage = null;
+ return true;
+ }
+
+ public bool WriteMediaTag(byte[] data, MediaTagType tag)
+ {
+ ErrorMessage = "Unsupported feature";
+ return false;
+ }
+
+ public bool WriteSector(byte[] data, ulong sectorAddress)
+ {
+ if(!IsWriting)
+ {
+ ErrorMessage = "Tried to write on a non-writable image";
+ return false;
+ }
+
+ if(sectorAddress >= sectorsToWrite)
+ {
+ ErrorMessage = "Tried to write past image size";
+ return false;
+ }
+
+ writingStream.Seek((long)(dataOffset + sectorAddress * 512), SeekOrigin.Begin);
+ writingStream.Write(data, 0, data.Length);
+
+ ErrorMessage = "";
+ return true;
+ }
+
+ public bool WriteSectors(byte[] data, ulong sectorAddress, uint length)
+ {
+ if(!IsWriting)
+ {
+ ErrorMessage = "Tried to write on a non-writable image";
+ return false;
+ }
+
+ if(data.Length != 512)
+ {
+ ErrorMessage = "Incorrect data size";
+ return false;
+ }
+
+ if(data.Length % 512 != 0)
+ {
+ ErrorMessage = "Incorrect data size";
+ return false;
+ }
+
+ if(sectorAddress + length >= sectorsToWrite)
+ {
+ ErrorMessage = "Tried to write past image size";
+ return false;
+ }
+
+ writingStream.Seek((long)(dataOffset + sectorAddress * 512), SeekOrigin.Begin);
+ writingStream.Write(data, 0, data.Length);
+
+ ErrorMessage = "";
+ return true;
+ }
+
+ public bool WriteSectorLong(byte[] data, ulong sectorAddress)
+ {
+ if(!IsWriting)
+ {
+ ErrorMessage = "Tried to write on a non-writable image";
+ return false;
+ }
+
+ if(header.TagSize == 0)
+ {
+ ErrorMessage = "Image does not support tags";
+ return false;
+ }
+
+ if(data.Length != 524)
+ {
+ ErrorMessage = "Incorrect data size";
+ return false;
+ }
+
+ if(sectorAddress >= sectorsToWrite)
+ {
+ ErrorMessage = "Tried to write past image size";
+ return false;
+ }
+
+ writingStream.Seek((long)(dataOffset + sectorAddress * 512), SeekOrigin.Begin);
+ writingStream.Write(data, 0, 512);
+ writingStream.Seek((long)(tagOffset + sectorAddress * 12), SeekOrigin.Begin);
+ writingStream.Write(data, 512, 12);
+
+ ErrorMessage = "";
+ return true;
+ }
+
+ public bool WriteSectorsLong(byte[] data, ulong sectorAddress, uint length)
+ {
+ if(!IsWriting)
+ {
+ ErrorMessage = "Tried to write on a non-writable image";
+ return false;
+ }
+
+ if(header.TagSize == 0)
+ {
+ ErrorMessage = "Image does not support tags";
+ return false;
+ }
+
+ if(data.Length % 524 != 0)
+ {
+ ErrorMessage = "Incorrect data size";
+ return false;
+ }
+
+ if(sectorAddress + length >= sectorsToWrite)
+ {
+ ErrorMessage = "Tried to write past image size";
+ return false;
+ }
+
+ for(uint i = 0; i < length; i++)
+ {
+ writingStream.Seek((long)(dataOffset + (sectorAddress + i) * 512), SeekOrigin.Begin);
+ writingStream.Write(data, (int)(i * 524 + 0), 512);
+ writingStream.Seek((long)(tagOffset + (sectorAddress + i) * 12),
+ SeekOrigin.Begin);
+ writingStream.Write(data, (int)(i * 524 + 512),
+ 12);
+ }
+
+ ErrorMessage = "";
+ return true;
+ }
+
+ public bool SetTracks(List