package com.intellij.flex.uiDesigner.io;
import com.intellij.util.PairConsumer;
import gnu.trove.TIntArrayList;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.io.Identifiable;
import java.io.IOException;
import java.util.Collection;
import java.util.List;
public class AmfOutputStream extends PrimitiveAmfOutputStream {
private static final byte[] STRING_ALIAS = {3, 115};
TransactionableStringIntHashMap stringTable;
TransactionableStringIntHashMap traitsTable;
public AmfOutputStream(AbstractByteArrayOutputStream out) {
super(out);
}
public void resetAfterMessage() {
if (stringTable != null) {
stringTable.clear();
}
if (traitsTable != null) {
traitsTable.clear();
}
}
@Override
public void reset() {
resetAfterMessage();
super.reset();
}
/**
* Write array as fixed flash Vector.<int>
*
* @param array of int
* @throws IOException if an I/O error occurs or if array length out of range (29-bit number)
*/
public void write(int[] array) {
write(Amf3Types.VECTOR_INT);
writeUInt29((array.length << 1) | 1);
write(true);
for (int i : array) {
writeInt(i);
}
}
/**
* Write array as fixed flash Vector.<String>
*/
public void write(String[] array) {
write(Amf3Types.VECTOR_OBJECT);
writeUInt29((array.length << 1) | 1);
write(true);
write(STRING_ALIAS);
for (String s : array) {
write(Amf3Types.STRING);
writeAmfUtf(s, true);
}
}
@SuppressWarnings({"UnusedDeclaration"})
public void writeStringCollection(Collection<String> collection) {
write(Amf3Types.VECTOR_OBJECT);
writeUInt29((collection.size() << 1) | 1);
write(true);
write(STRING_ALIAS);
for (String s : collection) {
write(Amf3Types.STRING);
writeAmfUtf(s, true);
}
}
public <T> void write(Collection<T> collection, PairConsumer<T, AmfOutputStream> outConsumer) {
writeUInt29(collection.size());
for (T e : collection) {
outConsumer.consume(e, this);
}
}
public <T extends Identifiable> void write(@Nullable List<T> collection) {
writeUInt29(collection == null ? 0 : collection.size());
if (collection == null) {
return;
}
for (Identifiable e : collection) {
writeUInt29(e.getId());
}
}
public void write(Collection<TIntArrayList> collection) {
writeUInt29(collection.size());
for (TIntArrayList list : collection) {
writeUInt29(list.size());
list.forEach(value -> {
writeUInt29(value);
return true;
});
}
}
public void write(Collection collection, Class elementType) {
write(collection, elementType.getName(), false);
}
public void write(Collection collection, String elementTypeName, boolean homogeneous) {
write(collection, elementTypeName, homogeneous, false);
}
public void write(Collection collection, String elementTypeName, boolean homogeneous, boolean emptyAsNull) {
if (collection == null || (emptyAsNull && collection.isEmpty())) {
write(Amf3Types.NULL);
}
else {
writeVector(collection, true, elementTypeName, homogeneous);
}
}
public void write(String s) {
if (s == null) {
write(Amf3Types.NULL);
}
else {
write(Amf3Types.STRING);
writeStringWithoutType(s);
}
}
public void writeAmfByteArray(byte[] bytes) {
writeUInt29(bytes.length);
write(bytes);
}
private void writeVector(Collection collection, boolean fixed, String elementTypeName, boolean homogeneous) {
write(Amf3Types.VECTOR_OBJECT);
final int n = collection.size();
writeUInt29((n << 1) | 1);
write(fixed);
if (elementTypeName.equals("java.lang.Object")) {
writeUInt29(1);
}
else {
writeStringWithoutType(elementTypeName);
}
if (n == 0) {
return;
}
for (Object current : collection) {
if (current == null) {
write(Amf3Types.NULL);
}
else {
write(Amf3Types.OBJECT);
writeObjectTraits(homogeneous ? elementTypeName : current.getClass().getName());
((AmfOutputable)current).writeExternal(this);
}
}
}
void writeStringWithoutType(String s) {
if (s.isEmpty()) {
write(1);
}
else if (!byReference(s)) {
writeAmfUtf(s, true);
}
}
private boolean byReference(String s) {
if (stringTable == null) {
stringTable = new TransactionableStringIntHashMap(32);
}
else {
int reference = stringTable.get(s);
if (reference != -1) {
writeUInt29(reference << 1);
return true;
}
}
stringTable.put(s, stringTable.size());
return false;
}
public void writeObjectTraits(String className) {
if (!traitsByReference(className)) {
write(7);
writeStringWithoutType(className);
}
}
private boolean traitsByReference(String s) {
if (traitsTable == null) {
traitsTable = new TransactionableStringIntHashMap(8);
}
else {
int reference = traitsTable.get(s);
if (reference != -1) {
writeUInt29((reference << 2) | 1);
return true;
}
}
traitsTable.put(s, traitsTable.size());
return false;
}
}