MexScript

From XentaxWiki
(Redirected from BMS)
Jump to: navigation, search

Introduction

BMS stands for Binary MultiEx Scripts. It is the format used by MultiEx Commander (MexCom) to "disassemble" an impressive array of GRAFs. The file format consists of a text file with a series of instructions to be run through an interpreter. The interpreter uses the instructions to traverse through a GRAF file and search for key data such as names, offsets, and sizes of various constituent files. MultiEx Commander then enables the user to extract and replace resources in these game archives.

The power of the script lies in the simple and compact use of it. A few scriptlines may be enough to support any new game resource archive, thus no hassle to code large plugins or low-level detailed scripts.

In MexCom, users can run their custom made BMS against an archive of their choice. The XeNTaX WIKI and XeNTaX Forum are the places to go to find a huge number of BMS, that could greatly help you understand the way the script works. Consequently, you can also add new BMS to the WIKI in a way that it is included in a database that can be called by MexCom. Check it here: http://wiki.xentax.com/index.php/BMS_to_Wiki

MexScriptor is a tool that comes with MexCom that enables one to write BMS scripts and save them as BMS files, which MexCom can read. The scriptor can be found in MexBinderPlus, a BMS-package tool that can save a selection of BMS-es as an MRF (MultiEx Resource File) file. In the current version of the scriptor, the Help dialog offers a rudimentary overview of the available statements.

Basics

Each line of a BMS script contains a single statement. The statement can be broken down into a series of tokens.

Each line can only contain one statement, but is nevertheless terminated by a semi-colon (;). This is superfluous, yes, but was intented to foresee multi-line statements. As it is, the need for a semi-colon will probably be removed in some future update. For now, it will need to be one space away from the last token on a line.

Remember, if you copy a BMS script from the Internet, there will often be extra spaces after the semicolons. These must be removed prior to saving, or an error will be returned.

Comments

As of version 4.3, comments are allowed, single line, preceded by a #, although single-quotes are forbidden. For example:

# Im a comment!
# But each new line needs
# its own pound sign,
# they dont "carry over".

Case Sensitivity

Statements are not case sensitive, so you could for example write IDString as idStrIng. Statements and operators are expected at the correct space-delimited column(s), so there's no need for case-sensitivity here. However, variable names ARE case-sensitive. So, if you declare a variable 'FileOffset', be sure to keep the cases when referencing this variable later on.

Variable manipulation

BMS scripts can declare variables and perform basic arithmetic operations on them and control operations with them.
To declare a new variable simply use them in a Set, Get or SavePos statement for the first time. Variables MUST have been previously declared when used in other statements.

The Set statement can be used to asign a value to a variable of your choice. This value can be any number, the value of another variable or a text string. For example, you could write Set MyVar Long 1024 ; to assign the value of 1024 to a long (32-bit) variable MyVar. Alternatively, you could write Set MyVar Long MyVar2 ; to assign the value of MyVar2 to MyVar. Finally, you could do Set MyVar String MultiEx ; and MyVar would now be a string variable with the text 'MultiEx'.

The Math statement can be used to do some simple arithmetic calculations. Math MyVar += 2 ; would then add 2 to the value in MyVar. Similarly, Math MyVar /= MyVar2 ; would divide the value in MyVar by the value in MyVar2. Note that this command will not only use the value in the target variable, but also change it to the outcome value of the operation.

Finally, the String statement will do some simple string manipulation. To be precise, it will add another string (or numeric value converted to a string) to the target string. Thus, String MyVar += MyVar2 will append the string in MyVar2 at the end of the string in MyVar. Note that when MyVar2 is a numeric value that this value will be converted to a text string and then appended to MyVar.

Control Structures

BMS scripts are executed in order from top to bottom unless an alternate control structure is encountered. These control structures include Do..While, For..Next, and the classic If..Then..Else loops.

Question: Is there any equivalent to the 'while {}' C structure or WHILE..WEND structure in BASIC? IOW, a pre-evaluation control structure instead of just the post-evaluation version? Well, you can use the IF...THEN...ELSE loop and change parameters used in the statement inside the IF control structure.

If..Then..Else

The structure of the If..Then..Else loop is as follows:

 If <var1> <operator> <var2> ;
 (do something)
 Else ;
 (do something else)
 EndIf ;

Thus, an If construction is always terminated with EndIf ; . Note also that Else ; is optional.

Do..While

The structure of the Do..While loop is as follows:

Do ;
statement 1 ;
--
statement n ;
While condition ; 

Condition compares 2 values, e.g., a variable and a constant, and branches execution back to statement 1 if the condition is evaluated to be true. The available comparison operators are:

< - less than
> - greater than
<> - not equal to
= equal to
>= greater than or equal to 
<= less than or equal to

For..Next

The structure of the For..Next loop is as follows:

For I = 1 to M;
statement 1 ;
--
statement n ;
Next I ;

This example performs the sequence of statements between the the For and Next statements for M iterations.

Statement Reference

CLog

CLog name offset size offsetoffset resourcesizeoffset uncompressedsize uncompressedsizeoffset;

The CLog statement is similar to the Log statement and signals to the interpreting engine that it has found the information for a particular compressed resource including the resource's name, absolute offset within the GRAF file, the number of contiguous bytes it occupies in the GRAF, the offsets of the aforementioned offset and size parameters in the GRAF, the uncompressed size of the resource (if known) and the position of the uncompressed size of the resource in the archive.

  • name: A text string indicating the resourcename. If the resourcename can not be determined, set this to NULL ("").
  • offset: The absolute offset of the resource within the GRAF.
  • size: The number of contiguous bytes that the resource occupies in the GRAF beginning from offset.
  • offsetoffset: the offset of the variable in the GRAF that points to the offset of the resource. This is needed for Replacement support (see ImpType statement).
  • sizeoffset: the offset of the variable in the GRAF that is the size of the resource. This is needed for Replacement support (see ImpType statement).
  • uncompressedsize : The size in bytes the resource would occupy after decompression.
  • uncompressedsizeoffset : The offset of the variable in the GRAF that specifies the original size of the resource.

Do

Do ; 

The Do statement marks the beginning of a Do..While control structure.

FindLoc

FindLoc <var> <datatype> <text/number> <filenumber>

FindLoc searches for a string in the open file and returns its offset in a user variable when found.

Example :
FindLoc MyOffset String RIFF 0 ;

Will look for the string 'RIFF' in file 0 and when found load MyOffset with the offset.

For

This is part of a standard For...Next loop.

Example :

For T = 1 To FileNum
{some chore}
Next T

This will load T with the value 1 and do {some chore} Filenum (whatever the number that is loaded there) times. The For loop will be closed with the Next statement. Specification of the loop variable (T in this case) is obligatory.

Get

Get VarName Type File

Will load (and create if necessary) the variable 'VarName' (any name will do) with the value of datatype Type that is found from the current file position of file File. Example:

Get FC Long 0

This would load (and create) a variable named FC with the 32-bit value that can be found frome the current position in File 0. File 0 is in this case the file that should be processed using the script, usually the game resource archive.

A number of data types are possible:

Long --> 32-bit value (4 bytes, Little endian) 
Int --> 16-bit value (2 bytes, Little endian)
Byte --> 8-bit value (1 byte)
ThreeByte --> 24-bit value (three bytes, Little endian)
String --> null-terminated string of characters (a string ending with a 0 byte)

GetDString

GetDString VarName NumberOfCharacters File

Gets a string of characters of NumberOfCharacters length from file File and saves it into the variable 'VarName'. Usefull when strings are not null-terminated, but of preDetermined size (hence the D in the statement).

GoTo

GoTo pos file ;

The GoTo statement causes the interpreter to jump to a specified offset with the GRAF file.

  • pos: The offset to jump to.
  • file: The open file to perform this command on. Usually this is file 0 (the archive). The BMS is run on a game archive, which is automatically file 0. Any new files opened from within the script with an Open statement will get a new number, in an incrementing way.

IDString

IDString filenumber bytes ;

The IDString statement compares bytes in order to check for an identifying signature. If the signature does not match, the BMS script terminates.

  • filenumber: the ID string applies to a file with this number (0 = main archive). The strings always start at offset 0.
  • bytes: The raw text bytes to compare against. Note that this is not a typical string since it is not enclosed in quotes. It is just raw text bytes which means it cannot have spaces.

Example usage:

IDString 0 BIFFV1 ;

This statement verifies that the first 6 bytes of a file (offsets 0..5) contain the characters "BIFFV1" which is the signature for the Baldur's Gate BIFF format.

ImpType

ImpType is used to tell MultiEx that a format is supported for Resource replacement, the offsets of the parameters which denote the Size and/or Offset of the Resources should be specified in the Log or CLog statement.

ImpType can be :

    • Standard: tells MultiEx that offsets of ResourceOffset and ResourceSize parameters are specified and will be Logged.
    • StandardTail: tells MultiEx that the Resource info is not in a header, but in a tail, and therefore further upstream than all actual resource data, and tells MultiEx that offsets of ResourceOffset and ResourceSize parameters are specified and will be Logged.
    • SFileSize : tells MultiEx that only offsets of ResourceSize parameters can be specified in the Log statement
    • SFileOff : tells MultiEx that only offsets of ResourceOffset parameters can be specified in the Log statement

Log

Log name offset size offsetoffset resourcesizeoffset ;

The Log statement signals to the interpreting engine that it has found the information for a particular resource including the resource's name, absolute offset within the GRAF file, the number of contiguous bytes it occupies in the GRAF, and the offsets of the aforementioned offset and size parameters in the GRAF.

  • name: A text string indicating the resourcename. If the resourcename can not be determined, set this to NULL ("").
  • offset: The absolute offset of the resource within the GRAF.
  • size: The number of contiguous bytes that the resource occupies in the GRAF beginning from offset.
  • offsetoffset: the offset of the variable in the GRAF that points to the offset of the resource. This is needed for Replacement support (see ImpType statement).
  • sizeoffset: the offset of the variable in the GRAF that is the size of the resource. This is needed for Replacement support (see ImpType statement).

Math

Math var1 op var2 ;

The Math statement performs an arithmetic operation on a variable.

  • var1: The variable to be modified.
  • op: The arithmetic operation to be performed. Operations include:
    • += : Add var2 to var1 and store the sum in var1.
    • *= : Multiply var1 by var2 and store product in var1.
    • /= : Integer divide var1 by var2 and store the quotient in var1.
    • -= : Subtract var2 from var1.
  • var2: The value to apply to first variable. Note that this can be either a variable or a constant value.

Next

Next VarName

See also the For statement. Marks the end of a For loop assigned to variable 'VarName' and increments the value in 'VarName' after which the code in the loop will start from the top, unless the value in 'VarNam' matches the criterium in the For statement.

Open

Open Folder/Specifier Filename/Extension File


The open statement will open a specified file. The folder needs to be specified seperately in MultiEx3. Alternatively, one can specify a folder-alias/label:

FileDir : Same folder as the archive that is processed (i.e. file 0)
FDDE    : Same folder as the archive, same name as the archive, but different extension. 

You must also provide the handle the file should get (i.e. 0 = main archive, and all newly opened files should get incrementing handles like 1, 2, 3 etc.)

Examples:

Open FDDE FAT 1 ;
This will open a file of the same name as the archive and in the same folder, 
but with the extension *.fat, with handle 1. 

Open FileDir sector.h 1 ;
This will open a file called sector.h in the same folder as the main archive, with handle 1.

SavePos

SavePos VarName File

Get the current position in file File and store it in a variable named 'VarName'

Set

Set VarName Var/Number ;

Sets the variable 'VarName' to the value specified (Number) or to the value of another variable.

Examples:

Set A B ;
Set A 1024 ;

In the first statement A is set to the value in B. In the second, A is set to the value 1024.

While

Do ;
{some chore}
While Varname Criterium VarName2 ;

Marks the end of a Do...While loop and checks whether the conditions to end the loop have been met. It checks whether the value in 'VarName' meets the condition in relation to the second variable 'VarName2'. See Control Structures.

String

String VarName1 +=/-= VarName2 

String is used to do some simple string manipulation. You can 'add' or 'subtract' another string to/from the first by using the += or -= operand. += will add it to the end, -= will subtract it from the end. You can also use a numeric variable for var2, the number will be converted to a string and then appended to the first string.

CleanExit

CleanExit

This will abort all running operations, clean up and exit the interpreter

Statements (MexScriptor's Help)

The first token on a statement line indicates what operation that line is to perform. These are the statement types: Taken from the help in MexScriptor (needs some text-formatting):

  • Set
Set
   Set <variable> <variable/number>
   1 (variable number) 2 
  • Get
Get
   Get <variable> <datatype> <filenumber>
   NOTE: <filenumber> 0 means the actual datafile
   There's no need to open it first
   NOTE: Datatype string means NULL terminated string
  • Open
Open
   Open <directory> <filename> <filenumber>

   <directory> FileDir is the dir of the first file 
    (code 504)
   This is for opening additional files
   <filenumber> must be chosen incrementingly e.g.
   0 is the actual datafile, so any additional files
   get number 1, 2, etc..
  • For
   For <variable> = <var/number> To <var/number>
   This is the standard for...next loop
  • Next
   Next <variable>
   This variable must equal the first variable used
   in the for syntax
  • GetDString
   GetDString <variable> <length (var or num)> <filenumber>
   Get a string of fixed length
  • IDString
   IDString <filenumber> <string>

    If the format starts with an Identity (magic word) string 
    in the archive file, name it here. 
    You specify which open file you refer to by the 'filenumber'. 
    The archive always is file 0. Any opened files by the script should be
    incrementingly assigned numbers.       


  • GoTo
   GoTo <var/number> <filenumber>

    Go to position (variable or number) in file. 
  • Math
   math <var> <math spec> <var/number>

   Do a mathematical operation on <var>,
   with specifiers as shown below in this 
   help text. 
  • Log
   Log <var name> <var offset> <var size> <var/num offoff> <var/num sizeoff>
    
   You must log the file info you got out of an 
   archive for each individual file in there, 
   for MultiEx Commander. MultiEx Commander uses
   this log to show archive contents and extract/import
   from/into archives. See also CLog. 
  • SavePos
   SavePos <var> <filenumber>
    
   This will save the actual filepointer 
   (the current position in a file)
   as a long in a variable of your choice. 
  • ImpType
   ImpType <Imptype>
    
   Specify what the condition is for Importing
   into the archive. See below for options. 
   Make sure you give enough info to the 
   Commander in the Log you create to be able 
   to support importing. You need to be able 
   to tell the Commander the exact position
   of the fileinformation such as Offset and Size
   in the archive, so when asked to import the 
   Commander can update these variables in the 
   archive as well, or things get pretty messy. 
  • GetCT
   stands for Get Character-Terminated
   GetCT <variable> <datatype> <character> <filenumber>

   Get a variable from a file 
   (a long, byte, string etc. ) 
   that is terminated with a specific character. 
   So, suppose there are strings for filenames 
   that end with the sign @ every time. 
   GetCT FileName String @ 0 
   would then load a string into the variable 
   FileName from file 0 (the archive) until it 
   reached the @ sign in the file. 
  • ComType
   Specify the compression type
   Zlib1 : Standard Zlib compression
   ComType <ComType>
  • CLog
   when you have specified a compression type you MUST use
   this log event instead of 'Log'
   CLog <var name> <var offset> <var size> <var/num 
   offoff> <var/num sizeoff> 
   <var/num OrSize> <var/num OrSizeOff>
  • FindLoc
   FindLoc <var> <datatype> <text/number> <filenumber>
   Find location of a certain string or number in
   filenumber. That is , only text is regarded as a
   string, only numbers as something you specify (byte, int, long)
   the found location will be stored in <var>iable.
   NOTE: ONLY A STRING PLEASE !!! THE OTHERS HAVE NOT BEEN CHECKED
  • String
   String <var1> <operator> <var2> 
   
   String is used to do some simple string manipulation.
   You can 'add' another string to the first by using the += operand.
   You can also use a numeric variable for var2, the number will
   be converted to a string and then appended to the first string. 
  • CleanExit
   CleanExit ;    
   This will abort all running operations, clean up and exit the interpreter 

Examples

Remember, this wiki already offers a lot of examples of BMS scripts, while you can get another huge list at the XeNTaX forum.

Here we will explain a few step-by-step.