raP File Format - OFP: Difference between revisions

From Bohemia Interactive Community
Jump to navigation Jump to search
(work in progress, hands off please.)
 
m (Work in progress)
Line 8: Line 8:
----
----


==Introduction==


Bin 2 CPP compression
raP encoding applies to any humanly readable text file in OFP that contains class statements. Examples of files that are, or should be, raPified, are mission.sqm, config.cpp, description.ext.
 
In fact, any text file that contains class statements, contains nothing else but class statements. So much so, that '''entire''' contents of that file, is considered to be a class !!!
 
eg
 
class mission.sqm
{
  ...
};
 
The fact of the matter is, if you do not raPify these files, the engine will before using them (and thus causing uneccessary cpu load)
 
raP encoding simply means that the data inherent in these types of files has been sanitised (stripped of commments and crud) and massaged into a form of indexed lookup table for the engine to use directly. Once done, it is free of the need to check for syntax errors, among other things. Hence, much much faster processing.
 
These types of files were once known as 'encrypted' or 'binarised' files. They are no such thing. They are simply a cleaner. closer equivalent to what the engine uses internally. For instance, all your savegames are raP encoded (there is no, text equivalent).
 
A raP encoded file is detected by the magic signature '\0raP' in the first four bytes of the file. Because of the leading 0 byte, no text file can inadvertently have this signature.
 
Importantly, '''the filename extension is immaterial'''.
 
The engine will work with config.'''cpp''' as a raP encoded entity, just as it would work with config.'''bin'''.
 
===Tools===
 
Various utilities exist which refer to binary <> cpp compression and extraction (or encoding and decoding). Again, these terms are misleading because the file concerned is not executable binary data, just tokenised strings and values.
 
===Basics===
There is no need here to elaborately define what a mission.sqm file is. But, it is worth understanding the basics of these (types of) files to understand the <u>very small</u> requirements needed to raPify them.
 
class files only contain one of 3 types of construct
 
#names
#variables
#classes


The mission.sqm contained within the three official Bis campaigns is compressed and not directly readable by a text editor such as notepad. Some refer to this as being encrypted, which is misleading. It might be true that by compressing these files Bis intended by proxy to make them 'encrypted', but, essentially, they are simply compressed data similar in intent to zip, rar or pbo files.
Various utilities exist which refer to binary <> cpp compression and extraction (or encoding and decoding). Again, these terms are misleading because the file concerned is not executable binary data, just compressed strings and values.
The intention of this compression is to reduce the quantity of identically named strings and produce a 'binary' file that closely reflects the overall, and very minimal, construct of the text version of any sqm file. The construct of a sqm file is minimal and quite rigid. There is no need here to elaborately define what a sqm file is. But, it is worth understanding the basics of these files to understand the very small requirements needed of a compression utility. The end result is that the structure, the construct, of an 'encrypted' file represents very closely how the ofp engine works with all text data internally.
sqm's only contain one of 3 types of construct
names,
variables,
classes,
names are  names = variable;
names are  names = variable;
variables come in 4 flavours
variables come in 4 flavours
name="A string";
name=77;   // short integer
aString="A string";
name= 1.855; // float
anInteger=77;  
name[]={......}; // an array containing more name's including (possibly) more arrays or more variables
aFloat 1.855; // float
anArray[]={......};  
  // an array containing more name's including (possibly) more arrays or more variables
 
 
  thing[]={ 1.0,  7.67,  "Elephants", fred[]={......} };
 


            thing[]={ 1.0,  7.67,  "Elephants", fred[]={......} };
raPifying encodes each of these basic types.


A compression utility encodes each of these basic types;
The only other construct of a sqm file is the class
The only other construct of a sqm file is the class
class classname [:inherit] { ...};
 
They are very similar to arrays[] and may contain multiply embedded classes;
class classname [:inherit] { ...};
 
[:inherit] is optional and simply refers to another classname
[:inherit] is optional and simply refers to another classname
This is the only other construct that a compression utility needs to encode.
This is the only other construct that a compression utility needs to encode.
An encrypted 'binary file' encodes everything as
 
class filename
==Construct==
{
 
all raPified data can be expressed as
 
class filename
{  
     number of embedded classes
     number of embedded classes
        lots of embedded classes and variables
    class FirstEmbeddedClass
};
    {
      number of embedded classes in this class
      ... variables
      class FirstEmbeddedEmbeddedClass
      {
        ...
      };
      ...
    };
    ...
    class LastEmbeddedClass
    {
    };
  };
       
number of #defines (optional)
number of #defines (optional)
#define table (if any)
#define table (if any)
the beginning class, the filename, is not recorded in the humanly readable text output.
the beginning class, the filename, is not recorded in the humanly readable text output.
See below for #defines
See below for #defines
A compressed mission sqm has the first 7 bytes of the file encoded as follows:
 
"\0raP\004\0\0"
==Header===
 
A raPified file the first 4 bytes of the file encoded as follows:
"\0raP"
 
For OFP and RESISTANCE the '''next''' three bytes are
 
\004\0\0"
 
see elsewhere for Elite and ArmA)
 
The rest of the file contains packets of 3 different construct types as noted above with the 1st byte defining what 'type' it is.
The rest of the file contains packets of 3 different construct types as noted above with the 1st byte defining what 'type' it is.
Thus
Thus
struct Packet
struct Packet
{
{
     byte    PacketType; // 0,1 or 2
     byte    PacketType; // 0,1 or 2
     ....... depends on packet type
     ....... depends on packet type
};
};
 
Packet Type 0: Classname
Packet Type 0: Classname
Packet Type 1: Variables
Packet Type 1: Variables
Packet Type 2: Arrays
Packet Type 2: Arrays
The very first packet encountered is a classname. It is the enclosing class for *everything* else in the file. The name of his class is the name of the file. It is *not* recorded in humanly readable text output.
 
Packet Type 0: Classname
'''The very first packet encountered is a classname. It is the enclosing class for *everything*  
class Classname: InheritedClassName {  Packets... };
else in the file. The name of his class is the name of the file. It is *not* recorded in humanly
struct ClassPacket
readable text output.'''
{
 
byte PacketType; // = 0 == class
==Packets==
IndexedString Classname;
===PacketType0: Classname===
Asciiz InheritedClassName; // optional or zero length string
 
BIS_short nImbeddedPackets; // Iterates thru embedded Packet(s) can be zero
class Classname: InheritedClassName {  Packets... };
};
struct ClassPacket
Packet Type 1 Variables
{
  byte PacketType; // = 0 == class
  IndexedString Classname;
  Asciiz InheritedClassName; // optional or zero length string
  BIS_short nImbeddedPackets; // Iterates thru embedded Packet(s) can be zero
};
 
===PacketType1:  Variables===
 
The first byte of this packet defines what type of variable. Thus
The first byte of this packet defines what type of variable. Thus
struct VarPacket
 
{
struct VarPacket
byte PacketType; // = 1
{
byte VarType; // = 0 to 2
  byte PacketType; // = 1
IndexedString SomeName;
  byte VarType; // = 0 to 2
.... depends on VarType
  IndexedString SomeName;
};
  .... depends on VarType
VarType0   String
};
VarType1    Float
 
VarType2    LongInteger
====VarType0 String====
SomeName="SomeOtherName";
SomeName="SomeOtherName";
struct VarTypString  
 
{
struct VarTypString  
byte PacketType; // = 1
{
byte VarType; // = 0
  byte PacketType; // = 1
IndexedString SomeName;
  byte VarType; // = 0
IndexedString SomeOtherName;
  IndexedString SomeName;
};
  IndexedString SomeOtherName;
};
====VarType1 Float====
SomeName=1.23445;
SomeName=1.23445;
struct VarTypFloat
 
{
struct VarTypFloat
byte PacketType; // = 1
{
byte VarType; // = 1
  byte PacketType; // = 1
IndexedString SomeName;
  byte VarType; // = 1
float value; // 4 bytes
  IndexedString SomeName;
};
  float value; // 4 bytes
};
====VarType2 Integer====
SomeName=123;
SomeName=123;
struct VarTypLongInteger
struct VarTypLongInteger
{
{
byte PacketType; // = 1
  byte PacketType; // = 1
byte VarType; // = 2
  byte VarType; // = 2
IndexedString SomeName;
  IndexedString SomeName;
int value; // 4 bytes
  int value; // 4 bytes
};
};
 
===PacketType2: Arrays===
Arrays[] contain four possible element types. They are the traditional variables mentioned above with an added tweak of an embedded array type.


Packet Type 2 Arrays
Arrays[] contain one of four element types. They are the traditional variables mentioned above with an added tweak of an embedded array type. Here, i refer to them as constants, simply because they are stand alone values, not associated with a name
thus
thus
SomeName[]={ constant,constant[],constant,....};
 
struct ArrayPacket
SomeName[]={ Element,Element[],"element",....};
{
 
byte PacketType; // = 2
struct ArrayPacket
IndexedString SomeName;
{
BIS_short nConstTypes; // iterate thru ConstTypes, can be 0
  byte PacketType; // = 2
.... depends on ConstTypes
  IndexedString SomeName;
};
  BIS_short nConstTypes; // iterate thru ConstTypes, can be 0
ConstType0 String
  .... depends on ConstTypes
ConstType1 Float
};
ConstType2 LongInteger
 
ConsType3 Embedded_Array
====ArrayType0 String====
{ constant, constant, ...};
"SomeName",
"SomeName",
struct ConstTypString
 
{
struct ArrayString
byte VarType; // = 0
{
IndexedString SomeName;
  byte VarType; // = 0
};
  IndexedString SomeName;
};
 
====ArrayType1 Float====
1.234,
1.234,
struct ConstTypFloat
struct ArrayFloat
{
{
byte VarType; // = 1
  byte VarType; // = 1
float value; // 4 bytes
  float value; // 4 bytes
};
};
 
 
====ArrayType2 Integer====
 
123,
123,
struct ConstTypLongInteger
 
{
struct ArrayInteger
byte VarType; // = 2
{
int value; // 4 bytes
  byte VarType; // = 2
};
  int value; // 4 bytes
{{constants...},{constants...},....},
};
struct ConstTypeArray
====ArrayType3 Embedded_Array====
{
{array(...},....},
byte VarType; // = 3
 
BIS_short nConstTypes; // iterate thru ConstTypes
struct EmbeddedArray
... depends on constypes
{
};
  byte VarType; // = 3
with the above construct (embedded array) each embedded array can contain any constant, including, another embedded array
  BIS_short nArrayElements; // iterate thru ConstTypes
The difference of course is these embedded arrays have no individual name associated with them (unlike the packet array)
... depends on elememt types in this embedded array
Added Wrinkles
};
 
with the above construct (embedded array) each embedded array can contain any ArrayType, including, another embedded array. The difference of course is these embedded arrays have no individual name associated with them (unlike the packet array).
 
 
==Added Wrinkles==
#defines
#defines
Optionally, an encrypted file can contain a #define table after the filename class definition.
Optionally, an encrypted file can contain a #define table after the filename class definition.
Long NumberOfDefines
Long NumberOfDefines
Struct DefTable
 
{
Struct DefTable
{
     Asciiz String;
     Asciiz String;
     Long    value;
     Long    value;
}[NumberOfDefines]
}[NumberOfDefines];





Revision as of 06:10, 14 July 2006

Gah!

dont' touch this one folks just at moment, it's a cut 'n paste from my website and needs *severe* re-wording.

I've plunked it here in my sandbox to get to work on it as and when....



Introduction

raP encoding applies to any humanly readable text file in OFP that contains class statements. Examples of files that are, or should be, raPified, are mission.sqm, config.cpp, description.ext.

In fact, any text file that contains class statements, contains nothing else but class statements. So much so, that entire contents of that file, is considered to be a class !!!

eg

class mission.sqm
{
  ...
};

The fact of the matter is, if you do not raPify these files, the engine will before using them (and thus causing uneccessary cpu load)

raP encoding simply means that the data inherent in these types of files has been sanitised (stripped of commments and crud) and massaged into a form of indexed lookup table for the engine to use directly. Once done, it is free of the need to check for syntax errors, among other things. Hence, much much faster processing.

These types of files were once known as 'encrypted' or 'binarised' files. They are no such thing. They are simply a cleaner. closer equivalent to what the engine uses internally. For instance, all your savegames are raP encoded (there is no, text equivalent).

A raP encoded file is detected by the magic signature '\0raP' in the first four bytes of the file. Because of the leading 0 byte, no text file can inadvertently have this signature.

Importantly, the filename extension is immaterial.

The engine will work with config.cpp as a raP encoded entity, just as it would work with config.bin.

Tools

Various utilities exist which refer to binary <> cpp compression and extraction (or encoding and decoding). Again, these terms are misleading because the file concerned is not executable binary data, just tokenised strings and values.

Basics

There is no need here to elaborately define what a mission.sqm file is. But, it is worth understanding the basics of these (types of) files to understand the very small requirements needed to raPify them.

class files only contain one of 3 types of construct

#names
#variables
#classes

names are names = variable;

variables come in 4 flavours

aString="A string";
anInteger=77; 
aFloat 1.855; // float
anArray[]={......}; 
 // an array containing more name's including (possibly) more arrays or more variables


 thing[]={ 1.0,  7.67,   "Elephants", fred[]={......} };


raPifying encodes each of these basic types.

The only other construct of a sqm file is the class

class classname [:inherit] { ...};

[:inherit] is optional and simply refers to another classname

This is the only other construct that a compression utility needs to encode.

Construct

all raPified data can be expressed as

class filename
{ 
   number of embedded classes
   class FirstEmbeddedClass
   {
      number of embedded classes in this class
      ... variables
      class FirstEmbeddedEmbeddedClass
      {
        ...
      };
      ...
    };
    ...
    class LastEmbeddedClass
    {
    };
 };
       

number of #defines (optional)

  1. define table (if any)

the beginning class, the filename, is not recorded in the humanly readable text output. See below for #defines

Header=

A raPified file the first 4 bytes of the file encoded as follows: "\0raP"

For OFP and RESISTANCE the next three bytes are

\004\0\0"

see elsewhere for Elite and ArmA)

The rest of the file contains packets of 3 different construct types as noted above with the 1st byte defining what 'type' it is.

Thus

struct Packet
{
   byte    PacketType;	// 0,1 or 2
   ....... depends on packet type
};

Packet Type 0: Classname Packet Type 1: Variables Packet Type 2: Arrays

The very first packet encountered is a classname. It is the enclosing class for *everything* 
else in the file. The name of his class is the name of the file. It is *not* recorded in humanly
readable text output.

Packets

PacketType0: Classname

class Classname: InheritedClassName {  Packets... };
struct ClassPacket
{
 byte		PacketType;		// = 0 == class
 IndexedString 	Classname;
 Asciiz		InheritedClassName;	// optional or zero length string
 BIS_short	nImbeddedPackets;	// Iterates thru embedded Packet(s) can be zero
};

PacketType1: Variables

The first byte of this packet defines what type of variable. Thus

struct VarPacket
{
 byte		PacketType;		// = 1
 byte		VarType;		// = 0 to 2
 IndexedString 	SomeName;
 .... depends on VarType
};

VarType0 String

SomeName="SomeOtherName";

struct VarTypString 
{
 byte		PacketType;	// = 1
 byte		VarType;	// = 0
 IndexedString	SomeName;
 IndexedString	SomeOtherName;
};

VarType1 Float

SomeName=1.23445;

struct VarTypFloat
{
 byte		PacketType;	// = 1
 byte		VarType;	// = 1
 IndexedString	SomeName;
 float		value;		// 4 bytes
};

VarType2 Integer

SomeName=123;

struct VarTypLongInteger
{
 byte		PacketType;	// = 1
 byte		VarType;	// = 2
 IndexedString	SomeName;
 int		value;		// 4 bytes
};

PacketType2: Arrays

Arrays[] contain four possible element types. They are the traditional variables mentioned above with an added tweak of an embedded array type.

thus

SomeName[]={ Element,Element[],"element",....};

struct ArrayPacket
{
 byte		PacketType;		// = 2
 IndexedString 	SomeName;
 BIS_short	nConstTypes;		// iterate thru ConstTypes, can be 0
 .... depends on ConstTypes
};

ArrayType0 String

"SomeName",

struct ArrayString 
{
 byte		VarType;	// = 0
 IndexedString	SomeName;
};

ArrayType1 Float

1.234,

struct ArrayFloat
{
 byte		VarType;	// = 1
 float		value;		// 4 bytes
};


ArrayType2 Integer

123,

struct ArrayInteger
{
 byte		VarType;	// = 2
 int		value;		// 4 bytes
};

ArrayType3 Embedded_Array

{array(...},....},

struct EmbeddedArray
{
 byte		VarType;	// = 3
 BIS_short	nArrayElements;	// iterate thru ConstTypes
... depends on elememt types in this embedded array 
};

with the above construct (embedded array) each embedded array can contain any ArrayType, including, another embedded array. The difference of course is these embedded arrays have no individual name associated with them (unlike the packet array).


Added Wrinkles

  1. defines

Optionally, an encrypted file can contain a #define table after the filename class definition.

Long NumberOfDefines

Struct DefTable
{
   Asciiz String;
   Long    value;
}[NumberOfDefines];


type definitions Bis_Short the value us either one, or two bytes. { int val;

if ((val = GetByte())==EOF) return EOF;
if (val & 0x80)
{
int extra;
 
 if ((extra = GetByte())==EOF) return EOF;
 val += (extra - 1) * 0x80;
}
return val;

}

IndexedString struct {

   Bis_Short    index;
   Asciiz          String;

}; a table of strings is recorded according to it's index number when that specific index number is first encountered. Although the values appear to be ordinal (0,1,2,3,4,5) you should not assume so. 0 ="Peter" 1="Paul" 2="Mary" These are defined index strings and appear, individually, and uniquely, within the mission.sqm as and when they are first encountered. From then on you will only see an index string as 1="" because 1 has been defined earlier on. Note that this is unlike a postscript dictionary in that strings are defined on an add -hoc basis, not at beginning, only when encountered, this 0="peter" 0= 0= 1="mary" 0= 1= 0= 2="fred" 2= 1= etc