mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-07-03 07:24:19 +00:00
AMF optimization: Pair type eliminated, ListSet and ListMap introduces (Set/Map which maintains order of keys)
This commit is contained in:
@@ -414,9 +414,9 @@ public class Amf3InputStream extends InputStream {
|
||||
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<>();
|
||||
Map<String, Object> assocPart = new ListMap<>();
|
||||
List<Object> densePart = new ArrayList<>();
|
||||
ArrayType retArray = new ArrayType(densePart, assocPart);
|
||||
ArrayType retArray = new ArrayType();
|
||||
objectTable.add(retArray); //add before processing elements which may reference this
|
||||
newDumpLevel("associativeValues", "assoc-value");
|
||||
while (true) {
|
||||
@@ -427,13 +427,15 @@ public class Amf3InputStream extends InputStream {
|
||||
} else {
|
||||
try {
|
||||
Object val = readValue("value", serializers, objectTable, traitsTable, stringTable);
|
||||
assocPart.add(new Pair<>(key, val));
|
||||
assocPart.put(key, val);
|
||||
} catch (NoSerializerExistsException nse) {
|
||||
assocPart.add(new Pair<>(key, nse.getIncompleteData()));
|
||||
assocPart.put(key, nse.getIncompleteData());
|
||||
retArray.setAssociativeValues(assocPart);
|
||||
throw new NoSerializerExistsException(nse.getClassName(), retArray, nse);
|
||||
}
|
||||
}
|
||||
}
|
||||
retArray.setAssociativeValues(assocPart);
|
||||
endDumpLevel();
|
||||
LOGGER.log(Level.FINEST, "Array value: assocSize={0}", new Object[]{assocPart.size()});
|
||||
|
||||
@@ -446,9 +448,12 @@ public class Amf3InputStream extends InputStream {
|
||||
for (int j = i + 1; j < denseCount; j++) {
|
||||
densePart.add(BasicType.UNKNOWN);
|
||||
}
|
||||
retArray.setDenseValues(densePart);
|
||||
throw new NoSerializerExistsException(nse.getClassName(), retArray, nse);
|
||||
}
|
||||
}
|
||||
retArray.setDenseValues(densePart);
|
||||
|
||||
endDumpLevel();
|
||||
LOGGER.log(Level.FINER, "Array value: dense_size={0},assocSize={1}", new Object[]{densePart.size(), assocPart.size()});
|
||||
result = retArray;
|
||||
@@ -477,11 +482,11 @@ public class Amf3InputStream extends InputStream {
|
||||
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);
|
||||
throw new NoSerializerExistsException(className, new ObjectType(new Traits(className, false, new ArrayList<>()), (byte[]) null, new HashMap<>()), null);
|
||||
}
|
||||
newDumpLevel("serializedData", "U8[]");
|
||||
MonitoredInputStream mis = new MonitoredInputStream(is);
|
||||
List<Pair<String, Object>> serMembers = serializers.get(className).readObject(className, mis);
|
||||
Map<String, Object> serMembers = serializers.get(className).readObject(className, mis);
|
||||
byte serData[] = mis.getReadData();
|
||||
endDumpLevel();
|
||||
Traits unserTraits = new Traits(className, false, new ArrayList<>());
|
||||
@@ -517,10 +522,10 @@ public class Amf3InputStream extends InputStream {
|
||||
traits = traitsTable.get(refIndexTraits);
|
||||
LOGGER.log(Level.FINER, "Traits value: reference({0}) - traitsize={1}", new Object[]{refIndexTraits, traits.getSealedMemberNames().size()});
|
||||
}
|
||||
List<Pair<String, Object>> sealedMembers = new ArrayList<>();
|
||||
List<Pair<String, Object>> dynamicMembers = new ArrayList<>();
|
||||
Map<String, Object> sealedMembers = new ListMap<>();
|
||||
Map<String, Object> dynamicMembers = new ListMap<>();
|
||||
|
||||
Object retObjectType = new ObjectType(traits, sealedMembers, dynamicMembers);
|
||||
ObjectType retObjectType = new ObjectType(traits);
|
||||
objectTable.add(retObjectType); //add it before any subvalue can reference it
|
||||
List<Object> sealedMemberValues = new ArrayList<>();
|
||||
NoSerializerExistsException error = null;
|
||||
@@ -541,18 +546,22 @@ public class Amf3InputStream extends InputStream {
|
||||
endDumpLevel();
|
||||
}
|
||||
|
||||
for (int i = 0; i < traits.getSealedMemberNames().size(); i++) {
|
||||
sealedMembers.add(new Pair<>(traits.getSealedMemberNames().get(i), sealedMemberValues.get(i)));
|
||||
List<String> memberNames = new ArrayList<>();
|
||||
memberNames.addAll(traits.getSealedMemberNames()); //Assuming it is ListSet so maintains order
|
||||
for (int i = 0; i < memberNames.size(); i++) {
|
||||
sealedMembers.put(memberNames.get(i), sealedMemberValues.get(i));
|
||||
}
|
||||
retObjectType.setSealedMembers(sealedMembers);
|
||||
if (traits.isDynamic()) {
|
||||
newDumpLevel("dynamicMembers", "dynamic-member[]");
|
||||
String dynamicMemberName;
|
||||
while (!(dynamicMemberName = readUtf8Vr("name", stringTable)).isEmpty()) {
|
||||
try {
|
||||
Object dynamicMemberValue = readValue("value", serializers, objectTable, traitsTable, stringTable);
|
||||
dynamicMembers.add(new Pair<>(dynamicMemberName, dynamicMemberValue));
|
||||
dynamicMembers.put(dynamicMemberName, dynamicMemberValue);
|
||||
} catch (NoSerializerExistsException nse) {
|
||||
dynamicMembers.add(new Pair<>(dynamicMemberName, nse.getIncompleteData()));
|
||||
dynamicMembers.put(dynamicMemberName, nse.getIncompleteData());
|
||||
retObjectType.setDynamicMembers(dynamicMembers);
|
||||
throw new NoSerializerExistsException(nse.getClassName(), retObjectType, nse);
|
||||
} finally {
|
||||
//group dumpInfo to one sub "dynamic-member"
|
||||
@@ -570,6 +579,7 @@ public class Amf3InputStream extends InputStream {
|
||||
}
|
||||
}
|
||||
}
|
||||
retObjectType.setDynamicMembers(dynamicMembers);
|
||||
renameLastDump("UTF-8-empty");
|
||||
endDumpLevel();
|
||||
}
|
||||
@@ -767,8 +777,8 @@ public class Amf3InputStream extends InputStream {
|
||||
renameU29("U29Dict-value", NO_REFERENCE_BIT_TEXT, "entries count");
|
||||
int numEntries = (int) (dictionaryObjectU29 >> 1);
|
||||
int weakKeys = readU8("weak keys");
|
||||
List<Pair<Object, Object>> data = new ArrayList<>();
|
||||
DictionaryType retDictionary = new DictionaryType(weakKeys == 1, data);
|
||||
Map<Object, Object> data = new ListMap<>(true);
|
||||
DictionaryType retDictionary = new DictionaryType(weakKeys == 1);
|
||||
objectTable.add(retDictionary);
|
||||
NoSerializerExistsException error = null;
|
||||
newDumpLevel("entries", "");
|
||||
@@ -789,10 +799,10 @@ public class Amf3InputStream extends InputStream {
|
||||
val = BasicType.UNKNOWN;
|
||||
}
|
||||
|
||||
data.add(new Pair<>(key, val));
|
||||
retDictionary.put(key, val);
|
||||
if (error != null) {
|
||||
for (int j = i + 1; j < numEntries; j++) {
|
||||
data.add(new Pair<>(BasicType.UNKNOWN, BasicType.UNKNOWN));
|
||||
retDictionary.put(BasicType.UNKNOWN, BasicType.UNKNOWN);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -175,9 +175,9 @@ public class Amf3OutputStream extends OutputStream {
|
||||
objectTable.add(val);
|
||||
|
||||
writeU29((val.getDenseValues().size() << 1) | NO_REFERENCE_FLAG);
|
||||
for (Pair<String, Object> p : val.getAssociativeValues()) {
|
||||
writeUtf8Vr(p.getFirst(), stringTable);
|
||||
writeValue(p.getSecond(), serializers, stringTable, traitsTable, objectTable);
|
||||
for (String key : val.associativeKeySet()) {
|
||||
writeUtf8Vr(key, stringTable);
|
||||
writeValue(val.getAssociative(key), serializers, stringTable, traitsTable, objectTable);
|
||||
}
|
||||
writeUtf8Vr("", stringTable);
|
||||
for (Object v : val.getDenseValues()) {
|
||||
@@ -207,22 +207,22 @@ public class Amf3OutputStream extends OutputStream {
|
||||
}
|
||||
} else {
|
||||
traitsTable.add(traits);
|
||||
writeU29((val.getSealedMembers().size() << 4) | NO_REFERENCE_FLAG | NO_TRAIT_REFERENCE_FLAG | (traits.isDynamic() ? DYNAMIC_FLAG : 0));
|
||||
writeU29((val.sealedMembersSize() << 4) | NO_REFERENCE_FLAG | NO_TRAIT_REFERENCE_FLAG | (traits.isDynamic() ? DYNAMIC_FLAG : 0));
|
||||
writeUtf8Vr(val.getClassName(), stringTable);
|
||||
for (Pair<String, Object> v : val.getSealedMembers()) {
|
||||
writeUtf8Vr(v.getFirst(), stringTable);
|
||||
for (String key : val.sealedMembersKeySet()) {
|
||||
writeUtf8Vr(key, stringTable);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
writeU29((traitsIndex << 2) | NO_REFERENCE_FLAG);
|
||||
}
|
||||
for (Pair<String, Object> v : val.getSealedMembers()) {
|
||||
writeValue(v.getSecond(), serializers, stringTable, traitsTable, objectTable);
|
||||
for (String key : val.sealedMembersKeySet()) {
|
||||
writeValue(val.getSealedMember(key), serializers, stringTable, traitsTable, objectTable);
|
||||
}
|
||||
if (traits.isDynamic()) {
|
||||
for (Pair<String, Object> v : val.getDynamicMembers()) {
|
||||
writeUtf8Vr(v.getFirst(), stringTable);
|
||||
writeValue(v.getSecond(), serializers, stringTable, traitsTable, objectTable);
|
||||
for (String key : val.dynamicMembersKeySet()) {
|
||||
writeUtf8Vr(key, stringTable);
|
||||
writeValue(val.getDynamicMember(key), serializers, stringTable, traitsTable, objectTable);
|
||||
}
|
||||
writeUtf8Vr("", stringTable);
|
||||
}
|
||||
@@ -349,11 +349,11 @@ public class Amf3OutputStream extends OutputStream {
|
||||
DictionaryType val = (DictionaryType) object;
|
||||
if (dictionaryIndex == -1) {
|
||||
objectTable.add(val);
|
||||
writeU29((val.getPairs().size() << 1) | NO_REFERENCE_FLAG);
|
||||
writeU29((val.size() << 1) | NO_REFERENCE_FLAG);
|
||||
writeU8(val.hasWeakKeys() ? 1 : 0);
|
||||
for (Pair<Object, Object> p : val.getPairs()) {
|
||||
writeValue(p.getFirst(), serializers, stringTable, traitsTable, objectTable);
|
||||
writeValue(p.getSecond(), serializers, stringTable, traitsTable, objectTable);
|
||||
for (Object key : val.keySet()) {
|
||||
writeValue(key, serializers, stringTable, traitsTable, objectTable);
|
||||
writeValue(val.get(key), serializers, stringTable, traitsTable, objectTable);
|
||||
}
|
||||
} else {
|
||||
writeU29(dictionaryIndex << 1);
|
||||
|
||||
@@ -0,0 +1,196 @@
|
||||
package com.jpexs.decompiler.flash.amf.amf3;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Map which maintains order of keys
|
||||
*
|
||||
* @param <K> Key type
|
||||
* @param <V> Value type
|
||||
*/
|
||||
public class ListMap<K, V> implements Map<K, V> {
|
||||
|
||||
private final Set<K> orderedKeys = new ListSet<>();
|
||||
private final Map<K, V> map;
|
||||
|
||||
/**
|
||||
* Creates new MaintainKeyOrderMap based on HashMap
|
||||
*/
|
||||
public ListMap() {
|
||||
this(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new MaintainKeyOrderMap
|
||||
*
|
||||
* @param useIdentityMap The HashMap will be based on IdentityHashMap
|
||||
*/
|
||||
public ListMap(boolean useIdentityMap) {
|
||||
this(useIdentityMap, new HashMap<>());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new MaintainKeyOrderMap based on HashMap
|
||||
*
|
||||
* @param m Initial items
|
||||
*/
|
||||
public ListMap(Map<? extends K, ? extends V> m) {
|
||||
this(false, m);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new MaintainKeyOrderMap
|
||||
*
|
||||
* @param useIdentityMap The HashMap will be based on IdentityHashMap
|
||||
* @param m Initial items
|
||||
*/
|
||||
public ListMap(boolean useIdentityMap, Map<? extends K, ? extends V> m) {
|
||||
if (useIdentityMap) {
|
||||
map = new IdentityHashMap<>();
|
||||
} else {
|
||||
map = new HashMap<>();
|
||||
}
|
||||
putAll(m);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return map.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return map.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
return map.containsKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object value) {
|
||||
return map.containsValue(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get(Object key) {
|
||||
return map.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V put(K key, V value) {
|
||||
orderedKeys.add(key);
|
||||
return map.put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V remove(Object key) {
|
||||
orderedKeys.remove(key);
|
||||
return map.remove(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Map<? extends K, ? extends V> m) {
|
||||
for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) {
|
||||
orderedKeys.add(e.getKey());
|
||||
}
|
||||
map.putAll(m);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
orderedKeys.clear();
|
||||
map.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<K> keySet() {
|
||||
return new ListSet<>(orderedKeys);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<V> values() {
|
||||
List<V> vals = new ArrayList<>();
|
||||
for (K key : orderedKeys) {
|
||||
vals.add(map.get(key));
|
||||
}
|
||||
return vals;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Entry<K, V>> entrySet() {
|
||||
Set<Entry<K, V>> ret = new ListSet<>();
|
||||
for (K key : orderedKeys) {
|
||||
V value = map.get(key);
|
||||
ret.add(new MyEntry<>(key, value));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static class MyEntry<K, V> implements Entry<K, V> {
|
||||
|
||||
private K key;
|
||||
private V value;
|
||||
|
||||
public MyEntry(K key, V value) {
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public K getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V setValue(V value) {
|
||||
V oldValue = this.value;
|
||||
this.value = value;
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 5;
|
||||
hash = 37 * hash + Objects.hashCode(this.key);
|
||||
hash = 37 * hash + Objects.hashCode(this.value);
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final MyEntry<?, ?> other = (MyEntry<?, ?>) obj;
|
||||
if (!Objects.equals(this.key, other.key)) {
|
||||
return false;
|
||||
}
|
||||
if (!Objects.equals(this.value, other.value)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
package com.jpexs.decompiler.flash.amf.amf3;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Set which maintains orders elements by time they were added
|
||||
*
|
||||
* @param <E>
|
||||
*/
|
||||
public class ListSet<E> implements Set<E> {
|
||||
|
||||
private final List<E> list = new ArrayList<>();
|
||||
|
||||
public ListSet() {
|
||||
|
||||
}
|
||||
|
||||
public ListSet(Collection<? extends E> c) {
|
||||
addAll(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return list.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return list.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
return list.contains(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<E> iterator() {
|
||||
return list.iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] toArray() {
|
||||
return list.toArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <E> E[] toArray(E[] a) {
|
||||
return (E[]) list.toArray(a);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(E e) {
|
||||
if (!contains(e)) {
|
||||
list.add(e);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object o) {
|
||||
return list.remove(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAll(Collection<?> c) {
|
||||
return list.containsAll(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(Collection<? extends E> c) {
|
||||
boolean modified = false;
|
||||
for (E e : c) {
|
||||
if (add(e)) {
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
return modified;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retainAll(Collection<?> c) {
|
||||
return list.retainAll(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAll(Collection<?> c) {
|
||||
return list.removeAll(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
list.clear();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,11 +3,11 @@ package com.jpexs.decompiler.flash.amf.amf3;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public interface ObjectTypeSerializeHandler {
|
||||
|
||||
public List<Pair<String, Object>> readObject(String className, InputStream is) throws IOException;
|
||||
public Map<String, Object> readObject(String className, InputStream is) throws IOException;
|
||||
|
||||
public void writeObject(List<Pair<String, Object>> members, OutputStream os) throws IOException;
|
||||
public void writeObject(Map<String, Object> members, OutputStream os) throws IOException;
|
||||
}
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
package com.jpexs.decompiler.flash.amf.amf3;
|
||||
|
||||
public class Pair<T1, T2> {
|
||||
|
||||
private T1 first;
|
||||
private T2 second;
|
||||
|
||||
public Pair(T1 first, T2 second) {
|
||||
this.first = first;
|
||||
this.second = second;
|
||||
}
|
||||
|
||||
public T1 getFirst() {
|
||||
return first;
|
||||
}
|
||||
|
||||
public T2 getSecond() {
|
||||
return second;
|
||||
}
|
||||
|
||||
public void setSecond(T2 second) {
|
||||
this.second = second;
|
||||
}
|
||||
|
||||
public void setFirst(T1 first) {
|
||||
this.first = first;
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,18 @@
|
||||
package com.jpexs.decompiler.flash.amf.amf3;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
|
||||
public class Traits {
|
||||
|
||||
private String className;
|
||||
private boolean dynamic;
|
||||
private List<String> sealedMemberNames;
|
||||
private Set<String> sealedMemberNames;
|
||||
|
||||
public Traits(String className, boolean dynamic, List<String> sealedMemberNames) {
|
||||
public Traits(String className, boolean dynamic, Collection<? extends String> sealedMemberNames) {
|
||||
this.className = className;
|
||||
this.dynamic = dynamic;
|
||||
this.sealedMemberNames = sealedMemberNames;
|
||||
this.sealedMemberNames = new ListSet<>(sealedMemberNames);
|
||||
}
|
||||
|
||||
public String getClassName() {
|
||||
@@ -22,8 +23,8 @@ public class Traits {
|
||||
return dynamic;
|
||||
}
|
||||
|
||||
public List<String> getSealedMemberNames() {
|
||||
return sealedMemberNames;
|
||||
public Set<String> getSealedMemberNames() {
|
||||
return new ListSet<>(sealedMemberNames);
|
||||
}
|
||||
|
||||
public void setClassName(String className) {
|
||||
@@ -34,8 +35,8 @@ public class Traits {
|
||||
this.dynamic = dynamic;
|
||||
}
|
||||
|
||||
public void setSealedMemberNames(List<String> sealedMemberNames) {
|
||||
this.sealedMemberNames = sealedMemberNames;
|
||||
public void setSealedMemberNames(Collection<? extends String> sealedMemberNames) {
|
||||
this.sealedMemberNames = new ListSet<>(sealedMemberNames);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,28 +1,69 @@
|
||||
package com.jpexs.decompiler.flash.amf.amf3.types;
|
||||
|
||||
import com.jpexs.decompiler.flash.amf.amf3.ListMap;
|
||||
import com.jpexs.decompiler.flash.exporters.amf.amf3.Amf3Exporter;
|
||||
import com.jpexs.decompiler.flash.amf.amf3.Pair;
|
||||
import com.jpexs.helpers.Helper;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import com.jpexs.decompiler.flash.amf.amf3.WithSubValues;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class ArrayType implements WithSubValues, Amf3ValueType {
|
||||
|
||||
private List<Object> denseValues;
|
||||
private List<Pair<String, Object>> associativeValues;
|
||||
private Map<String, Object> associativeValues;
|
||||
|
||||
public ArrayType(List<Object> denseValues, List<Pair<String, Object>> associativeValues) {
|
||||
this.denseValues = denseValues;
|
||||
this.associativeValues = associativeValues;
|
||||
public ArrayType(Map<? extends String, ? extends Object> associativeValues) {
|
||||
this(new ArrayList<>(), associativeValues);
|
||||
}
|
||||
|
||||
public ArrayType(List<Object> denseValues) {
|
||||
this(denseValues, new HashMap<>());
|
||||
}
|
||||
|
||||
public ArrayType() {
|
||||
this(new ArrayList<>(), new HashMap<>());
|
||||
}
|
||||
|
||||
public ArrayType(List<Object> denseValues, Map<? extends String, ? extends Object> associativeValues) {
|
||||
this.denseValues = new ArrayList<>(denseValues);
|
||||
this.associativeValues = new ListMap<>(associativeValues);
|
||||
}
|
||||
|
||||
public List<Object> getDenseValues() {
|
||||
return denseValues;
|
||||
return new ArrayList<>(denseValues);
|
||||
}
|
||||
|
||||
public List<Pair<String, Object>> getAssociativeValues() {
|
||||
return associativeValues;
|
||||
public void setDenseValues(List<Object> denseValues) {
|
||||
this.denseValues = new ArrayList<>(denseValues);
|
||||
}
|
||||
|
||||
public Object setDense(int key, Object value) {
|
||||
return denseValues.set(key, value);
|
||||
}
|
||||
|
||||
public Object putAssociative(String key, Object value) {
|
||||
return associativeValues.put(key, value);
|
||||
}
|
||||
|
||||
public Map<String, Object> getAssociativeValues() {
|
||||
return new ListMap<>(associativeValues);
|
||||
}
|
||||
|
||||
public Object getAssociative(String key) {
|
||||
return associativeValues.get(key);
|
||||
}
|
||||
|
||||
public Object getDense(int index) {
|
||||
if (index >= 0 && index < denseValues.size()) {
|
||||
return denseValues.get(index);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Set<String> associativeKeySet() {
|
||||
return associativeValues.keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -33,14 +74,14 @@ public class ArrayType implements WithSubValues, Amf3ValueType {
|
||||
@Override
|
||||
public List<Object> getSubValues() {
|
||||
List<Object> ret = new ArrayList<>();
|
||||
for (Pair<String, Object> p : associativeValues) {
|
||||
ret.add(p.getFirst());
|
||||
ret.add(p.getSecond());
|
||||
}
|
||||
for (Object v : denseValues) {
|
||||
ret.add(v);
|
||||
}
|
||||
ret.addAll(associativeValues.keySet());
|
||||
ret.addAll(associativeValues.values());
|
||||
ret.addAll(denseValues);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void setAssociativeValues(Map<String, Object> associativeValues) {
|
||||
this.associativeValues = new ListMap<>(associativeValues);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,32 +1,31 @@
|
||||
package com.jpexs.decompiler.flash.amf.amf3.types;
|
||||
|
||||
import com.jpexs.decompiler.flash.amf.amf3.ListMap;
|
||||
import com.jpexs.decompiler.flash.exporters.amf.amf3.Amf3Exporter;
|
||||
import com.jpexs.decompiler.flash.amf.amf3.Pair;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import com.jpexs.decompiler.flash.amf.amf3.WithSubValues;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class DictionaryType implements WithSubValues, Amf3ValueType {
|
||||
public class DictionaryType extends ListMap<Object, Object> implements WithSubValues, Amf3ValueType {
|
||||
|
||||
private boolean weakKeys;
|
||||
private List<Pair<Object, Object>> pairs;
|
||||
private final boolean weakKeys;
|
||||
|
||||
public DictionaryType(boolean weakKeys, List<Pair<Object, Object>> pairs) {
|
||||
this.weakKeys = weakKeys;
|
||||
this.pairs = pairs;
|
||||
public DictionaryType(boolean weakKeys) {
|
||||
this(weakKeys, new HashMap<>());
|
||||
}
|
||||
|
||||
public List<Pair<Object, Object>> getPairs() {
|
||||
return pairs;
|
||||
public DictionaryType(boolean weakKeys, Map<Object, Object> entries) {
|
||||
super(true /*IdentityMap*/, entries);
|
||||
this.weakKeys = weakKeys; //TODO? Really make the Map weak - something like WeakIdentityMap - but is it neccessary for serialization?
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Object> getSubValues() {
|
||||
List<Object> ret = new ArrayList<>();
|
||||
for (Pair<Object, Object> p : pairs) {
|
||||
ret.add(p.getFirst());
|
||||
ret.add(p.getSecond());
|
||||
}
|
||||
ret.addAll(keySet());
|
||||
ret.addAll(values());
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,18 +1,22 @@
|
||||
package com.jpexs.decompiler.flash.amf.amf3.types;
|
||||
|
||||
import com.jpexs.decompiler.flash.amf.amf3.ListSet;
|
||||
import com.jpexs.decompiler.flash.amf.amf3.ListMap;
|
||||
import com.jpexs.decompiler.flash.exporters.amf.amf3.Amf3Exporter;
|
||||
import com.jpexs.decompiler.flash.amf.amf3.Pair;
|
||||
import com.jpexs.decompiler.flash.amf.amf3.Traits;
|
||||
import com.jpexs.helpers.Helper;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import com.jpexs.decompiler.flash.amf.amf3.WithSubValues;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class ObjectType implements WithSubValues, Amf3ValueType {
|
||||
public class ObjectType implements WithSubValues, Amf3ValueType, Map<String, Object> {
|
||||
|
||||
private List<Pair<String, Object>> sealedMembers;
|
||||
private List<Pair<String, Object>> dynamicMembers;
|
||||
private List<Pair<String, Object>> serializedMembers;
|
||||
private Map<String, Object> sealedMembers;
|
||||
private Map<String, Object> dynamicMembers;
|
||||
private Map<String, Object> serializedMembers;
|
||||
//null = not serialized or unknown
|
||||
private byte[] serializedData = null;
|
||||
private boolean serialized;
|
||||
@@ -26,19 +30,23 @@ public class ObjectType implements WithSubValues, Amf3ValueType {
|
||||
return traits;
|
||||
}
|
||||
|
||||
public ObjectType(Traits traits, byte[] serializedData, List<Pair<String, Object>> serializedMembers) {
|
||||
public ObjectType(Traits traits, byte[] serializedData, Map<String, Object> serializedMembers) {
|
||||
this.traits = traits;
|
||||
this.serializedData = serializedData;
|
||||
this.serializedMembers = serializedMembers;
|
||||
this.dynamicMembers = new ArrayList<>();
|
||||
this.sealedMembers = new ArrayList<>();
|
||||
this.serializedMembers = new ListMap(serializedMembers);
|
||||
this.dynamicMembers = new ListMap<>();
|
||||
this.sealedMembers = new ListMap<>();
|
||||
this.serialized = true;
|
||||
}
|
||||
|
||||
public ObjectType(Traits traits, List<Pair<String, Object>> sealedMembers, List<Pair<String, Object>> dynamicMembers) {
|
||||
this.sealedMembers = sealedMembers;
|
||||
this.dynamicMembers = dynamicMembers;
|
||||
this.serializedMembers = new ArrayList<>();
|
||||
public ObjectType(Traits traits) {
|
||||
this(traits, new HashMap<>(), new HashMap<>());
|
||||
}
|
||||
|
||||
public ObjectType(Traits traits, Map<String, Object> sealedMembers, Map<String, Object> dynamicMembers) {
|
||||
this.sealedMembers = new ListMap<>(sealedMembers);
|
||||
this.dynamicMembers = new ListMap<>(dynamicMembers);
|
||||
this.serializedMembers = new ListMap<>();
|
||||
this.serialized = false;
|
||||
this.traits = traits;
|
||||
}
|
||||
@@ -47,14 +55,6 @@ public class ObjectType implements WithSubValues, Amf3ValueType {
|
||||
return traits.isDynamic();
|
||||
}
|
||||
|
||||
public List<Pair<String, Object>> getDynamicMembers() {
|
||||
return dynamicMembers;
|
||||
}
|
||||
|
||||
public List<Pair<String, Object>> getSealedMembers() {
|
||||
return sealedMembers;
|
||||
}
|
||||
|
||||
public String getClassName() {
|
||||
return traits.getClassName();
|
||||
}
|
||||
@@ -62,20 +62,14 @@ public class ObjectType implements WithSubValues, Amf3ValueType {
|
||||
@Override
|
||||
public List<Object> getSubValues() {
|
||||
List<Object> ret = new ArrayList<>();
|
||||
for (Pair<String, Object> p : dynamicMembers) {
|
||||
ret.add(p.getFirst());
|
||||
ret.add(p.getSecond());
|
||||
}
|
||||
for (Pair<String, Object> p : sealedMembers) {
|
||||
ret.add(p.getFirst());
|
||||
ret.add(p.getSecond());
|
||||
}
|
||||
ret.addAll(dynamicMembers.keySet());
|
||||
ret.addAll(dynamicMembers.values());
|
||||
|
||||
for (Pair<String, Object> p : serializedMembers) {
|
||||
ret.add(p.getFirst());
|
||||
ret.add(p.getSecond());
|
||||
}
|
||||
ret.addAll(sealedMembers.keySet());
|
||||
ret.addAll(sealedMembers.values());
|
||||
|
||||
ret.addAll(serializedMembers.keySet());
|
||||
ret.addAll(serializedMembers.values());
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -92,12 +86,227 @@ public class ObjectType implements WithSubValues, Amf3ValueType {
|
||||
return serializedData;
|
||||
}
|
||||
|
||||
public void setSerializedMembers(List<Pair<String, Object>> serializedMembers) {
|
||||
this.serializedMembers = serializedMembers;
|
||||
public void setSerializedMembers(Map<String, Object> serializedMembers) {
|
||||
this.serializedMembers = new ListMap<>(serializedMembers);
|
||||
}
|
||||
|
||||
public List<Pair<String, Object>> getSerializedMembers() {
|
||||
return serializedMembers;
|
||||
public Map<String, Object> getSerializedMembers() {
|
||||
return new ListMap<>(serializedMembers);
|
||||
}
|
||||
|
||||
public void setSealedMembers(Map<String, Object> sealedMembers) {
|
||||
this.sealedMembers = new ListMap<>(sealedMembers);
|
||||
}
|
||||
|
||||
public void setDynamicMembers(Map<String, Object> sealedMembers) {
|
||||
this.dynamicMembers = new ListMap<>(sealedMembers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return keySet().size();
|
||||
}
|
||||
|
||||
public int sealedMembersSize() {
|
||||
return sealedMembers.size();
|
||||
}
|
||||
|
||||
public int dynamicMembersSize() {
|
||||
return dynamicMembers.size();
|
||||
}
|
||||
|
||||
public int serializedMembersSize() {
|
||||
return serializedMembers.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return dynamicMembers.isEmpty() && sealedMembers.isEmpty() && serializedMembers.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
return dynamicMembers.containsKey(key) || sealedMembers.containsKey(key) || serializedMembers.containsKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object value) {
|
||||
return dynamicMembers.containsValue(value) || sealedMembers.containsValue(value) || serializedMembers.containsValue(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(Object key) {
|
||||
if (!(key instanceof String)) {
|
||||
return null;
|
||||
}
|
||||
String stringKey = (String) key;
|
||||
|
||||
if (dynamicMembers.containsKey(stringKey)) {
|
||||
return dynamicMembers.get(stringKey);
|
||||
}
|
||||
if (sealedMembers.containsKey(stringKey)) {
|
||||
return sealedMembers.get(stringKey);
|
||||
}
|
||||
if (serializedMembers.containsKey(stringKey)) {
|
||||
return serializedMembers.get(stringKey);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Object getSealedMember(Object key) {
|
||||
if (!(key instanceof String)) {
|
||||
return null;
|
||||
}
|
||||
String stringKey = (String) key;
|
||||
|
||||
return sealedMembers.get(stringKey);
|
||||
}
|
||||
|
||||
public Object getDynamicMember(Object key) {
|
||||
if (!(key instanceof String)) {
|
||||
return null;
|
||||
}
|
||||
String stringKey = (String) key;
|
||||
|
||||
return dynamicMembers.get(stringKey);
|
||||
}
|
||||
|
||||
public Object getSerializedMember(Object key) {
|
||||
if (!(key instanceof String)) {
|
||||
return null;
|
||||
}
|
||||
String stringKey = (String) key;
|
||||
|
||||
return serializedMembers.get(stringKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object put(String key, Object value) {
|
||||
return putDynamicMember(key, value);
|
||||
}
|
||||
|
||||
public Object putDynamicMember(String key, Object value) {
|
||||
remove(key);
|
||||
return dynamicMembers.put(key, value);
|
||||
}
|
||||
|
||||
public Object putSealedMember(String key, Object value) {
|
||||
remove(key);
|
||||
return sealedMembers.put(key, value);
|
||||
}
|
||||
|
||||
public Object putSerializedMember(String key, Object value) {
|
||||
remove(key);
|
||||
return serializedMembers.put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object remove(Object key) {
|
||||
if (!(key instanceof String)) {
|
||||
return null;
|
||||
}
|
||||
String stringKey = (String) key;
|
||||
if (dynamicMembers.containsKey(stringKey)) {
|
||||
return dynamicMembers.remove(stringKey);
|
||||
}
|
||||
if (sealedMembers.containsKey(stringKey)) {
|
||||
return sealedMembers.remove(stringKey);
|
||||
}
|
||||
if (serializedMembers.containsKey(stringKey)) {
|
||||
return serializedMembers.remove(stringKey);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Map<? extends String, ? extends Object> m) {
|
||||
for (Map.Entry<? extends String, ? extends Object> e : m.entrySet()) {
|
||||
put(e.getKey(), e.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
public void putAllDynamicMember(Map<? extends String, ? extends Object> m) {
|
||||
for (Map.Entry<? extends String, ? extends Object> e : m.entrySet()) {
|
||||
putDynamicMember(e.getKey(), e.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
public void putAllSealedMember(Map<? extends String, ? extends Object> m) {
|
||||
for (Map.Entry<? extends String, ? extends Object> e : m.entrySet()) {
|
||||
putSealedMember(e.getKey(), e.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
public void putAllSerializedMember(Map<? extends String, ? extends Object> m) {
|
||||
for (Map.Entry<? extends String, ? extends Object> e : m.entrySet()) {
|
||||
putSerializedMember(e.getKey(), e.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
clearDynamicMembers();
|
||||
clearSealedMembers();
|
||||
clearSerializedMembers();
|
||||
}
|
||||
|
||||
public void clearDynamicMembers() {
|
||||
dynamicMembers.clear();
|
||||
}
|
||||
|
||||
public void clearSealedMembers() {
|
||||
sealedMembers.clear();
|
||||
}
|
||||
|
||||
public void clearSerializedMembers() {
|
||||
serializedMembers.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> keySet() {
|
||||
Set<String> ret = new ListSet<>();
|
||||
ret.addAll(sealedMembers.keySet());
|
||||
ret.addAll(dynamicMembers.keySet());
|
||||
ret.addAll(serializedMembers.keySet());
|
||||
return ret;
|
||||
}
|
||||
|
||||
public Set<String> sealedMembersKeySet() {
|
||||
return new ListSet<>(sealedMembers.keySet());
|
||||
}
|
||||
|
||||
public Set<String> dynamicMembersKeySet() {
|
||||
return new ListSet<>(dynamicMembers.keySet());
|
||||
}
|
||||
|
||||
public Set<String> serializedMembersKeySet() {
|
||||
return new ListSet<>(serializedMembers.keySet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Object> values() {
|
||||
List<Object> values = new ArrayList<>();
|
||||
Set<String> keys = keySet();
|
||||
for (String key : keys) {
|
||||
if (dynamicMembers.containsKey(key)) {
|
||||
values.add(dynamicMembers.get(key));
|
||||
} else if (sealedMembers.containsKey(key)) {
|
||||
values.add(sealedMembers.get(key));
|
||||
} else {
|
||||
values.add(serializedMembers.get(key));
|
||||
}
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Entry<String, Object>> entrySet() {
|
||||
Set<String> keys = keySet();
|
||||
Set<Entry<String, Object>> ret = new ListSet<>();
|
||||
for (String key : keys) {
|
||||
ret.add(new ListMap.MyEntry<>(key, get(key)));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.jpexs.decompiler.flash.exporters.amf.amf3;
|
||||
|
||||
import com.jpexs.decompiler.flash.amf.amf3.Pair;
|
||||
import com.jpexs.decompiler.flash.amf.amf3.WithSubValues;
|
||||
import com.jpexs.decompiler.flash.amf.amf3.types.ArrayType;
|
||||
import com.jpexs.decompiler.flash.amf.amf3.types.XmlType;
|
||||
@@ -153,13 +152,17 @@ public class Amf3Exporter {
|
||||
ret.append(indent(level + 1)).append("\"serialized\": \"").append(javax.xml.bind.DatatypeConverter.printHexBinary(serData)).append("\",").append(newLine);
|
||||
if (!ot.getSerializedMembers().isEmpty()) {
|
||||
ret.append(indent(level + 1)).append("\"unserializedMembers\": {").append(newLine);
|
||||
for (int i = 0; i < ot.getSerializedMembers().size(); i++) {
|
||||
Pair<String, Object> member = ot.getSerializedMembers().get(i);
|
||||
ret.append(indent(level + 2)).append(amfToString(indentStr, newLine, processedObjects, level + 2, member.getFirst(), referenceCount, objectAlias)).append(":").append(amfToString(indentStr, newLine, processedObjects, level + 1, member.getSecond(), referenceCount, objectAlias));
|
||||
if (i < ot.getSerializedMembers().size() - 1) {
|
||||
ret.append(",").append(newLine);
|
||||
} else {
|
||||
ret.append(newLine);
|
||||
{
|
||||
int i = 0;
|
||||
for (String key : ot.sealedMembersKeySet()) {
|
||||
Object val = ot.getSealedMember(key);
|
||||
ret.append(indent(level + 2)).append(amfToString(indentStr, newLine, processedObjects, level + 2, key, referenceCount, objectAlias)).append(":").append(amfToString(indentStr, newLine, processedObjects, level + 1, val, referenceCount, objectAlias));
|
||||
if (i < ot.serializedMembersSize() - 1) {
|
||||
ret.append(",").append(newLine);
|
||||
} else {
|
||||
ret.append(newLine);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
ret.append(indent(level + 1)).append("}");
|
||||
@@ -170,13 +173,17 @@ public class Amf3Exporter {
|
||||
ret.append(indent(level + 1)).append("\"dynamic\": ").append(ot.isDynamic()).append(",").append(newLine);
|
||||
//if (!ot.getSealedMembers().isEmpty()) {
|
||||
ret.append(indent(level + 1)).append("\"sealedMembers\": {").append(newLine);
|
||||
for (int i = 0; i < ot.getSealedMembers().size(); i++) {
|
||||
Pair<String, Object> member = ot.getSealedMembers().get(i);
|
||||
ret.append(indent(level + 2)).append(amfToString(indentStr, newLine, processedObjects, level + 2, member.getFirst(), referenceCount, objectAlias)).append(":").append(amfToString(indentStr, newLine, processedObjects, level + 1, member.getSecond(), referenceCount, objectAlias));
|
||||
if (i < ot.getSealedMembers().size() - 1) {
|
||||
ret.append(",").append(newLine);
|
||||
} else {
|
||||
ret.append(newLine);
|
||||
{
|
||||
int i = 0;
|
||||
for (String key : ot.sealedMembersKeySet()) {
|
||||
Object val = ot.getSealedMember(key);
|
||||
ret.append(indent(level + 2)).append(amfToString(indentStr, newLine, processedObjects, level + 2, key, referenceCount, objectAlias)).append(":").append(amfToString(indentStr, newLine, processedObjects, level + 1, val, referenceCount, objectAlias));
|
||||
if (i < ot.sealedMembersSize() - 1) {
|
||||
ret.append(",").append(newLine);
|
||||
} else {
|
||||
ret.append(newLine);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
ret.append(indent(level + 1)).append("}");
|
||||
@@ -187,15 +194,19 @@ public class Amf3Exporter {
|
||||
//}
|
||||
//if (!ot.getDynamicMembers().isEmpty()) {
|
||||
ret.append(indent(level + 1)).append("\"dynamicMembers\": {").append(newLine);
|
||||
for (int i = 0; i < ot.getDynamicMembers().size(); i++) {
|
||||
Pair<String, Object> member = ot.getDynamicMembers().get(i);
|
||||
ret.append(indent(level + 2)).append(amfToString(indentStr, newLine, processedObjects, level + 2, member.getFirst(), referenceCount, objectAlias));
|
||||
ret.append(":");
|
||||
ret.append(amfToString(indentStr, newLine, processedObjects, level + 2, member.getSecond(), referenceCount, objectAlias));
|
||||
if (i < ot.getDynamicMembers().size() - 1) {
|
||||
ret.append(",");
|
||||
{
|
||||
int i = 0;
|
||||
for (String key : ot.dynamicMembersKeySet()) {
|
||||
Object val = ot.getDynamicMember(key);
|
||||
ret.append(indent(level + 2)).append(amfToString(indentStr, newLine, processedObjects, level + 2, key, referenceCount, objectAlias));
|
||||
ret.append(":");
|
||||
ret.append(amfToString(indentStr, newLine, processedObjects, level + 2, val, referenceCount, objectAlias));
|
||||
if (i < ot.dynamicMembersSize() - 1) {
|
||||
ret.append(",");
|
||||
}
|
||||
ret.append(newLine);
|
||||
i++;
|
||||
}
|
||||
ret.append(newLine);
|
||||
}
|
||||
ret.append(indent(level + 1)).append("}").append(newLine);
|
||||
//}
|
||||
@@ -219,13 +230,17 @@ public class Amf3Exporter {
|
||||
if (!at.getAssociativeValues().isEmpty()) {
|
||||
ret.append(newLine);
|
||||
}
|
||||
for (int i = 0; i < at.getAssociativeValues().size(); i++) {
|
||||
Pair<String, Object> p = at.getAssociativeValues().get(i);
|
||||
ret.append(indent(level + 2)).append(amfToString(indentStr, newLine, processedObjects, level + 1, p.getFirst(), referenceCount, objectAlias)).append(" : ").append(amfToString(indentStr, newLine, processedObjects, level + 1, p.getSecond(), referenceCount, objectAlias));
|
||||
if (i < at.getAssociativeValues().size() - 1) {
|
||||
ret.append(",");
|
||||
{
|
||||
int i = 0;
|
||||
for (String key : at.associativeKeySet()) {
|
||||
Object val = at.getAssociative(key);
|
||||
ret.append(indent(level + 2)).append(amfToString(indentStr, newLine, processedObjects, level + 1, key, referenceCount, objectAlias)).append(" : ").append(amfToString(indentStr, newLine, processedObjects, level + 1, val, referenceCount, objectAlias));
|
||||
if (i < at.getAssociativeValues().size() - 1) {
|
||||
ret.append(",");
|
||||
}
|
||||
ret.append(newLine);
|
||||
i++;
|
||||
}
|
||||
ret.append(newLine);
|
||||
}
|
||||
if (!at.getAssociativeValues().isEmpty()) {
|
||||
ret.append(indent(level + 1));
|
||||
@@ -239,13 +254,17 @@ public class Amf3Exporter {
|
||||
ret.append(addId);
|
||||
ret.append(indent(level + 1)).append("\"weakKeys\": ").append(dt.hasWeakKeys()).append(",").append(newLine);
|
||||
ret.append(indent(level + 1)).append("\"entries\": {").append(newLine);
|
||||
for (int i = 0; i < dt.getPairs().size(); i++) {
|
||||
Pair<Object, Object> pair = dt.getPairs().get(i);
|
||||
ret.append(indent(level + 1)).append(amfToString(indentStr, newLine, processedObjects, level + 1, pair.getFirst(), referenceCount, objectAlias)).append(" : ").append(amfToString(indentStr, newLine, processedObjects, level + 1, pair.getSecond(), referenceCount, objectAlias));
|
||||
if (i < dt.getPairs().size() - 1) {
|
||||
ret.append(",");
|
||||
{
|
||||
int i = 0;
|
||||
for (Object key : dt.keySet()) {
|
||||
Object val = dt.get(key);
|
||||
ret.append(indent(level + 1)).append(amfToString(indentStr, newLine, processedObjects, level + 1, key, referenceCount, objectAlias)).append(" : ").append(amfToString(indentStr, newLine, processedObjects, level + 1, val, referenceCount, objectAlias));
|
||||
if (i < dt.size() - 1) {
|
||||
ret.append(",");
|
||||
}
|
||||
ret.append(newLine);
|
||||
i++;
|
||||
}
|
||||
ret.append(newLine);
|
||||
}
|
||||
ret.append(indent(level + 1)).append("}").append(newLine);
|
||||
ret.append(indent(level)).append("}");
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.jpexs.decompiler.flash.importers.amf.amf3;
|
||||
|
||||
import com.jpexs.decompiler.flash.amf.amf3.Pair;
|
||||
import com.jpexs.decompiler.flash.amf.amf3.ListMap;
|
||||
import com.jpexs.decompiler.flash.amf.amf3.Traits;
|
||||
import com.jpexs.decompiler.flash.amf.amf3.types.ArrayType;
|
||||
import com.jpexs.decompiler.flash.amf.amf3.types.BasicType;
|
||||
@@ -22,6 +22,7 @@ import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class Amf3Importer {
|
||||
|
||||
@@ -111,17 +112,29 @@ public class Amf3Importer {
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("{");
|
||||
for (Pair<Object, Object> p : values) {
|
||||
sb.append(p.getFirst()).append(":").append("?").append(",\r\n");
|
||||
for (Object key : values.keySet()) {
|
||||
sb.append(key).append(":").append("?").append(",\r\n");
|
||||
}
|
||||
sb.append("}");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private final List<Pair<Object, Object>> values = new ArrayList<>();
|
||||
private final Map<Object, Object> values = new ListMap<>();
|
||||
|
||||
public void add(Object key, Object value) {
|
||||
values.add(new Pair<>(key, value));
|
||||
public Object remove(Object key) {
|
||||
return values.remove(key);
|
||||
}
|
||||
|
||||
public Set<Object> keySet() {
|
||||
return values.keySet();
|
||||
}
|
||||
|
||||
public Object get(Object key) {
|
||||
return values.get(key);
|
||||
}
|
||||
|
||||
public void put(Object key, Object value) {
|
||||
values.put(key, value);
|
||||
}
|
||||
|
||||
public String getString(Object key) throws Amf3ParseException {
|
||||
@@ -251,64 +264,35 @@ public class Amf3Importer {
|
||||
}
|
||||
|
||||
public boolean containsKey(Object key) {
|
||||
for (Pair<Object, Object> p : values) {
|
||||
if (p.getFirst().equals(key)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public Object get(Object key) {
|
||||
for (Pair<Object, Object> p : values) {
|
||||
if (p.getFirst().equals(key)) {
|
||||
return p.getSecond();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return values.containsKey(key);
|
||||
}
|
||||
|
||||
public void resolve(Object key, Map<String, Object> objectTable, boolean allowTypedObject) throws Amf3ParseException {
|
||||
for (Pair<Object, Object> p : values) {
|
||||
if (p.getFirst().equals(key)) {
|
||||
Object resolved = resolveObjects(p.getSecond(), objectTable, allowTypedObject);
|
||||
p.setSecond(resolved);
|
||||
return;
|
||||
}
|
||||
}
|
||||
Object val = values.get(key);
|
||||
Object resolved = resolveObjects(val, objectTable, allowTypedObject);
|
||||
values.put(key, resolved);
|
||||
}
|
||||
|
||||
public List<String> stringKeys() {
|
||||
List<String> ret = new ArrayList<>();
|
||||
for (Pair<Object, Object> p : values) {
|
||||
if (p.getFirst() instanceof String) {
|
||||
ret.add((String) p.getFirst());
|
||||
for (Object key : values.keySet()) {
|
||||
if (key instanceof String) {
|
||||
ret.add((String) key);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public List<Pair<Object, Object>> getAll() {
|
||||
public Map<Object, Object> getAll() {
|
||||
return values;
|
||||
}
|
||||
|
||||
public List<Pair<String, Object>> getStringMapped() {
|
||||
List<Pair<String, Object>> ret = new ArrayList<>();
|
||||
for (Pair<Object, Object> p : values) {
|
||||
if (p.getFirst() instanceof String) {
|
||||
String keyStr = (String) p.getFirst();
|
||||
ret.add(new Pair<>(keyStr, p.getSecond()));
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public Map<String, Object> getStringMap() {
|
||||
Map<String, Object> ret = new HashMap<>();
|
||||
for (Pair<Object, Object> p : values) {
|
||||
if (p.getFirst() instanceof String) {
|
||||
String keyStr = (String) p.getFirst();
|
||||
ret.put(keyStr, values);
|
||||
public Map<String, Object> getStringMapped() {
|
||||
Map<String, Object> ret = new ListMap<>();
|
||||
for (Object key : values.keySet()) {
|
||||
if (key instanceof String) {
|
||||
String keyStr = (String) key;
|
||||
ret.put(keyStr, values.get(key));
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
@@ -326,7 +310,7 @@ public class Amf3Importer {
|
||||
Object key = value(objectTable);
|
||||
expectedType(SymbolType.COLON);
|
||||
Object value = value(objectTable);
|
||||
ret.add(key, value);
|
||||
ret.put(key, value);
|
||||
if ("id".equals(key)) {
|
||||
if (!(value instanceof String)) {
|
||||
throw new Amf3ParseException("id must be string value", lexer.yyline());
|
||||
@@ -381,9 +365,9 @@ public class Amf3Importer {
|
||||
typedObject.resolve("sealedMembers", objectTable, false);
|
||||
JsObject jsoSealed = typedObject.getJsObject("sealedMembers");
|
||||
|
||||
List<Pair<String, Object>> sealedMembers = jsoSealed.getStringMapped();
|
||||
Map<String, Object> sealedMembers = jsoSealed.getStringMapped();
|
||||
typedObject.resolve("dynamicMembers", objectTable, false);
|
||||
List<Pair<String, Object>> dynamicMembers = typedObject.getJsObject("dynamicMembers").getStringMapped();
|
||||
Map<String, Object> dynamicMembers = typedObject.getJsObject("dynamicMembers").getStringMapped();
|
||||
|
||||
List<String> sealedMemberNames = new ArrayList<>(jsoSealed.stringKeys());
|
||||
resultObject = new ObjectType(new Traits(className, dynamic, sealedMemberNames), sealedMembers, dynamicMembers);
|
||||
@@ -394,7 +378,7 @@ public class Amf3Importer {
|
||||
List<Object> denseValues = typedObject.getJsArray("denseValues").getValues();
|
||||
typedObject.resolve("associativeValues", objectTable, false);
|
||||
JsObject resolvedArr = typedObject.getJsObject("associativeValues");
|
||||
List<Pair<String, Object>> associativeValues = resolvedArr.getStringMapped();
|
||||
Map<String, Object> associativeValues = resolvedArr.getStringMapped();
|
||||
resultObject = new ArrayType(denseValues, associativeValues);
|
||||
break;
|
||||
|
||||
@@ -427,7 +411,7 @@ public class Amf3Importer {
|
||||
case "Dictionary":
|
||||
boolean weakKeys = typedObject.getBoolean("weakKeys");
|
||||
typedObject.resolve("entries", objectTable, false);
|
||||
List<Pair<Object, Object>> entries = typedObject.getJsObject("entries").getAll();
|
||||
Map<Object, Object> entries = typedObject.getJsObject("entries").getAll();
|
||||
resultObject = new DictionaryType(weakKeys, entries);
|
||||
break;
|
||||
default:
|
||||
@@ -439,9 +423,12 @@ public class Amf3Importer {
|
||||
}
|
||||
} else { //not allowTypeObject
|
||||
JsObject jsObject = (JsObject) object;
|
||||
for (Pair<Object, Object> p : jsObject.getAll()) {
|
||||
p.setFirst(resolveObjects(p.getFirst(), objectTable, true));
|
||||
p.setSecond(resolveObjects(p.getSecond(), objectTable, true));
|
||||
for (Object key : jsObject.keySet()) {
|
||||
Object val = jsObject.get(key);
|
||||
Object resKey = resolveObjects(key, objectTable, true);
|
||||
Object resVal = resolveObjects(val, objectTable, true);
|
||||
jsObject.remove(key);
|
||||
jsObject.put(resKey, resVal);
|
||||
}
|
||||
resultObject = jsObject;
|
||||
}
|
||||
@@ -496,19 +483,23 @@ public class Amf3Importer {
|
||||
return objectsTable.get(key);
|
||||
} else if (object instanceof ObjectType) {
|
||||
ObjectType ot = (ObjectType) object;
|
||||
for (Pair<String, Object> p : ot.getSealedMembers()) {
|
||||
p.setSecond(replaceReferences(p.getSecond(), objectsTable));
|
||||
for (String key : ot.sealedMembersKeySet()) {
|
||||
ot.putSealedMember(key, replaceReferences(ot.getSealedMember(key), objectsTable));
|
||||
}
|
||||
for (Pair<String, Object> p : ot.getDynamicMembers()) {
|
||||
p.setSecond(replaceReferences(p.getSecond(), objectsTable));
|
||||
for (String key : ot.dynamicMembersKeySet()) {
|
||||
ot.putDynamicMember(key, replaceReferences(ot.getDynamicMember(key), objectsTable));
|
||||
}
|
||||
for (String key : ot.serializedMembersKeySet()) {
|
||||
ot.putSerializedMember(key, replaceReferences(ot.getSerializedMember(key), objectsTable));
|
||||
}
|
||||
|
||||
} else if (object instanceof ArrayType) {
|
||||
ArrayType at = (ArrayType) object;
|
||||
for (Pair<String, Object> p : at.getAssociativeValues()) {
|
||||
p.setSecond(replaceReferences(p.getSecond(), objectsTable));
|
||||
for (String key : at.associativeKeySet()) {
|
||||
at.putAssociative(key, replaceReferences(at.getAssociative(key), objectsTable));
|
||||
}
|
||||
for (int i = 0; i < at.getDenseValues().size(); i++) {
|
||||
at.getDenseValues().set(i, replaceReferences(at.getDenseValues().get(i), objectsTable));
|
||||
at.setDense(i, replaceReferences(at.getDense(i), objectsTable));
|
||||
}
|
||||
} else if (object instanceof VectorObjectType) {
|
||||
VectorObjectType vot = (VectorObjectType) object;
|
||||
@@ -517,9 +508,12 @@ public class Amf3Importer {
|
||||
}
|
||||
} else if (object instanceof DictionaryType) {
|
||||
DictionaryType dt = (DictionaryType) object;
|
||||
for (Pair<Object, Object> p : dt.getPairs()) {
|
||||
p.setFirst(replaceReferences(p.getFirst(), objectsTable));
|
||||
p.setSecond(replaceReferences(p.getSecond(), objectsTable));
|
||||
for (Object key : dt.keySet()) {
|
||||
Object val = dt.get(key);
|
||||
Object newKey = replaceReferences(key, objectsTable);
|
||||
Object newVal = replaceReferences(val, objectsTable);
|
||||
dt.remove(key);
|
||||
dt.put(newKey, newVal);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,6 @@ import com.jpexs.decompiler.flash.SWFCompression;
|
||||
import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.action.Action;
|
||||
import com.jpexs.decompiler.flash.amf.amf3.Amf3Value;
|
||||
import com.jpexs.decompiler.flash.amf.amf3.Pair;
|
||||
import com.jpexs.decompiler.flash.amf.amf3.types.ObjectType;
|
||||
import com.jpexs.decompiler.flash.configuration.Configuration;
|
||||
import com.jpexs.decompiler.flash.exporters.MovieExporter;
|
||||
@@ -1199,9 +1198,8 @@ public class XFLConverter {
|
||||
if (metadataObject.isDynamic()) {
|
||||
writer.writeStartElement("persistentData");
|
||||
List<String> exportedNames = new ArrayList<>();
|
||||
for (Pair<String, Object> dynamicMember : metadataObject.getDynamicMembers()) {
|
||||
String n = dynamicMember.getFirst();
|
||||
Object v = dynamicMember.getSecond();
|
||||
for (String n : metadataObject.dynamicMembersKeySet()) {
|
||||
Object v = metadataObject.getDynamicMember(n);
|
||||
if (v instanceof Long) {
|
||||
exportedNames.add(n);
|
||||
writer.writeStartElement("PD");
|
||||
|
||||
Reference in New Issue
Block a user