mirror of
https://github.com/aaru-dps/Aaru.git
synced 2025-12-16 19:24:25 +00:00
Updated SuperCardPro plugin, documentation and template to image version 1.6.
This commit is contained in:
@@ -35,6 +35,7 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using DiscImageChef.CommonTypes;
|
||||
using DiscImageChef.Console;
|
||||
using DiscImageChef.Filters;
|
||||
@@ -78,6 +79,24 @@ namespace DiscImageChef.ImagePlugins
|
||||
public uint trackLength;
|
||||
public uint dataOffset;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct ScpFooter
|
||||
{
|
||||
public uint manufacturerOffset;
|
||||
public uint modelOffset;
|
||||
public uint serialOffset;
|
||||
public uint creatorOffset;
|
||||
public uint applicationOffset;
|
||||
public uint commentsOffset;
|
||||
public long creationTime;
|
||||
public long modificationTime;
|
||||
public byte applicationVersion;
|
||||
public byte hardwareVersion;
|
||||
public byte firmwareVersion;
|
||||
public byte imageVersion;
|
||||
public uint signature;
|
||||
}
|
||||
#endregion Internal Structures
|
||||
|
||||
#region Internal Constants
|
||||
@@ -89,6 +108,10 @@ namespace DiscImageChef.ImagePlugins
|
||||
/// SuperCardPro track header signature: "TRK"
|
||||
/// </summary>
|
||||
readonly byte[] TrkSignature = { 0x54, 0x52, 0x4B };
|
||||
/// <summary>
|
||||
/// SuperCardPro footer signature: "FPCS"
|
||||
/// </summary>
|
||||
const uint FooterSignature = 0x53435046;
|
||||
|
||||
public enum ScpDiskType : byte
|
||||
{
|
||||
@@ -138,7 +161,11 @@ namespace DiscImageChef.ImagePlugins
|
||||
/// <summary>
|
||||
/// If set image is read/write capable
|
||||
/// </summary>
|
||||
Writable = 0x10
|
||||
Writable = 0x10,
|
||||
/// <summary>
|
||||
/// If set, image has footer
|
||||
/// </summary>
|
||||
HasFooter = 0x20,
|
||||
}
|
||||
#endregion Internal Constants
|
||||
|
||||
@@ -272,9 +299,117 @@ namespace DiscImageChef.ImagePlugins
|
||||
tracks.Add(t, trk);
|
||||
}
|
||||
|
||||
if(header.flags.HasFlag(ScpFlags.HasFooter))
|
||||
{
|
||||
long position = stream.Position;
|
||||
stream.Seek(-4, SeekOrigin.End);
|
||||
|
||||
while(stream.Position >= position)
|
||||
{
|
||||
byte[] footerSig = new byte[4];
|
||||
stream.Read(footerSig, 0, 4);
|
||||
uint footerMagic = BitConverter.ToUInt32(footerSig, 0);
|
||||
|
||||
if(footerMagic == FooterSignature)
|
||||
{
|
||||
stream.Seek(-Marshal.SizeOf(typeof(ScpFooter)), SeekOrigin.Current);
|
||||
|
||||
DicConsole.DebugWriteLine("SuperCardPro plugin", "Found footer at {0}", stream.Position);
|
||||
|
||||
byte[] ftr = new byte[Marshal.SizeOf(typeof(ScpFooter))];
|
||||
stream.Read(ftr, 0, Marshal.SizeOf(typeof(ScpFooter)));
|
||||
|
||||
IntPtr ftrPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(ScpFooter)));
|
||||
Marshal.Copy(ftr, 0, ftrPtr, Marshal.SizeOf(typeof(ScpFooter)));
|
||||
ScpFooter footer = (ScpFooter)Marshal.PtrToStructure(ftrPtr, typeof(ScpFooter));
|
||||
Marshal.FreeHGlobal(ftrPtr);
|
||||
|
||||
DicConsole.DebugWriteLine("SuperCardPro plugin", "footer.manufacturerOffset = 0x{0:X8}", footer.manufacturerOffset);
|
||||
DicConsole.DebugWriteLine("SuperCardPro plugin", "footer.modelOffset = 0x{0:X8}", footer.modelOffset);
|
||||
DicConsole.DebugWriteLine("SuperCardPro plugin", "footer.serialOffset = 0x{0:X8}", footer.serialOffset);
|
||||
DicConsole.DebugWriteLine("SuperCardPro plugin", "footer.creatorOffset = 0x{0:X8}", footer.creatorOffset);
|
||||
DicConsole.DebugWriteLine("SuperCardPro plugin", "footer.applicationOffset = 0x{0:X8}", footer.applicationOffset);
|
||||
DicConsole.DebugWriteLine("SuperCardPro plugin", "footer.commentsOffset = 0x{0:X8}", footer.commentsOffset);
|
||||
DicConsole.DebugWriteLine("SuperCardPro plugin", "footer.creationTime = {0}", footer.creationTime);
|
||||
DicConsole.DebugWriteLine("SuperCardPro plugin", "footer.modificationTime = {0}", footer.modificationTime);
|
||||
DicConsole.DebugWriteLine("SuperCardPro plugin", "footer.applicationVersion = {0}.{1}", (footer.applicationVersion & 0xF0) >> 4, footer.applicationVersion & 0xF);
|
||||
DicConsole.DebugWriteLine("SuperCardPro plugin", "footer.hardwareVersion = {0}.{1}", (footer.hardwareVersion & 0xF0) >> 4, footer.hardwareVersion & 0xF);
|
||||
DicConsole.DebugWriteLine("SuperCardPro plugin", "footer.firmwareVersion = {0}.{1}", (footer.firmwareVersion & 0xF0) >> 4, footer.firmwareVersion & 0xF);
|
||||
DicConsole.DebugWriteLine("SuperCardPro plugin", "footer.imageVersion = {0}.{1}", (footer.imageVersion & 0xF0) >> 4, footer.imageVersion & 0xF);
|
||||
DicConsole.DebugWriteLine("SuperCardPro plugin", "footer.signature = \"{0}\"", StringHandlers.CToString(BitConverter.GetBytes(footer.signature)));
|
||||
|
||||
ImageInfo.driveManufacturer = ReadPStringUTF8(stream, footer.manufacturerOffset);
|
||||
ImageInfo.driveModel = ReadPStringUTF8(stream, footer.modelOffset);
|
||||
ImageInfo.driveSerialNumber = ReadPStringUTF8(stream, footer.serialOffset);
|
||||
ImageInfo.imageCreator = ReadPStringUTF8(stream, footer.creatorOffset);
|
||||
ImageInfo.imageApplication = ReadPStringUTF8(stream, footer.applicationOffset);
|
||||
ImageInfo.imageComments = ReadPStringUTF8(stream, footer.commentsOffset);
|
||||
|
||||
DicConsole.DebugWriteLine("SuperCardPro plugin", "ImageInfo.driveManufacturer = \"{0}\"", ImageInfo.driveManufacturer);
|
||||
DicConsole.DebugWriteLine("SuperCardPro plugin", "ImageInfo.driveModel = \"{0}\"", ImageInfo.driveModel);
|
||||
DicConsole.DebugWriteLine("SuperCardPro plugin", "ImageInfo.driveSerialNumber = \"{0}\"", ImageInfo.driveSerialNumber);
|
||||
DicConsole.DebugWriteLine("SuperCardPro plugin", "ImageInfo.imageCreator = \"{0}\"", ImageInfo.imageCreator);
|
||||
DicConsole.DebugWriteLine("SuperCardPro plugin", "ImageInfo.imageApplication = \"{0}\"", ImageInfo.imageApplication);
|
||||
DicConsole.DebugWriteLine("SuperCardPro plugin", "ImageInfo.imageComments = \"{0}\"", ImageInfo.imageComments);
|
||||
|
||||
if(footer.creationTime != 0)
|
||||
ImageInfo.imageCreationTime = DateHandlers.UNIXToDateTime(footer.creationTime);
|
||||
else
|
||||
ImageInfo.imageCreationTime = imageFilter.GetCreationTime();
|
||||
|
||||
if(footer.modificationTime != 0)
|
||||
ImageInfo.imageLastModificationTime = DateHandlers.UNIXToDateTime(footer.modificationTime);
|
||||
else
|
||||
ImageInfo.imageLastModificationTime = imageFilter.GetLastWriteTime();
|
||||
|
||||
DicConsole.DebugWriteLine("SuperCardPro plugin", "ImageInfo.imageCreationTime = {0}", ImageInfo.imageCreationTime);
|
||||
DicConsole.DebugWriteLine("SuperCardPro plugin", "ImageInfo.imageLastModificationTime = {0}", ImageInfo.imageLastModificationTime);
|
||||
|
||||
ImageInfo.imageApplicationVersion =
|
||||
string.Format("{0}.{1}", (footer.applicationVersion & 0xF0) >> 4, footer.applicationVersion & 0xF);
|
||||
ImageInfo.driveFirmwareRevision =
|
||||
string.Format("{0}.{1}", (footer.firmwareVersion & 0xF0) >> 4, footer.firmwareVersion & 0xF);
|
||||
ImageInfo.imageVersion =
|
||||
string.Format("{0}.{1}", (footer.imageVersion & 0xF0) >> 4, footer.imageVersion & 0xF);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
stream.Seek(-8, SeekOrigin.Current);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ImageInfo.imageApplication = "SuperCardPro";
|
||||
ImageInfo.imageApplicationVersion =
|
||||
string.Format("{0}.{1}", (header.version & 0xF0) >> 4, header.version & 0xF);
|
||||
ImageInfo.imageCreationTime = imageFilter.GetCreationTime();
|
||||
ImageInfo.imageLastModificationTime = imageFilter.GetLastWriteTime();
|
||||
ImageInfo.imageVersion = "1.5";
|
||||
}
|
||||
|
||||
throw new NotImplementedException("Flux decoding is not yet implemented.");
|
||||
}
|
||||
|
||||
string ReadPStringUTF8(Stream stream, uint position)
|
||||
{
|
||||
if(position == 0)
|
||||
return null;
|
||||
|
||||
stream.Position = position;
|
||||
byte[] len_b = new byte[2];
|
||||
stream.Read(len_b, 0, 2);
|
||||
ushort len = BitConverter.ToUInt16(len_b, 0);
|
||||
|
||||
if(len == 0 || len + stream.Position >= stream.Length)
|
||||
return null;
|
||||
|
||||
byte[] str = new byte[len];
|
||||
stream.Read(str, 0, len);
|
||||
|
||||
return Encoding.UTF8.GetString(str);
|
||||
}
|
||||
|
||||
public override bool ImageHasPartitions()
|
||||
{
|
||||
return ImageInfo.imageHasPartitions;
|
||||
|
||||
@@ -10,9 +10,18 @@ v1.4 - 11/21/14
|
||||
|
||||
* Redefined the HEADS definition and added it to BYTE $000A in IFF defines.
|
||||
|
||||
v1.5 - 01/12/16
|
||||
|
||||
* Extended track range. This should not affect any programs using .scp image files
|
||||
that followed the guidelines.
|
||||
|
||||
v1.6 - 12/05/17
|
||||
|
||||
* Added extension footer, courtesy of Natalia Portillo.
|
||||
|
||||
--------------------------------------------------------------------------------------
|
||||
|
||||
This information is copyright (C) 2012-2014 By Jim Drew. Permissions is granted
|
||||
This information is copyright (C) 2012-2017 By Jim Drew. Permissions is granted
|
||||
for inclusion with any source code when keeping this copyright notice.
|
||||
|
||||
======================================================================================
|
||||
@@ -34,7 +43,9 @@ then the file is not ours.
|
||||
|
||||
BYTE 0x03 is the version/revision as a byte. This is encoded as (Version<<4|Revision),
|
||||
so that 0x39= version 3.9 of the format. This is the version number of the SCP imaging
|
||||
software that created this image.
|
||||
software that created this image. If bit 5 (FOOTER) of the FLAGS (byte 0x08) is set,
|
||||
this byte will be zero, and you are required to use the version and name entries in the
|
||||
extension footer.
|
||||
|
||||
BYTE 0x04 is the disk type and represents the type of disk for the image (see disk types
|
||||
in the defines).
|
||||
@@ -63,6 +74,9 @@ Bit 3 - TYPE, cleared for preservation quality image
|
||||
Bit 4 - MODE, cleared if the image is read-only
|
||||
set if the image is read/write capable
|
||||
|
||||
Bit 5 - FOOTER, cleared if the image does not contain an extension footer
|
||||
set if the image contains an extension footer
|
||||
|
||||
FLAGS bit 0 is used to determine when the reading of flux data started. If this bit is
|
||||
set then the flux data was read immediately after the index pulse was detected. If
|
||||
this bit is clear then the flux data was read starting at some random location on the
|
||||
@@ -84,6 +98,9 @@ images will be read-only (write protected) for emulation usage. The read/write
|
||||
images contain padded space to allow the track to change size within the image. Only a
|
||||
single revolution is allowed when the TYPE bit is set (read/write capable).
|
||||
|
||||
FLAGS bit 5 is used to determine the presence of an extension footer after the end of
|
||||
the image.
|
||||
|
||||
BYTE 0x09 is the width of the bit cell time. Normally this is always 0 which means
|
||||
16 bits wide, but if the value is non-zero then it represents the number of bits for
|
||||
each bit cell entry. For example, if this byte was set to 8, then each bit cell entry
|
||||
@@ -102,12 +119,12 @@ end of the image file. Checksum is standard addition, with a wrap beyond 32 bit
|
||||
rolling over. A value of 0x00000000 is used when FLAGS bit 4 (MODE) is set, as no checksum
|
||||
is calculated for read/write capable images.
|
||||
|
||||
BYTES 0x10-0x2A7 are a table of longwords with each entry being a offset to a Track Data
|
||||
BYTES 0x10-0x2AF are a table of longwords with each entry being a offset to a Track Data
|
||||
Header (TDH) for each track that is stored in the image. The table is always sequential.
|
||||
There is an entry for every track, with up to 166 tracks supported. This means that disk
|
||||
images of up to 83 tracks with sides 0/1 are possible. If no flux data for a track is
|
||||
There is an entry for every track, with up to 168 tracks supported. This means that disk
|
||||
images of up to 84 tracks with sides 0/1 are possible. If no flux data for a track is
|
||||
present, then the entry will contain a longword of zeros (0x00000000). The 1st TDH
|
||||
will probably start at offset 0x000002A8, but could technically start anywhere in the file
|
||||
will probably start at offset 0x000002B0, but could technically start anywhere in the file
|
||||
because all entries are offset based, so track data does not have to be in any order. This
|
||||
was done so you could append track data to the file and change the header to point to the
|
||||
appended data. For simplicity it is recommended that you follow the normal image format
|
||||
@@ -174,10 +191,90 @@ offset based. For simplicity, please try to keep the revolutions sequential. S
|
||||
Pro's imaging software always stores the revolutions sequentially.
|
||||
|
||||
|
||||
After the last byte of flux data there will be a timestamp. This timestamp is an
|
||||
ASCII string, ie: 1/05/2014 5:15:21 PM
|
||||
TIMESTAMP INFORMATION
|
||||
----------------------------
|
||||
|
||||
After the last byte of flux data there will be a timestamp. This timestamp is an ASCII
|
||||
string, ie: 1/05/2014 5:15:21 PM. Some implementations are known not to write it, so
|
||||
its presence is not guaranteed. Also its format depends on the region settings of the
|
||||
user that created the image. If the footer is present, implementations are required to
|
||||
use the timestamps on it.
|
||||
|
||||
|
||||
EXTENSION FOOTER INFO:
|
||||
----------------------------
|
||||
The extension footer contains some metadata describing the contents and origins of the
|
||||
disk image. Its presence is indicated by setting bit 5 of the FLAGS (byte 0x08). Fields
|
||||
and their meanings will not be modified by future versions of the image format, only
|
||||
expanded prepending new fields to the existing ones. This way, software can safely
|
||||
ignore any new fields.
|
||||
|
||||
The extension footer, and any of the data its offsets point to, will always start
|
||||
after all of track data and the ASCII timestamp. Since ASCII text characters have a
|
||||
value of 0x30 to 0x5F, it is safe to assume that if the first byte after the track data
|
||||
is not a valid ASCII value, that no timestamp is actually included (some apps using SCP
|
||||
format elected not to include a timestamp). This first byte would be the start of the
|
||||
extension footer data.
|
||||
|
||||
All offsets are relative to the start of the image file, and all strings they point to
|
||||
are to be stored as null-terminated UTF-8 format, prefixed with a 16-bit little-endian
|
||||
length in bytes not counting itself or the null-termination.
|
||||
E.g.: "My app" => 0x06 0x00 0x4D 0x79 0x20 0x97 0x70 0x70 0x00
|
||||
|
||||
Because localization makes the ASCII timestamp be different depending on language and
|
||||
location user settings when creating an image, timestamps in the footer must be stored
|
||||
as a little-endian signed 64-bit count of seconds since 1st January 1970 00:00:00 in UTC.
|
||||
|
||||
BYTES 0x00-0x03 contains the offset from the start of the file where the null-terminated
|
||||
UTF-8 string containing the drive manufacturer is stored. If the value is 0, the string
|
||||
is not present in the file.
|
||||
|
||||
BYTES 0x04-0x07 contains the offset from the start of the file where the null-terminated
|
||||
UTF-8 string containing the drive model is stored. If the value is 0, the string is not
|
||||
present in the file.
|
||||
|
||||
BYTES 0x08-0x0B contains the offset from the start of the file where the null-terminated
|
||||
UTF-8 string containing the drive serial number is stored. If the value is 0, the string
|
||||
is not present in the file.
|
||||
|
||||
BYTES 0x0C-0x0F contains the offset from the start of the file where the null-terminated
|
||||
UTF-8 string containing the name of the user is stored. If the value is 0, the string is
|
||||
not present in the file.
|
||||
|
||||
BYTES 0x10-0x13 contains the offset from the start of the file where the null-terminated
|
||||
UTF-8 string containing the name of the application that created this image is stored.
|
||||
Applications supporting any version of this footer are required to store their name in
|
||||
this footer. If the value is 0, the string is not present in the file.
|
||||
|
||||
BYTES 0x14-0x17 contains the offset from the start of the file where the null-terminated
|
||||
UTF-8 string containing the user comments is stored. If the value is 0, the string is not
|
||||
present in the file.
|
||||
|
||||
BYTES 0x18-0x1F contains the little-endian signed 64-bit count of seconds since
|
||||
1st January 1970 00:00:00 in UTC corresponding to the date and time when the image was
|
||||
created.
|
||||
|
||||
BYTES 0x20-0x27 contains the little-endian signed 64-bit count of seconds since
|
||||
1st January 1970 00:00:00 in UTC corresponding to the date and time when the image was
|
||||
last modified (e.g. adding this footer to old images, or adding new fields to this footer).
|
||||
|
||||
BYTE 0x28 is the version/subversion of the application that created this image as a byte.
|
||||
This is encoded as (Version<<4|Subversion), so that 0x15= version 1.5 of the application.
|
||||
|
||||
BYTE 0x29 is the version/revision of the SuperCardPro hardware as returned by the get
|
||||
info command. This is encoded as (Version<<4|Revision), so that 0x15= version 1.5 of the
|
||||
SuperCardPro hardware.
|
||||
|
||||
BYTE 0x2A is the version/revision of the SuperCardPro firmware as returned by the get
|
||||
info command. This is encoded as (Version<<4|Revision), so that 0x11= version 1.2 of the
|
||||
SuperCardPro firmware.
|
||||
|
||||
BYTE 0x2B is the revision of this format. This is encoded as (Version<<4|Revision), so
|
||||
currently it must be 0x16. Whenever the format is expanded, this revision will increase.
|
||||
Applications that encounter a revision higher than the last they know should treat the
|
||||
footer as they would with a known version.
|
||||
|
||||
BYTES 0x2C-0x2F contains the ASCII of "FPCS" as the last 4 bytes of the file.
|
||||
|
||||
; ------------------------------------------------------------------
|
||||
; SCP IMAGE FILE FORMAT
|
||||
@@ -212,11 +309,28 @@ ASCII string, ie: 1/05/2014 5:15:21 PM
|
||||
; 0014 OFFSET TO 2nd TRACK DATA HEADER (4 bytes of 0 if track is skipped)
|
||||
; 0018 OFFSET TO 3rd TRACK DATA HEADER (4 bytes of 0 if track is skipped)
|
||||
; ....
|
||||
; 02A4 OFFSET TO 166th TRACK DATA HEADER (4 bytes of 0 if track is skipped)
|
||||
; 02A8 TYPICAL START OF 1st TRACK DATA HEADER (always the case with SCP created images)
|
||||
; 02AC OFFSET TO 168th TRACK DATA HEADER (4 bytes of 0 if track is skipped)
|
||||
; 02B0 TYPICAL START OF 1st TRACK DATA HEADER (always the case with SCP created images)
|
||||
;
|
||||
; .... END OF TRACK DATA
|
||||
; ???? TIMESTAMP (AS ASCII STRING - ie. 7/17/2013 12:45:49 PM)
|
||||
;
|
||||
; Start of extension footer
|
||||
;
|
||||
; ???? OFFSET TO DRIVE MANUFACTURER STRING (optional)
|
||||
; ???? OFFSET TO DRIVE MODEL STRING (optional)
|
||||
; ???? OFFSET TO DRIVE SERIAL NUMBER STRING (optional)
|
||||
; ???? OFFSET TO CREATOR STRING (optional)
|
||||
; ???? OFFSET TO APPLICATION NAME STRING (optional)
|
||||
; ???? OFFSET TO COMMENTS (optional)
|
||||
; ???? UTC TIME/DATE OF IMAGE CREATION
|
||||
; ???? UTC TIME/DATE OF IMAGE MODIFICATION
|
||||
; ???? VERSION/SUBVERSION OF APPLICATION THAT CREATED IMAGE
|
||||
; ???? VERSION/SUBVERSION OF SUPERCARD PRO HARDWARE
|
||||
; ???? VERSION/SUBVERSION OF SUPERCARD PRO FIRMWARE
|
||||
; ???? VERSION/SUBVERSION OF THIS IMAGE FORMAT
|
||||
; ???? ASCII 'FPCS'
|
||||
|
||||
|
||||
; ## FILE FORMAT DEFINES ##
|
||||
|
||||
@@ -232,7 +346,7 @@ IFF_HEADS = 0x0A ; 0=both heads are in image, 1=side 0 only, 2
|
||||
IFF_RSRVED = 0x0B ; reserved space
|
||||
IFF_CHECKSUM = 0x0C ; 32 bit checksum of data added together starting at 0x0010 through EOF
|
||||
IFF_THDOFFSET = 0x10 ; first track data header offset
|
||||
IFF_THDSTART = 0x2A8 ; start of first Track Data Header
|
||||
IFF_THDSTART = 0x2B0 ; start of first Track Data Header
|
||||
|
||||
; FLAGS BIT DEFINES (BIT NUMBER)
|
||||
|
||||
@@ -241,14 +355,15 @@ FB_TPI = 0x01 ; clear = drive is 48TPI, set = drive is 96TP
|
||||
FB_RPM = 0x02 ; clear = drive is 300 RPM drive, set = drive is 360 RPM drive
|
||||
FB_TYPE = 0x03 ; clear = image is has original flux data, set = image is flux data that has been normalized
|
||||
FB_MODE = 0x04 ; clear = image is read-only, set = image is read/write capable
|
||||
FB_FOOTER = 0x05 ; clear = image does not contain a footer, set = image contains a footer at the end of it
|
||||
|
||||
; MANUFACTURERS 7654 3210
|
||||
man_CBM = 0x00 ; 0000 xxxx
|
||||
man_Atari = 0x10 ; 0001 xxxx
|
||||
man_Apple = 0x20 ; 0010 xxxx
|
||||
man_PC = 0x40 ; 0011 xxxx
|
||||
man_Tandy = 0x21 ; 0100 xxxx
|
||||
man_TI = 0x40 ; 0101 xxxx
|
||||
man_PC = 0x30 ; 0011 xxxx
|
||||
man_Tandy = 0x40 ; 0100 xxxx
|
||||
man_TI = 0x50 ; 0101 xxxx
|
||||
man_Roland = 0x60 ; 0110 xxxx
|
||||
|
||||
; DISK TYPE BIT DEFINITIONS
|
||||
@@ -280,8 +395,8 @@ disk_PC144M = 0x03 ; xxxx 0011
|
||||
; TANDY DISK TYPES
|
||||
disk_TRS80SSSD = 0x00 ; xxxx 0000
|
||||
disk_TRS80SSDD = 0x01 ; xxxx 0001
|
||||
disk_TRS80DSSD = 0x10 ; xxxx 0010
|
||||
disk_TRS80DSDD = 0x11 ; xxxx 0011
|
||||
disk_TRS80DSSD = 0x02 ; xxxx 0010
|
||||
disk_TRS80DSDD = 0x03 ; xxxx 0011
|
||||
|
||||
; TI DISK TYPES
|
||||
disk_TI994A = 0x00 ; xxxx 0000
|
||||
@@ -347,6 +462,20 @@ TDH_DURATION = 0x4 ; duration of track, from index pulse to inde
|
||||
TDH_LENGTH = 0x08 ; length of track (1st revolution)
|
||||
TDH_OFFSET = 0x0C ; offset to flux data from start of TDH (1st revolution)
|
||||
|
||||
|
||||
|
||||
|
||||
; ------------------------------------------------------------------
|
||||
; EXTENSION FOOTER FORMAT
|
||||
; ------------------------------------------------------------------
|
||||
;
|
||||
; 0000 DRIVE MANUFACTURER STRING OFFSET - 4 bytes
|
||||
; 0004 DRIVE MODEL STRING OFFSET - 4 bytes
|
||||
; 0008 DRIVE SERIAL NUMBER STRING OFFSET - 4 bytes
|
||||
; 000C CREATOR STRING OFFSET - 4 bytes
|
||||
; 0010 APPLICATION NAME STRING OFFSET - 4 bytes
|
||||
; 0014 COMMENTS STRING OFFSET - 4 bytes
|
||||
; 0018 IMAGE CREATION TIMESTAMP - 8 bytes
|
||||
; 0020 IMAGE MODIFICATION TIMESTAMP - 8 bytes
|
||||
; 0028 APPLICATION VERSION (nibbles major/minor) - 1 byte
|
||||
; 0029 SCP HARDWARE VERSION (nibbles major/minor) - 1 byte
|
||||
; 002A SCP FIRMWARE VERSION (nibbles major/minor) - 1 byte
|
||||
; 002B IMAGE FORMAT REVISION (nibbles major/minor) - 1 byte
|
||||
; 002C 'FPCS' (ASCII CHARS) - 4 bytes
|
||||
|
||||
173
templates/SCP.bt
Normal file
173
templates/SCP.bt
Normal file
@@ -0,0 +1,173 @@
|
||||
//------------------------------------------------
|
||||
//--- 010 Editor v7.0 Binary Template
|
||||
//
|
||||
// File: SCP.bt
|
||||
// Authors: Vasyl Tsvirkunov
|
||||
// Natalia Portillo
|
||||
// Version: 0.3
|
||||
// Purpose: SuperCard Pro dump file format
|
||||
// based on official format document.
|
||||
// Category: Misc
|
||||
// File Mask: *.scp
|
||||
// ID Bytes: 53 43 50 //SCP
|
||||
// History:
|
||||
// 0.3 2017-12-05 Natalia Portillo: Updated for v1.6 file format
|
||||
// 0.2 2016-03-29 Vasyl Tsvirkunov: Updated for v7 compliancy
|
||||
// 0.1 2014-11-08 Vasyl Tsvirkunov: Initial release
|
||||
//------------------------------------------------
|
||||
|
||||
LittleEndian();
|
||||
|
||||
char signature[3];
|
||||
byte version <read=ReadVersion>;
|
||||
|
||||
string ReadVersion(byte& v)
|
||||
{
|
||||
string s;
|
||||
SPrintf(s, "%d.%d", v>>4, v&0x0f);
|
||||
return s;
|
||||
}
|
||||
|
||||
enum <unsigned byte> DiskType
|
||||
{
|
||||
disk_C64 = 0x00,
|
||||
disk_Amiga = 0x04,
|
||||
disk_AtariFMSS = 0x10,
|
||||
disk_AtariFMDS = 0x11,
|
||||
disk_AtariFMEx = 0x12,
|
||||
disk_AtariSTSS = 0x14,
|
||||
disk_AtariSTDS = 0x15,
|
||||
disk_AppleII = 0x20,
|
||||
disk_AppleIIPro = 0x21,
|
||||
disk_Apple400K = 0x24,
|
||||
disk_Apple800K = 0x25,
|
||||
disk_Apple144 = 0x26,
|
||||
disk_PC360K = 0x30,
|
||||
disk_PC720K = 0x31,
|
||||
disk_PC12M = 0x32,
|
||||
disk_PC144M = 0x33,
|
||||
disk_TRS80SSSD = 0x40,
|
||||
disk_TRS80SSDD = 0x41,
|
||||
disk_TRS80DSSD = 0x42,
|
||||
disk_TRS80DSDD = 0x43,
|
||||
disk_TI994A = 0x50,
|
||||
disk_D20 = 0x60
|
||||
};
|
||||
|
||||
DiskType disk_type;
|
||||
|
||||
byte revolutions;
|
||||
unsigned byte start_track;
|
||||
unsigned byte end_track;
|
||||
|
||||
unsigned byte flags <read=ReadFlags>;
|
||||
|
||||
string ReadFlags(unsigned byte f)
|
||||
{
|
||||
string s;
|
||||
SPrintf(s, "%s, %s, %s, %s, %s, %s",
|
||||
f & 0x01 ? "flux data starts at index" : "no index reference",
|
||||
f & 0x02 ? "96TPI" : "48TPI",
|
||||
f & 0x04 ? "360 RPM" : "300 RPM",
|
||||
f & 0x08 ? "normalized flux" : "original flux data",
|
||||
f & 0x10 ? "read/write" : "read only",
|
||||
f & 0x20 ? "has footer" : "has no footer");
|
||||
return s;
|
||||
}
|
||||
|
||||
byte cell_width;
|
||||
byte number_of_heads;
|
||||
byte reserved;
|
||||
long checksum;
|
||||
|
||||
long track_offset[end_track-start_track+1];
|
||||
|
||||
typedef struct
|
||||
{
|
||||
long duration;
|
||||
long cell_count;
|
||||
long offset;
|
||||
} RevInfo;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char signature[3];
|
||||
unsigned byte track_num;
|
||||
RevInfo rev_info[revolutions];
|
||||
} TrackHeader;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
BigEndian(); // sic!
|
||||
if(cell_width == 0 || cell_width == 16)
|
||||
short flux[track_header.rev_info[rev].cell_count];
|
||||
else
|
||||
byte flux[track_header.rev_info[rev].cell_count];
|
||||
LittleEndian();
|
||||
} FluxData;
|
||||
|
||||
local int track, rev;
|
||||
for(track=0; track<end_track-start_track+1; track++)
|
||||
{
|
||||
FSeek(track_offset[track]);
|
||||
TrackHeader track_header;
|
||||
|
||||
for(rev=0; rev<revolutions; rev++)
|
||||
{
|
||||
FSeek(track_offset[track]+track_header.rev_info[rev].offset);
|
||||
FluxData flux;
|
||||
}
|
||||
}
|
||||
|
||||
local long timestampPosition = FTell();
|
||||
local long footerPosition = 0;
|
||||
|
||||
wstring ReadPStringUTF8(uint pos)
|
||||
{
|
||||
FSeek(pos);
|
||||
ushort strLen = ReadUShort();
|
||||
char str[] = ReadString(pos + 2, strLen);
|
||||
return StringToWString(str, CHARSET_UTF8);
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint manufacturer <read=ReadPStringUTF8>;
|
||||
uint model <read=ReadPStringUTF8>;
|
||||
uint serial <read=ReadPStringUTF8>;
|
||||
uint creator <read=ReadPStringUTF8>;
|
||||
uint application <read=ReadPStringUTF8>;
|
||||
uint comments <read=ReadPStringUTF8>;
|
||||
time_t creationTime;
|
||||
uint ctime_2038;
|
||||
time_t modificationTime;
|
||||
uint mtime_2038;
|
||||
byte applicationVersion <read=ReadVersion>;
|
||||
byte hardwareVersion <read=ReadVersion>;
|
||||
byte firmwareVersion <read=ReadVersion>;
|
||||
byte imageVersion <read=ReadVersion>;
|
||||
char footerMagic[4];
|
||||
} Footer;
|
||||
|
||||
local uint footerSignature = 0x53435046;
|
||||
|
||||
if(flags & 0x20)
|
||||
{
|
||||
FSeek(FileSize() - 4);
|
||||
local int foo;
|
||||
for(foo = 0;FTell() > timestampPosition; FSkip(-4))
|
||||
{
|
||||
local uint sig = ReadUInt();
|
||||
if(sig == footerSignature)
|
||||
{
|
||||
FSkip(-44);
|
||||
footerPosition = FTell();
|
||||
Footer footer;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
string timestamp;
|
||||
}
|
||||
Reference in New Issue
Block a user