diff --git a/Documentation/Changes.txt b/Documentation/Changes.txt
index 470cf2a..72fa3d7 100755
--- a/Documentation/Changes.txt
+++ b/Documentation/Changes.txt
@@ -884,6 +884,43 @@ Bug fixes
* A failed delete, or the user clicking on 'No' to confirm a deletion, would leave the confirmation window open until it was a successful delete, or the user clicked 'Yes'.
* The configuration option to compress UEF images did not get saved to the registry.
+1.44 - 18th December 2022
+-------------------------
+New or improved features
+* Added a new class for accessing the registry.
+* Added an option, when creating ADFS hard drive images, to add the 512-byte 'emulator header'.
+* Changed some of the internal procedures so that they return a Boolean, instead of a structure, to make it easier to add multi-partition support.
+* MMFS support has been temporarily removed.
+* Added an option, when creating ADFS hard drive images, whether it will be an IDE drive or not. This fixes an issue where the resultant drive could not be read by RISC OS 3.11 in Arculator.
+* ADFS Directories which have not been read in for reasons other than the flag not being set, are now reported as broken.
+* ADFS broken directory error codes have been expanded. Now checks for non-sector aligned directories, invalid Start or End names (i.e. not 'Hugo' or 'Nick'), and any other reason it is found to be broken.
+* When adding multiple files to an image, no format checking is done and the files are just added.
+* When adding directories to an image, the progress indicator is shown.
+* When IDing DFS images, any image over 400KB (200KB double sided) is rejected.
+* Added the address of the file to the CSV output.
+* Extra range checking when updating ADFS New Map fragments, and if any part fails, the original is restored from the backup.
+* Moved the 'Waiting' and 'Progress Update' labels on the Progress dialogue window.
+* Performed some code optimisation on ADFS New Map.
+* Writing objects to ADFS New Map will now create, or re-use, shared fragments.
+* When outputting a CSV file of the contents, a dialogue box is now presented to select which columns, with some options, are to be included.
+* CSV output now prefixes all hex numbers with '0x' for easier importing into Excel/Numbers/etc.
+* Added 'Show Report' button and window.
+* Image report can also be included in the CSV output.
+* ADFS Hardware information is now saved into hard drive images (ADFS New Map).
+
+Bug fixes
+* In ADFS and Acorn FS, if a file had the same sector as the root then the filename would be blank. This would usually happen with New Map ADFS (usually an 'E' floppy) where the root was addressed directly, but the files were addressed indirectly.
+* Changing time/date on a file now updates the 'unsaved' icon in the status bar.
+* Some ADFS New Map fragment IDs were being used more than once, so the checking on unique IDs has been tightened up.
+* The ADFS disc size was being read in as the root size.
+* The heads and sectors per track fields were not being read in with ADFS New Map.
+* Sometimes the root on ADFS New Map was not being found, so this has been improved.
+* Renaming a directory in ADFS caused issues when then adding files to it as it kept it's old name.
+* Sometimes when writing a file on ADFS New Map, two (or more) files would have the same indirect address (fragment ID).
+* When writing a file to ADFS New Map, the end of free space marker on a zone would be beyond the zone and trample the following zone. When subsequent files where then written, this would continue into the following zone(s).
+* On ADFS New Map, the free space would sometimes be incorrectly reported meaning that some files were stored where there was not enough space to store the file.
+* On ADFS New Map, the smallest possible space to contain a fragment ID and the stop bit was not taken into consideration, meaning that a file stored could then not be retrieved.
+* Some ADFS New and Big directory object's attributes, that only had a single attribute, where having '00' appended to the end.
Platform History
----------------
diff --git a/Documentation/Disc Image Manager User Guide.docx b/Documentation/Disc Image Manager User Guide.docx
index 041c178..3b14f19 100644
Binary files a/Documentation/Disc Image Manager User Guide.docx and b/Documentation/Disc Image Manager User Guide.docx differ
diff --git a/Documentation/Disc Image Manager User Guide.pdf b/Documentation/Disc Image Manager User Guide.pdf
index de8de8b..b1aa514 100644
Binary files a/Documentation/Disc Image Manager User Guide.pdf and b/Documentation/Disc Image Manager User Guide.pdf differ
diff --git a/Documentation/Guide To Disc Formats.pdf b/Documentation/Guide To Disc Formats.pdf
index 7a8af19..9250839 100644
Binary files a/Documentation/Guide To Disc Formats.pdf and b/Documentation/Guide To Disc Formats.pdf differ
diff --git a/Documentation/ToDo.txt b/Documentation/ToDo.txt
index cd4b812..7f5db05 100644
--- a/Documentation/ToDo.txt
+++ b/Documentation/ToDo.txt
@@ -4,18 +4,19 @@ In no particular order
Bugs
* Scaling - there is a report that icons 'grow' on scaled screens. I have been unable to reproduce this.
- + This appears to happen on Windows (and probably Linux), with single screen only (dual or more it does not do this), resolution of 1400 by anything (or more), and scaled to more than 100%. The icons in the Directory Listing grow as the mouse moves. - TO BE TESTED
+ + This appears to happen on Windows (and probably Linux), with single screen only (dual or more it does not do this), resolution of 1400 by anything (or more), and scaled to more than 100%. The icons in the Directory Listing grow as the mouse moves. - UNABLE TO REPLICATE. This may have been fixed by the upgrade to Lazarus 2.2.0.
* 'Bad FS Map' from BeebEm when loading an ADFS/AFS hybrid image after making a change to the ADFS partition. - UNABLE TO REPLICATE
-* Some SS DFS images are IDed as DS images when 'Allow zero sectors' is selected in the preferences.
+* Some SS DFS images are IDed as DS images when 'Allow zero sectors' is selected in the preferences. - UNABLE TO REPLICATE
* Access violation has been reported when creating an ADFS HDD image (default options) on Windows. - UNABLE TO REPLICATE
* Does not work on Windows 11. - UNABLE TO REPLICATE
-* Changing time/date on a file does not update the 'unsaved' icon in the status bar.
-General
+General - Ideas, currently unlikely to be added
* Drag and Drop facilities out of the application...currently looking unlikely for cross platform. This will need to be done using 'code-per-platform' directives.
* Extend drag and drop copy/move to multiple selection.
* Application to application communications.
* Copy entire files onto clipboard? And then paste from clipboard? - as Drag and Drop, this will need to be done using 'code-per-platform' directives.
+
+General - Ideas which are maybe possible
* Ask to force overwrite if many files are getting written.
* Export the contents of an open image to another image, or set of images if the selected format is too small or are more directory entries than the format allows.
* Cancel button for progress display?
@@ -23,25 +24,16 @@ General
* For macOS, change the settings being saved to the registry to being saved in a plist file, or within the application directory itself.
* Ablity to add/remove/delete partitions using the command line.
* Allow for multiple (>2) partitions - i.e. two or more DOS partitions on an ADFS structure, or ADFS/AFS/DOS hybrid.
-
-DFS
-
-ADFS
-* Import an existing AFS or DOS image into ADFS as a new partition (importing DOS image as parition is as easy as just adding a DOS Image file).
-
-AFS
-* AFS0 images do not get created correctly (in particular the free space allocation maps) - AWAITING MORE INFO ON AFS FORMATS.
-* Add option to new Level 3 images for pre-1988 or post-1988 format - AWAITING MORE INFO ON AFS FORMATS.
-* When extracting the AFS partition, remove the ADFS partition and re-address all the objects, instead of just blanking out the ADFS part - IN PROGRESS.
-
-Amiga
-
-Spectrum/Amstrad
-* Write entire module - REQUIRE MORE INFO ON SPECTRUM FORMAT.
-
-MMFS
-* Rewrite/rethink entire MMFS idea. Possibly remove from Disc Image Manager.
-
-SparkFS
-
-DOS Plus
\ No newline at end of file
+* ADFS: When a DOS image file is added to an ADFS image (and the "Open DOS Partition" setting is set), automatically open as the second partition (if there isn't one already).
+* AFS: AFS0 images do not get created correctly (in particular the free space allocation maps) - AWAITING MORE INFO ON AFS FORMATS.
+* AFS: Add option to new Level 3 images for pre-1988 or post-1988 format - AWAITING MORE INFO ON AFS FORMATS.
+* AFS: When extracting the AFS partition, remove the ADFS partition and re-address all the objects, instead of just blanking out the ADFS part - IN PROGRESS.
+* Amiga: Add in support for Rigid Disks (multi-partition hard discs) - NEED TO IMPLEMENT MULTI-PARTITION SUPPORT FIRST.
+* Amiga: Add in support for Professional File System - AWAITING FORMAT DETAILS AND SAMPLE(S).
+* Amiga: Add in support for Smart File System - AWAITING SAMPLE(S).
+* Spectrum/Amstrad: Write entire module - REQUIRE MORE INFO ON SPECTRUM FORMAT.
+* MMFS: Rewrite/rethink entire MMFS idea - might be more viable once multi-partitions are implemented.
+* DOS: Add in support for partitioned hard drive images - NEED TO IMPLEMENT MULTI_PARTITION SUPPORT FIRST.
+* Have different TImageList components for each format.
+* File Viewer: ability to export contents in a different format (e.g. BASIC -> Text, or Sprite -> PNG).
+* Function to check every file and directory on a volume and produce a report detailing number of files with error (CRC32) and number of broken directories (ADFS), and list them, with option to save to a text file.
\ No newline at end of file
diff --git a/Graphics/Buttons/Show Report/Show Report.png b/Graphics/Buttons/Show Report/Show Report.png
new file mode 100755
index 0000000..d352f2a
Binary files /dev/null and b/Graphics/Buttons/Show Report/Show Report.png differ
diff --git a/Graphics/Misc/Marble_Tile.png b/Graphics/Misc/Marble_Tile.png
new file mode 100644
index 0000000..49a4318
Binary files /dev/null and b/Graphics/Misc/Marble_Tile.png differ
diff --git a/LazarusSource/.DS_Store b/LazarusSource/.DS_Store
new file mode 100644
index 0000000..5008ddf
Binary files /dev/null and b/LazarusSource/.DS_Store differ
diff --git a/LazarusSource/AboutUnit.lfm b/LazarusSource/AboutUnit.lfm
index b205c0d..87b01cf 100755
--- a/LazarusSource/AboutUnit.lfm
+++ b/LazarusSource/AboutUnit.lfm
@@ -76,7 +76,7 @@ object AboutForm: TAboutForm
Align = alTop
Alignment = taCenter
BorderSpacing.Bottom = 4
- Caption = 'http://www.geraldholdsworth.co.uk'
+ Caption = 'https://www.geraldholdsworth.co.uk'
Font.Color = clNavy
Font.Height = -16
Font.Name = 'Tahoma'
diff --git a/LazarusSource/CSVPrefUnit.lfm b/LazarusSource/CSVPrefUnit.lfm
new file mode 100644
index 0000000..e1f13df
--- /dev/null
+++ b/LazarusSource/CSVPrefUnit.lfm
@@ -0,0 +1,171 @@
+object CSVPrefForm: TCSVPrefForm
+ Left = 632
+ Height = 309
+ Top = 378
+ Width = 225
+ BorderIcons = []
+ BorderStyle = bsDialog
+ Caption = 'CSV Preferences'
+ ClientHeight = 309
+ ClientWidth = 225
+ OnPaint = FormPaint
+ Position = poMainFormCenter
+ LCLVersion = '2.2.0.4'
+ object cb_IncDir: TCheckBox
+ Left = 40
+ Height = 18
+ Top = 32
+ Width = 129
+ Caption = 'Include Directories'
+ TabOrder = 0
+ end
+ object cb_Parent: TCheckBox
+ Left = 40
+ Height = 18
+ Top = 112
+ Width = 59
+ Caption = 'Parent'
+ Checked = True
+ State = cbChecked
+ TabOrder = 3
+ end
+ object Label1: TLabel
+ Left = 32
+ Height = 16
+ Top = 88
+ Width = 53
+ Caption = 'Columns'
+ end
+ object cb_Filename: TCheckBox
+ Left = 40
+ Height = 18
+ Top = 130
+ Width = 73
+ Caption = 'Filename'
+ Checked = True
+ State = cbChecked
+ TabOrder = 4
+ end
+ object cb_LoadAddr: TCheckBox
+ Left = 40
+ Height = 18
+ Top = 148
+ Width = 100
+ Caption = 'Load Address'
+ Checked = True
+ State = cbChecked
+ TabOrder = 5
+ end
+ object cb_ExecAddr: TCheckBox
+ Left = 40
+ Height = 18
+ Top = 166
+ Width = 127
+ Caption = 'Execution Address'
+ Checked = True
+ State = cbChecked
+ TabOrder = 6
+ end
+ object cb_Length: TCheckBox
+ Left = 40
+ Height = 18
+ Top = 184
+ Width = 62
+ Caption = 'Length'
+ Checked = True
+ State = cbChecked
+ TabOrder = 7
+ end
+ object cb_Attributes: TCheckBox
+ Left = 40
+ Height = 18
+ Top = 202
+ Width = 78
+ Caption = 'Attributes'
+ Checked = True
+ State = cbChecked
+ TabOrder = 8
+ end
+ object cb_Address: TCheckBox
+ Left = 40
+ Height = 18
+ Top = 220
+ Width = 69
+ Caption = 'Address'
+ TabOrder = 9
+ end
+ object cb_CRC32: TCheckBox
+ Left = 40
+ Height = 18
+ Top = 238
+ Width = 62
+ Caption = 'CRC32'
+ Checked = True
+ State = cbChecked
+ TabOrder = 10
+ end
+ object Label2: TLabel
+ Left = 32
+ Height = 16
+ Top = 8
+ Width = 47
+ Caption = 'Options'
+ end
+ object CancelButton: TBitBtn
+ Left = 8
+ Height = 30
+ Top = 272
+ Width = 100
+ Cancel = True
+ Caption = 'Cancel'
+ Color = 15527148
+ ModalResult = 2
+ TabOrder = 11
+ end
+ object OKBtnBack: TPanel
+ Left = 112
+ Height = 30
+ Top = 272
+ Width = 100
+ BevelColor = clYellow
+ BevelInner = bvLowered
+ BevelOuter = bvLowered
+ BevelWidth = 4
+ ClientHeight = 30
+ ClientWidth = 100
+ Color = clYellow
+ ParentColor = False
+ TabOrder = 12
+ object OKButton: TBitBtn
+ Left = 0
+ Height = 30
+ Top = 0
+ Width = 100
+ Caption = '&OK'
+ Color = 15527148
+ Default = True
+ ModalResult = 1
+ TabOrder = 0
+ end
+ end
+ object cb_IncFilename: TCheckBox
+ Left = 40
+ Height = 18
+ Top = 50
+ Width = 118
+ Caption = 'Include Filename'
+ Checked = True
+ State = cbChecked
+ TabOrder = 1
+ end
+ object cb_IncReport: TCheckBox
+ Left = 40
+ Height = 18
+ Top = 68
+ Width = 143
+ Caption = 'Include Image Report'
+ Checked = True
+ State = cbChecked
+ TabOrder = 2
+ end
+end
diff --git a/LazarusSource/CSVPrefUnit.pas b/LazarusSource/CSVPrefUnit.pas
new file mode 100644
index 0000000..d70d9eb
--- /dev/null
+++ b/LazarusSource/CSVPrefUnit.pas
@@ -0,0 +1,59 @@
+unit CSVPrefUnit;
+
+{$mode ObjFPC}{$H+}
+
+interface
+
+uses
+ Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, Buttons,
+ ExtCtrls;
+
+type
+
+ { TCSVPrefForm }
+
+ TCSVPrefForm = class(TForm)
+ CancelButton: TBitBtn;
+ cb_IncDir: TCheckBox;
+ cb_Parent: TCheckBox;
+ cb_Filename: TCheckBox;
+ cb_LoadAddr: TCheckBox;
+ cb_ExecAddr: TCheckBox;
+ cb_Length: TCheckBox;
+ cb_Attributes: TCheckBox;
+ cb_Address: TCheckBox;
+ cb_CRC32: TCheckBox;
+ cb_IncFilename: TCheckBox;
+ cb_IncReport: TCheckBox;
+ Label1: TLabel;
+ Label2: TLabel;
+ OKBtnBack: TPanel;
+ OKButton: TBitBtn;
+ procedure FormPaint(Sender: TObject);
+ private
+
+ public
+
+ end;
+
+var
+ CSVPrefForm: TCSVPrefForm;
+
+implementation
+
+uses MainUnit;
+
+{$R *.lfm}
+
+{ TCSVPrefForm }
+
+{------------------------------------------------------------------------------}
+//Tile the form
+{------------------------------------------------------------------------------}
+procedure TCSVPrefForm.FormPaint(Sender: TObject);
+begin
+ MainForm.FileInfoPanelPaint(Sender);
+end;
+
+end.
+
diff --git a/LazarusSource/DiscImage.pas b/LazarusSource/DiscImage.pas
index d44d2d1..adbed48 100755
--- a/LazarusSource/DiscImage.pas
+++ b/LazarusSource/DiscImage.pas
@@ -1,7 +1,7 @@
unit DiscImage;
{
-TDiscImage class V1.43
+TDiscImage class V1.44
Manages retro disc images, presenting a list of files and directories to the
parent application. Will also extract files and write new files. Almost a complete
filing system in itself. Compatible with Acorn DFS, Acorn ADFS, UEF, Commodore
@@ -54,11 +54,44 @@ TDir = record
DOSPartition, //Is this in the DOS Plus partition? (ADFS/DOS Plus)
AFSPartition: Boolean; //Is this in the AFS partition? (ADFS/AFS)
Sector, //Where is this directory located (same as TDirEntry)
+ Length, //How big is the directory (same as TDirEntry)
Partition : Cardinal; //Which partition (side) is this on?
Parent : Integer; //What is the TDir reference of the parent (-1 if none)
end;
//Collection of directories
TDisc = array of TDir;
+ //Partitions
+ TPartition = record //Details about the partition
+ Directories : TDisc; //All the directories
+ Title, //Title of the partition
+ RootTitle, //Title of the root directory
+ RootName : String; //Root name ($, A:, C:, DF0, DH0, etc.)
+ DirSep : Char; //Directory separator
+ HeaderAddr, //Offset(s) of the header(s)
+ FSMAddr : array of Cardinal;//Offset(s) of the FSM/Map/Bitmap/FAT(s)
+ FreeSpaceMap : array of TTrack; //The free space map
+ DOSVolInRoot : Boolean; //Volume name is stored in the root (DOS)
+ RootAddress, //Offset of the root
+ SectorSize, //Sector Size
+ DOSalloc, //Allocation Unit (DOS Plus)
+ Version, //Format version
+ Root_size, //Size of the root directory
+ DOSBlocks, //Size of the DOS partition in blocks
+ DOSCluster_size : Cardinal; //Size of a DOS cluster
+ FreeSpace, //Amount of free space in bytes
+ PartitionSize : QWord; //Size of the partition in bytes
+ Format, //Major format of this partition
+ DOSFATSize, //Size of DOS Plus FAT in blocks
+ DOSResSecs : Word; //Number of reserved blocks
+ SecsPerTrack, //Number of sectors per track
+ Heads, //Number of heads (Acorn ADFS New)
+ Density, //Density (Acorn ADFS New)
+ DOSFATType, //FAT Type - 12: FAT12, 16: FAT16, 32: FAT32
+ DOSNumFATs, //Number of FATs in a DOS Plus image
+ AmigaMapType : Byte; //OFS/FFS/PFS/OFS
+ end;
+ //Partitions
+ TPartitions = array of TPartition;
//Fragment
TFragment = record //For retrieving the ADFS E/F fragment information
Offset,
@@ -71,6 +104,7 @@ TFragment = record //For retrieving the ADFS E/F fragment informati
TProgressProc = procedure(Fupdate: String) of Object;
private
FDisc : TDisc; //Container for the entire catalogue
+ FPartitions : TPartitions; //Container for the entire catalogue (partitioned)
Fdata : TDIByteArray; //Container for the image to be loaded into
FDSD, //Double sided flag (Acorn DFS)
FMap, //Old/New Map flag (Acorn ADFS) OFS/FFS (Amiga)
@@ -146,25 +180,29 @@ TFragment = record //For retrieving the ADFS E/F fragment informati
SparkFile : TSpark; //For reading in Spark archives
//Private methods
procedure ResetVariables;
+ procedure AddPartition;
function ReadString(ptr,term: Integer;control: Boolean=True): String;
function ReadString(ptr,term: Integer;var buffer: TDIByteArray;
- control: Boolean=True): String; overload;
+ control: Boolean=True): String; overload;
procedure WriteString(str: String;ptr,len: Cardinal;pad: Byte);
procedure WriteString(str: String;ptr,len: Cardinal;pad: Byte;
var buffer: TDIByteArray); overload;
function FormatToString: String;
function FormatToExt: String;
+ function GetMajorFormatNumber: Word;
+ function GetMinorFormatNumber: Byte;
function ReadBits(offset,start,length: Cardinal): Cardinal;
procedure WriteBits(value,offset,start,length: Cardinal);
- procedure WriteBits(value,offset,start,length: Cardinal;buffer: TDIByteArray); overload;
+ procedure WriteBits(value,offset,start,length: Cardinal;
+ buffer: TDIByteArray); overload;
function RISCOSToTimeDate(filedatetime: Int64): TDateTime;
function TimeDateToRISCOS(delphitime: TDateTime): Int64;
function Read32b(offset: Cardinal; bigendian: Boolean=False): Cardinal;
function Read32b(offset: Cardinal; var buffer: TDIByteArray;
- bigendian: Boolean=False): Cardinal; overload;
+ bigendian: Boolean=False): Cardinal; overload;
function Read24b(offset: Cardinal; bigendian: Boolean=False): Cardinal;
function Read24b(offset: Cardinal; var buffer: TDIByteArray;
- bigendian: Boolean=False): Cardinal; overload;
+ bigendian: Boolean=False): Cardinal; overload;
function Read16b(offset: Cardinal; bigendian: Boolean=False): Word;
function Read16b(offset: Cardinal; var buffer: TDIByteArray;
bigendian: Boolean=False): Word; overload;
@@ -181,7 +219,8 @@ TFragment = record //For retrieving the ADFS E/F fragment informati
procedure Write16b(value: Word; offset: Cardinal; var buffer: TDIByteArray;
bigendian: Boolean=False); overload;
procedure WriteByte(value: Byte; offset: Cardinal);
- procedure WriteByte(value: Byte; offset: Cardinal; var buffer: TDIByteArray); overload;
+ procedure WriteByte(value: Byte; offset: Cardinal;
+ var buffer: TDIByteArray); overload;
function GetDataLength: Cardinal;
procedure SetDataLength(newlen: Cardinal);
function ROR13(v: Cardinal): Cardinal;
@@ -189,7 +228,8 @@ TFragment = record //For retrieving the ADFS E/F fragment informati
function MapFlagToByte: Byte;
function MapTypeToString: String;
function DirTypeToString: String;
- function GeneralChecksum(offset,length,chkloc,start: Cardinal;carry: Boolean): Cardinal;
+ function GeneralChecksum(offset,length,chkloc,start: Cardinal;
+ carry: Boolean): Cardinal;
function GetImageCrc: String;
function GetCRC(var buffer: TDIByteArray): String;
function GetCRC16(start,len: Cardinal;var buffer: TDIByteArray): Cardinal;
@@ -202,36 +242,43 @@ TFragment = record //For retrieving the ADFS E/F fragment informati
function ID_ADFS: Boolean;
function ReadADFSDir(dirname: String; sector: Cardinal): TDir;
function CalculateADFSDirCheck(sector: Cardinal): Byte;
- function CalculateADFSDirCheck(sector: Cardinal;buffer:TDIByteArray): Byte; overload;
- function NewDiscAddrToOffset(addr: Cardinal;offset:Boolean=True): TFragmentArray;
+ function CalculateADFSDirCheck(sector: Cardinal;
+ buffer: TDIByteArray): Byte; overload;
+ function NewDiscAddrToOffset(addr: Cardinal;
+ offset: Boolean=True): TFragmentArray;
function OffsetToOldDiscAddr(offset: Cardinal): Cardinal;
function ByteChecksum(offset,size: Cardinal): Byte;
- function ByteChecksum(offset,size: Cardinal;var buffer: TDIByteArray): Byte; overload;
- function ReadADFSDisc: TDisc;
+ function ByteChecksum(offset,size: Cardinal;
+ var buffer: TDIByteArray): Byte; overload;
+ function ReadADFSDisc: Boolean;
procedure ADFSFreeSpaceMap;
procedure ADFSFillFreeSpaceMap(address: Cardinal;usage: Byte);
- function FormatADFSFloppy(minor: Byte): TDisc;
+ function FormatADFSFloppy(minor: Byte): Boolean;
procedure FormatOldMapADFS(disctitle: String);
- procedure FormatNewMapADFS(disctitle: String);
- function FormatADFSHDD(harddrivesize:Cardinal;newmap:Boolean;dirtype:Byte):TDisc;
+ procedure FormatNewMapADFS(disctitle: String; ide: Boolean);
+ function FormatADFSHDD(harddrivesize: Cardinal; newmap: Boolean; dirtype:Byte;
+ ide,addheader: Boolean): Boolean;
function UpdateADFSDiscTitle(title: String): Boolean;
function UpdateADFSBootOption(option: Byte): Boolean;
function ADFSGetFreeFragments(offset:Boolean=True): TFragmentArray;
function WriteADFSFile(var file_details: TDirEntry;var buffer: TDIByteArray;
extend:Boolean=True): Integer;
- function ADFSFindFreeSpace(filelen: Cardinal;var fragid: Cardinal): TFragmentArray;
+ function ADFSFindFreeSpace(filelen: Cardinal;
+ var fragid: Cardinal): TFragmentArray;
function WriteFragmentedData(fragments: TFragmentArray;
- var buffer: TDIByteArray): Boolean;
- procedure ADFSAllocateFreeSpace(filelen,freeptr: Cardinal);
- procedure ADFSAllocateFreeSpace(filelen,fragid: Cardinal;fragments: TFragmentArray); overload;
- function ADFSSectorAlignLength(filelen: Cardinal): Cardinal;
+ var buffer: TDIByteArray): Boolean;
+ function ADFSAllocateFreeSpace(filelen,freeptr: Cardinal): Boolean;
+ function ADFSAllocateFreeSpace(filelen,fragid: Cardinal;
+ fragments: TFragmentArray): Boolean; overload;
+ function ADFSSectorAlignLength(filelen: Cardinal;
+ bpmbalign: Boolean=True): Cardinal;
procedure ADFSCalcFileDate(var Entry: TDirEntry);
function CreateADFSDirectory(var dirname,parent,attributes: String): Integer;
procedure UpdateADFSCat(directory: String;newname: String='');
function UpdateADFSFileAttributes(filename,attributes: String): Boolean;
function ValidateADFSFilename(filename: String): String;
function RetitleADFSDirectory(filename,newtitle: String): Boolean;
- function RenameADFSFile(oldfilename: String;var newfilename: String):Integer;
+ function RenameADFSFile(oldfilename: String;var newfilename: String): Integer;
procedure ConsolodateADFSFreeSpaceMap;
procedure ConsolodateADFSFragments(fragid: Cardinal);
function DeleteADFSFile(filename: String;
@@ -248,26 +295,30 @@ TFragment = record //For retrieving the ADFS E/F fragment informati
procedure ReduceADFSCat(dir,entry: Cardinal);
function FixBrokenADFSDirectories: Boolean;
function FixADFSDirectory(dir,entry: Integer):Boolean;
- function ADFSGetHardDriveParams(Ldiscsize:Cardinal;bigmap:Boolean;
- var Lidlen,Lzone_spare,Lnzones,Llog2bpmb,Lroot: Cardinal):Boolean;
- function UpdateADFSFileAddr(filename:String;newaddr:Cardinal;load:Boolean):Boolean;
+ function ADFSGetHardDriveParams(Ldiscsize: Cardinal; bigmap,ide: Boolean;
+ var Lidlen,Lzone_spare,Lnzones,Llog2bpmb,Lroot,
+ Llog2secsize,Llowsec: Cardinal): Boolean;
+ function UpdateADFSFileAddr(filename: String; newaddr: Cardinal;
+ load: Boolean): Boolean;
function UpdateADFSFileType(filename:String;newtype:String):Boolean;
function UpdateADFSTimeStamp(filename:String;newtimedate:TDateTime):Boolean;
function ExtractADFSPartition(side: Cardinal): TDIByteArray;
function GetADFSMaxLength(lastentry:Boolean): Cardinal;
+ function ADFSReport(CSV: Boolean): TStringList;
//Acorn FileStore Routines
function ID_AFS: Boolean;
procedure ReadAFSPartition;
- function ReadAFSDirectory(dirname:String;addr: Cardinal):TDir;
+ function ReadAFSDirectory(dirname: String; addr: Cardinal): TDir;
function ExtractAFSFile(filename: String;var buffer: TDIByteArray): Boolean;
function ReadAFSObject(offset: Cardinal): TDIByteArray;
function GetAFSObjLength(offset: Cardinal): Cardinal;
function GetAllocationMap: Cardinal;
- function GetAllocationMap(sector:Cardinal;var spt:Cardinal):Cardinal; overload;
+ function GetAllocationMap(sector: Cardinal;
+ var spt: Cardinal): Cardinal; overload;
procedure ReadAFSFSM;
function AFSGetFreeSectors(used: Boolean=False): TFragmentArray;
function AFSAllocateFreeSpace(size :Cardinal;
- var fragments: TFragmentArray;addheader:Boolean=True): Cardinal;
+ var fragments: TFragmentArray; addheader: Boolean=True): Cardinal;
procedure AFSDeAllocateFreeSpace(addr: Cardinal);
procedure FinaliseAFSL2Map;
function FormatAFS(harddrivesize: Cardinal;afslevel: Byte): Boolean;
@@ -277,8 +328,8 @@ TFragment = record //For retrieving the ADFS E/F fragment informati
function CreateAFSPassword(Accounts: TUserAccounts): Integer;
function ReadAFSPassword: TUserAccounts;
function WriteAFSFile(var file_details: TDirEntry;
- var buffer: TDIByteArray):Integer;
- function AFSAttrToByte(attr: String):Byte;
+ var buffer: TDIByteArray): Integer;
+ function AFSAttrToByte(attr: String): Byte;
procedure WriteAFSObject(offset: Cardinal;var buffer: TDIByteArray);
function RenameAFSFile(oldname:String;var newname: String): Integer;
procedure UpdateAFSDirectory(dirname: String);
@@ -287,72 +338,82 @@ TFragment = record //For retrieving the ADFS E/F fragment informati
function RemoveAFSEntry(dir,entry: Cardinal): Boolean;
function InsertAFSEntry(dir: Cardinal;file_details:TDirEntry): Integer;
function MoveAFSFile(filename,directory: String): Integer;
- function UpdateAFSFileAddr(filename:String;newaddr:Cardinal;load:Boolean):Boolean;
- function UpdateAFSTimeStamp(filename:String;newtimedate:TDateTime):Boolean;
- function AFSTimeToWord(timedate: TDateTime):Word;
+ function UpdateAFSFileAddr(filename: String; newaddr: Cardinal;
+ load: Boolean): Boolean;
+ function UpdateAFSTimeStamp(filename: String; newtimedate: TDateTime):Boolean;
+ function AFSTimeToWord(timedate: TDateTime): Word;
function UpdateAFSAttributes(filename,attributes: String): Boolean;
function UpdateAFSDiscTitle(title: String): Boolean;
function AddAFSPartition(size: Cardinal): Boolean;
+ function AFSReport(CSV: Boolean): TStringList;
//DFS Routines
function ID_DFS: Boolean;
- function ReadDFSDisc(mmbdisc:Integer=-1): TDisc;
- procedure DFSFreeSpaceMap(LDisc: TDisc);
+ function ReadDFSDisc(mmbdisc:Integer=-1): Boolean;
+ procedure DFSFreeSpaceMap;
function IsWatford(s: Integer): Boolean;
function ConvertDFSSector(address,side: Integer): Integer;
- function WriteDFSFile(var file_details: TDirEntry;var buffer: TDIByteArray): Integer;
+ function WriteDFSFile(var file_details: TDirEntry;
+ var buffer: TDIByteArray): Integer;
procedure UpdateDFSCat(side: Integer);
function ValidateDFSFilename(filename: String): String;
function RenameDFSFile(oldfilename: String;var newfilename: String):Integer;
function DeleteDFSFile(filename: String):Boolean;
function UpdateDFSFileAttributes(filename,attributes: String): Boolean;
- function FormatDFS(minor,tracks: Byte): TDisc;
+ function FormatDFS(minor,tracks: Byte): Boolean;
function UpdateDFSDiscTitle(title: String;side: Byte): Boolean;
function UpdateDFSBootOption(option,side: Byte): Boolean;
function ExtractDFSFile(filename: String;var buffer: TDIByteArray): Boolean;
- function UpdateDFSFileAddr(filename:String;newaddr:Cardinal;load:Boolean):Boolean;
+ function UpdateDFSFileAddr(filename: String; newaddr: Cardinal;
+ load: Boolean):Boolean;
function ExtractDFSPartition(side: Cardinal): TDIByteArray;
function AddDFSSide(var buffer: TDIByteArray): Boolean;
function AddDFSSide(filename: String): Boolean; overload;
function MoveDFSFile(filename,directory: String): Integer;
+ function DFSReport(CSV: Boolean): TStringList;
//Commodore 1541/1571/1581 Routines
function ID_CDR: Boolean;
function ConvertDxxTS(format,track,sector: Integer): Integer;
- function ReadCDRDisc: TDisc;
- function FormatCDR(minor: Byte): TDisc;
+ function ReadCDRDisc: Boolean;
+ function FormatCDR(minor: Byte): Boolean;
procedure CDRFreeSpaceMap;
- procedure CDRSetClearBAM(track,sector: Byte;used: Boolean);
+ procedure CDRSetClearBAM(track,sector: Byte; used: Boolean);
function UpdateCDRDiscTitle(title: String): Boolean;
- function ExtractCDRFile(filename:String;var buffer:TDIByteArray): Boolean;
- function WriteCDRFile(file_details: TDirEntry;var buffer: TDIByteArray): Integer;
+ function ExtractCDRFile(filename: String; var buffer:TDIByteArray): Boolean;
+ function WriteCDRFile(file_details: TDirEntry;
+ var buffer: TDIByteArray): Integer;
procedure UpdateCDRCat;
function CDRFindNextSector(var track,sector: Byte): Boolean;
function CDRFindNextTrack(var track,sector: Byte): Boolean;
function RenameCDRFile(oldfilename: String;var newfilename: String):Integer;
function DeleteCDRFile(filename: String):Boolean;
function UpdateCDRFileAttributes(filename,attributes: String): Boolean;
+ function CDRReport(CSV: Boolean): TStringList;
//Sinclair Spectrum +3/Amstrad Routines
function ID_Sinclair: Boolean;
- function ReadSinclairDisc: TDisc;
- function FormatSpectrum(minor: Byte): TDisc;
- function WriteSpectrumFile(file_details: TDirEntry;var buffer: TDIByteArray): Integer;
- function RenameSpectrumFile(oldfilename: String;var newfilename: String):Integer;
+ function ReadSinclairDisc: Boolean;
+ function FormatSpectrum(minor: Byte): Boolean;
+ function WriteSpectrumFile(file_details: TDirEntry;
+ var buffer: TDIByteArray): Integer;
+ function RenameSpectrumFile(oldfilename: String;
+ var newfilename: String):Integer;
function DeleteSinclairFile(filename: String):Boolean;
function UpdateSinclairFileAttributes(filename,attributes: String): Boolean;
function UpdateSinclairDiscTitle(title: String): Boolean;
function ExtractSpectrumFile(filename:String;var buffer:TDIByteArray):Boolean;
//Commodore Amiga Routines
function ID_Amiga: Boolean;
- function ReadAmigaDisc: TDisc;
+ function ReadAmigaDisc: Boolean;
function ReadAmigaDir(dirname: String; offset: Cardinal): TDir;
function AmigaBootChecksum(offset: Cardinal): Cardinal;
function AmigaChecksum(offset: Cardinal): Cardinal;
- function ExtractAmigaFile(filename:String;var buffer:TDIByteArray):Boolean;
+ function ExtractAmigaFile(filename: String; var buffer: TDIByteArray):Boolean;
function ExtractAmigaData(sector,filelen: Cardinal;
var buffer: TDIByteArray): Boolean;
- function FormatAmigaFDD(minor: Byte): TDisc;
- function FormatAmigaHDD(harddrivesize: Cardinal): TDisc;
+ function FormatAmigaFDD(minor: Byte): Boolean;
+ function FormatAmigaHDD(harddrivesize: Cardinal): Boolean;
procedure FormatAmiga(size: Cardinal);
- function WriteAmigaFile(var file_details: TDirEntry;var buffer: TDIByteArray): Integer;
+ function WriteAmigaFile(var file_details: TDirEntry;
+ var buffer: TDIByteArray): Integer;
function CreateAmigaDirectory(var dirname,parent,attributes: String): Integer;
function RenameAmigaFile(oldfilename: String;var newfilename: String):Integer;
function DeleteAmigaFile(filename: String):Boolean;
@@ -366,54 +427,63 @@ TFragment = record //For retrieving the ADFS E/F fragment informati
function AmigaIntToStrAttr(attr: Cardinal): String;
function AmigaStrToIntAttr(attr: String): Cardinal;
function AmigaCalculateHashValue(filename: String): Cardinal;
- procedure AmigaAllocateFSMBlock(addr:Cardinal;used:Boolean;var fsm:TDIByteArray);
+ procedure AmigaAllocateFSMBlock(addr:Cardinal;used:Boolean;
+ var fsm:TDIByteArray);
function GetAmigaFSMOffset(addr: Cardinal;var bit: Byte): Cardinal;
function AmigaReadBitmap(var fsm: TDIByteArray): TFragmentArray;
procedure AmigaWriteBitmap(fsmlist: TFragmentArray;var fsm: TDIByteArray);
function AmigaFindFreeSpace(filelen: Cardinal): TFragmentArray;
- function UpdateAmigaTimeStamp(filename: String;newtimedate: TDateTime): Boolean;
+ function UpdateAmigaTimeStamp(filename: String;
+ newtimedate: TDateTime): Boolean;
function GetAmigaChain(sector: Cardinal): TFragmentArray;
procedure AmigaAddToChain(filename: String;paraddr,sector: Cardinal);
- function AmigaRemoveFromChain(filename: String;paraddr,sector: Cardinal):Boolean;
+ function AmigaRemoveFromChain(filename: String;
+ paraddr,sector: Cardinal):Boolean;
procedure ValidateAmigaFile(var filename: String);
+ function AmigaReport(CSV: Boolean): TStringList;
//Acorn CFS Routines
function ID_CFS: Boolean;
- function ReadUEFFile: TDisc;
+ function ReadUEFFile: Boolean;
function CFSBlockStatus(status: Byte): String;
function CFSTargetMachine(machine: Byte): String;
- function ExtractCFSFile(entry: Integer;var buffer:TDIByteArray):Boolean;
- procedure WriteUEFFile(filename: String;uncompress: Boolean=False);
- function FormatCFS:TDisc;
+ function ExtractCFSFile(entry: Integer; var buffer:TDIByteArray): Boolean;
+ procedure WriteUEFFile(filename: String; uncompress: Boolean=False);
+ function FormatCFS: Boolean;
function DeleteCFSFile(entry: Cardinal): Boolean;
- function UpdateCFSAttributes(entry: Cardinal;attributes:String): Boolean;
+ function UpdateCFSAttributes(entry: Cardinal; attributes:String): Boolean;
function MoveCFSFile(entry: Cardinal;dest: Integer): Integer;
function CopyCFSFile(entry: Cardinal;dest: Integer): Integer;
- function WriteCFSFile(var file_details: TDirEntry;var buffer: TDIByteArray): Integer;
- function RenameCFSFile(entry: Cardinal;newfilename: String): Integer;
- function UpdateCFSFileAddr(entry,newaddr:Cardinal;load:Boolean):Boolean;
+ function WriteCFSFile(var file_details: TDirEntry;
+ var buffer: TDIByteArray): Integer;
+ function RenameCFSFile(entry: Cardinal; newfilename: String): Integer;
+ function UpdateCFSFileAddr(entry,newaddr: Cardinal; load: Boolean): Boolean;
//MMFS Routines
function ID_MMB: Boolean;
- function ReadMMBDisc: TDisc;
+ function ReadMMBDisc: Boolean;
//Spark Routines
function ID_Spark: Boolean;
- function ReadSparkArchive: TDisc;
+ function ReadSparkArchive: Boolean;
function ExtractSparkFile(filename: String;var buffer: TDIByteArray): Boolean;
- function FormatSpark(Zipfilename: String): TDisc;
+ function FormatSpark(Zipfilename: String): Boolean;
function DeleteSparkFile(filename: String): Boolean;
function UpdateSparkAttributes(filename,attributes: String): Boolean;
function MoveSparkFile(filename, dest: String): Integer;
- function WriteSparkFile(var file_details:TDirEntry;var buffer:TDIByteArray):Integer;
+ function WriteSparkFile(var file_details: TDirEntry;
+ var buffer: TDIByteArray): Integer;
function RenameSparkFile(filename, newfilename: String): Integer;
function UpdateSparkFileType(filename: String; newtype: String): Boolean;
- function UpdateSparkTimeStamp(filename: String;newtimedate:TDateTime): Boolean;
- function UpdateSparkFileAddr(filename:String;newaddr:Cardinal;load:Boolean):Boolean;
+ function UpdateSparkTimeStamp(filename: String;
+ newtimedate: TDateTime): Boolean;
+ function UpdateSparkFileAddr(filename: String; newaddr: Cardinal;
+ load: Boolean): Boolean;
function CreateSparkDirectory(filename, parent, attributes: String): Integer;
//DOS Plus Routines
function ID_DOSPlus: Boolean;
function IDDOSPartition(ctr: Cardinal): Boolean;
procedure ReadDOSPartition;
function ReadDOSHeader: Boolean;
- function ReadDOSDirectory(dirname:String;addr:Cardinal;var len:Cardinal):TDir;
+ function ReadDOSDirectory(dirname: String; addr: Cardinal;
+ var len: Cardinal): TDir;
function DOSExtToFileType(ext: String): String;
function ConvertDOSTimeDate(time,date: Word): TDateTime;
function DOSTime(time: TDateTime): Word;
@@ -424,18 +494,19 @@ TFragment = record //For retrieving the ADFS E/F fragment informati
function GetClusterEntry(cluster: Cardinal): Cardinal;
procedure SetClusterEntry(cluster,entry: Cardinal);
function IsClusterValid(cluster: Cardinal): Boolean;
- function GetClusterChain(cluster:Cardinal;len:Cardinal=0):TFragmentArray;
+ function GetClusterChain(cluster: Cardinal; len: Cardinal=0): TFragmentArray;
procedure SetClusterChain(fragments: TFragmentArray);
- function ExtractDOSFile(filename: String;var buffer: TDIByteArray): Boolean;
+ function ExtractDOSFile(filename: String; var buffer: TDIByteArray): Boolean;
function ReadDOSObject(cluster: Cardinal;len: Cardinal=0): TDIByteArray;
procedure ReadDOSFSM;
function DOSGetFreeSectors(used: Boolean=False): TFragmentArray;
- function RenameDOSFile(oldname:String;var newname: String): Integer;
+ function RenameDOSFile(oldname: String; var newname: String): Integer;
function ValidateDOSFilename(filename: String;long: Boolean=False): String;
procedure UpdateDOSDirectory(dirname: String);
- procedure AllocateDOSClusters(len:Cardinal;var fragments:TFragmentArray);
- procedure DeAllocateDOSClusters(len:Cardinal;var fragments:TFragmentArray);
- function WriteDOSObject(buffer:TDIByteArray;fragments:TFragmentArray):Boolean;
+ procedure AllocateDOSClusters(len: Cardinal; var fragments: TFragmentArray);
+ procedure DeAllocateDOSClusters(len: Cardinal; var fragments: TFragmentArray);
+ function WriteDOSObject(buffer: TDIByteArray;
+ fragments: TFragmentArray): Boolean;
function WriteDOSFile(var file_details: TDirEntry;
var buffer: TDIByteArray):Integer;
function InsertDOSEntry(dir: Cardinal;direntry: TDirEntry): Integer;
@@ -444,15 +515,16 @@ TFragment = record //For retrieving the ADFS E/F fragment informati
procedure RemoveDOSEntry(dir, entry: Cardinal);
function UpdateDOSAttributes(filename,attributes: String): Boolean;
function UpdateDOSDiscTitle(title: String): Boolean;
- function UpdateDOSTimeStamp(filename:String;newtimedate:TDateTime):Boolean;
+ function UpdateDOSTimeStamp(filename: String; newtimedate: TDateTime):Boolean;
function AddDOSPartition(size: Cardinal): Boolean;
- function FormatDOS(size: QWord;fat: Byte): TDisc;
+ function FormatDOS(size: QWord;fat: Byte): Boolean;
procedure WriteDOSHeader(offset, size: QWord;fat: Byte;bootable: Boolean);
procedure WriteDOSHeader(offset, size: QWord;fat: Byte;bootable: Boolean;
- var buffer:TDIByteArray);overload;
+ var buffer: TDIByteArray);overload;
function MoveDOSFile(filename,directory: String): Integer;
function DOSShortFilename(path,LFN: String;SFN :String=''): String;
function BuildDOSFilename(f,e: String): String;
+ function DOSReport(CSV: Boolean): TStringList;
//Private constants
const
//When the change of number of sectors occurs on Commodore 1541/1571 discs
@@ -478,27 +550,35 @@ TFragment = record //For retrieving the ADFS E/F fragment informati
function LoadFromFile(filename: String;readdisc: Boolean=True): Boolean;
function IDImage: Boolean;
procedure ReadImage;
- procedure SaveToFile(filename: String;uncompress: Boolean=False);
+ function SaveToFile(filename: String;uncompress: Boolean=False): Boolean;
procedure Close;
- function FormatFDD(major:Word;minor:Byte=0;tracks: Byte=0;filename: String=''): Boolean;
- function FormatHDD(major:Word;harddrivesize:Cardinal;newmap:Boolean;dirtype:Byte):Boolean;
- function ExtractFile(filename:String;var buffer:TDIByteArray;entry:Cardinal=0): Boolean;
- function WriteFile(var file_details: TDirEntry; var buffer: TDIByteArray): Integer;
- function FileExists(filename: String;var Ref: Cardinal;sfn: Boolean=False): Boolean;
- function FileExists(filename: String;var dir,entry: Cardinal;sfn: Boolean=False): Boolean; overload;
+ function FormatFDD(major:Word;minor:Byte=0;tracks: Byte=0;
+ filename: String=''): Boolean;
+ function FormatHDD(major:Word;harddrivesize:Cardinal;ide,newmap:Boolean;
+ dirtype:Byte;addheader:Boolean):Boolean;
+ function ExtractFile(filename:String;var buffer:TDIByteArray;
+ entry:Cardinal=0): Boolean;
+ function WriteFile(var file_details: TDirEntry;
+ var buffer: TDIByteArray;ShowFSM: Boolean=False): Integer;
+ function FileExists(filename: String;var Ref: Cardinal;
+ sfn: Boolean=False): Boolean;
+ function FileExists(filename: String;var dir,entry: Cardinal;
+ sfn: Boolean=False): Boolean; overload;
function ReadDiscData(addr,count,side,offset: Cardinal;
var buffer: TDIByteArray): Boolean;
function WriteDiscData(addr,side: Cardinal;var buffer: TDIByteArray;
count: Cardinal;start: Cardinal=0): Boolean;
function FileSearch(search: TDirEntry): TSearchResults;
- function RenameFile(oldfilename: String;var newfilename: String;entry: Cardinal=0): Integer;
+ function RenameFile(oldfilename: String;var newfilename: String;
+ entry: Cardinal=0): Integer;
function DeleteFile(filename: String;entry: Cardinal=0): Boolean;
function MoveFile(filename,directory: String): Integer;
function MoveFile(source: Cardinal;dest: Integer): Integer; overload;
function CopyFile(filename,directory: String): Integer;
function CopyFile(filename,directory,newfilename: String): Integer; overload;
function CopyFile(source: Cardinal;dest: Integer): Integer; overload;
- function UpdateAttributes(filename,attributes: String;entry:Cardinal=0): Boolean;
+ function UpdateAttributes(filename,attributes: String;
+ entry:Cardinal=0): Boolean;
function UpdateDiscTitle(title: String;side: Byte): Boolean;
function UpdateBootOption(option,side: Byte): Boolean;
function CreateDirectory(var filename,parent,attributes: String): Integer;
@@ -506,8 +586,10 @@ TFragment = record //For retrieving the ADFS E/F fragment informati
function GetFileCRC(filename: String;entry:Cardinal=0): String;
function FixDirectories: Boolean;
function SaveFilter(var FilterIndex: Integer;thisformat: Integer=-1):String;
- function UpdateLoadAddr(filename:String;newaddr:Cardinal;entry:Cardinal=0): Boolean;
- function UpdateExecAddr(filename:String;newaddr:Cardinal;entry:Cardinal=0): Boolean;
+ function UpdateLoadAddr(filename:String;newaddr:Cardinal;
+ entry:Cardinal=0): Boolean;
+ function UpdateExecAddr(filename:String;newaddr:Cardinal;
+ entry:Cardinal=0): Boolean;
function TimeStampFile(filename: String;newtimedate: TDateTime): Boolean;
function ChangeFileType(filename,newtype: String): Boolean;
function GetFileTypeFromNumber(filetype: Integer): String;
@@ -528,12 +610,16 @@ TFragment = record //For retrieving the ADFS E/F fragment informati
function ChangeInterleaveMethod(NewMethod: Byte): Boolean;
function GetDirSep(partition: Byte): Char;
function ReadDirectory(dirname: String): Integer;
+ function ImageReport(CSV: Boolean): TStringList;
//Published properties
property AFSPresent: Boolean read FAFSPresent;
property AFSRoot: Cardinal read Fafsroot;
- property AllowDFSZeroSectors: Boolean read FDFSzerosecs write FDFSzerosecs;
- property DFSBeyondEdge: Boolean read FDFSBeyondEdge write FDFSBeyondEdge;
- property DFSAllowBlanks: Boolean read FDFSAllowBlank write FDFSAllowBlank;
+ property AllowDFSZeroSectors: Boolean read FDFSzerosecs
+ write FDFSzerosecs;
+ property DFSBeyondEdge: Boolean read FDFSBeyondEdge
+ write FDFSBeyondEdge;
+ property DFSAllowBlanks: Boolean read FDFSAllowBlank
+ write FDFSAllowBlank;
property BootOpt: TDIByteArray read bootoption;
property CRC32: String read GetImageCrc;
property DirectoryType: Byte read FDirType;
@@ -543,23 +629,31 @@ TFragment = record //For retrieving the ADFS E/F fragment informati
property DOSPlusRoot: Cardinal read Fdosroot;
property DOSPresent: Boolean read FDOSPresent;
property DoubleSided: Boolean read FDSD;
- property Filename: String read imagefilename write imagefilename;
+ property Filename: String read imagefilename
+ write imagefilename;
property FormatExt: String read FormatToExt;
property FormatNumber: Word read FFormat;
property FormatString: String read FormatToString;
property FreeSpaceMap: TSide read free_space_map;
property InterleaveInUse: String read InterleaveString;
property InterleaveInUseNum: Byte read FInterleave;
- property InterleaveMethod: Byte read FForceInter write FForceInter;
+ property InterleaveMethod: Byte read FForceInter
+ write FForceInter;
+ property MajorFormatNumber: Word read GetMajorFormatNumber;
property MapType: Byte read MapFlagToByte;
property MapTypeString: String read MapTypeToString;
property MaxDirectoryEntries: Cardinal read FMaxDirEnt;
- property OpenDOSPartitions: Boolean read FOpenDOSPart write FOpenDOSPart;
+ property MinorFormatNumber: Byte read GetMinorFormatNumber;
+ property OpenDOSPartitions: Boolean read FOpenDOSPart
+ write FOpenDOSPart;
+ property Partitions: TPartitions read FPartitions;
property ProgressIndicator: TProgressProc write FProgress;
property RAWData: TDIByteArray read Fdata;
property RootAddress: Cardinal read GetRootAddress;
- property ScanSubDirs: Boolean read FScanSubDirs write FScanSubDirs;
- property SparkAsFS: Boolean read FSparkAsFS write FSparkAsFS;
+ property ScanSubDirs: Boolean read FScanSubDirs
+ write FScanSubDirs;
+ property SparkAsFS: Boolean read FSparkAsFS
+ write FSparkAsFS;
public
destructor Destroy; override;
End;
diff --git a/LazarusSource/DiscImageManager.lpi b/LazarusSource/DiscImageManager.lpi
index dd31511..7ac03db 100644
--- a/LazarusSource/DiscImageManager.lpi
+++ b/LazarusSource/DiscImageManager.lpi
@@ -323,7 +323,7 @@
-
+
@@ -460,6 +460,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/LazarusSource/DiscImageManager.lpr b/LazarusSource/DiscImageManager.lpr
index 7c05387..429d66e 100644
--- a/LazarusSource/DiscImageManager.lpr
+++ b/LazarusSource/DiscImageManager.lpr
@@ -23,7 +23,9 @@
ImportSelectorUnit in 'ImportSelectorUnit.pas',
PWordEditorUnit in 'PWordEditorUnit.pas',
AFSPartitionUnit in 'AFSParitionUnit.pas',
- ChangeInterleaveUnit in 'ChangeInterleaveUnit.pas';
+ ChangeInterleaveUnit in 'ChangeInterleaveUnit.pas', GJHRegistryClass,
+ CSVPrefUnit in 'CSVPrefUnit.pas',
+ ImageReportUnit in 'ImageReportUnit.pas';
{$R *.res}
@@ -45,5 +47,7 @@
Application.CreateForm(TPwordEditorForm, PwordEditorForm);
Application.CreateForm(TAFSPartitionForm, AFSPartitionForm);
Application.CreateForm(TChangeInterleaveForm, ChangeInterleaveForm);
+ Application.CreateForm(TCSVPrefForm, CSVPrefForm);
+ Application.CreateForm(TImageReportForm, ImageReportForm);
Application.Run;
end.
diff --git a/LazarusSource/DiscImageManager.lps b/LazarusSource/DiscImageManager.lps
index 025a16a..c659b78 100644
--- a/LazarusSource/DiscImageManager.lps
+++ b/LazarusSource/DiscImageManager.lps
@@ -4,12 +4,12 @@
-
+
-
-
+
+
@@ -20,8 +20,8 @@
-
-
+
+
@@ -29,9 +29,9 @@
-
-
-
+
+
+
@@ -41,9 +41,8 @@
-
-
-
+
+
@@ -54,9 +53,9 @@
-
-
-
+
+
+
@@ -67,7 +66,7 @@
-
+
@@ -77,17 +76,17 @@
-
-
+
+
+
-
-
-
+
+
@@ -97,9 +96,9 @@
-
-
-
+
+
+
@@ -110,9 +109,9 @@
-
-
-
+
+
+
@@ -131,7 +130,7 @@
-
+
@@ -143,7 +142,7 @@
-
+
@@ -153,9 +152,7 @@
-
-
-
+
@@ -165,7 +162,7 @@
-
+
@@ -178,9 +175,9 @@
-
-
-
+
+
+
@@ -191,7 +188,7 @@
-
+
@@ -204,7 +201,7 @@
-
+
@@ -217,7 +214,7 @@
-
+
@@ -230,7 +227,7 @@
-
+
@@ -243,7 +240,7 @@
-
+
@@ -256,244 +253,270 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
-
-
+
+
-
-
-
+
+
+
-
-
+
+
-
-
-
+
+
+
-
-
+
+
-
-
-
+
+
+
-
-
+
+
-
-
+
+
+
-
-
+
+
-
+
-
-
+
+
-
-
-
+
+
+
-
-
+
+
-
+
+
+
-
-
+
+
-
-
-
+
+
-
-
+
+
-
-
+
+
+
-
-
+
+
-
-
-
+
+
+
-
-
+
+
-
-
-
+
+
+
-
-
+
+
-
-
-
+
+
+
-
-
+
+
-
+
-
-
-
-
-
-
-
-
+
-
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
-
-
@@ -505,16 +528,16 @@
-
-
-
+
+
-
-
-
+
+
-
-
-
+
+
diff --git a/LazarusSource/DiscImageManager.res b/LazarusSource/DiscImageManager.res
index 66ee94d..0718d95 100644
Binary files a/LazarusSource/DiscImageManager.res and b/LazarusSource/DiscImageManager.res differ
diff --git a/LazarusSource/DiscImage_ADFS.pas b/LazarusSource/DiscImage_ADFS.pas
index d11b053..31cd46b 100644
--- a/LazarusSource/DiscImage_ADFS.pas
+++ b/LazarusSource/DiscImage_ADFS.pas
@@ -114,21 +114,21 @@ function TDiscImage.ID_ADFS: Boolean;
if FAFSPresent then //We'll just check the end name, and set to AFS L3
if ReadString($6FB,-4)<>'Hugo' then FFormat:=diAcornFS<<4+2;
end;
- if(FFormat mod $10<3)or(FFormat=diAcornADFS<<4+$0E)then //ADFS S,M,L or unknown
+ if(GetMinorFormatNumber<3)or(FFormat=diAcornADFS<<4+$0E)then //ADFS S,M,L or unknown
begin
//Set the number of sectors per track - this is not held in the disc
secspertrack:= 16;
//Size of the sectors in bytes
secsize :=256;
end;
- if FFormat mod $10=3 then //ADFS D
+ if GetMinorFormatNumber=3 then //ADFS D
begin
//Set the number of sectors per track - this is not held in the disc
secspertrack:= 5;
//Size of the sectors in bytes
secsize :=1024;
end;
- if FFormat mod $10=$F then //ADFS Hard drive
+ if GetMinorFormatNumber=$F then //ADFS Hard drive
begin
secspertrack:= 16;
secsize :=256;
@@ -155,13 +155,16 @@ function TDiscImage.ID_ADFS: Boolean;
if emuheader+dr_ptr+$402 then
@@ -255,7 +258,7 @@ function TDiscImage.ID_ADFS: Boolean;
end;
end;
//Return a true or false
- Result:=FFormat>>4=diAcornADFS;
+ Result:=GetMajorFormatNumber=diAcornADFS;
if Result then root_name:='$';
end;
end;
@@ -286,7 +289,7 @@ function TDiscImage.ReadADFSDir(dirname: String; sector: Cardinal): TDir;
//Attributes - not to be confused with what is returned from OSFILE
//See the function GetAttributes in DiscImageUtils
OldAtts: array[0..9] of Char = ('R','W','L','D','E','r','w','e','P',' ');
- NewAtts: array[0..7] of Char = ('R','W','L','D','r','w',' ',' ');
+ NewAtts: array[0..5] of Char = ('R','W','L','D','r','w');
begin
SetLength(dirbuffer,0);
RemoveControl(dirname);
@@ -336,14 +339,26 @@ function TDiscImage.ReadADFSDir(dirname: String; sector: Cardinal): TDir;
//New Map, so the sector will be an internal disc address
if dirname=root_name then //root address
begin
- addr:=NewDiscAddrToOffset(rootfrag);
+ if rootfrag=sector then addr:=NewDiscAddrToOffset(rootfrag)
+ else
+ begin
+ SetLength(addr,1);
+ addr[0].Offset:=sector;
+ addr[0].Length:=root_size;
+ end;
Result.Sector:=rootfrag;
+ dirsize:=addr[0].Length;
end
else //other object address
addr:=NewDiscAddrToOffset(sector);
//We need the total length of the big directory
if Length(addr)>0 then
- for amt:=0 to Length(addr)-1 do inc(dirsize,addr[amt].Length);
+ begin
+ if FDirType=diADFSOldDir then dirsize:=1280;
+ if FDirType=diADFSNewDir then dirsize:=2048;
+ if FDirType=diADFSBigDir then
+ for amt:=0 to Length(addr)-1 do inc(dirsize,addr[amt].Length);
+ end;
end
else
begin
@@ -357,6 +372,7 @@ function TDiscImage.ReadADFSDir(dirname: String; sector: Cardinal): TDir;
//But big type directories the length varies - we worked this out above
dirsize:=addr[0].Length;
end;
+ Result.Length:=dirsize;
//Read the entire directory into a buffer
if ExtractFragmentedData(addr,dirsize,dirbuffer) then
begin
@@ -432,12 +448,22 @@ function TDiscImage.ReadADFSDir(dirname: String; sector: Cardinal): TDir;
//ADFS normally refuses to list broken directories, but we will list them anyway,
//just marking the directory as broken and return an error code
Result.ErrorCode:=0;
+ //Start and End sequence numbers do not match
if EndSeq<>StartSeq then
Result.ErrorCode:=Result.ErrorCode OR $01;
- if(FDirTypeEndName)then
- Result.ErrorCode:=Result.ErrorCode OR $02;
+ if FDirTypeEndName then//Start and End names do not match (Hugo or Nick)
+ Result.ErrorCode:=Result.ErrorCode OR $02
+ else //Start and End names are not valid for Old or New Directories
+ if((StartName<>'Hugo')and(StartName<>'Nick'))
+ or((EndName<>'Hugo')and(EndName<>'Nick'))then
+ Result.ErrorCode:=Result.ErrorCode OR $40;
+ //Start and End names are not valid for Big Directories
if(FDirType=diADFSBigDir)and((StartName<>'SBPr') or (EndName<>'oven'))then
Result.ErrorCode:=Result.ErrorCode OR $04;
+ //Not sector aligned
+ if sector mod secsize<>0 then
+ Result.ErrorCode:=Result.ErrorCode OR $20;
Result.Broken:=Result.ErrorCode<>$00;
//Check for valid directory
//We won't try and get the directory structure if it appears that it is invalid
@@ -481,7 +507,7 @@ function TDiscImage.ReadADFSDir(dirname: String; sector: Cardinal): TDir;
endofentry:=False;
if Length(Entry.Filename)>0 then
begin
- for amt:=0 to 9 do //Length(Entry.Filename)-1 do
+ for amt:=0 to 9 do
begin
//if ord(Entry.Filename[amt+1])>>7=1 then
if ReadByte(offset+amt,dirbuffer)>>7=1 then
@@ -525,12 +551,13 @@ function TDiscImage.ReadADFSDir(dirname: String; sector: Cardinal): TDir;
if FDirType>diADFSOldDir then
begin
temp:='';
- for amt:=0 to 7 do
+ for amt:=0 to 5 do
if IsBitSet(NewDirAtts,amt) then temp:=temp+NewAtts[amt];
//Reverse the attribute order to match actual ADFS
- if Length(temp)>0 then
+ if Length(temp)>1 then
for amt:=Length(temp) downto 1 do
- Entry.Attributes:=Entry.Attributes+temp[amt];//Attributes
+ Entry.Attributes:=Entry.Attributes+temp[amt];
+ if Length(temp)=1 then Entry.Attributes:=temp;
end;
//If we have a valid entry then we can see if it is filetyped/datestamped
//and add it to the list
@@ -564,6 +591,11 @@ function TDiscImage.ReadADFSDir(dirname: String; sector: Cardinal): TDir;
end;
end;
Result.BeenRead:=True;
+ end
+ else
+ begin //Could not be read in for some other reason
+ if not Result.Broken then Result.ErrorCode:=Result.ErrorCode OR $10;
+ Result.Broken:=True;
end;
end;
if Result.Broken then inc(brokendircount);
@@ -578,8 +610,8 @@ procedure TDiscImage.ADFSCalcFileDate(var Entry: TDirEntry);
rotd: Int64;
begin
//Only valid for New and Big directories in ADFS or SparkFS
- if((FFormat>>4=diAcornADFS)and((FDirType=diADFSNewDir)or(FDirType=diADFSBigDir)))
- or(FFormat>>4=diSpark)then
+ if((GetMajorFormatNumber=diAcornADFS)and((FDirType=diADFSNewDir)or(FDirType=diADFSBigDir)))
+ or(GetMajorFormatNumber=diSpark)then
if Entry.LoadAddr>>20=$FFF then //Only if the top 12 bits are set
begin
//Get the 12 bit filetype
@@ -694,28 +726,28 @@ function TDiscImage.CalculateADFSDirCheck(sector:Cardinal;buffer:TDIByteArray):
-------------------------------------------------------------------------------}
function TDiscImage.NewDiscAddrToOffset(addr: Cardinal;offset:Boolean=True): TFragmentArray;
var
- fragid : TFragmentArray;
i,j,sector,id,
allmap,len,off,
zone,start,
start_zone,
zonecounter,
+ fragid,
id_per_zone : Cardinal;
const
dr_size = $40; //Size of disc record + header (zone 0)
header = 4; //Size of zone header only (zones >0)
begin
+ //Reset the result
Result:=nil;
- sector:=0;
SetLength(Result,0);
if FMap then //Only works for new maps
begin
- if addr=0 then //Root
+ if(addr=0)or(addr=rootfrag)then //Root
begin
//We've been given the address of the root, but we know where this is so no
//need to calculate it.
SetLength(Result,1);
- Result[0].Offset:=root;//bootmap+(nzones*secsize*2);
+ Result[0].Offset:=bootmap+(nzones*secsize*2);
case FDirType of
diADFSOldDir: Result[0].Length:=$500;
diADFSNewDir: Result[0].Length:=$800;
@@ -724,13 +756,17 @@ function TDiscImage.NewDiscAddrToOffset(addr: Cardinal;offset:Boolean=True): TFr
end
else
begin
- //Set up an array
- SetLength(fragid,0);
+ //Extract the fragment ID part of the address
+ fragid:=(addr div $100)mod(1<=1
+ if sector>=1 then dec(sector);
//Go through the allocation map, looking for the fragment
//First we need to know how many ids per zone there are (max)
id_per_zone:=((secsize*8)-zone_spare)div(idlen+1);
//Then work out the start zone
- start_zone:=((addr DIV $100) mod $10000)div id_per_zone;
+ start_zone:=((addr DIV $100)mod(1<=allmap;
end;
- //Now we need to set up the result array and convert from addresses to offsets
- SetLength(Result,Length(fragid));
- if Length(fragid)>0 then
- for i:=0 to Length(fragid)-1 do
- begin
- sector:=addr mod $100;
- //Sector needs to have 1 subtracted, if >=1
- if sector>=1 then dec(sector);
- //Then calculate the offset
- if offset then
- Result[i].Offset:=(fragid[i].Offset+(sector*secsize))
- else
- Result[i].Offset:=fragid[i].Offset;
- //Add the length of this fragment
- Result[i].Length:=fragid[i].Length;
- //Add the zone of this fragment
- Result[i].Zone :=fragid[i].Zone;
- end;
+ //If offsets have been called for, then convert them
+ if Length(Result)>0 then
+ if offset then
+ for i:=0 to Length(Result)-1 do
+ Result[i].Offset:=(Result[i].Offset+(sector*secsize));
//Root indirect address
if(addr=rootfrag)and(Length(Result)>1)and(nzones>1)
and(Result[0].Offset=sector*secsize)then
@@ -833,7 +856,7 @@ function TDiscImage.OffsetToOldDiscAddr(offset: Cardinal): Cardinal;
begin
Result:=offset;
//ADFS L or AFS with 'INT' option
- if((FFormat=diAcornADFS<<4+$02)or(FFormat>>4=diAcornFS))
+ if((FFormat=diAcornADFS<<4+$02)or(GetMajorFormatNumber=diAcornFS))
and(Finterleave=2)then
begin
//Track Size;
@@ -885,8 +908,8 @@ function TDiscImage.ByteChecksum(offset,size: Cardinal;var buffer:TDIByteArray):
{-------------------------------------------------------------------------------
Read ADFS Disc
-------------------------------------------------------------------------------}
-function TDiscImage.ReadADFSDisc: TDisc;
- function ReadTheADFSDisc: TDisc;
+function TDiscImage.ReadADFSDisc: Boolean;
+ function ReadTheADFSDisc: Boolean;
type
TVisit = record
Sector : Cardinal;
@@ -901,8 +924,9 @@ TVisit = record
begin
//Initialise some variables
root :=$00; //Root address (set to zero so we can id the disc)
- Result:=nil;
- SetLength(Result,0);
+ FDisc:=nil;
+ Result:=False;
+ SetLength(FDisc,0);
brokendircount:=0;
//Read in the header information (that hasn't already been read in during
//the initial checks
@@ -978,11 +1002,12 @@ TVisit = record
disctype :=Read32b(bootmap+$24);
//Newer attributes for E+ and F+
disc_size[0]:=disc_size[0]+Read32b(bootmap+$28)*$100000000;
- share_size :=1<0 then
begin
//The above method removes the initial system fragment, if present
- root:=addr[0].Offset;
+ if Length(addr)>1 then
+ begin
+ i:=0;
+ while i<=Length(addr)-1 do
+ begin
+ if addr[i].Length=nzones*secsize*2+root_size then
+ root:=addr[i].Offset;
+ inc(i);
+ end;
+ end
+ else root:=addr[0].Offset;
//This failed to find it, so 'guess' - we'll assume it is after the bootmap
if root=0 then
for d:=Length(addr)-1 downto 0 do
@@ -1007,13 +1042,13 @@ TVisit = record
if root>$00 then //If root is still $00, then we have failed to id the disc
begin
//Create an entry for the root
- SetLength(Result,1);
+ SetLength(FDisc,1);
//Blank the values
- ResetDir(Result[0]);
+ ResetDir(FDisc[0]);
//Calculate the Free Space Map
ADFSFreeSpaceMap;
//Read the root
- Result[0]:=ReadADFSDir(root_name,root);
+ FDisc[0]:=ReadADFSDir(root_name,root);
//Now iterate through the entries and find the sub-directories
d:=0;
//Add the root as a visited directory
@@ -1022,50 +1057,51 @@ TVisit = record
visited[0].Name:=root_name;
repeat
//If there are actually any entries
- if Length(Result[d].Entries)>0 then
+ if Length(FDisc[d].Entries)>0 then
begin
//Go through the entries
- for ptr:=0 to Length(Result[d].Entries)-1 do
+ for ptr:=0 to Length(FDisc[d].Entries)-1 do
begin
//Make sure we haven't seen this before. If a directory references a higher
//directory we will end up in an infinite loop.
if Length(visited)>0 then
for i:=0 to Length(visited)-1 do
- if(visited[i].Sector=Result[d].Entries[ptr].Sector)
- and(visited[i].Name=Result[d].Entries[ptr].Filename)then
- Result[d].Entries[ptr].Filename:='';//Blank off the filename so we can remove it later
+ if(visited[i].Sector=FDisc[d].Entries[ptr].Sector)
+ and(visited[i].Name=FDisc[d].Entries[ptr].Filename)then
+ FDisc[d].Entries[ptr].Filename:='';//Blank off the filename so we can remove it later
//And add them if they are valid
- if Result[d].Entries[ptr].Filename<>'' then
+ if FDisc[d].Entries[ptr].Filename<>'' then
begin
//Attribute has a 'D', so drill down
- if Pos('D',Result[d].Entries[ptr].Attributes)>0 then
+ if Pos('D',FDisc[d].Entries[ptr].Attributes)>0 then
begin
//Once found, list their entries
- SetLength(Result,Length(Result)+1);
+ SetLength(FDisc,Length(FDisc)+1);
//Read in the contents of the directory
if FScanSubDirs then
- Result[Length(Result)-1]:=ReadADFSDir(GetParent(d)
+ FDisc[Length(FDisc)-1]:=ReadADFSDir(GetParent(d)
+dir_sep
- +Result[d].Entries[ptr].Filename,
- Result[d].Entries[ptr].Sector);
- Result[Length(Result)-1].Parent:=d;
+ +FDisc[d].Entries[ptr].Filename,
+ FDisc[d].Entries[ptr].Sector);
+ FDisc[Length(FDisc)-1].Parent:=d;
//Remember it
SetLength(visited,Length(visited)+1);
- visited[Length(visited)-1].Sector:=Result[d].Entries[ptr].Sector;
- visited[Length(visited)-1].Name:=Result[d].Entries[ptr].Filename;
+ visited[Length(visited)-1].Sector:=FDisc[d].Entries[ptr].Sector;
+ visited[Length(visited)-1].Name:=FDisc[d].Entries[ptr].Filename;
//Update the directory reference
- Result[d].Entries[ptr].DirRef:=Length(Result)-1;
+ FDisc[d].Entries[ptr].DirRef:=Length(FDisc)-1;
end;
end;
end;
end;
inc(d);
//The length of disc will increase as more directories are found
- until d=Cardinal(Length(Result));
+ until d=Cardinal(Length(FDisc));
end;
+ Result:=Length(FDisc)>0;
end;
begin
- if FFormat>>4=diAcornADFS then //But only if the format is ADFS
+ if GetMajorFormatNumber=diAcornADFS then //But only if the format is ADFS
begin
//Read in the disc
Result:=ReadTheADFSDisc;
@@ -1083,6 +1119,7 @@ TVisit = record
until(brokendircount=0)or(Finterleave=2);//Until we get back to the start
end;
end;
+ Result:=Result;
end;
{-------------------------------------------------------------------------------
@@ -1100,7 +1137,7 @@ procedure TDiscImage.ADFSFreeSpaceMap;
if not Fupdating then //Only if we are not updating
begin
//Update progress
- UpdateProgress('Reading ADFS Free Space Map.');
+// UpdateProgress('Reading ADFS Free Space Map.');
//Reset the free space counter
free_space[0]:=0;
//Reset the array
@@ -1122,7 +1159,7 @@ procedure TDiscImage.ADFSFreeSpaceMap;
free_space_map[0,c,d]:=$FF;
end;
//Update progress
- UpdateProgress('Reading ADFS Free Space Map..');
+// UpdateProgress('Reading ADFS Free Space Map..');
end;
//Old Map (ADFS S,M,L, and D)
if not FMap then
@@ -1159,7 +1196,7 @@ procedure TDiscImage.ADFSFreeSpaceMap;
//Move to the next entry
inc(d,3);
//Update progress
- UpdateProgress('Reading ADFS Free Space Map..'+AddChar('.','',d div 3));
+// UpdateProgress('Reading ADFS Free Space Map..'+AddChar('.','',d div 3));
end;
end;
//New Map (ADFS E,E+,F,F+)
@@ -1250,7 +1287,7 @@ procedure TDiscImage.ADFSFillFreeSpaceMap(address: Cardinal;usage: Byte);
{-------------------------------------------------------------------------------
Create ADFS blank floppy image
-------------------------------------------------------------------------------}
-function TDiscImage.FormatADFSFloppy(minor: Byte): TDisc;
+function TDiscImage.FormatADFSFloppy(minor: Byte): Boolean;
var
t : Integer;
dirid,
@@ -1344,7 +1381,7 @@ function TDiscImage.FormatADFSFloppy(minor: Byte): TDisc;
if not FMap then //Old Map
FormatOldMapADFS(disctitle);
if FMap then //New Map
- FormatNewMapADFS(disctitle);
+ FormatNewMapADFS(disctitle,False);
//Now write the root
dirid:='$';
att:='DLR';
@@ -1404,7 +1441,7 @@ procedure TDiscImage.FormatOldMapADFS(disctitle: String);
{-------------------------------------------------------------------------------
Format a new map ADFS image
-------------------------------------------------------------------------------}
-procedure TDiscImage.FormatNewMapADFS(disctitle: String);
+procedure TDiscImage.FormatNewMapADFS(disctitle: String; ide: Boolean);
var
log2secsize,
log2bpmb : Byte;
@@ -1424,6 +1461,30 @@ procedure TDiscImage.FormatNewMapADFS(disctitle: String);
//Defect List
Write32b($20000000,$C00); //Terminate the list
Write32b($FFFFFFFF,$DAC); //Not sure - is never explained
+ //ADFS Hardware Information
+ if disc_size[0]>1638400 then //Hard drive only
+ begin
+ Write32b($00000000,$DB0); //SL
+ if not ide then
+ begin
+ Write32b($0D0C200A,$DB4); //GPL2 GPL3 SH GPL1
+ Write16b($03FF,$DB8); //Low Current Cylinder
+ Write16b($0080,$DBA); //Pre Compensation Cylinder
+ end
+ else
+ begin
+ Write32b($00000000,$DB4);
+ Write16b($0000,$DB8);
+ WriteByte($00,$DBA); //LBA Flag
+ WriteByte($01,$DBB); //Init Flag
+ end;
+ //Parking Cylinder
+ t:=disc_size[0]div(secspertrack*heads*secsize);
+ if FDirType=diADFSBigDir then
+ Write32b(secspertrack*heads*(t-1),$DBC)
+ else
+ Write32b(secsize*secspertrack*heads*(t-1),$DBC);
+ end;
//Partial Disc Record
WriteByte(log2secsize,$DC0); //log2secsize
WriteByte(secspertrack,$DC1);
@@ -1543,7 +1604,8 @@ procedure TDiscImage.FormatNewMapADFS(disctitle: String);
{-------------------------------------------------------------------------------
Create ADFS blank hard disc image
-------------------------------------------------------------------------------}
-function TDiscImage.FormatADFSHDD(harddrivesize:Cardinal;newmap:Boolean;dirtype:Byte):TDisc;
+function TDiscImage.FormatADFSHDD(harddrivesize: Cardinal; newmap: Boolean;
+ dirtype: Byte; ide,addheader: Boolean): Boolean;
var
bigmap,
ok : Boolean;
@@ -1551,7 +1613,9 @@ function TDiscImage.FormatADFSHDD(harddrivesize:Cardinal;newmap:Boolean;dirtype:
Lzone_spare,
Lnzones,
Llog2bpmb,
- Lroot : Cardinal;
+ Lroot,
+ Llog2secsize,
+ Llowsec : Cardinal;
t : Byte;
dirid,att : String;
begin
@@ -1563,6 +1627,8 @@ function TDiscImage.FormatADFSHDD(harddrivesize:Cardinal;newmap:Boolean;dirtype:
Lnzones:=0;
Llog2bpmb:=0;
Lroot:=0;
+ Llog2secsize:=9;
+ Llowsec:=1;
//Old or new map?
dirtype:=dirtype mod 3;//Can only be 0, 1 or 2
if dirtype=0 then newmap:=False; //Old directory only on old map
@@ -1570,8 +1636,8 @@ function TDiscImage.FormatADFSHDD(harddrivesize:Cardinal;newmap:Boolean;dirtype:
harddrivesize:=512*1024*1024; //512MB max on old map
//Work out the parameters based on the drive size
if newmap then //But only for new map
- ok:=ADFSGetHardDriveParams(harddrivesize,bigmap,Lidlen,Lzone_spare,Lnzones,
- Llog2bpmb,Lroot)
+ ok:=ADFSGetHardDriveParams(harddrivesize,bigmap,ide,Lidlen,Lzone_spare,
+ Lnzones,Llog2bpmb,Lroot,Llog2secsize,Llowsec)
else
ok:=True; //old map is easier
//Got some figures OK, so now do the formatting
@@ -1589,7 +1655,7 @@ function TDiscImage.FormatADFSHDD(harddrivesize:Cardinal;newmap:Boolean;dirtype:
//Set the filename
imagefilename:='Untitled.'+FormatExt;
//Setup the data area
- emuheader:=0;//If required, put $200 in here.
+ if addheader then emuheader:=$200 else emuheader:=0;
SetDataLength(harddrivesize+emuheader);
//Fill with zeros
for t:=0 to GetDataLength-1 do WriteByte(0,t);
@@ -1608,12 +1674,20 @@ function TDiscImage.FormatADFSHDD(harddrivesize:Cardinal;newmap:Boolean;dirtype:
nzones:=Lnzones;
bpmb:=1<512*1024*1024 then big_flag:=1;
end;
- FormatNewMapADFS(disctitle);
+ FormatNewMapADFS(disctitle,ide);
end;
//Now write the root
dirid:=root_name;
@@ -1736,7 +1810,7 @@ function TDiscImage.ADFSGetFreeFragments(offset:Boolean=True): TFragmentArray;
startoffset:=0;
while startoffset<=Ceil(nzones/2) do
begin
- zone:=(zonecounter{+startzone}){mod nzones};
+ zone:=zonecounter;
//i is the bit counter...number of bits from the first freelink
//Get the first freelink of the zone and set our counter
i:=ReadBits(bootmap+(zone*secsize)+1,0,15);
@@ -1762,7 +1836,7 @@ function TDiscImage.ADFSGetFreeFragments(offset:Boolean=True): TFragmentArray;
//Read in the next free link number of bits - this can be idlen bits
freelink:=ReadBits(bootmap+(zone*secsize)+1+(i DIV 8),i mod 8,idlen);
//Now find the end of the fragment length
- j:=(i+idlen)-1; //Start after the freelink
+ j:=i-1; //Start after the freelink
repeat
inc(j); //Length counter
//Continue until we find a set bit
@@ -1809,19 +1883,60 @@ function TDiscImage.ADFSGetFreeFragments(offset:Boolean=True): TFragmentArray;
{-------------------------------------------------------------------------------
Write a file to ADFS image
-------------------------------------------------------------------------------}
-function TDiscImage.WriteADFSFile(var file_details:TDirEntry;var buffer:TDIByteArray;
- extend:Boolean=True): Integer;
+function TDiscImage.WriteADFSFile(var file_details: TDirEntry;
+ var buffer: TDIByteArray;extend: Boolean=True): Integer;
//Set extend to FALSE to ensure that the ExtendDirectory is run (Big Directory)
var
- dir : Integer;
timestamp : Int64;
- l,ref,ptr,
+ dir,entry,
+ l,ptr,
freeptr,
safilelen,
- dest,fragid : Cardinal;
+ dest,fragid : Cardinal;
success,
spacefound : Boolean;
fragments : TFragmentArray;
+ sharedbyte : Byte;
+ //Set the shared byte
+ procedure SetSharedByte(entrylength: Cardinal;setinitial: Boolean);
+ begin
+ //Get the sharing offset
+ if setinitial then
+ sharedbyte:=ADFSSectorAlignLength(entrylength,False)div secsize;
+ //If these are equal, we need to move on 1
+ if ADFSSectorAlignLength(entrylength,False)=entrylength then inc(sharedbyte);
+ end;
+ //Check for shared fragment
+ procedure CheckForShared(start: Integer);
+ var
+ entry2 : Cardinal;
+ currfile: String;
+ begin
+ //Don't check the current file, as this will be the same (obvs)
+ if start>=0 then currfile:=FDisc[dir].Entries[start].Filename
+ else currfile:='';
+ //Iterate through the other files in the directory
+ if Length(FDisc[dir].Entries)>0 then
+ for entry2:=0 to Length(FDisc[dir].Entries)-1 do
+ if (FDisc[dir].Entries[entry2].Sector>>8=fragid)
+ and(FDisc[dir].Entries[entry2].Sector mod$100>=sharedbyte)
+ and(FDisc[dir].Entries[entry2].Filename<>currfile)then
+ begin
+ //Work out the shared byte
+ sharedbyte:=(ADFSSectorAlignLength(FDisc[dir].Entries[entry2].Length
+ ,False)div secsize)
+ +(FDisc[dir].Entries[entry2].Sector mod $100);
+ //As before, if the lengths are equal, move on 1
+ SetSharedByte(FDisc[dir].Entries[entry2].Length,False);
+ end;
+ //No space sharing with siblings, so reset the flag
+ if safilelen>fragments[0].Length-sharedbyte*secsize then
+ begin
+ sharedbyte:=$00;
+ SetLength(fragments,0);
+ end;
+ end;
+//Main procedure
begin
//Is this on the AFS partition?
if FAFSPresent then
@@ -1847,10 +1962,11 @@ function TDiscImage.WriteADFSFile(var file_details:TDirEntry;var buffer:TDIByteA
if not((file_details.Filename=root_name)and(FDirType=diADFSBigDir))then
file_details.Filename:=ValidateADFSFilename(file_details.Filename);
//First make sure it doesn't exist already
- if(not FileExists(file_details.Parent+dir_sep+file_details.Filename,ref))
+ if(not FileExists(file_details.Parent+dir_sep+file_details.Filename,dir,entry))
or((file_details.Filename=root_name)and(FDirType=diADFSBigDir))then
//Get the directory where we are adding it to, and make sure it exists
- if(FileExists(file_details.Parent,ref))OR(file_details.Parent=root_name)then
+ if(FileExists(file_details.Parent,dir,entry))
+ OR(file_details.Parent=root_name)then
begin
if file_details.filename<>root_name then
begin
@@ -1859,7 +1975,7 @@ function TDiscImage.WriteADFSFile(var file_details:TDirEntry;var buffer:TDIByteA
if file_details.Parent=root_name then
dir :=0
else
- dir :=FDisc[ref div $10000].Entries[ref mod $10000].DirRef;
+ dir :=FDisc[dir].Entries[entry].DirRef;
//Has it been read in?
if not FDisc[dir].BeenRead then ReadDirectory(file_details.Parent);
//Big Dir - Verify directory is big enough or if it needs extending and moved.
@@ -1872,7 +1988,7 @@ function TDiscImage.WriteADFSFile(var file_details:TDirEntry;var buffer:TDIByteA
//Get the length of the file
l:=Length(FDisc[dir].Entries);
//Work out the "sector aligned file length"
- safilelen:=Ceil(file_details.Length/secsize)*secsize;
+ safilelen:=ADFSSectorAlignLength(file_details.Length,False);
end else safilelen:=file_details.Length; //New length of the root
Result:=-4;//Catalogue full
//Make sure it will actually fit on the disc
@@ -1887,9 +2003,55 @@ function TDiscImage.WriteADFSFile(var file_details:TDirEntry;var buffer:TDIByteA
spacefound:=False;
success:=False;
dest:=disc_size[0];
+ sharedbyte:=$00; //Clear this to indicate we're not reusing
//Find a big enough space
- fragid:=0; //The function returns the fragment ID, or free pointer, with this
- fragments:=ADFSFindFreeSpace(file_details.Length,fragid);
+ if (FMap)
+ and(Pos('D',file_details.Attributes)=0)
+ and(file_details.filename<>root_name)
+ and(file_details.Length<((idlen+1)*bpmb)-secsize)then
+ begin
+ //Looks like we can share this - is there any already shared we can reuse
+ //First check the parent - if this is '1' then see if there's any space
+ if (FDisc[dir].Sector mod $100=$01)
+ and(FDisc[dir].Directory<>root_name)then //Don't share with the root though
+ begin
+ //Get the fragments for this object
+ fragments:=NewDiscAddrToOffset(FDisc[dir].Sector);
+ //If there is not just the one, then skip
+ if Length(fragments)=1 then
+ begin
+ //Get the fragment ID
+ fragid:=FDisc[dir].Sector>>8;
+ //And the sharing offset
+ SetSharedByte(FDisc[dir].Length,True);
+ //And check the children for the same ID
+ CheckForShared(-1);
+ end;
+ end;
+ //No space, so go through the children and do the same checks
+ if(sharedbyte=$00)and(Length(FDisc[dir].Entries)>0)then
+ for entry:=0 to Length(FDisc[dir].Entries)-1 do
+ if(FDisc[dir].Entries[entry].Sector mod$100=$01)
+ and(entry>8;
+ //And the sharing offset
+ SetSharedByte(FDisc[dir].Entries[entry].Length,True);
+ CheckForShared(entry);
+ end;
+ end;
+ end;
+ //Nothing we can reuse, so look for a new one
+ if sharedbyte=$00 then
+ begin
+ fragid:=0; //The function returns the fragment ID, or free pointer, with this
+ fragments:=ADFSFindFreeSpace(file_details.Length,fragid);
+ end;
//Set the flag, if space has been found
spacefound:=Length(fragments)>0;
//Need to set up some variables for old map
@@ -1903,6 +2065,9 @@ function TDiscImage.WriteADFSFile(var file_details:TDirEntry;var buffer:TDIByteA
if(spacefound)and(Length(fragments)>0)then
begin
Result:=-5;//Unknown error
+ //Compensate for shared fragment
+ if(Length(fragments)=1)and(sharedbyte>$01)then
+ inc(fragments[0].Offset,(sharedbyte-1)*secsize);
//Write the data back to the image
success:=WriteFragmentedData(fragments,buffer);
//Set this marker to the start of the first offset
@@ -1912,7 +2077,7 @@ function TDiscImage.WriteADFSFile(var file_details:TDirEntry;var buffer:TDIByteA
if success then
begin
//Update the checksum, if it is a directory
- if(Pos('D',file_details.Attributes)>0){or(file_details.filename='$')}then
+ if(Pos('D',file_details.Attributes)>0)then
if FDirType>diADFSOldDir then //New/Big Directory (Old Dir has zero for checksum)
WriteByte(CalculateADFSDirCheck(dest),dest+(file_details.Length-1));
//Now update the free space map
@@ -1920,14 +2085,24 @@ function TDiscImage.WriteADFSFile(var file_details:TDirEntry;var buffer:TDIByteA
ADFSAllocateFreeSpace(file_details.Length,freeptr);
if FMap then //New map
begin
- file_details.Sector:=fragid*$100; //take account of the sector offset
- ADFSAllocateFreeSpace(file_details.Length,fragid,fragments);
+ //Can this fragment be shared, if not already?
+ if (sharedbyte=$00)
+ and(Length(fragments)=1)
+ and(file_details.Length<(idlen+1)*bpmb)
+ and(fragments[0].Length-file_details.Length>secsize)then sharedbyte:=$01;
+ //Unless it's Big Map and is a directory (not shared because they grow)
+ if(FDirType=diADFSBigDir)
+ and(Pos('D',file_details.Attributes)>0)
+ and(file_details.filename<>root_name)then sharedbyte:=$00;
+ //Make note of the fragment ID
+ file_details.Sector:=fragid<<8+sharedbyte;
+ //Only need to allocate the free space if we're not reusing
+ if sharedbyte<$02 then
+ ADFSAllocateFreeSpace(file_details.Length,fragid,fragments);
end;
//Now update the directory (local copy)
if file_details.filename<>root_name then
begin
- //Get the number of entries in the directory
- ref:=Length(FDisc[dir].Entries);
//Convert load/exec address into filetype and datestamp, if necessary
ADFSCalcFileDate(file_details);
//Now we add the entry into the directory catalogue
@@ -2014,14 +2189,15 @@ function TDiscImage.ADFSFindFreeSpace(filelen: Cardinal;
safilelen,
i,j,
freelink,
- zone : Cardinal;
+ zone,
+ idperzone : Cardinal;
spacefound : Boolean;
fsfragments: TFragmentArray;
begin
Result:=nil;
spacefound:=False;
//Work out the "sector aligned file length"
- safilelen:=Ceil(filelen/secsize)*secsize;
+ safilelen:=ADFSSectorAlignLength(filelen,False);//Ceil(filelen/secsize)*secsize;
//Find some free space
if not FMap then //Old map
begin
@@ -2042,6 +2218,7 @@ function TDiscImage.ADFSFindFreeSpace(filelen: Cardinal;
//New map
if FMap then
begin
+ idperzone:=((secsize*8)-zone_spare)div(idlen+1); //Max IDs per zone
//Get the free space fragments
fsfragments:=ADFSGetFreeFragments;
if Length(fsfragments)>0 then
@@ -2049,7 +2226,8 @@ function TDiscImage.ADFSFindFreeSpace(filelen: Cardinal;
//Go through them to find a big enough fragment
i:=0;
repeat
- if(fsfragments[i].Length>=filelen)
+ if(fsfragments[i].Length>=safilelen)
+ and(fsfragments[i].Length>=(idlen+1)*bpmb)//Smallest possible length
and(fsfragments[i].Offset+filelen0)and(fragid=0)then
begin
- // Now scan the zone again and find a unique ID
- zone:=Result[0].Zone; //Zone of the first fragment
- // IDs start here for this zone
- fragid:=zone*(((secsize*8)-zone_spare)div(idlen+1));
- if fragid<3 then fragid:=3; //Can't be 0,1 or 2
- {if zone=0 then j:=3 else }j:=0; //Highest used ID in this zone
- //Check each fragment ID until we find one that doesn't exist
- while Length(NewDiscAddrToOffset((fragid+j)*$100))>0 do
- inc(j);
- inc(fragid,j); //We'll use this one
+ i:=0;
+ while(fragid=0)and(i0)and(j=1<ref then
begin
@@ -2162,42 +2358,54 @@ procedure TDiscImage.ADFSAllocateFreeSpace(filelen,freeptr: Cardinal);
//Update the checksums
WriteByte(ByteCheckSum($0000,$100),$0FF);
WriteByte(ByteCheckSum($0100,$100),$1FF);
+ Result:=True;
end;
end;
{-------------------------------------------------------------------------------
Allocate the space in the free space map (new map)
-------------------------------------------------------------------------------}
-procedure TDiscImage.ADFSAllocateFreeSpace(filelen,fragid: Cardinal;
- fragments: TFragmentArray);
+function TDiscImage.ADFSAllocateFreeSpace(filelen,fragid: Cardinal;
+ fragments: TFragmentArray): Boolean;
var
ref,
safilelen,
freeptr,
freelink,
zone,
+ zoneptr,
ptr,i,j : Cardinal;
+ zonesize : QWord;
freelen : Byte;
+ //freelen is set to 15 bits if it is the first entry in the zone.
+ procedure SetFreeLen(pos: Cardinal);
+ begin
+ if pos=8 then freelen:=15 else freelen:=idlen;
+ end;
begin
+ Result:=False;
if FMap then //New map
begin
+ Result:=True;
//Recalculate the file length to be bpmb-aligned
safilelen:=ADFSSectorAlignLength(filelen);
+ //Zone size, so we don't accidentally go over the end
+ zonesize:=((secsize*8)-zone_spare)+$20; //Take account of the 4-byte zone header
//For each fragment:
for i:=0 to Length(fragments)-1 do
begin
//Scan the zone, from the beginning, until we find a pointer to our fragment
zone:=fragments[i].Zone; //Zone
- freeptr:=(1+zone*secsize)*8;//Pointer to the next freelink, start at the beginning
+ zoneptr:=zone*secsize; //Pointer to the start of the zone
+ freeptr:=(1+zoneptr)*8; //Pointer to the next freelink, start at the beginning
repeat
//Next freelink
- if freeptr-(zone*secsize*8)=8 then freelen:=15 else freelen:=idlen;
- freelink:=ReadBits(bootmap+(freeptr DIV 8),
- freeptr MOD 8,freelen);
+ SetFreeLen(freeptr-(zoneptr*8));
+ freelink:=ReadBits(bootmap+(freeptr DIV 8),freeptr MOD 8,freelen);
//move the pointer on
inc(freeptr,freelink);
//we need it as an absolute address
- ref:=((freeptr-$200)-zone_spare*zone)*bpmb;
+ ref:=((freeptr-$200)-zone_spare*zone)*bpmb; // $200 is 64 bytes in bits
//Continue until it points to our fragment
until ref=fragments[i].Offset;
//Make a note of the length of data we are laying down for this fragment
@@ -2212,59 +2420,80 @@ procedure TDiscImage.ADFSAllocateFreeSpace(filelen,fragid: Cardinal;
//Smallest object size has to be bigger than idlen
if reffragments[i].Length then
begin
//Adjust the previous freelink to point to after this fragment
- if(freeptr-(zone*secsize))-freelink=8 then freelen:=15 else freelen:=idlen;
- WriteBits(freelink+ref,
- bootmap+(freeptr-freelink)DIV 8,(freeptr-freelink)MOD 8,
- freelen);
+ SetFreeLen((freeptr-zoneptr*8)-freelink);
+ if (((freeptr-freelink)-zoneptr*8)+freelen<=zonesize)
+ and(Result)then
+ WriteBits(freelink+ref,
+ bootmap+(freeptr-freelink)DIV 8,(freeptr-freelink)MOD 8,
+ freelen)
+ else Result:=False;
//Reduce the freelink for this fragment by the above length and move afterwards
//If it is not zero
- if (freeptr-(zone*secsize))+ref=8 then freelen:=15 else freelen:=idlen;
+ SetFreeLen((freeptr-zoneptr*8)+ref);
if ptr<>0 then
if ReadBits(bootmap+(freeptr+ref)DIV 8,(freeptr+ref)MOD 8,freelen)=0 then
- WriteBits(ptr-ref,bootmap+(freeptr+ref)DIV 8,(freeptr+ref)MOD 8,freelen);
+ if (((freeptr+ref)-zoneptr*8)+freelen<=zonesize)and(Result)then
+ WriteBits(ptr-ref,bootmap+(freeptr+ref)DIV 8,(freeptr+ref)MOD 8,freelen)
+ else Result:=False;
end
else
//If the data we are laying down fits exactly into the space
begin
//Take this pointer and add it to the previous pointer
- if (freeptr-(zone*secsize))-freelink=8 then freelen:=15 else freelen:=idlen;
+ SetFreeLen((freeptr-zoneptr*8)-freelink);
//Unless this pointer is zero, then the previous will need to be zero
if ptr<>0 then
- WriteBits(0,
- bootmap+(freeptr-freelink)DIV 8,(freeptr-freelink)MOD 8,
- freelen)
+ begin
+ if (((freeptr-freelink)-zoneptr*8)+freelen<=zonesize)and(Result)then
+ WriteBits(0,
+ bootmap+(freeptr-freelink)DIV 8,(freeptr-freelink)MOD 8,
+ freelen)
+ else Result:=False;
+ end
else
- WriteBits(freelink+ptr+ref,bootmap+(freeptr-freelink)DIV 8,
- (freeptr-freelink)MOD 8,
- freelen);
+ begin
+ if (((freeptr-freelink)-zoneptr*8)+freelen>4=diAcornADFS then //Can't fix it if it isn't ADFS
+ if GetMajorFormatNumber=diAcornADFS then //Can't fix it if it isn't ADFS
begin
//Go through each directory and find any reported as broken
if Length(FDisc)>0 then
@@ -3790,7 +4020,7 @@ function TDiscImage.FixBrokenADFSDirectories: Boolean;
if FDisc[FDisc[dir].Entries[entry].DirRef].Broken then
Result:=FixADFSDirectory(dir,entry)or Result;//Set to true to indicate it has changed
end;
- FDisc:=ReadADFSDisc; //Rescan the image
+ ReadADFSDisc; //Rescan the image
end;
end;
@@ -3919,8 +4149,9 @@ function TDiscImage.FixADFSDirectory(dir,entry: Integer): Boolean;
{-------------------------------------------------------------------------------
Calculates the parameters for a new map hard drive
-------------------------------------------------------------------------------}
-function TDiscImage.ADFSGetHardDriveParams(Ldiscsize:Cardinal;bigmap:Boolean;
- var Lidlen,Lzone_spare,Lnzones,Llog2bpmb,Lroot: Cardinal):Boolean;
+function TDiscImage.ADFSGetHardDriveParams(Ldiscsize:Cardinal;bigmap,ide:Boolean;
+ var Lidlen,Lzone_spare,Lnzones,Llog2bpmb,Lroot,
+ Llog2secsize,Llowsec: Cardinal):Boolean;
//Adapted from the RISC OS RamFS ARM code procedure InitDiscRec in RamFS50
var
r0,r1,r2,r3,r4,r6,r7,r8,r9,r10,r11,
@@ -3938,8 +4169,18 @@ function TDiscImage.ADFSGetHardDriveParams(Ldiscsize:Cardinal;bigmap:Boolean;
zone0bits=8*60;
bigdirminsize=2048;
newdirsize=$500;
- Llog2secsize=9; //Min is 8, max is 12. HForm fixes this at 9.
+ //Llog2secsize=9; //Min is 8, max is 12. HForm fixes this at 9.
begin
+ if ide then //IDE format
+ begin
+ Llog2secsize:=9;
+ Llowsec:=1;
+ end
+ else //ST506 format
+ begin
+ Llog2secsize:=8;
+ Llowsec:=0;
+ end;
//heads should be 16, and secspertrack should be 63
Result:=False;
minidlen:=Llog2secsize+3; //idlen MUST be at least log2secsize+3
@@ -4381,7 +4622,7 @@ function TDiscImage.GetADFSMaxLength(lastentry:Boolean): Cardinal;
begin
Result:=0;
//Only for adding AFS partition to 8 bit ADFS
- if(FFormat>>4=diAcornADFS)and(not FMap)and(FDirType=diADFSOldDir)then
+ if(GetMajorFormatNumber=diAcornADFS)and(not FMap)and(FDirType=diADFSOldDir)then
begin
//Is there enough space? Must be contiguous at the end
fsptr:=ReadByte($1FE); //Pointer to next free space entry
@@ -4407,3 +4648,78 @@ function TDiscImage.GetADFSMaxLength(lastentry:Boolean): Cardinal;
end;
end;
end;
+
+{-------------------------------------------------------------------------------
+Produce a report of the image's details
+-------------------------------------------------------------------------------}
+function TDiscImage.ADFSReport(CSV: Boolean): TStringList;
+var
+ temp: String;
+begin
+ Result:=TStringList.Create;
+ if FMap then
+ begin
+ temp:='New Map';
+ if FDirType=diADFSNewDir then temp:=temp+' New Directory';
+ if FDirType=diADFSBigDir then temp:=temp+' Big Directory';
+ Result.Add(temp);
+ if not CSV then Result.Add('');
+ Result.Add('Disc Record');
+ if not CSV then Result.Add('-----------');
+ Result.Add('Sector Size: '+IntToStr(secsize)+' bytes');
+ Result.Add('Sectors per Track: '+IntToStr(secspertrack));
+ Result.Add('Heads: '+IntToStr(heads));
+ temp:=IntToStr(density);
+ case density of
+ 0: temp:='Hard Drive';
+ 1: temp:='Single';
+ 2: temp:='Double';
+ 3: temp:='Double+';
+ 4: temp:='Quad';
+ 8: temp:='Octal';
+ end;
+ Result.Add('Density: '+temp);
+ Result.Add('ID Length: '+IntToStr(idlen)+' bits');
+ Result.Add('Bits per Map Byte (LFAU): '+IntToStr(bpmb)+' bytes');
+ Result.Add('Skew: '+IntToStr(skew));
+ temp:=IntToStr(bootoption[0]);
+ case bootoption[0] of
+ 0: temp:='None';
+ 1: temp:='Load';
+ 2: temp:='Run';
+ 3: temp:='Exec';
+ end;
+ Result.Add('Boot Option: '+temp);
+ Result.Add('Low Sector: '+IntToStr(lowsector));
+ Result.Add('Number of Zones: '+IntToStr(nzones));
+ Result.Add('Zone Spare Bits: '+IntToStr(zone_spare)+' bits');
+ Result.Add('Root Indirect Address: 0x'+IntToHex(rootfrag,8));
+ Result.Add('Disc Size: '+IntToStr(disc_size[0])+' bytes');
+ Result.Add('Disc ID: 0x'+IntToHex(disc_id,4));
+ Result.Add('Disc Name: '+disc_name[0]);
+ Result.Add('Disc Type: 0x'+IntToHex(disctype,4));
+ if FDirType=diADFSBigDir then
+ begin
+ Result.Add('Share Size: 0x'+IntToHex(share_size,4));
+ Result.Add('Big Flag: '+IntToStr(big_flag));
+ Result.Add('Format Version: '+IntToStr(format_vers));
+ Result.Add('Root Size: '+IntToStr(root_size)+' bytes');
+ end;
+ if not CSV then Result.Add('');
+ Result.Add('Root Address: 0x'+IntToHex(root,8));
+ end
+ else
+ begin
+ temp:='Old Map';
+ if FDirType=diADFSNewDir then temp:=temp+' New Directory';
+ if FDirType=diADFSOldDir then temp:=temp+' Old Directory';
+ Result.Add(temp);
+ Result.Add('Disc Size: '+IntToStr(disc_size[0])+' bytes');
+ Result.Add('Disc Name: '+disc_name[0]);
+ Result.Add('Root Address: 0x'+IntToHex(root<<8,8));
+ end;
+ Result.Add('Boot Map Location: 0x'+IntToHex(bootmap,8));
+ Result.Add('Free Space: '+IntToStr(free_space[0])+' bytes');
+ Result.Add('Cylinders: '+IntToStr(Length(free_space_map[0])));
+ Result.Add('Broken Directory Count: '+IntToStr(brokendircount));
+end;
diff --git a/LazarusSource/DiscImage_AFS.pas b/LazarusSource/DiscImage_AFS.pas
index 49f12ba..d4b9e0e 100644
--- a/LazarusSource/DiscImage_AFS.pas
+++ b/LazarusSource/DiscImage_AFS.pas
@@ -80,13 +80,13 @@ function TDiscImage.ID_AFS: Boolean;
end else FFormat:=diInvalidImg; //Headers not matching, no format
end else FFormat:=diInvalidImg; //No header ID, invalid image
end;
- Result:=FFormat>>4=diAcornFS;
+ Result:=GetMajorFormatNumber=diAcornFS;
end;
var
start: Byte;
begin
Result:=False;
- if(FFormat=diInvalidImg)or(FFormat>>4=diAcornFS)then
+ if(FFormat=diInvalidImg)or(GetMajorFormatNumber=diAcornFS)then
begin
//Interleaving, depending on the option
Finterleave:=FForceInter;
@@ -119,10 +119,10 @@ procedure TDiscImage.ReadAFSPartition;
begin
visited:=nil;
//Is this an ADFS disc with Acorn FileStore partition?
- if((FFormat>>4=diAcornADFS)and(FAFSPresent))
- or(FFormat>>4=diAcornFS)then
+ if((GetMajorFormatNumber=diAcornADFS)and(FAFSPresent))
+ or(GetMajorFormatNumber=diAcornFS)then
begin
- if FFormat>>4=diAcornADFS then
+ if GetMajorFormatNumber=diAcornADFS then
begin
afshead:=Read24b($0F6)*secsize;
afshead2:=Read24b($1F6)*secsize;
@@ -139,7 +139,7 @@ procedure TDiscImage.ReadAFSPartition;
if FFormat=diAcornFS<<4+2 then //Level 3
disc_size[0]:=Read24b(afshead+$16)*secsize;
i:=0;
- if FFormat>>4=diAcornADFS then //Level 3/ADFS Hybrid
+ if GetMajorFormatNumber=diAcornADFS then //Level 3/ADFS Hybrid
begin
SetLength(disc_size,2);
SetLength(free_space,2);
@@ -163,7 +163,7 @@ procedure TDiscImage.ReadAFSPartition;
d:=Length(FDisc);
SetLength(FDisc,d+1);
//Start the chain by reading the root
- if FFormat>>4=diAcornADFS then startdir:=afsrootname else startdir:='$';
+ if GetMajorFormatNumber=diAcornADFS then startdir:=afsrootname else startdir:='$';
FDisc[d]:=ReadAFSDirectory(startdir,allocmap);
//Add the root as a visited directory
SetLength(visited,1);
@@ -277,7 +277,7 @@ function TDiscImage.ReadAFSDirectory(dirname:String;addr: Cardinal):TDir;
//And set the partition flag to true
Result.AFSPartition:=True;
//ADFS hybrid?
- if FFormat>>4=diAcornADFS then side:=1 else side:=0;
+ if GetMajorFormatNumber=diAcornADFS then side:=1 else side:=0;
Result.Partition:=side;
//Directory title
Result.Directory:=ReadString($03,-10,buffer);
@@ -386,7 +386,7 @@ function TDiscImage.ReadAFSObject(offset: Cardinal): TDIByteArray;
Result:=nil;
//Make sure it is a valid allocation map for Level 3
if(ReadString(offset,-6)='JesMap')
- and((FFormat=diAcornFS<<4+2)or(FFormat>>4=diAcornADFS))then
+ and((FFormat=diAcornFS<<4+2)or(GetMajorFormatNumber=diAcornADFS))then
begin
//Start of the list
ptr:=$0A;
@@ -480,7 +480,7 @@ function TDiscImage.GetAFSObjLength(offset: Cardinal): Cardinal;
end;
//Level 3
if(ReadString(offset,-6)='JesMap')
- and((FFormat=diAcornFS<<4+2)or(FFormat>>4=diAcornADFS))then
+ and((FFormat=diAcornFS<<4+2)or(GetMajorFormatNumber=diAcornADFS))then
begin
lenLSB:=ReadByte(offset+$08); //LSB of the length
ptr:=$0A;
@@ -524,7 +524,7 @@ function TDiscImage.GetAllocationMap(sector:Cardinal;var spt:Cardinal):Cardinal;
if ReadByte(Read24b(afshead+$1B)*secsize)>ReadByte(Read24b(afshead+$1E)*secsize)then
Result:=Read24b(afshead+$1B)*secsize else Result:=Read24b(afshead+$1E)*secsize;
//Level 3 and Hybrid
- if(FFormat=diAcornFS<<4+2)or(FFormat>>4=diAcornADFS)then
+ if(FFormat=diAcornFS<<4+2)or(GetMajorFormatNumber=diAcornADFS)then
begin
spt:=Read16b(afshead+$1A);
//Level 3
@@ -575,18 +575,18 @@ procedure TDiscImage.ReadAFSFSM;
//Get all the used sectors
fragments:=AFSGetFreeSectors(True);
//Initialise the variables
- if FFormat>>4=diAcornFS then //AFS Level 2 and 3
+ if GetMajorFormatNumber=diAcornFS then //AFS Level 2 and 3
begin
SetLength(free_space_map,1);
part:=0;
end;
- if FFormat>>4=diAcornADFS then //Hybrids - AFS will take up the second 'side'
+ if GetMajorFormatNumber=diAcornADFS then //Hybrids - AFS will take up the second 'side'
begin
SetLength(free_space_map,2);
part:=1;
end;
//Get the local sectors per track
- if(FFormat>>4=diAcornADFS)or(FFormat=diAcornFS<<4+2)then
+ if(GetMajorFormatNumber=diAcornADFS)or(FFormat=diAcornFS<<4+2)then
spt:=Read16b(afshead+$1A) else spt:=secspertrack;
//Initialise the free space
free_space[part]:=disc_size[part];
@@ -811,11 +811,11 @@ function TDiscImage.AFSAllocateFreeSpace(size :Cardinal;
if Length(FSM)>0 then
begin
//The above array will have offsets relative to the start of the AFS partition
- if FFormat>>4=diAcornADFS then
+ if GetMajorFormatNumber=diAcornADFS then
for index:=0 to Length(FSM)-1 do
inc(FSM[index].Offset,disc_size[0]); //So add the ADFS size to the offset
//Level 3 includes a 256 byte object header
- if((FFormat=diAcornFS<<4+2)or(FFormat>>4=diAcornADFS))
+ if((FFormat=diAcornFS<<4+2)or(GetMajorFormatNumber=diAcornADFS))
and(addheader)then inc(size,$100);
//Are there any that will fit the data without fragmenting?
index:=0;
@@ -910,7 +910,7 @@ function TDiscImage.AFSAllocateFreeSpace(size :Cardinal;
//Mark as written
WriteBits(1,allocmap+(alloc[index].Offset*2)+6,7,1);
end;
- if(FFormat=diAcornFS<<4+2)or(FFormat>>4=diAcornADFS)then
+ if(FFormat=diAcornFS<<4+2)or(GetMajorFormatNumber=diAcornADFS)then
begin
for fragsize:=0 to Ceil(alloc[index].Length/secsize)-1 do
begin
@@ -961,7 +961,7 @@ procedure TDiscImage.AFSDeAllocateFreeSpace(addr: Cardinal);
FinaliseAFSL2Map;
end;
//Level 3 and Hybrid
- if(FFormat=diAcornFS<<4+2)or(FFormat>>4=diAcornADFS)then
+ if(FFormat=diAcornFS<<4+2)or(GetMajorFormatNumber=diAcornADFS)then
begin
addr:=addr*secsize;
if ReadString(addr,-6)='JesMap' then //Make sure it is a valid block
@@ -1390,7 +1390,7 @@ function TDiscImage.CreateAFSDirectory(dirname,parent,attributes: String): Integ
//Copy of cycle number at end of root
WriteByte(cycle,dirsize-1,buffer);
//First entry at $11 (pointer is $FFFF to indicate parent), for Level 3
- if(FFormat>>4=diAcornADFS)or(FFormat=diAcornFS<<4+2)then
+ if(GetMajorFormatNumber=diAcornADFS)or(FFormat=diAcornFS<<4+2)then
begin
//Get the parent directory address
if dirname<>'$' then
@@ -1413,7 +1413,7 @@ function TDiscImage.CreateAFSDirectory(dirname,parent,attributes: String): Integ
begin
//Then we'll just copy the data across and we're done
addr:=Fafsroot;
- if(FFormat>>4=diAcornADFS)or(FFormat=diAcornFS<<4+2)then addr:=Fafsroot+$100;
+ if(GetMajorFormatNumber=diAcornADFS)or(FFormat=diAcornFS<<4+2)then addr:=Fafsroot+$100;
for ptr:=0 to Length(buffer)-1 do
WriteByte(buffer[ptr],addr+ptr); //Replace with bulk copy function
Result:=0;
@@ -1454,7 +1454,7 @@ function TDiscImage.ExtendAFSDirectory(sector: Cardinal):Cardinal;
buffer:=nil;
l3offset:=0;
//Take account of the JesMap header
- if(FFormat=diAcornFS<<4+2)or(FFormat>>4=diAcornADFS)then l3offset:=secsize;
+ if(FFormat=diAcornFS<<4+2)or(GetMajorFormatNumber=diAcornADFS)then l3offset:=secsize;
//Only continue if the directory needs extending
if Read16b(sector*secsize+$0D+l3offset)=0 then
begin
@@ -1482,7 +1482,7 @@ function TDiscImage.ExtendAFSDirectory(sector: Cardinal):Cardinal;
//Set the directory's next free chain to point into here
Write16b(addr,$0D,buffer);
//Level 3 : Update the JesMap pointers to include this
- if(FFormat=diAcornFS<<4+2)or(FFormat>>4=diAcornADFS)then
+ if(FFormat=diAcornFS<<4+2)or(GetMajorFormatNumber=diAcornADFS)then
begin
//Start of chain
addr:=$0A-5;
@@ -1560,8 +1560,8 @@ function TDiscImage.CreateAFSPassword(Accounts: TUserAccounts): Integer;
afslevel: Byte;
begin
afslevel:=0;
- if FFormat>>4=diAcornFS then afslevel:=(FFormat AND$F)+1;
- if FFormat>>4=diAcornADFS then afslevel:=3;
+ if GetMajorFormatNumber=diAcornFS then afslevel:=(FFormat AND$F)+1;
+ if GetMajorFormatNumber=diAcornADFS then afslevel:=3;
//Default response
Result:=-5;
buffer:=nil; //To stop 'hints' or 'warnings' from the compiler
@@ -1641,7 +1641,7 @@ function TDiscImage.CreateAFSPassword(Accounts: TUserAccounts): Integer;
//Set up the file entry
ResetDirEntry(newentry);
newentry.Filename:='Passwords';
- if FFormat>>4=diAcornADFS then
+ if GetMajorFormatNumber=diAcornADFS then
begin
newentry.Parent :=afsrootname;
newentry.Side :=1;
@@ -1676,7 +1676,7 @@ function TDiscImage.ReadAFSPassword: TUserAccounts;
//Start with a blank array
Result:=nil;
//Get the full pathname for the password file
- if FFormat>>4=diAcornADFS then pwordfile:=afsrootname+dir_sep+'Passwords'
+ if GetMajorFormatNumber=diAcornADFS then pwordfile:=afsrootname+dir_sep+'Passwords'
else pwordfile:=FDisc[0].Directory+dir_sep+'Passwords';
//Make sure it exists
if FileExists(pwordfile,dir,entry) then
@@ -1815,7 +1815,7 @@ function TDiscImage.WriteAFSFile(var file_details: TDirEntry;
//Set the date
file_details.TimeStamp:=Floor(Now);
//Write the file data
- if(FFormat=diAcornFS<<4+2)or(FFormat>>4=diAcornADFS)then
+ if(FFormat=diAcornFS<<4+2)or(GetMajorFormatNumber=diAcornADFS)then
begin
//First, for level 3, we'll need a header
SetLength(block,$100);
@@ -1892,7 +1892,7 @@ procedure TDiscImage.WriteAFSObject(offset: Cardinal;var buffer: TDIByteArray);
begin
//Make sure it is a valid allocation map for Level 3
if(ReadString(offset,-6)='JesMap')
- and((FFormat=diAcornFS<<4+2)or(FFormat>>4=diAcornADFS))then
+ and((FFormat=diAcornFS<<4+2)or(GetMajorFormatNumber=diAcornADFS))then
begin
//Start of the list
ptr:=$0A;
@@ -1974,7 +1974,7 @@ function TDiscImage.RenameAFSFile(oldname:String;var newname: String): Integer;
FDisc[FDisc[dir].Entries[entry].DirRef].Directory:=newname;
//Get the address of the directory
ptr:=FDisc[dir].Entries[entry].Sector*secsize;
- if(FFormat>>4=diAcornADFS)or(FFormat=diAcornFS<<4+2)then //Level 3
+ if(GetMajorFormatNumber=diAcornADFS)or(FFormat=diAcornFS<<4+2)then //Level 3
ptr:=Read24b(ptr+$0A)*secsize;
//And write it to the header
WriteString(newname,ptr+$03,10,32);
@@ -2391,7 +2391,7 @@ function TDiscImage.UpdateAFSDiscTitle(title: String): Boolean;
//Make sure it is not overlength
title:=LeftStr(title,16);
//And update the internal variable
- if FFormat>>4=diAcornADFS then disc_name[1]:=title else disc_name[0]:=title;
+ if GetMajorFormatNumber=diAcornADFS then disc_name[1]:=title else disc_name[0]:=title;
//Write to the image header
WriteString(title,afshead+4,16,32);
//And the copy
@@ -2414,7 +2414,7 @@ function TDiscImage.AddAFSPartition(size: Cardinal): Boolean;
Result:=False;
if size<9*secsize then exit; //Minimum size is 9 sectors
//Only for adding AFS partition to 8 bit ADFS
- if(FFormat>>4=diAcornADFS)and(not FMap)and(FDirType=diADFSOldDir)then
+ if(GetMajorFormatNumber=diAcornADFS)and(not FMap)and(FDirType=diADFSOldDir)then
begin
fsed:=GetADFSMaxLength(False);
//Is there enough free space?
@@ -2463,3 +2463,29 @@ function TDiscImage.AddAFSPartition(size: Cardinal): Boolean;
end;
end;
end;
+
+{-------------------------------------------------------------------------------
+Produce a report of the image's details
+-------------------------------------------------------------------------------}
+function TDiscImage.AFSReport(CSV: Boolean): TStringList;
+var
+ side: Integer;
+begin
+ Result:=TStringList.Create;
+ side:=0;
+ if GetMajorFormatNumber=diAcornADFS then
+ begin
+ side:=1;
+ if not CSV then Result.Add('');
+ Result.Add('Acorn FS partition');
+ if not CSV then Result.Add('------------------');
+ end;
+ Result.Add('Sector Size: '+IntToStr(secsize)+' bytes');
+ Result.Add('Sectors per Track: '+IntToStr(secspertrack));
+ Result.Add('Root Address: 0x'+IntToHex(Fafsroot,8));
+ Result.Add('Root Size: '+IntToStr(afsroot_size)+' bytes');
+ Result.Add('Disc Size: '+IntToStr(disc_size[side])+' bytes');
+ Result.Add('Free Space: '+IntToStr(free_space[side])+' bytes');
+ Result.Add('Boot Map Location: 0x'+IntToHex(afshead,8));
+ Result.Add('Disc Name: '+disc_name[side]);
+end;
diff --git a/LazarusSource/DiscImage_Amiga.pas b/LazarusSource/DiscImage_Amiga.pas
index 3b13e85..7059d06 100644
--- a/LazarusSource/DiscImage_Amiga.pas
+++ b/LazarusSource/DiscImage_Amiga.pas
@@ -32,7 +32,7 @@ function TDiscImage.ID_Amiga: Boolean;
FDirType :=$00;
//Get more details from the boot block disc ID
FMap :=IsBitSet(ReadByte($03),0); //AmigaDOS OFS/FFS
- FDirType:=(ReadByte($03) AND $4)shr 2; //AmigaDOS DIRC
+ FDirType:=(ReadByte($03) AND $4)<<2; //AmigaDOS DIRC
//Look at the checksum
if not FMap then //OFS should have a checksum
begin
@@ -111,7 +111,7 @@ function TDiscImage.ID_Amiga: Boolean;
ResetVariables;
end;
end;
- Result:=FFormat>>4=diAmiga;
+ Result:=GetMajorFormatNumber=diAmiga;
end;
end;
end;
@@ -119,14 +119,14 @@ function TDiscImage.ID_Amiga: Boolean;
{-------------------------------------------------------------------------------
Read Commodore Amiga Disc
-------------------------------------------------------------------------------}
-function TDiscImage.ReadAmigaDisc: TDisc;
+function TDiscImage.ReadAmigaDisc: Boolean;
var
d,ptr,
sectors : Integer;
begin
- Result:=nil;
+ FDisc:=nil;
//Initialise some variables
- SetLength(Result,0);
+ SetLength(FDisc,0);
if FFormat<>diInvalidImg then
begin
//Total number of sectors will be double where the root is
@@ -136,44 +136,45 @@ function TDiscImage.ReadAmigaDisc: TDisc;
//Disc name
disc_name[0]:=ReadString(root*secsize+$1B1,-(root*secsize+$1B0));
//Create an entry for the root
- SetLength(Result,1);
+ SetLength(FDisc,1);
//Blank the values
- ResetDir(Result[0]);
+ ResetDir(FDisc[0]);
//We'll start by reading the root
- Result[0]:=ReadAmigaDir(root_name,root);
+ FDisc[0]:=ReadAmigaDir(root_name,root);
//Now iterate through the entries and find the sub-directories
d:=0;
repeat
//If there are actually any entries
- if Length(Result[d].Entries)>0 then
+ if Length(FDisc[d].Entries)>0 then
begin
//Go through the entries
- for ptr:=0 to Length(Result[d].Entries)-1 do
+ for ptr:=0 to Length(FDisc[d].Entries)-1 do
//And add them if they are valid
- if Result[d].Entries[ptr].Filename<>'' then
+ if FDisc[d].Entries[ptr].Filename<>'' then
begin
//Attribute has a 'F', so drill down
- if Pos('F',Result[d].Entries[ptr].Attributes)>0 then
+ if Pos('F',FDisc[d].Entries[ptr].Attributes)>0 then
begin
//Once found, list their entries
- SetLength(Result,Length(Result)+1);
+ SetLength(FDisc,Length(FDisc)+1);
//Read in the contents of the directory
if FScanSubDirs then
- Result[Length(Result)-1]:=ReadAmigaDir(GetParent(d)+dir_sep
- +Result[d].Entries[ptr].Filename,
- Result[d].Entries[ptr].Sector);
- Result[Length(Result)-1].Parent:=d;
+ FDisc[Length(FDisc)-1]:=ReadAmigaDir(GetParent(d)+dir_sep
+ +FDisc[d].Entries[ptr].Filename,
+ FDisc[d].Entries[ptr].Sector);
+ FDisc[Length(FDisc)-1].Parent:=d;
//Update the directory reference
- Result[d].Entries[ptr].DirRef:=Length(Result)-1;
+ FDisc[d].Entries[ptr].DirRef:=Length(FDisc)-1;
end;
end;
end;
inc(d);
//The length of disc will increase as more directories are found
- until d>=Length(Result);
+ until d>=Length(FDisc);
//Get the free space map
ReadAmigaFSM;
end;
+ Result:=Length(FDisc)>0;
end;
{-------------------------------------------------------------------------------
@@ -582,7 +583,7 @@ function TDiscImage.CreateAmigaDirectory(var dirname,parent,attributes: String):
{-------------------------------------------------------------------------------
Create a new Amiga image - Floppy
-------------------------------------------------------------------------------}
-function TDiscImage.FormatAmigaFDD(minor: Byte): TDisc;
+function TDiscImage.FormatAmigaFDD(minor: Byte): Boolean;
begin
//Blank everything
ResetVariables;
@@ -590,8 +591,8 @@ function TDiscImage.FormatAmigaFDD(minor: Byte): TDisc;
//Set the format
//FFormat:=diAmiga<<4+minor;
//Start with blank result
- Result:=nil;
- SetLength(Result,0);
+ FDisc:=nil;
+ SetLength(FDisc,0);
//Format the drive
case minor of
0: FormatAmiga(880*1024);
@@ -606,7 +607,7 @@ function TDiscImage.FormatAmigaFDD(minor: Byte): TDisc;
{-------------------------------------------------------------------------------
Create a new Amiga image - Hard Disc
-------------------------------------------------------------------------------}
-function TDiscImage.FormatAmigaHDD(harddrivesize: Cardinal): TDisc;
+function TDiscImage.FormatAmigaHDD(harddrivesize: Cardinal): Boolean;
begin
//Blank everything
ResetVariables;
@@ -614,8 +615,8 @@ function TDiscImage.FormatAmigaHDD(harddrivesize: Cardinal): TDisc;
//Set the format
//FFormat:=diAmiga<<4+$F;
//Start with blank result
- Result:=nil;
- SetLength(Result,0);
+ FDisc:=nil;
+ SetLength(FDisc,0);
//Format the drive
FormatAmiga(harddrivesize);
//Read it back in to set the rest up
@@ -936,7 +937,7 @@ procedure TDiscImage.ReadAmigaFSM;
c,d : Cardinal;
bit : Byte;
begin
- UpdateProgress('Reading Free Space Map');
+ //UpdateProgress('Reading Free Space Map');
//Set up the variables
free_space[0]:=0;
secspertrack:=22;//Not used anywhere else
@@ -1395,3 +1396,31 @@ procedure TDiscImage.ValidateAmigaFile(var filename: String);
//If nothing was supplied, then supply something
if Length(filename)=0 then filename:='Unnamed';
end;
+
+{-------------------------------------------------------------------------------
+Produce a report of the image's details
+-------------------------------------------------------------------------------}
+function TDiscImage.AmigaReport(CSV: Boolean): TStringList;
+var
+ temp: String;
+begin
+ Result:=TStringList.Create;
+ if FMap then temp:='Fast File System' else temp:='Original File System';
+ if FDirType=diAmigaDir then temp:=temp+' AmigaDOS Directory';
+ if FDirType=diAmigaCache then temp:=temp+' AmigaDOS Directory Cache';
+ Result.Add(temp);
+ Result.Add('Sector Size: '+IntToStr(secsize)+' bytes');
+ temp:=IntToStr(density);
+ case density of
+ 0: temp:='Hard Drive';
+ 1: temp:='Single';
+ 2: temp:='Double';
+ 4: temp:='Quad';
+ 8: temp:='Octal';
+ end;
+ Result.Add('Density: '+temp);
+ Result.Add('Root Address: 0x'+IntToHex(root,8));
+ Result.Add('Disc Size: '+IntToStr(disc_size[0])+' bytes');
+ Result.Add('Free Space: '+IntToStr(free_space[0])+' bytes');
+ Result.Add('Disc Name: '+disc_name[0]);
+end;
diff --git a/LazarusSource/DiscImage_C64.pas b/LazarusSource/DiscImage_C64.pas
index 168c8ab..b4d62f7 100644
--- a/LazarusSource/DiscImage_C64.pas
+++ b/LazarusSource/DiscImage_C64.pas
@@ -80,8 +80,8 @@ function TDiscImage.ID_CDR: Boolean;
//Successful checks
if ctr=16 then FFormat:=diCommodore<<4+2; //1581
end;
- FDSD :=(FFormat mod$10>0)and(FFormat mod$10<$F); //Set/reset the DoubleSided flag
- Result:=FFormat>>4=diCommodore; //Return TRUE if succesful ID
+ FDSD :=(GetMinorFormatNumber>0)and(GetMinorFormatNumber<$F); //Set/reset the DoubleSided flag
+ Result:=GetMajorFormatNumber=diCommodore; //Return TRUE if succesful ID
If Result then FMap:=False; //and reset the NewMap flag
end;
end;
@@ -135,7 +135,7 @@ function TDiscImage.ConvertDxxTS(format,track,sector: Integer): Integer;
{-------------------------------------------------------------------------------
Read Commodore Disc
-------------------------------------------------------------------------------}
-function TDiscImage.ReadCDRDisc: TDisc;
+function TDiscImage.ReadCDRDisc: Boolean;
var
ptr,t,s,amt,
file_chain,
@@ -143,9 +143,9 @@ function TDiscImage.ReadCDRDisc: TDisc;
ch,c,f,dirTr :Integer;
temp : String;
begin
- Result:=nil;
- SetLength(Result,1);
- ResetDir(Result[0]);
+ FDisc:=nil;
+ SetLength(FDisc,1);
+ ResetDir(FDisc[0]);
//Get the format
f:=FFormat AND $F; //'f' is the format - 0: D64, 1: D71, 2: D81
dirTr:=18; //D64 and D71 disc info is on track 18, sector 0
@@ -179,9 +179,9 @@ function TDiscImage.ReadCDRDisc: TDisc;
ptr:=ConvertDxxTS(f,t,s);
amt:=0;
//Set the root directory name
- Result[0].Directory:=root_name;
- Result[0].Sector:=root;
- Result[0].BeenRead:=True;
+ FDisc[0].Directory:=root_name;
+ FDisc[0].Sector:=root;
+ FDisc[0].BeenRead:=True;
repeat
//Track/Sector for next link or 00/FF for end
t:=ReadByte(ptr);
@@ -189,34 +189,34 @@ function TDiscImage.ReadCDRDisc: TDisc;
for c:=0 to 7 do
if ReadByte(ptr+(c*$20)+2)>$00 then
begin
- SetLength(Result[0].Entries,amt+1);
- ResetDirEntry(Result[0].Entries[amt]);
- Result[0].Entries[amt].Parent:=root_name;
+ SetLength(FDisc[0].Entries,amt+1);
+ ResetDirEntry(FDisc[0].Entries[amt]);
+ FDisc[0].Entries[amt].Parent:=root_name;
//First track/sector of Fdata
- Result[0].Entries[amt].Track :=ReadByte(ptr+(c*$20)+3);
- Result[0].Entries[amt].Sector:=ReadByte(ptr+(c*$20)+4);
+ FDisc[0].Entries[amt].Track :=ReadByte(ptr+(c*$20)+3);
+ FDisc[0].Entries[amt].Sector:=ReadByte(ptr+(c*$20)+4);
//Filetype
- Result[0].Entries[amt].ShortFiletype:=
+ FDisc[0].Entries[amt].ShortFiletype:=
LeftStr(CDRFileTypes[ReadByte(ptr+(c*$20)+2) AND $0F],3);
- Result[0].Entries[amt].Filetype:=
+ FDisc[0].Entries[amt].Filetype:=
Copy(CDRFileTypes[ReadByte(ptr+(c*$20)+2) AND $0F],4);
//Attributes
if (ReadByte(ptr+(c*$20)+2) AND $40)=$40 then //Locked
- Result[0].Entries[amt].Attributes:=Result[0].Entries[amt].Attributes+'L';
+ FDisc[0].Entries[amt].Attributes:=FDisc[0].Entries[amt].Attributes+'L';
if (ReadByte(ptr+(c*$20)+2) AND $80)=$80 then // Closed
- Result[0].Entries[amt].Attributes:=Result[0].Entries[amt].Attributes+'C';
+ FDisc[0].Entries[amt].Attributes:=FDisc[0].Entries[amt].Attributes+'C';
//Length of file - in sectors
- Result[0].Entries[amt].Length:=Read16b(ptr+(c*$20)+$1E);
+ FDisc[0].Entries[amt].Length:=Read16b(ptr+(c*$20)+$1E);
//now follow the chain to find the exact file length}
file_ptr:=ConvertDxxTS(f,
- Result[0].Entries[amt].Track,Result[0].Entries[amt].Sector); //first sector
+ FDisc[0].Entries[amt].Track,FDisc[0].Entries[amt].Sector); //first sector
//Now read the rest of the chain
- for file_chain:=1 to Result[0].Entries[amt].Length-1 do
+ for file_chain:=1 to FDisc[0].Entries[amt].Length-1 do
file_ptr:=ConvertDxxTS(f,ReadByte(file_ptr),ReadByte(file_ptr+1));
//and get the partial usage of final sector
if ReadByte(file_ptr)=$00 then
- Result[0].Entries[amt].Length:=
- ((Result[0].Entries[amt].Length-1)*254)+ReadByte(file_ptr+1)-1;
+ FDisc[0].Entries[amt].Length:=
+ ((FDisc[0].Entries[amt].Length-1)*254)+ReadByte(file_ptr+1)-1;
//Filename
temp:='';
for ch:=0 to 15 do
@@ -224,20 +224,21 @@ function TDiscImage.ReadCDRDisc: TDisc;
p:=ReadByte(ptr+(c*$20)+5+ch);
if (p>32) and (p<>$A0) then temp:=temp+chr(p AND $7F);
end;
- Result[0].Entries[amt].Filename:=temp;
+ FDisc[0].Entries[amt].Filename:=temp;
//Not a directory - not used by D64/D71/D81
- Result[0].Entries[amt].DirRef:=-1;
+ FDisc[0].Entries[amt].DirRef:=-1;
inc(amt);
end;
//If not end of directory, go to next block
if (t<>$00) and (s<>$FF) then ptr:=ConvertDxxTS(f,t,s);
until (t=$00) and (s=$FF);
+ Result:=Length(FDisc)>0;
end;
{-------------------------------------------------------------------------------
Create a new, blank, disc
-------------------------------------------------------------------------------}
-function TDiscImage.FormatCDR(minor: Byte): TDisc;
+function TDiscImage.FormatCDR(minor: Byte): Boolean;
var
t,i : Integer;
c : Byte;
@@ -376,7 +377,8 @@ function TDiscImage.FormatCDR(minor: Byte): TDisc;
//First directory entry
WriteByte($FF,$61B01);
end;
- Result:=ReadCDRDisc;
+ ReadCDRDisc;
+ Result:=Length(FDisc)>0;
end;
{-------------------------------------------------------------------------------
@@ -491,7 +493,7 @@ procedure TDiscImage.CDRSetClearBAM(track,sector: Byte;used: Boolean);
ptr,
ptr1 : Cardinal;
begin
- f:=FFormat mod $10;
+ f:=GetMinorFormatNumber;
//Pointer to BAM number of free sectors:
//ptr will be the number of free sectors
//ptr1 will be the allocation bits for the track
@@ -543,8 +545,8 @@ function TDiscImage.UpdateCDRDiscTitle(title: String): Boolean;
begin
disc_name[0]:=title;
//Get the location of the disc title, less one
- if FFormat mod $10<2 then ptr:=ConvertDxxTS(FFormat mod $10,18,0)+$8F;
- if FFormat mod $10=2 then ptr:=ConvertDxxTS(FFormat mod $10,40,0)+$03;
+ if GetMinorFormatNumber<2 then ptr:=ConvertDxxTS(GetMinorFormatNumber,18,0)+$8F;
+ if GetMinorFormatNumber=2 then ptr:=ConvertDxxTS(GetMinorFormatNumber,40,0)+$03;
//Fill the 16 bytes
for i:=1 to 16 do
begin
@@ -627,7 +629,7 @@ function TDiscImage.WriteCDRFile(file_details: TDirEntry;
count:=file_details.Length;
if count>0 then //Make sure that there is something to write
begin
- f:=FFormat MOD $10; //Minor format (sub format)
+ f:=GetMinorFormatNumber; //Minor format (sub format)
//Overwrite the parent
file_details.Parent:=root_name;
//Check that the filename is valid
@@ -770,7 +772,7 @@ procedure TDiscImage.UpdateCDRCat;
sector:=1; //Sector where the first directory is
maxsector:=19; //Maximum sectors on this track
//1581 track and sector number
- if FFormat mod $10=2 then
+ if GetMinorFormatNumber=2 then
begin
track:=40;
sector:=3;
@@ -804,7 +806,7 @@ procedure TDiscImage.UpdateCDRCat;
free_space_map[0,track-1,dirsector]:=$FE;
sectors[i DIV 8]:=dirsector;
end;
- ptr:=ConvertDxxTS(FFormat mod $10,track,dirsector)+(i MOD 8)*$20;
+ ptr:=ConvertDxxTS(GetMinorFormatNumber,track,dirsector)+(i MOD 8)*$20;
//t/s link to next directory - they are all 00/00 except for the first
WriteByte($00,ptr ); //Track
WriteByte($00,ptr+1); //Sector
@@ -862,7 +864,7 @@ procedure TDiscImage.UpdateCDRCat;
for i:=0 to j do
begin
//Pointer to this directory
- ptr:=ConvertDxxTS(FFormat mod $10,track,sectors[i]);
+ ptr:=ConvertDxxTS(GetMinorFormatNumber,track,sectors[i]);
if i=j then WriteByte($00,ptr) else WriteByte(track,ptr);
WriteByte(sectors[i+1],ptr+1);
//Update the BAM for the system track
@@ -921,7 +923,7 @@ function TDiscImage.CDRFindNextTrack(var track,sector: Byte): Boolean;
freesecs : Boolean;
begin
//Number of sides - also, number of times to repeat main loop
- if FFormat mod $10=1 then cycles:=2 else cycles:=1;
+ if GetMinorFormatNumber=1 then cycles:=2 else cycles:=1;
//Counter for distance from root
counter:=1;
repeat
@@ -931,7 +933,7 @@ function TDiscImage.CDRFindNextTrack(var track,sector: Byte): Boolean;
while i$00 do
begin
CDRSetClearBAM(track,sector,False);
- ptr:=ConvertDxxTS(FFormat MOD$10,track,sector);
+ ptr:=ConvertDxxTS(GetMinorFormatNumber,track,sector);
track:=ReadByte(ptr);
sector:=ReadByte(ptr+1);
for i:=0 to $FF do WriteByte($00,ptr+i);// Delete the data
@@ -1071,3 +1073,17 @@ function TDiscImage.UpdateCDRFileAttributes(filename,attributes: String):Boolean
Result:=True;
end;
end;
+
+{-------------------------------------------------------------------------------
+Produce a report of the image's details
+-------------------------------------------------------------------------------}
+function TDiscImage.CDRReport(CSV: Boolean): TStringList;
+begin
+ Result:=TStringList.Create;
+ if FDSD then Result.Add('Double Sided') else Result.Add('Single Sided');
+ Result.Add('Disc Size: '+IntToStr(disc_size[0])+' bytes');
+ Result.Add('Free Space: '+IntToStr(free_space[0])+' bytes');
+ Result.Add('Disc Name: '+disc_name[0]);
+ Result.Add('Root Address: 0x'+IntToHex(root,8));
+ Result.Add('Tracks: '+IntToStr(Length(free_space_map[0])));
+end;
diff --git a/LazarusSource/DiscImage_CFS.pas b/LazarusSource/DiscImage_CFS.pas
index c701679..180fb5c 100644
--- a/LazarusSource/DiscImage_CFS.pas
+++ b/LazarusSource/DiscImage_CFS.pas
@@ -31,7 +31,7 @@ function TDiscImage.ID_CFS: Boolean;
{-------------------------------------------------------------------------------
Read in and decode the file
-------------------------------------------------------------------------------}
-function TDiscImage.ReadUEFFile: TDisc;
+function TDiscImage.ReadUEFFile: Boolean;
var
i,j : Integer;
filenum,
@@ -52,10 +52,10 @@ function TDiscImage.ReadUEFFile: TDisc;
crcok : Boolean;
dummy : TDIByteArray;
begin
- Result:=nil;
+ FDisc:=nil;
SetLength(dummy,0);
//Set up the TDisc structure for return
- Result:=FormatCFS;
+ FormatCFS;
{ SetLength(Result,1);
ResetDir(Result[0]);
//Set the root directory name
@@ -106,54 +106,54 @@ function TDiscImage.ReadUEFFile: TDisc;
//Sometimes a file has no filename, so give it one
if temp='' then temp:='?';
//Create a new entry in our array, if need be
- if filenum>=Length(Result[0].Entries) then
+ if filenum>=Length(FDisc[0].Entries) then
begin
//If the last file failed CRC checks on any block, clear the data
if (not crcok) and (Length(FilesData)>0) then
SetLength(FilesData[filenum],0);
//Now create the entry for this file
- SetLength(Result[0].Entries,filenum+1);
- ResetDirEntry(Result[0].Entries[filenum]);
- Result[0].Entries[filenum].Length :=0; //Length counter
- Result[0].Entries[filenum].Filename:=FilenameToASCII(temp);//Filename
- Result[0].Entries[filenum].Sector :=pos-6; //Where to find it (first block)
- Result[0].Entries[filenum].Parent :=Result[0].Directory;
- Result[0].Entries[filenum].DirRef :=-1;
+ SetLength(FDisc[0].Entries,filenum+1);
+ ResetDirEntry(FDisc[0].Entries[filenum]);
+ FDisc[0].Entries[filenum].Length :=0; //Length counter
+ FDisc[0].Entries[filenum].Filename:=FilenameToASCII(temp);//Filename
+ FDisc[0].Entries[filenum].Sector :=pos-6; //Where to find it (first block)
+ FDisc[0].Entries[filenum].Parent :=FDisc[0].Directory;
+ FDisc[0].Entries[filenum].DirRef :=-1;
SetLength(FilesData,filenum+1);
firstblck:=True;
//Read in the load address
- Result[0].Entries[filenum].LoadAddr:=Read32b(pos+i);
+ FDisc[0].Entries[filenum].LoadAddr:=Read32b(pos+i);
//Read in the execution address
- Result[0].Entries[filenum].ExecAddr:=Read32b(pos+i+4);
+ FDisc[0].Entries[filenum].ExecAddr:=Read32b(pos+i+4);
//CRC Checks
crcok:=True;
end;
//Read in the block number
blocknum:=Read16b(pos+i+8);
//Is it a new block, or copy protection?
- if(blocknum>0)and(firstblck)and(Length(Result[0].Entries)>1)then
+ if(blocknum>0)and(firstblck)and(Length(FDisc[0].Entries)>1)then
if (lastblock=blocknum-1)
- and(Result[0].Entries[filenum-1].Filename=Result[0].Entries[filenum].Filename)
+ and(FDisc[0].Entries[filenum-1].Filename=FDisc[0].Entries[filenum].Filename)
{and(files[filenum-1].LoadAddr=files[filenum].LoadAddr)
and(files[filenum-1].ExecAddr=files[filenum].ExecAddr)}then
begin
- SetLength(Result[0].Entries,Length(Result[0].Entries)-1);
+ SetLength(FDisc[0].Entries,Length(FDisc[0].Entries)-1);
dec(filenum);
firstblck:=False;
end;
lastblock:=blocknum;
//Take a note of where we are in the file's data, as we build it up
- ptr:=Result[0].Entries[filenum].Length;
+ ptr:=FDisc[0].Entries[filenum].Length;
//Get the length of this block
blocklen:=Read16B(pos+i+10);
//And add it to the total length
- inc(Result[0].Entries[filenum].Length,blocklen);
+ inc(FDisc[0].Entries[filenum].Length,blocklen);
//Get the block status
blockst:=ReadByte(pos+i+12);
if IsBitSet(blockst,0) then
- Result[0].Entries[filenum].Attributes:='L'
+ FDisc[0].Entries[filenum].Attributes:='L'
else
- Result[0].Entries[filenum].Attributes:='';
+ FDisc[0].Entries[filenum].Attributes:='';
//Get the CRC16 value for the header
headcrc:=Read16b(pos+i+17);
//Check it is valid
@@ -161,7 +161,7 @@ function TDiscImage.ReadUEFFile: TDisc;
//Move our chunk pointer onto the data
inc(i,19);//Points to the data
//Increase the file's data length to match the total length, so far
- SetLength(FilesData[filenum],Result[0].Entries[filenum].Length);
+ SetLength(FilesData[filenum],FDisc[0].Entries[filenum].Length);
//And copy in the data in this block
for j:=0 to blocklen-1 do FilesData[filenum][ptr+j]:=ReadByte(pos+i+j);
//Move to after the data
@@ -181,6 +181,7 @@ function TDiscImage.ReadUEFFile: TDisc;
//Move our offset pointer to the next chunk
inc(pos,chunklen);
end;
+ Result:=Length(FDisc)>0;
end;
{-------------------------------------------------------------------------------
@@ -395,20 +396,21 @@ procedure TDiscImage.WriteUEFFile(filename: String;uncompress: Boolean=False);
{-------------------------------------------------------------------------------
Create a new, empty, UEF file for CFS
-------------------------------------------------------------------------------}
-function TDiscImage.FormatCFS:TDisc;
+function TDiscImage.FormatCFS: Boolean;
begin
- Result:=nil;
+ FDisc:=nil;
//Set up the TDisc structure for return
- SetLength(Result,1);
- ResetDir(Result[0]);
+ SetLength(FDisc,1);
+ ResetDir(FDisc[0]);
//Set the root directory name
root_name:='tape';
- Result[0].Directory:=root_name;
- Result[0].BeenRead:=True;
+ FDisc[0].Directory:=root_name;
+ FDisc[0].BeenRead:=True;
//Set the format
FFormat:=diAcornUEF<<4;
//Set the filename
imagefilename:='Untitled.'+FormatExt;
+ Result:=True;
end;
{-------------------------------------------------------------------------------
diff --git a/LazarusSource/DiscImage_DFS.pas b/LazarusSource/DiscImage_DFS.pas
index d0cc251..2140014 100644
--- a/LazarusSource/DiscImage_DFS.pas
+++ b/LazarusSource/DiscImage_DFS.pas
@@ -15,7 +15,7 @@ function TDiscImage.ID_DFS: Boolean;
begin
ResetVariables;
//Is there actually any data?
- if GetDataLength>0 then
+ if(GetDataLength>0)and(GetDataLength<=400*1024)then
begin
chk:=True;
//Offset 0x0001 should have 9 bytes >31
@@ -164,7 +164,7 @@ function TDiscImage.ID_DFS: Boolean;
for i:=0 to 3 do
if ReadByte($0300+i)=$00 then inc(c);
if c=12 then
- if FFormat>>4=diAcornDFS then
+ if GetMajorFormatNumber=diAcornDFS then
t0:=1;//Set side 1 to Watford
//Now we check side 2
if dbl then
@@ -177,7 +177,7 @@ function TDiscImage.ID_DFS: Boolean;
for i:=0 to 3 do
if ReadByte($0D00+i)=$00 then inc(c);
if c=12 then
- if FFormat>>4=diAcornDFS then
+ if GetMajorFormatNumber=diAcornDFS then
t1:=1;//Set side 1 to Watford
end;
//Determine the format
@@ -202,7 +202,7 @@ function TDiscImage.ID_DFS: Boolean;
end;
end;
end;
- Result:=FFormat>>4=diAcornDFS;
+ Result:=GetMajorFormatNumber=diAcornDFS;
end;
{-------------------------------------------------------------------------------
@@ -226,7 +226,7 @@ function TDiscImage.ConvertDFSSector(address,side: Integer): Integer;
Result:=(((sector MOD 10)+(20*(sector DIV 10))+(10*side))*$100)+offset;
end;
//MMB
- if FFormat>>4=diMMFS then
+ if GetMajorFormatNumber=diMMFS then
begin
if(side<0)or(side>511)then side:=0;
Result:=Result+side*$32000+$2000;
@@ -236,7 +236,7 @@ function TDiscImage.ConvertDFSSector(address,side: Integer): Integer;
{-------------------------------------------------------------------------------
Read Acorn DFS Disc
-------------------------------------------------------------------------------}
-function TDiscImage.ReadDFSDisc(mmbdisc:Integer=-1): TDisc;
+function TDiscImage.ReadDFSDisc(mmbdisc:Integer=-1): Boolean;
var
s,t,f,
locked,
@@ -244,44 +244,47 @@ function TDiscImage.ReadDFSDisc(mmbdisc:Integer=-1): TDisc;
diroff : Integer;
temp : String;
begin
- Result:=nil;
+ Result:=False;
+ FDisc:=nil;
//Determine how many sides
if FDSD then //Double sided image
begin
- SetLength(Result,2);
+ SetLength(FDisc,2);
SetLength(bootoption,2);
SetLength(disc_size,2);
SetLength(disc_name,2);
+ //SetLength(FPartitions,2);
end
else //Single sided image
begin
- SetLength(Result,1);
+ SetLength(FDisc,1);
SetLength(bootoption,1);
SetLength(free_space,1);
SetLength(disc_name,1);
+ //SetLength(FPartitions,1);
end;
//Used by MMB. For DFS, this should be 0
if(mmbdisc<0)or(mmbdisc>511)then mmbdisc:=0;
s:=mmbdisc;
repeat
- ResetDir(Result[s-mmbdisc]);
+ ResetDir(FDisc[s-mmbdisc]);
//Number of entries on disc side
t:=ReadByte(ConvertDFSSector($105,s)) div 8;
- if(FFormat mod$10>$1)and(FFormat mod$10<$4)then //Extra files on Watford DFS
+ if(GetMinorFormatNumber>$1)and(GetMinorFormatNumber<$4)then //Extra files on Watford DFS
inc(t,ReadByte(ConvertDFSSector($305,s))div 8);
- SetLength(Result[s-mmbdisc].Entries,t);
+ SetLength(FDisc[s-mmbdisc].Entries,t);
//Directory name - as DFS only has $, this will be the drive number + '$'
- Result[s-mmbdisc].Directory:=':'+IntToStr(s*2)+dir_sep+root_name;
- Result[s-mmbdisc].Partition:=s;
- Result[s-mmbdisc].BeenRead :=True;
+ FDisc[s-mmbdisc].Directory:=':'+IntToStr(s*2)+dir_sep+root_name;
+ FDisc[s-mmbdisc].Partition:=s;
+ FDisc[s-mmbdisc].BeenRead :=True;
//Get the disc title(s)
- Result[s-mmbdisc].Title:=ReadString(ConvertDFSSector($000,s),-8)
+ FDisc[s-mmbdisc].Title:=ReadString(ConvertDFSSector($000,s),-8)
+ReadString(ConvertDFSSector($100,s),-4);
- RemoveSpaces(Result[s-mmbdisc].Title);
- RemoveControl(Result[s-mmbdisc].Title);
- disc_name[s]:=Result[s-mmbdisc].Title;
+ RemoveSpaces(FDisc[s-mmbdisc].Title);
+ RemoveControl(FDisc[s-mmbdisc].Title);
+ disc_name[s]:=FDisc[s-mmbdisc].Title;
//Boot Option
- if FFormat>>4=diAcornDFS then
+ if GetMajorFormatNumber=diAcornDFS then
bootoption[s]:=(ReadByte(ConvertDFSSector($106,s))AND$30)>>4;
//Disc Size
disc_size[s]:=(ReadByte(ConvertDFSSector($107,s))
@@ -292,11 +295,11 @@ function TDiscImage.ReadDFSDisc(mmbdisc:Integer=-1): TDisc;
for f:=1 to t do
begin
//Reset the variables
- ResetDirEntry(Result[s-mmbdisc].Entries[f-1]);
+ ResetDirEntry(FDisc[s-mmbdisc].Entries[f-1]);
//Is it a Watford, and are we in the Watford area?
diroff:=$000;
ptr:=f;
- if(FFormat mod$10=2)or(FFormat mod$10=3)then
+ if(GetMinorFormatNumber=2)or(GetMinorFormatNumber=3)then
if (f>31) then
begin
diroff:=$200;
@@ -306,54 +309,60 @@ function TDiscImage.ReadDFSDisc(mmbdisc:Integer=-1): TDisc;
temp:=ReadString(ConvertDFSSector(diroff+($08*ptr),s),-7);
RemoveTopBit(temp); //Attributes are in the top bit
RemoveSpaces(temp); //Remove extraneous spaces
- Result[s-mmbdisc].Entries[f-1].Filename:=temp;
+ FDisc[s-mmbdisc].Entries[f-1].Filename:=temp;
//Get the directory character
temp:=chr(ReadByte(ConvertDFSSector(diroff+($08*ptr)+7,s))AND$7F);
if temp=' 'then temp:=root_name; //Acorn Atom DOS root is ' '
//If the directory is not root, add it to the filename
if temp<>root_name then
- Result[s-mmbdisc].Entries[f-1].Filename:=temp+dir_sep
- +Result[s-mmbdisc].Entries[f-1].Filename;
+ FDisc[s-mmbdisc].Entries[f-1].Filename:=temp+dir_sep
+ +FDisc[s-mmbdisc].Entries[f-1].Filename;
//Make up a parent directory pathname so this can be found
- Result[s-mmbdisc].Entries[f-1].Parent:=':'+IntToStr(s*2)+dir_sep+root_name;
+ FDisc[s-mmbdisc].Entries[f-1].Parent:=':'+IntToStr(s*2)+dir_sep+root_name;
//Is it locked? This is actually the top bit of the final filename character
locked:=(ReadByte(ConvertDFSSector(diroff+($08*ptr)+7,s))AND$80)>>7;
if locked=1 then
- Result[s-mmbdisc].Entries[f-1].Attributes:='L'
+ FDisc[s-mmbdisc].Entries[f-1].Attributes:='L'
else
- Result[s-mmbdisc].Entries[f-1].Attributes:='';
+ FDisc[s-mmbdisc].Entries[f-1].Attributes:='';
//Load address - need to multiply bits 16/17 by $55 to expand it to 8 bits
- Result[s-mmbdisc].Entries[f-1].LoadAddr:=
+ FDisc[s-mmbdisc].Entries[f-1].LoadAddr:=
(((ReadByte(ConvertDFSSector(diroff+$106+($08*ptr),s))AND$0C)<<14)*$55)
+Read16b( ConvertDFSSector(diroff+$100+($08*ptr),s));
//Execution address - need to multiply bits 16/17 by $55 to expand it to 8 bits
- Result[s-mmbdisc].Entries[f-1].ExecAddr:=
+ FDisc[s-mmbdisc].Entries[f-1].ExecAddr:=
(((ReadByte(ConvertDFSSector(diroff+$106+($08*ptr),s))AND$C0)<<10)*$55)
+ Read16b( ConvertDFSSector(diroff+$102+($08*ptr),s));
//Length
- Result[s-mmbdisc].Entries[f-1].Length:=
+ FDisc[s-mmbdisc].Entries[f-1].Length:=
(((ReadByte(ConvertDFSSector(diroff+$106+($08*ptr),s))AND$30)<<12))
+ Read16b( ConvertDFSSector(diroff+$104+($08*ptr),s));
//Sector of start of data
- Result[s-mmbdisc].Entries[f-1].Sector:=
+ FDisc[s-mmbdisc].Entries[f-1].Sector:=
((ReadByte(ConvertDFSSector(diroff+$106+($08*ptr),s))AND$03)<<8)
+ReadByte(ConvertDFSSector(diroff+$107+($08*ptr),s));
//Which side it is on
- Result[s-mmbdisc].Entries[f-1].Side:=s;
+ FDisc[s-mmbdisc].Entries[f-1].Side:=s;
//Not a directory - not used in DFS
- Result[s-mmbdisc].Entries[f-1].DirRef:=-1;
+ FDisc[s-mmbdisc].Entries[f-1].DirRef:=-1;
end;
//Next side
if(FFormat AND $1=1)then inc(s) else s:=2+mmbdisc;
+ {FPartitions[s-mmbdisc].Directories:=Result;
+ FPartitions[s-mmbdisc].DirSep:=dir_sep;
+ FPartitions[s-mmbdisc].Format:=diAcornDFS;
+ FPartitions[s-mmbdisc].Title:=disc_name[s];
+ FPartitions[s-mmbdisc].RootName:=root_name;}
until s=2+mmbdisc;
//Free Space Map (not MMB)
- if FFormat>>4=diAcornDFS then DFSFreeSpaceMap(Result);
+ if GetMajorFormatNumber=diAcornDFS then DFSFreeSpaceMap;
+ Result:=Length(FDisc)>0;
end;
{-------------------------------------------------------------------------------
Update the DFS Free Space Map, and update the free space counter
-------------------------------------------------------------------------------}
-procedure TDiscImage.DFSFreeSpaceMap(LDisc: TDisc);
+procedure TDiscImage.DFSFreeSpaceMap;
var
f,s,c,e,fs: Cardinal;
begin
@@ -389,20 +398,22 @@ procedure TDiscImage.DFSFreeSpaceMap(LDisc: TDisc);
free_space_map[s,0,2]:=$FE;
free_space_map[s,0,3]:=$FE;
end;
- if Length(LDisc[s].Entries)>0 then
- for e:=0 to Length(LDisc[s].Entries)-1 do
+ if Length(FDisc[s].Entries)>0 then
+ for e:=0 to Length(FDisc[s].Entries)-1 do
begin
- inc(free_space[s],(LDisc[s].Entries[e].Length div $100)*$100);
- if LDisc[s].Entries[e].Length mod $100>0 then inc(free_space[s],$100);
+ inc(free_space[s],(FDisc[s].Entries[e].Length div $100)*$100);
+ if FDisc[s].Entries[e].Length mod $100>0 then inc(free_space[s],$100);
//Add it to the free space map
- c:=LDisc[s].Entries[e].Length div $100;
- if LDisc[s].Entries[e].Length mod $100>0 then inc(c);
+ c:=FDisc[s].Entries[e].Length div $100;
+ if FDisc[s].Entries[e].Length mod $100>0 then inc(c);
if c>0 then //Take care of zero length files
for fs:=0 to c-1 do
- if(LDisc[s].Entries[e].Sector+fs)div 100;
end;
{-------------------------------------------------------------------------------
@@ -979,13 +991,13 @@ function TDiscImage.AddDFSSide(filename: String): Boolean;
if SysUtils.FileExists(filename) then
begin
//Only for Acorn DFS
- if(FFormat>>4=diAcornDFS)and(not FDSD)then //Single sided images only
+ if(GetMajorFormatNumber=diAcornDFS)and(not FDSD)then //Single sided images only
begin
//Pre-load the proposed image
NewImage:=TDiscImage.Create;
NewImage.LoadFromFile(filename,False);
//And make sure it is a DFS SS image
- if (NewImage.FormatNumber>>4=diAcornDFS)
+ if (NewImage.MajorFormatNumber=diAcornDFS)
and(not NewImage.DoubleSided)then
begin
//Load the file in
@@ -1017,3 +1029,35 @@ function TDiscImage.MoveDFSFile(filename,directory: String): Integer;
//We just need to delete the original once copied
if Result>-1 then DeleteFile(oldfn);
end;
+
+{-------------------------------------------------------------------------------
+Produce a report of the image's details
+-------------------------------------------------------------------------------}
+function TDiscImage.DFSReport(CSV: Boolean): TStringList;
+var
+ temp: String;
+ side: Integer;
+begin
+ Result:=TStringList.Create;
+ if FDSD then Result.Add('Double Sided') else Result.Add('Single Sided');
+ side:=0;
+ while side>4=diDOSPlus;
+ Result:=GetMajorFormatNumber=diDOSPlus;
end;
end;
@@ -109,14 +109,14 @@ procedure TDiscImage.ReadDOSPartition;
part : Byte;
begin
//Is this an ADFS disc with DOS Plus partition?
- if((FFormat>>4=diAcornADFS)and(FDOSPresent))
- or(FFormat>>4=diDOSPlus)then //Or a straight DOS Plus?
+ if((GetMajorFormatNumber=diAcornADFS)and(FDOSPresent))
+ or(GetMajorFormatNumber=diDOSPlus)then //Or a straight DOS Plus?
begin
i:=0;
part:=0;
- if FFormat>>4=diDOSPlus then dir_sep:='\';
+ if GetMajorFormatNumber=diDOSPlus then dir_sep:='\';
//ADFS Hybrid?
- if FFormat>>4=diAcornADFS then
+ if GetMajorFormatNumber=diAcornADFS then
begin
part:=1;
//Set up the second partition
@@ -308,7 +308,7 @@ function TDiscImage.ReadDOSDirectory(dirname: String;addr: Cardinal;
//Don't need the parent or self referrals
if(RightStr(dirname,1)='.')or(RightStr(dirname,2)='..')then exit;
//ADFS hybrid?
- if FFormat>>4=diAcornADFS then side:=1 else side:=0;
+ if GetMajorFormatNumber=diAcornADFS then side:=1 else side:=0;
//Directory name
index:=Pos(GetDirSep(side),dirname);
while Pos(GetDirSep(side),dirname,index+1)>index do
@@ -776,12 +776,12 @@ procedure TDiscImage.ReadDOSFSM;
//Get all the used sectors
fragments:=DOSGetFreeSectors(True);
//Initialise the variables
- if FFormat>>4=diDOSPlus then
+ if GetMajorFormatNumber=diDOSPlus then
begin
SetLength(free_space_map,1);
part:=0;
end;
- if FFormat>>4=diAcornADFS then //Hybrids - DOS will take up the second 'side'
+ if GetMajorFormatNumber=diAcornADFS then //Hybrids - DOS will take up the second 'side'
begin
SetLength(free_space_map,2);
part:=1;
@@ -896,7 +896,7 @@ function TDiscImage.RenameDOSFile(oldname:String;var newname: String): Integer;
side : Byte;
begin
//ADFS hybrid?
- if FFormat>>4=diAcornADFS then side:=1 else side:=0;
+ if GetMajorFormatNumber=diAcornADFS then side:=1 else side:=0;
Result:=-2; //Original file does not exist
//Validate the filename
newname:=ValidateDOSFilename(newname);
@@ -1354,7 +1354,7 @@ function TDiscImage.WriteDOSFile(var file_details: TDirEntry;
dir:=0;
entry:=0;
//ADFS hybrid?
- if FFormat>>4=diAcornADFS then partition:=1 else partition:=0;
+ if GetMajorFormatNumber=diAcornADFS then partition:=1 else partition:=0;
SetLength(fragments,0);
//Start with a negative result
Result:=-3;//File already exists
@@ -1374,7 +1374,7 @@ function TDiscImage.WriteDOSFile(var file_details: TDirEntry;
end;
//Validate the proposed filename (ADFS rules the same as AFS)
if(file_details.Filename<>dosrootname)
- and((FFormat>>4=diAcornADFS)or(FFormat=diDOSPlus))then //ADFS partition or DOS Plus
+ and((GetMajorFormatNumber=diAcornADFS)or(FFormat=diDOSPlus))then //ADFS partition or DOS Plus
file_details.Filename:=ValidateDOSFilename(file_details.Filename);
//First make sure it doesn't exist already
if not FileExists(file_details.Parent+GetDirSep(partition)+file_details.Filename,pdir,entry)then
@@ -1479,7 +1479,7 @@ function TDiscImage.CreateDOSDirectory(dirname,parent,attributes: String): Integ
side : Byte;
begin
//ADFS hybrid?
- if FFormat>>4=diAcornADFS then side:=1 else side:=0;
+ if GetMajorFormatNumber=diAcornADFS then side:=1 else side:=0;
Result:=-3; //Directory already exists
ok:=False;
//Make sure that the directory does not already exists
@@ -1547,7 +1547,7 @@ function TDiscImage.DeleteDOSFile(filename: String): Boolean;
side : Byte;
begin
//ADFS hybrid?
- if FFormat>>4=diAcornADFS then side:=1 else side:=0;
+ if GetMajorFormatNumber=diAcornADFS then side:=1 else side:=0;
Result:=False;
//Make sure the file exists, and is not the root
if filename<>dosrootname then
@@ -1678,7 +1678,7 @@ function TDiscImage.AddDOSPartition(size: Cardinal): Boolean;
Result:=False;
if size<9*secsize then exit; //Minimum size is 9 sectors
//Only for adding DOS partition to 8 bit ADFS
- if(FFormat>>4=diAcornADFS)and(not FMap)and(FDirType=diADFSOldDir)then
+ if(GetMajorFormatNumber=diAcornADFS)and(not FMap)and(FDirType=diADFSOldDir)then
begin
fsed:=GetADFSMaxLength(False);
//Is there enough free space?
@@ -1729,7 +1729,7 @@ function TDiscImage.AddDOSPartition(size: Cardinal): Boolean;
{-------------------------------------------------------------------------------
Create a new DOS Plus or DOS image
-------------------------------------------------------------------------------}
-function TDiscImage.FormatDOS(size: QWord;fat: Byte): TDisc;
+function TDiscImage.FormatDOS(size: QWord;fat: Byte): Boolean;
var
index: Cardinal;
const
@@ -1738,7 +1738,8 @@ function TDiscImage.FormatDOS(size: QWord;fat: Byte): TDisc;
GB = 1024*1024*1024;
begin
//Default return value
- Result:=nil;
+ Result:=False;
+ FDisc:=nil;
//Ensure that we don't create an illegal shape
//Min sizes - these are Microsoft specs
if size< 180*KB then size:= 180*KB; // 180KB
@@ -1761,15 +1762,16 @@ function TDiscImage.FormatDOS(size: QWord;fat: Byte): TDisc;
UpdateProgress('Formatting...');
for index:=0 to size-1 do WriteByte(0,index);
//Master 512 DOS Plus or Standard DOS?
- if(size<>800*1024)and(size<>640*1024)then //Standard DOS
+ if(size<>800*KB)and(size<>640*KB)then //Standard DOS
WriteDOSHeader(0,size,fat,True)
else
begin //Master 512
//BBC Master DOS Plus images do not have a DOS header, which makes them easier.
- if size=640*1024 then //Master 512 hybrid image
+ if size=640*KB then //Master 512 hybrid image
begin
//Create the ADFS image (ADFS 'L')
- Result:=FormatADFSFloppy(2);
+ FormatADFSFloppy(2);
+ Result:=Length(FDisc)>0;
//Create the 636K DOS partition
for index:=0 to $1FA do WriteByte(0,index);//Most of the ADFS header needs blanked
Write24b($000AA0,$FC); //Signature for 640K DOS Plus
@@ -1779,7 +1781,7 @@ function TDiscImage.FormatDOS(size: QWord;fat: Byte): TDisc;
WriteByte(ByteCheckSum($0000,$100),$0FF);//Checksum sector 0
WriteByte(ByteCheckSum($0100,$100),$1FF);//Checksum sector 1
end;
- if size=800*1024 then //Master 512 800K image
+ if size=800*KB then //Master 512 800K image
begin
//Very simplistic this format.
WriteByte($FD,0); //Media descriptor byte
@@ -1794,7 +1796,7 @@ function TDiscImage.FormatDOS(size: QWord;fat: Byte): TDisc;
//And read it in
ReadImage;
//Returning a result
- Result:=FDisc;
+ Result:=Length(FDisc)>0;
//Set the filename
imagefilename:='Untitled.'+FormatExt;
end;
@@ -1909,7 +1911,7 @@ procedure TDiscImage.WriteDOSHeader(offset, size: QWord;fat: Byte;
if totBlocks<=$FFFF then //If it'll fit in the original BIOS block
Write16b(totBlocks,offset+$13,buffer)
else //Otherwise it'll need to go in the extended block - only for FAT16 & FAT32
- Write32b(totBlocks,offset+$20,buffer);
+ if(fat=diFAT16)or(fat=diFAT32)then Write32b(totBlocks,offset+$20,buffer);
//Media descriptor byte
WriteByte(mdb,offset+$15,buffer);
//FAT Size
@@ -2071,10 +2073,10 @@ function TDiscImage.DOSShortFilename(path,LFN: String;SFN :String=''): String;
begin
Result:='';
//Validate the path exists, and check for DOS FAT12, 16 or 32
- if(FileExists(path,dir,entry))and(FFormat>>4=diDOSPlus)then
+ if(FileExists(path,dir,entry))and(GetMajorFormatNumber=diDOSPlus)then
begin
//DOS Plus - then just return the shortened, validated, filename
- if FFormat mod$10=0 then
+ if GetMinorFormatNumber=0 then
begin
Result:=ValidateDOSFilename(LFN);
exit;
@@ -2132,3 +2134,36 @@ function TDiscImage.BuildDOSFilename(f,e: String): String;
Result:=f;
if Length(e)>0 then Result:=Result+'.'+e;
end;
+
+{-------------------------------------------------------------------------------
+Produce a report of the image's details
+-------------------------------------------------------------------------------}
+function TDiscImage.DOSReport(CSV: Boolean): TStringList;
+var
+ side: Integer;
+begin
+ Result:=TStringList.Create;
+ side:=0;
+ if GetMajorFormatNumber=diAcornADFS then
+ begin
+ if not CSV then Result.Add('');
+ Result.Add('DOS Plus partition');
+ if not CSV then Result.Add('------------------');
+ side:=1;
+ end;
+ Result.Add('Sector Size: '+IntToStr(secsize)+' bytes');
+ Result.Add('Sectors per Track: '+IntToStr(secspertrack));
+ Result.Add('Root Address: 0x'+IntToHex(Fdosroot,8));
+ Result.Add('Root Size: '+IntToStr(dosroot_size)+' bytes');
+ Result.Add('Disc Size: '+IntToStr(disc_size[side])+' bytes');
+ Result.Add('Free Space: '+IntToStr(free_space[side])+' bytes');
+ Result.Add('Boot Map Location: 0x'+IntToHex(doshead,8));
+ Result.Add('FAT Location: 0x'+IntToHex(dosmap,8));
+ Result.Add('FAT Size: '+IntToStr(DOSFATSize*secsize)+' bytes');
+ Result.Add('Number of FATs: '+IntToStr(NumFATs));
+ Result.Add('Cluster Size: '+IntToStr(cluster_size)+' bytes');
+ Result.Add('Allocation Unit: '+IntToStr(dosalloc)+' blocks');
+ Result.Add('Number of Blocks: '+IntToStr(DOSblocks));
+ Result.Add('Reserved Sectors: '+IntToStr(DOSResSecs));
+ Result.Add('Disc Name: '+disc_name[side]);
+end;
diff --git a/LazarusSource/DiscImage_MMB.pas b/LazarusSource/DiscImage_MMB.pas
index 9f4ffda..6823fab 100644
--- a/LazarusSource/DiscImage_MMB.pas
+++ b/LazarusSource/DiscImage_MMB.pas
@@ -4,10 +4,11 @@
Identifies an MMB
-------------------------------------------------------------------------------}
function TDiscImage.ID_MMB: Boolean;
-var
- c,i,ptr : Integer;
+{var
+ c,i,ptr : Integer;}
begin
- if FFormat=diInvalidImg then
+ Result:=False;
+{ if FFormat=diInvalidImg then
begin
ResetVariables;
//Check it is of the correct length (511 images * 200K + 0x2000 bytes)
@@ -24,22 +25,22 @@ function TDiscImage.ID_MMB: Boolean;
if c<511 then FFormat:=diInvalidImg;
end;
end;
- Result:=FFormat>>4=diMMFS;
+ Result:=GetMajorFormatNumber=diMMFS;}
end;
{-------------------------------------------------------------------------------
Read MMB file
-------------------------------------------------------------------------------}
-function TDiscImage.ReadMMBDisc: TDisc;
-var
+function TDiscImage.ReadMMBDisc: Boolean;
+{var
i,j,
dir : Integer;
ptr : Cardinal;
c : Byte;
- d : TDisc;
+ d : TDisc; }
begin
- Result:=nil;
- //511 entries in an MMB file
+ Result:=False;
+{ //511 entries in an MMB file
SetLength(Result,511);
//Now go through them and read them in
for i:=0 to 510 do
@@ -75,5 +76,5 @@ function TDiscImage.ReadMMBDisc: TDisc;
Result[i].Directory:=IntToStr(i)+': empty';
end;
disc_name[0]:='MMFS File';
- disc_size[0]:=511;
+ disc_size[0]:=511; }
end;
diff --git a/LazarusSource/DiscImage_Private.pas b/LazarusSource/DiscImage_Private.pas
index 6dc1ee1..e88aa2e 100644
--- a/LazarusSource/DiscImage_Private.pas
+++ b/LazarusSource/DiscImage_Private.pas
@@ -63,6 +63,45 @@ procedure TDiscImage.ResetVariables;
Fupdating :=False;
end;
+{-------------------------------------------------------------------------------
+Reset the partition to match the global variables
+-------------------------------------------------------------------------------}
+procedure TDiscImage.AddPartition;
+var
+ part: Integer;
+begin
+ part:=Length(FPartitions);
+ SetLength(FPartitions,part+1);
+ FPartitions[part].Directories:=FDisc;
+ FPartitions[part].Title:=disc_name[part];
+// FPartitions[part].RootTitle:=
+ FPartitions[part].RootName:=root_name;
+ FPartitions[part].DirSep:=dir_sep;
+// FPartitions[part].HeaderAddr:=
+// FPartitions[part].FSMAddr
+{ FreeSpaceMap : array of TTrack; //The free space map
+ DOSVolInRoot : Boolean; //Volume name is stored in the root (DOS)
+ RootAddress, //Offset of the root
+ SectorSize, //Sector Size
+ DOSalloc, //Allocation Unit (DOS Plus)
+ Version, //Format version
+ Root_size, //Size of the root directory
+ DOSBlocks, //Size of the DOS partition in blocks
+ DOSCluster_size : Cardinal; //Size of a DOS cluster
+ FreeSpace, //Amount of free space in bytes
+ PartitionSize : QWord; //Size of the partition in bytes
+ Format, //Major format of this partition
+ DOSFATSize, //Size of DOS Plus FAT in blocks
+ DOSResSecs : Word; //Number of reserved blocks
+ SecsPerTrack, //Number of sectors per track
+ Heads, //Number of heads (Acorn ADFS New)
+ Density, //Density (Acorn ADFS New)
+ DOSFATType, //FAT Type - 12: FAT12, 16: FAT16, 32: FAT32
+ DOSNumFATs, //Number of FATs in a DOS Plus image
+ AmigaMapType : Byte; //OFS/FFS/PFS/OFS
+}
+end;
+
{-------------------------------------------------------------------------------
Extract a string from ptr to the next chr(term) or length(-term)
-------------------------------------------------------------------------------}
@@ -162,12 +201,12 @@ function TDiscImage.FormatToString: String;
('Plus','FAT12','FAT16','FAT32','','','','','','','','','','','',''));
begin
Result:='';
- if FFormat>>4<=High(FS) then
- if FFormat mod $10<=High(SUB[FFormat>>4]) then
+ if GetMajorFormatNumber<=High(FS) then
+ if GetMinorFormatNumber<=High(SUB[GetMajorFormatNumber]) then
begin
- Result:= FS[FFormat>>4];
- if SUB[FFormat>>4,FFormat MOD $10]<>'' then
- Result:=Result+' '+SUB[FFormat>>4,FFormat MOD $10];
+ Result:= FS[GetMajorFormatNumber];
+ if SUB[GetMajorFormatNumber,GetMinorFormatNumber]<>'' then
+ Result:=Result+' '+SUB[GetMajorFormatNumber,GetMinorFormatNumber];
end;
//ADFS with AFS partition
if(FFormat=diAcornADFS<<4+ 2)and(FAFSPresent)then
@@ -197,9 +236,25 @@ function TDiscImage.FormatToExt: String;
('img','fat12','fat16','fat32','','','','','','','','','','','',''));//DOS and DOS Plus
begin
Result:='img';
- if FFormat>>4<=High(EXT) then
- if FFormat mod $10<=High(EXT[FFormat>>4]) then
- Result:=EXT[FFormat>>4,FFormat MOD $10];
+ if GetMajorFormatNumber<=High(EXT) then
+ if GetMinorFormatNumber<=High(EXT[GetMajorFormatNumber]) then
+ Result:=EXT[GetMajorFormatNumber,GetMinorFormatNumber];
+end;
+
+{-------------------------------------------------------------------------------
+Get the major format number
+-------------------------------------------------------------------------------}
+function TDiscImage.GetMajorFormatNumber: Word;
+begin
+ Result:=FFormat>>4;
+end;
+
+{-------------------------------------------------------------------------------
+Get the minor format number
+-------------------------------------------------------------------------------}
+function TDiscImage.GetMinorFormatNumber: Byte;
+begin
+ Result:=FFormat mod $10;
end;
{-------------------------------------------------------------------------------
@@ -461,10 +516,10 @@ function TDiscImage.DiscAddrToIntOffset(disc_addr: Cardinal): Cardinal;
oldheads = 2;
begin
Result:=disc_addr;
- if(FForceInter=0)and(FFormat>>4=diAcornADFS)then
+ if(FForceInter=0)and(GetMajorFormatNumber=diAcornADFS)then
if(FFormat<>diAcornADFS<<4+$02)then exit;
//ADFS L or AFS with 'INT' option
- if((FFormat>>4=diAcornADFS{<<4+$02})or(FFormat>>4=diAcornFS))
+ if((GetMajorFormatNumber=diAcornADFS{<<4+$02})or(GetMajorFormatNumber=diAcornFS))
and(Finterleave>1)then
begin
//Variables not set, then set them to default
@@ -658,17 +713,17 @@ procedure TDiscImage.ResetDir(var Entry: TDir);
function TDiscImage.MapFlagToByte: Byte;
begin
Result:=diUnknownDir; //Default value for non-ADFS
- if FFormat>>4=diAcornADFS then //Is it ADFS?
+ if GetMajorFormatNumber=diAcornADFS then //Is it ADFS?
begin
Result:=diADFSOldMap; // ADFS Old Map
if FMap then Result:=diADFSNewMap; // ADFS New Map
end;
- if FFormat>>4=diAmiga then //Is it Amiga?
+ if GetMajorFormatNumber=diAmiga then //Is it Amiga?
begin
Result:=diAmigaOFS; // AmigaDOS OFS
if FMap then Result:=diAmigaFFS; // AmigaDOS FFS
end;
- if FFormat>>4=diDOSPlus then //Is it DOS
+ if GetMajorFormatNumber=diDOSPlus then //Is it DOS
Result:=FATType;
end;
@@ -679,7 +734,7 @@ function TDiscImage.MapTypeToString: String;
begin
Result:='';
//ADFS and AmigaDOS
- if(FFormat>>4=diAcornADFS)or(FFormat>>4=diAmiga)then
+ if(GetMajorFormatNumber=diAcornADFS)or(GetMajorFormatNumber=diAmiga)then
begin
case MapFlagToByte of
diADFSOldMap: Result:='ADFS Old Map';
@@ -688,7 +743,7 @@ function TDiscImage.MapTypeToString: String;
diAmigaFFS : Result:='AmigaDOS FFS';
end;
end;
- if FFormat>>4=diDOSPlus then
+ if GetMajorFormatNumber=diDOSPlus then
begin
case FATType of
diFAT12 : Result:='FAT12';
@@ -817,7 +872,7 @@ procedure TDiscImage.UpdateProgress(Fupdate: String);
function TDiscImage.GetRootAddress: Cardinal;
begin
Result:=root;
- if FFormat>>4=diAcornADFS then //New map will return the fragment ID
+ if GetMajorFormatNumber=diAcornADFS then //New map will return the fragment ID
if FMap then Result:=rootfrag;
end;
@@ -939,11 +994,11 @@ function TDiscImage.InterleaveString: String;
ints:array[0..2] of String=('Sequential','Interleave','Multiplex');
begin
Result:='';
- if(FFormat>>4=diAcornDFS)and(FDSD)then Result:=ints[1];
+ if(GetMajorFormatNumber=diAcornDFS)and(FDSD)then Result:=ints[1];
{if(FFormat=diAcornADFS<<4+2)
or(FFormat=diAcornADFS<<4+$E)}
- if(FFormat>>4=diAcornADFS)
- or(FFormat>>4=diAcornFS)then
+ if(GetMajorFormatNumber=diAcornADFS)
+ or(GetMajorFormatNumber=diAcornFS)then
if FInterleave-1<=High(ints) then Result:=ints[FInterleave-1];
end;
diff --git a/LazarusSource/DiscImage_Published.pas b/LazarusSource/DiscImage_Published.pas
index e8e9746..b6bf6ef 100644
--- a/LazarusSource/DiscImage_Published.pas
+++ b/LazarusSource/DiscImage_Published.pas
@@ -79,7 +79,7 @@ function TDiscImage.FixDirectories: Boolean;
begin
Result:=False;
//Only for ADFS
- if FFormat>>4=diAcornADFS then Result:=FixBrokenADFSDirectories;
+ if GetMajorFormatNumber=diAcornADFS then Result:=FixBrokenADFSDirectories;
end;
{-------------------------------------------------------------------------------
@@ -133,7 +133,7 @@ function TDiscImage.LoadFromFile(filename: String;readdisc: Boolean=True): Boole
//Make a note of the file being read in
FFilename:=filename;
//Free up the Spark instance, if used
- if FFormat>>4=diSpark then SparkFile.Free;
+ if GetMajorFormatNumber=diSpark then SparkFile.Free;
//Blank off the variables
ResetVariables;
//Read the file in, uncompressing if need be
@@ -185,25 +185,25 @@ procedure TDiscImage.ReadImage;
var
d: Cardinal;
begin
- case FFormat>>4 of
- diAcornDFS : FDisc:=ReadDFSDisc; //Acorn DFS
+ case GetMajorFormatNumber of
+ diAcornDFS : ReadDFSDisc; //Acorn DFS
diAcornADFS:
begin
- FDisc:=ReadADFSDisc; //Acorn ADFS
+ ReadADFSDisc; //Acorn ADFS
ReadAFSPartition;//Read in the AFS partition, if one is present
ReadDOSPartition;//Read in the DOS Plus partition, if one is present
end;
diAcornFS : ReadAFSPartition; //Acorn File Server
- diCommodore: FDisc:=ReadCDRDisc; //Commodore
- diSinclair : FDisc:=ReadSinclairDisc;//Sinclair/Amstrad
- diAmiga : FDisc:=ReadAmigaDisc; //Amiga
- diAcornUEF : FDisc:=ReadUEFFile; //Acorn CFS
- diMMFS : FDisc:=ReadMMBDisc; //MMFS
- diSpark : FDisc:=ReadSparkArchive;//Spark archive
+ diCommodore: ReadCDRDisc; //Commodore
+ diSinclair : ReadSinclairDisc; //Sinclair/Amstrad
+ diAmiga : ReadAmigaDisc; //Amiga
+ diAcornUEF : ReadUEFFile; //Acorn CFS
+ diMMFS : ReadMMBDisc; //MMFS
+ diSpark : ReadSparkArchive; //Spark archive
diDOSPlus : ReadDOSPartition; //DOS Plus
end;
//Find the maximum directory entries
- if FFormat>>4<>diSpark then //Not Spark, as this already provides this info
+ if GetMajorFormatNumber<>diSpark then //Not Spark, as this already provides this info
begin
FMaxDirEnt:=0;
if Length(FDisc)>0 then
@@ -217,11 +217,12 @@ procedure TDiscImage.ReadImage;
{-------------------------------------------------------------------------------
Saves an image to a file
-------------------------------------------------------------------------------}
-procedure TDiscImage.SaveToFile(filename: String;uncompress: Boolean=False);
+function TDiscImage.SaveToFile(filename: String;uncompress: Boolean=False): Boolean;
var
FDiscDrive: TFileStream;
ext: String;
begin
+ Result:=False;
//Validate the filename
ext:=ExtractFileExt(filename); //First extract the extension
if ext='' then //If it hasn't been given an extension, then give it the default
@@ -229,7 +230,7 @@ procedure TDiscImage.SaveToFile(filename: String;uncompress: Boolean=False);
filename:=LeftStr(filename,Length(filename)-Length(ext));
filename:=filename+'.'+FormatToExt;
end;
- if FFormat>>4<>diAcornUEF then //Not CFS
+ if GetMajorFormatNumber<>diAcornUEF then //Not CFS
begin
//Create the stream
try
@@ -242,11 +243,13 @@ procedure TDiscImage.SaveToFile(filename: String;uncompress: Boolean=False);
FDiscDrive.Free;
//Change the image's filename
imagefilename:=filename;
+ Result:=True;
except
//Could not create
+ Result:=False;
end;
end;
- if FFormat>>4=diAcornUEF then WriteUEFFile(filename,uncompress); //CFS
+ if GetMajorFormatNumber=diAcornUEF then WriteUEFFile(filename,uncompress); //CFS
end;
{-------------------------------------------------------------------------------
@@ -269,52 +272,23 @@ function TDiscImage.FormatFDD(major:Word;minor:Byte=0;tracks: Byte=0;filename: S
if major<>diDOSPlus then
tracks:=tracks MOD 2;
case major of
- diAcornDFS://Create DFS
- begin
- FDisc:=FormatDFS(minor,tracks);
- Result:=Length(FDisc)>0;
- end;
- diAcornADFS://Create ADFS
- begin
- FDisc:=FormatADFSFloppy(minor);
- Result:=Length(FDisc)>0;
- end;
- diCommodore://Create Commodore 64/128
- begin
- FDisc:=FormatCDR(minor);
- Result:=Length(FDisc)>0;
- end;
- diSinclair://Create Sinclair/Amstrad
- begin
- FDisc:=FormatSpectrum(minor);
- Result:=Length(FDisc)>0;
- end;
- diAmiga://Create AmigaDOS
- begin
- FDisc:=FormatAmigaFDD(minor);
- Result:=Length(FDisc)>0;
- end;
- diAcornUEF://Create CFS
- begin
- FDisc:=FormatCFS;
- Result:=Length(FDisc)>0;
- end;
- diSpark://Create Spark
- begin
- FDisc:=FormatSpark(filename);
- Result:=Length(FDisc)>0;
- end;
- diDOSPlus://Create DOS or DOS Plus
+ diAcornDFS : Result:=FormatDFS(minor,tracks); //Create DFS
+ diAcornADFS: Result:=FormatADFSFloppy(minor); //Create ADFS
+ diCommodore: Result:=FormatCDR(minor); //Create Commodore 64/128
+ diSinclair : Result:=FormatSpectrum(minor); //Create Sinclair/Amstrad
+ diAmiga : Result:=FormatAmigaFDD(minor); //Create AmigaDOS
+ diAcornUEF : Result:=FormatCFS; //Create CFS
+ diSpark : Result:=FormatSpark(filename); //Create Spark
+ diDOSPlus : //Create DOS or DOS Plus
begin
case minor of
- 0: FDisc:=FormatDOS( 640*1024,diFAT12);// 640KB ADFS/DOS Plus
- 1: FDisc:=FormatDOS( 800*1024,diFAT12);// 800KB DOS Plus
- 2: FDisc:=FormatDOS( 360*1024,diFAT12);// 360KB DOS
- 3: FDisc:=FormatDOS( 720*1024,diFAT12);// 720KB DOS
- 4: FDisc:=FormatDOS(1440*1024,diFAT12);//1.44MB DOS
- 5: FDisc:=FormatDOS(2880*1024,diFAT12);//2.88MB DOS
+ 0: Result:=FormatDOS( 640*1024,diFAT12); // 640KB ADFS/DOS Plus
+ 1: Result:=FormatDOS( 800*1024,diFAT12); // 800KB DOS Plus
+ 2: Result:=FormatDOS( 360*1024,diFAT12); // 360KB DOS
+ 3: Result:=FormatDOS( 720*1024,diFAT12); // 720KB DOS
+ 4: Result:=FormatDOS(1440*1024,diFAT12); //1.44MB DOS
+ 5: Result:=FormatDOS(2880*1024,diFAT12); //2.88MB DOS
end;
- Result:=Length(FDisc)>0;
end;
end;
end;
@@ -322,29 +296,21 @@ function TDiscImage.FormatFDD(major:Word;minor:Byte=0;tracks: Byte=0;filename: S
{-------------------------------------------------------------------------------
Create and format a new hard disc image
-------------------------------------------------------------------------------}
-function TDiscimage.FormatHDD(major:Word;harddrivesize:Cardinal;newmap:Boolean;
- dirtype:Byte):Boolean;
+function TDiscimage.FormatHDD(major: Word;harddrivesize: Cardinal;
+ ide,newmap: Boolean;dirtype: Byte;addheader: Boolean): Boolean;
begin
Result:=False;
//Make sure the numbers are within bounds
major :=major AND $FFF;
case major of
- diAcornADFS: //Create ADFS
- begin
- FDisc:=FormatADFSHDD(harddrivesize,newmap,dirtype);
- Result:=Length(FDisc)>0;
- end;
- diAcornFS: Result:=FormatAFS(harddrivesize,dirtype);//Create Acorn FS
- diDOSPlus: //Create DOS HDD
- begin
- FDisc:=FormatDOS(harddrivesize,dirtype);
- Result:=Length(FDisc)>0;
- end;
- diAmiga : //Create Amiga HDD
- begin
- FDisc:=FormatAmigaHDD(harddrivesize);
- Result:=Length(FDisc)>0;
- end;
+ diAcornADFS: Result:=FormatADFSHDD(harddrivesize,
+ newmap,
+ dirtype,
+ ide,
+ addheader); //Create ADFS
+ diAcornFS : Result:=FormatAFS(harddrivesize,dirtype);//Create Acorn FS
+ diDOSPlus : Result:=FormatDOS(harddrivesize,dirtype);//Create DOS HDD
+ diAmiga : Result:=FormatAmigaHDD(harddrivesize); //Create Amiga HDD
end;
end;
@@ -352,11 +318,11 @@ function TDiscimage.FormatHDD(major:Word;harddrivesize:Cardinal;newmap:Boolean;
Extracts a file, filename contains complete path (CFS, entry is entry number)
-------------------------------------------------------------------------------}
function TDiscImage.ExtractFile(filename:String;var buffer:TDIByteArray;
- entry:Cardinal=0): Boolean;
+ entry:Cardinal=0): Boolean;
begin
//Start with a false result
Result:=False;
- case FFormat>>4 of
+ case GetMajorFormatNumber of
diAcornDFS :Result:=ExtractDFSFile(filename,buffer); //Extract DFS
diAcornADFS:Result:=ExtractADFSFile(filename,buffer); //Extract ADFS
diCommodore:Result:=ExtractCDRFile(filename,buffer); //Extract Commodore 64/128
@@ -372,7 +338,8 @@ function TDiscImage.ExtractFile(filename:String;var buffer:TDIByteArray;
{-------------------------------------------------------------------------------
Save a file into the disc image, from buffer
-------------------------------------------------------------------------------}
-function TDiscImage.WriteFile(var file_details: TDirEntry; var buffer: TDIByteArray): Integer;
+function TDiscImage.WriteFile(var file_details: TDirEntry;
+ var buffer: TDIByteArray;ShowFSM: Boolean=False): Integer;
var
count : Integer;
begin
@@ -381,15 +348,15 @@ function TDiscImage.WriteFile(var file_details: TDirEntry; var buffer: TDIByteAr
//Get the length of data to be written
count:=file_details.Length;
//Only write a file if there is actually any data to be written
- if(count>0)and((Length(free_space)>0)or(FFormat>>4=diSpark))then
+ if(count>0)and((Length(free_space)>0)or(GetMajorFormatNumber=diSpark))then
begin
- if FFormat>>4<>diSpark then
+ if GetMajorFormatNumber<>diSpark then
file_details.Side:=file_details.Side mod Length(free_space);
//Can only write a file that will fit on the disc, or CFS
if(count<=free_space[file_details.Side])
- or(FFormat>>4=diAcornUEF)
- or(FFormat>>4=diSpark)then
- case FFormat>>4 of
+ or(GetMajorFormatNumber=diAcornUEF)
+ or(GetMajorFormatNumber=diSpark)then
+ case GetMajorFormatNumber of
diAcornDFS :Result:=WriteDFSFile(file_details,buffer); //Write DFS
diAcornADFS:Result:=WriteADFSFile(file_details,buffer); //Write ADFS
diCommodore:Result:=WriteCDRFile(file_details,buffer); //Write Commodore 64/128
@@ -411,7 +378,7 @@ function TDiscImage.CreateDirectory(var filename,parent,attributes: String): Int
begin
//Start with a false result
Result:=-1;
- case FFormat>>4 of
+ case GetMajorFormatNumber of
diAcornDFS : exit;//Can't create directories on DFS
diAcornADFS: //Create directory on ADFS
Result:=CreateADFSDirectory(filename,parent,attributes);
@@ -436,7 +403,7 @@ function TDiscImage.RetitleDirectory(var filename,newtitle: String): Boolean;
begin
//Start with a false result
Result:=False;
- case FFormat>>4 of
+ case GetMajorFormatNumber of
diAcornDFS : //DFS doesn't have directories
begin
//Update the disc title instead
@@ -513,15 +480,15 @@ function TDiscImage.FileExists(filename: String;var dir,entry: Cardinal;sfn: Boo
begin
SetLength(Path,0);
//Explode the pathname into an array, without the '.'
- if(FFormat>>4<>diAcornDFS)and(FFormat>>4<>diCommodore)then //Not DFS or Commodore
+ if(GetMajorFormatNumber<>diAcornDFS)and(GetMajorFormatNumber<>diCommodore)then //Not DFS or Commodore
begin
- if(FFormat>>4=diAcornADFS)and(FDOSPresent)
+ if(GetMajorFormatNumber=diAcornADFS)and(FDOSPresent)
and(LeftStr(filename,Length(dosrootname))=dosrootname)then//Is this on a DOS Partition of an ADFS?
Path:=filename.Split('\')
else
Path:=filename.Split(dir_sep);
end;
- if FFormat>>4=diAcornDFS then //With DFS, we need the initial root name, including the '.'
+ if GetMajorFormatNumber=diAcornDFS then //With DFS, we need the initial root name, including the '.'
begin
//So should only be 2 entries
SetLength(Path,2);
@@ -545,7 +512,7 @@ function TDiscImage.FileExists(filename: String;var dir,entry: Cardinal;sfn: Boo
Path[1]:=filename;
end;
end;
- if FFormat>>4=diCommodore then //Commodore is similar to DFS
+ if GetMajorFormatNumber=diCommodore then //Commodore is similar to DFS
begin
//So should only be 2 entries
SetLength(Path,2);
@@ -657,11 +624,11 @@ function TDiscImage.ReadDiscData(addr,count,side,offset: Cardinal;
begin
if offset+i>4<>diAcornDFS then //All but DFS
+ if GetMajorFormatNumber<>diAcornDFS then //All but DFS
if addr+i>4=diAcornDFS then //DFS only
+ if GetMajorFormatNumber=diAcornDFS then //DFS only
if ConvertDFSSector(addr+i,side)>4<>diAcornDFS then //not DFS
+ if GetMajorFormatNumber<>diAcornDFS then //not DFS
begin
//Ensure that the entire block will fit into the available space
Result:=(addr+count)<=GetDataLength;
@@ -842,7 +809,7 @@ function TDiscImage.RenameFile(oldfilename: String;var newfilename: String;
entry:Cardinal=0): Integer;
begin
Result:=-1;//Failed to rename
- case FFormat>>4 of
+ case GetMajorFormatNumber of
diAcornDFS : Result:=RenameDFSFile(oldfilename,newfilename); //Rename DFS
diAcornADFS: Result:=RenameADFSFile(oldfilename,newfilename); //Rename ADFS
diCommodore: Result:=RenameCDRFile(oldfilename,newfilename); //Rename Commodore 64/128
@@ -861,7 +828,7 @@ function TDiscImage.RenameFile(oldfilename: String;var newfilename: String;
function TDiscImage.DeleteFile(filename: String;entry: Cardinal=0): Boolean;
begin
Result:=False;
- case FFormat>>4 of
+ case GetMajorFormatNumber of
diAcornDFS : Result:=DeleteDFSFile(filename); //Delete DFS
diAcornADFS: Result:=DeleteADFSFile(filename); //Delete ADFS
diCommodore: Result:=DeleteCDRFile(filename); //Delete Commodore 64/128
@@ -880,7 +847,7 @@ function TDiscImage.DeleteFile(filename: String;entry: Cardinal=0): Boolean;
function TDiscImage.MoveFile(filename,directory: String): Integer;
begin
Result:=-12;
- case FFormat>>4 of
+ case GetMajorFormatNumber of
diAcornDFS : Result:=MoveDFSFile(filename,directory); //Move on DFS
diAcornADFS: Result:=MoveADFSFile(filename,directory); //Move ADFS File
diAmiga : Result:=MoveAmigaFile(filename,directory);//Move Amiga File
@@ -893,7 +860,7 @@ function TDiscImage.MoveFile(source: Cardinal;dest: Integer): Integer;
begin
Result:=-12;
//Can only move files on DFS (between drives), ADFS, Amiga, AFS and CFS
- if FFormat>>4=diAcornUEF then //Move on CFS
+ if GetMajorFormatNumber=diAcornUEF then //Move on CFS
Result:=MoveCFSFile(source,dest);
end;
@@ -938,7 +905,7 @@ function TDiscImage.CopyFile(filename,directory,newfilename: String): Integer;
DeleteFile(directory+dir_sep+file_details.Filename);
//Set up the filedetails
file_details.Parent:=directory;
- if FFormat>>4=diAcornDFS then //DFS
+ if GetMajorFormatNumber=diAcornDFS then //DFS
if(directory[1]=':')and(directory[2]='2') then
file_details.Side:=1
else
@@ -978,7 +945,7 @@ function TDiscImage.CopyFile(source: Cardinal;dest: Integer): Integer;
begin
Result:=-12;
//Can only copy files on DFS (between drives), ADFS, Amiga, AFS and CFS
- if FFormat>>4=diAcornUEF then //Copy on CFS
+ if GetMajorFormatNumber=diAcornUEF then //Copy on CFS
Result:=CopyCFSFile(source,dest);
end;
@@ -989,7 +956,7 @@ function TDiscImage.UpdateAttributes(filename,attributes: String;entry:Cardinal=
begin
Result:=False;
if(filename<>root_name)and(filename<>afsrootname)then
- case FFormat>>4 of
+ case GetMajorFormatNumber of
diAcornDFS : Result:=UpdateDFSFileAttributes(filename,attributes); //Update DFS attributes
diAcornADFS: Result:=UpdateADFSFileAttributes(filename,attributes); //Update ADFS attributes
diCommodore: Result:=UpdateCDRFileAttributes(filename,attributes); //Update Commodore 64/128 attributes
@@ -1008,7 +975,7 @@ function TDiscImage.UpdateAttributes(filename,attributes: String;entry:Cardinal=
function TDiscImage.UpdateDiscTitle(title: String;side: Byte): Boolean;
begin
Result:=False;
- case FFormat>>4 of
+ case GetMajorFormatNumber of
diAcornDFS : Result:=UpdateDFSDiscTitle(title,side);//Title DFS Disc
diAcornADFS:
begin
@@ -1032,7 +999,7 @@ function TDiscImage.UpdateDiscTitle(title: String;side: Byte): Boolean;
function TDiscImage.UpdateBootOption(option,side: Byte): Boolean;
begin
Result:=False;
- case FFormat>>4 of
+ case GetMajorFormatNumber of
diAcornDFS : Result:=UpdateDFSBootOption(option,side);//Update DFS Boot
diAcornADFS: Result:=UpdateADFSBootOption(option); //Update ADFS Boot
diCommodore: exit;//Update Commodore 64/128 Boot ++++++++++++++++++++++++++++++++++++++
@@ -1050,7 +1017,7 @@ function TDiscImage.UpdateBootOption(option,side: Byte): Boolean;
function TDiscImage.UpdateLoadAddr(filename:String;newaddr:Cardinal;entry:Cardinal=0): Boolean;
begin
Result:=False;
- case FFormat>>4 of
+ case GetMajorFormatNumber of
diAcornDFS : Result:=UpdateDFSFileAddr(filename,newaddr,True); //Update DFS Load Address
diAcornADFS: Result:=UpdateADFSFileAddr(filename,newaddr,True);//Update ADFS Load Address
diCommodore: exit;//Update Commodore 64/128 Load Address
@@ -1069,7 +1036,7 @@ function TDiscImage.UpdateLoadAddr(filename:String;newaddr:Cardinal;entry:Cardin
function TDiscImage.UpdateExecAddr(filename:String;newaddr:Cardinal;entry:Cardinal=0): Boolean;
begin
Result:=False;
- case FFormat>>4 of
+ case GetMajorFormatNumber of
diAcornDFS : Result:=UpdateDFSFileAddr(filename,newaddr,False); //Update DFS Execution Address
diAcornADFS: Result:=UpdateADFSFileAddr(filename,newaddr,False);//Update ADFS Execution Address
diCommodore: exit;//Update Commodore 64/128 Execution Address
@@ -1088,7 +1055,7 @@ function TDiscImage.UpdateExecAddr(filename:String;newaddr:Cardinal;entry:Cardin
function TDiscImage.TimeStampFile(filename:String;newtimedate:TDateTime):Boolean;
begin
Result:=False;
- case FFormat>>4 of
+ case GetMajorFormatNumber of
diAcornDFS : exit;//Update DFS Timestamp
diAcornADFS: Result:=UpdateADFSTimeStamp(filename,newtimedate);//Update ADFS Timestamp
diCommodore: exit;//Update Commodore 64/128 Timestamp
@@ -1107,7 +1074,7 @@ function TDiscImage.TimeStampFile(filename:String;newtimedate:TDateTime):Boolean
function TDiscImage.ChangeFileType(filename,newtype: String): Boolean;
begin
Result:=False;
- case FFormat>>4 of
+ case GetMajorFormatNumber of
diAcornDFS : exit;//Update DFS Filetype
diAcornADFS: Result:=UpdateADFSFileType(filename,newtype);//Update ADFS Filetype
diCommodore: exit;//Update Commodore 64/128 Filetype
@@ -1168,7 +1135,7 @@ procedure TDiscImage.BeginUpdate;
procedure TDiscImage.EndUpdate;
begin
Fupdating:=False;
- case FFormat>>4 of
+ case GetMajorFormatNumber of
diAcornDFS : exit;//Update DFS
diAcornADFS: ADFSFreeSpaceMap;//Update ADFS
diCommodore: exit;//Update Commodore 64/128
@@ -1200,7 +1167,7 @@ function TDiscImage.ValidateFilename(parent:String;var filename:String): Boolean
Result:=False;
len:=0; //Maximum file length
//Work out the max file length for the system
- case FFormat>>4 of
+ case GetMajorFormatNumber of
diAcornDFS : len:=7;
diAcornADFS:
begin
@@ -1221,7 +1188,7 @@ function TDiscImage.ValidateFilename(parent:String;var filename:String): Boolean
diAcornFS : len:=10;
diDOSPlus :
begin
- if FFormat mod$10=0 then len:=12 //Filename+'.'+extension - Master 512 DOS Plus
+ if GetMinorFormatNumber=0 then len:=12 //Filename+'.'+extension - Master 512 DOS Plus
else len:=255; //FAT12, 16, and 32
end;
end;
@@ -1230,7 +1197,7 @@ function TDiscImage.ValidateFilename(parent:String;var filename:String): Boolean
while Pos(GetDirSep(part),filename)>0 do
filename:=Copy(filename,Pos(GetDirSep(part),filename)+1);
//CFS files can have multiple files with the same name
- if FFormat>>4=diAcornUEF then
+ if GetMajorFormatNumber=diAcornUEF then
begin
Result:=True;
exit;
@@ -1286,8 +1253,8 @@ function TDiscImage.Title(partition: Cardinal):String;
function TDiscImage.CreatePasswordFile(Accounts: TUserAccounts): Integer;
begin
Result:=-5;
- if(FFormat>>4=diAcornFS)
- or((FFormat>>4=diAcornADFS)and(Fafspresent)) then
+ if(GetMajorFormatNumber=diAcornFS)
+ or((GetMajorFormatNumber=diAcornADFS)and(Fafspresent)) then
Result:=CreateAFSPassword(Accounts);
end;
@@ -1297,8 +1264,8 @@ function TDiscImage.CreatePasswordFile(Accounts: TUserAccounts): Integer;
function TDiscImage.ReadPasswordFile: TUserAccounts;
begin
Result:=nil;
- if(FFormat>>4=diAcornFS)
- or((FFormat>>4=diAcornADFS)and(Fafspresent)) then
+ if(GetMajorFormatNumber=diAcornFS)
+ or((GetMajorFormatNumber=diAcornADFS)and(Fafspresent)) then
Result:=ReadAFSPassword;
end;
@@ -1346,7 +1313,7 @@ function TDiscImage.SeparatePartition(side: Cardinal;filename: String=''): Boole
if side=1 then side:=0;
end;
//Extract the partition/side into a buffer.
- case FFormat>>4 of
+ case GetMajorFormatNumber of
diAcornDFS : buffer:=ExtractDFSPartition(side); //DFS
diAcornADFS: buffer:=ExtractADFSPartition(side); //ADFS/AFS or DOS
end;
@@ -1364,10 +1331,10 @@ function TDiscImage.SeparatePartition(side: Cardinal;filename: String=''): Boole
//Remember the current format
oldformat:=FFormat;
//If we have an ADFS/AFS hybrid, and are saving the AFS partition
- if(FFormat>>4=diAcornADFS)and(side<>0)and(FAFSPresent)then
+ if(GetMajorFormatNumber=diAcornADFS)and(side<>0)and(FAFSPresent)then
FFormat:=diAcornFS<<4;
//If we have an ADFS/DOS hybrid, and are saving the DOS partition
- if(FFormat>>4=diAcornADFS)and(side<>0)and(FDOSPresent)then
+ if(GetMajorFormatNumber=diAcornADFS)and(side<>0)and(FDOSPresent)then
FFormat:=diDOSPlus<<4;
filename:=filename+'.'+FormatToExt;
//Change back
@@ -1413,7 +1380,7 @@ function TDiscImage.GetMaxLength: Cardinal;
begin
Result:=0;
//Only 8 bit ADFS
- if(FFormat>>4=diAcornADFS)and(not FMap)and(FDirType=diADFSOldDir)then
+ if(GetMajorFormatNumber=diAcornADFS)and(not FMap)and(FDirType=diADFSOldDir)then
Result:=GetADFSMaxLength(False);
end;
@@ -1424,7 +1391,7 @@ function TDiscImage.AddPartition(size: Cardinal;format: Byte): Boolean;
begin
Result:=False;
//Only for adding AFS or DOS Plus partition to 8 bit ADFS
- if(FFormat>>4=diAcornADFS)and(not FMap)and(FDirType=diADFSOldDir)then
+ if(GetMajorFormatNumber=diAcornADFS)and(not FMap)and(FDirType=diADFSOldDir)then
case format of
0: Result:=AddAFSPartition(size); //Add AFS partition
1: Result:=AddDOSPartition(size); //Add DOS Plus partition
@@ -1434,7 +1401,7 @@ function TDiscImage.AddPartition(filename: String): Boolean;
begin
Result:=False;
//Only for Acorn DFS, given a filename
- if(FFormat>>4=diAcornDFS)and(not FDSD)then //Single sided images only
+ if(GetMajorFormatNumber=diAcornDFS)and(not FDSD)then //Single sided images only
Result:=AddDFSSide(filename);
end;
@@ -1452,8 +1419,8 @@ function TDiscImage.ChangeInterleaveMethod(NewMethod: Byte): Boolean;
//Only works with ADFS L and Acorn FS, or ADFS with non-auto interleave
if(FFormat=diAcornADFS<<4+2)
or(FFormat=diAcornADFS<<4+$E)
- or((FFormat>>4=diAcornADFS)and(FForceInter>0))
- or(FFormat>>4=diAcornFS) then
+ or((GetMajorFormatNumber=diAcornADFS)and(FForceInter>0))
+ or(GetMajorFormatNumber=diAcornFS) then
begin
//Set up the buffer
SetLength(buffer,GetDataLength);
@@ -1508,7 +1475,7 @@ function TDiscImage.ReadDirectory(dirname: String): Integer;
begin
sector:=FDisc[dir].Entries[entry].Sector;
//Divert to the appropriate function
- case FFormat>>4 of
+ case GetMajorFormatNumber of
diAcornADFS: NewDir:=ReadADFSDir(dirname,sector);
diAcornFS : NewDir:=ReadAFSDirectory(dirname,sector);
diAmiga : NewDir:=ReadAmigaDir(dirname,sector);
@@ -1536,3 +1503,51 @@ function TDiscImage.ReadDirectory(dirname: String): Integer;
end;
end;
end;
+
+{-------------------------------------------------------------------------------
+Produce a report of the image's details
+-------------------------------------------------------------------------------}
+function TDiscImage.ImageReport(CSV: Boolean): TStringList;
+var
+ temp,
+ uline : String;
+ side : Integer;
+ report: TStringList;
+begin
+ Result:=TStringList.Create;
+ if FFormat<>diInvalidImg then
+ begin
+ //Header
+ temp:='Container format: '+FormatToString;
+ Result.Add(temp);
+ if not(CSV) then
+ begin
+ uline:='';
+ uline:=AddChar('=',uline,Length(temp));
+ Result.Add(uline);
+ Result.Add('');
+ end;
+ //Main Report, depending on format
+ if GetMajorFormatNumber=diAcornDFS then report:=DFSReport(CSV); //DFS
+ if GetMajorFormatNumber=diAcornADFS then report:=ADFSReport(CSV);//ADFS
+ if(GetMajorFormatNumber=diAcornFS)
+ or((GetMajorFormatNumber=diAcornADFS)
+ and(FAFSPresent)) then report:=AFSReport(CSV);//AFS
+ if(GetMajorFormatNumber=diDOSPlus)
+ or((GetMajorFormatNumber=diAcornADFS)
+ and(FDOSPresent)) then report:=DOSReport(CSV);//DOS
+ if GetMajorFormatNumber=diCommodore then report:=CDRReport(CSV);//C64
+ if GetMajorFormatNumber=diAmiga then report:=AmigaReport(CSV);//Amiga
+ if GetMajorFormatNumber=diSinclair then report:=TStringList.Create;//Not written yet
+ if GetMajorFormatNumber=diAcornUEF then report:=TStringList.Create;//Nothing to report
+ if GetMajorFormatNumber=diSpark then report:=TStringList.Create;//Nothing to report
+ //Incorporate the report
+ if report.Count>0 then
+ for side:=0 to report.Count-1 do Result.Add(report[side]);
+ report.Free;
+ //Re-jig the output if CSV has been specified
+ if(CSV)and(Result.Count>0)then
+ for side:=0 to Result.Count-1 do
+ Result[side]:='"'+StringReplace(Result[side],': ','","',[rfReplaceAll])+'"';
+ end;
+end;
diff --git a/LazarusSource/DiscImage_Spark.pas b/LazarusSource/DiscImage_Spark.pas
index 875bd08..18e1d28 100644
--- a/LazarusSource/DiscImage_Spark.pas
+++ b/LazarusSource/DiscImage_Spark.pas
@@ -28,19 +28,19 @@ function TDiscImage.ID_Spark: Boolean;
{-------------------------------------------------------------------------------
Read Spark archive
-------------------------------------------------------------------------------}
-function TDiscImage.ReadSparkArchive: TDisc;
+function TDiscImage.ReadSparkArchive: Boolean;
var
index,
ref : Integer;
d,
e : Cardinal;
pnt : String;
- OldDisc: TDisc;
+// OldDisc: TDisc;
begin
//In order to be able to use FileExists, we need to populate FDisc
- OldDisc:=FDisc; //So take a note
+// OldDisc:=FDisc; //So take a note
//We will be returning a TDisc in Result
- Result:=nil;
+ Result:=False;
//Set up the array for the basic root entry
SetLength(FDisc,1);
ResetDir(FDisc[0]);
@@ -107,15 +107,16 @@ function TDiscImage.ReadSparkArchive: TDisc;
//Disc size (total uncompressed size)
disc_size[0]:=SparkFile.UncompressedSize;
//Return a result
- Result:=FDisc;
+ Result:=Length(FDisc)>0;
//And restore FDisc to what it was
- FDisc:=OldDisc;
+ //FDisc:=OldDisc;
end;
{-------------------------------------------------------------------------------
Extract a file from Spark archive
-------------------------------------------------------------------------------}
-function TDiscImage.ExtractSparkFile(filename: String;var buffer: TDIByteArray): Boolean;
+function TDiscImage.ExtractSparkFile(filename: String;
+ var buffer: TDIByteArray): Boolean;
var
d,e : Cardinal;
index: Integer;
@@ -142,17 +143,17 @@ function TDiscImage.ExtractSparkFile(filename: String;var buffer: TDIByteArray):
{-------------------------------------------------------------------------------
Create a new Spark archive
-------------------------------------------------------------------------------}
-function TDiscImage.FormatSpark(Zipfilename: String): TDisc;
+function TDiscImage.FormatSpark(Zipfilename: String): Boolean;
begin
- Result:=nil;
+ Result:=True;
if Zipfilename='' then exit;
//Set up the TDisc structure for return
- SetLength(Result,1);
- ResetDir(Result[0]);
+ SetLength(FDisc,1);
+ ResetDir(FDisc[0]);
//Set the root directory name
root_name:='$';
- Result[0].Directory:=root_name;
- Result[0].BeenRead:=True;
+ FDisc[0].Directory:=root_name;
+ FDisc[0].BeenRead:=True;
//Set the format
FFormat:=diSpark<<4;
//Create a blank file
diff --git a/LazarusSource/DiscImage_Spectrum.pas b/LazarusSource/DiscImage_Spectrum.pas
index 71f00ec..e7857d6 100644
--- a/LazarusSource/DiscImage_Spectrum.pas
+++ b/LazarusSource/DiscImage_Spectrum.pas
@@ -20,9 +20,9 @@ function TDiscImage.ID_Sinclair: Boolean;
{-------------------------------------------------------------------------------
Read Spectrum Disc
-------------------------------------------------------------------------------}
-function TDiscImage.ReadSinclairDisc: TDisc;
+function TDiscImage.ReadSinclairDisc: Boolean;
begin
- Result:=nil;
+ Result:=False;
{This functionality is not written yet}
end;
@@ -30,7 +30,7 @@ function TDiscImage.ReadSinclairDisc: TDisc;
Write a file to Spectrum image
-------------------------------------------------------------------------------}
function TDiscImage.WriteSpectrumFile(file_details: TDirEntry;
- var buffer: TDIByteArray): Integer;
+ var buffer: TDIByteArray): Integer;
begin
Result:=-1;
end;
@@ -38,9 +38,9 @@ function TDiscImage.WriteSpectrumFile(file_details: TDirEntry;
{-------------------------------------------------------------------------------
Create a new Spectrum image
-------------------------------------------------------------------------------}
-function TDiscImage.FormatSpectrum(minor: Byte): TDisc;
+function TDiscImage.FormatSpectrum(minor: Byte): Boolean;
begin
- Result:=nil;
+ Result:=False;
end;
{-------------------------------------------------------------------------------
diff --git a/LazarusSource/GJHRegistryClass.pas b/LazarusSource/GJHRegistryClass.pas
new file mode 100644
index 0000000..530c368
--- /dev/null
+++ b/LazarusSource/GJHRegistryClass.pas
@@ -0,0 +1,224 @@
+unit GJHRegistryClass;
+
+{
+TGJHRegistry class V1.00
+Copyright (C) 2022 Gerald Holdsworth gerald@hollypops.co.uk
+
+This source is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public Licence as published by the Free
+Software Foundation; either version 3 of the Licence, or (at your option)
+any later version.
+
+This code 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 General Public Licence for more
+details.
+
+A copy of the GNU General Public Licence is available on the World Wide Web
+at . You can also obtain it by writing
+to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
+Boston, MA 02110-1335, USA.
+}
+
+{$mode ObjFPC}{$H+}
+
+interface
+
+uses
+ Classes, Registry;
+
+{$M+}
+
+type
+ TGJHRegistry = class
+ private
+ FRegistry : TRegistry;
+ FRegKey : String;
+ procedure OpenReg(key: String);
+ function ExtractKey(var V: String):String;
+ published
+ constructor Create(RegKey: String);
+ function DeleteKey(key: String): Boolean;
+ function GetRegValS(V: String;D: String): String;
+ procedure GetRegValA(V: String;var D: array of Byte);
+ function GetRegValI(V: String;D: Cardinal): Cardinal;
+ function GetRegValB(V: String;D: Boolean): Boolean;
+ procedure SetRegValS(V: String;D: String);
+ procedure SetRegValA(V: String;var D: array of Byte);
+ procedure SetRegValI(V: String;D: Cardinal);
+ procedure SetRegValB(V: String;D: Boolean);
+ function DoesKeyExist(V: String):Boolean;
+ public
+ destructor Destroy; override;
+ end;
+
+implementation
+
+{-------------------------------------------------------------------------------
+Class creator - initialises the global variables
+-------------------------------------------------------------------------------}
+constructor TGJHRegistry.Create(RegKey: String);
+begin
+ inherited Create;
+ FRegKey:=RegKey;
+end;
+
+{-------------------------------------------------------------------------------
+Class destructor
+-------------------------------------------------------------------------------}
+destructor TGJHRegistry.Destroy;
+begin
+ inherited;
+end;
+
+{-------------------------------------------------------------------------------
+Open the registry key
+-------------------------------------------------------------------------------}
+procedure TGJHRegistry.OpenReg(key: String);
+begin
+ FRegistry:=TRegistry.Create;
+ if key<>'' then key:='\'+key;
+ FRegistry.OpenKey(FRegKey+key,true);
+end;
+
+{-------------------------------------------------------------------------------
+Function to delete a key from the registry
+-------------------------------------------------------------------------------}
+function TGJHRegistry.DeleteKey(key: String): Boolean;
+var
+ x: Boolean;
+begin
+ x:=True;
+ OpenReg(ExtractKey(key));
+ if FRegistry.ValueExists(key) then x:=FRegistry.DeleteValue(key);
+ FRegistry.Free;
+ Result:=x;
+end;
+
+{-------------------------------------------------------------------------------
+Function to read a string from the registry, or create it if it doesn't exist
+-------------------------------------------------------------------------------}
+function TGJHRegistry.GetRegValS(V: String;D: String): String;
+var
+ X: String;
+begin
+ OpenReg(ExtractKey(V));
+ If FRegistry.ValueExists(V)then X:=FRegistry.ReadString(V)
+ else begin X:=D;FRegistry.WriteString(V,X);end;
+ FRegistry.Free;
+ Result:=X;
+end;
+
+{-------------------------------------------------------------------------------
+Function to read an array from the registry, or create it if it doesn't exist
+-------------------------------------------------------------------------------}
+procedure TGJHRegistry.GetRegValA(V: String;var D: array of Byte);
+var
+ s: Integer;
+begin
+ OpenReg(ExtractKey(V));
+ If FRegistry.ValueExists(V)then
+ begin
+ s:=FRegistry.GetDataSize(V);
+ FRegistry.ReadBinaryData(V,D,s);
+ end
+ else
+ begin
+ FRegistry.WriteBinaryData(V,D,SizeOf(D));
+ end;
+ FRegistry.Free;
+end;
+
+{-------------------------------------------------------------------------------
+Function to read an integer from the registry, or create it if it doesn't exist
+-------------------------------------------------------------------------------}
+function TGJHRegistry.GetRegValI(V: String;D: Cardinal): Cardinal;
+var
+ X: Cardinal;
+begin
+ OpenReg(ExtractKey(V));
+ If FRegistry.ValueExists(V)then X:=FRegistry.ReadInteger(V)
+ else begin X:=D;FRegistry.WriteInteger(V,X);end;
+ FRegistry.Free;
+ Result:=X;
+end;
+
+{-------------------------------------------------------------------------------
+Function to read a boolean from the registry, or create it if it doesn't exist
+-------------------------------------------------------------------------------}
+function TGJHRegistry.GetRegValB(V: String;D: Boolean): Boolean;
+var
+ X: Boolean;
+begin
+ OpenReg(ExtractKey(V));
+ If FRegistry.ValueExists(V)then X:=FRegistry.ReadBool(V)
+ else begin X:=D;FRegistry.WriteBool(V,X);end;
+ FRegistry.Free;
+ Result:=X;
+end;
+
+{-------------------------------------------------------------------------------
+Does the specified key exist?
+-------------------------------------------------------------------------------}
+function TGJHRegistry.DoesKeyExist(V: String):Boolean;
+begin
+ OpenReg(ExtractKey(V));
+ Result:=FRegistry.ValueExists(V);
+ FRegistry.Free;
+end;
+
+{-------------------------------------------------------------------------------
+Function to save a string to the registry
+-------------------------------------------------------------------------------}
+procedure TGJHRegistry.SetRegValS(V: String;D: String);
+begin
+ OpenReg(ExtractKey(V));
+ FRegistry.WriteString(V,D);
+ FRegistry.Free;
+end;
+
+{-------------------------------------------------------------------------------
+Function to save an array to the registry
+-------------------------------------------------------------------------------}
+procedure TGJHRegistry.SetRegValA(V: String;var D: array of Byte);
+begin
+ OpenReg(ExtractKey(V));
+ FRegistry.WriteBinaryData(V,D,SizeOf(D));
+ FRegistry.Free;
+end;
+
+{-------------------------------------------------------------------------------
+Function to save an integer to the registry
+-------------------------------------------------------------------------------}
+procedure TGJHRegistry.SetRegValI(V: String;D: Cardinal);
+begin
+ OpenReg(ExtractKey(V));
+ FRegistry.WriteInteger(V,D);
+ FRegistry.Free;
+end;
+
+{-------------------------------------------------------------------------------
+Function to save a boolean to the registry
+-------------------------------------------------------------------------------}
+procedure TGJHRegistry.SetRegValB(V: String;D: Boolean);
+begin
+ OpenReg(ExtractKey(V));
+ FRegistry.WriteBool(V,D);
+ FRegistry.Free;
+end;
+
+{-------------------------------------------------------------------------------
+Function to extract key part of string
+-------------------------------------------------------------------------------}
+function TGJHRegistry.ExtractKey(var V: String):String;
+begin
+ Result:='';
+ if Pos('\',V)>0 then
+ begin
+ Result:=Copy(V,1,Pos('\',V)-1);
+ V:=Copy(V,Pos('\',V)+1);
+ end;
+end;
+
+end.
+
diff --git a/LazarusSource/Global.pas b/LazarusSource/Global.pas
index 740167e..c0f2042 100644
--- a/LazarusSource/Global.pas
+++ b/LazarusSource/Global.pas
@@ -23,31 +23,10 @@
interface
-uses
- Classes,SysUtils,Registry
-{ {$IFDEF Darwin}
- ,MacOSAll
- {$ENDIF}}
- ;
+uses Classes;
function ReadLine(var Stream: TFileStream;var Line: string): boolean;
function WriteLine(var Stream: TFileStream;Line: string): boolean;
-procedure OpenReg(key: String);
-function DeleteKey(key: String): Boolean;
-function GetRegValS(V: String;D: String): String;
-procedure GetRegValA(V: String;var D: array of Byte);
-function GetRegValI(V: String;D: Cardinal): Cardinal;
-function GetRegValB(V: String;D: Boolean): Boolean;
-procedure SetRegValS(V: String;D: String);
-procedure SetRegValA(V: String;var D: array of Byte);
-procedure SetRegValI(V: String;D: Cardinal);
-procedure SetRegValB(V: String;D: Boolean);
-function ExtractKey(var V: String):String;
-var
- DIMReg : TRegistry;
-const
- //Registry Key to use
- RegKey = '\Software\GJH Software\Disc Image Manager';
implementation
@@ -96,143 +75,4 @@ function WriteLine(var Stream: TFileStream;Line: string): boolean;
Result:=x=l;
end;
-{-------------------------------------------------------------------------------
-Open the registry key
--------------------------------------------------------------------------------}
-procedure OpenReg(key: String);
-begin
- DIMReg:=TRegistry.Create;
- if key<>'' then key:='\'+key;
- DIMReg.OpenKey(RegKey+key,true);
-end;
-
-{-------------------------------------------------------------------------------
-Function to delete a key from the registry
--------------------------------------------------------------------------------}
-function DeleteKey(key: String): Boolean;
-var
- x: Boolean;
-begin
- x:=True;
- OpenReg(ExtractKey(key));
- if DIMReg.ValueExists(key) then x:=DIMReg.DeleteValue(key);
- DIMReg.Free;
- Result:=x;
-end;
-
-{-------------------------------------------------------------------------------
-Function to read a string from the registry, or create it if it doesn't exist
--------------------------------------------------------------------------------}
-function GetRegValS(V: String;D: String): String;
-var
- X: String;
-begin
- OpenReg(ExtractKey(V));
- If DIMReg.ValueExists(V)then X:=DIMReg.ReadString(V)
- else begin X:=D;DIMReg.WriteString(V,X);end;
- DIMReg.Free;
- Result:=X;
-end;
-
-{-------------------------------------------------------------------------------
-Function to read an array from the registry, or create it if it doesn't exist
--------------------------------------------------------------------------------}
-procedure GetRegValA(V: String;var D: array of Byte);
-var
- s: Integer;
-begin
- OpenReg(ExtractKey(V));
- If DIMReg.ValueExists(V)then
- begin
- s:=DIMReg.GetDataSize(V);
- DIMReg.ReadBinaryData(V,D,s);
- end
- else
- begin
- DIMReg.WriteBinaryData(V,D,SizeOf(D));
- end;
- DIMReg.Free;
-end;
-
-{-------------------------------------------------------------------------------
-Function to read an integer from the registry, or create it if it doesn't exist
--------------------------------------------------------------------------------}
-function GetRegValI(V: String;D: Cardinal): Cardinal;
-var
- X: Cardinal;
-begin
- OpenReg(ExtractKey(V));
- If DIMReg.ValueExists(V)then X:=DIMReg.ReadInteger(V)
- else begin X:=D;DIMReg.WriteInteger(V,X);end;
- DIMReg.Free;
- Result:=X;
-end;
-
-{-------------------------------------------------------------------------------
-Function to read a boolean from the registry, or create it if it doesn't exist
--------------------------------------------------------------------------------}
-function GetRegValB(V: String;D: Boolean): Boolean;
-var
- X: Boolean;
-begin
- OpenReg(ExtractKey(V));
- If DIMReg.ValueExists(V)then X:=DIMReg.ReadBool(V)
- else begin X:=D;DIMReg.WriteBool(V,X);end;
- DIMReg.Free;
- Result:=X;
-end;
-
-{-------------------------------------------------------------------------------
-Function to save a string to the registry
--------------------------------------------------------------------------------}
-procedure SetRegValS(V: String;D: String);
-begin
- OpenReg(ExtractKey(V));
- DIMReg.WriteString(V,D);
- DIMReg.Free;
-end;
-
-{-------------------------------------------------------------------------------
-Function to save an array to the registry
--------------------------------------------------------------------------------}
-procedure SetRegValA(V: String;var D: array of Byte);
-begin
- OpenReg(ExtractKey(V));
- DIMReg.WriteBinaryData(V,D,SizeOf(D));
- DIMReg.Free;
-end;
-
-{-------------------------------------------------------------------------------
-Function to save an integer to the registry
--------------------------------------------------------------------------------}
-procedure SetRegValI(V: String;D: Cardinal);
-begin
- OpenReg(ExtractKey(V));
- DIMReg.WriteInteger(V,D);
- DIMReg.Free;
-end;
-
-{-------------------------------------------------------------------------------
-Function to save a boolean to the registry
--------------------------------------------------------------------------------}
-procedure SetRegValB(V: String;D: Boolean);
-begin
- OpenReg(ExtractKey(V));
- DIMReg.WriteBool(V,D);
- DIMReg.Free;
-end;
-
-{-------------------------------------------------------------------------------
-Function to extract key part of string
--------------------------------------------------------------------------------}
-function ExtractKey(var V: String):String;
-begin
- Result:='';
- if Pos('\',V)>0 then
- begin
- Result:=Copy(V,1,Pos('\',V)-1);
- V:=Copy(V,Pos('\',V)+1);
- end;
-end;
-
end.
diff --git a/LazarusSource/HardDriveUnit.lfm b/LazarusSource/HardDriveUnit.lfm
index 4188049..81b8e1e 100644
--- a/LazarusSource/HardDriveUnit.lfm
+++ b/LazarusSource/HardDriveUnit.lfm
@@ -146,6 +146,44 @@ object HardDriveForm: THardDriveForm
Width = 34
Caption = '10MB'
end
+ object DOSControls: TPanel
+ Left = 80
+ Height = 20
+ Top = 56
+ Width = 402
+ BevelOuter = bvNone
+ ClientHeight = 20
+ ClientWidth = 402
+ TabOrder = 4
+ OnPaint = FormPaint
+ object rb_FAT12: TRadioButton
+ Left = 27
+ Height = 18
+ Top = 0
+ Width = 56
+ Caption = 'FAT12'
+ OnChange = rb_FAT12Change
+ TabOrder = 0
+ end
+ object rb_FAT16: TRadioButton
+ Left = 136
+ Height = 18
+ Top = 0
+ Width = 57
+ Caption = 'FAT16'
+ OnChange = rb_FAT16Change
+ TabOrder = 1
+ end
+ object rb_FAT32: TRadioButton
+ Left = 256
+ Height = 18
+ Top = 0
+ Width = 58
+ Caption = 'FAT32'
+ OnChange = rb_FAT32Change
+ TabOrder = 2
+ end
+ end
object ADFSControls: TPanel
Left = 80
Height = 20
@@ -157,7 +195,7 @@ object HardDriveForm: THardDriveForm
TabOrder = 3
OnPaint = FormPaint
object cb_NewMap: TCheckBox
- Left = 16
+ Left = 0
Height = 18
Top = 0
Width = 75
@@ -166,14 +204,14 @@ object HardDriveForm: THardDriveForm
TabOrder = 0
end
object DirectoryLabel: TLabel
- Left = 144
+ Left = 216
Height = 16
- Top = 0
+ Top = 1
Width = 60
Caption = 'Directory:'
end
object rb_OldDir: TRadioButton
- Left = 224
+ Left = 276
Height = 18
Top = 0
Width = 42
@@ -183,7 +221,7 @@ object HardDriveForm: THardDriveForm
TabStop = True
end
object rb_NewDir: TRadioButton
- Left = 277
+ Left = 318
Height = 18
Top = 0
Width = 48
@@ -191,50 +229,30 @@ object HardDriveForm: THardDriveForm
TabOrder = 2
end
object rb_BigDir: TRadioButton
- Left = 333
+ Left = 365
Height = 18
Top = 0
Width = 41
Caption = 'Big'
TabOrder = 3
end
- end
- object DOSControls: TPanel
- Left = 80
- Height = 20
- Top = 56
- Width = 402
- BevelOuter = bvNone
- ClientHeight = 20
- ClientWidth = 402
- TabOrder = 4
- OnPaint = FormPaint
- object rb_FAT12: TRadioButton
- Left = 27
+ object cb_IDE: TCheckBox
+ Left = 76
Height = 18
Top = 0
- Width = 56
- Caption = 'FAT12'
- OnChange = rb_FAT12Change
- TabOrder = 0
- end
- object rb_FAT16: TRadioButton
- Left = 136
- Height = 18
- Top = 0
- Width = 57
- Caption = 'FAT16'
- OnChange = rb_FAT16Change
- TabOrder = 1
+ Width = 42
+ Caption = 'IDE'
+ Checked = True
+ State = cbChecked
+ TabOrder = 4
end
- object rb_FAT32: TRadioButton
- Left = 256
+ object cb_AddHeader: TCheckBox
+ Left = 120
Height = 18
Top = 0
- Width = 58
- Caption = 'FAT32'
- OnChange = rb_FAT32Change
- TabOrder = 2
+ Width = 76
+ Caption = 'Emulator'
+ TabOrder = 5
end
end
end
diff --git a/LazarusSource/HardDriveUnit.pas b/LazarusSource/HardDriveUnit.pas
index 605bbf8..a4a9c79 100644
--- a/LazarusSource/HardDriveUnit.pas
+++ b/LazarusSource/HardDriveUnit.pas
@@ -33,6 +33,8 @@ interface
THardDriveForm = class(TForm)
cb_NewMap: TCheckBox;
+ cb_AddHeader: TCheckBox;
+ cb_IDE: TCheckBox;
Image1: TImage;
CapacityHeaderLabel: TLabel;
CapacityLabel: TLabel;
@@ -93,6 +95,7 @@ procedure THardDriveForm.cb_NewMapChange(Sender: TObject);
//Enable/disable the appropriate radio boxes
rb_BigDir.Enabled:=cb_NewMap.Checked;
rb_OldDir.Enabled:=not cb_NewMap.Checked;
+ cb_IDE.Enabled:=cb_NewMap.Checked;
//If Old map is selected
if not cb_NewMap.Checked then
begin
@@ -133,15 +136,19 @@ procedure THardDriveForm.FormShow(Sender: TObject);
ADFSControls.Visible:=True;
DOSControls.Visible:=False;
Caption:='Create ADFS Hard Drive';
- //Set directory type to 'Old'
- rb_OldDir.Checked:=True;
- rb_NewDir.Checked:=False;
- rb_BigDir.Checked:=False;
- //Enable/Disable the appropriate radio boxes
- rb_OldDir.Enabled:=True;
- rb_BigDir.Enabled:=False;
- cb_NewMap.Checked:=False;
end;
+ //Set directory type to 'Old'
+ rb_OldDir.Checked:=True;
+ rb_NewDir.Checked:=False;
+ rb_BigDir.Checked:=False;
+ //Enable/Disable the appropriate radio boxes
+ rb_OldDir.Enabled:=True;
+ rb_BigDir.Enabled:=False;
+ //Other options
+ cb_NewMap.Checked:=False;
+ cb_AddHeader.Checked:=False;
+ cb_IDE.Checked:=True;
+ cb_IDE.Enabled:=cb_NewMap.Checked;
if AmigaHDD then
begin
//Set capacity to 40MB
@@ -165,10 +172,10 @@ procedure THardDriveForm.FormShow(Sender: TObject);
ADFSControls.Visible:=False;
DOSControls.Visible:=True;
Caption:='Create DOS Hard Drive';
- rb_FAT12.Checked:=True;
- rb_FAT16.Checked:=False;
- rb_FAT32.Checked:=False;
end;
+ rb_FAT12.Checked:=True;
+ rb_FAT16.Checked:=False;
+ rb_FAT32.Checked:=False;
end;
{-------------------------------------------------------------------------------
diff --git a/LazarusSource/ImageReportUnit.lfm b/LazarusSource/ImageReportUnit.lfm
new file mode 100644
index 0000000..4648251
--- /dev/null
+++ b/LazarusSource/ImageReportUnit.lfm
@@ -0,0 +1,26 @@
+object ImageReportForm: TImageReportForm
+ Left = 304
+ Height = 401
+ Top = 113
+ Width = 518
+ Caption = 'Image Report'
+ ClientHeight = 401
+ ClientWidth = 518
+ Position = poMainFormCenter
+ LCLVersion = '2.2.0.4'
+ object Report: TMemo
+ Left = 0
+ Height = 401
+ Top = 0
+ Width = 518
+ Align = alClient
+ Font.Name = 'Courier New'
+ Lines.Strings = (
+ 'Report'
+ )
+ ParentFont = False
+ ReadOnly = True
+ ScrollBars = ssAutoBoth
+ TabOrder = 0
+ end
+end
diff --git a/LazarusSource/ImageReportUnit.pas b/LazarusSource/ImageReportUnit.pas
new file mode 100644
index 0000000..f710fc6
--- /dev/null
+++ b/LazarusSource/ImageReportUnit.pas
@@ -0,0 +1,30 @@
+unit ImageReportUnit;
+
+{$mode ObjFPC}{$H+}
+
+interface
+
+uses
+ Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls;
+
+type
+
+ { TImageReportForm }
+
+ TImageReportForm = class(TForm)
+ Report: TMemo;
+ private
+
+ public
+
+ end;
+
+var
+ ImageReportForm: TImageReportForm;
+
+implementation
+
+{$R *.lfm}
+
+end.
+
diff --git a/LazarusSource/MainUnit.lfm b/LazarusSource/MainUnit.lfm
index f7a10f7..21ed2b1 100755
--- a/LazarusSource/MainUnit.lfm
+++ b/LazarusSource/MainUnit.lfm
@@ -2,10 +2,10 @@ object MainForm: TMainForm
Left = 393
Height = 599
Top = 185
- Width = 751
+ Width = 745
AllowDropFiles = True
ClientHeight = 599
- ClientWidth = 751
+ ClientWidth = 745
Color = 15527148
Constraints.MinHeight = 500
Constraints.MinWidth = 664
@@ -4298,18 +4298,18 @@ object MainForm: TMainForm
Left = 0
Height = 505
Top = 76
- Width = 391
+ Width = 385
Align = alClient
BevelColor = 15527148
ClientHeight = 505
- ClientWidth = 391
+ ClientWidth = 385
TabOrder = 0
OnPaint = FileInfoPanelPaint
object lb_contents: TLabel
Left = 1
Height = 16
Top = 1
- Width = 389
+ Width = 383
Align = alTop
Alignment = taCenter
Caption = 'Image Contents'
@@ -4322,7 +4322,7 @@ object MainForm: TMainForm
Left = 1
Height = 487
Top = 17
- Width = 389
+ Width = 383
Align = alClient
BackgroundColor = clNone
BorderStyle = bsNone
@@ -4373,7 +4373,7 @@ object MainForm: TMainForm
Left = 0
Height = 18
Top = 581
- Width = 751
+ Width = 745
Panels = <
item
Style = psOwnerDraw
@@ -4477,7 +4477,7 @@ object MainForm: TMainForm
Visible = False
end
object ToolSplitter: TSplitter
- Left = 391
+ Left = 385
Height = 505
Top = 76
Width = 5
@@ -4487,7 +4487,7 @@ object MainForm: TMainForm
ResizeAnchor = akRight
end
object FileInfoPanel: TPanel
- Left = 396
+ Left = 390
Height = 505
Top = 76
Width = 355
@@ -9569,7 +9569,7 @@ object MainForm: TMainForm
Left = 0
Height = 76
Top = 0
- Width = 751
+ Width = 745
AutoSize = True
BandBorderStyle = bsNone
BandMaximize = bmNone
@@ -9581,7 +9581,7 @@ object MainForm: TMainForm
FixedSize = True
MinWidth = 274
ParentColor = False
- Width = 274
+ Width = 311
end
item
Break = False
@@ -9619,13 +9619,13 @@ object MainForm: TMainForm
object ToolsToolBar: TToolBar
AnchorSideLeft.Control = ToolBarContainer
AnchorSideTop.Control = ToolBarContainer
- Left = 12
+ Left = 208
Height = 37
Top = 39
Width = 186
Align = alNone
AutoSize = True
- BorderSpacing.Left = 12
+ BorderSpacing.Left = 208
BorderSpacing.Top = 39
ButtonHeight = 37
ButtonWidth = 37
@@ -9685,7 +9685,7 @@ object MainForm: TMainForm
Left = 12
Height = 37
Top = 0
- Width = 260
+ Width = 297
Align = alNone
AutoSize = True
BorderSpacing.Left = 12
@@ -9759,16 +9759,24 @@ object MainForm: TMainForm
ImageIndex = 8
OnClick = btn_FileSearchClick
end
+ object btn_ShowReport: TToolButton
+ Left = 260
+ Hint = 'Show Image Report'
+ Top = 0
+ AutoSize = True
+ ImageIndex = 24
+ OnClick = btn_ShowReportClick
+ end
end
object FilesToolBar: TToolBar
AnchorSideLeft.Control = ToolBarContainer
AnchorSideTop.Control = ToolBarContainer
- Left = 286
+ Left = 323
Height = 37
Top = 0
Width = 260
Align = alNone
- BorderSpacing.Left = 286
+ BorderSpacing.Left = 323
ButtonHeight = 37
ButtonWidth = 37
Caption = 'Files'
@@ -9844,12 +9852,13 @@ object MainForm: TMainForm
object PartitionToolBar: TToolBar
AnchorSideLeft.Control = ToolBarContainer
AnchorSideTop.Control = ToolBarContainer
- Left = 560
+ Left = 12
Height = 37
- Top = 0
+ Top = 39
Width = 182
Align = alNone
- BorderSpacing.Left = 560
+ BorderSpacing.Left = 12
+ BorderSpacing.Top = 39
ButtonHeight = 37
ButtonWidth = 37
Caption = 'Partition'
@@ -9974,7 +9983,7 @@ object MainForm: TMainForm
Left = 80
Top = 152
Bitmap = {
- 4C7A1800000044000000440000008AC501000000000078DAE49D075854D7F6F6
+ 4C7A190000004400000044000000A8D501000000000078DAE49D075854D7F6F6
C7129368346A8CA9E62637B9E5FFE5DE7463622276052C181B6A62EFBD61EFBD
170494DE417A95228AA22845A508A2220A22166CD8626288C9FAD6BB67F67866
98A1054B72E779DEE7CC9CBAF7EFACBDF6DAE59C51A91EEFA7C5DB6FFFFD1FEF
@@ -13365,244 +13374,373 @@ object MainForm: TMainForm
A7F4060CB0213ED61DC693CB6371E78250C4959CFD88AF5F585524851746DEAA
B38D8A31B4A1ECDC1D0573C37625BEB60B09FFDD86686921A27B6DC0F97367EE
6E2F3E9292CF2EF1F3AE43C2C11AA41CAEC791CCAB4849B98AF8C3400C61F8E8
- 1848B7AEC57D8F6DC5FD4F981176A0C70326B8EBFFAA3BF3B81AF7F5EFDFD866
- 4AA492296556868450C624438650941476D98568B38D99C9944D64A84849E60C
- 5B6C691E08A5C81C453491E65AB59ADEBF6F6DCF3ECF39AFF33B673FCFCBF93D
- AFE78FCFEBDB4AD6BABFEFFBBA3ED775ADFB6EA51E8BF3D56CA290F1482E27AA
- 58F847819C2BA2B7F4CD92E3F1B1821D29E5FCF24C865D7225E3025219EEFA08
- 0D111F2A9BE278FAB576F8FED0757334F677793CF6F8EC8C5BF7E27EFCABC79C
- 7DF3F9A43B3DD6A6DFD45A9E9E119964F53D6B49DAFBAA95D7038B88BF5750CF
- 23E5752DCF93FFE0111E0B332C1ED0A0B9EB1F3CBA78A2D4E5082DDA1FA1A54A
- 282B02B20817F171BF424E68510541A2B69CCFA9C03BB31CB7F7325C5E89D878
- 2263BEE8A74607A430A29E471C3D76A5941D8D0F3BBDE69A2DCDCE7741F29290
- 6C54587D604F600595AAF57954FBAFFB6F5966DE0F85A9E98DBE776DF5F2CD71
- 080D2E213E369FA44745BC11BD61F2D31AE21E40A8E889669A3F123C76D3A6A3
- 3B4A9D4F081DA4B9CA219A2B85B0EC641677058F28E1A7770A2BB89E276A6D8E
- 8CA31925EC4C2D61D58B12EC1E17332BBE0C8333AF31D81D8FE6B60728ACBB57
- E5127C5ABC7C319F29C4F2B513528060325962C832A382C0674196FFEEB86BCA
- E562B6ADF9EEBDC6C5C05C9B9B374A78189D4FE2C3425E88D8487C5C438C888D
- E0C83A1E75F1B147F0F0A08DBA174AAA5E346FE7293C2404879319DC16F91226
- 780415C8B89C5BC169C1C35DF0D82A7838BD2862C1E342263F2C6284DF4BC1A3
- 2E3E1ED06A7538375FBFA66E202910AA104C4F7DB946E7E05E486B0497598DD8
- E0BED5AF0C59EBFFE9F9EC5142A9D9954B85C44516921057C433E11D09F13544
- 8BD8B8132E78CC7D88D4E8240A0A775154BE8A82BA2F4D5B5EA389F4029B5FE5
- 44882749A4BE7DE6AAF0E2539F455DF95482CBBB121C9F1761995088515C21C3
- 048F51BB1FD6F350581BC3D5B4E7E27FBDE055E5439EC86304971C9E92C2BC57
- 3F221D134CA6490CB6D6CB887A1C39B5EE384B29ADAF45FF691EE131852637AE
- 15722FBC8047F78A484EAC21FE610D9191B5DC09038BB96982C746A41E13453C
- EB232D1F86646F81346C355D577BB1FC710CEE2FDF72EA5321FE5FC157E8A8A8
- 4FDB7361D907519F9ED732F65139FAFE6F19EB9680E68E785AAE8BE6744A1C72
- 927859F98024C123B6229817B50FC922038FCFDEA8DF14BE6226B8E84A6C7173
- 3996C1A7FA1A945B962BC96BE5FF311EC92F2BC65E3C5F404C683E0F6384A726
- D4F230AE86F0F05A6E07C318E31446DAAE6247983DB37E9D87FE1913BADDEC4F
- D3C36D907E698864D918699E8AF0435D5457CE61A0D746C65DF361EA6FE14C0D
- 7A89C99DCF0C8DAA44D73F9FB1BBD3D1589F2CFAB1083C5362C9E53E8FE59124
- C845FD95871259FE1B2165977923BA9AB0E250A647CEAAFFAC56A9ABC488697A
- 299149A163EB8E59E49154CB7FE67DB192921AFDB367F28912B3D283A802121F
- D51277AF8690905A826E419F918938EDF5153FFA95A2820C523F2472FF491057
- 434E71E4E64E7EBE22385D30456FAF1E1D5676A5D16605A48D4DC43E5A222DEB
- 4CE36583696E634A8BF97674B6DF493BCB33B4587897E399F7C5DC132518DC26
- A6E277A1202265D7B85B7241F4F89EDC2D3FC7839A30363FDE44FBEDEA48BD25
- 9A6848B87A6DDFFB678DA9927D771E0F1E950CBC10904FE49D02EE47E6132F62
- 2336BA86E03BB5FC1604030DDE32C7E508F9C239138B42492CB84372DE5D91E9
- 51A4714FB86138C9E537B8577086DF3EB8E3F3700BAEB79D703C3F8FA99E6318
- B653879EF62A283848B414E7BA8DE52C941725D49ADF38C4A57C7731D68773AB
- 2290DF6597B8531AC0AD225FAEE77B11F0E5A0F0D85DDC94FB703CED00A38F8D
- 411A2D62A59DC4041BA327C9E9C9F5F3716DEDF78D936DBB32FA040A3F8DB893
- 474CD8571EC4D6101551C3EDDB355C17F3B6EEC834A6ADF5205B0CDF09B921C4
- 6505119B7595A892CB84C9C4F1171CE3EAE77D5CCCDCCAF9F4F55C485B47E05B
- 17FC92D6B2EDEE8F2C3D6BC128BF6128B92AA0642578CC1E4BDBA5F76A0F3F7E
- E47428767DE08A0467AE70912BD5FE5C283CC1C582A39CCF3DC4999C7D78656D
- C72D6D158773D670F0D366A69F9F8ECA2255A48E82CB1009AF70CF9FBF777C9C
- BB98A771E15C2177AEE7121592CDBDA81A22426BB8F95B0D57AFC390911F98B0
- FC5752C5513FC80D1673D87522B32F1321BBC85DD919820A8F11F8651FE73E6D
- E1F4DB5F38FE6C291EF1766C0D33C7FAF2188C4E0EA4B347071456B64175DE0F
- 82C970E1351749ADA41B5595D2F6DF77BBCDBA3D0BD7DC2DF8551FE3C417573C
- B377703C6333473EAEE3D7B4D56C7F66877D8229D64FA63321601C3DB7F6409A
- 2DB1E4A45D588DF091EADAEFF7DEE993E4C276FE7EF965970372B8733393A8B0
- 6A4283456C5CABE14A20E81BA463E0E0262AA33FB139B789F820E222E702C1F2
- 006E947973B9E020019F77E2F3693DC7DF3AE1FECC9E83F10BD91436074BC163
- F4A9FE747657A78DB3126A0B9AA1347F244D6D2F1094259B51FABFCE49E2A549
- 33AFCCCCB68A9FCDAEEAF56CA85EC696FC65ECFCB40CD7949F589B608945A431
- 06D706D3DBB33BBAA7B4D1DADF998FF91F7BD7E7CC77F4D6ACECCA563E27BFE6
- FB9FCAE6CAF90CEEDEAE24F8763581576AB87019468A99566FF15EA26B8F7123
- F332D7DE099FC8394360950F01A547385D20CE67CE460EA7AFC4ED8D3DAE4F17
- B0F3E13C56879832EBD270869DEA4587232AB45955C7A3294AF3F4E962739E75
- 39E55336D5F599FCD1537CA92C9496463BEF9D7D79728D6BE02AD686D9B2F499
- 19F6EFA762F66A18431E76A7F365557A081E759FFFEC70D6F1DA7FA8E6363EE3
- 9B97E3E591C159DF74826E94F37B5035172F5613705ED4DB513968CF73E5AC6C
- 9798597D38FACA03EF9CE3F8541FE558C91E0EE5B9B02FCB991D69766C7A359F
- 7549B359736F3A0EC113987C5197013EDD68EFD10EA5D5ED509DDF9036E60368
- 62794ED411A6FCEDFAA4D00B3ABC738FD970C1C0ADE692EE1A4E1939E06BBD8B
- FD6B7F66C5EED94C3B38946EFB5569FE6B13D40EA9CB722869C8970A49FEAEE8
- BBF2C8C949957C7D723E1C3F9C83DFC934AE5D9171F37A35E702AAF10F80F186
- B9F4B2DA840F9BF0C83AC5BE1707D89FE3865BD55E5C8B37B1F9EB4AD665FCC8
- CFEF2C59F67C064B1E9960176984759021E3CF6BD3D7A713CA1E4AB45DF58DC7
- 9CDE74700EE77844F2D4B0A04049FEA1AC7394F9899BFE5DD77241612D97BB6E
- C053DB91081DE1DF3D6379AC114A92C61DE2BB8B1AD4DF936D431D711FB3A6EC
- FDFAFB87D397DC5DFB715FD094DA9A8AEF36D7E9E88C967E754B797DD6A78CD3
- 5EEF09BC24134C040BBF2A7CCF887EDD288F96066E58A4ADC439D79B559927D8
- CB51F6B09F0DF2B5387FB567C9C7B9D8BE31C5F2A911E6F70D9815A28FE9F5C1
- 189CED452F1F75948FD4F15046CDA6116D6669A2E27813FF17D9535FBE7A2E7D
- 894A5D96B4EB14EF8E4793B92F95A7F6C1C44FFD9D47BAA296750824B4C5596E
- 35F4E6B6E44DF40F6778DFFA1A2FA55384484EFCD66A3EC7BBD893FB2C6FE0F7
- E271ECC41BC9DB332BC9E3D74C4E9D48E7F27931979DAFC2E75415277D60CE82
- 425A4917316DA6865D9FC6CC9BACC9B4DD6398946CC1D84A6B8CB1622AB3999E
- 6FC2D4144326DE1F8CD1EDFE8CBAD49B417E5DD13AA98AF22125DAAD56416DB1
- 880F335554ADAF73B6327F4ADD757BF9BD7CFBEAD769F0E5DB1BD42F84A2E414
- 5DCA24FBD0735EAD89E2F1C2206E99787366F0562E6938E0D7C9920BDD6D7153
- 9B886133676A3F31E2BBF969168247E6BDBD3B3FE0753495F3FE259CF3AFC2DB
- 53CE096F309C56C424AD037CDC68C1F51993D8D15B93E98A2D19DA4AA2B7A684
- C678892ECB7FA0CB0925BADE5547E37157341235E916A949D76B9DE8E8AF42BB
- 634A62866B4BF3753FD0CC6A000A220622E435136BA8964A23321617DE7E4845
- 781E55BFCB90DF2CA2EA461135D78AA9BD5A0CD74415BA2803EFAFD4B8BFE3CD
- 247F023B2C619BDA5C96359DC45CCD7DB8DA78E8C63F7DF0DD3CE4A45746C88E
- 4D291C3FFC8E333EC59C395DC5F163951C3D0E23C666317188A7387F3728CFB8
- 4FDAE320926FFA12736017B7ED96E233663ADB7A0C64815A7B467668C0A03E12
- 3A82512F5B09B5F50D51706B2A82B0050DB734A2F79456A8EAEE405A9A441C0C
- AF7FFDE4E2899581AF205CD009AA447EB1888AB3F9949FCA45E69143B95B16B2
- 9D1F29DDF4868AED2FC9187F1DAF668B58D4D2849F14CCD866E8898E34486FCC
- 0883BFEF33B76D93264D9A24A5A6A64A7A7A7A92939393545DFDEFFB94BA6BAC
- FE7E05D737AF7B87C7C1544E7996E0E355C511F74ADC0F8381C917A6F4F1A03A
- 743FC5626629B97582F2601138D17EF05414E464D1A4449DA524E0082FB76CE0
- AE852DA7874DC0554B9B5F3AAB63A7A5C858BD96D8F56E468024B15245833946
- 73B8B9DAFC49E2CD7D2EB77C3CBDA2571C24F3F05BAACF8A23124FC939A8F294
- 51BAEF23653B33906DF948C9BAD794AD7DCA9BD101B82BD8B044D1147BC1C365
- 983B13A4F17A8BE6DB8A3E04E9D2E54069A3CB967FFAB7D55EBD7CF997E2E3C6
- F5D2F3AB57BCE3E0FEB79CF028C553C4C6C10315B8FD2AF2654A11337B7922BB
- BA85EC9B47C9BE7C904F17DC28B9B01B0236537D72359C58095EABC0671D9CDE
- 08273750E4BA9C4C5B0B1E8F9B4454773D229BB725DCBA3F41AB7B123242E2AA
- 9859CF8E93383D4D22C0AC3981D6BDB866358DAB761B79E47401D9B68FC877E6
- 51EA928E6CDD7B4A9C5F52E69CC453435F0E2858B15C7106B60AD3593DF8A888
- 0F3DEDEB776F492F9FC6D5EF5B414151D2EAAADAC460600FD5E906837BCD19D2
- 77C262B3694322EFDD97D2D33FFC4B167979D5D2A95345A77F767ACB2E118F07
- DD8A397AB892FD7BE5ECD95B8B81690533B44E5279622959A7B6917E6C13E947
- 37203BB1965AEF5FA83CEA4CE501472A772D46BED112F92A336A5698C2622398
- 3C98FC217D78DC439D6B2236DE5DDE420DEFF870DF9B87A75611B26F1661CB87
- 126ED58508B3C6DC359438A227E12638C5982DA2667D3565EB3F51F6731AC5CB
- 9E53B2348127067EB8292E60459B69CC53988949FBB5B547E7FA7691BDB93BF6
- D1D5C5E7422F2D08FB18EF929419B62AA3F8CE46511C9CC9DE2C46BFE025A877
- 506937D4D0E45F5F9B4C92492E2EF9C77F5EF182B5AB1FB37B6731EEBF56B27B
- 979C1DBB6A193D438E51A793C876DB907DC099D73B9691BEFD27AA76D951B56F
- 09957BEC916FB141BE761E72E759C81DA722B737A1DC72348586FD48D7EAC023
- D536DC6820F1CACB41BC649850607D6294579CE6C37337E2039D093D388FA865
- BAC4CF6BCBADE9124113C653B04E78C8AA6C4A97BFA3F8A7648AED1F923CC217
- F736B6AC10F932B7F56C26B477FD90E87F7E7DF987C3E48BFE88527F8ADF7B50
- 91E64DD9CBE37C0E71267E6347F28E74C0B05F3BE3D64AAAD2DEBD7BEB7DA5B4
- B4F49F5CAFAC95FCFD4B7FB5B57EC6CAE5F16CDF5A84DBDE4AB66DAD60DB7630
- 9A9387818A1B79EBACF8B46B09C9EB1793BEDE86EA8D5654BACCA762DD5C2A56
- 9821FFC9948A4513A9B01A4B858521E5A643281CD283F4AEAA240A1E414D245E
- 7A2EA6A2F00A6579EEC80BB75199B59AF2274ED4242F85B70E7C081D4FAC656B
- 6EF590B83DD68C9CCD5F285D9A4391DD5B0A173EA1C8368E2782C721251B9CDA
- 4CC1BCD56C4CD5F77F78E0714C246B10B5827579FE71CA33DD294B71A534612D
- 25114B78E5D69BDCDD4D38BD63D62F92D4F04F3F515252FAA7311219C1F639B3
- 9EB25CC4A3CBFA7C76EFA864D3C60AB60B1E26F3F218A1BC93DC65334917FB8F
- 779A47BAF31C6A579B090ED329B79F44B9CD04CAE78EA6C26C04E55387526EA2
- 8B6CB43605DA5D49EFD88E4415456E3695787E7C01E59F7D29CDDD23B8ACA7E4
- F90AF222ED298EB1A2306C262997F489B35020BCAFC4CD71B3C9D9F09912BB6C
- 0A16BCE3EBBCA77C9D7B9FA7FA7EB8B713F1D16632335BCE62B2F2A6C29787FC
- 0621BBF2A228EF08059F9C297CBD9C82F8C5E487CEE1EB85F1E49CD6E5D1CE56
- 3CF31E7AAF6DF3BFF7D87F64111A764B725E796BDD32C7AF382E89E79755B96C
- DD2CAFE7B16B0798DA14A3D7561CBFFD10642E26BC5A6A4AF18A69B0623295B6
- E32817B1209BA18F6CD26064E3065066D89732FD5E94EA6A91DF539DF76A6D79
- 2578DC6A2691E4664ED9FBC3947C76A1FCEB728AE2ED2888B4A6347A3605A153
- 79153084C4058A84F6173C8C447CACC9A278412605966FF93AE7095F67DDE7C9
- 505FF6B5B3C649D184E92DCD58A4B5BBC66DC1BAD6AF12DD6E54951F42F675A1
- 888D19943E1C4BC9EF03F97A4C91C2234DB9EC204AFB55EBE8B58E0BFE258F88
- 88DFA4154ED79C96391662BFF8014ECB32D9B8BE82CD2EA2BEEC85D9569F91A4
- A358759CCF9EF1465C98A6C72BDB3E60DF0BE68A71DB5447249590411F2A8774
- A76C8006A57D3B53D24BE46C3735DEAB28F146A50DC1223E12B71953FC6A17C5
- 9F575096B988C2581117824559C4540A422690767110CFEDDA706780F00F6373
- B2576651649149DEECD77C99F698AFA6313C1EE2C3F6765638B436668AE0B16B
- 8C57AD669B01D2C6D5464EA2B0892DAD1126BCE22BE98BD2786A9D24CC2E82F8
- F5375F9C5FB9ABACBAAA4DDD9E9F3D7B2EDDB87143DABD7BF73FCD9767C9FC38
- 69E27316D9C6F293FD07D6ACAA107923FC635315EB561531CF22959E835FD346
- F9162D1A1E4051B263BC82113B7A681334A83DEF86364336B82968B7829E6DA1
- 9B0A7455A1B4A3329F94154912F111DCB4014FD68F242FF1178AB217539A6A4E
- 7EC40C8AA2A7501A664461C828B2AEE8F0C24E89DB223E6E4FB6256779168533
- 330587D77C9E94408EB1E8DDF5BCD9AE6CC9A2D6133169398313A33D6BC7771E
- D2BD45F32692F1883E83461BEA74339D325E61DC687D698A91A1E4BAE75729FE
- 79C6FF517F9A94543E7FCAA4146CACE3B05BFC81954EE5AC154C56AD94E1B24E
- F4EE1E70DE17D1BFD6B2668D9C19730AD01996825A9710149BED434D32C7401A
- 8863838E9C6EDD8C785589CF1D254AD47EA050A91929223EEE0A3F4DF8599BDC
- 078E22C72D287E39998270112FD1E328093510BD9E3E9F03FB916C2BEA8BF08F
- B06976B0B21CCCE56096C167E37832478793A0EBC5CEF656A2F710FED1622AD7
- C77956CC1C304EFBDFFE5DF9FD07A49A9ABF763D2FEE816CD694496FB1127EB5
- D0368D650EE5383B55887A538ED3D272962E2967FD6A39C70E547341CC78D7CF
- 8B8A297A48AF13B0612B58FC58CC08E36768F5BD8C92E236142433B4A5DE984B
- 6D7011297A5341C2BB9144E4CF22C71E5952F9652665CFC75314395AF0182178
- 0CA52C7C189FAE6AF3C4A61D09431AE139C808D71EE7F1D7B84672CF500A86C7
- 933D2A8C848127D8DD7E3E960A9358D4623AD1463E6506FDF47B7DDBB682504B
- A13AD76C26D4B44183068D1515151B686A6A4A55557FED7A5644448989E9E454
- CC67DF17319286C312394B7F2AC7B14E82C5921FCB71B09789DC91B1698D8899
- D562FDA59C9D1BE51CD95783AFE0E22F4AFFF1637236BB16B1D0E913C666B10C
- D2F7A453277BFA361C485B6934665ABADC3BD29BC212D11F7D1D206AAC585F8B
- 31E6E1706A1E8D24FD376D926CDA5234A1393F6B7617BE355068041A6DD712D9
- 3F84EA11B13C1C708C6D2AF39823FC63450B731E8DF72BD2EBADDB53ECBDA1D8
- BB521D13B1B6AAE3D1B469D3464252BF7EFD24030303492EFFF7D7B1E415B552
- 6C4CF1E869A6EF98392D0ECBB96982891C5BEB7216D9C8586CFB87162E90B164
- B18C654BFE90D34F32563A08399689AF4B586E5788B343019B56177160670947
- 0F9670F0601E5B76A5B378752253C48C3F6CC82E7407D9606C3A4E78555F0E2D
- EBC4FD031D29BCDD1D12FB93E92DEAD18F4DB92DE61D1D8529B456DE84468F83
- FCD07B1F7EFD450F37289AB8FEC77051B1C0BAF5781C9B9B1131E644DEA0EE62
- 8A14FB171CDA8BB5AD90625D9C08164D9B3717C62258356EDCF82FDE3F86F4F4
- 69C5F0C92629984E89C16CE6272191B2332B9833AB0C0BF332E699CBEA656921
- 13395586F53C190B2C65D85A09CD2F659175A1502E8BADB3853EB1D02A8D0516
- 29589BBFC66EC15BD638A5B36DC34736AC4B15F99884D1A8DFD1E97F8A9E3D37
- A2AD6986D1A0812CD26FCB16D1AF2F1DAC4827D18F77E874869EDD4FA0ACEA48
- 53354702FB0609BF8E244EFB189B542D58DA6A0CB39B9BE26BE8FE7564B741FD
- C59E5B0B751052116A27D4A68E8B6054973B0D5C5D5DEBEFA3BD7AF5AAC88708
- 293B3BBB7EFEFDA7F79764D7F4EAD7379ADE3D8F3151F8D6D429854C995CC4E4
- 493562453CAEC674AA8C6953CB982E34C354685A9988A712CCA617327B7A2EB3
- 67643367C647CC67A609A508BDC4DC2C59AC89CC327D80E9C418264F88619AC9
- 032C66460B66312C14E570FACC28748707A0D97B331A9A963457DA8E72A70B74
- 5477A68DE2649454C6D2B68B05B7BADFA646F84878BF23AC559DC3D296E3306E
- 361DE7510773F4BBE9F4FBC6A0B3D8BFBA90EAB758511471D1B051A34652FFFE
- FD256565E57A93A9F3127D7DFD7FDA7FD4DF4B5143C3E39E6F57188E3C12D3A7
- D7D9AA0E6AB174EE182D623B9971E3D2319EF01923A3528CC6D508C184F15542
- A5188F2F60A2D1174C2664097D144A65D284374C327EC164E3A762FF8F851E0A
- C532756234A62651824B18538CAF6232FE06C663C219671886E1F030060DBA82
- B6CE3934BA9EA565CBC5288A7E4B55652AED3B0CA36DB7D9DCD4FC9DCA2EB789
- EDED818B9A250E8D8763DB7A11FBE604CA7A76EADAF55B6C74131CBA08751252
- ABCB19C1A299508B6F1EDBF41FD4E4BFBD0757562D656494488F13B23A7A7BBF
- 9FBBD4F1B1D7A85177DF6874FD0D95F6C174D378C890C16F186598C668C34F18
- 8ECCC7D0A04448AC23B31865902AF44AE8B950925002A3463E108A65B44124A3
- 4786887D0733D6309089E3BC852E3261CC1DC68FBAC5A8E157E8D5E3049D3A9C
- A05D5B175AB79E8172BBF98287252AEA2350D69A4790D61DE8124942CFC3EC69
- 3999ABEA0BB93ED34B3E718485A31849EA4E7C9DA776171C34C5AAF12D5FFECC
- 21F1FD36828B8250AB6F35A8BE0EFD773CCACA2AFFE17B7229F76BB1141B9B3D
- 70B7EBEB157366C7DDE8D3FBF73C55951B82CF0DBA748E40776002FAC3121836
- F42943F5DE0AA5D7AF43F49E08767142D142E14277D11B748B41FD83183CE83C
- 2387793066A427630C4E337AC429F1F818DA7DF6A1D9F528AAED77A2A8309FF6
- CA735153B541B5D374BA682DE6A45600316A8779A4B185744377CE4CD97047B7
- 573F836FE75D47A82E67EAEA6E1FB1F73A068DEA3C56EC5FB161C3862DFFB7F8
- 68FC4D3FD4FDCC5FBF7FFDEFAF79A5A57D968283D35AF9F9A64D747048DC633C
- 21E48146D773828D2F0AAD8FA3A9E1457F1D7F060DB8C200511B07E824D05F3B
- 49E83E3AFD82D1EE775DAC37D0EE1B40FFBE47059B930CD13DCE505D0F06E978
- D043F380E0E18D9ACA76912B7351113D6807B53974509F4D3F9DF535360397F9
- AFE96676E3D2D055CF9C0CAD368ADD297F3BF77A4203BF31A9F355ADBA3CD0D0
- D090ECECECA4E1C387FFD993E9E8E8488255FDD7898989929F9FDFFFF57BAC72
- F9DF7ABBA74FBE88782A95E2E2323536AC4FB0B6B78BF2D5EEEBFDA1558B2DB4
- 6CFE0B8AAD5788F859439FDEBBE8D3EBA8F0E9BA7CB85BAFDE3D7F130A105FFB
- 89D55FC88FEE9AA7E9D2C99B6EC23B3AA86C153E6A2EE2C49A8E1DCC515733C1
- 60B81BADB5FACFA8EBB01AB56A5A17079D847485F4BFF118FC6DAD63D2AA4993
- 26D283077FBCBF5C5757162E5C281D3E7CB8FEF1EBD7AFA5C18307D7F7AA7FA5
- 1FF94BF78C1457FED9BB4446A64BA9695FA4FBF7321ADCBE9531DC6149CC06A3
- F167C37AF7DA56D1BC990D0DA46928B432177C7E44B3DB6A2157B4BA1D454BE3
- A288A940C1E0121A9DCF8958F012EB693AAAED103CAC44AE58D04E69AAF85927
- 51D38EC93AAA7737127BED2D344CC8E09B0C85467D5BEB7828ABA9A9D57DBEC9
- BF3CFE828202293737570A0909F9AED7F6B23265E239D3A557AFBE0ADE7FE457
- 6969A59492922705DF4957DDB8EEE11CCB7941C7F5871D78D54E6981E835C708
- 0DA169E3C122CF4CE9A4BE14F50E9BE9A0EA869292BBA8695E224E560B3F3516
- 31668AEE808DA28E6D08EBD6AD8FD1B7733F5668F83716238406D579A8906A9D
- 3FF4ECD953CACACAFACBC79F9999F93FF33B81B57F70F9733E8ACB965C77C5F5
- DFBCE99EA3DD8F972FF4EBEB90D95070116540A80B8D7FE82B6AAC9E60F123ED
- DB398A1AE32072647FD970FDF95B5BB56A54B7DF3EDF18A80B0F68A6A4A4D4AA
- AE869A989834F0F2F29256AD5A25999B9B4B2FFFE2FBE7FFAF959A9A2FFCE66F
- B95A545CDD24262663F4962DBF6F9D3C694F54A78E569592D49E869231FA7A67
- 19A1BFEA4E8FEEFD867DAB01755E51D74BD4F5DDA2DEC5D6F752F3E7CFFFFFF6
- F704F3F2CAFEDB7F2B2D45785F8EFAD9B30F2CAC2C0FBB0F196CBEB065CBBFCD
- E9C6C6C6527474B4A4A5A555FFF8EEDDBBF57EB862C58AEF726CFF0518F8A521
+ 1848B7AEC57D8F6DC5FD4F981176A0C70326B8EBFFBAFB0AB02AB6EEFDB11BC4
+ 006CEC2E6C05131103031504030CB031AF89AD58784D0C5014111B0BC4A04301
+ 4114EC00452594AE030781F7BFD7D1CD1DCF05C47BF1F77DDF7F9E673D733867
+ CECCEC77BF6BAD77AD3D407D7F2CB9120B1F48F0402A854F1A8B1FC9525C66DA
+ F2548C14873E6463CBEB2CFCF14402D3F01C0C768C401FCB075063FC505E1780
+ B084FC3EBBDD574D54DBDDF8E1A023133EDDBC1730ABA4F71CEBFC74F8ED962B
+ A39C9B2F8CFAE4FD687269E692C8775F175F734A45F0BD64191EAF5FE6E369F8
+ 373C3CFD81B106812853C5F21B1E8D8F41A9F14154AD7B10D594DDB1C831069E
+ 8C1FF7B3A5704FCD860BCB2DE7E2B2611B9D05AB771258BC60DC782CC114A6A7
+ 0638BE465F191E0168B9ED75A675B0C7C915574D50F95C630836020463652CDF
+ B3C3291B392A323FCA2F5E7F4BA213CBA74444952BEDDC6A732A6EAEFB9D7404
+ FB27E1D18354BC62DA303C2C0F0181803BD344E3F41F303CB6A36683FD506A74
+ 94D95E5451DE872A4A6E58703C0677191E3E2C9EDE4EC9C6B544966BE324B0FE
+ 948EAD11E958F62C1DA60FD3303E38131AA75F42637B309A6D0A84C2AA7B5F2D
+ EE9C64974FC367A4C0E8A539044786C908013D1668253B3D7131FAD97DE76549
+ 596D9B57EA5AE38253BCB1F3F57404F92621342805CF1837421FE6C18F71E38E
+ 37E141FCD8C1F038849AF56DA0A462832AB58FB118E286B9C73FC195F98B07C3
+ C32559824BF1D938C9F0D8CFF0D8C8F0307F968A690F53302228157DED9F333C
+ 881F81A8BEDC13CE2F5F820A926466D90CD3135FAEA2D19DD61056305CC697C3
+ 9AFD1BED3321A9F17F5D9F3D08C9D0BB7C310501DE29080948C513163B4282F3
+ E0CBB871DB93E131290842B9E35050B80BC53A57A050FF142A55BB8A8AC23318
+ FF2985173B492864F21957582C3EF199E5958FE9B0789B8E794F5361149202AD
+ 8014F46278F4DF1E24C34361A51FAE443E65DF7A86173941782CF563B8C4210C
+ AF61F8621684C30C93D102BA4DEDFEC9E7A1F728BACF0C64C872D1EFC6C3D32F
+ 45E7FAD514DCF34CC6837BA9080FCD4370501EBCBDF371DB03309814C9F0580B
+ A1E530C6E7DE1016F682606600A1D77234596E83850FFDB0FFF91B9CF8980287
+ 04E014336B969F36C7030BDEB3FCF4341F831E64A1B7C31B0CB20A41B32DC1A8
+ B6CA17275F07408A47789E1388470C0FFFEC3B78961F84187CC2A1CFB6A8EFCC
+ E28A1EC3455DC0062B8BC39FF0519683E233E30569BEF4B7E111FE3C7BD08573
+ C9F0734F42901F8BA921F9080AC883A7673E5CEF0003B55FA39FC9326CF130C3
+ F83F0DD1FBB40E9A3A7742A5033521FC51168251050886CA2C1EAA4365F14474
+ B1598BC157ED30EA862746B93C87CEEDCFE8E993037587240CDA1E05B5D5E14C
+ 8F79E1D86B7FC4E33E1E4ABD112265F957EA0EEFAC1B70CBBC84574CD578A4B9
+ 638CF778D9DF6A159A08E83BBAFB6BEF47EE83E89E991F09F9F83D7DB1F4F4BC
+ DE674E27C187D54A813EC9087D908F807B797073CB87CB4DA06DBF5098EF3CC5
+ 0E4D406AF22744BC0FC5FDC72EB8E27602079DB762E96586D3795D74DFD91DF5
+ 163741B9F50A10D65664E3A8066141235458D00D558C7551758A291A996D456D
+ A3D3A83AFD2E8E44DF67758F0FC3C0157ED9B798B9C05B721577D3CF338D7F0C
+ 77B3CE2230CF03EB1FAE43DDCDF521B41150514D80A5CDE69D0539E6ABA4D4F1
+ 087C90DEE5BC6312BC6F27E3BE7712821937FC7DF370E7763E6EB8005D34DE60
+ A2C54124B1C8199AEA8ED0E4DB084FBCCB3CDD0791B8C7A2A127C2B3AEE35EF2
+ 69DC78BF1F76411B60E96A8E79E70C31EAD840F4DADA11ADCC94A13057403536
+ D7358DC6A3CE8C907CFDEBFB7031693F2BEB3D7133DB09B72417713BC3113753
+ 4FE15A920D1CBFEC6531761B9CA5763812B907030E0F84308071A5B680A1C65A
+ 8FC3A3C265F5717E7EE9F264D3B64F6D9D583CF5BA9D083F8F0404FAE7C1C72B
+ 0FAEAE79B8C6EA6DF57E9118BDF2106259F11D12EF86801817F8C75C814FFA25
+ 7848D8FD271FC695CFBB70217A23CE45ADC6F9C855707A6301FB472BB1E9EE2C
+ CC3F6380FEF6BDA064A900A5C90C8F0983506BFEBDFC030F1F98EFF35FEDB428
+ 64092EE3022EE73AE07CCA515C48B6C6B9F87D381DB70B36319B6115B90C07E2
+ 5660EFC7F518736E0C9467A84068C070E921C0C6F3D8D2D2E6C7D90B896AE7CF
+ A6E0F6B578F8B8C5E29E4F1EBCDCF3E07C230F57AE013DFABDC7D0857F2282DD
+ 7560FC1D56875D8377EC2578492EE0AEE4345C520EC3E9CB2E9CFDB80127DFFC
+ 81234FE6E350B029367AE863EAA581D03ADE058D0ED583C2E29A50312CCF30E9
+ C362CD0544E4A029BEE6089B6F6DB71AEF3A1E96F11B609F7B1847BF58E258EC
+ 161CF9B41E073FACC29F91CBB1F98929CC427431F5F1180C751C8C561B5B4298
+ 2060F671538F3C164772F34BAF77FA383CA5B6837D52E625C738DC768E868F47
+ 2EDCEF306E5CCDC36527A0B7461434E65AB1CCE800FF385778BD67BC883B8F3B
+ 52475CCFB4C5A5E4BD70FCBC15761F57E3C81B73EC7F6286BDC1D3B1CE63228C
+ 181E034E7442A3FDF55173891254A75586D2947EA864721E2E3192B1197C4E42
+ 2F0E1F77795CECE4E009D896BB1A6B72176043D2026CFDB80096AFE760658811
+ 0CBCB5A171B51BDA1C6B01F5131DD07C77237C48FAD046E633A5185B636273AA
+ DB1D4F487238118BCBE73EE1AE6B0EEEB8E6C2E9721ECE5F02FAB19AB6FBCC9D
+ F0CD3F8CEBD19770F52D8B1371A7E1F4D50E8E1907713299CD67DC5A1C885A0C
+ AB5766B00C9B86AD418658EEA68BF117FBA0D789D6A87750193597111E95A064
+ D81B8D8DCF61555CD6C875A433F14D537CC94911E6FB2ED939E1D2883C4BA765
+ 58E96182F94FF460F66E14F45EF4428FA016687449052D191EF4F79FE79E9977
+ F537E5DC0AA74F25C6D91CFA8433A7A2E0723D0BB75C7271E1422E1CCFB17CDB
+ 3F0E1D0C2D7146B28DD5AC76B07E7108B6714760976B8DC3E93BB02FD102BB62
+ 96604BA429D6BD9882558F2660C5BD31987B6728465C504767BBA6A87BA83694
+ 96D786CA94B2A8A9DF19158DCEB23C82917FAD4F327B867A6FF7FBAD39AF6195
+ 77517D054E68CDC5A9A9DBB07BE5522CDA3E01A3F7F644D3DD2AA8F26745A8EE
+ AB2F89437A597CC916A46F534B158FB8B808E1945DDCFB2307E2607F3C12572F
+ 4BE07C2D17671D73E1E0080CD18C47EBC9EB60877538147302BB9EEDC1EE382B
+ 587DDD09CBB475589FB018AB3ECDC2D2B74658F0742C663FD081A9B716A6BA68
+ 62C8B90E6867D710750E29A1D6B2EF784C6C837A4B3C71C42B7C94878B93207D
+ 9FD9C847FFA8B343939538AFB012979AACC1B10EF3E0D591C5EF56FE78A8E68E
+ 476AB711DC82E5A04EC7B0A9E73CEC1FB822F3DDEAFB07A266DF5DF96197CBC8
+ FCBCEC52ABEB3A761C20FC69F5FAE519BB4C9CB47907A78B128609C3C2FE2B4E
+ 9D667A5D2B11D534AC6010B9184BE26DB12CFA2876C21A3BB01B6BA42BB124C1
+ 0CB33F4C82C92B5D18856941FFBE06C6BBF586EEB56ED038D31AADEDEAA3CE41
+ C2A30E548DCBA1E6F866509EE70C8767B1A39EBF782A7CF18958F068DB09BC3D
+ E28BE85D110833BB83E051B7F0409DE5B27A4E70AF7A0637CBDAC255B0856FF9
+ D37857E32A9E0B27E02698E346F52938D2D80CF14F12BB94161E878FBE126C8F
+ C53C3AF467344E1C8DC2A573AC2E3BF7157627BEE2B81D30715A0AAA0B17A05B
+ 5915A66D2BC07044338CDE3E10C3C30D3028672AB43119A3300163927430EAB5
+ 2686DDEF062DD74EE87FB10DBADA3741F3E32AA8B34F09B5972B437526E3879E
+ 0A54A65EC3999CA491B46E2FBD976496FB3212F8F2BD41FD8C998F14A917A311
+ BBEF295EACF0C1C3E92EB8A9638BD3DD36E2A2DA5CD83734C2F91626B0521D06
+ CDCA4B90FF117D4B2D9EC680E1117D6FE7D6F7B0B18EC03987749C75F80ADB63
+ 521CB5053447A76278F33DF8B0D600D7C60EC79636CD3046B11A7A5617D0A699
+ 00B521021A2F2C8FC64795D0E46E7DA83D6C02B5D06668EADD0C4DAE36440307
+ 65D43EACC46AB85AA8B2AA3C2A4FEE0C05C6012F69DEB03CE40A195E9F66A6B8
+ 0621DB33115F6F4920754EC5D7EBA9C8BB9A86FC2B69C05596852E4800DB04E4
+ ED7F8B57C31DE0546F3636A94EC2824AC331A9D92E581A1F520F0E0B2CB51872
+ DCE693DB9675AF71E4C05B9CB64BC3E9935F71E4700EAC8F007D07C560588F63
+ 6CFEAE23EBD37D443E7441B8F329F8EDD90657D3F9B01B38069B5A76C134D5BA
+ E857AF0CBAB615D09161D4DA4480EAEAB250B0AAC4485815653794439B91D5A1
+ A2BE05C2FC470800FAC8AE1F9E362CC7E905E0C9D071C981F4422AB2CF2421EB
+ 443C2487E290651503C9D60FC858F70AD99B9FE3D3906BB0A93C0333AAE9608E
+ 821E36691E4347A16BF7817D357ED4999B3609C3870F1722222284EEDDBB0BE6
+ E6E6426EEECF750AADB13AD8275F5BBFEA2D0EED8DC08963E9B0B3F98A83FB73
+ B0FF00A0A1F30523DB1E42AEFB6EA4B19A25FDE65164DD61C4F1B507C258420E
+ 6722C5E70CD21D0FE2F98635B86B608293BD86C2B27907FCD1A83E4C9B2B6250
+ F76A306D53198E8280C5CA6A98A83511CECBF51F873AEFB2B86977CCC677D15E
+ 441F7883DC33EC8ED8297116F87A4C828C5D1F90B9F513241B3E207DD54B64AE
+ 0CC3AB018ED8AF608CD98ABA30637858F4DA8FA1C290EE33A698301D02E1E225
+ 2761ADC58642FFB7DA8BE7CF4BC48FEBD732CE2D5FF4167B77BFC1D1431938C6
+ B8B1774F36ACFE64FE323215E35A1F83E4CA06C43A5B23F6D25E7C3C6F85F4F3
+ DB01C7F5C83DBE1C38BA18B05906D8AD024EAE058EAF41AAE542449B18E0E1E0
+ E1F069D11DDE556AC1736A27B82C6F05B7BE02AEB09AF5CC600127470B70D4AB
+ 02A7A9AD7175F2685C315D8B07E6E721D9F401D2AD89C8B0888264D53BA42F79
+ 8ECC258F10A6790A7B142663A1E25898288CC1F26ED68C1FDD3B5CBB7B53781E
+ 16201BB78282A2D0BC894A458D2E2D55C668746B3DB147BBA133F546F7F0BE77
+ 5F888A7A5F2C168989B9C28913A927979ABFC136C6C7BD5669B03E9083DD3BA5
+ D8B1331F1ABAD918DBFC38728ECE47CC894D883ABC0E51D66B2039BA12F9B67F
+ 20C77A0972F6CC43CEB69990AE358274991EF216E90233B58011DD90D4A32D1E
+ B6AC8FAB8C1B6F2F6D401EDEE2FD7D5B049D5806B75DE3E1B1B0273C27378697
+ 5E05DCD51470B0BB002B86939FDE0CE4ADCE45E6EA8FC85C1A89B4054F913E3F
+ 048F35EC61A5380D8B6A8E86A1C238E8D45D996F3DE95463C9ABBB831E5C9979
+ D6FDE2348F0FC1168FA23D967D4ABBBD96258725885DCF4ABF3BB351BF9E72ED
+ 9E9A3AC5AF4D3E920816164947962E7A8695CB1F62FBD634ECFF3307DBB749B1
+ 655B3E068C9542ABE17148B61B2376CF12BCDCB200519BE7E0EB36537CDD351B
+ 393BCC20DD600CE94A4348978C8774DE2848CD7490653400299AED11D5BC1E1E
+ A8D4C4F532025ED8CC6597F460E624738CACEC9378FFD40AC14E4BE0BED7103E
+ 0BD4116C580B37C70870193A04C9AB580C59168B8C856F9136271C69664108EF
+ 7B0AFB6B9A6011F39749352660685DCBF7A10EE75667BD3F8024A68F90E180B4
+ 7787901D698BCCE747F0D96D0982D73640E2C17AD06C5F5BBB86928AB073E74E
+ 595CC9C8C82864BD325F7070C8F8D364EA132C5E188CCD1B5361B533079B3666
+ 63D366406B62223494AD90B86A323E6E9B8DF0D53311B5DA18B96B2723C7620A
+ B2574D42F6223D48E7E8227BC630644F1E846C034D64E9F6404A8F96886AA282
+ 5086874B4501CF8FCD4476CA656426EE8734651372629623EBB139F2C2E7036F
+ E6E2BDFB10F81BD5C0CD96025C07E9216EFD1764CC8F43AAE91BA44C7F8C5493
+ 003C6678EC53328679CD91D0AF3E01BAF577BF0F3C749839AB0BF219D6594947
+ 9015BD1F99AF2D9111B212E95EB3F1C2AA0DE2B757C4C92DE3FF1084B205F144
+ 4949A9508E787B61F3C4F16158C8F868B13A09DBB7E460DDDA6C6C6678E81826
+ A26F9DAD885F300E516CFCC1E686885A3211F9CBF5180E639065361C59C64391
+ 356900B2F5FA226B544F64E9A84332A003923B34415483DA085556847325014F
+ 8F4C43D6E753C888DFC170598DF4A78B90E86D8634BFC948F11887D7177B23C0
+ 40019EED04380F9E80B8359F916E1A8BE4696F916018868449F711D6DB1EFB6B
+ 337ED41C8171D5C663449D7529CFF7D97785E4F2B3D4C48348FEB804292F1722
+ 39782692DC2722E1FC10C49D54C783ADD5F1C4B6E7BD5A557E8CB1F258B87BDC
+ 14962CBEB96AC1BC04CC9B1D8C3F96C563E37AA90C8F6D5B005DE33474AFC5EE
+ DFAC0724163A78315F17698B46038B4620C76430B2181724637B4332BC1B2483
+ 3B2353B31D327BB746867A7324B5AA8F77AAB5F082E171B3B2804756FAC87C77
+ 00E99F2D9095B010A9C1A648F69E8A0CDF0948761F85178E3D103A4D11EE9D18
+ 1E5A8C1F2B6290362D1AC9466F9030F13112C6DFC7E39EA7B0ABF654982BEA60
+ 4C353DCC68BE3DCF6ADAAA1A2F42ADAE7FCDDA0749C274C68DB1C8081A84F45B
+ 5D9070581129072BE1D25C96DAAF4CF55D396F5AB1787879DD1016995F355F30
+ 2F0566330361BE201A6B576763BD05CB2F3B8109933F4310AC31B9C114EC18A2
+ 85F3A3BBE385495BC0AC35308995DBBA1D995331D3688B9C1E2D90D9590D19ED
+ 1A21BD35F3D9A6AA78A7AC8457CA357187F123749336D25E6C43DAE745C88C9E
+ 81147FC60B8645A6D72824BB0D45E485AE786A5A13B73BB3F8A1AD8FD8C53148
+ 358846E28497F832FA211274FDF0B0871D36D79E8CB935B43192E1B16DA04D7E
+ B39A9D85B5CBB5CC596263435AC182F0A20444CD8844D8D4472CD8792178B5F3
+ B3738BB765E67EAD49637EF2E4A970FDFA7561FBF6ED85FACB9370CC1A3EEC29
+ 6698F8638ED97BAC5896CDFC86C58F755FB16A592A0C0D22D0AADB4BD4AC7313
+ 55CBEE81A2608A210A5AD8D2B2035CBAD6C5DB9E9521E95609E8501D68550B68
+ AA0C34514646833AF85847118F183FEE542A83C7ABFB2131F40FA4C6CE444684
+ 3E92BCC622D57724323CB490E2D61F31973BE299A9125C193F5C4798206E610C
+ 52C645331C5EE2F3F010C46933EDDEDD169BEB1861468D61D0A9361647071CCB
+ 1FD2A8478BAA552A0ADA7DDB761DA0D9B1A9EEC8210A8307F416466A690A963B
+ FE14829F7EFA257DFAE851D69491C35FC3786A004C67BEC762F32CAC64982C5B
+ 2C81C52AA6DD0F01E74E81E9D77CAC5821C5D889C9E8D8EB35541BBB41B1F22E
+ A80AFAD010BA605E99063859A3328255047C6E20205DB53C52942AE335E3C75D
+ 164F439676407CE03CE6E306487B3E02C99E8C2FBE8391EEAEC1B45E6F7C766A
+ 8F7013965F58FCF0186D0A2CCE02F4A580DE277CD60E46F4004F84A8DB606BDD
+ C94C7BB0F8517514AE0D3E963DAEF3E00E3FFDBFF2BBF7087979255BCF0B0894
+ 8C1F39FC0D26B37835DD24120BE66661897936CB3759309F9F85F9B3B3B07AB9
+ 1487F7E4E23CABF1AE9D63199369489BA3C09A8D80C1AC34F4D57E82E6ED2E41
+ 49711314043D7410DA405FA8090BE6A2CE0A026CCB09F05ECA7CEC811172BE8C
+ 43E6D32148F51EC0F0E8CBF0E8894CCF5EF878A5031E1BD746488F7238D6550B
+ 962DCFC141ED2AC25BB923B94F3062FB7B20A4CB516CAF3B05460AC331A3EA18
+ F86AD9656AB4EFDDFAFBB0159855634651B332B34A65CA94A9A0A8A858A659B3
+ 66C2D7AF255BCFF2F24AD7D11D1101FD09F71947223177B614F3E764611E19C3
+ 62F6AC2CCC359330DF9160DD0AC699E56CFF4716B6AE95E2E0AE3C9C62B838B0
+ D47FE4B014EB2D5331DDFC23B4F5FCD1B5F731346C68867665BBA09630007ACD
+ D571EF601BA4A4337D94D099E558B67FC9CA98A03EC87BD00F51373AE091712D
+ A40EAD82A5CD5AB0B8D585595FA8D55A09EF4E6EC8EDEB8FA0CE87B149D91013
+ 59FC5854551F0F86D8A7766FA3DE8A8DBD2C1BBB1261C2F6D5098F4A952A9563
+ 26B46FDF5ED0D0D010A4D29FAF6349B3F3057FBFB401A375DF62DCE800184D8A
+ 6498486132350B338C259869F2CDA64F9360F64C0916CCFE66E67324583C97D9
+ BC4CF63A1D0B4D53B0646E32D62D4FC59EADE9B0DE9B8EBD7B13B1615B14662E
+ 0FC54856E3F7EAB10DEA5D8DA1AD3B98C5AA76D8B7A021EEEF698014D7164068
+ 2744DBB27C34AB125C59BDD35161246AD45907B5967B51BECD2ED877621AAEAB
+ 2F023A1D8685B201A6D618827955F4E035F06862D716AC8A64E36738D465FB5A
+ CC1489270C8B4A55AAB0C0C2B0AA50A142099F1F83101696DD6784CE6BE88EF4
+ 83DEB88FCC98CB8ECBC6C4F19930D0CF84A1BE4466460612E65399986A28C134
+ 23094C26339B928119535398C563E6D458661F317D7224A619BCC654FD97309D
+ F6062BCCA3B069CD07AC5915C1FCF111B4FADF42C74E27D0AAD55A7468A607AD
+ AE5D30A3772D6C607A7D7E374534647ABC5EC3D368D5E228EAA8CC4325D57970
+ 6AE7C2E2B537023A1CC63A1503CCAF3E1013AAE8E294E6FE847E4DBB766263AE
+ C1AC1E336566B599D5245C1846E43B652C2D2D65CFD15EB97285F98397101B1B
+ 2BAB7F0B7DBE2436AF75FB76BE68D3EA3086B1B8356A640A468E48C588E1796C
+ 0FF6732E744749307A5426C6301BABCB6C7426E3533AF4C6A460C298784C181B
+ 8B89633F407F5C24B3D7CC9E435F2F9CED43315E3710BAC3FC3062A81F46EB04
+ C2609C2FC3CC0FD3593A1C33CE07EA7D1CD1ACCD7AA835334215A5CDA8D3F03C
+ 1AD45F829A8A23A0A43C08B51A1BE0660B57E4B138E2D9FE2056AA4CC4FC6A83
+ A15D790C96F4DF1BD7BB69C7F6DF3168C4C65F9F99CA77AE28325E942D57AE9C
+ D0A95327A14E9D3AB22043B1A477EFDE85EA0FD9B31479287BE4D89B459AFD0E
+ FAB56D7DE66B3D557F346AE0CBB81D8EC183A3A03DF433B4B432A035388F1930
+ 74C8576619D01E928C615A5FA0333486D9076611183EF415866B3FC308ED3036
+ FE87CC8298F963D4305FE8EAF8305C3C3052FB0A74865C87F6404F0CD6F48066
+ 1F0F74ED7A191D3A9E855A9333A8566D261499DE52511E85BAF57AA156D30970
+ 6E760B398D5DE1DFE6102C548D30B7421F98D498815D139D24AD1A3669F29D1B
+ 4D190E8D993564A64A3EC3B0A8CCACEAF7185B49CE2A16F90CAE2457F8F4295D
+ 781812D3C0D6F6DDA4F9F31EDAF4EF7FF7955A931B50AE7B074DD582D0A3DB2B
+ F4D78CC400CD8FD0EC97044D8D74666CDF2F06FD352298BD60F694D9236621E8
+ DF2F90993F06687863403F3736EE3B18A4E98461836D995DC0D081B731A4FF4D
+ F4EF7319AD5B1E45C37A4751BB96056AD4188B3AB5A7303C8CA05CBF2FEA3437
+ 844BF3DB40636F84B43A801DD546E04AFDE9B836CE463AACAFC13C5692D0C453
+ 4C6DC17068C6F66ADFFDA5C087D8FB35192E0ACCAA7FCF41B23C54141E999939
+ 72EF4985F88434C1DF3FB6CB76CB978B264E08B8DEB6CDAD4415E5EB0C9FEB68
+ DCC80BEA5D42D0BB57087AF50C43CFEE6F9845C9F63DBA3F66D80530F365E6C9
+ EC2EBA77BD89AE9D5CD0ADEB39F4EB750803FB1DC3408D9318D0F704FBF9303A
+ B4DD85664DACA152772B1415A6A06E9D49505531864AC33168DC7C268E377784
+ 9FEA013C50DB8028CDFD383D72CD6DF5D6ED35BECF7B4766E4339477DBB2B113
+ 06E528C6B2F12B962D5BB69A881F15BE5B793AA6E4CFAFFFB8E61519F959B873
+ 27B2BAFDA9C86173E786EED01EEA16A8D6E42CC3E614146A1C4133351B74EAE8
+ 80AE9D2FA333CB8D9D3B86A0538747CCEEA363FB3BE8D0FE1ADB5F4787768EE8
+ D4CE9A61731C3DD48FA0A7FA2174ED78082D9BED6178D842557933F395495066
+ 1AB49EEA44D4AB3F01ED3BAECE33EEB2C0614553BDEB177B2E7B62AE39792D1B
+ 5D9DEF73DF9D5997EF98505C6D4E7EA0A6A626989A9A0A7DFAF429D0641D3B76
+ 141856B2D7A1A1A182BDBDFD3FEEB14AA57F69BBB0C75F189F3284808068B535
+ AB43A69A99FA9CEAD0CEF67DF5AA1B50ADCA1F50ACB188F16705DAB6D986B6AD
+ AD599C267FB82BB336AD6E307364AFEDD9DE81993D5A343B89C60D6DD194C58E
+ 7ACA1B591CD5673C998A06F5F4515F55071A7DAC50A379A7B1A4B0CA55AF443C
+ 68C84C9D59EFEF7874FBBE274CAA57AC5851080CFCD65FA6BC327DFA74E1C081
+ 03B29F5FBE7C2974EBD64DA6554BA2474AF4CC485A4E8176F1F68E122222BF08
+ F7EF7D2AE37AF3539FB9B3FDD6680D39E3D1A6F5A6EC2A958D5146180D85EAFA
+ 0C9F5968D67439334B346F6A8DE66A1718A79C180617A1D6E82CE3820DDB9F44
+ 03D52D0C8FC9CC570C505B69143BD69CE5B4C39206F55B68B1B1B661D68B99C6
+ 77D364D6FFFB9EF0A8A3AAAA4A7FDFA4D8FB4F4E4E16E2E3E3053737B7525DDB
+ 8B8996B07346092F5E2430BCBFF95746468EF0FA75A270E77694CADA5541138D
+ 0C5D8EF4EEB5E7456DA5694C6B0E64D603952A74637EA68B86F5E7A37EBDF5A8
+ A7620525A5FD2CA7D9309E2C67F1549B714C17EA9DD7B23CB6C6A369D3B65ADF
+ E77E10B33EDFB1E8CBAC2BC550662A141F5AB56A25C4C4C494F8FEA3A3A3FF6F
+ 7E2730FF1B2E05F55140AC60B92DA0D3FA75F7E699CEBA74BE7DBBB9D165192E
+ 2C0D306B8C0AE5DBB11CDB9D61310B756BCF6339662EF391DD997D7A4FD958BD
+ 7A391A6FDBEF18D46731A0B292925275CAA13A3A3A656C6C6C8465CB9609FAFA
+ FAC2F312F6CFFFD3161191C4E2CD5FBE9A9A965BD1CFEFD3800D1B6E6D1C317C
+ 874FC306937304A12ECA0ADAE8DDFD0CFAF65E76BB658BF6BDBEE7008A15A425
+ 4877B37CE72FD35253A64CF99FFD3DC1C4C4CC223FCBC8008B7D71F5CF9C0934
+ 986C74607F8F6EFAD3AB55FBAB4ED7D6D6167C7D7D85E6CD9BCB7EBE7BF7AE2C
+ 1E2E5AB4A8947EF7290B6412890419EC66FE5B2D2D2DED6F76694A653CDB2920
+ E7261BCA5D0179B705249D15F0C24A80D76201170C04845CDC03162FFF664949
+ 4932A3D75FBE7C81A85FF83FB93D3CB51ABECBBF8D9FB020CBBC2620EA8880A0
+ B5029C6794C1799346253A17E171F5EA55FCAFE2214D4FC6F5E902DEEC13907B
+ EB1B16B48FB513106629C06D8180B3E305C4847995188F8B172F222424E47F92
+ 1BB756F4917120C3E92F6EA45E1410C124D6BD9502AE4E63FC58A651E2F3713C
+ DCDDDD4BFC1D969B4B6D3C2F65CFEEFFDA35F867899161B8692AE0A3CDB77841
+ 5850FC88B615F0688B803B73059C195F016971EF7E198F9B376FFEF0FE8D1B37
+ B074E952998D1A350A1B366C9019CBE9B27D696D741DF9B1D3CF666666857296
+ 8EE7D7779A514B36EEEC1B7F718362C8CB3D822C9E5C36121040EBE9BFB0111E
+ F4FF92E4F1A079A3FBA27B32343494BD26BB7DFBB6EC7EE87D3EB7F4BE979757
+ A1734AC7F073F1CFC5AFC5FC109F935F437C2C3F863E7339B20E9E2CAD7EB1FF
+ 31867E38CAF2C80641C61B470305D9FF3DE2E7105F9F5F5B7C4D8E87A3A3A30C
+ F7C236311EFC679A3B1A3F7187D582B2EF93D1CFE28DDEA36BF1F3F3E3F898E8
+ 33FA0E9D9B1F6B656525DBD3E7740DFA9E3C6674FD8B46E565B9549C5FE31D04
+ 59CE95E5577D01B70FAD2AE0139D9FF6742D7AEFF4E9D33F8C838F8FF3E357F0
+ E0E7A5F3D079694FDFA7738B794163E31C179BFC39FCFCFCFEE683F4335D57DE
+ 67E8E70326EAB25899725EC48D2B02DE1DFA2BBF9E99D2F0876BD075B90F725E
+ 883FE7E38B8B8BFB657E88CFE3E4E454306E31AFC5732FC642CC0F7E0EE218ED
+ C5BE459FD379E5710AF2F7928D97C6CEF32B7184F2EB93ED7FE55757FBBD0563
+ E2E7E1E72C6C1CB4CFC9C9C1870F1F64734CE32A2ADE89E789F38BF396739BBF
+ 96F7177A9FCF0FC788DF1BC5223E677CFE781CA2D7DC07F91868BB32AF2D82D7
+ FF3DBF92FEE0F9F5B499FA0F715A1C278A1B07695F8A3784075DFB776D9C1BFF
+ 768B7DE22BCBA1944F39163CBF520CE5F99534DAAF6CD9D9D932CD9F90908067
+ CF9EE1E8D1A3B0B3B3FB6D78703EFCDB8DF22B694E9E5FC5358ACFD26FF935E8
+ C4CA7F8C454C4C8CCC770F1C3820FB3BB9FFCDDBD36B7B657923FECCDF6B9407
+ EBFECAAFFF040BCA29E45B919191B87FFF3E76EDDA85BD7BF7FE762DFAAFB831
+ AD3C5EEDFD31BF92F6A0FC4A3A84F2EBBB7B574B7C3EAAE3E5B1A018427165CB
+ 962DD8B16347A15A8AE7845FD9E89CA5198FBCB64FC0FD35DFE226E706C553CA
+ 31F43ED57397E774F8C7BC88888890FDFDE8C78F1FCB62BC858505B66EDD5AA8
+ DF8B35C5EFE04A615A5DBCBD0D0B84F3AC3232BF90CFAFBC7E75182720E1EDA3
+ 12F19A78919A9A2AC382C62FC622303050F6FF80E97F10C9F383B8417996721D
+ D710949B68DE09237ACDF3A87CEEE07A868E13EB4DD25D94DB786DC4F7FC789E
+ 9BE9BA5CF752DF827207E92D717E25DFA1FC4A31748F41DB829C4D7BFE9A6B60
+ BA073AF7EEDDBB0BB0A0BF297EE9D2A582BC4F58F8FAFACA7A1FC40F718E17F3
+ 83D710FC73AE21C4355F51F9B528DDC5F596F8BEF9B15C3F9106586F364E36FF
+ C4058E05E516AA6743377D8BA1F663CBE3CC49DB82EBD126D638FC1A648405E9
+ 4FD25C1E1E1EB2B1CF9A350BF6F6F6F0F6F696CD17D5719B366D92E598A2F010
+ 6320C646AC694A130FCEADCBD3AACA34A7D45954A39CF931BF3A59CE2AD054FC
+ 3EF835F9FDF2FBA17C4A5890E6A2FC4178D0F76C6D6D65581047DCDCDC606969
+ F9B77CCB3522F705EE27FC5EC546C789FD955F9F9F83F0231FE0FEC27D8DC75D
+ B14EE4EF5DDB31BBC81E20E557D2ECC747572AB826F76B7E7DAE6FF9FC91BD7F
+ FF1EAF5EBD427878380C0C0C606E6E2EDB931FD1F569BE8827946F09A3C2629D
+ 789CF2AFE5EB67311EE2385CD839E58DF383E690F425E96EF91E20E557E28B87
+ F9B71A85F46A71719A6227F5899F3E7D5AC0738A9BF49AE686C64E7A837841EF
+ D371F7EEDD9371877CA834369A073E2FBFAAE939CF3C36EBCA3820AE51E835F5
+ 0029BF96A407486B048405E14BDA429C43286E921116840DBD4F3A9DFC887E3E
+ 78F0E06FAD5F4A9A77C9A8B7477192FA3AF2F995F70029BF16D7032C0C0BF205
+ C282384158D06B8E057D4E79978EA59F2976500FE4BF61BB32ABA16CDC142B78
+ 0CA53E07E5D79FF500F3F2F20AB0E03A8BE69DC64D5CE039846341FE4158102F
+ 28CE127EF433F1431E0F9E138AEAF7FE939AEE6735EE872067596CF87CEAEFF9
+ 95F7004F8E2E8F3D3BB6C8F2B158231486058F1B3C56702C882BF419C556E204
+ C78274097DAF287FE179B0B8785AD23821DF732A4C97527E955F63E3F955DC03
+ A439E27D5CFA1EC7826A54E23BCD37E510FABF25E2B8493FF3B849C71016F47D
+ C28170240D4FD890F6280E0FAE13786F4B9C27B9EEE19FC973806B597E8C3867
+ F36BD2FEF4A2C1C5AEB1518D727854D582F9E1F999DF078D89CE4B7961F1E2C5
+ 325D5558DCE4FE41B9578C05F582A8AEA1F7F6EDDB572C1EE27CC8C72BEE0772
+ 5DCE8F15CFB97C0F55AC13B83F6E5ABB52365ECA1F45D528945FE74E18F2031E
+ 743F349F741E1A3FE14358D09EB416F1A2B0B829F60FD2ACC42DC242E6B3EC33
+ C283FCB1283CB8D614D72AF2B51E9F7FF91A48AC39B9BEE731896343B569616B
+ 6CE21EE0F53F06FDD0B7E478D018E99CB48644FA8AC74D710E11FB078D97343B
+ F70FD228B9B9B97FC530F639E90F793CC4FA94EE5BEC1BBCA74AE3E763E27E50
+ 18A6BC9F4B7BEE271C5FBEC6463DBFE2D6D8C2023C65EB62F41D8A175CE3D2B8
+ A906E1B5081D43FA52ACB178DCE49CA0757CEE1F74AE1F62FA773C0AD36345C5
+ 4B796DC9E7ABA8D85AD43968BB38B5646B6CE2EBD1588817744DE202C5561E37
+ 09171E37B9C6E2FE41F196FB879813F2F745F3F66FF429AFDD7F758BF4395764
+ 0F907AE8BC07C8FBC33497C471E23BCFA73476C281E790C262857CCC94E7843C
+ 3FFE2D1EFF74BB3CA5BC8C073CBF522C955F637B7EC35A762CCD276141F34CE3
+ A47CCAB5B7180B7A9FFB87387F8863E6CF7432D577274F9EFC3FC5C26797D1DF
+ D6D8C43D40AA5F9D4C5B1560413C272C88FF34FF3C6E8A73088F9B944BC5FE21
+ 1F338BD5848C1F147FFEE97A03EF7F15A6BF0A5B9FA7F7485F16B5C626CEAFD4
+ 03E458D0BCD1BC13163C56F01CC26305F70FF227EAF788737B49B77F8BC7AFAE
+ 41D1FD9D36A8F3D335B65B1B46FE80055F5B1363C1E3268F15DC3F78AE2B2927
+ E4F1A0DE696178F0FEBBB867CAD71DC5EBF1E25EBC7C8F8EEBD9827514EF2BB2
+ 1C4A3509C782FA5F945FA907489FF11E20F19F9ED3E1CF9DCC9F3F5FD6F3E4EB
+ 2314C7ADADAD657B8A1BE41F14374827F0BE136125BE1732AE1D0B9B2F8E877C
+ 3FA8306D595CFF8F73931BD75EF27DA1CBC68A329FE03D409E5FA946E1F995D6
+ D8C80FE85AC403636363191ED4CBA23E30D59EC411D2A2FC9EE878CA1FB4262D
+ E626EFC588D7ADB91E2ACC97080F5A6B90C743BE9F591C1E625CE4D7C1C5EB94
+ 3F5B63A37505EA01523EA06BD178A95FB56EDD3A98989860CA9429B2B500DE0F
+ A76BD2FC734E72FF10F72BC5F7C5639D780DBBA47888D7D8B926A5EF73CDCAFB
+ A162CCF9F1DC9FF877694F1A82AFB1C9F700C56B6C964B8CE1EAEA2AF30BCA7B
+ C403FAFE9C3973649A7CC58A15057D1BBA36BD96AFC3F9B5C575B5F8591BDEF7
+ 2D6C4D99E3417C2C2CF6F15A8DF38FFB207F5643FCFC8E58A3F26B723FA5F848
+ B1B2A835368AA1174DDBCAE222F709FA3ECF21942FF8DCF2BCCBAFCDAF23AEA9
+ E59FCD11D73DFC1993C29E5DA35C4DEB95B4C65F5CEFE2DFF413A9B757D41A1B
+ 6975BEC646350ADD2F61C0B1A01C42B192EB6E5E9392A6284E67FED3AD2478C8
+ E3FDABDBF5F9AD64B983F700790C15AFB1396F185FA0BDE95A1437B8C612E752
+ 1E337FD74678D07A547178FC9B8D7A80255963F3F3BC5BA037090B8AD15C5790
+ 7F70CDFD3B38218F07C595C2F0288D757AF9E7ECC95FC4CFB0D073F6B4F624AE
+ C92856928FD3BD71FF2849EDF1BBF1F8B79B109B02212119755F4516F99C3D69
+ 55B1F6968F15E41FFF4467FED38DFA6C45E1C1FB9CF2BA94E757AE47F99EEB3E
+ 7ADDE3D25D088CE332235C223260ED652ACBAFA4C7A88F4EF9F5C0BAF9323D48
+ E7259DC1FB19840D6142E7E6EB89E29EAD3807F2DEEEAFAE0510CE64C43DF247
+ 8A5F749DA2E247513A4C7E3D5AFCEC203F46884FFE8605ED3FA6CAF0109E4950
+ 2930BDA046B19ED048A661A89F4D463A9CB0A0F352CCE4E3E76BC085E5399E4B
+ F9FC10A7C446B51D37BA37C2987C42BC6647F18A9EAFA4B56CFE3C7A69E2A11A
+ F0FA1B16CC5764DC789F0EE1452684B06C080FBEA2AC7F2EE6AC9A8E65738C65
+ 71937380EE47ACF139DF8AAB11C5FD7EFA8CC627FFBFD2896B64346EDE2F21DC
+ E978D23AA445E93561466BFB3FC3435E97F23E31E730AFED391E321CE2BF6311
+ 9506E1CD376E080FA5287B3F0F82673E0C5D5FC9F438DD276951DA739CC59A4E
+ FCEC6A61FC90EFCFD279E878EA1B92D1BCD3F949DBD2D8E9FBD4FBA2F1D2BA13
+ ED49EB514F955ED379C85F686E8AABD9C5BA54BCAEC2E7876B55D9F8090BCE89
+ A759DFEC3B3704DF6F78DC0B7B269B3B9A2FE22E8F99F27A915FA3281DC4D742
+ B8DF707CF97869ED80D663090FD2BC1C53BA36E571D2758405718670203C8823
+ 853D5B5C54AFA7D89C42DC204CD8F8890BADFC32A1E5F919F5D89E63B129EC5B
+ 5D4EF539698AD25C13E77894E4F9518E058D916A16CE0DC2A6347E5F4CE61F14
+ 3B1916FDFD530AFADF5C7BD3CFD7C2DFC9621AC5F3D2D6991C0FEE1B25C182E6
+ 85C70CC282D65D4AE3F709577C917EC383C588F391A905CF16500CA31C427193
+ 7405C52CAA757F87CE243C48CFFD0C0F8E05D75E1C0BEE0F85E151DCEFF814C9
+ 0D1633090B8E01E533E201EF5BD1FE77EA4CE21D5D9BB0280A0F8E05C50EE285
+ 3866107FE5FE3EDDDFD6554AF27B86BD3E64C96206C505C281EB87C2F4CFEFDC
+ 0873DE2F29EC79163116D467E4BC280C8BC2F010F759B8D610AF6DF35E0F6161
+ 1C9220E3EA7FEAF96EC29AF84F9CA67C2AAF538AC2828FB1B0BFD356DCF30E62
+ CD23FE9D1D7A9F3F8FF49FDC080FE207F59FA9374EF1BB2458D0F145FDDDBAE2
+ 9E7790EF93F175EEFF968DF0A079A15E23E55AD2A93FC3823457717FC7AF283C
+ 380FB896116BF3D27A9EAAB4F0204D4A6B118481388F8873EACF7851547EE17C
+ E0F592F8D91EAE8FFFD3CF25F28DF216DD27C551F217B1BE10E7D492F0E27FFD
+ EF19D0467D128A19549F528EE3BA53CC8BA2F2C8FF8F7890CE231D46FC252C08
+ 1BD2E0C5E98BFF9FF120DDC16B767A56415E77FE2A16FFCB7850BD4EE3A53A8E
+ D60AC4B18262895883FFCA46DF93EF1BF0DE01AF09285EF1BA996A1F32D23F64
+ 342F747D32EAB190913F53ED4D4679908CF21ED5E2BC2F463539E50432FEBB08
+ D41FA27E1919F513C988F3E40364346E1A331FB7FC9E8E2F69DCFC1926548B51
+ 5FF5DF6241F66FB0E0381487853C0EF47DBAF77FCA09F1F6FF004DFA3E53
}
end
object icons: TImageList
@@ -13757,6 +13895,12 @@ object MainForm: TMainForm
ImageIndex = 8
OnClick = btn_FileSearchClick
end
+ object menuShowReport: TMenuItem
+ Caption = 'Show Image &Report...'
+ Enabled = False
+ ImageIndex = 24
+ OnClick = btn_ShowReportClick
+ end
end
object FilesMenu: TMenuItem
Caption = '&Files'
diff --git a/LazarusSource/MainUnit.pas b/LazarusSource/MainUnit.pas
index 2a1ad4e..fe59807 100755
--- a/LazarusSource/MainUnit.pas
+++ b/LazarusSource/MainUnit.pas
@@ -35,7 +35,7 @@ interface
SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, DiscImage,
Global, DiscImageUtils, ExtCtrls, Buttons, ComCtrls, Menus, DateUtils,
ImgList, StrUtils, Clipbrd, HexDumpUnit, Spark, FPImage, IntfGraphics,
- ActnList, GraphType, DateTimePicker, Types;
+ ActnList, GraphType, DateTimePicker, Types, GJHRegistryClass;
type
//We need a custom TTreeNode, as we want to tag on some extra information
@@ -95,6 +95,7 @@ TMainForm = class(TForm)
menuFixADFS: TMenuItem;
menuDefrag: TMenuItem;
menuChangeInterleave: TMenuItem;
+ menuShowReport: TMenuItem;
OAAttrLabelAmiga: TLabel;
OthAttrLabelAmiga: TLabel;
MiscAttrLabelAmiga: TLabel;
@@ -109,6 +110,7 @@ TMainForm = class(TForm)
btn_AddPartition: TToolButton;
btn_ChangeInterleave: TToolButton;
btn_Defrag: TToolButton;
+ btn_ShowReport: TToolButton;
ToolsToolBar: TToolBar;
PartitionToolBar: TToolBar;
DuplicateFile1: TMenuItem;
@@ -269,6 +271,7 @@ TMainForm = class(TForm)
procedure btn_SaveAsCSVClick(Sender: TObject);
procedure btn_SavePartitionClick(Sender: TObject);
procedure btn_SettingsClick(Sender: TObject);
+ procedure btn_ShowReportClick(Sender: TObject);
procedure DuplicateFile1Click(Sender: TObject);
procedure ed_timestampEditingDone(Sender: TObject);
procedure HexDumpSubItemClick(Sender: TObject);
@@ -466,6 +469,8 @@ TMainForm = class(TForm)
//What are we running on?
platform,
arch :String;
+ //Registry
+ DIMReg :TGJHRegistry;
const
//These point to certain icons used when no filetype is found, or non-ADFS
//The numbers are indexes into the TImageList component 'FileImages'.
@@ -572,7 +577,8 @@ implementation
uses
AboutUnit,NewImageUnit,ImageDetailUnit,ProgressUnit,SearchUnit,
CustomDialogueUnit,ErrorLogUnit,SettingsUnit,ImportSelectorUnit,
- PWordEditorUnit,AFSPartitionUnit,ChangeInterleaveUnit;
+ PWordEditorUnit,AFSPartitionUnit,ChangeInterleaveUnit,CSVPrefUnit,
+ ImageReportUnit;
{------------------------------------------------------------------------------}
//Rescale the form
@@ -644,15 +650,17 @@ procedure TMainForm.AddDirectoryToImage(dirname: String);
fields : array of String;
Dir : TSearchRec;
begin
+ Image.ProgressIndicator:=nil;
+ ProgressForm.Show;
//First, if there is no selection, make one, or if multiple, select the root
- if (DirList.SelectionCount=0) OR (DirList.SelectionCount>1) then
+ if(DirList.SelectionCount=0)OR(DirList.SelectionCount>1)then
begin
DirList.ClearSelection;
DirList.Items[0].Selected:=True;
end;
OriginalNode:=DirList.Selected;
//If ADFS, create the directory, then select it
- if Image.FormatNumber>>4=diAcornADFS then
+ if Image.MajorFormatNumber=diAcornADFS then
begin
importname:=ExtractFilename(dirname);
attr :='DLR';
@@ -696,7 +704,10 @@ procedure TMainForm.AddDirectoryToImage(dirname: String);
if (Dir.Name<>'.') and (Dir.Name<>'..') then
begin
if (Dir.Attr AND faDirectory)=faDirectory then
- AddDirectoryToImage(dirname+pathdelim+Dir.Name)
+ begin
+ UpdateProgress('Adding '+Dir.Name);
+ AddDirectoryToImage(dirname+pathdelim+Dir.Name);
+ end
else
AddFileToImage(dirname+pathdelim+Dir.Name);
end;
@@ -751,13 +762,14 @@ procedure TMainForm.AddSparkToImage(filename: String);
ok:=True;
if((SparkFile.MaxDirEnt>47)and(Image.DirectoryType=diADFSOldDir))//Old dir
or((SparkFile.MaxDirEnt>77)and(Image.DirectoryType=diADFSNewDir))//New dir
- or(Image.FormatNumber>>4<>diAcornADFS) //Acorn ADFS
+ or(Image.MajorFormatNumber<>diAcornADFS) //Acorn ADFS
or(SparkFile.UncompressedSize>Image.FreeSpace(0))then //Not enough space
ok:=AskConfirm('The current open image is not suitable for this archive. '
+'Would you like to continue?','Yes','No','')=mrOK;
if ok then
begin
//Show the progress form
+ Image.ProgressIndicator:=@UpdateProgress;
ProgressForm.Show;
//Bypass the GUI if over a certain number of files
if Length(SparkFile.FileList)>bypassGUIThres then bypassGUI:=True;
@@ -789,7 +801,7 @@ procedure TMainForm.AddSparkToImage(filename: String);
//Update the attributes
filedetails.Attributes:=GetAttributes(
IntToHex(SparkFile.FileList[Index].Attributes,2),
- Image.FormatNumber>>4);
+ Image.MajorFormatNumber);
//Assign the parent directory (if bypassing the GUI)
if bypassGUI then
begin
@@ -945,7 +957,7 @@ function TMainForm.AddFileToImage(filename:String;filedetails: TDirEntry;
ReadInDirectory(DirList.Selected);
//Find out which side of a DFS disc it is
if (Image.DoubleSided)//FormatNumber mod 2=1)
- and(Image.FormatNumber>>4=diAcornDFS)then //Only for DFS double sided
+ and(Image.MajorFormatNumber=diAcornDFS)then //Only for DFS double sided
//As with DFS we can only Add with the root selected, the index will be the side
side:=DirList.Selected.Index
else
@@ -969,9 +981,9 @@ function TMainForm.AddFileToImage(filename:String;filedetails: TDirEntry;
//Does the filename contain the filetype?
if ((Pos(',',importfilename)>0)
or (Pos('.',importfilename)>0))
- and((Image.FormatNumber>>4=diAcornADFS) //ADFS
- or (Image.FormatNumber>>4=diCommodore) //Commodore
- or (Image.FormatNumber>>4=diSpark))then //!Spark
+ and((Image.MajorFormatNumber=diAcornADFS) //ADFS
+ or (Image.MajorFormatNumber=diCommodore) //Commodore
+ or (Image.MajorFormatNumber=diSpark))then //!Spark
begin
i:=Length(importfilename);
while (importfilename[i]<>'.')and(importfilename[i]<>',')do dec(i);
@@ -984,19 +996,19 @@ function TMainForm.AddFileToImage(filename:String;filedetails: TDirEntry;
if Copy(Extensions[index],4)=LowerCase(filetype) then
filetype:=LeftStr(Extensions[index],3);
//ADFS and Spark
- if(Image.FormatNumber>>4=diAcornADFS)
- or(Image.FormatNumber>>4=diSpark)then
+ if(Image.MajorFormatNumber=diAcornADFS)
+ or(Image.MajorFormatNumber=diSpark)then
begin
filetype:=IntToHex(StrToIntDef('$'+filetype,0),3);
if filetype='000' then filetype:='';//None, so reset
end;
end;
//ADFS, AFS, DFS, Spark & CFS only stuff
- if((Image.FormatNumber>>4=diAcornDFS)
- or(Image.FormatNumber>>4=diAcornADFS)
- or(Image.FormatNumber>>4=diAcornUEF)
- or(Image.FormatNumber>>4=diSpark)
- or(Image.FormatNumber>>4=diAcornFS))
+ if((Image.MajorFormatNumber=diAcornDFS)
+ or(Image.MajorFormatNumber=diAcornADFS)
+ or(Image.MajorFormatNumber=diAcornUEF)
+ or(Image.MajorFormatNumber=diSpark)
+ or(Image.MajorFormatNumber=diAcornFS))
and(filename<>'')then
begin
//Is there an inf file?
@@ -1032,18 +1044,18 @@ function TMainForm.AddFileToImage(filename:String;filedetails: TDirEntry;
attributes:=''; //Default
if attr1='' then
begin
- if(Image.FormatNumber>>4=diAcornADFS)
- or(Image.FormatNumber>>4=diSpark) then attributes:='WR';//Default for ADFS and Spark
- if Image.FormatNumber>>4=diCommodore then attributes:='C' ;//Default for Commodore
+ if(Image.MajorFormatNumber=diAcornADFS)
+ or(Image.MajorFormatNumber=diSpark) then attributes:='WR';//Default for ADFS and Spark
+ if Image.MajorFormatNumber=diCommodore then attributes:='C' ;//Default for Commodore
end;
- attributes:=attributes+GetAttributes(attr1,Image.FormatNumber>>4);
+ attributes:=attributes+GetAttributes(attr1,Image.MajorFormatNumber);
if importfilename='' then importfilename:='NewFile';
//Validate the filename (ADFS, AFS, DFS, Spark & CFS only)
- if(Image.FormatNumber>>4=diAcornDFS)
- or(Image.FormatNumber>>4=diAcornADFS)
- or(Image.FormatNumber>>4=diAcornUEF)
- or(Image.FormatNumber>>4=diSpark)
- or(Image.FormatNumber>>4=diAcornFS)then
+ if(Image.MajorFormatNumber=diAcornDFS)
+ or(Image.MajorFormatNumber=diAcornADFS)
+ or(Image.MajorFormatNumber=diAcornUEF)
+ or(Image.MajorFormatNumber=diSpark)
+ or(Image.MajorFormatNumber=diAcornFS)then
begin
//Remove any extraenous specifiers
while (importfilename[4]=Image.DirSep) do
@@ -1054,10 +1066,10 @@ function TMainForm.AddFileToImage(filename:String;filedetails: TDirEntry;
//Convert a Windows filename to a BBC filename
WinToBBC(importfilename);
//Check to make sure that a DFS directory hasn't been changed
- if((Image.FormatNumber>>4=diAcornDFS)
- or(Image.FormatNumber>>4=diAcornADFS)
- or(Image.FormatNumber>>4=diSpark)
- or(Image.FormatNumber>>4=diAcornFS))
+ if((Image.MajorFormatNumber=diAcornDFS)
+ or(Image.MajorFormatNumber=diAcornADFS)
+ or(Image.MajorFormatNumber=diSpark)
+ or(Image.MajorFormatNumber=diAcornFS))
and(importfilename[2]='/')then
importfilename[2]:=Image.DirSep;
//Remove any spaces, unless it is a big directory
@@ -1072,11 +1084,11 @@ function TMainForm.AddFileToImage(filename:String;filedetails: TDirEntry;
NewFile.Attributes :=attributes;
NewFile.DirRef :=-1; //Not a directory
NewFile.ShortFileType:=filetype;
- if(Image.FormatNumber>>4=diAcornADFS) //Need the selected directory for ADFS
- or(Image.FormatNumber>>4=diSpark) //And Spark
- or(Image.FormatNumber>>4=diAcornFS) //And Acorn FS
- or(Image.FormatNumber>>4=diAmiga) //And Amiga
- or(Image.FormatNumber>>4=diDOSPlus)then//And DOS Plus
+ if(Image.MajorFormatNumber=diAcornADFS) //Need the selected directory for ADFS
+ or(Image.MajorFormatNumber=diSpark) //And Spark
+ or(Image.MajorFormatNumber=diAcornFS) //And Acorn FS
+ or(Image.MajorFormatNumber=diAmiga) //And Amiga
+ or(Image.MajorFormatNumber=diDOSPlus)then//And DOS Plus
if(DirList.Selected.Text='$')
or(DirList.Selected.Text='AFS$')
or(DirList.Selected.Text='DF0:')
@@ -1085,13 +1097,13 @@ function TMainForm.AddFileToImage(filename:String;filedetails: TDirEntry;
else
NewFile.Parent :=GetImageFilename(TMyTreeNode(DirList.Selected).ParentDir,
DirList.Selected.Index);
- if Image.FormatNumber>>4=diAcornDFS then //We'll set up a parent for DFS
+ if Image.MajorFormatNumber=diAcornDFS then //We'll set up a parent for DFS
NewFile.Parent:=':'+IntToStr(side*2)+'.$';
//Set the length - the actual length overrides everything else
NewFile.Length:=Length(buffer);
//Does the file already exist?
ok:=True;
- if Image.FormatNumber>>4<>diAcornUEF then
+ if Image.MajorFormatNumber<>diAcornUEF then
if Image.FileExists(NewFile.Parent+Image.DirSep+NewFile.Filename,ref) then
begin
ok:=AskConfirm('"'+NewFile.Filename+'" already exists in the directory "'
@@ -1117,7 +1129,7 @@ function TMainForm.AddFileToImage(filename:String;filedetails: TDirEntry;
//Function returns pointer to next item (or parent if no children)
if Result>-1 then //File added OK
begin
- if Image.FormatNumber>>4<>diSpark then HasChanged:=True;
+ if Image.MajorFormatNumber<>diSpark then HasChanged:=True;
AddFileToTree(DirList.Selected,NewFile.Filename,Result,False,DirList,False);
UpdateImageInfo(side);
end
@@ -1390,11 +1402,11 @@ function TMainForm.GetWindowsFilename(dir,entry: Integer): String;
if (Image.Disc[dir].Entries[entry].ShortFileType<>'')
and(Image.Disc[dir].Entries[entry].DirRef=-1) then
begin
- if(Image.FormatNumber>>4=diAcornDFS)
- or(Image.FormatNumber>>4=diAcornADFS)
- or(Image.FormatNumber>>4=diAcornFS)then extsep:=','; //DFS, ADFS and AFS
- if(Image.FormatNumber>>4=diCommodore) //Commodore
- or(Image.FormatNumber>>4=diAmiga)then extsep:='.'; //Amiga
+ if(Image.MajorFormatNumber=diAcornDFS)
+ or(Image.MajorFormatNumber=diAcornADFS)
+ or(Image.MajorFormatNumber=diAcornFS)then extsep:=','; //DFS, ADFS and AFS
+ if(Image.MajorFormatNumber=diCommodore) //Commodore
+ or(Image.MajorFormatNumber=diAmiga)then extsep:='.'; //Amiga
Result:=Result+extsep+Image.Disc[dir].Entries[entry].ShortFileType;
end;
end;
@@ -1461,7 +1473,7 @@ procedure TMainForm.CreateINFFile(dir,entry: Integer; path: String;filename: Str
//Length of the hex numbers
hexlen:=8;
//6 for DFS (after discussion on Stardot forum)
- if Image.FormatNumber>>4=diAcornDFS then hexlen:=6;
+ if Image.MajorFormatNumber=diAcornDFS then hexlen:=6;
if DoCreateInf then
begin
imagefilename:=Image.Disc[dir].Entries[entry].Filename;
@@ -1470,7 +1482,7 @@ procedure TMainForm.CreateINFFile(dir,entry: Integer; path: String;filename: Str
else //Otherwise just use the supplied name
windowsfilename:=filename;
//Add the root, if DFS and no directory specifier
- if(Image.FormatNumber>>4=diAcornDFS)and(imagefilename[2]<>'.')then
+ if(Image.MajorFormatNumber=diAcornDFS)and(imagefilename[2]<>'.')then
imagefilename:=RightStr(Image.GetParent(dir),1)+'.'+imagefilename;
//Put quotes round the filename if it contains a space
if Pos(' ',imagefilename)>0 then imagefilename:='"'+imagefilename+'"';
@@ -1481,11 +1493,11 @@ procedure TMainForm.CreateINFFile(dir,entry: Integer; path: String;filename: Str
+IntToHex(Image.Disc[dir].Entries[entry].Length,hexlen);
//Create the attributes
attributes:=$00;
- if(Image.FormatNumber>>4=diAcornDFS)
- or(Image.FormatNumber>>4=diAcornUEF)then //DFS and CFS
+ if(Image.MajorFormatNumber=diAcornDFS)
+ or(Image.MajorFormatNumber=diAcornUEF)then //DFS and CFS
if Image.Disc[dir].Entries[entry].Attributes='L' then attributes:=$08;
- if(Image.FormatNumber>>4=diAcornADFS)
- or(Image.FormatNumber>>4=diAcornFS)then //ADFS and AFS
+ if(Image.MajorFormatNumber=diAcornADFS)
+ or(Image.MajorFormatNumber=diAcornFS)then //ADFS and AFS
for t:=0 to 7 do
if Pos(adfsattr[t+1],Image.Disc[dir].Entries[entry].Attributes)>0 then
inc(attributes,1<0 then
begin
btn_ImageDetails.Enabled:=True;
menuImageDetails.Enabled:=True;
end;
- if Image.FormatNumber>>4=diAcornADFS then
+ if Image.MajorFormatNumber=diAcornADFS then
begin
btn_FixADFS.Enabled:=True;
menuFixADFS.Enabled:=True;
@@ -1762,7 +1777,7 @@ procedure TMainForm.AddImageToTree(Tree: TTreeView;ImageToUse: TDiscImage);
until highdir=Length(ImageToUse.Disc);
TMyTreeNode(Tree.Items[0]).ParentDir:=-1;
//Expand the top level of the tree (but not MMB)
- if ImageToUse.FormatNumber>>4<>diMMFS then Tree.TopItem.Expand(False);
+ if ImageToUse.MajorFormatNumber<>diMMFS then Tree.TopItem.Expand(False);
//And the root for the other side of the disc
if ImageToUse.DoubleSided then
begin
@@ -1806,7 +1821,7 @@ procedure TMainForm.UpdateImageInfo(partition: Cardinal=0);
ImageDetails.Panels[4].Text:=ConvertToKMG(Image.FreeSpace(partition))
+' ('+IntToStrComma(Image.FreeSpace(partition))+' Bytes)';
//Double sided or not (DFS only)
- if Image.FormatNumber>>4=diAcornDFS then
+ if Image.MajorFormatNumber=diAcornDFS then
if Image.DoubleSided then
ImageDetails.Panels[5].Text:='Double Sided'
else
@@ -1885,8 +1900,8 @@ procedure ArrangeComponent(c,p: TControl;l: TLabel);
if(cbpos>0)and(attr)then
begin
//DFS and UEF
- if(Image.FormatNumber>>4=diAcornDFS)
- or(Image.FormatNumber>>4=diAcornUEF)then
+ if(Image.MajorFormatNumber=diAcornDFS)
+ or(Image.MajorFormatNumber=diAcornUEF)then
begin
//Make it visible
DFSAttrPanel.Visible:=True;
@@ -1901,8 +1916,8 @@ procedure ArrangeComponent(c,p: TControl;l: TLabel);
DFSAttrPanel.Height:=cb_DFS_l.Top+cb_DFS_l.Height;
end;
//ADFS and SparkFS
- if((Image.FormatNumber>>4=diAcornADFS)
- or(Image.FormatNumber>>4=diSpark))
+ if((Image.MajorFormatNumber=diAcornADFS)
+ or(Image.MajorFormatNumber=diSpark))
and(not afs)and(not dos)then
begin
//Make it visible
@@ -1935,13 +1950,13 @@ procedure ArrangeComponent(c,p: TControl;l: TLabel);
//And change the panel height to accomodate
ADFSAttrPanel.Height:=cb_ADFS_pubw.Top+cb_ADFS_pubw.Height;
//Show/hide those not applicable for new/old directories
- cb_ADFS_owne.Visible:=Image.FormatNumber mod $10<3;
+ cb_ADFS_owne.Visible:=Image.MinorFormatNumber<3;
cb_ADFS_pube.Visible:=cb_ADFS_owne.Visible;
cb_ADFS_pubp.Visible:=cb_ADFS_owne.Visible;
end;
//Acorn FS
- if(Image.FormatNumber>>4=diAcornFS)
- or((Image.FormatNumber>>4=diAcornADFS)and(afs))then
+ if(Image.MajorFormatNumber=diAcornFS)
+ or((Image.MajorFormatNumber=diAcornADFS)and(afs))then
begin
//Make it visible
AFSAttrPanel.Visible:=True;
@@ -1969,8 +1984,8 @@ procedure ArrangeComponent(c,p: TControl;l: TLabel);
AFSAttrPanel.Height:=cb_AFS_pubw.Top+cb_AFS_pubw.Height;
end;
//DOS Plus
- if(Image.FormatNumber>>4=diDOSPlus)
- or((Image.FormatNumber>>4=diAcornADFS)and(dos))then
+ if(Image.MajorFormatNumber=diDOSPlus)
+ or((Image.MajorFormatNumber=diAcornADFS)and(dos))then
begin
//Make it visible
DOSAttrPanel.Visible:=True;
@@ -1992,7 +2007,7 @@ procedure ArrangeComponent(c,p: TControl;l: TLabel);
DOSAttrPanel.Height:=cb_DOS_hidden.Top+cb_DOS_hidden.Height;
end;
//Commodore 64
- if Image.FormatNumber>>4=diCommodore then
+ if Image.MajorFormatNumber=diCommodore then
begin
//Make it visible
C64AttrPanel.Visible:=True;
@@ -2011,7 +2026,7 @@ procedure ArrangeComponent(c,p: TControl;l: TLabel);
C64AttrPanel.Height:=cb_C64_l.Top+cb_C64_l.Height;
end;
//Commodore Amiga
- if Image.FormatNumber>>4=diAmiga then
+ if Image.MajorFormatNumber=diAmiga then
begin
//Make it visible
AmigaAttrPanel.Visible:=True;
@@ -2082,9 +2097,9 @@ function TMainForm.FindPartitionRoot(filepath: String): Integer;
if Length(Image.Disc)>1 then //Definately another root present
begin
//Then extract the root part
- if(Pos('.',filepath)>0)and(Image.FormatNumber>>4<>diAcornDFS)then
+ if(Pos('.',filepath)>0)and(Image.MajorFormatNumber<>diAcornDFS)then
filepath:=LeftStr(filepath,Pos('.',filepath)-1);
- if(Pos('.',filepath)>3)and(Image.FormatNumber>>4=diAcornDFS)then
+ if(Pos('.',filepath)>3)and(Image.MajorFormatNumber=diAcornDFS)then
filepath:=LeftStr(filepath,Pos('.',filepath,3)-1);
//Then look to find the AFS root
Result:=0;
@@ -2147,16 +2162,16 @@ procedure TMainForm.DirListChange(Sender: TObject; Node: TTreeNode);
DuplicateFile1.Enabled :=btn_DuplicateFile.Enabled;
menuDuplicateFile.Enabled:=btn_DuplicateFile.Enabled;
//Delete and Save Partition
- afspart:=((Image.FormatNumber>>4=diAcornDFS)and(Image.DoubleSided)) //DFS DS
- or((Image.FormatNumber>>4=diAcornADFS)and(Image.AFSPresent)) //ADFS/AFS
- or((Image.FormatNumber>>4=diAcornADFS)and(Image.DOSPresent));//ADFS/DOS
+ afspart:=((Image.MajorFormatNumber=diAcornDFS)and(Image.DoubleSided)) //DFS DS
+ or((Image.MajorFormatNumber=diAcornADFS)and(Image.AFSPresent)) //ADFS/AFS
+ or((Image.MajorFormatNumber=diAcornADFS)and(Image.DOSPresent));//ADFS/DOS
//Show/Hide partition options
btn_DeletePartition.Enabled:=(afspart)and(DirList.SelectionCount=1);
menuDeletePartition.Enabled:=btn_DeletePartition.Enabled;
btn_SavePartition.Enabled :=(afspart)and(DirList.SelectionCount=1);
menuSavePartition.Enabled :=btn_SavePartition.Enabled;
//Check for 8 bit ADFS
- btn_AddPartition.Enabled :=(Image.FormatNumber>>4=diAcornADFS)
+ btn_AddPartition.Enabled :=(Image.MajorFormatNumber=diAcornADFS)
and(Image.DirectoryType=diADFSOldDir)
and(Image.MapType=diADFSOldMap)
and(not Image.AFSPresent)
@@ -2168,13 +2183,13 @@ procedure TMainForm.DirListChange(Sender: TObject; Node: TTreeNode);
//Change Interleave
btn_ChangeInterleave.Enabled:=(Image.FormatNumber=diAcornADFS<<4+2) //ADFS L
or(Image.FormatNumber=diAcornADFS<<4+$E)//ADFS Hybrid
- or(Image.FormatNumber>>4=diAcornFS) //Acorn FS
- or((Image.FormatNumber>>4=diAcornADFS) //Acorn ADFS
+ or(Image.MajorFormatNumber=diAcornFS) //Acorn FS
+ or((Image.MajorFormatNumber=diAcornADFS) //Acorn ADFS
and(Image.InterleaveMethod>0)); //with non-auto interleave
menuChangeInterleave.Enabled:=btn_ChangeInterleave.Enabled;
//Change the captions
temp:='Partition';
- if Image.FormatNumber>>4=diAcornDFS then temp:='Side';
+ if Image.MajorFormatNumber=diAcornDFS then temp:='Side';
btn_DeletePartition.Hint :='Delete '+temp;
menuDeletePartition.Caption:='&Delete '+temp;
btn_SavePartition.Hint :='Save '+temp+' As';
@@ -2206,11 +2221,11 @@ procedure TMainForm.DirListChange(Sender: TObject; Node: TTreeNode);
btn_Rename.Enabled :=True;
menuRenameFile.Enabled:=True;
//Enable the create directory button
- if(Image.FormatNumber>>4=diAcornADFS)
- OR(Image.FormatNumber>>4=diAmiga)
- or(Image.FormatNumber>>4=diAcornFS)
- or(Image.FormatNumber>>4=diSpark)
- or(Image.FormatNumber>>4=diDOSPlus)then //ADFS, Amiga, Acorn FS, Spark and DOS Plus
+ if(Image.MajorFormatNumber=diAcornADFS)
+ OR(Image.MajorFormatNumber=diAmiga)
+ or(Image.MajorFormatNumber=diAcornFS)
+ or(Image.MajorFormatNumber=diSpark)
+ or(Image.MajorFormatNumber=diDOSPlus)then //ADFS, Amiga, Acorn FS, Spark and DOS Plus
begin
NewDirectory1.Enabled :=True;
btn_NewDirectory.Enabled:=True;
@@ -2240,12 +2255,12 @@ procedure TMainForm.DirListChange(Sender: TObject; Node: TTreeNode);
dospart:=Image.Disc[dr].DOSPartition;
end;
//Enable the add/edit password buttons
- if(Image.FormatNumber>>4=diAcornFS)
- or((Image.FormatNumber>>4=diAcornADFS)and(Image.AFSPresent))then
+ if(Image.MajorFormatNumber=diAcornFS)
+ or((Image.MajorFormatNumber=diAcornADFS)and(Image.AFSPresent))then
begin
rt:=FindPartitionRoot(GetFilePath(DirList.Selections[0]));
//ADFS...find the AFS parent
- if(Image.FormatNumber>>4=diAcornADFS)and(rt=0)then rt:=-1;
+ if(Image.MajorFormatNumber=diAcornADFS)and(rt=0)then rt:=-1;
if rt>=0 then
begin
//Does the password file exist on the root?
@@ -2272,13 +2287,13 @@ procedure TMainForm.DirListChange(Sender: TObject; Node: TTreeNode);
//Attributes
DoNotUpdate :=True; //Make sure the event doesn't fire
//DFS and UEF
- if(Image.FormatNumber>>4=diAcornDFS)
- or(Image.FormatNumber>>4=diAcornUEF)then
+ if(Image.MajorFormatNumber=diAcornDFS)
+ or(Image.MajorFormatNumber=diAcornUEF)then
//Tick/untick it
cb_DFS_l.Checked:=Pos('L',Image.Disc[dir].Entries[entry].Attributes)>0;
//ADFS and SparkFS
- if((Image.FormatNumber>>4=diAcornADFS)
- or(Image.FormatNumber>>4=diSpark))
+ if((Image.MajorFormatNumber=diAcornADFS)
+ or(Image.MajorFormatNumber=diSpark))
and(not afspart)and(not dospart)then
begin
//Tick/untick them
@@ -2292,8 +2307,8 @@ procedure TMainForm.DirListChange(Sender: TObject; Node: TTreeNode);
cb_ADFS_pubp.Checked:=Pos('P',Image.Disc[dir].Entries[entry].Attributes)>0;
end;
//Acorn FS
- if(Image.FormatNumber>>4=diAcornFS)
- or((Image.FormatNumber>>4=diAcornADFS)
+ if(Image.MajorFormatNumber=diAcornFS)
+ or((Image.MajorFormatNumber=diAcornADFS)
and(afspart))then
begin
//Tick/untick them
@@ -2304,8 +2319,8 @@ procedure TMainForm.DirListChange(Sender: TObject; Node: TTreeNode);
cb_AFS_pubr.Checked:=Pos('r',Image.Disc[dir].Entries[entry].Attributes)>0;
end;
//DOS Plus
- if(Image.FormatNumber>>4=diDOSPlus)
- or((Image.FormatNumber>>4=diAcornADFS)
+ if(Image.MajorFormatNumber=diDOSPlus)
+ or((Image.MajorFormatNumber=diAcornADFS)
and(dospart))then
begin
//Tick/untick them
@@ -2315,14 +2330,14 @@ procedure TMainForm.DirListChange(Sender: TObject; Node: TTreeNode);
cb_DOS_archive.Checked:=Pos('A',Image.Disc[dir].Entries[entry].Attributes)>0;
end;
//Commodore 64
- if Image.FormatNumber>>4=diCommodore then
+ if Image.MajorFormatNumber=diCommodore then
begin
//Tick/untick them
cb_C64_l.Checked:=Pos('L',Image.Disc[dir].Entries[entry].Attributes)>0;
cb_C64_c.Checked:=Pos('C',Image.Disc[dir].Entries[entry].Attributes)>0;
end;
//Amiga
- if Image.FormatNumber>>4=diAmiga then
+ if Image.MajorFormatNumber=diAmiga then
begin
//Tick/untick them
cb_Amiga_ownw.Checked:=Pos('W',Image.Disc[dir].Entries[entry].Attributes)=0;
@@ -2428,7 +2443,7 @@ procedure TMainForm.DirListChange(Sender: TObject; Node: TTreeNode);
btn_NewDirectory.Enabled:=False;
menuNewDir.Enabled :=False;
//Filetype hints
- if Image.FormatNumber>>4=diDOSPlus then
+ if Image.MajorFormatNumber=diDOSPlus then
begin //Can't edit
img_Filetype.Hint:='';
lb_FileType.Hint :='';
@@ -2463,12 +2478,12 @@ procedure TMainForm.DirListChange(Sender: TObject; Node: TTreeNode);
FileImages.StretchDraw(img_FileType.Canvas,ft,R);
img_FileType.Tag:=ft; //To keep track of which image it is
//Filetype text - only show for certain systems
- if(Image.FormatNumber>>4=diAcornADFS) //ADFS
- or(Image.FormatNumber>>4=diCommodore) //C64
- or(Image.FormatNumber>>4=diAmiga) //AmigaDOS
- or(Image.FormatNumber>>4=diSpark) //Spark
- or(Image.FormatNumber>>4=diAcornFS) //Acorn FS
- or(Image.FormatNumber>>4=diDOSPlus)then//DOS Plus
+ if(Image.MajorFormatNumber=diAcornADFS) //ADFS
+ or(Image.MajorFormatNumber=diCommodore) //C64
+ or(Image.MajorFormatNumber=diAmiga) //AmigaDOS
+ or(Image.MajorFormatNumber=diSpark) //Spark
+ or(Image.MajorFormatNumber=diAcornFS) //Acorn FS
+ or(Image.MajorFormatNumber=diDOSPlus)then//DOS Plus
lb_FileType.Caption:=filetype;
location:=''; //Default location string
if dir>=0 then
@@ -2486,15 +2501,15 @@ procedure TMainForm.DirListChange(Sender: TObject; Node: TTreeNode);
lb_parent.Caption:=temp;
//Timestamp - ADFS, Spark, FileStore, Amiga and DOS only
if (Image.Disc[dir].Entries[entry].TimeStamp>0)
- and((Image.FormatNumber>>4=diAcornADFS)
- or (Image.FormatNumber>>4=diSpark)
- or (Image.FormatNumber>>4=diAcornFS)
- or (Image.FormatNumber>>4=diAmiga)
- or (Image.FormatNumber>>4=diDOSPlus))then
+ and((Image.MajorFormatNumber=diAcornADFS)
+ or (Image.MajorFormatNumber=diSpark)
+ or (Image.MajorFormatNumber=diAcornFS)
+ or (Image.MajorFormatNumber=diAmiga)
+ or (Image.MajorFormatNumber=diDOSPlus))then
lb_timestamp.Caption:=FormatDateTime(TimeDateFormat,
Image.Disc[dir].Entries[entry].TimeStamp);
if(Image.Disc[dir].Entries[entry].TimeStamp=0)
- or(Image.FormatNumber>>4=diAcornFS)then
+ or(Image.MajorFormatNumber=diAcornFS)then
if Image.Disc[dir].Entries[entry].DirRef=-1 then
begin
//Load address
@@ -2517,7 +2532,7 @@ procedure TMainForm.DirListChange(Sender: TObject; Node: TTreeNode);
//Location of object - varies between formats
//ADFS Old map and Acorn FS - Sector is an offset
if(Image.MapType=diADFSOldMap)
- or(Image.FormatNumber>>4=diAcornFS)then
+ or(Image.MajorFormatNumber=diAcornFS)then
location:='Sector offset: 0x'
+IntToHex(Image.Disc[dir].Entries[entry].Sector,8)+' ';
//ADFS New map - Sector is an indirect address (fragment and sector)
@@ -2525,23 +2540,23 @@ procedure TMainForm.DirListChange(Sender: TObject; Node: TTreeNode);
location:='Indirect address: 0x'
+IntToHex(Image.Disc[dir].Entries[entry].Sector,8)+' ';
//DOS Plus - Sector is the starting cluster
- if(Image.FormatNumber>>4=diDOSPlus)
+ if(Image.MajorFormatNumber=diDOSPlus)
or(Image.Disc[dir].DOSPartition)then
location:='Starting Cluster: 0x'
+IntToHex(Image.Disc[dir].Entries[entry].Sector,4);
//Commodore formats - Sector and Track
- if Image.FormatNumber>>4=diCommodore then
+ if Image.MajorFormatNumber=diCommodore then
location:='Track ' +IntToStr(Image.Disc[dir].Entries[entry].Track)+' ';
//All other formats - Sector
- if(Image.FormatNumber>>4=diAcornDFS)
- or(Image.FormatNumber>>4=diAmiga) then
+ if(Image.MajorFormatNumber=diAcornDFS)
+ or(Image.MajorFormatNumber=diAmiga) then
location:=location+'Sector '
+IntToStr(Image.Disc[dir].Entries[entry].Sector)+' ';
//DFS - indicates which side also
- if Image.FormatNumber>>4=diAcornDFS then
+ if Image.MajorFormatNumber=diAcornDFS then
location:=location+'Side ' +IntToStr(Image.Disc[dir].Entries[entry].Side);
//CFS - indicates offset to starting block
- if Image.FormatNumber>>4=diAcornUEF then
+ if Image.MajorFormatNumber=diAcornUEF then
location:='Starting Block 0x'
+IntToHex(Image.Disc[dir].Entries[entry].Sector,8);
end;
@@ -2553,12 +2568,12 @@ procedure TMainForm.DirListChange(Sender: TObject; Node: TTreeNode);
location:='';
//ADFS Old map and Acorn File Server - Sector is an offset
if(Image.MapType=diADFSOldMap)
- or(Image.FormatNumber>>4=diAcornFS)
- or((Image.FormatNumber>>4=diDOSPlus)and(Image.MapType<>diFAT32))
+ or(Image.MajorFormatNumber=diAcornFS)
+ or((Image.MajorFormatNumber=diDOSPlus)and(Image.MapType<>diFAT32))
or(Image.Disc[dr].AFSPartition)
or(Image.Disc[dr].DOSPartition)then
location:='Sector Offset: 0x'+IntToHex(Image.Disc[dr].Sector,8);
- if(Image.FormatNumber>>4=diDOSPlus)and(Image.MapType=diFAT32)then
+ if(Image.MajorFormatNumber=diDOSPlus)and(Image.MapType=diFAT32)then
location:='Starting Cluster: 0x'+IntToHex(Image.Disc[dr].Sector,8);
//Number of entries in a directory
ptr:=Length(Image.Disc[dr].Entries);
@@ -2622,9 +2637,9 @@ function TMainForm.GetImageIndex(Node: TTreeNode;ImageToUse: TDiscImage): Intege
begin
WriteToDebug('Non-directory');
//Are we ADFS, SparkFS, AFS or DOS?
- if((ImageToUse.FormatNumber>>4=diAcornADFS)
- or(ImageToUse.FormatNumber>>4=diSpark)
- or(ImageToUse.FormatNumber>>4=diAcornFS))
+ if((ImageToUse.MajorFormatNumber=diAcornADFS)
+ or(ImageToUse.MajorFormatNumber=diSpark)
+ or(ImageToUse.MajorFormatNumber=diAcornFS))
and(Length(ImageToUse.Disc)>0)and(not dospart)then
begin
//Default
@@ -2642,7 +2657,7 @@ function TMainForm.GetImageIndex(Node: TTreeNode;ImageToUse: TDiscImage): Intege
end;
end;
//Is it a Commodore format?
- if(ImageToUse.FormatNumber>>4=diCommodore)
+ if(ImageToUse.MajorFormatNumber=diCommodore)
and(Length(ImageToUse.Disc)>0)then
begin
//Default is a PRG file
@@ -2651,8 +2666,8 @@ function TMainForm.GetImageIndex(Node: TTreeNode;ImageToUse: TDiscImage): Intege
if i<>unknown then ft:=i;
end;
//DOS Plus (DOS)
- if((ImageToUse.FormatNumber>>4=diDOSPlus)
- or((ImageToUse.FormatNumber>>4=diAcornADFS)and(dospart)))
+ if((ImageToUse.MajorFormatNumber=diDOSPlus)
+ or((ImageToUse.MajorFormatNumber=diAcornADFS)and(dospart)))
and(Length(ImageToUse.Disc)>0)then
begin
i:=GetFileTypeGraphic(filetype,Low(DOSFileTypes),DOSFileTypes);
@@ -2671,8 +2686,8 @@ function TMainForm.GetImageIndex(Node: TTreeNode;ImageToUse: TDiscImage): Intege
ft:=directory;
//If RISC OS, and an application
if(not dospart)and(not afspart)then
- if(ImageToUse.FormatNumber>>4=diAcornADFS)
- or(ImageToUse.FormatNumber>>4=diSpark)then //ADFS and Spark only
+ if(ImageToUse.MajorFormatNumber=diAcornADFS)
+ or(ImageToUse.MajorFormatNumber=diSpark)then //ADFS and Spark only
if(ImageToUse.DirectoryType=diADFSNewDir)
OR(ImageToUse.DirectoryType=diADFSBigDir)then //New or Big
if Node.Text[1]='!' then
@@ -2682,7 +2697,7 @@ function TMainForm.GetImageIndex(Node: TTreeNode;ImageToUse: TDiscImage): Intege
if i<>unknown then ft:=i;
end;
//If MMB
- if ImageToUse.FormatNumber>>4=diMMFS then
+ if ImageToUse.MajorFormatNumber=diMMFS then
begin
ft:=mmbdisc;
if ImageToUse.Disc[Node.Index].Locked then ft:=mmbdisclock;
@@ -2822,6 +2837,7 @@ procedure TMainForm.DisableControls;
btn_SaveAsCSV.Enabled :=False;
btn_FixADFS.Enabled :=False;
btn_FileSearch.Enabled :=False;
+ btn_ShowReport.Enabled :=False;
//Pop up Menu items
ExtractFile1.Enabled :=False;
RenameFile1.Enabled :=False;
@@ -2843,6 +2859,7 @@ procedure TMainForm.DisableControls;
menuAbout.Enabled :=True;
menuFixADFS.Enabled :=False;
menuFileSearch.Enabled :=False;
+ menuShowReport.Enabled :=False;
//Close the search window
SearchForm.Close;
//Disable the directory view
@@ -2951,7 +2968,7 @@ procedure TMainForm.ParseCommandLine(cmd: String);
if(not newmap)and(harddrivesize>512*1024*1024)then
harddrivesize:=512*1024*1024;//512MB max for old map
//OK, now create it
- if Image.FormatHDD(diAcornADFS,harddrivesize,newmap,dirtype) then
+ if Image.FormatHDD(diAcornADFS,harddrivesize,True,newmap,dirtype,False) then
begin
HasChanged:=True;
ShowNewImage(Image.Filename);
@@ -2973,7 +2990,8 @@ procedure TMainForm.ParseCommandLine(cmd: String);
//But not too big
if harddrivesize>512*1024 then harddrivesize:=512*1024;
//Create it
- if Image.FormatHDD(diAcornFS,harddrivesize*1024,False,dirtype) then
+ if Image.FormatHDD(diAcornFS,harddrivesize*1024,
+ True,False,dirtype,False) then
begin
HasChanged:=True;
ShowNewImage(Image.Filename);
@@ -2992,7 +3010,8 @@ procedure TMainForm.ParseCommandLine(cmd: String);
//But not too big
if harddrivesize>1024*1024 then harddrivesize:=512*1024;
//Create it
- if Image.FormatHDD(diDOSPlus,harddrivesize*1024,False,dirtype) then
+ if Image.FormatHDD(diDOSPlus,harddrivesize*1024,
+ True,False,dirtype,False) then
begin
HasChanged:=True;
ShowNewImage(Image.Filename);
@@ -3009,7 +3028,7 @@ procedure TMainForm.ParseCommandLine(cmd: String);
//But not too big
if harddrivesize>1024*1024 then harddrivesize:=512*1024;
//Create it
- if Image.FormatHDD(diAmiga,harddrivesize*1024,False,0) then
+ if Image.FormatHDD(diAmiga,harddrivesize*1024,True,False,0,False) then
begin
HasChanged:=True;
ShowNewImage(Image.Filename);
@@ -3118,7 +3137,7 @@ procedure TMainForm.ParseCommandLine(cmd: String);
if(option='--interleave')or(option='-in')then
if(Image.FormatNumber=diAcornADFS<<4+2)
or(Image.FormatNumber=diAcornADFS<<4+$E)
- or(Image.FormatNumber>>4=diAcornFS)then
+ or(Image.MajorFormatNumber=diAcornFS)then
if Image.ChangeInterleaveMethod(StrToIntDef(param,0)) then HasChanged:=True;
//Extract files ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
if (option='--extract') or (option='-e') then
@@ -3266,39 +3285,41 @@ procedure TMainForm.FormCreate(Sender: TObject);
ErrorReporting:=True;
//Reset the form shift state
FormShiftState:=[];
+ //Initiate the Registry
+ DIMReg:=TGJHRegistry.Create('\Software\GJH Software\Disc Image Manager');
//Texture style - get from the registry
- TextureType :=GetRegValI('Texture',1);
+ TextureType :=DIMReg.GetRegValI('Texture',1);
//ADFS L Interleaved type - get from the registry
- ADFSInterleave:=GetRegValI('ADFS_L_Interleave',0);
+ ADFSInterleave:=DIMReg.GetRegValI('ADFS_L_Interleave',0);
//Treat Spark as FS?
- SparkIsFS :=GetRegValB('Spark_Is_FS',True);
+ SparkIsFS :=DIMReg.GetRegValB('Spark_Is_FS',True);
//Threshold of when to bypass the GUI (during import) - get from registry
- bypassGUIThres:={GetRegValI('bypass_GUI_Threshold',}100;//);
+ bypassGUIThres:={DIMReg.GetRegValI('bypass_GUI_Threshold',}100;//);
//Create INF Files?
- DoCreateINF :=GetRegValB('CreateINF',True);
+ DoCreateINF :=DIMReg.GetRegValB('CreateINF',True);
//Hide Commodore DEL files
- DoHideDEL :=GetRegValB('Hide_CDR_DEL',False);
+ DoHideDEL :=DIMReg.GetRegValB('Hide_CDR_DEL',False);
//Allow DFS images with zero sectors
- FDFSZeroSecs :=GetRegValB('DFS_Zero_Sectors',False);
+ FDFSZeroSecs :=DIMReg.GetRegValB('DFS_Zero_Sectors',False);
//Check for files going over the DFS disc edge
- FDFSBeyondEdge:=GetRegValB('DFS_Beyond_Edge',False);
+ FDFSBeyondEdge:=DIMReg.GetRegValB('DFS_Beyond_Edge',False);
//Check for blank filenames in DFS
- FDFSAllowBlank:=GetRegValB('DFS_Allow_Blanks',False);
+ FDFSAllowBlank:=DIMReg.GetRegValB('DFS_Allow_Blanks',False);
//Compress UEF Files on save
- FUEFCompress :=GetRegValB('UEF_Compress',True);
+ FUEFCompress :=DIMReg.GetRegValB('UEF_Compress',True);
//Scan all sub directories on opening
- FScanSubDirs :=GetRegValB('Scan_SubDirs',True);
+ FScanSubDirs :=DIMReg.GetRegValB('Scan_SubDirs',True);
//Open DOS Partitions on ADFS
- FOpenDOS :=GetRegValB('Open_DOS',True);
+ FOpenDOS :=DIMReg.GetRegValB('Open_DOS',True);
//View menu options
- ViewOptions :=GetRegValI('View_Options',$FFFF);
+ ViewOptions :=DIMReg.GetRegValI('View_Options',$FFFF);
//Toolbar order - this doesn't work currently
-{ ToolBarContainer.Bands.Items[0]:=GetRegValS('ToolBar0','ImageToolBar');
- ToolBarContainer.Bands.Items[1].Text:=GetRegValS('ToolBar1','FilesToolBar');
- ToolBarContainer.Bands.Items[2].Text:=GetRegValS('ToolBar2','PartitionToolBar');
- ToolBarContainer.Bands.Items[3].Text:=GetRegValS('ToolBar3','ToolsToolBar');}
+{ ToolBarContainer.Bands.Items[0]:=DIMReg.GetRegValS('ToolBar0','ImageToolBar');
+ ToolBarContainer.Bands.Items[1].Text:=DIMReg.GetRegValS('ToolBar1','FilesToolBar');
+ ToolBarContainer.Bands.Items[2].Text:=DIMReg.GetRegValS('ToolBar2','PartitionToolBar');
+ ToolBarContainer.Bands.Items[3].Text:=DIMReg.GetRegValS('ToolBar3','ToolsToolBar');}
//Produce log files for debugging
- Fdebug:=GetRegValB('Debug_Mode',False);
+ Fdebug:=DIMReg.GetRegValB('Debug_Mode',False);
debuglogfile:=GetTempDir+'DIM_LogFile.txt';
//Write some debugging info
WriteToDebug('Application Started.');
@@ -3448,6 +3469,7 @@ procedure TMainForm.FormDropFiles(Sender: TObject;
sparksize : Cardinal;
isspark : Boolean;
confirm : TModalResult;
+ ListOfFile: array of String;
begin
//Create a new DiscImage instance
NewImage:=TDiscImage.Create;
@@ -3457,84 +3479,101 @@ procedure TMainForm.FormDropFiles(Sender: TObject;
NewImage.DFSBeyondEdge:=FDFSBeyondEdge;
NewImage.DFSAllowBlanks:=FDFSAllowBlank;
NewImage.ScanSubDirs:=True;
+ //Extract any *.inf files
+ SetLength(ListOfFile,0);
for FileName in FileNames do
+ if LowerCase(RightStr(FileName,4))<>'.inf' then
+ begin
+ SetLength(ListOfFile,Length(ListOfFile)+1);
+ ListOfFile[Length(ListOfFile)-1]:=FileName;
+ end;
+ //And then iterate through them and add them
+ for FileName in ListOfFile do
begin
//If it is not a directory
if not DirectoryExists(Filename) then
begin
//Open or add ($00=ignore, $01=open, $02=add, $03=ask)
open:=$00;
- //Load and ID the file
- NewImage.LoadFromFile(FileName,false);
- //Valid image?
- if NewImage.FormatNumber<>diInvalidImg then //Is an image
- begin
- open:=open OR $01;
- //Get the detected format string
- fmt:=NewImage.FormatString;
- end;
- //Is there something loaded?
- if Image.Filename<>'' then open:=open OR $02; //Something is open
- if((NewImage.FormatNumber=diAcornDFS<<4+0)
- or (NewImage.FormatNumber=diAcornDFS<<4+2))
- and((Image.FormatNumber=diAcornDFS<<4+0)
- or (Image.FormatNumber=diAcornDFS<<4+2))then //Loading a DFS SS while a SS is open
- open:=$04; //Might want to convert an SS to a DS
- //Go through the different states
- if open=$04 then //Convert DFS SS to DFS DS
- begin
- msg:='The new image is a '+NewImage.FormatString+', '
- +'and the open image is a '+Image.FormatString+'.'#13#10;
- msg:=msg+'Would you like to open this as an image, '
- +'or convert the open one by adding this as a second side/partition?';
- confirm:=AskConfirm(msg,'Open','Convert','');
- if confirm=mrOK then open:=$01;
- if confirm=mrCancel then open:=$04;
- end;
- if open=$03 then //Ask user
+ if Length(ListOfFile)=1 then //If more than one, then just add, otherwise explore other options
begin
- //Prepare message
- msg:='There is already an image open.'#13#10;
- msg:=msg+'Open this file as a';
- //Is the first letter a vowel?
- if(fmt[1]='A')or(fmt[1]='E')or(fmt[1]='I')or(fmt[1]='O')or(fmt[1]='U')then
- msg:=msg+'n';
- msg:=msg+' '+fmt+' image, add this file to existing image, ';
- msg:=msg+'or import this file''s contents to existing image?';
- //Pose question
- confirm:=AskConfirm(msg,'Open','Add','Import');
- if confirm=mrOK then open:=$01;
- if confirm=mrCancel then open:=$02;
- if confirm=mrIgnore then open:=$03;
- end;
- if open=$02 then //Add file
- begin
- //Is this 32bit ADFS?
- if (Image.DirectoryType>0)
- and(Image.FormatNumber>>4=diAcornADFS)
- and(not SparkIsFS)then //And Spark is not being treated as a filing system
+ //Load and ID the file
+ NewImage.LoadFromFile(FileName,false);
+ //Valid image?
+ if NewImage.FormatNumber<>diInvalidImg then //Is an image
begin
- //See if it is a spark archive
- SparkFile:=TSpark.Create(FileName);
- sparksize:=SparkFile.UncompressedSize;
- isspark:=SparkFile.IsSpark;
- SparkFile.Free;
- //Is it a valid Spark Archive?
- if(isspark)and(sparksize'' then open:=open OR $02; //Something is open
+ if((NewImage.FormatNumber=diAcornDFS<<4+0)
+ or (NewImage.FormatNumber=diAcornDFS<<4+2))
+ and((Image.FormatNumber=diAcornDFS<<4+0)
+ or (Image.FormatNumber=diAcornDFS<<4+2))then //Loading a DFS SS while a SS is open
+ open:=$04; //Might want to convert an SS to a DS
+ //Go through the different states
+ if open=$04 then //Convert DFS SS to DFS DS
+ begin
+ msg:='The new image is a '+NewImage.FormatString+', '
+ +'and the open image is a '+Image.FormatString+'.'#13#10;
+ msg:=msg+'Would you like to open this as an image, '
+ +'or convert the open one by adding this as a second side/partition?';
+ confirm:=AskConfirm(msg,'Open','Convert','');
+ if confirm=mrOK then open:=$01;
+ if confirm=mrCancel then open:=$04;
+ end;
+ if open=$03 then //Ask user
+ begin
+ //Prepare message
+ msg:='There is already an image open.'#13#10;
+ msg:=msg+'Open this file as a';
+ //Is the first letter a vowel?
+ if(fmt[1]='A')or(fmt[1]='E')or(fmt[1]='I')or(fmt[1]='O')or(fmt[1]='U')then
+ msg:=msg+'n';
+ msg:=msg+' '+fmt+' image, add this file to existing image, ';
+ msg:=msg+'or import this file''s contents to existing image?';
+ //Pose question
+ confirm:=AskConfirm(msg,'Open','Add','Import');
+ if confirm=mrOK then open:=$01;
+ if confirm=mrCancel then open:=$02;
+ if confirm=mrIgnore then open:=$03;
+ end;
+ if open=$02 then //Add file
+ begin
+ //Is this 32bit ADFS?
+ if (Image.DirectoryType>0)
+ and(Image.MajorFormatNumber=diAcornADFS)
+ and(not SparkIsFS)then //And Spark is not being treated as a filing system
+ begin
+ //See if it is a spark archive
+ SparkFile:=TSpark.Create(FileName);
+ sparksize:=SparkFile.UncompressedSize;
+ isspark:=SparkFile.IsSpark;
+ SparkFile.Free;
+ //Is it a valid Spark Archive?
+ if(isspark)and(sparksize>4=diAcornADFS) //Check ADFS
+ if ((Image.MajorFormatNumber=diAcornADFS) //Check ADFS
and(((MaxDirEnt>47)and(Image.DirectoryType=diADFSOldDir))
or((MaxDirEnt>77)and(Image.DirectoryType=diADFSNewDir))))
- or ((Image.FormatNumber>>4=diAcornDFS)and(NumFiles>31)) //Check DFS
- or ((Image.FormatNumber>>4=diCommodore)and(NumFiles>144)) //Check Commodore
+ or ((Image.MajorFormatNumber=diAcornDFS)and(NumFiles>31)) //Check DFS
+ or ((Image.MajorFormatNumber=diCommodore)and(NumFiles>144)) //Check Commodore
then
if Dialogue then ok:=AskConfirm(
'The current open image is not suitable for this archive. '
@@ -3676,6 +3717,7 @@ procedure TMainForm.ImportFiles(NewImage: TDiscImage;Dialogue: Boolean=True);
begin
//We don't need progress update from the class as we'll produce our own
NewImage.ProgressIndicator:=nil;
+ Image.ProgressIndicator:=@UpdateProgress;
//Show the progress form again
ProgressForm.Show;
Application.ProcessMessages;
@@ -3703,8 +3745,8 @@ procedure TMainForm.ImportFiles(NewImage: TDiscImage;Dialogue: Boolean=True);
end
else //Nothing selected, then this is the root
rootname:=Image.Disc[0].Directory;
- curformat:=Image.FormatNumber>>4; //Format of the current open image
- newformat:=NewImage.FormatNumber>>4;//Format of the importing image
+ curformat:=Image.MajorFormatNumber; //Format of the current open image
+ newformat:=NewImage.MajorFormatNumber;//Format of the importing image
//Go through each directory
if Length(NewImage.Disc)>0 then
for dir:=0 to Length(NewImage.Disc)-1 do
@@ -3823,8 +3865,8 @@ procedure TMainForm.sb_FileTypeClick(Sender: TObject);
entry: Integer;
begin
//ADFS or Spark non directories only
- if((Image.FormatNumber>>4=diAcornADFS)
- or(Image.FormatNumber>>4=diSpark))
+ if((Image.MajorFormatNumber=diAcornADFS)
+ or(Image.MajorFormatNumber=diSpark))
and(not TMyTreeNode(DirList.Selected).IsDir)then
begin
//Get the references
@@ -3883,7 +3925,7 @@ procedure TMainForm.FileTypeClick(Sender: TObject);
//If all went OK, update the display
DirListChange(Sender,DirList.Selected);
//And mark as changed
- if Image.FormatNumber>>4<>diSpark then HasChanged:=True;
+ if Image.MajorFormatNumber<>diSpark then HasChanged:=True;
end;
end;
end;
@@ -3956,7 +3998,7 @@ procedure TMainForm.ShowHideToolbar(Sender: TObject);
//Then set it, if needed
if TMenuItem(Sender).Checked then ViewOptions:=ViewOptions OR(1<- >4=diAcornADFS)
- or(Image.FormatNumber>>4=diAcornFS)
- or(Image.FormatNumber>>4=diDOSPlus)
- or(Image.FormatNumber>>4=diAmiga)
- or(Image.FormatNumber>>4=diSpark)then
+ if(Image.MajorFormatNumber=diAcornADFS)
+ or(Image.MajorFormatNumber=diAcornFS)
+ or(Image.MajorFormatNumber=diDOSPlus)
+ or(Image.MajorFormatNumber=diAmiga)
+ or(Image.MajorFormatNumber=diSpark)then
begin
//Get the references
entry:=DirList.Selected.Index;
@@ -4038,7 +4080,11 @@ procedure TMainForm.ed_timestampEditingDone(Sender: TObject);
//Display the new details
lb_timestamp.Caption:=FormatDateTime(TimeDateFormat,
Image.Disc[dir].Entries[entry].TimeStamp);
- if Image.FormatNumber>>4<>diSpark then HasChanged:=True;
+ if Image.MajorFormatNumber<>diSpark then
+ begin
+ HasChanged:=True;
+ UpdateImageInfo;
+ end;
end;
end;
@@ -4144,7 +4190,7 @@ procedure TMainForm.ed_execaddrEditingDone(Sender: TObject);
//If success, then change the text
lb_execaddr.Caption:='0x'+IntToHex(Image.Disc[dir].Entries[entry].ExecAddr,8);
lb_loadaddr.Caption:='0x'+IntToHex(Image.Disc[dir].Entries[entry].LoadAddr,8);
- if Image.FormatNumber>>4<>diSpark then HasChanged:=True;
+ if Image.MajorFormatNumber<>diSpark then HasChanged:=True;
end;
end;
end;
@@ -4200,7 +4246,7 @@ procedure TMainForm.btn_ImageDetailsClick(Sender: TObject);
ImageDetailForm.lbImgFormat.Caption:=Image.FormatString;
//Map type
ImageDetailForm.lbMap.Caption :=Image.MapTypeString;
- if Image.FormatNumber>>4<>diDOSPlus then
+ if Image.MajorFormatNumber<>diDOSPlus then
ImageDetailForm.MapLabel.Caption:='Map Type'
else
ImageDetailForm.MapLabel.Caption:='FAT Type';
@@ -4248,7 +4294,7 @@ procedure TMainForm.btn_ImageDetailsClick(Sender: TObject);
ImageDetailForm.BBCMasterLogo.Visible:=False;
ImageDetailForm.MicrosoftLogo.Visible:=False;
//Now display the appropriate one
- case Image.FormatNumber>>4 of
+ case Image.MajorFormatNumber of
diAcornDFS,
diAcornADFS,
diAcornUEF,
@@ -4257,7 +4303,7 @@ procedure TMainForm.btn_ImageDetailsClick(Sender: TObject);
diAmiga : ImageDetailForm.AmigaLogo.Visible :=True;
diSinclair : ImageDetailForm.SinclairLogo.Visible :=True;
diDOSPlus :
- if Image.FormatNumber mod $10<>0 then
+ if Image.MinorFormatNumber<>0 then
ImageDetailForm.MicrosoftLogo.Visible:=True
else
ImageDetailForm.BBCMasterLogo.Visible:=True;
@@ -4348,16 +4394,16 @@ procedure TMainForm.btn_ImageDetailsClick(Sender: TObject);
titles[side].Text:=title;
titles[0].Enabled:=not Image.AFSPresent;
//Limit the length
- if Image.FormatNumber>>4=diAcornDFS then titles[side].MaxLength:=12; //DFS
- if Image.FormatNumber>>4=diAcornADFS then
+ if Image.MajorFormatNumber=diAcornDFS then titles[side].MaxLength:=12; //DFS
+ if Image.MajorFormatNumber=diAcornADFS then
begin
if(Image.DOSPresent)and(side=1)then
titles[side].MaxLength:=11 //DOS Partition in an ADFS disc
else
titles[side].MaxLength:=10; //ADFS
end;
- if Image.FormatNumber>>4=diAcornFS then titles[side].MaxLength:=10; //AFS
- if Image.FormatNumber>>4=diDOSPlus then titles[side].MaxLength:=11; //DOS
+ if Image.MajorFormatNumber=diAcornFS then titles[side].MaxLength:=10; //AFS
+ if Image.MajorFormatNumber=diDOSPlus then titles[side].MaxLength:=11; //DOS
//Boot Option
boots[side].Visible :=True;
if Length(Image.BootOpt)>side then
@@ -4367,13 +4413,13 @@ procedure TMainForm.btn_ImageDetailsClick(Sender: TObject);
bootlbs[side].Visible:=boots[side].Visible;
end;
//Is this an ADFS/AFS Hybrid?
- if(Image.FormatNumber>>4=diAcornADFS)and(Image.AFSPresent)then
+ if(Image.MajorFormatNumber=diAcornADFS)and(Image.AFSPresent)then
begin
FSMlabel[0].Caption:=FSMlabel[0].Caption+' ADFS Partition';
FSMlabel[1].Caption:=FSMlabel[1].Caption+' Acorn FS Partition';
end;
//Is this an ADFS/DOS Hybrid?
- if(Image.FormatNumber>>4=diAcornADFS)and(Image.DOSPresent)then
+ if(Image.MajorFormatNumber=diAcornADFS)and(Image.DOSPresent)then
begin
FSMlabel[0].Caption:=FSMlabel[0].Caption+' ADFS Partition';
FSMlabel[1].Caption:=FSMlabel[1].Caption+' DOS Plus Partition';
@@ -4465,18 +4511,18 @@ procedure TMainForm.btn_SavePartitionClick(Sender: TObject);
//Open the Save As dialogue box
SaveImage.Title:='Save Partition As';
//DS DFS Image, so target is SS DFS
- if(Image.FormatNumber>>4=diAcornDFS)
+ if(Image.MajorFormatNumber=diAcornDFS)
and(Image.DoubleSided)then targetformat:=Image.FormatNumber-1;
//ADFS/AFS Hybrid, with AFS partition selected, so target will be AFS Level 3
- if(Image.FormatNumber>>4=diAcornADFS)
+ if(Image.MajorFormatNumber=diAcornADFS)
and(Image.AFSPresent)
and(side<>0)then targetformat:=diAcornFS<<4+2;
//ADFS/DOS Hybrid, with DOS partition selected, so target will be DOS Plus
- if(Image.FormatNumber>>4=diAcornADFS)
+ if(Image.MajorFormatNumber=diAcornADFS)
and(Image.DOSPresent)
and(side<>0)then targetformat:=diDOSPlus<<4;
//ADFS/AFS Hybrid, with ADFS partition selected, so target will be ADFS Hard Disc
- if(Image.FormatNumber>>4=diAcornADFS)
+ if(Image.MajorFormatNumber=diAcornADFS)
and(side=0)then targetformat:=diAcornADFS<<4+$F;
//Populate the filter part of the dialogue
index:=0;
@@ -4491,6 +4537,7 @@ procedure TMainForm.btn_SavePartitionClick(Sender: TObject);
if SaveImage.Execute then
begin
//Show a progress message
+ Image.ProgressIndicator:=@UpdateProgress;
ProgressForm.Show;
//Process the messages to close the file dialogue box
Application.ProcessMessages;
@@ -4701,6 +4748,7 @@ procedure TMainForm.btn_FixADFSClick(Sender: TObject);
c: Boolean;
begin
//Show a progress message
+ Image.ProgressIndicator:=@UpdateProgress;
ProgressForm.Show;
//Process the messages to close the file dialogue box
Application.ProcessMessages;
@@ -4740,7 +4788,7 @@ procedure TMainForm.btn_NewDirectoryClick(Sender: TObject);
inc(x);
dirname:=dirname+IntToStr(x);
//Create the directory
- if Image.FormatNumber>>4<>diAmiga then
+ if Image.MajorFormatNumber<>diAmiga then
CreateDirectory(dirname,'DLR')
else
CreateDirectory(dirname,''); //Create with no protection flags for Amiga
@@ -4755,54 +4803,125 @@ procedure TMainForm.btn_SaveAsCSVClick(Sender: TObject);
dir,
entry : Integer;
filename,
- ext : String;
+ ext,
+ line : String;
hexlen : Byte;
+ report : TStringList;
begin
- //Remove the existing part of the original filename
- filename:=ExtractFileName(Image.Filename);
- ext:=ExtractFileExt(filename);
- filename:=LeftStr(filename,Length(filename)-Length(ext));
- //Populate the save dialogue box
- SaveImage.DefaultExt:='.csv';
- SaveImage.Filter:='CSV File|*.csv';
- SaveImage.FilterIndex:=1;
- SaveImage.Title:='Save CSV of image contents';
- //Add the csv extension
- SaveImage.Filename:=filename+'.csv';
- //Show the dialogue box
- if SaveImage.Execute then
+ //Get the last used settings from the registry
+ CSVPrefForm.cb_IncDir.Checked :=DIMReg.GetRegValB('CSVIncDir' ,False);
+ CSVPrefForm.cb_IncFilename.Checked:=DIMReg.GetRegValB('CSVIncFilename',True);
+ CSVPrefForm.cb_IncReport.Checked :=DIMReg.GetRegValB('CSVIncReport' ,True);
+ CSVPrefForm.cb_Parent.Checked :=DIMReg.GetRegValB('CSVParent' ,True);
+ CSVPrefForm.cb_Filename.Checked :=DIMReg.GetRegValB('CSVFilename' ,True);
+ CSVPrefForm.cb_LoadAddr.Checked :=DIMReg.GetRegValB('CSVLoadAddr' ,True);
+ CSVPrefForm.cb_ExecAddr.Checked :=DIMReg.GetRegValB('CSVExecAddr' ,True);
+ CSVPrefForm.cb_Length.Checked :=DIMReg.GetRegValB('CSVLength' ,True);
+ CSVPrefForm.cb_Attributes.Checked :=DIMReg.GetRegValB('CSVAttributes' ,True);
+ CSVPrefForm.cb_Address.Checked :=DIMReg.GetRegValB('CSVAddress' ,False);
+ CSVPrefForm.cb_CRC32.Checked :=DIMReg.GetRegValB('CSVCRC32' ,True);
+ //Ask user what they want in the CSV file
+ CSVPrefForm.ShowModal;
+ if CSVPrefForm.ModalResult=mrOK then //Unless they clicked Cancel
begin
- hexlen:=8;
- if Image.FormatNumber>>4=diAcornDFS then hexlen:=6;
- //Show a progress message
- ProgressForm.Show;
- //Process the messages to close the file dialogue box
- Application.ProcessMessages;
- //Open a new file
- F:=TFileStream.Create(SaveImage.FileName,fmCreate OR fmShareDenyNone);
- //Write the image details
- WriteLine(F,'"'+Image.Filename+'","'+Image.CRC32+'"');
- //Write the headers
- WriteLine(F,'"Parent","Filename","Load Address","Execution Address","Length","Attributes","CRC32"');
- //Go through each directory
- for dir:=0 to Length(Image.Disc)-1 do
- //And each entry in that directory
- for entry:=0 to Length(Image.Disc[dir].Entries)-1 do
- //write out each entry
- if Image.Disc[dir].Entries[entry].DirRef=-1 then
- WriteLine(F,'"'+Image.GetParent(dir)+'","'
- +Image.Disc[dir].Entries[entry].Filename+'","'
- +IntToHex(Image.Disc[dir].Entries[entry].LoadAddr,hexlen)+'","'
- +IntToHex(Image.Disc[dir].Entries[entry].ExecAddr,hexlen)+'","'
- +IntToHex(Image.Disc[dir].Entries[entry].Length,hexlen)+'","'
- +Image.Disc[dir].Entries[entry].Attributes+'","'
- +Image.GetFileCRC(Image.GetParent(dir)
- +Image.GetDirSep(Image.Disc[dir].Partition)
- +Image.Disc[dir].Entries[entry].Filename)+'"');
- //Finally free up the file stream
- F.Free;
- //Close the progress window
- ProgressForm.Hide;
+ //Save the settings to the registry
+ DIMReg.SetRegValB('CSVIncDir' ,CSVPrefForm.cb_IncDir.Checked);
+ DIMReg.SetRegValB('CSVIncFilename',CSVPrefForm.cb_IncFilename.Checked);
+ DIMReg.SetRegValB('CSVIncReport' ,CSVPrefForm.cb_IncReport.Checked);
+ DIMReg.SetRegValB('CSVParent' ,CSVPrefForm.cb_Parent.Checked);
+ DIMReg.SetRegValB('CSVFilename' ,CSVPrefForm.cb_Filename.Checked);
+ DIMReg.SetRegValB('CSVLoadAddr' ,CSVPrefForm.cb_LoadAddr.Checked);
+ DIMReg.SetRegValB('CSVExecAddr' ,CSVPrefForm.cb_ExecAddr.Checked);
+ DIMReg.SetRegValB('CSVLength' ,CSVPrefForm.cb_Length.Checked);
+ DIMReg.SetRegValB('CSVAttributes' ,CSVPrefForm.cb_Attributes.Checked);
+ DIMReg.SetRegValB('CSVAddress' ,CSVPrefForm.cb_Address.Checked);
+ DIMReg.SetRegValB('CSVCRC32' ,CSVPrefForm.cb_CRC32.Checked);
+ //Remove the existing part of the original filename
+ filename:=ExtractFileName(Image.Filename);
+ ext:=ExtractFileExt(filename);
+ filename:=LeftStr(filename,Length(filename)-Length(ext));
+ //Populate the save dialogue box
+ SaveImage.DefaultExt:='.csv';
+ SaveImage.Filter:='CSV File|*.csv';
+ SaveImage.FilterIndex:=1;
+ SaveImage.Title:='Save CSV of image contents';
+ //Add the csv extension
+ SaveImage.Filename:=filename+'.csv';
+ //Show the dialogue box
+ if SaveImage.Execute then
+ begin
+ hexlen:=8;
+ if Image.MajorFormatNumber=diAcornDFS then hexlen:=6;
+ //Show a progress message
+ Image.ProgressIndicator:=@UpdateProgress;
+ ProgressForm.Show;
+ //Process the messages to close the file dialogue box
+ Application.ProcessMessages;
+ //Open a new file
+ F:=TFileStream.Create(SaveImage.FileName,fmCreate OR fmShareDenyNone);
+ //Write the image details
+ if CSVPrefForm.cb_IncFilename.Checked then
+ WriteLine(F,'"'+Image.Filename+'","0x'+Image.CRC32+'"');
+ //Write the report
+ if CSVPrefForm.cb_IncReport.Checked then
+ begin
+ report:=Image.ImageReport(True);
+ if report.Count>0 then
+ for dir:=0 to report.Count-1 do
+ WriteLine(F,report[dir]);
+ end;
+ //Write the headers
+ line:='';
+ if CSVPrefForm.cb_Parent.Checked then line:=line+'"Parent",';
+ if CSVPrefForm.cb_Filename.Checked then line:=line+'"Filename",';
+ if CSVPrefForm.cb_LoadAddr.Checked then line:=line+'"Load Address",';
+ if CSVPrefForm.cb_ExecAddr.Checked then line:=line+'"Execution Address",';
+ if CSVPrefForm.cb_Length.Checked then line:=line+'"Length",';
+ if CSVPrefForm.cb_Attributes.Checked then line:=line+'"Attributes",';
+ if CSVPrefForm.cb_Address.Checked then line:=line+'"Address",';
+ if CSVPrefForm.cb_CRC32.Checked then line:=line+'"CRC32,"';
+ line:=LeftStr(line,Length(line)-1);
+ WriteLine(F,line);
+ //Go through each directory
+ for dir:=0 to Length(Image.Disc)-1 do
+ //And each entry in that directory
+ for entry:=0 to Length(Image.Disc[dir].Entries)-1 do
+ //write out each entry
+ if(Image.Disc[dir].Entries[entry].DirRef=-1) //Exclude directories?
+ or(CSVPrefForm.cb_IncDir.Checked)then //Or include them?
+ begin
+ line:='';
+ if CSVPrefForm.cb_Parent.Checked then
+ line:=line+'"'+Image.GetParent(dir)+'",';
+ if CSVPrefForm.cb_Filename.Checked then
+ line:=line+'"'+Image.Disc[dir].Entries[entry].Filename+'",';
+ if CSVPrefForm.cb_LoadAddr.Checked then
+ line:=line+'"0x'+IntToHex(Image.Disc[dir].Entries[entry].LoadAddr,hexlen)+'",';
+ if CSVPrefForm.cb_ExecAddr.Checked then
+ line:=line+'"0x'+IntToHex(Image.Disc[dir].Entries[entry].ExecAddr,hexlen)+'",';
+ if CSVPrefForm.cb_Length.Checked then
+ line:=line+'"0x'+IntToHex(Image.Disc[dir].Entries[entry].Length,hexlen)+'",';
+ if CSVPrefForm.cb_Attributes.Checked then
+ line:=line+'"'+Image.Disc[dir].Entries[entry].Attributes+'",';
+ if CSVPrefForm.cb_Address.Checked then
+ line:=line+'"0x'+IntToHex(Image.Disc[dir].Entries[entry].Sector,hexlen)+'",';
+ if CSVPrefForm.cb_CRC32.Checked then
+ line:=line+'"0x'+Image.GetFileCRC(Image.GetParent(dir)
+ +Image.GetDirSep(Image.Disc[dir].Partition)
+ +Image.Disc[dir].Entries[entry].Filename)+',"';
+ line:=LeftStr(line,Length(line)-1);
+ WriteLine(F,line);
+ end;
+ //Write a footer
+ WriteLine(F,'""');
+ WriteLine(F,'"'+ApplicationTitle+' v'+ApplicationVersion+'",'
+ +'"by Gerald J Holdsworth",'
+ +'"gerald@geraldholdsworth.co.uk"');
+ //Finally free up the file stream
+ F.Free;
+ //Close the progress window
+ ProgressForm.Hide;
+ end;
end;
end;
@@ -4866,21 +4985,36 @@ procedure TMainForm.btn_SettingsClick(Sender: TObject);
end;
end;
+{------------------------------------------------------------------------------}
+//Produces a report on the image
+{------------------------------------------------------------------------------}
+procedure TMainForm.btn_ShowReportClick(Sender: TObject);
+begin
+ ImageReportForm.Report.Clear;
+ ImageReportForm.Report.Lines:=Image.ImageReport(False);
+ //Add a footer
+ ImageReportForm.Report.Lines.Add('__________________________________________');
+ ImageReportForm.Report.Lines.Add(ApplicationTitle+' v'+ApplicationVersion);
+ ImageReportForm.Report.Lines.Add('by Gerald J Holdsworth');
+ ImageReportForm.Report.Lines.Add('gerald@geraldholdsworth.co.uk');
+ ImageReportForm.ShowModal;
+end;
+
{------------------------------------------------------------------------------}
//Saves the configuration settings to the registry
{------------------------------------------------------------------------------}
procedure TMainForm.SaveConfigSettings;
begin
- SetRegValI('Texture', TextureType);
- SetRegValI('ADFS_L_Interleave',ADFSInterleave);
- SetRegValB('CreateINF', DoCreateINF);
- SetRegValB('Debug_Mode', Fdebug);
- SetRegValB('DFS_Zero_Sectors', FDFSZeroSecs);
- SetRegValB('DFS_Beyond_Edge', FDFSBeyondEdge);
- SetRegValB('DFS_Allow_Blanks', FDFSAllowBlank);
- SetRegValB('Scan_SubDirs', FScanSubDirs);
- SetRegValB('Open_DOS', FOpenDOS);
- SetRegValB('UEF_Compress', FUEFCompress);
+ DIMReg.SetRegValI('Texture', TextureType);
+ DIMReg.SetRegValI('ADFS_L_Interleave',ADFSInterleave);
+ DIMReg.SetRegValB('CreateINF', DoCreateINF);
+ DIMReg.SetRegValB('Debug_Mode', Fdebug);
+ DIMReg.SetRegValB('DFS_Zero_Sectors', FDFSZeroSecs);
+ DIMReg.SetRegValB('DFS_Beyond_Edge', FDFSBeyondEdge);
+ DIMReg.SetRegValB('DFS_Allow_Blanks', FDFSAllowBlank);
+ DIMReg.SetRegValB('Scan_SubDirs', FScanSubDirs);
+ DIMReg.SetRegValB('Open_DOS', FOpenDOS);
+ DIMReg.SetRegValB('UEF_Compress', FUEFCompress);
end;
{------------------------------------------------------------------------------}
@@ -5163,7 +5297,7 @@ function TMainForm.CreateDirectory(dirname, attr: String): TTreeNode;
if index>-1 then //Directory added OK
begin
//Mark as changed
- if Image.FormatNumber>>4<>diSpark then HasChanged:=True;
+ if Image.MajorFormatNumber<>diSpark then HasChanged:=True;
//Create the node as a file
Node:=AddFileToTree(DirList.Selected,dirname,index,True,DirList,False);
//Update the directory reference and the directory flag
@@ -5318,16 +5452,16 @@ procedure TMainForm.DirListMouseMove(Sender: TObject; Shift: TShiftState; X,
//Are we over another node?
Dst:=GetNodeAt(Y);//Node under the cursor
if (DraggedItem<>nil)AND(Dst<>nil)
- AND((DraggedItem<>Dst)or(Image.FormatNumber>>4=diAcornUEF))then
+ AND((DraggedItem<>Dst)or(Image.MajorFormatNumber=diAcornUEF))then
begin
//If it is not a directory, and not CFS, then get the parent
- if(not TMyTreeNode(Dst).IsDir)and(Image.FormatNumber>>4<>diAcornUEF)then
+ if(not TMyTreeNode(Dst).IsDir)and(Image.MajorFormatNumber<>diAcornUEF)then
Dst:=Dst.Parent;
//Clear any selections and then highlight the original item, unless it is CFS
DirList.ClearSelection;
- if Image.FormatNumber>>4<>diAcornUEF then DraggedItem.Selected:=True;
+ if Image.MajorFormatNumber<>diAcornUEF then DraggedItem.Selected:=True;
//Only allow copying if it is a different parent and not within itself
- if(DraggedItem<>Dst)or(Image.FormatNumber>>4=diAcornUEF)then//Or UEF
+ if(DraggedItem<>Dst)or(Image.MajorFormatNumber=diAcornUEF)then//Or UEF
begin
//Highlight it
Dst.Selected:=True;
@@ -5458,7 +5592,7 @@ function TMainForm.GetCopyMode(Shift: TShiftState): Boolean;
end;
//If the destination is the same as the source, copy only (not UEF)
if(DraggedItem<>nil)and(Dst<>nil)then
- if(DraggedItem.Parent=Dst)and(Image.FormatNumber>>4<>diAcornUEF)then
+ if(DraggedItem.Parent=Dst)and(Image.MajorFormatNumber<>diAcornUEF)then
Result:=True;
end;
@@ -5522,13 +5656,13 @@ procedure TMainForm.DoCopyMove(copymode: Boolean);
begin
//Are we dragging something, over something and is not the same as the source?
if (DraggedItem<>nil)AND(Dst<>nil)
- AND((DraggedItem<>Dst)or(Image.FormatNumber>>4=diAcornUEF))then
+ AND((DraggedItem<>Dst)or(Image.MajorFormatNumber=diAcornUEF))then
begin
//If it is not a directory, or CFS format, then get the parent
if (not TMyTreeNode(Dst).IsDir)
- and(Image.FormatNumber>>4<>diAcornUEF)then Dst:=Dst.Parent;
+ and(Image.MajorFormatNumber<>diAcornUEF)then Dst:=Dst.Parent;
//Only allow moving/copying if it is not within itself
- if(DraggedItem<>Dst)or(Image.FormatNumber>>4=diAcornUEF)then
+ if(DraggedItem<>Dst)or(Image.MajorFormatNumber=diAcornUEF)then
begin
//Read in the destination, if necessary
if(TMyTreeNode(Dst).IsDir)and(not TMyTreeNode(Dst).BeenRead)then
@@ -5536,7 +5670,7 @@ procedure TMainForm.DoCopyMove(copymode: Boolean);
//Take a copy of the filename
newfn:=DraggedItem.Text;
//Do the copy/move
- if Image.FormatNumber>>4<>diAcornUEF then //Everything but UEF
+ if Image.MajorFormatNumber<>diAcornUEF then //Everything but UEF
begin
if copymode then //copy - here we rename the file if the destination already
if Image.ValidateFilename(GetFilePath(Dst),newfn) then //has one the same
@@ -5544,7 +5678,7 @@ procedure TMainForm.DoCopyMove(copymode: Boolean);
if not copymode then //move
index:=Image.MoveFile(GetFilePath(DraggedItem),GetFilePath(Dst));
end;
- if Image.FormatNumber>>4=diAcornUEF then //UEF only
+ if Image.MajorFormatNumber=diAcornUEF then //UEF only
begin
if copymode then //copy - Acorn UEF
index:=Image.CopyFile(DraggedItem.AbsoluteIndex-1,Dst.AbsoluteIndex-1);
@@ -5558,9 +5692,9 @@ procedure TMainForm.DoCopyMove(copymode: Boolean);
//new reference
ref:=0;
if(Image.FileExists(GetFilePath(Dst)+Image.DirSep+newfn,ref))
- or(Image.FormatNumber>>4=diAcornUEF)then
+ or(Image.MajorFormatNumber=diAcornUEF)then
begin
- if Image.FormatNumber>>4<>diAcornUEF then
+ if Image.MajorFormatNumber<>diAcornUEF then
begin
entry:=ref mod $10000; //Bottom 16 bits - entry reference
dir :=ref div $10000; //Top 16 bits - directory reference
@@ -5578,7 +5712,7 @@ procedure TMainForm.DoCopyMove(copymode: Boolean);
end;
end;
//Mark as changed
- if Image.FormatNumber>>4<>diSpark then HasChanged:=True;
+ if Image.MajorFormatNumber<>diSpark then HasChanged:=True;
if not copymode then //If moving
begin
//Update any open hexdumps
@@ -5728,17 +5862,19 @@ procedure TMainForm.btn_NewImageClick(Sender: TObject);
//Show the dialogue and set the filename
if SaveImage.Execute then filename:=SaveImage.FileName else exit;
end;
+ Image.ProgressIndicator:=@UpdateProgress;
ProgressForm.Show;
Application.ProcessMessages;
- Image.ProgressIndicator:=@UpdateProgress;
hdd:=False;
//ADFS Hard Drive
if(major=diAcornADFS)and(minor=8)then
begin
ok:=Image.FormatHDD(diAcornADFS,
NewImageForm.harddrivesize,
+ NewImageForm.ide,
NewImageForm.newmap,
- NewImageForm.dirtype);
+ NewImageForm.dirtype,
+ NewImageForm.addheader);
hdd:=True;
end;
//AFS HardDrive
@@ -5747,7 +5883,7 @@ procedure TMainForm.btn_NewImageClick(Sender: TObject);
//Create the format
ok:=Image.FormatHDD(diAcornFS,
NewImageForm.AFSImageSize.Position*10*1024,
- False,minor+2);
+ True,False,minor+2,False);
if(ok)and(NewImageForm.cb_AFScreatepword.Checked)then
//Create blank password file for AFS
if Image.CreatePasswordFile(nil)<0 then //If fails, report an error
@@ -5757,14 +5893,14 @@ procedure TMainForm.btn_NewImageClick(Sender: TObject);
//DOS Hard Drive
if(major=diDOSPlus)and(minor=6)then
begin
- ok:=Image.FormatHDD(major,NewImageForm.harddrivesize,False,
- NewImageForm.fat);
+ ok:=Image.FormatHDD(major,NewImageForm.harddrivesize,True,False,
+ NewImageForm.fat,False);
hdd:=True;
end;
//Amiga Hard Drive
if(major=diAmiga)and(minor=2)then
begin
- ok:=Image.FormatHDD(major,NewImageForm.harddrivesize,False,0);
+ ok:=Image.FormatHDD(major,NewImageForm.harddrivesize,True,False,0,False);
hdd:=True;
end;
//Floppy Drive
@@ -5814,12 +5950,12 @@ procedure TMainForm.AttributeChangeClick(Sender: TObject);
end;
att:='';
//Attributes - DFS and UEF
- if(Image.FormatNumber>>4=diAcornDFS)
- or(Image.FormatNumber>>4=diAcornUEF)then
+ if(Image.MajorFormatNumber=diAcornDFS)
+ or(Image.MajorFormatNumber=diAcornUEF)then
if cb_DFS_l.Checked then att:=att+'L';
//Attributes - ADFS
- if((Image.FormatNumber>>4=diAcornADFS)
- or(Image.FormatNumber>>4=diSpark))
+ if((Image.MajorFormatNumber=diAcornADFS)
+ or(Image.MajorFormatNumber=diSpark))
and(not afs)and(not dos)then
begin
if cb_ADFS_ownw.Checked then att:=att+'W';
@@ -5832,8 +5968,8 @@ procedure TMainForm.AttributeChangeClick(Sender: TObject);
if cb_ADFS_pubp.Checked then att:=att+'P';
end;
//Attributes - AFS
- if(Image.FormatNumber>>4=diAcornFS)
- or((Image.FormatNumber>>4=diAcornADFS)and(afs))then
+ if(Image.MajorFormatNumber=diAcornFS)
+ or((Image.MajorFormatNumber=diAcornADFS)and(afs))then
begin
if cb_AFS_ownw.Checked then att:=att+'W';
if cb_AFS_ownr.Checked then att:=att+'R';
@@ -5842,14 +5978,14 @@ procedure TMainForm.AttributeChangeClick(Sender: TObject);
if cb_AFS_pubr.Checked then att:=att+'r';
end;
//Attributes - Commodore 64
- if Image.FormatNumber>>4=diCommodore then
+ if Image.MajorFormatNumber=diCommodore then
begin
if cb_C64_c.Checked then att:=att+'C';
if cb_C64_l.Checked then att:=att+'L';
end;
//Attributes - DOS Plus
- if(Image.FormatNumber>>4=diDOSPlus)
- or((Image.FormatNumber>>4=diAcornADFS)and(dos))then
+ if(Image.MajorFormatNumber=diDOSPlus)
+ or((Image.MajorFormatNumber=diAcornADFS)and(dos))then
begin
if cb_DOS_hidden.Checked then att:=att+'H';
if cb_DOS_read.Checked then att:=att+'R';
@@ -5857,7 +5993,7 @@ procedure TMainForm.AttributeChangeClick(Sender: TObject);
if cb_DOS_archive.Checked then att:=att+'A';
end;
//Attributes - Amiga
- if Image.FormatNumber>>4=diAmiga then
+ if Image.MajorFormatNumber=diAmiga then
begin
if not cb_Amiga_ownd.Checked then att:=att+'D';
if not cb_Amiga_owne.Checked then att:=att+'E';
@@ -5878,13 +6014,13 @@ procedure TMainForm.AttributeChangeClick(Sender: TObject);
end;
//Add the directory attribute
if TMyTreeNode(DirList.Selected).IsDir then
- if Image.FormatNumber>>4<>diAmiga then att:=att+'D' else att:=att+'F';
+ if Image.MajorFormatNumber<>diAmiga then att:=att+'D' else att:=att+'F';
//Get the file path
filepath:=GetFilePath(DirList.Selected);
//Update the attributes for the file
if Image.UpdateAttributes(filepath,att,DirList.Selected.Index) then
begin
- if Image.FormatNumber>>4<>diSpark then HasChanged:=True;
+ if Image.MajorFormatNumber<>diSpark then HasChanged:=True;
//Update the status bar
UpdateImageInfo;
end
@@ -5965,7 +6101,7 @@ procedure TMainForm.DeleteFile(confirm: Boolean);
ok:=Image.DeleteFile(filepath);
if ok then
begin
- if Image.FormatNumber>>4<>diSpark then HasChanged:=True;
+ if Image.MajorFormatNumber<>diSpark then HasChanged:=True;
//Update the status bar
UpdateImageInfo;
//Now update the node and filedetails panel
@@ -6244,7 +6380,7 @@ procedure TMainForm.DirListEditingEnd(Sender: TObject; Node: TTreeNode;
end
else
begin
- if Image.FormatNumber>>4<>diSpark then HasChanged:=True;
+ if Image.MajorFormatNumber<>diSpark then HasChanged:=True;
//Update the status bar
UpdateImageInfo;
//Otherwise change the text on the tree and the file details panel
@@ -6414,7 +6550,7 @@ procedure TMainForm.ToolBarContainerChange(Sender: TObject);
index: Integer;
begin
for index:=0 to ToolBarContainer.Bands.Count-1 do
- SetRegValS('ToolBar'+IntToStr(index)
+ DIMReg.SetRegValS('ToolBar'+IntToStr(index)
,ToolBarContainer.Bands[index].Control.Name);
end;
@@ -6445,16 +6581,16 @@ procedure TMainForm.ImageDetailsDrawPanel(StatusBar: TStatusBar;
{ inc(panwid,imgRect.Width+5);
Rect.Width:=panwid;}
png:=0;
- case Image.FormatNumber>>4 of
+ case Image.MajorFormatNumber of
diAcornDFS : png:=bbclogo; //BBC Micro logo for DFS
diAcornADFS:
begin
- if(Image.FormatNumber mod $10<>3)
+ if (Image.MinorFormatNumber<>3)
and(Image.MapType=diADFSOldMap) then
- png:=acornlogo; //Acorn logo for 8 bit ADFS
- if(Image.FormatNumber mod $10=3)
+ png:=acornlogo; //Acorn logo for 8 bit ADFS
+ if(Image.MinorFormatNumber=3)
or(Image.MapType=diADFSNewMap) then
- png:=riscoslogo; //RISC OS logo for 32 bit ADFS
+ png:=riscoslogo; //RISC OS logo for 32 bit ADFS
end;
diCommodore: png:=commodorelogo; //Commodore logo
diSinclair : png:=sinclairlogo; //Sinclair logo
@@ -6464,8 +6600,10 @@ procedure TMainForm.ImageDetailsDrawPanel(StatusBar: TStatusBar;
diSpark : png:=sparklogo; //!SparkFS logo for Spark
diAcornFS : png:=bbclogo; //BBC Micro logo for Acorn FS
diDOSPlus :
- if Image.FormatNumber mod $10<>0 then png:=msdoslogo //MS DOS logo for DOS
- else png:=bbcmasterlogo; //BBC Master logo for DOS Plus
+ if Image.MinorFormatNumber<>0 then
+ png:=msdoslogo //MS DOS logo for DOS
+ else
+ png:=bbcmasterlogo; //BBC Master logo for DOS Plus
end;
Rect.Height:=Rect.Height-2;
//Draw the icon
diff --git a/LazarusSource/NewImageUnit.pas b/LazarusSource/NewImageUnit.pas
index 768804a..e1dfd0b 100755
--- a/LazarusSource/NewImageUnit.pas
+++ b/LazarusSource/NewImageUnit.pas
@@ -57,7 +57,9 @@ TNewImageForm = class(TForm)
public
harddrivesize : Cardinal;
- newmap : Boolean;
+ newmap,
+ addheader,
+ ide : Boolean;
dirtype,
fat : Byte;
end;
@@ -165,6 +167,8 @@ procedure TNewImageForm.btn_OKClick(Sender: TObject);
begin
//Selected hard drive size in MB
harddrivesize:=HardDriveForm.CapacitySlider.Position*1024*1024;
+ addheader:=HardDriveForm.cb_AddHeader.Checked;
+ ide:=HardDriveForm.cb_IDE.Checked;
if MainFormat.ItemIndex=1 then //ADFS Specific
begin
//New or old map
diff --git a/LazarusSource/ProgressUnit.lfm b/LazarusSource/ProgressUnit.lfm
index ae7a92a..d217820 100644
--- a/LazarusSource/ProgressUnit.lfm
+++ b/LazarusSource/ProgressUnit.lfm
@@ -31,8 +31,7 @@ object ProgressForm: TProgressForm
Height = 18
Top = 181
Width = 595
- Align = alBottom
- Alignment = taRightJustify
+ Alignment = taCenter
AutoSize = False
Caption = 'UpdateProgress'
Font.Color = clBlue
@@ -42,9 +41,9 @@ object ProgressForm: TProgressForm
end
object WaitLabel: TLabel
Left = 1
- Height = 37
+ Height = 38
Top = 1
- Width = 342
+ Width = 331
Alignment = taCenter
Caption = 'Please wait, working...'
end
diff --git a/LazarusSource/ProgressUnit.pas b/LazarusSource/ProgressUnit.pas
index 256c45a..73d21df 100644
--- a/LazarusSource/ProgressUnit.pas
+++ b/LazarusSource/ProgressUnit.pas
@@ -64,7 +64,11 @@ procedure TProgressForm.FormShow(Sender: TObject);
UpdateProgress.Caption:='';
//Re-position the 'Waiting' label
WaitLabel.Left:=(Width-WaitLabel.Width)div 2;
- WaitLabel.Top:=(Height-WaitLabel.Height)div 2;
+ WaitLabel.Top:=(Height-WaitLabel.Height)div 4;
+ //Re-position the 'Progress' label
+ UpdateProgress.Left:=0;
+ UpdateProgress.Width:=Width;
+ UpdateProgress.Top:=WaitLabel.Top+WaitLabel.Height+16;
end;
procedure TProgressForm.FormPaint(Sender: TObject);
diff --git a/binaries/Linux/Disc Image Manager 32 bit.zip b/binaries/Linux/Disc Image Manager 32 bit.zip
index 09480d8..8cdb840 100644
Binary files a/binaries/Linux/Disc Image Manager 32 bit.zip and b/binaries/Linux/Disc Image Manager 32 bit.zip differ
diff --git a/binaries/Linux/Disc Image Manager ARM 32 bit.zip b/binaries/Linux/Disc Image Manager ARM 32 bit.zip
index 4964ca7..b064c45 100644
Binary files a/binaries/Linux/Disc Image Manager ARM 32 bit.zip and b/binaries/Linux/Disc Image Manager ARM 32 bit.zip differ
diff --git a/binaries/Linux/Disc Image Manager.zip b/binaries/Linux/Disc Image Manager.zip
index be506e8..5d4d070 100644
Binary files a/binaries/Linux/Disc Image Manager.zip and b/binaries/Linux/Disc Image Manager.zip differ
diff --git a/binaries/Windows/Disc Image Manager 32 bit.zip b/binaries/Windows/Disc Image Manager 32 bit.zip
index 638d1af..c722f3d 100644
Binary files a/binaries/Windows/Disc Image Manager 32 bit.zip and b/binaries/Windows/Disc Image Manager 32 bit.zip differ
diff --git a/binaries/Windows/Disc Image Manager.zip b/binaries/Windows/Disc Image Manager.zip
index 56af77a..95eb0e4 100644
Binary files a/binaries/Windows/Disc Image Manager.zip and b/binaries/Windows/Disc Image Manager.zip differ
diff --git a/binaries/macOS/Disc Image Manager 32 bit.dmg b/binaries/macOS/Disc Image Manager 32 bit.dmg
index 71beccb..d983234 100644
Binary files a/binaries/macOS/Disc Image Manager 32 bit.dmg and b/binaries/macOS/Disc Image Manager 32 bit.dmg differ
diff --git a/binaries/macOS/Disc Image Manager ARM.dmg b/binaries/macOS/Disc Image Manager ARM.dmg
index 6dad103..d3fd69a 100644
Binary files a/binaries/macOS/Disc Image Manager ARM.dmg and b/binaries/macOS/Disc Image Manager ARM.dmg differ
diff --git a/binaries/macOS/Disc Image Manager.dmg b/binaries/macOS/Disc Image Manager.dmg
index a4a7f7c..45f9fa0 100644
Binary files a/binaries/macOS/Disc Image Manager.dmg and b/binaries/macOS/Disc Image Manager.dmg differ