2024-12-21 19:55:31 +03:00

214 lines
5.3 KiB
Java

package org.cl0zzzy.rtmp;
import java.util.ArrayList;
import java.util.Arrays;
public class AMF {
private ArrayList<AMFObject> AMFMessage = new ArrayList<AMFObject>();
private byte[] amf;
public boolean next = false;
public byte[] nextArr;
public AMF( byte[] amf ) {
this.amf = amf;
this.decodeAMF();
}
private AMFResult decodeNumber( int i ) {
byte[] number = new byte[8];
number[0] = amf[i+1];
number[1] = amf[i+2];
number[2] = amf[i+3];
number[3] = amf[i+4];
number[4] = amf[i+5];
number[5] = amf[i+6];
number[6] = amf[i+7];
number[7] = amf[i+8];
AMFResult result = new AMFResult();
result.value = this.numberToDouble( Util.bytesToHex( number ) );
result.index = i+8;
return result;
}
private AMFResult decodeString( int i ) {
byte[] stringLength = new byte[2];
stringLength[0] = amf[i+1];
stringLength[1] = amf[i+2];
int length = Integer.parseInt( Util.bytesToHex(stringLength), 16 );
ArrayList<Byte> str = new ArrayList<Byte>();
for( int u = (i+3); u < (i+3+length); u++ ) {
str.add( amf[u] );
}
AMFResult result = new AMFResult();
byte[] _a = new byte[str.size()];
int j = 0;
for(Byte b : str) {
_a[j++] = b.byteValue();
}
try { result.value = new String( _a, "UTF-8" ); } catch( Exception e ) { e.printStackTrace(); }
result.index = i+2+length;
return result;
}
private AMFResult decodeECMA( int i ) {
AMFEcmaArray ecma = new AMFEcmaArray();
if( amf[i] == AMFObject.AMF_ECMA_ARRAY_START &&
amf[i+1] == 0x00 &&
amf[i+2] == 0x00 &&
amf[i+3] == 0x00 &&
amf[i+4] == 0x00 &&
amf[i+5] == 0x00 &&
amf[i+6] == 0x00 &&
amf[i+7] == AMFObject.AMF_OBJECT_END ) {
i = i + 7;
AMFResult result = new AMFResult();
result.value = ecma;
result.index = i;
return result;
}
i+=5;
int index = 0;
while( true ) {
if( amf[i] == 0x00 && amf[i+1] == 0x00 && amf[i+2] == 0x09 ) {
i = i + 2;
break;
}
i+=3;
int __index = index;
__index = __index - ( __index % 10 );
if( __index > 0 ) {
int len = String.valueOf(__index).substring(1).length();
i += len;
}
Result res = this.decodeOne(i);
AMFObject value = new AMFObject( amf[i], res.val );
ecma.add(value);
i = res.i;
i++;
index++;
}
AMFResult result = new AMFResult();
result.value = ecma;
result.index = i;
return result;
}
private AMFResult decodeObj( int i ) {
i++;
AMFObjectArray array = new AMFObjectArray();
while( true ) {
if( amf[i] == 0x00 && amf[i+1] == 0x00 && amf[i+2] == 0x09 ) {
i = i + 2;
break;
}
byte[] length = new byte[2];
length[0] = amf[i];
length[1] = amf[i+1];
int decimal = Integer.parseInt( Util.bytesToHex(length), 16 );
String key = "";
for( int u = i+2; u < (i+2+decimal); u++ ) {
key = key + new String( new byte[] {amf[u]} );
}
Result res = this.decodeOne(i+2+decimal);
AMFObject obj = new AMFObject( amf[i+2+decimal], res.val );
array.add(key, obj);
i = res.i + 1;
}
AMFResult result = new AMFResult();
result.value = array;
result.index = i;
return result;
}
private Result decodeOne( int i ) {
Object val = null;
if( amf[i] == AMFObject.AMF_NUMBER ) {
AMFResult result = this.decodeNumber(i);
val = result.value;
i = result.index;
} else if( amf[i] == AMFObject.AMF_STRING ) {
AMFResult result = this.decodeString(i);
val = result.value;
i = result.index;
} else if( amf[i] == AMFObject.AMF_BOOLEAN ) {
if( amf[i+1] == 0x00 ) {
val = false;
} else {
val = true;
}
i++;
} else if( amf[i] == AMFObject.AMF_OBJECT_START ) {
AMFResult result = this.decodeObj(i);
val = result.value;
i = result.index;
} else if( amf[i] == AMFObject.AMF_NULL ) {
val = null;
} else if( amf[i] == AMFObject.AMF_ECMA_ARRAY_START ) {
AMFResult result = this.decodeECMA(i);
val = result.value;
i = result.index;
} else if( amf[i] == AMFObject.AMF_DATE ) {
val = "Date";
i = i + 10;
} else if( amf[i] == (byte) 0x43 || amf[i] == (byte) 0x83 ){
val = "end";
next = true;
nextArr = Arrays.copyOfRange(amf, i, amf.length);
}
Result res = new Result();
res.i = i;
res.val = val;
return res;
}
private void decodeAMF() {
for( int i = 0; i < amf.length; i++ ) {
Object val = null;
int _i = i;
Result res = this.decodeOne( i );
i = res.i;
val = res.val;
if( val != null && val.equals("end") ) {
break;
}
if( amf[_i] != AMFObject.AMF_BOOLEAN &&
amf[_i] != AMFObject.AMF_ECMA_ARRAY_START &&
amf[_i] != AMFObject.AMF_NUMBER &&
amf[_i] != AMFObject.AMF_OBJECT_START &&
amf[_i] != AMFObject.AMF_STRING ) {
amf[_i] = AMFObject.AMF_NULL;
}
AMFObject value = new AMFObject( amf[_i], val );
AMFMessage.add(value);
}
}
public int getLength() {
return this.AMFMessage.size();
}
public AMFObject get( int index ) {
return this.AMFMessage.get(index);
}
private double numberToDouble( String hexString ) {
long longHex = parseUnsignedHex(hexString);
return Double.longBitsToDouble(longHex);
}
private long parseUnsignedHex(String text) {
if (text.length() == 16) {
return (parseUnsignedHex(text.substring(0, 1)) << 60)
| parseUnsignedHex(text.substring(1));
}
return Long.parseLong(text, 16);
}
}