Wiimms SZS Tools/KMP
- 1 Extracting and decoding a KMP file
- 2 Editing
- 3 Encoding/Compiling and packing
- 4 Syntax
- 5 Tips and Tricks
- 6 Links
Extracting and decoding a KMP file
Extracting track files
If you have a SZS file you can extract it's content with:
wszst extract MY.szs
wszst extract --decode MY.szs
There are also some short cuts for the same command:
wszst x --dec MY.szs wszst xdecode MY.szs wszst xd MY.szs
The following command line shows a way to extract and decode the KMP of a SZS file without extracting the whole archive. The kmp command writes to stdout (standard output). Therefor a redirection with '>' is necessary.
wszst kmp MY.szs >my.kmp.txt
There are a lot of options to override the standard settings. Some important for extracting are:
- -d= --dest=dir
- Define a new destination directory in an existing parent directory.
- -D= --DEST=dir
- Define a new destination directory. All directories in the path are created automatically.
- -H --no-header
- Suppress syntax info in the head of the decoded files.
- -B --brief
- Suppress information lines in decoded KMP text files. This includes syntax information (--no-header). If set twice, the output of unneeded sections is also suppressed.
- -P --no-param
- Suppress the parameter template in decoded KMP text files.
Decoding a KMP file
If you have already an extracted KMP file, you decode it with:
wkmpt decode course.kmp
After decoding, you have a text file, typical named course.txt or course.kmp.txt. You can edit it with a text editor of your choice and can use all powerful commands of the editor. It is also possible to use scripts, batch files or other tools to modify it.
See the syntax section below.
Encoding/Compiling and packing
Encoding means to create a new KMP file using the text source. The text parser is designed as compiler and allow conditional parsing and supports variables and expressions. This make the encoding process very powerful. If using the option --const=terms, you can define constanst for the parser to create different KMP files with the same text source. Page »Wiimms SZS Tools/KMP/Tutorial« shows the power of a KMP compiler with concrete examples.
Encoding a KMP file
Encoding is as simple as decoding:
wkmpt encode course.txt
Packing a SZS file
If you have extracted a complete SZS file, you can pack it again and encoding is done automatically:
wszst create MY.d --verbose
wszst c MY.d -v
MY.d is the previous created directory containing all sub files. The tools knows (because of reading the file wszst-setup.txt) all about the extraction process. It compares the time stamps of the binary and decoded files and encode files, if they are younger or if the binary file is missed. For KMP this means: If you have edited and stored it, it will be encoded automatically, if not, the original binary file is used. An explicit encoding is not necessary.
There are a lot of options to override the standard settings. Some important are:
- -d= --dest=file
- Define an alternative destination file.
- -o --overwrite
- Overwrite already existing destination files.
- --encode-all (or --eall)
- Encode all files and ignore the time stamps.
- Compress the SZS file very fast: it becomes larger. This is useful for test cycles.
- --c= --const=terms
- Define constants for the KMP compiler.
- -v --verbose
- Be verbose and log the encoding of files.
- -t --test
- Don't create the szs archive, but print out what to do.
The KMP encoder of Wiimms SZS Tools works like a compiler with preprocessor. It support variables, C like arithmetic expressions and nested IF-THEN-ELSE structures.
All of the following documentation is also available in the header of each decoded KMP file, if not disabled by the options --no-header or --brief.
- The tools generate always windows compatible text files with CR+LF as line termination. Unix system has no problems with it. If scanning a text file, windows and Unix format is allowed.
- The first 8 characters of a KMP text file must be '#KMP-TXT'. A byte order mark (BOM) is detected and skipped.
- Spaces and tabs (=blanks) at beginning or end of line are ignored. Blanks (single or multiple) are used to separate columns.
- Empty lines (= lines containing only blanks) and lines beginning with a '#' are ignored.
- Lines beginning with a '[' signal the beginning of a new section.
- Lines beginning with a '@' are preprocessor directives.
- Lines beginning with a '$' (and followed by a name) are grouping markers or special commands.
- Lines beginning with a letter or digit are normal lines and contain lists of parameters. They may be splitted into multiple lines.
- A line beginning with a '>' is a continuation line of the previous line. The base line and all related continuation lines are logically used as one long input line.
- Names and keywords are sequences of letters (case ignored), digits and '_', '.' and '$', but never begin with a digit or '.'.
- Numbers are floats or integer values. Hexadecimal integers are prefixed with '0x'. Floats are detected by the decimal point or by an exponent.
- The text scanner accepts variable names instead of numbers in any place of the text file. If the variable does not exist, a warning is printed and value 0 is assumed → see Variables for details.
- If the text scanner expects a 2D or 3D vector and scan a variable with a vector value or expression, all components of the read vector are used to read the vector in one step.
The whole file is divided into sections. Each section starts with »[NAME]« and ends at the beginning of the next section. If the same section exists two or more times, the later one overrides the previous definitions. It is planned to change this behavior to allow a more logical definition order.
The complete source is read in 2 passes. The first pass (global variable '$PASS' is set to 1) is used to define names. Warning and error messages are suppressed. The second path ('$PASS' is set to 2) is the one that defines the objects.
The »[SETUP]« section is special and should stay at the beginning of the source file. The most important parameter is:
REVISION = number
This numeric value is used to decide, how the following sections are read and handled. This may be important if the tools change the syntax and/or semantics. Any section may have a parameter @REVISION = number to change the revision number only for the current section.
If an external tool add some sections at the end, they should first declare "@REVISION" in each section to specify the data handling. Example:
[NAME] # Use syntax and semantics of tools revision 1234 for this section @REVISION = 1234 # Calculated check points ...
→ Define and calculate global values in the setup section.
The text compiler supports variables in three name spaces: local, global and constant. The local name space is cleared every time when a new section begins. The global name space is held until the scanning is finished. The constant name space can be set by using the command line option
--const name1=val1,name2=val2,... (or -c=...)
If searching a variable the local name space is searched first, then the global name space and last the constant name space.
Some sections define automatically global variables for cross section links. The user can define local and global variables (makes development easier):
Syntax: @DEF NAME ['?']'=' EXPRESSION [, NAME= ...]... or: @GDEF NAME ['?']'=' EXPRESSION [, NAME= ...]...
'@DEF' defines a local variable and '@GDEF' defines a global variable. The type of the variable is the result type of the expression. Multiple variables can be defined using a comma as separator. An extension immediately behind the DEF command force the storing type:
[G]DEF.I: Define an integer variable. [G]DEF.F: Define a floating point variable. [G]DEF.V: Define a 3d vector (3* floating point) variable. [G]DEF.X: Define a 3d vector and overwrite/store the x member. [G]DEF.Y: Define a 3d vector and overwrite/store the y member. [G]DEF.Z: Define a 3d vector and overwrite/store the z member.
The old commands @NUM, @GNUM, @INT, @GINT, @FLOAT and @GFLOAT are still allowed for compatibility reasons as alternatives for @DEF, @GDEF, @DEF.I, @GDEF.I, @DEF.F and @GDEF.F.
NAME is the variable name: A sequence of letters (case ignored), digits and '_', '.' and '$', but never begins with a digit or '.'. If the optional '?' is set, then an existing variable is not redefined. EXPRESSION is a numerical expression (see below).
@def.i my_item = 0x0a + 3 @gdef.f origin ?= 123.4, origin2 = origin/2 @def $a.num = -12.3
If a vector with name 'NAME' is defined, then the 3 virtual variables 'NAME.X', 'NAME.Y' and 'NAME.Z' are also defined to access the 3 members. The access to these virtual variables is only possible, if no real variable with same name is defined.
If decoding a text file the scanned index names are used for the new output.
A value is a number (integer or float) or a variable name or an expression surrounded by parentheses. Each value can be preceded by any number of signs.
Syntax: VALUE := [SIGN]... OPERAND SIGN := '+' | '-' | '!' | '^' OPERAND := INTEGER | BITFIELD | FLOAT | NAME | FUNCTION | '(' EXPRESSION ')' BITFIELD := '<' [BITPARAM] '>' BITPARAM := VALUE [ ':' VALUE ] [ ',' BITPARAM ] FUNCTION := FUNCNAME '(' [PARAMLIST] ')'
Signs are calculated from right to left:
sign description --------------------------------------------------------------------- + Don't change the value. - Mathematical negation. ! Logical negation. The result is either 0 (FALSE) or 1 (TRUE). ^ Bitwise negation. The result is always an integer.
A Bitfield is an easy way to set bits in an integer. For example value <2,4:6> is an integer with bits 2 and 4..6 set (=0x74).
The text compiler supports C like numerical expressions. @IF conditions and assignments are automatically scanned for expressions. Parameters of tables are only scanned for values. Use parentheses () to force expression scanning.
Syntax: EXPRESSION := VALUE | EXPRESSION2 | EXPRESSION3 EXPRESSION2 := EXPRESSION OPERATOR EXPRESSION EXPRESSION3 := EXPRESSION '?' EXPRESSION ':' EXPRESSION OPERATOR := '**' | '*' | '/' | '%' | '+' | ...
The following operators are supported:
operator prio description -------------------------------------------------------------- ** 1 Power of * 2 Multiplication / 2 Division % 2 Modulo + 3 Addition - 3 Subtraction << 4 Shift left >> 4 Shift right > 5 Greater than >= 5 Greater than or equal < 5 Less than <= 5 Less than or equal == 6 Equal value != 6 Non equal value === 6 Equal type AND equal value !== 6 Non equal type OR non equal value & 7 Bitwise AND (parameters are converted to INT) | 8 Bitwise OR (parameters are converted to INT) ^ 9 Bitwise EOR (parameters are converted to INT) && 10 Logical AND (all non null values are TRUE) || 11 Logical OR (all non null values are TRUE) ^^ 12 Logical EOR (all non null values are TRUE) ? : 13 Alternation Syntax: EXPRESSION '?' EXPRESSION ':' EXPRESSION
The parser supports different kinds of functions. Some general functions are available for all tools, some other functions only in in a specific context like KMP parsing.
FUNCTION := FUNCNAME '(' [PARAMLIST] ')' FUNCNAME := Any combination of a-z (case ignored), 0-9 and '$'. PARAMLIST := EXPRESSION [ ',' PARAMLIST ]
For a list of supported functions use the command 'wszst FUNCTIONS' to print all general functions. To print tool (file type) specific functions, use the tool specific command 'FUNCTIONS' (like 'wkmpt FUNCTIONS').
There is also an online reference.
@IF .. @ELIF .. @ELSE .. @ENDIF
The parser supports nested if-then-else structures. Conditions are always expressions.
- @IF condition
If 'condition' is not null (=TRUE), then all lines until the next @ELIF or @ELSE of the same level are scanned and executed. Then all lines until @ENDIF are skipped. If 'condition' is null (=FALSE) all lines until the next @ELIF or @ELSE of the same level are ignored. The @IF command is the first command of a if-then-else structure.
- @ELIF condition
This is an alternative condition for an already opened @IF structure. It work like the @IF, but is only scanned if the @IF condition and all previous @ELIF conditions of the same if-then-else level are FALSE. This command is optional and can be used multiple times.
The lines behind are scanned and executed if all @IF and @ELIF conditions of the same if-then-else level are FALSE. This command is optional. If used it must be the last command before the @ENDIF command of the same if-then-else level.
A if-then-else structure is closed.
Import of SZS Modifier text
You can paste text of SZS Modifier's KMP Editor and copy it into the KMP text file.
Floats with comma (1,2) instead of a point (1.2) are always accepted. If you copy complete lines, tell the scanner to switch to the SZS-Modifier Mode. "@SZS-MODIFIER = 1" enables the mode and "@SZS-MODIFIER = 0" disables it. Instead of writing "@szs-modifier = value" you can also write the more handy "@smod value".
Example (all 4 parameter lines are identical):
[ENPT] 0 1.111 2.222 3.333 4.444 0x1234 0x5678 @szs-modifier = 1 0 1,111 2,222 3,333 4,444 12345678 @szs-modifier = 0 0 1.111 2.222 3.333 4.444 0x1234 0x5678 @smod 1 0 1,111 2,222 3,333 4,444 12345678 @smod 0
Decode the text file and copy the relevant part into the source file to get the normal layout.
wkmpt decode my.kmp.txt -d temp.kmp.txt
Tips and Tricks
If the tools read a KMP file it is transformed in an internal data structure and then written to the binary or text format. The type of source (binary or text) is detected automatically. If you have edited and changed a text KMP file and want to have a new optimized text file, just use the DECODE command with a text source:
wkmpt decode old-kmp.txt --dest new-kmp.txt
It's also possible to copy only some parts of the new created text file to the original source. This is wise if you will keep compiler instruction in the original KMP source.
ENCODE works similar. If you want to recreate a binary KMP, use:
wkmpt encode old.kmp --dest new.kmp