Skip to content

Commit

Permalink
Add deserializer
Browse files Browse the repository at this point in the history
  • Loading branch information
liias committed Apr 26, 2016
1 parent 61b6a0d commit 1acc531
Show file tree
Hide file tree
Showing 17 changed files with 515 additions and 31 deletions.
19 changes: 11 additions & 8 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ allprojects {
sourceCompatibility = 1.8
targetCompatibility = 1.8
tasks.withType(JavaCompile) { options.encoding = 'UTF-8' }

apply plugin: 'org.jetbrains.intellij'

intellij {
Expand All @@ -25,9 +25,19 @@ allprojects {
}
}

group 'io.github.liias'
version pluginVersion

repositories {
mavenCentral()
flatDir {
dirs 'lib'
}
}

dependencies {
compile project(':jps-plugin')
compile project(':deserializer')
}

sourceSets.main.java.srcDirs += 'src/main/gen'
Expand All @@ -50,11 +60,4 @@ afterEvaluate {
task("debugIdea", type: RunIdeaTask, group: 'intellij', dependsOn: 'prepareSandbox') {
jvmArgs += ["-Dcompiler.process.debug.port=9128"]
}
}

group 'io.github.liias'
version pluginVersion

repositories {
mavenCentral()
}
1 change: 1 addition & 0 deletions deserializer/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
jar.archiveName = "deserializer.jar"
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package io.github.liias.monkey.deserializer;

import io.github.liias.monkey.deserializer.type.MonkeyType;
import io.github.liias.monkey.deserializer.type.MonkeyTypeCollection;
import io.github.liias.monkey.deserializer.type.MonkeyTypeString;
import org.jetbrains.annotations.NotNull;

import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.IntStream;

public class Deserializer {
private static final int STRING_BLOCK_MARKER = 0xABCDABCD;
private static final int DATA_BLOCK_MARKER = 0xDA7ADA7A;

@NotNull
private final List<MonkeyType> monkeyTypes;

@NotNull
private final Map<Integer, String> stringsByOffset;

public Deserializer(byte[] bytes) {
int stringBlockOffset = 0;
int stringBlockSize = getBlockSize(bytes, stringBlockOffset, STRING_BLOCK_MARKER);
byte[] stringBlockBytes = getBlockBytes(bytes, stringBlockOffset, stringBlockSize);
stringsByOffset = deserializeStrings(stringBlockBytes);

int dataBlockOffset = stringBlockSize == 0 ? 0 : stringBlockSize + 8;
int dataBlockSize = getBlockSize(bytes, dataBlockOffset, DATA_BLOCK_MARKER);
byte[] dataBlockBytes = getBlockBytes(bytes, dataBlockOffset, dataBlockSize);

monkeyTypes = deserializeDataBlock(dataBlockBytes);
}

public List<MonkeyType> getTypes() {
return monkeyTypes;
}

private static Map<Integer, String> deserializeStrings(byte[] bytes) {
Map<Integer, String> stringsByOffset = new HashMap<>();

int offset = 0;
while (offset < bytes.length) {
int stringSize = ByteBuffer.wrap(bytes, offset, 2).getShort();
byte[] stringBytes = Arrays.copyOfRange(bytes, offset + 2, offset + 2 + stringSize - 1);
String stringValue = new String(stringBytes, StandardCharsets.UTF_8);
stringsByOffset.put(offset, stringValue);
offset += (2 + stringSize);
}

return stringsByOffset;
}

private List<MonkeyType> deserializeDataBlock(byte[] bytes) {
LinkedList<MonkeyType> deserializedQueue = fillDeserializedQueue(bytes);
return fillCollections(deserializedQueue);
}

@NotNull
private LinkedList<MonkeyType> fillDeserializedQueue(byte[] bytes) {
LinkedList<MonkeyType> deserializedQueue = new LinkedList<>();
int i = 0;
while (i < bytes.length) {
byte type = bytes[i];
int size = MonkeyType.getSize(type);
ByteBuffer bb = ByteBuffer.wrap(bytes, 1 + i, size);
MonkeyType monkeyType = MonkeyType.of(type, bb);
if (monkeyType instanceof MonkeyTypeString) {
MonkeyTypeString monkeyTypeString = (MonkeyTypeString) monkeyType;
monkeyTypeString.setValue(stringsByOffset.get(monkeyTypeString.getOffset()));
}
deserializedQueue.add(monkeyType);
i = i + 1 + monkeyType.getSize();
}
return deserializedQueue;
}

private List<MonkeyType> fillCollections(LinkedList<MonkeyType> deserializedQueue) {
List<MonkeyType> deserialized = new ArrayList<>();

do {
MonkeyType monkeyType = deserializedQueue.poll();
if (monkeyType instanceof MonkeyTypeCollection) {
fillCollection((MonkeyTypeCollection) monkeyType, deserializedQueue);
}
deserialized.add(monkeyType);
} while (!deserializedQueue.isEmpty());
return deserialized;
}

private static void fillCollection(MonkeyTypeCollection monkeyType, LinkedList<MonkeyType> deserializedQueue) {
IntStream.range(0, monkeyType.getChildCount()).forEach(i -> monkeyType.fill(deserializedQueue));
monkeyType.getChildren().stream()
.filter(mt -> mt instanceof MonkeyTypeCollection)
.map(mt -> (MonkeyTypeCollection) mt)
.forEach(mt -> fillCollection(mt, deserializedQueue));
}

private static byte[] getBlockBytes(byte[] bytes, int offset, int size) {
if (size > 0) {
return Arrays.copyOfRange(bytes, offset + 8, offset + 8 + size);
}
return new byte[0];
}

private static int getBlockSize(byte[] bytes, int offset, int startMarker) {
ByteBuffer bb = ByteBuffer.wrap(bytes, offset, 8);
// getInt() also increments position by 4
if (bb.getInt() == startMarker) {
return bb.getInt();
}
return 0;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package io.github.liias.monkey.deserializer.type;

import com.google.common.collect.ImmutableMap;

import java.nio.ByteBuffer;
import java.util.Map;

public abstract class MonkeyType<T> {

public abstract T getValue();

public abstract int getSize();

public interface Type {
byte NULL = 0;
byte INT = 1;
byte FLOAT = 2;
byte STRING = 3;
byte ARRAY = 5;
byte BOOLEAN = 9;
byte HASH = 11;
}

public static Map<Byte, Integer> sizes = ImmutableMap.<Byte, Integer>builder()
.put(Type.NULL, 0)
.put(Type.INT, 4)
.put(Type.FLOAT, 4)
.put(Type.STRING, 4)
.put(Type.ARRAY, 4)
.put(Type.BOOLEAN, 1)
.put(Type.HASH, 4)
.build();

public static int getSize(byte type) {
return sizes.get(type);
}

public static MonkeyType of(byte type, ByteBuffer bb) {
switch (type) {
case Type.NULL:
return new MonkeyTypeNull();
case Type.INT:
return new MonkeyTypeInt(bb);
case Type.FLOAT:
return new MonkeyTypeFloat(bb);
case Type.STRING:
return new MonkeyTypeString(bb);
case Type.ARRAY:
return new MonkeyTypeArray(bb);
case Type.BOOLEAN:
return new MonkeyTypeBool(bb);
case Type.HASH:
return new MonkeyTypeHash(bb);
}

throw new IllegalArgumentException("unknown type");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package io.github.liias.monkey.deserializer.type;

import org.jetbrains.annotations.NotNull;

import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

public class MonkeyTypeArray extends MonkeyType<List<MonkeyType>> implements MonkeyTypeCollection {

private final int childCount;

@NotNull
private final List<MonkeyType> items;

public MonkeyTypeArray(ByteBuffer bb) {
childCount = bb.getInt();
items = new ArrayList<>();
}

@Override
public int getChildCount() {
return childCount;
}

@Override
public List<MonkeyType> getValue() {
return items;
}

@Override
public int getSize() {
return 4;
}

public void add(MonkeyType monkeyType) {
items.add(monkeyType);
}

@Override
public void fill(LinkedList<MonkeyType> deserializedQueue) {
add(deserializedQueue.poll());
}

@Override
public List<MonkeyType> getChildren() {
return items;
}

@Override
public String toString() {
return Arrays.toString(items.toArray());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package io.github.liias.monkey.deserializer.type;

import java.nio.ByteBuffer;

public class MonkeyTypeBool extends MonkeyType<Boolean> {
final boolean value;

public MonkeyTypeBool(ByteBuffer bb) {
value = bb.get() > 0;
}

@Override
public Boolean getValue() {
return value;
}

@Override
public int getSize() {
return 1;
}

@Override
public String toString() {
return String.valueOf(value);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package io.github.liias.monkey.deserializer.type;

import java.util.LinkedList;
import java.util.List;

public interface MonkeyTypeCollection {
int getChildCount();

void fill(LinkedList<MonkeyType> deserializedQueue);

List<MonkeyType> getChildren();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package io.github.liias.monkey.deserializer.type;

import java.nio.ByteBuffer;

public class MonkeyTypeFloat extends MonkeyType<Float> {

private final float value;

public MonkeyTypeFloat(ByteBuffer bb) {
value = bb.getFloat();
}

@Override
public Float getValue() {
return value;
}

@Override
public int getSize() {
return 4;
}

@Override
public String toString() {
return String.valueOf(value);
}

}
Loading

0 comments on commit 1acc531

Please sign in to comment.