Scripting (experimental)

Scripting is a powerful extension of RAID Reconstructor's capabilities. Based on the PASCAL programming language, scripts allow you to access your drives and process them with all the elements available in a higher programming language.

In order to take full advantage of this feature, knowledge of PASCAL is required.

NOTE: Scripting is experimental and at this time no integral part of RAID Reconstructor. Use at your own discretion. No support is provided on script writing.

Load and Run a Script

To load a script into the editor, double-click an entry on the left side or click on File->Load. To run a loaded script press F9.

Example Scripts

Please inspect the sample scripts (*.scr) that come with RAID Reconstructor.

Script Name Purpose
copy_drive_to_image.scr Demonstrates how to copy a drive to an image file
drive_info.scr Shortest demo
drive_info_partitiontable.scr Display a drives partition table
iterate_through_drive.scr Go through each sector
list_mfts.scr Extract sector numbers of MFT locations into an external file
raid0_destripe.scr Reconstruct a 2 drive RAID-0
raid0_3drives_destripe.scr Reconstruct a 3 drive RAID-0

Reference - Special Functions

Function Purpose Example
class TBinData Basic buffer structure, used to store sector data  
function TBinData.CreateZero(Cnt: integer): TBinData; Creates a TBinData with Cnt bytes. All bytes are initialized to 0 BD := TBinData.CreateZero(512);
function TBinData.CreateFromString(S: string[; Encoding: string=BYTES|ANSI|UTF8|OEM|UNICODE|HEX]): TBinData; Creates a TBinData from a string;
Encoding can be:
BYTES (uninterpreted 1-byte characters) (Default),
ANSI (interpreted 1-byte characters),
UTF8 (interpreted multi-byte UTF8 characters),
UNICODE (uninterpreted 2-byte characters),
OEM (interpreted as 1-byte OEM characters),
HEX? (as 1-byte hex values with ? as delimiter)
BD := TBinData.CreateFromString('ABC');
BD := TBinData.CreateFromString('414243', 'HEX');
//creates TBinData with 3 bytes: $41,$42,$43
BD := TBinData.CreateFromString('ABC', 'UNICODE');
//create 6 bytes: $41,$00,$42,$00,$43,$00
function TBinData.Copy(Offset, Len: integer): TBinData; Duplicates the TBinData, with bytes beginning at Offset, with a length of Len. BD := TBinData.CreateFromString('ABC');
BD2 := BD.Copy(2,1);
//BD2 contains 'C'
function TBinData.String(Offset: integer[; Len: integer[; Encoding: string=BYTES|ANSI|UTF8|OEM|UNICODE|HEX]]): string Creates a string from TBinData.
Encoding can be:
BYTES (uninterpreted 1-byte characters) (Default),
ANSI (interpreted 1-byte characters),
UTF8 (interpreted multi-byte UTF8 characters),
UNICODE (uninterpreted 2-byte characters),
OEM (interpreted as 1-byte OEM characters),
HEX? (as 1-byte hex values with ? as delimiter)
BD := TBinData.CreateFromString('410042004300', 'HEX');
S := BD.String(0, maxint, 'UNICODE');
//S contains 'ABC'
procedure TBinData.SetByte(Offset, B: integer); Set byte at Offset to B BD := TBinData.CreateFromString('ABC');
BD.SetByte(0, 64);
//BD now contains '@BC'
function TBinData.Bytes(Offset, Len: integer; Signed: string): int64; Returns the number at Offset, Len in Little-Endian notation. Maximum for Len is 8. If Signed is 'SIGNED' the two-complement of the number will be returned. BD := TBinData.CreateFromString('FFFFFFFF','HEX');
I := BD.Bytes(0, 4);
//I is 4294967295
I := BD.Bytes(0, 4, 'SIGNED');
//I is -1
function TBinData.BytesAsStr(Offset, Len: integer; Signed: string): int64; Same as Bytes but returns the number as string  
function TBinData.BytesAsStrT(Offset, Len: integer; Signed: string): int64; Same as Bytes but returns the number as string with thousand delimiters  
function TBinData.BytesAsHex(Offset, Len: integer; Signed: string): int64; Same as Bytes but returns the hex representation of the number. BD := TBinData.CreateFromString('FFFFFFFF','HEX');
S := BD.BytesAsHex(0,4);
//S contains 'FFFFFFFF'
S := BD.BytesAsHex(0,4,'SIGNED');
//S contains 'FFFFFFFFFFFFFFFF' (-1 in int64)
function TBinData.BEBytes(Offset, Len: integer; Signed: string): int64; As Bytes, but using Big-Endian notation  
function TBinData.BEBytesAsStr(Offset, Len: integer; Signed: string): int64; As BytesAsStr, but using Big-Endian notation  
function TBinData.BEBytesAsStrT(Offset, Len: integer; Signed: string): int64; As BytesAsStrT, but using Big-Endian notation  
function TBinData.BEBytesAsHex(Offset, Len: integer; Signed: string): int64; As BytesAsHex, but using Big-Endian notation  
property TBinData.Count: integer; Get or set the number of bytes in the TBinData structure. Existing bytes lower than Count are being preserved. New bytes are initialized to 0 BD := TBinData.CreateFromString('ABC');
I := BD.Count;
//I is 3
BD.Count := 4;
//BD is $41,$42,$43,$00
function TBinData.GetPointer: pointer; Returns a pointer to the buffer containing the data of the TBinData structure BD := TBinData.CreateFromString('ABC');
P := BD.GetPointer;
//P now points to a memory area containing $41,$42,$43

procedure TBinData.Append(BD: TBinData); Appends an existing TBinData structure with another one BD := TBinData.CreateFromString('ABC');
BD2 := TBinData.CreateFromString('DEF');
//BD now contains 'ABCDEF'
procedure TBinData.SetUpcase; Upcases all bytes in the TBinData structure, if possible BD := TBinData.CreateFromString('abc');
//BD now contains 'ABC'
function TBinData.Pos(Needle: TBinData; Index: integer): integer; Searches for Needle bytes in a TBinData, beginning at Index. First index is 0. Returns -1 if not found, otherwise the offset in the TBinData structure BD := TBinData.CreateFromString('ABCDEF');
Needle := TBinData.CreateFromString('CD');
I := BD.Pos(Needle);
//I is 2
Drive functions    
function Drives(D: string): TDrive; Define a drive Drive := Drives('hd128');
Drive := Drives('c:\myimage.img');
Drive := Drives['D:');
function Drives(i: integer): TDrive; Define a drive Drive := Drives(128);
class TDriveList    
function BuildDriveList(DriveString: string): TDriveList Generates the DriveList DriveList := BuildDriveList('HD128:,HD129:,C:,D:);
function DriveList.GetDrive(No: integer): TDrive; Return a drive from the drivelist Drive := DriveList.GetDrive(0);
function DriveList.Count: integer; Returns number of drives in DriveList Cnt := DriveList.Count;
class TDrive    
function Drive.InfoCapaciy: string; Capacity of the drive as string ShowMessage(Drive.InfoCapacity);
function Drive.TotalSectors: int64; Capacity of the drive in sectors, returns an int64. ShowMessage(IntToStr(Drive.TotalSectors));
function Drive.ReadAsPointer(LBAStart, Count: int64; Buffer: pointer; var ErrCode: integer): boolean; Read from the drive into a buffer GetMem(Buffer, 512);
if Drive.Read(0, 1, Buffer, ErrCode) then
  ShowMessage('Error ' + IntToStr(ErrCode));
function Drive.Read(LBAStart, Count: int64; var Error: integer): TBinData; Read from the drive into a TBinData structure Sector := Read(0, 1, ErrCode);
SomeStream.WriteBuffer(Sector.GetPointer, Sector.Count);
function Drive.DriveLetter: string; Returns the drive letter, e.g. HD128:, C:, C:\image.img ShowMessage(Drive.DriveLetter);
procedure Drive.FirstSector; Set drive to the first sector Drive.FirstSector;
while not Drive.EndOfDrive do
    WriteImage(Image, Drive.GetSector);
procedure Drive.NextSector[(IncBy: int64)]; Move to the next sector
function Drive.EndOfDrive: boolean; Test if end of drive is reached
function Drive.GetSector: TBinData; Read current sector into a TBinData buffer
function Drive.CurrentSector: int64; Determine the current sector (int64)
procedure Drive.LastSector; Set drive to the last sector Drive.LastSector;
procedure Drive.GotoSector(Sec: int64); Move to a sector Drive.GotoSector(1000);
function Drive.GetSectorAsPointer: pointer; Read one sector into a buffer P := Drive.GetSectorAsPointer:
function Drive.ReadSectors(NumSecs: integer): TBinData; Read NumSec sectors into a TBinData buffer, starting with the current sector BD := Drive.ReadSectors(128):
function Drive.String(Ofs: integer[; Len: integer[; Encoding: string=BYTES|ANSI|UTF8|OEM|UNICODE|HEX[; Sec: int64]]]): string;


Returns the string starting at Ofs, length Len of the current sector, or, sector Sec if provided. If Len is not provided, the data from the current offset to the end of the sector is used.
Encoding can be:
BYTES (uninterpreted 1-byte characters) (Default),
ANSI (interpreted 1-byte characters),
UTF8 (interpreted multi-byte UTF8 characters),
UNICODE (uninterpreted 2-byte characters),
OEM (interpreted as 1-byte OEM characters),
HEX? (as 1-byte hex values with ? as delimiter)
S :=Drive.String(0, 4, 'BYTES', 0);
//S is 'NTFS'
S :=Drive.String(0, 4, 'ANSI', 0);
//S is 'NTFS'
S :=Drive.String(0, 4, 'UTF8', 0);
//S is 'NTFS'
S :=Drive.String(0, 4, 'UNICODE', 0);
//S is '??'
S :=Drive.String(0, 4, 'HEX-', 0);
//S is '4E-54-46-53'
function Drive.Bytes(Ofs, Len: integer[; Sec: int64]): int64; Returns the value starting at Ofs, length Len of the current sector, or, sector Sec if provided. I := Drive.Bytes(8, 5);
//I is 123456890
function Drive.BytesAsStr(Ofs, Len: integer[; Sec: int64]): int64; same as Drive.Bytes but returning a string representation of the value S := Drive.BytesAsStr(8, 5);
//S is '1234567890'
function Drive.BytesAsStrT(Ofs, Len: integer[; Sec: int64]): int64; same as Drive.Bytes but returning a string representation with thousand delimiters of the value S := Drive.BytesAsStrT(8, 5);
//S is '1,234,567,890'
function Drive.BytesAsHex(Ofs, Len: integer[; Sec: int64]): int64; same as Drive.Bytes but returning a string representation of the value S := Drive.BytesAsHex(8, 5);
//S is '499602D2'
function Drive.Entropy: float Shannon entropy of current sector F := Drive.Entropy;
//f is between 0.00 and 1.00
function Drive.DriveKind: integer; Indicates the kind of drive:
0: Physical drive (HD128:,...)
1: Logical drive (C:,D:,...)
2: Image file (*.img, *.imc)
3: Virtual image file (*.vim)
4: Remote physcial drive
I := Drive.DriveKind;
function Drive.Info: string; Returns a more descriptive string for the drive, e.g. "1st hard drive 466 GB (HD128:) - ST95005620AS" S := Drive.Info
function Drive.Partition(i: integer): TPartItem Returns a drive's partition at index i, 0-based Part := Drive.Partition(0);
function Drive.PartitionCount: integer; Number of partitions on drive I := Drive.PartitionCount;
class TPartItem    
function PartItem.Info: string Descriptive string for this partition S := Drive.Partition.Info;
if Drive.Partition(1).IsExtended then
  S := 'Extended ' + Drive.Partition(1).Info
  S := 'Primary ' + Drive.Partition(1).Info;
function PartItem.IsExtended: booleean; Indicates if this is a primary or extended partition
function PartItem.StartSector: int64; This partition's start sector on the drive I := Drive.Partition(1).StartSector;
function PartItem.Sectors: int64; Length in sectors of this partition I := Drive.Partition(1).Sectors;
function PartItem.Type: integer; Type of this partition, e.g. NTFS I := Drive.Partition(1).Type;
Memory functions    
procedure GetMem(var P: pointer; MemSize: integer); Allocate a buffer GetMem(P, 1024);
//do something with P
procedure FreeMem(P: pointer); Free a buffer
Image functions    
function CreateImage(FileName: string; Compressed: boolean): integer; Create a new image file for output Image := CreateImage('c:\newimage.img', false);
while not Drive.EndOfDrive do
    WriteImage(Image, Drive.GetSector);
function WriteImage(Image: integer; Sec: string): integer; Write a string (sector) to the image file
procedure CloseImage(Image: integer); Close image file
class TFileStream    
function TFileStream.Create(FileName: string; FileMode: integer): TFileStream; Create new file FStrm := TFileStream.Create('somefile', fmCreate);
  Sectors := Drive.GetSector;
  FStrm.WriteBuffer(Sectors.GetPointer, Sectors.Count);
procedure TFileStream.WriteBuffer(P: pointer; Size: integer); Write to TFileStream
procedure TFileStream.Free; Free the object
Statusline functions    
procedure ShowStatus(Info: string); Display a message in Scripter's window ShowStatus('Current Sector' + IntToStr(Drive.CurrentSector));
procedure SetStatusRefreshRate(MS: integer); Set the refresh rate of the status message in Millie seconds SetStatusRefreshRate(10);
MessageDlg(Msg: string; DlgType; Buttons: variantarray): integer; Displays Windows' message dialog if MessageDlg('File exists. Overwrite?', mtConfirmation, [mbYes,mbNo]) = mrYes then
File functions    
function FileExists(FileName: string): boolean; Tests if a file already exists if FileExists('c:\myimage.img') then
Conversion routines    
function PartTypeToString(PartType: integer): string; Converts partition type into a string, e.g. 7 -> 'NTFS' S := PartTypeToString(Drive.Partition(1).Type);
function PartitionGUIDToString(GUID: string): string; Converts GPT partition GUID into a string, e.g. 'EBD0A0A2-B9E5-4433-87C0-68B6B72699C7' -> 'Windows or Linux data partition' S := PartitionGUIDToString('EBD0A0A2-B9E5-4433-87C0-68B6B72699C7');
function FmtSignificanceByte(i: int64; digits: integer): string; Converts a byte number S := FmtSignificanceByte(1000000, 4);
//returns '976.6 KB'
function IntToStr(i: int64): string; Converts an int64 to a string S := IntToStr(12345);
//returns '12345'
function IntToStrT(i: int64): string; Converts an int64 to a string with thousand delimiters S := IntToStrT(12345);
//returns '12,345'
function IntToHex(i: int64[; MinDigits, MaxDigits: integer]): string; Converts an int64 to a hex string S := IntToHex(12345);
//returns '3039'
S := IntToHex(12345, 8);
//returns '00003039'
S := IntToHex(12345, 4, 2);
//returns '39'
function IntToDual(i: int64[; MinDigits: integer]): string; Converts an int64 to a binary string S := IntToDual(12345);
//returns '11000000111001'
S := IntToDual(12345, 16);
//returns '0011000000111001'
function StrToInt(s: string): int64; Converts a string to an int64 I := StrToInt('12345678901234');
//returns 12345678901234
Bit operations    
function Int32OR(i1, i2: integer): integer; Returns i1 OR i2. Use instead of bug with OR operator. i := Int32OR(1, 2);
//returns 3
function Int32AND(i1, i2: integer): integer; Returns i1 AND i2. Use instead of bug with AND operator. i := Int32AND(1, 3);
//returns 1
function Int32SHL(i1, i2: integer): integer; Returns i1 SHL i2. Use instead of bug with SHL operator. i := Int32SHL(1, 2);
//returns 4
function Int32SHR(i1, i2: integer): integer; Returns i1 SHR i2. Use instead of bug with SHR operator. i := Int32SHR(7, 2);
//returns 1
function Int64DIV(i1, i2: int64): int64; Divide two int64 numbers I := Int64DIV(10,3);
//returns 3
function Int64MOD(i1, i2: int64): int64; Modulo of two int64 numbers I := Int64MOD(10,3);
//returns 1
function Int64SHL(i1, i2: int64): integer; Returns i1 SHL i2. i := Int64SHL(1, 2);
//returns 4
String routines    
function Token(No: integer; s: string; Separator: string): string; Extracts token No. 1-based S := Token(2, 'Monday;Tuesday', ';');
//returns 'Tuesday'
function TokCount(s, Separator: string): integer; Counts the number of tokens in s I := TokCount('M,T,W,T,F,S,S', ',');
//returns 7
function ParseTag(Src, StartTag, StopTag: string; var Index: integer): string; Extract tokens delimited by start/stop tags S := 'Drive HD128: 1TB'#13#10'Drive HD129: 2TB';
i := 1;
ShowMessage(ParseTag(S, 'Drive ', ':', I));
//returns 'HD128', I is 13
ShowMessage(ParseTag(S, 'Drive ', ':', I));
//returns 'HD129'
function CalculateString(Expression: string): float Compute the mathematical expression. Accepts hex prefixes $ and 0x
Ln, Exp, Abs
F := CalculateString('5+6*2');
//returns 17
function Replace(StoDel, StoIns, s: string): string; Replace all occurrences of StoDel in s with StoIns S := Replace('ell', 'oh', 'hello');
//returns 'hoho'
function Replicate(s: string; Cnt: integer): string; Return Cnt times the string s S := Replicate('ab', 4);
//returns 'abababab'
function EnCodeStr(s: string): string; Encodes s in base64 S := EnCodeStr('abc');
//returns 'abc'
function DeCodeStr(s: string): string; Decodes a base64-encoded string
function Reverse(s: string): string; Reverses a astring S := Reverse('123');
//returns '321'
function GroupString(s: string; CharsPerGroup: integer; Delimiter: string): string; Groups a string into of groups of CharsPerGroup characters each. Groups are delimited with Delimiter S := GroupString('EF1C77', 2, ' ');
//returns 'EF 1C 77'
function HexStringToGUID(s: string): string; Returns a 32-character Hex string formatted as a GUID S := HexStringToGUID('1234567890abcdef1234567890abcdef')
//returns '78563412-AB90-EFCD-1234-567890ABCDEF'
Date and time routines    
function FileTimeToDateTime(f: float): float; Convert NTFS file timestamps to TDateTime dt := FileTimeToDateTime(f);
function FileDateToDateTime(i: integer): float; Convert DOS file timestamps to TDateTime dt := FileDateToDateTime(i);
function LinuxTimeToDateTime(i: integer): float; Convert Linux file timestamps to TDateTime dt := LinuxTimeToDateTime(i);
function HFSDateToDateTime(i: integer): float; Convert HFS file timestamps to TDateTime dt := HFSDateToDateTime(i);
function APFSDateToDateTime(i: int64): float; Convert APFS file timestamps to TDateTime dt := APFSDateToDateTime(ii);
HTML routines    
function Linked(Link, Disp: string): string; Returns an <a> tag with Link being the href attribute and Disp being the display string. S := Linked('', 'Runtime Software');
//returns <a href="">Runtime Software</a>
function MakeTable(Params: variantarray): string; Creates HTML code for a table S := MakeTable(
[[8,4],[], [],[200,100,200,100],[], [0,2], ...8x4 elements... ]);
//8 rows, 4 columns, could get table attributes as 3rd param, e.g. width="100%"
//no flags, could be 'td-right=1', number of right-aligned columns
//no heights
//4 column widths
//no header rows
//0, 2 are header columns
//8x4 elements
function BuildLink(View, DriveLetter: string; Sector: int64; Display: string): boolean; Creates a clickable <A> tag that will load the requested sector of the requested drive into the requested view. BuildLink('partition_table', 'HD128:', 0, '1st HD');
Miscellaneous routines    
function iif(Condition: boolean; s1, s2: string): string; Returns s1 if condition is true, otherweise s2 S := iif(x<0, 'negative', 'positive');
function iifarr(Needle: variant; HayArr, ThenArr: variantarray; ElseValue: variant): variant If Needle is found in array HayArr, the element with the same position in ThenArr is returned. If Needle is not found in array HayArr the variant ElseValue is returned. V := iifarr(-1, [-2, '-1', 0, 1, 2], ['-two', '-one', 'zero', 'one', 'two'], 'other'); //returns '-one'
V := iifarr(3, [-2, '-1', 0, 1, 2], ['-two', '-one', 'zero', 'one', 'two'], 'other'); //returns 'other'
function FlagArr(Flags: int64; Arr: variantarray; Delimiter: string): string; If a bit in Flags is set, the corresponding element of Arr is copied to the result, separated by Delimiter. s := FlagArr(5, ['bit0', 'bit1', 'bit2', 'bit3'], '-'); //returns 'bit0-bit2'
function VarType(V: variant): integer; Returns the type of the variant V.
0 (varEmpty)
1 (varNull)
2 (varSmallInt)
3 (varInteger)
4 (varSingle)
5 (varDouble)
6 (varCurrency)
7 (varDate)
8 (varOleStr)
9 (varDispatch)
10 (varError)
11 (varBoolean)
12 (varVariant)
13 (varUnknown)
17 (varByte)
18 (varWord)
19 (varLongWord)
20 (varInt64)
72 (varStrArg)
256 (varString)
257 (varAny)
4095 (varTypeMask)
V := 1000000;
I := VarType(V);
//returns 3''''
function VarTypeToString(V: variant): string; Returns the variant type as a string. V := 1000000;
S := VarTypeToString(V);
//returns 'varInteger'
function GlobalExists(VarName: string): boolean; Returns TRUE if the variable with the name in VarName exists B := GlobalExists('myvar');
//returns TRUE if myvar exists
procedure Swap(var X, Y: variant); Swap the contents of two variables X := 'hello';
Y := 13;
Swap(X, Y);
//X now contains 13, Y contains 'hello'
function XorSectors(Sectors: variantarray): string; XOR sec1,sec2...secx into a string S := XorSectors([sec1, sec2, sec3]);
Array routines    
function ArrayCreate(HighBound: integer): variantarray Creates a variant array with HighBound+1 elements Arr := ArrayCreate(10);
//creates an Arr with 11 elements, addressable as Arr[0]..Arr[10]
function ArrayRedim(V: variantarray; NewHighBound: integer): variantarray; Re-dimension a variant array v := ArrayCreate(6);
//v has 7 elements
v := ArrayRedim(v, 10);
//v has 11 elements
function ArrayHigh(V: variantarray): integer; Returns the index of the last element v := ArrayCreate(6);
I := ArrayHigh(v);
//I is 6
function ArrayContains(Arr: variantarray; V: variant): boolean; Tests if V is in Arr Arr := ['abc', 'def', 123];
B := ArrayContains(Arr, '123');
//returns TRUE



Reference - Variables

Variable Description
Provides a data container that is accessible over all scripts.
AvailableViews A TDictionary<string,string> with information about the available views.
AvailableViews.Items['boot_fat,VIEWNAME'] Returns the VIEWNAME of boot_fat.scr
AvailableViews.Items['*INDEX*0'] Returns the first available view
Drive: TDrive Current drive
ExtendedPartitionBase: float do not use
Sector0: float do not use
ClusterSize: integer do not use
DriveList: TDriveList List of active drives
CurrentURL: string Currently displayed URL
CurrentView: string Currently used view

Reference - Constants

Constants Description
tag_br, tag_hr '<br>', '<hr>'
Drive types (0,1,2,3)
maxint Largest possible integer: 2147483647 ($7fff ffff)
maxint64 Largest possible int64: 9223372036854775807‬ ($7fff ffff ffff ffff)
fmCreate, fmOpenRead, fmOpenWrite, fmOpenReadWrite File mode constants for TFileStream.Create
AppDir Application directory
TempDir System's temp directory
mtWarning, mtError mtInformation, mtConfirmation Message type constants
mbYes, mbNo, mbOK, mbCancel, mbAbort, mbRetry, mbIgnore, mbAll, mbNoToAll, mbYesToAll Message dialog button constants
mrNone, mrOk, mrCancel, mrAbort, mrRetry, mrIgnore, mrYes, mrNo, mrAll, mrNoToAll, mrYesToAll Message dialog result constants

Reference - System Functions


Reference - Basic PASCAL Syntax

begin .. end
procedure and function declarations
if .. then .. else
for .. to .. do .. step
while .. do
repeat .. until
try .. except and try .. finally blocks
case statements
array constructors (x:=[ 1, 2, 3 ];)
^ , * , / , and , + , - , or , <> , >=, <= , = , > , < , div , mod , xor , shl , shr operators
access to object properties and methods (ObjectName.SubObject.Property)
comments: // or (* *) or {}
variable declarations: var a;