This is currently my sum total documentation on the AMF format, and
until I find some binary AMF data to test with, it'll be hard to know
if I've got this initial reverse engineering project working
correctly. 

Anyone that gets the urge is welcome to split this library off from
Gnash and make it be a standalone development reesource. There don't
appear to be any GPL'd AMF tools out there that I could find non
WinDoze systems.

===========================================================

All of this info came from OSFlash:
http://osflash.org/amf


 AMF has core data types that are there every step of the way for
serializing data. These should not be confused with the AMF
actionscript data types. The core data types include:

    * Byte
    * Int
    * MediumInt
    * Long
    * Double
    * UTF8
    * LongUTF8

An AMF Byte is the simplest data type to read and write. It is simply
an 8-bit byte.

An AMF Int is made up of 2 consecutive bytes. It represents a 16-bit
number. The first byte in the file/stream is the most significant bit
and the second byte in the file/stream is the LSB. 

An AMF MediumInt is made up of 3 consecutive bytes. It represents a
24-bit number. The first byte in the file/stream is the most
significant bit and the third byte in the file/stream is the
LSB. MediumInt's appear to be used exclusively by FlashCom. 

The AMF Long is made up of 4 consecutive bytes. It represents a 32-bit
number. Like the Int and MediumInt, it is unsigned and the LSB is on
the right. 

The AMF Double is made up of 8 consecutive bytes. It represents a
floating point, signed number. The double is little-endian encoded. In
PHP a double can be read in the following way (this should also work
for any language that has a pack function): 

The AMF UTF8 represents a string shorter than 2^16 bytes. It is
composed of an Int (2 bytes) representing string length followed by
the UTF8-encoded string. 

The AMF LongUTF8 represents a string potentially longer than 2^16
bytes. It is composed of an LongInt (4 bytes) representing string
length followed by the UTF8-encoded string. 


Remoting envelope

A Remoting request from the client consists of a short preamble,
headers, and bodys. The preamble contains basic information about the
nature of the request. Headers can be used to request debugging
information, send authentication info, tag transactions, etc. Bodies
contain actual Remoting requests and responses. A single Remoting
envelope can contain several requests; Remoting supports batching out
of the box. 

Client headers and bodies need not be responded to in a one-to-one
manner. That is, a body or header may not require a response. Debug
information is requested by a header but sent back as a body
object. The response index is essential for Flash player to understand
the response therefore. 
Preamble

The first byte of the AMF file/stream is believed to be a version
indicator. So far the only valid value for this field that has been
found is 000. If it is anything other than 000 (zero), your
system should consider the AMF file/stream to be
'cmalformed'd. This can happen in the IDE if AMF calls are put
on the stack but never executed and the user exits the movie from the
IDE; the two top bytes will be random and the number of headers will
be unreliable.

The second byte of the AMF file/stream is appears to be 000 if the
client is the Flash Player and 001 if the client is the FlashCom
server. 

The third and fourth bytes form an integer value that specifies the
number of headers. 

AMF Headers

Each header consists of the following:

    * UTF string (including length bytes) - name
    * Boolean - specifies if understanding the header is `required'
    * Long - Length in bytes of header
    * Variable - Actual data (including a type code)

AMF headers may be user-created. However, certain headers have certain
meaning that a gateway should respond to. See predefined headers for
more information. 
AMF Bodies

Between the headers and the start of the bodies is a int specifying
the number of bodies. Each body consists of the following: 

    * UTF String - Target
    * UTF String - Response
    * Long - Body length in bytes
    * Variable - Actual data (including a type code)

The target may be one of the following:

    * An http or https URL. In that case the gateway should respond by
sending a SOAP request to that URL with the specified data. In that
case the data will be an array and the first key (data[0]) contains
the parameters to be sent. 
    * A string with at least one period (.). The value to the right of
the right-most period is the method to be called. The value to the
left of that is the service to be invoked including package name. In
that case data will be an array of arguments to be sent to the
method. 

The response is a string that gives the body an id so it can be
tracked by the player. 

Body response

The response to a request has the exact same structure as a request. A
request requiring a body response should be answered in the following
way: 

    * Target: set to Response index plus one of "/onStatus",
"onResult", or "/onDebugEvents". "/onStatus" is reserved for
runtime errors. "/onResult" is for succesful calls. "/onDebugEvents"
is for debug information, see debug information. Thus if the client
requested something with response index 1/1', and the call was succesful,
1/1/onResult' should be sent back. 
    * Response: should be set to the string `null'.
    * Data: set to the returned data.


==========================================================
http://www.vanrijkom.org/archives/2005/06/amf_format.html

Flash AMF

Used for:

    * Local Connection
    * SOL
    * Remoting

The folowing elements are defined within AMF. These are all based on
their ActionScript equivalants.

Type	Tagbyte

Number 0x00;
Boolean 0x01;
String 0x02;
Object 0x03;
MovieClip 0x04;
Null 0x05;
Undefined 0x06;
Reference 0x07;
ECMAArray 0x08;
ObjectEnd 0x09;
StrictArray 0x0a;
Date 0x0b;
LongString 0x0c;
Unsupported 0x0d;
Recordset 0x0e;
XMLObject 0x0f;
TypedObject(Class) 0x10;


For terminating sequences, a byte with value 0x09 is used.

Number: 0x00 B7 B6  B0

Numbers in AMF are 64 bit Big Endian. Windows works with little
endians, so conversion is required. 

Boolean: 0x01 B0 (BOOL)

BOOL is 0 for FALSE and 1 for TRUE

String: 0x02 L0 L1 SMBSTRING

L1+L2 is Big Endian, length of the string. String is in multibyte
format, prefixed with a 2 byte Big Endian length specifier. 

Object: 0x03 [SMBSTRING AMFELEMENT ] 0x09

An object contains zero or more AMF elements that are prefixed with a
multibyte string that indicates the AMF elements identifyer within the
object. 

Undefined: 0x06

An undefined element consists of soley one byte with the value 0x06.

Reference (TODO): 0x07 ?

A reference refers to an array or object that stored somewhere
before. Its probably a mechanism that prevents 

Associative Array: 0x08 L3 L2 L1 L0 [SMBSTRING AMFELEMENT ] 0x09

L0..L3 for a 32 bit number indicating the number of elements present
in the array. The length of the array is followed by (length) AMF
elements that are prefixed with a multibyte string (with a 2 byte
length prefix) that indicates the AMF elements identifyer within the
array. 

Array: 0x0A L3 L2 L1 L0 [ AMFELEMENT ]

L0..L3 form a 32 bit Big Endian number indicating the number of
elements present in the array. The size of the array is followed by
(length) AMF elements. Note that this collection is NOT terminated using 0x09. 

Date: 0x0B T7 T6 .. T0 Z1 Z2

T7 to T0 form a 64 bit Big Endian number that specifies the number
of nanoseconds that have passed since 1/1/1970 0:00 to the
specified time. This format is UTC 1970. Z1 an Z0 for a 16 bit
Big Endian number indicating the indicated times timezone. 

SimpleObject: 0x0C ?

To do %G–%@ meaning unknown.

XML: 0x0F LMBSTRING

The multi-byte string is prefixed with a 32 bit Big Endian number,
indicating the length of the multibytestring that follows. 

Class: 0x10 SMBSTRING [ SMBSTRING AMFELEMENT ] 0x09

A class element is similar to an object element, but has a class
name indentifyer string prefixed to the array of member elements. 

*Element containers*

Currently AMF is used with SharedObjectsLocal (.sol) files,
Local Connection and Flash Remoting.


  // S3 .. S0 forms a 32 bit Big Endian number indicating the size of
  // the file. The small multibyte string reflects the name of the
  // object shared in the file. The array that follows has pairs of
  // name (SMBSTRING) lue pairs.
  
Reference tag
16 big big-endian number follows the tag identifier 0x07.
 
------------------------------------
http://sourceforge.net/docman/display_doc.php?docid=27130&group_id=131628

Flashcoders Wiki - SharedObjectFile
SharedObjectFile

The format of the shared object files

 This script creates the described .sol file

 so = SharedObject.getLocal("test");
 so.data.myInt = 7;
 so.data.myFloat = Math.PIE;
 so.data.myString = 'ralle';
 so.data.myIntArray = [1,2,3];
 so.data.myStringArray = ['eins','zwei'];
 so.data.myObject1 = {p1: 5, p2: 6};
 so.data.myObject2 = {p3: 'hallo', p4: 8};
 so.data.myDate = new Date();
 so.data.myXML = new XML("<start><p>test</p><p>test2</p></start>");
 so.data.myBool = true;
 so.flush();

 ----

 header   00 BF
 len      00 00 01 04 //length of file starting at filetype
 filetype TCSO ...      00 04 00 00 00 00

 //myInt = 7;
 00 05 myInt         00  40 1C 00 00 00 00 00 00  00
 len   name          typ floatval      		  end

 //myFloat = Math.PI;
 00 07 myFloat       00  40 09 21 FB 54 44 2D 18  00
 len   name          typ floatval 		  end

 //myString = "ralle";
 00 08 myString      02  00 05  r  a  l  l  e 	  00
 len   name          typ lenstr str 		  end

 //myIntArray = [1,2,3];
 00 0A myIntArray    08  00 00 00 03
 len   name          typ countidx

 00 01  '0'  00  3F F0 00 00 00 00 00 00  	!! no end here
 00 01  '1'  00  40 00 00 00 00 00 00 00
 00 01  '2'  00  40 08 00 00 00 00 00 00
 lenidx idx  typ floatval

 00 00 09 00
 end of array

 //myStringArray = ["eins","zwei"];
 00 0D myStringArray 08  00 00 00 02
 len   name          typ count

 00 10  '0'  02  00 04  e  i  n  s
 00 01  '1'  02  00 04  z  w  e  i
 lenidx idx  typ strlen string

 00 00 09 00
 end of array

 //myObject1 = {p1: 5, p2: 6};
 00 09  myObject1 03
 00 02  p2  00  40 18 00 00 00 00 00 00 	!!no end here
 00 02  p1  00  40 14 00 00 00 00 00 00
 lenidx idx typ floatval

 00 00 09 00
 end of array

 //myObject2 = {p3: "hallo", p4: 8};
 00 09 myObject2 03
 00 02  p4  00  40 20 00 00 00 00 00 00 	00
 lenidx idx typ floatval 			end
 00 20  p3  02  00 05  hallo
 lenidx idx typ strlen string

 00 00 09 00
 end of array

// AlexisIsaac

 It seems that the previous sample isn't exact there is no end byte on the first property:
 00 09 myObject2 03
 00 02  p4  00  40 20 00 00 00 00 00 00 	00
 lenidx idx typ floatval 			end
 00 20  p3  02  00 05  hallo
 lenidx idx typ strlen string

 00 00 09 00
 end of array

 //myDate = new Date();
 00 06 myDate 0B
 42 6D DA E6 18 52 C0 00  FF 88 00
 floatval-getTime         timezone (mins -ve of GMT)
                          FF88 = GMT +2 (-2 * 60)
                          FDE4 = GMT +9 (-9 * 60)
                          0000 = GMT
                          01E0 = GMT -8 (8 * 60)

 //myXML = new XML("<start><p>test</p><p>test2</p></start>")
 00 05 myXML 0F
 00 00 00 26 <start><p>test</p><p>test2</p></start> 00
 length      xmlval                                 end

 //myBool = true;
 00 06 myBool 01
 01 00

// bokel

Here are all the data type ids I can find:

      00 : number
      01 : boolean
      02 : string
      03 : object Object
      05 : null
      06 : undefined
      08 : object Array
      0A : raw Array (amf only)
      0B : object Date
      0D : object String, Number, Boolean, TextFormat
      0F : object XML
      10 : object CustomClass

Where CustomClass is a class registered with Object.registerClass

 // eg
      My
            this.x = 1;
      }
      Object.registerClass("classID",MyClass);
      myObj = new MyClass();

      00 05 m y o b j 10 00 07 c l a s s I D //len   name      typ      class identifier
      00 01 x 00 3F F0 00 00 00 00 00 00 //props
      00 00 09 00 //end

// Peter Hall

and here is a function to convert binary floats to a float

 function binaryFloatStringToFloat(bfs){
	var c0 = ord(bfs.charAt(0));
	var c1 = ord(bfs.charAt(1));

 //calculate sign
	var sign = (c0 & (1 << 7)) ? -1 : 1; //negative if highest bit is set

 //calculate exponent
	c0 &= 0x7f; //delete sign
	var exp = (((c0 << 8) + c1) >> 4) - 1023;

 //calculate mantissa
        var e = 4;
	var sum = (c1 & 0x0f) / Math.pow(2, e); //delete upper four bits
	var byteIdx = 2;
	do {
                e += 8;
		var byte = ord(bfs.charAt(byteIdx));
		sum += byte / Math.pow(2, e);
	} while (++byteIdx < bfs.length);

 //trace(sum + " " + exp + " " + sign);
	return (1 + sum) * Math.pow(2, exp) * sign;
 }

 //some tests
 s = String.fromCharCode(0x40,0x08,0,0,0,0,0,0); //3 //s = String.fromCharCode(0x40,0x1c,0,0,0,0,0,0); //7 //s = String.fromCharCode(0x40,0x0A,0x66,0x66,0x66,0x66,0x66,0x66); //3.3
 trace(binaryFloatStringToFloat(s));

// bokel 


This is the first RTMP message:

(gdb) p buffer
$10 = "\003\000\000\017\000\000%G￿%@\024\000\000\000\000\002\000\aconnect\000?%G￿%@\000\000\000\000\000\000\003\000\003app\002\000#software/gnash/tests/1153948634.flv\000\bflashVer\002\000\fLNX 6,0,82,0\000\006swfUrl\002\000\035file:///file|%2Ftmp%2Fout.swf%G￿%@\000\005tcUrl\002\0004rtmp://localhost/software/gnash/tests/1153948634.flv\000\000\t\002\000\005userx"...
(gdb) p/x buffer
$11 = {
 *0x3,* 0x0,  0x0,  0xf,  0x0,  0x0, *0xc9,*0x14, 0x00, 0x00, 0x00,  0x0,  0x2,  0x0, 0x7,
  0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x00, 0x3f, 0xf0, 0x00,  0x0,  0x0,  0x0,
  0x0,  0x0,  0x3,  0x0,  0x3,  0x61, 0x70, 0x70, 0x02, 0x00, 0x23, 0x73, 0x6f, 0x66, 0x74,
  0x77, 0x61, 0x72, 0x65, 0x2f, 0x67, 0x6e, 0x61, 0x73, 0x68, 0x2f, 0x74, 0x65,
  0x73, 0x74, 0x73, 0x2f, 0x31, 0x31, 0x35, 0x33, 0x39, 0x34, 0x38, 0x36, 0x33,
  0x34, 0x2e, 0x66, 0x6c, 0x76, 0x0,  0x8,  0x66, 0x6c, 0x61, 0x73, 0x68, 0x56, 0x65,
  0x72, 0x2,  0x0,  0xc,  0x4c, 0x4e, 0x58, 0x20, 0x36, 0x2c, 0x30, 0x2c, 0x38, 0x32,
  0x2c, 0x30, 0x0,  0x6,  0x73, 0x77, 0x66, 0x55, 0x72, 0x6c, 0x02, 0x00, 0x1d, 0x66,
  0x69, 0x6c, 0x65, 0x3a, 0x2f, 0x2f, 0x2f, 0x66, 0x69, 0x6c, 0x65, 0x7c, 0x25,
  0x32, 0x46, 0x74, 0x6d, 0x70, 0x25, 0x32, 0x46, 0x6f, 0x75, 0x74, 0x2e, 0x73,
  0x77, 0x66,*0xc3*,0x0,  0x5,  0x74, 0x63, 0x55, 0x72, 0x6c, 0x02, 0x00, 0x34, 0x72,
  0x74, 0x6d, 0x70, 0x3a, 0x2f, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x68, 0x6f,
  0x73, 0x74, 0x2f, 0x73, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x2f, 0x67,
  0x6e, 0x61, 0x73, 0x68, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x73, 0x2f, 0x31, 0x31,
  0x35, 0x33, 0x39, 0x34, 0x38, 0x36, 0x33, 0x34, 0x2e, 0x66, 0x6c, 0x76, 0x0, 0x0,
  0x9,  0x2,  0x0,  0x5,  0x75, 0x73, 0x65, 0x72, 0x78...}


"\003\000\000\017\000\000
%G￿%@ \024\000\000\000\000\002\000
\a
connect\000
?%G ￿ %@ \000\000\000\000\000\000

First byte:
\003 = Object type
\002 = String type
\000 = Number type
\008 = Video type
\009 = Video type

0x09 is also the terminating byte of and object definition
All numbers are 64 bit big endian in AMF

0xc9 0x14 0x0

0x02 <--- string type
0x00 0x07 connect	
0x00 <---- number type (64 bit big endian)
0x3f 0xf0 0x00 0x00 0x00 0x00 0x00 0x00

0x03  <--- object type
0x00 0x03 app
0x02 <--- string type
0x00 0035 software/gnash/tests/1153948634.flv

0x00 0x08 flashVer
0x02 <--- string type
0x00 0xf LNX 6,0,82,0

0x00 0x06 swfUrl
0x02 <--- string type
0x00 0x00 35 file:///file|/%2Ftmp%2Fout.swf

%G ￿ %@
0xc3 <---- header byte
0x00 0x05 tcUrl
0x02 <--- string type
0x00 0x00 0x04 rtmp://localhost/software/gnash/tests/1153948634.flv

0x00 0x00 0x09 <--- end of object definition

0x02 0x00 0x05 userx


//myInt = 7;
 00 05 myInt         00  40 1C 00 00 00 00 00 00  00
 len   name          typ floatval      		  end

 //myFloat = Math.PI;
 00 07 myFloat       00  40 09 21 FB 54 44 2D 18  00
 len   name          typ floatval 		  end

 //myString = "ralle";
 00 08 myString      02  00 05  r  a  l  l  e 	  00
 len   name          typ lenstr str 		  end

 //myIntArray = [1,2,3];
 00 0A myIntArray    08  00 00 00 03
 len   name          typ countidx

 00 01  '0'  00  3F F0 00 00 00 00 00 00  	!! no end here
 00 01  '1'  00  40 00 00 00 00 00 00 00
 00 01  '2'  00  40 08 00 00 00 00 00 00
 lenidx idx  typ floatval

 00 00 09 00
 end of array
