raP File Format - Elite

From Bohemia Interactive Community
Revision as of 18:18, 13 October 2009 by Mikero (talk | contribs) (→‎Class Body)
Jump to navigation Jump to search

Template:unsupported-doc

Caveat

If you are researching the nitty gritty of raP encoding for OFP or ArmA you are in the wrong place. This document is specifically for Elite raPified files on the Xbox. However, if you are not too familiar with this subject, the Introduction in the OFP version will help you best.

Changes for Elite

Two new entry types

/*extern*/ class thing;
delete /*class*/ thing;

Enhanced TokenName

name= true _variable (as opposed to name="variable";)

Non contiguous data file

Serious alterations to non-contiguous data stream. The data for class bodies is now located in a flle offset, as opposed to being directly after the class name.

Introduction

raP encoding for Xbox Files

Conventions

see Generic FileFormat Data Types

Mandatory PreReading

The Human

BI use c++ class syntax for almost everything connected with text (humanly readable) files. Anything configurable / alterable / makeable / editable by a player (author) involves creating a file or files consisting of class statements. The Mission Editor eg, creates several files for a mission consisting solely of class statements. Everything is defined or declared within classes. EVEN the cfg (configuration files) have implied class statements.

Class syntax can briefly (but accurately) be described as follows:

class thing [: InheritedClass]
{
  body
};

[: InheritedClass] is optional. It is heavily used in the config.cpp's of addons. If specified it must be referenced prior to being used.

The body of a class consists of

{
 #tokens and /or
 #arrays and /or
 #(embedded) classes and /or
 #nothing at all!  class default{};  is perfectly valid eg.
};

Any given file that contains classes, contains nothing else but classes. There aren't, classes, and ummm, err, ummm 'other' things.

The file itself is considered an implied class!

The very first statement of all files is

//class filename {

Everything within that file is embedded within the class filename {....};

The Engine

The class structure is used internally within the engine for all most game data and configuration. The engine holds this data in tokenised form for more efficient processing.

This internal tokenised data can also be held in a file (a savegame eg). But, it is a class structure regardless.

To improve loading speed many files within the ofp tree are pre-tokenised. They were 'converted' to hold the tokenised form of the same class statements.

In fact, the engine does not care which 'type' of file it is dealing with. A mission.sqm can be either. If it hasn't been pre-tokenised (eg contains text-readable class statements) the engine converts it on the fly.

Tokenised files have a magic signature as their first four bytes. "\0raP". The file extension is meaningless in this regard.

In the early days of ofp, when the campaign mission.sqm's came pre-tokenised, it was assumed wrongly, this was some attempt at encryption. They were also called 'binary' files because it was noticed that the tokenised form of a config.cpp was called config.bin (config.rap would have been far more appropriate). In fact, the engine will happily work with a config.cpp that is rap encoded.

Various utilities (tools) arrived on the internet in an attempt to decode them (and conversely, encode them). cpp2bin, bin2cpp, Coc binview are the most well known of these.

They are detailed here as 'raP' files because of their unique signature. This document refers to rapifying and de-rapifying files containing nothing but, class statements.

Xbox

Xbox raP encoding is an extension to Flashpoint PC raP encoding.

Overall Structure

struct raP
{
 char   Signature[4]; // 4 byte raP signature (\0raP)
 byte   AuthenticationSignature[20] //not on all types of file, XBOX ONLY NOT ARMA
 ulong  Always0;
 ushort Always8;
 ImpliedClassBody
 {
   byte                EntryType;          // always 0 (a class entry)
   Asciiz              ClassName;          // uniquely ""
   ulong               OffsetToEnums;  
   Asciiz              InheritedClassname; // always 0
   #CompressedInteger  nEntries;
   Entries ...         // a series of entries
 };
 Enums
 {
  ulong  nEnums;  // generally always 0
  enumlist....    // optional
 };
};

Entries consist of strings, arrays, classes, etc. The 1st byte of each entry defines what 'type' it is.

Note that ALL classes other than this first, implied class body are EMBEDDED classes within this one. This 1st, implied class is unique in that it's offset refers to the enum list rather than the location of it's class body. The class body of this class, uniquely, immediately follows the nEntries.

Furthermore, this unique class cannot have an inheritence (obviously), and their is no classname associated with it. In OFP raP the classname of this unique class was, the name of the file (config.cpp eg)

Authentication Signature

Currently unique to Xbox, not known on ArmA.

Following the four byte signature "\0 r a P" is an optional 20 byte signature intended to provide a unique value to this file and to prevent tampering. This value, or 'Authentication signature' is generated from a common 'Authentication Key' plus the content of the file itself. The Authentication key for Xbox Elite is 16 bytes and not listed here.

You can obtain source code for generating signatures elsewhere.

The signature is 'optional' only in the sense that not all types of files have it. A signature appears in .par files for example, but not in the official bis mission.sqms.

File Offset to Enumerated list

The 1st entry, being a class entry, contains a file offset to the next class at the same indent level. Since there can be more no classes at the same indent level, this offset refers to the end of all classes and the beginning of the enumerated list (if any).

There may well be, no enumerated list, there will be an ListCount saying so!

Class Body

Entry Types

Class Bodies contain Entries. Eg

{
 thing=123;
 Array[]={1,2,3};
 string="hello";
 class EmbeddedClass: [inherit]
 {
   more entries
 };
};
Entries have self defining lengths according to their type. There are five types of entry possible. Two of them newly introduced to Elite.
0 Embedded Class
1 value = (string, float, integer, variable)
2 array[]={....};
3 /*extern*/ class label;
4 delete /*class*/ label;

EntryType 0: RapClass

RapClass
{
 byte                     Type;             // 0
 Asciiz                   ClassName
 ulong                    OffsetToClassBody; 
};

Class Body

ClassBody
{
 Asciiz               InheritedClassname; // can be zero
 #CompressedInteger   nEntries;           // can be zero.
 ClassEntry           ClassEntries[nEntries];
};


All offsets in raP are relative to the start of file.

EntryType 1: Value Eq

RapValue
{
  byte   Type;   //1
  byte   SubType;
  Asciiz Aname;
  01 00 Aname="AString";
  01 01 Aname= float;
  01 02 Aname= long;
//01 03 AnArray[]= { .........}; not used
  01 04 Aname=Asciiz Variable name; // public or private

EQ Type 4: Asciiz Variable Name

This has been newly introduced to Elite (vs OFP).

A variable name (as opposed to a string constant) is as follows

Aname = "fred"; // constant
Aname=_fred;    // public or private variable

EntryType 2: array[]

RapArray
{
  byte   Type;// 02
  Asciiz ArrayName;
 #CompressedInteger nElements;
};

nElements is a declaring how many items make up the array, zero, is a legal value

Array Elements

each element of the array consists of a single subtype byte followed by appropriate data for the type. Thus

0 Asciiz string constant;
1 float
2 long
3 recursive array
4 Asciiz String variable

A recursive array recurses into further entries with no name attached.

A recursive array is as follows

AnArray[]= { {1,2} , 3,4};

EntryType 3:ExternClass

03 Asciiz Classname; // class Classname;

EntryType 4:Delete Class

04 Asciiz Classname; // delete Classname;

Extern Classes

Unlike OFP, a valuable addition to the Token types has been the definition

/*extern*/ class car;

class BigCar:car {...};
class RedCar:BigCar{...};

The tedious business of listing

class All:Default{};
class Vehicle:All{};
...
class Target:Vehicle{};
class Strategic:Target{};
class car{}:Strategic{};

simply to declate a car !!! has been done away with.

Instead, the new types deal with all things car. (or at least the engine goes looking elsewhere, which it did, anyway, in ofp).

One other immediate, and not immediately apparent, benefit, is you do not need to know anything about how the underlying class (eg CfgVehicles) is constructed.

In fact, the inheritence tree of OFP (for CfgVehicles) is different to Elite, and using the above OFP method of constructon would fail. It would not find, a Target class.


CompressedInteger

This is the same construct as found in OFP raP files.

The value is used to declare the number of entries in the class body or nArrays

enumerated list

optional

the next four bytes after all class bodie are the enumerated list count., and these defines (if any) continue until end of file.

where no list exist(the very normal case), the count is zero

A list consists of an asciiz name and integer value as follows

(manposnoweapon) {01 00 00 00}

which equates in C to

enum {
manposweapon=1,
manshower=88,
manhungry=12,
....
}

This list is encountered in some few 'official' config.cpp's. It's use by model makers is rare.