Improved dumpInfo in AMF3

This commit is contained in:
Jindra Petřík
2016-07-18 21:32:08 +02:00
parent ce91076693
commit d82f0f17c3

View File

@@ -14,11 +14,15 @@ import com.jpexs.decompiler.flash.amf.amf3.types.DictionaryType;
import com.jpexs.decompiler.flash.amf.amf3.types.VectorUIntType;
import com.jpexs.decompiler.flash.amf.amf3.types.BasicType;
import com.jpexs.decompiler.flash.dumpview.DumpInfo;
import com.jpexs.decompiler.flash.ecma.EcmaScript;
import com.jpexs.helpers.Helper;
import com.jpexs.helpers.MemoryInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -30,6 +34,11 @@ public class Amf3InputStream extends InputStream {
public final static Logger LOGGER = Logger.getLogger(Amf3InputStream.class.getName());
private final MemoryInputStream is;
public DumpInfo dumpInfo;
private static String NO_REFERENCE_BIT_TEXT = "not reference";
private static String REFERENCE_BIT_TEXT = "not reference";
private static String OBJECT_INDEX_TEXT = "object index";
private static String STRING_INDEX_TEXT = "string index";
private static String TRAIT_INDEX_TEXT = "trait index";
public Amf3InputStream(MemoryInputStream is) {
this.is = is;
@@ -59,16 +68,6 @@ public class Amf3InputStream extends InputStream {
}
}
private void renameLastDump(String newname) {
if (dumpInfo != null) {
if (!dumpInfo.getChildInfos().isEmpty()) {
DumpInfo di = dumpInfo.getChildInfos().get(dumpInfo.getChildInfos().size() - 1);
di.name = newname;
}
}
}
public void endDumpLevelUntil(DumpInfo di) {
if (di != null) {
while (dumpInfo != null && dumpInfo != di) {
@@ -135,7 +134,7 @@ public class Amf3InputStream extends InputStream {
newDumpLevel(name, "DOUBLE");
long lval = readLong();
double ret = Double.longBitsToDouble(lval);
endDumpLevel(ret);
endDumpLevel(EcmaScript.toString(ret));
return ret;
}
@@ -146,6 +145,68 @@ public class Amf3InputStream extends InputStream {
return val;
}
private void renameU29O_ref() {
renameU29("U29O-ref", REFERENCE_BIT_TEXT, OBJECT_INDEX_TEXT);
}
private void renameU29S_ref() {
renameU29("U29S-ref", REFERENCE_BIT_TEXT, STRING_INDEX_TEXT);
}
private void renameU29Traits_ref() {
renameU29("U29O-traits-ref", NO_REFERENCE_BIT_TEXT, "trait reference", TRAIT_INDEX_TEXT);
}
private void renameLastDump(String wholeName) {
if (dumpInfo != null) {
if (!dumpInfo.getChildInfos().isEmpty()) {
DumpInfo u29DumpInfo = dumpInfo.getChildInfos().get(dumpInfo.getChildInfos().size() - 1);
u29DumpInfo.name = wholeName;
}
}
}
private void setDumpInfoType(String type) {
if (dumpInfo != null) {
dumpInfo.type = type;
}
}
private void renameU29(String wholeName, String name1, String... names) {
List<String> bitNames = new ArrayList<>();
bitNames.add(name1);
bitNames.addAll(Arrays.asList(names));
String restName = bitNames.remove(bitNames.size() - 1);
if (bitNames.size() > 6) {
throw new RuntimeException("Renaming more than 6 bits in U29 is not supported");
}
if (dumpInfo != null) {
if (!dumpInfo.getChildInfos().isEmpty()) {
DumpInfo u29DumpInfo = dumpInfo.getChildInfos().get(dumpInfo.getChildInfos().size() - 1);
u29DumpInfo.name = wholeName;
long lastBytePos = u29DumpInfo.startByte + u29DumpInfo.lengthBytes - 1; //last byte of U29 is least significant (U29 is big endian)
int remainingBitLength = ((int) u29DumpInfo.lengthBytes) * 8 - bitNames.size();
long u29val = ((long) (Long) u29DumpInfo.previewValue);
DumpInfo restDumpInfo = new DumpInfo(restName, "UB(" + remainingBitLength + ")", u29val >> bitNames.size(), lastBytePos, 0, u29DumpInfo.lengthBytes, remainingBitLength);
restDumpInfo.parent = u29DumpInfo;
u29DumpInfo.getChildInfos().add(restDumpInfo);
for (int i = bitNames.size() - 1; i >= 0; i--) {
int bitVal = (int) ((u29val >> i) & 1);
DumpInfo bitDumpInfo = new DumpInfo(bitNames.get(i), "bit", bitVal, lastBytePos, 7 - i, 1, 1);
bitDumpInfo.parent = u29DumpInfo;
u29DumpInfo.getChildInfos().add(bitDumpInfo);
}
}
}
}
public long readS29(String name) throws IOException {
newDumpLevel(name, "S29");
long val = signExtend(readU29Internal(), 29);
@@ -191,31 +252,34 @@ public class Amf3InputStream extends InputStream {
throw new EndOfStreamException();
}
String retString = new String(buf, "UTF-8");
endDumpLevel(retString);
endDumpLevel("\"" + Helper.escapeActionScriptString(retString) + "\"");
return retString;
}
public String readUtf8Vr(String name, List<String> stringTable) throws IOException {
newDumpLevel(name, "UTF-8-vr");
long u = readU29("U29S");
int stringNoRefFlag = (int) (u & 1);
String retString;
if (stringNoRefFlag == 1) {
renameLastDump("U29S-value");
renameU29("U29S-value", NO_REFERENCE_BIT_TEXT, "byte length");
long byteLength = u >> 1; //TODO: long strings, int is not enough for them
String retString = readUtf8Char("characters", byteLength);
retString = readUtf8Char("characters", byteLength);
if (byteLength > 0) {
stringTable.add(retString);
}
LOGGER.log(Level.FINE, "Read string: \"{0}\"", retString);
return retString;
} else { //flag==0
renameLastDump("U29S-ref");
renameU29S_ref();
int stringRefTableIndex = (int) (u >> 1);
String retString = stringTable.get(stringRefTableIndex);
retString = stringTable.get(stringRefTableIndex);
LOGGER.log(Level.FINE, "Read string: reference({0}):" + retString, stringRefTableIndex);
return retString;
}
endDumpLevel("\"" + Helper.escapeActionScriptString(retString) + "\"");
return retString;
}
private int readInternal() throws IOException {
@@ -253,26 +317,31 @@ public class Amf3InputStream extends InputStream {
switch (marker) {
case Marker.UNDEFINED:
renameLastDump("undefined-marker");
setDumpInfoType("undefined-type");
LOGGER.log(Level.FINE, "Read value: undefined");
result = BasicType.UNDEFINED;
break;
case Marker.NULL:
renameLastDump("null-marker");
setDumpInfoType("null-type");
LOGGER.log(Level.FINE, "Read value: null");
result = BasicType.NULL;
break;
case Marker.FALSE:
renameLastDump("false-marker");
setDumpInfoType("false-type");
LOGGER.log(Level.FINE, "Read value: false");
result = Boolean.FALSE;
break;
case Marker.TRUE:
renameLastDump("true-marker");
setDumpInfoType("true-type");
LOGGER.log(Level.FINE, "Read value: true");
result = Boolean.TRUE;
break;
case Marker.INTEGER:
renameLastDump("integer-marker");
setDumpInfoType("integer-type");
LOGGER.log(Level.FINE, "Read value: integer");
long ival = readS29("intValue");
LOGGER.log(Level.FINER, "Integer value: {0}", ival);
@@ -280,6 +349,7 @@ public class Amf3InputStream extends InputStream {
break;
case Marker.DOUBLE:
renameLastDump("double-marker");
setDumpInfoType("double-type");
LOGGER.log(Level.FINE, "Read value: double");
double dval = readDouble("doubleValue");
LOGGER.log(Level.FINER, "Double value: {0}", "" + dval);
@@ -287,6 +357,7 @@ public class Amf3InputStream extends InputStream {
break;
case Marker.STRING:
renameLastDump("string-marker");
setDumpInfoType("string-type");
LOGGER.log(Level.FINE, "Read value: string");
String sval = readUtf8Vr("stringValue", stringTable);
LOGGER.log(Level.FINER, "String value: {0}", sval);
@@ -294,11 +365,12 @@ public class Amf3InputStream extends InputStream {
break;
case Marker.XML_DOC:
renameLastDump("xml-doc-marker");
setDumpInfoType("xml-doc-type");
LOGGER.log(Level.FINE, "Read value: xml_doc");
long xmlDocU29 = readU29("U29");
int xmlDocNoRefFlag = (int) (xmlDocU29 & 1);
if (xmlDocNoRefFlag == 1) {
renameLastDump("U29X-value");
renameU29("U29X-value", NO_REFERENCE_BIT_TEXT, "byte length");
long byteLength = xmlDocU29 >> 1;
String xval = readUtf8Char("characters", byteLength);
LOGGER.log(Level.FINER, "XmlDoc value: {0}", xval);
@@ -306,7 +378,7 @@ public class Amf3InputStream extends InputStream {
objectTable.add(retXmlDoc);
result = retXmlDoc;
} else {
renameLastDump("U29O-ref");
renameU29O_ref();
int refIndexXmlDoc = (int) (xmlDocU29 >> 1);
LOGGER.log(Level.FINER, "XmlDoc value: reference({0})", refIndexXmlDoc);
result = objectTable.get(refIndexXmlDoc); //What if it's not XmlRef?
@@ -314,11 +386,12 @@ public class Amf3InputStream extends InputStream {
break;
case Marker.DATE:
renameLastDump("date-marker");
setDumpInfoType("date-type");
LOGGER.log(Level.FINE, "Read value: date");
long dateU29 = readU29("U29");
int dateNoRefFlag = (int) (dateU29 & 1);
if (dateNoRefFlag == 1) {
renameLastDump("U29D-value");
renameU29("U29D-value", NO_REFERENCE_BIT_TEXT, "unused");
//remaining bits of dateU29 are not used
double dtval = readDouble("date-time");
DateType retDate = new DateType(dtval);
@@ -326,7 +399,7 @@ public class Amf3InputStream extends InputStream {
objectTable.add(retDate);
result = retDate;
} else {
renameLastDump("U29O-ref");
renameU29O_ref();
int refIndexDate = (int) (dateU29 >> 1);
LOGGER.log(Level.FINER, "Date value: reference({0})", refIndexDate);
result = objectTable.get(refIndexDate); //What if it's not Date?
@@ -334,18 +407,19 @@ public class Amf3InputStream extends InputStream {
break;
case Marker.ARRAY:
renameLastDump("array-marker");
setDumpInfoType("array-type");
LOGGER.log(Level.FINE, "Read value: array");
long arrayU29 = readU29("U29");
int arrayNoRefFlag = (int) (arrayU29 & 1);
if (arrayNoRefFlag == 1) {
renameLastDump("U29A-value");
renameU29("U29A-value", NO_REFERENCE_BIT_TEXT, "dense count");
int denseCount = (int) (arrayU29 >> 1);
LOGGER.log(Level.FINEST, "Array value: denseCount={0}", new Object[]{denseCount});
List<Pair<String, Object>> assocPart = new ArrayList<>();
List<Object> densePart = new ArrayList<>();
ArrayType retArray = new ArrayType(densePart, assocPart);
objectTable.add(retArray); //add before processing elements which may reference this
newDumpLevel("associativeValues", "assoc-value");
while (true) {
String key = readUtf8Vr("key", stringTable);
if (key.isEmpty()) {
@@ -361,8 +435,10 @@ public class Amf3InputStream extends InputStream {
}
}
}
endDumpLevel();
LOGGER.log(Level.FINEST, "Array value: assocSize={0}", new Object[]{assocPart.size()});
newDumpLevel("denseValues", "value-type[]");
for (int i = 0; i < denseCount; i++) {
try {
densePart.add(readValue("denseValue", serializers, objectTable, traitsTable, stringTable));
@@ -374,11 +450,12 @@ public class Amf3InputStream extends InputStream {
throw new NoSerializerExistsException(nse.getClassName(), retArray, nse);
}
}
endDumpLevel();
LOGGER.log(Level.FINER, "Array value: dense_size={0},assocSize={1}", new Object[]{densePart.size(), assocPart.size()});
result = retArray;
} else {
renameLastDump("U29O-ref");
renameU29O_ref();
int refIndexArray = (int) (arrayU29 >> 1);
LOGGER.log(Level.FINER, "Array value: reference({0})", refIndexArray);
result = objectTable.get(refIndexArray); //What if it's not Array?
@@ -387,6 +464,7 @@ public class Amf3InputStream extends InputStream {
case Marker.OBJECT:
renameLastDump("object-marker");
setDumpInfoType("object-type");
LOGGER.log(Level.FINE, "Read value: object");
long objectU29 = readU29("U29");
int objectNoRefFlag = (int) (objectU29 & 1);
@@ -397,15 +475,16 @@ public class Amf3InputStream extends InputStream {
int objectTraitsExtFlag = (int) ((objectU29 >> 2) & 1);
ObjectType retObjectType;
if (objectTraitsExtFlag == 1) {
renameLastDump("U29O-traits-ext");
renameU29("U29O-traits-ext", NO_REFERENCE_BIT_TEXT, "not trait reference", "externalized traits", "unused");
String className = readUtf8Vr("className", stringTable);
if (!serializers.containsKey(className)) {
throw new NoSerializerExistsException(className, new ObjectType(new Traits(className, false, new ArrayList<>()), (byte[]) null, new ArrayList<>()), null);
}
newDumpLevel("serializedData", "U8[]");
MonitoredInputStream mis = new MonitoredInputStream(is);
List<Pair<String, Object>> serMembers = serializers.get(className).readObject(className, mis);
byte serData[] = mis.getReadData();
endDumpLevel();
Traits unserTraits = new Traits(className, false, new ArrayList<>());
retObjectType = new ObjectType(unserTraits, serData, serMembers);
@@ -414,7 +493,7 @@ public class Amf3InputStream extends InputStream {
result = retObjectType;
break markerswitch;
} else {
renameLastDump("U29O-traits");
renameU29("U29O-traits", NO_REFERENCE_BIT_TEXT, "not trait reference", "not externalized traits", "dynamic", "sealed count");
int dynamicFlag = (int) ((objectU29 >> 3) & 1);
int numSealed = (int) (objectU29 >> 4);
LOGGER.log(Level.FINEST, "object dynamicFlag:{0}", dynamicFlag);
@@ -422,14 +501,19 @@ public class Amf3InputStream extends InputStream {
String className = readUtf8Vr("className", stringTable);
LOGGER.log(Level.FINEST, "object className:{0}", className);
List<String> sealedMemberNames = new ArrayList<>();
for (int i = 0; i < numSealed; i++) {
sealedMemberNames.add(readUtf8Vr("sealedMemberName", stringTable));
if (numSealed > 0) {
newDumpLevel("sealedMemberNames", "UTF-8-vr[]");
for (int i = 0; i < numSealed; i++) {
sealedMemberNames.add(readUtf8Vr("sealedMemberName", stringTable));
}
endDumpLevel();
}
traits = new Traits(className, dynamicFlag == 1, sealedMemberNames);
traitsTable.add(traits);
}
} else {
renameLastDump("U29O-traits-ref");
renameU29Traits_ref();
int refIndexTraits = (int) (objectU29 >> 2);
traits = traitsTable.get(refIndexTraits);
LOGGER.log(Level.FINER, "Traits value: reference({0}) - traitsize={1}", new Object[]{refIndexTraits, traits.getSealedMemberNames().size()});
@@ -441,41 +525,60 @@ public class Amf3InputStream extends InputStream {
objectTable.add(retObjectType); //add it before any subvalue can reference it
List<Object> sealedMemberValues = new ArrayList<>();
NoSerializerExistsException error = null;
for (int i = 0; i < traits.getSealedMemberNames().size(); i++) {
try {
sealedMemberValues.add(readValue("sealedMemberValue", serializers, objectTable, traitsTable, stringTable));
} catch (NoSerializerExistsException nse) {
sealedMemberValues.add(nse.getIncompleteData());
for (int j = i + 1; j < traits.getSealedMemberNames().size(); j++) {
sealedMemberValues.add(BasicType.UNKNOWN);
if (!traits.getSealedMemberNames().isEmpty()) {
newDumpLevel("sealedMemberValues", "value-type[]");
for (int i = 0; i < traits.getSealedMemberNames().size(); i++) {
try {
sealedMemberValues.add(readValue("sealedMemberValue", serializers, objectTable, traitsTable, stringTable));
} catch (NoSerializerExistsException nse) {
sealedMemberValues.add(nse.getIncompleteData());
for (int j = i + 1; j < traits.getSealedMemberNames().size(); j++) {
sealedMemberValues.add(BasicType.UNKNOWN);
}
error = nse;
break;
}
error = nse;
break;
}
endDumpLevel();
}
for (int i = 0; i < traits.getSealedMemberNames().size(); i++) {
sealedMembers.add(new Pair<>(traits.getSealedMemberNames().get(i), sealedMemberValues.get(i)));
}
if (traits.isDynamic()) {
newDumpLevel("dynamicMembers", "dynamic-member[]");
String dynamicMemberName;
while (!(dynamicMemberName = readUtf8Vr("dynamicMemberName", stringTable)).isEmpty()) {
while (!(dynamicMemberName = readUtf8Vr("name", stringTable)).isEmpty()) {
try {
Object dynamicMemberValue = readValue("dynamicMemberValue", serializers, objectTable, traitsTable, stringTable);
Object dynamicMemberValue = readValue("value", serializers, objectTable, traitsTable, stringTable);
dynamicMembers.add(new Pair<>(dynamicMemberName, dynamicMemberValue));
} catch (NoSerializerExistsException nse) {
dynamicMembers.add(new Pair<>(dynamicMemberName, nse.getIncompleteData()));
throw new NoSerializerExistsException(nse.getClassName(), retObjectType, nse);
} finally {
//group dumpInfo to one sub "dynamic-member"
if (dumpInfo != null) {
DumpInfo valueDumpInfo = dumpInfo.getChildInfos().remove(dumpInfo.getChildInfos().size() - 1);
DumpInfo nameDumpInfo = dumpInfo.getChildInfos().remove(dumpInfo.getChildInfos().size() - 1);
DumpInfo memberDumpInfo = new DumpInfo("member", "dynamic-member", "", nameDumpInfo.startByte, nameDumpInfo.lengthBytes + valueDumpInfo.lengthBytes);
memberDumpInfo.getChildInfos().add(nameDumpInfo);
memberDumpInfo.getChildInfos().add(valueDumpInfo);
memberDumpInfo.parent = dumpInfo;
nameDumpInfo.parent = memberDumpInfo;
valueDumpInfo.parent = memberDumpInfo;
memberDumpInfo.previewValue = "" + nameDumpInfo.previewValue + (valueDumpInfo.previewValue != null ? " : " + valueDumpInfo.previewValue : "");
dumpInfo.getChildInfos().add(memberDumpInfo);
}
}
}
renameLastDump("UTF-8-empty");
endDumpLevel();
}
LOGGER.log(Level.FINER, "Object value: dynamic={0},className={1},sealedSize={2},dynamicSize={3}", new Object[]{traits.isDynamic(), traits.getClassName(), sealedMembers.size(), dynamicMembers.size()});
result = retObjectType;
} else {
renameLastDump("U29O-ref");
renameU29O_ref();
int refIndexObject = (int) (objectU29 >> 1);
LOGGER.log(Level.FINER, "Object value: reference({0})", refIndexObject);
result = objectTable.get(refIndexObject);
@@ -483,11 +586,12 @@ public class Amf3InputStream extends InputStream {
break;
case Marker.XML:
renameLastDump("xml-marker");
setDumpInfoType("xml-type");
LOGGER.log(Level.FINE, "Read value: xml");
long xmlU29 = readU29("U29");
int xmlNoRefFlag = (int) (xmlU29 & 1);
if (xmlNoRefFlag == 1) {
renameLastDump("U29X-value");
renameU29("U29X-value", NO_REFERENCE_BIT_TEXT, "byte length");
long byteLength = (xmlU29 >> 1);
String xString = readUtf8Char("characters", byteLength);
XmlType retXmlType = new XmlType(xString);
@@ -495,7 +599,7 @@ public class Amf3InputStream extends InputStream {
objectTable.add(retXmlType);
result = retXmlType;
} else {
renameLastDump("U29O-ref");
renameU29O_ref();
int refIndexXml = (int) (xmlU29 >> 1);
LOGGER.log(Level.FINER, "XML value: reference({0})", refIndexXml);
result = objectTable.get(refIndexXml);
@@ -503,23 +607,26 @@ public class Amf3InputStream extends InputStream {
break;
case Marker.BYTE_ARRAY:
renameLastDump("byte-array-marker");
setDumpInfoType("bytearray-type");
LOGGER.log(Level.FINE, "Read value: bytearray");
long byteArrayU29 = readU29("U29");
int byteArrayNoRefFlag = (int) (byteArrayU29 & 1);
if (byteArrayNoRefFlag == 1) {
renameLastDump("U29B-value");
renameU29("U29B-value", NO_REFERENCE_BIT_TEXT, "byte array length");
int byteArrayLength = (int) (byteArrayU29 >> 1);
newDumpLevel("bytes", "U8[]");
byte byteArrayBuf[] = new byte[byteArrayLength];
if (is.read(byteArrayBuf) != byteArrayLength) {
throw new EndOfStreamException();
}
endDumpLevel();
LOGGER.log(Level.FINER, "ByteArray value: bytes[{0}]", byteArrayLength);
ByteArrayType retByteArrayType = new ByteArrayType(byteArrayBuf);
objectTable.add(retByteArrayType);
result = retByteArrayType;
} else {
renameLastDump("U290-ref");
renameU29O_ref();
int refIndexByteArray = (int) (byteArrayU29 >> 1);
LOGGER.log(Level.FINER, "ByteArray value: reference({0})", refIndexByteArray);
result = objectTable.get(refIndexByteArray);
@@ -527,23 +634,26 @@ public class Amf3InputStream extends InputStream {
break;
case Marker.VECTOR_INT:
renameLastDump("vector-int-marker");
setDumpInfoType("vector-int-type");
LOGGER.log(Level.FINE, "Read value: vector_int");
long vectorIntU29 = readU29("U29");
int vectorIntNoRefFlag = (int) (vectorIntU29 & 1);
if (vectorIntNoRefFlag == 1) {
renameLastDump("U29V-value");
renameU29("U29V-value", NO_REFERENCE_BIT_TEXT, "item count");
int vectorIntCountItems = (int) (vectorIntU29 >> 1);
int fixed = readU8("fixed");
List<Long> vals = new ArrayList<>();
newDumpLevel("items", "S32[]");
for (int i = 0; i < vectorIntCountItems; i++) {
vals.add(readS32("value"));
vals.add(readS32("intValue"));
}
endDumpLevel();
VectorIntType retVectorInt = new VectorIntType(fixed == 1, vals);
LOGGER.log(Level.FINER, "Vector<int> value: fixed={0}, size={1}]", new Object[]{fixed, vectorIntCountItems});
objectTable.add(retVectorInt);
result = retVectorInt;
} else {
renameLastDump("U29O-ref");
renameU29O_ref();
int refIndexVectorInt = (int) (vectorIntU29 >> 1);
LOGGER.log(Level.FINER, "Vector<int> value: reference({0})", refIndexVectorInt);
result = objectTable.get(refIndexVectorInt);
@@ -551,23 +661,27 @@ public class Amf3InputStream extends InputStream {
break;
case Marker.VECTOR_UINT:
renameLastDump("vector-uint-marker");
setDumpInfoType("vector-uint-type");
LOGGER.log(Level.FINE, "Read value: vector_uint");
long vectorUIntU29 = readU29("U29");
int vectorUIntNoRefFlag = (int) (vectorUIntU29 & 1);
if (vectorUIntNoRefFlag == 1) {
renameLastDump("U29V-value");
renameU29("U29V-value", NO_REFERENCE_BIT_TEXT, "item count");
int vectorUIntCountItems = (int) (vectorUIntU29 >> 1);
int fixed = readU8("fixed");
List<Long> vals = new ArrayList<>();
newDumpLevel("items", "U32[]");
for (int i = 0; i < vectorUIntCountItems; i++) {
vals.add(readU32("value"));
vals.add(readU32("uintValue"));
}
endDumpLevel();
VectorUIntType retVectorUInt = new VectorUIntType(fixed == 1, vals);
LOGGER.log(Level.FINER, "Vector<uint> value: fixed={0}, size={1}]", new Object[]{fixed, vectorUIntCountItems});
objectTable.add(retVectorUInt);
result = retVectorUInt;
} else {
renameLastDump("U29O-ref");
renameU29O_ref();
int refIndexVectorUInt = (int) (vectorUIntU29 >> 1);
LOGGER.log(Level.FINER, "Vector<uint> value: reference({0})", refIndexVectorUInt);
result = objectTable.get(refIndexVectorUInt);
@@ -575,23 +689,27 @@ public class Amf3InputStream extends InputStream {
break;
case Marker.VECTOR_DOUBLE:
renameLastDump("vector-double-marker");
setDumpInfoType("vector-double-type");
LOGGER.log(Level.FINE, "Read value: vector_double");
long vectorDoubleU29 = readU29("U29");
int vectorDoubleNoRefFlag = (int) (vectorDoubleU29 & 1);
if (vectorDoubleNoRefFlag == 1) {
renameLastDump("U29V-value");
renameU29("U29V-value", NO_REFERENCE_BIT_TEXT, "item count");
int vectorDoubleCountItems = (int) (vectorDoubleU29 >> 1);
int fixed = readU8("fixed");
List<Double> vals = new ArrayList<>();
newDumpLevel("items", "DOUBLE[]");
for (int i = 0; i < vectorDoubleCountItems; i++) {
vals.add(readDouble("value"));
vals.add(readDouble("doubleValue"));
}
endDumpLevel();
VectorDoubleType retVectorDouble = new VectorDoubleType(fixed == 1, vals);
LOGGER.log(Level.FINER, "Vector<double> value: fixed={0}, size={1}]", new Object[]{fixed, vectorDoubleCountItems});
objectTable.add(retVectorDouble);
result = retVectorDouble;
} else {
renameLastDump("U29O-ref");
renameU29O_ref();
int refIndexVectorDouble = (int) (vectorDoubleU29 >> 1);
LOGGER.log(Level.FINER, "Vector<double> value: reference({0})", refIndexVectorDouble);
result = objectTable.get(refIndexVectorDouble);
@@ -599,16 +717,19 @@ public class Amf3InputStream extends InputStream {
break;
case Marker.VECTOR_OBJECT:
renameLastDump("vector-object-marker");
setDumpInfoType("vector-object-type");
LOGGER.log(Level.FINE, "Read value: vector_object");
long vectorObjectU29 = readU29("U29");
int vectorObjectNoRefFlag = (int) (vectorObjectU29 & 1);
if (vectorObjectNoRefFlag == 1) {
renameLastDump("U29V-value");
renameU29("U29V-value", NO_REFERENCE_BIT_TEXT, "item count");
int vectorObjectCountItems = (int) (vectorObjectU29 >> 1);
int fixed = readU8("fixed");
String objectTypeName = readUtf8Vr("object-type-name", stringTable); //uses "*" for any type
List<Object> vals = new ArrayList<>();
NoSerializerExistsException error = null;
newDumpLevel("items", "value_type[]");
for (int i = 0; i < vectorObjectCountItems; i++) {
try {
vals.add(readValue("value", serializers, objectTable, traitsTable, stringTable));
@@ -621,6 +742,7 @@ public class Amf3InputStream extends InputStream {
break;
}
}
endDumpLevel();
VectorObjectType retVectorObject = new VectorObjectType(fixed == 1, objectTypeName, vals);
LOGGER.log(Level.FINER, "Vector<Object> value: fixed={0}, size={1}, typeName:{2}]", new Object[]{fixed, vectorObjectCountItems, objectTypeName});
objectTable.add(retVectorObject);
@@ -629,7 +751,7 @@ public class Amf3InputStream extends InputStream {
}
result = retVectorObject;
} else {
renameLastDump("U29O-ref");
renameU29O_ref();
int refIndexVectorObject = (int) (vectorObjectU29 >> 1);
LOGGER.log(Level.FINER, "Vector<Object> value: reference({0})", refIndexVectorObject);
@@ -638,16 +760,19 @@ public class Amf3InputStream extends InputStream {
break;
case Marker.DICTIONARY:
renameLastDump("dictionary-marker");
setDumpInfoType("dictionary-type");
long dictionaryObjectU29 = readU29("U29");
int dictionaryNoRefFlag = (int) (dictionaryObjectU29 & 1);
if (dictionaryNoRefFlag == 1) {
renameLastDump("U29Dict-value");
renameU29("U29Dict-value", NO_REFERENCE_BIT_TEXT, "entries count");
int numEntries = (int) (dictionaryObjectU29 >> 1);
int weakKeys = readU8("fixed");
int weakKeys = readU8("weak keys");
List<Pair<Object, Object>> data = new ArrayList<>();
DictionaryType retDictionary = new DictionaryType(weakKeys == 1, data);
objectTable.add(retDictionary);
NoSerializerExistsException error = null;
newDumpLevel("entries", "");
for (int i = 0; i < numEntries; i++) {
Object key;
Object val;
@@ -673,12 +798,13 @@ public class Amf3InputStream extends InputStream {
break;
}
}
endDumpLevel();
if (error != null) {
throw new NoSerializerExistsException(error.getClassName(), retDictionary, error);
}
result = retDictionary;
} else {
renameLastDump("U29O-ref");
renameU29O_ref();
int refIndexDictionary = (int) (dictionaryObjectU29 >> 1);
LOGGER.log(Level.FINER, "Dictionary value: reference({0})", refIndexDictionary);
result = objectTable.get(refIndexDictionary);
@@ -693,6 +819,29 @@ public class Amf3InputStream extends InputStream {
return result;
}
private static String valToPreviewString(Object v) {
if (v instanceof ObjectType) {
return "{...}";
}
if (v instanceof ArrayType) {
return "[...]";
}
if (v instanceof DictionaryType) {
return "";
}
if (v instanceof BasicType) {
return "";
}
if (v instanceof DateType) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SS");
return sdf.format(((DateType) v).toDate());
}
if (v instanceof String) {
return "\"" + Helper.escapeActionScriptString((String) v) + "\"";
}
return EcmaScript.toString(v);
}
private class MonitoredInputStream extends InputStream {
private final InputStream is;