Migrated to Kotlin

This commit is contained in:
Christian Basler 2017-09-21 16:25:03 +02:00
parent 48f4848c0a
commit 69bb57d0c3
27 changed files with 1262 additions and 1620 deletions

View File

@ -4,14 +4,14 @@ Simple MessagePack
[![Javadoc](https://javadoc-emblem.rhcloud.com/doc/ch.dissem.msgpack/msgpack/badge.svg)](http://www.javadoc.io/doc/ch.dissem.msgpack/msgpack)
[![Apache 2](https://img.shields.io/badge/license-Apache_2.0-blue.svg)](https://raw.githubusercontent.com/Dissem/Jabit/master/LICENSE)
This is a simple Java library for handling MessagePack data. It doesn't do any object mapping, but maps to special
objects representing MessagePack types. To build, use command `./gradlew build`.
This is a simple Kotlin/Java library for handling MessagePack data. It doesn't do any object mapping, but maps to
special objects representing MessagePack types. To build, use command `./gradlew build`.
For most cases you might be better off using `org.msgpack:msgpack`, but I found that I needed something that generically
represents the internal structure of the data.
_Simple MessagePack_ uses Semantic Versioning, meaning as long as the major version doesn't change, nothing should break if you
update. Be aware though that this doesn't necessarily applies for SNAPSHOT builds and the development branch.
_Simple MessagePack_ uses Semantic Versioning, meaning as long as the major version doesn't change, nothing should break
if you update. Be aware though that this doesn't necessarily applies for SNAPSHOT builds and the development branch.
#### Master

View File

@ -50,7 +50,7 @@ class GitFlowVersion implements Plugin<Project> {
project.ext.isRelease = isRelease(project)
project.version = getVersion(project)
project.task('version') << {
project.task('version').doLast {
println "Version deduced from git: '${project.version}'"
}
}

View File

@ -1,6 +1,6 @@
#Tue Jan 17 07:22:12 CET 2017
#Tue Sep 19 21:21:56 CEST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-3.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-bin.zip

2
gradlew vendored
View File

@ -154,7 +154,7 @@ if $cygwin ; then
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an value, following the shell quoting and substitution rules
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}

View File

@ -1,64 +0,0 @@
/*
* Copyright 2017 Christian Basler
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ch.dissem.msgpack;
import ch.dissem.msgpack.types.*;
import java.io.IOException;
import java.io.InputStream;
import java.util.LinkedList;
/**
* Reads MPType object from an {@link InputStream}.
*/
public class Reader {
private LinkedList<MPType.Unpacker<?>> unpackers = new LinkedList<>();
private static final Reader instance = new Reader();
private Reader() {
unpackers.add(new MPNil.Unpacker());
unpackers.add(new MPBoolean.Unpacker());
unpackers.add(new MPInteger.Unpacker());
unpackers.add(new MPFloat.Unpacker());
unpackers.add(new MPString.Unpacker());
unpackers.add(new MPBinary.Unpacker());
unpackers.add(new MPMap.Unpacker(this));
unpackers.add(new MPArray.Unpacker(this));
}
public static Reader getInstance() {
return instance;
}
/**
* Register your own extensions
*/
public void register(MPType.Unpacker<?> unpacker) {
unpackers.addFirst(unpacker);
}
public MPType read(InputStream in) throws IOException {
int firstByte = in.read();
for (MPType.Unpacker<?> unpacker : unpackers) {
if (unpacker.is(firstByte)) {
return unpacker.unpack(firstByte, in);
}
}
throw new IOException(String.format("Unsupported input, no reader for 0x%02x", firstByte));
}
}

View File

@ -1,256 +0,0 @@
/*
* Copyright 2017 Christian Basler
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ch.dissem.msgpack.types;
import ch.dissem.msgpack.Reader;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.util.*;
/**
* Representation of a msgpack encoded array. Uses a list to represent data internally, and implements the {@link List}
* interface for your convenience.
*
* @param <T>
*/
public class MPArray<T extends MPType> implements MPType<List<T>>, List<T> {
private List<T> array;
public MPArray() {
this.array = new LinkedList<>();
}
public MPArray(List<T> array) {
this.array = array;
}
@SafeVarargs
public MPArray(T... objects) {
this.array = Arrays.asList(objects);
}
public List<T> getValue() {
return array;
}
public void pack(OutputStream out) throws IOException {
int size = array.size();
if (size < 16) {
out.write(0b10010000 + size);
} else if (size < 65536) {
out.write(0xDC);
out.write(ByteBuffer.allocate(2).putShort((short) size).array());
} else {
out.write(0xDD);
out.write(ByteBuffer.allocate(4).putInt(size).array());
}
for (MPType o : array) {
o.pack(out);
}
}
@Override
public int size() {
return array.size();
}
@Override
public boolean isEmpty() {
return array.isEmpty();
}
@Override
public boolean contains(Object o) {
return array.contains(o);
}
@Override
public Iterator<T> iterator() {
return array.iterator();
}
@Override
public Object[] toArray() {
return array.toArray();
}
@Override
@SuppressWarnings("SuspiciousToArrayCall")
public <T1> T1[] toArray(T1[] t1s) {
return array.toArray(t1s);
}
@Override
public boolean add(T t) {
return array.add(t);
}
@Override
public boolean remove(Object o) {
return array.remove(o);
}
@Override
public boolean containsAll(Collection<?> collection) {
return array.containsAll(collection);
}
@Override
public boolean addAll(Collection<? extends T> collection) {
return array.addAll(collection);
}
@Override
public boolean addAll(int i, Collection<? extends T> collection) {
return array.addAll(i, collection);
}
@Override
public boolean removeAll(Collection<?> collection) {
return array.removeAll(collection);
}
@Override
public boolean retainAll(Collection<?> collection) {
return array.retainAll(collection);
}
@Override
public void clear() {
array.clear();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MPArray<?> mpArray = (MPArray<?>) o;
return Objects.equals(array, mpArray.array);
}
@Override
public int hashCode() {
return Objects.hash(array);
}
@Override
public T get(int i) {
return array.get(i);
}
@Override
public T set(int i, T t) {
return array.set(i, t);
}
@Override
public void add(int i, T t) {
array.add(i, t);
}
@Override
public T remove(int i) {
return array.remove(i);
}
@Override
public int indexOf(Object o) {
return array.indexOf(o);
}
@Override
public int lastIndexOf(Object o) {
return array.lastIndexOf(o);
}
@Override
public ListIterator<T> listIterator() {
return array.listIterator();
}
@Override
public ListIterator<T> listIterator(int i) {
return array.listIterator(i);
}
@Override
public List<T> subList(int fromIndex, int toIndex) {
return array.subList(fromIndex, toIndex);
}
@Override
public String toString() {
return toJson();
}
@Override
public String toJson() {
return toJson("");
}
String toJson(String indent) {
StringBuilder result = new StringBuilder();
result.append("[\n");
Iterator<T> iterator = array.iterator();
String indent2 = indent + " ";
while (iterator.hasNext()) {
T item = iterator.next();
result.append(indent2);
result.append(Utils.toJson(item, indent2));
if (iterator.hasNext()) {
result.append(',');
}
result.append('\n');
}
result.append("]");
return result.toString();
}
public static class Unpacker implements MPType.Unpacker<MPArray> {
private final Reader reader;
public Unpacker(Reader reader) {
this.reader = reader;
}
public boolean is(int firstByte) {
return firstByte == 0xDC || firstByte == 0xDD || (firstByte & 0b11110000) == 0b10010000;
}
public MPArray<MPType<?>> unpack(int firstByte, InputStream in) throws IOException {
int size;
if ((firstByte & 0b11110000) == 0b10010000) {
size = firstByte & 0b00001111;
} else if (firstByte == 0xDC) {
size = in.read() << 8 | in.read();
} else if (firstByte == 0xDD) {
size = in.read() << 24 | in.read() << 16 | in.read() << 8 | in.read();
} else {
throw new IllegalArgumentException(String.format("Unexpected first byte 0x%02x", firstByte));
}
List<MPType<?>> list = new LinkedList<>();
for (int i = 0; i < size; i++) {
MPType value = reader.read(in);
list.add(value);
}
return new MPArray<>(list);
}
}
}

View File

@ -1,98 +0,0 @@
/*
* Copyright 2017 Christian Basler
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ch.dissem.msgpack.types;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.util.Arrays;
import static ch.dissem.msgpack.types.Utils.bytes;
/**
* Representation of msgpack encoded binary data a.k.a. byte array.
*/
public class MPBinary implements MPType<byte[]> {
private byte[] value;
public MPBinary(byte[] value) {
this.value = value;
}
public byte[] getValue() {
return value;
}
public void pack(OutputStream out) throws IOException {
int size = value.length;
if (size < 256) {
out.write(0xC4);
out.write((byte) size);
} else if (size < 65536) {
out.write(0xC5);
out.write(ByteBuffer.allocate(2).putShort((short) size).array());
} else {
out.write(0xC6);
out.write(ByteBuffer.allocate(4).putInt(size).array());
}
out.write(value);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MPBinary mpBinary = (MPBinary) o;
return Arrays.equals(value, mpBinary.value);
}
@Override
public int hashCode() {
return Arrays.hashCode(value);
}
@Override
public String toString() {
return toJson();
}
@Override
public String toJson() {
return Utils.base64(value);
}
public static class Unpacker implements MPType.Unpacker<MPBinary> {
public boolean is(int firstByte) {
return firstByte == 0xC4 || firstByte == 0xC5 || firstByte == 0xC6;
}
public MPBinary unpack(int firstByte, InputStream in) throws IOException {
int size;
if (firstByte == 0xC4) {
size = in.read();
} else if (firstByte == 0xC5) {
size = in.read() << 8 | in.read();
} else if (firstByte == 0xC6) {
size = in.read() << 24 | in.read() << 16 | in.read() << 8 | in.read();
} else {
throw new IllegalArgumentException(String.format("Unexpected first byte 0x%02x", firstByte));
}
return new MPBinary(bytes(in, size).array());
}
}
}

View File

@ -1,88 +0,0 @@
/*
* Copyright 2017 Christian Basler
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ch.dissem.msgpack.types;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Objects;
/**
* Representation of a msgpack encoded boolean.
*/
public class MPBoolean implements MPType<Boolean> {
private final static int FALSE = 0xC2;
private final static int TRUE = 0xC3;
private final boolean value;
public MPBoolean(boolean value) {
this.value = value;
}
public Boolean getValue() {
return value;
}
public void pack(OutputStream out) throws IOException {
if (value) {
out.write(TRUE);
} else {
out.write(FALSE);
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MPBoolean mpBoolean = (MPBoolean) o;
return value == mpBoolean.value;
}
@Override
public int hashCode() {
return Objects.hash(value);
}
@Override
public String toString() {
return String.valueOf(value);
}
@Override
public String toJson() {
return String.valueOf(value);
}
public static class Unpacker implements MPType.Unpacker<MPBoolean> {
public boolean is(int firstByte) {
return firstByte == TRUE || firstByte == FALSE;
}
public MPBoolean unpack(int firstByte, InputStream in) {
if (firstByte == TRUE) {
return new MPBoolean(true);
} else if (firstByte == FALSE) {
return new MPBoolean(false);
} else {
throw new IllegalArgumentException(String.format("0xC2 or 0xC3 expected but was 0x%02x", firstByte));
}
}
}
}

View File

@ -1,110 +0,0 @@
/*
* Copyright 2017 Christian Basler
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ch.dissem.msgpack.types;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.util.Objects;
import static ch.dissem.msgpack.types.Utils.bytes;
/**
* Representation of a msgpack encoded float32 or float64 number.
*/
public class MPFloat implements MPType<Double> {
public enum Precision {FLOAT32, FLOAT64}
private final double value;
private final Precision precision;
public MPFloat(float value) {
this.value = value;
this.precision = Precision.FLOAT32;
}
public MPFloat(double value) {
this.value = value;
this.precision = Precision.FLOAT64;
}
@Override
public Double getValue() {
return value;
}
public Precision getPrecision() {
return precision;
}
public void pack(OutputStream out) throws IOException {
switch (precision) {
case FLOAT32:
out.write(0xCA);
out.write(ByteBuffer.allocate(4).putFloat((float) value).array());
break;
case FLOAT64:
out.write(0xCB);
out.write(ByteBuffer.allocate(8).putDouble(value).array());
break;
default:
throw new IllegalArgumentException("Unknown precision: " + precision);
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MPFloat mpFloat = (MPFloat) o;
return Double.compare(mpFloat.value, value) == 0;
}
@Override
public int hashCode() {
return Objects.hash(value);
}
@Override
public String toString() {
return String.valueOf(value);
}
@Override
public String toJson() {
return String.valueOf(value);
}
public static class Unpacker implements MPType.Unpacker<MPFloat> {
public boolean is(int firstByte) {
return firstByte == 0xCA || firstByte == 0xCB;
}
public MPFloat unpack(int firstByte, InputStream in) throws IOException {
switch (firstByte) {
case 0xCA:
return new MPFloat(bytes(in, 4).getFloat());
case 0xCB:
return new MPFloat(bytes(in, 8).getDouble());
default:
throw new IllegalArgumentException(String.format("Unexpected first byte 0x%02x", firstByte));
}
}
}
}

View File

@ -1,160 +0,0 @@
/*
* Copyright 2017 Christian Basler
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ch.dissem.msgpack.types;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.util.Objects;
import static ch.dissem.msgpack.types.Utils.bytes;
/**
* Representation of a msgpack encoded integer. The encoding is automatically selected according to the value's size.
* Uses long due to the fact that the msgpack integer implementation may contain up to 64 bit numbers, corresponding
* to Java long values. Also note that uint64 values may be too large for signed long (thanks Java for not supporting
* unsigned values) and end in a negative value.
*/
public class MPInteger implements MPType<Long> {
private long value;
public MPInteger(long value) {
this.value = value;
}
@Override
public Long getValue() {
return value;
}
public void pack(OutputStream out) throws IOException {
if ((value > ((byte) 0b11100000) && value < 0x80)) {
out.write((int) value);
} else if (value > 0) {
if (value <= 0xFF) {
out.write(0xCC);
out.write((int) value);
} else if (value <= 0xFFFF) {
out.write(0xCD);
out.write(ByteBuffer.allocate(2).putShort((short) value).array());
} else if (value <= 0xFFFFFFFFL) {
out.write(0xCE);
out.write(ByteBuffer.allocate(4).putInt((int) value).array());
} else {
out.write(0xCF);
out.write(ByteBuffer.allocate(8).putLong(value).array());
}
} else {
if (value >= -32) {
out.write(new byte[]{
(byte) value
});
} else if (value >= Byte.MIN_VALUE) {
out.write(0xD0);
out.write(ByteBuffer.allocate(1).put((byte) value).array());
} else if (value >= Short.MIN_VALUE) {
out.write(0xD1);
out.write(ByteBuffer.allocate(2).putShort((short) value).array());
} else if (value >= Integer.MIN_VALUE) {
out.write(0xD2);
out.write(ByteBuffer.allocate(4).putInt((int) value).array());
} else {
out.write(0xD3);
out.write(ByteBuffer.allocate(8).putLong(value).array());
}
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MPInteger mpInteger = (MPInteger) o;
return value == mpInteger.value;
}
@Override
public int hashCode() {
return Objects.hash(value);
}
@Override
public String toString() {
return String.valueOf(value);
}
@Override
public String toJson() {
return String.valueOf(value);
}
public static class Unpacker implements MPType.Unpacker<MPInteger> {
public boolean is(int firstByte) {
switch (firstByte) {
case 0xCC:
case 0xCD:
case 0xCE:
case 0xCF:
case 0xD0:
case 0xD1:
case 0xD2:
case 0xD3:
return true;
default:
return (firstByte & 0b10000000) == 0 || (firstByte & 0b11100000) == 0b11100000;
}
}
public MPInteger unpack(int firstByte, InputStream in) throws IOException {
if ((firstByte & 0b10000000) == 0 || (firstByte & 0b11100000) == 0b11100000) {
return new MPInteger((byte) firstByte);
} else {
switch (firstByte) {
case 0xCC:
return new MPInteger(in.read());
case 0xCD:
return new MPInteger(in.read() << 8 | in.read());
case 0xCE: {
long value = 0;
for (int i = 0; i < 4; i++) {
value = value << 8 | in.read();
}
return new MPInteger(value);
}
case 0xCF: {
long value = 0;
for (int i = 0; i < 8; i++) {
value = value << 8 | in.read();
}
return new MPInteger(value);
}
case 0xD0:
return new MPInteger(bytes(in, 1).get());
case 0xD1:
return new MPInteger(bytes(in, 2).getShort());
case 0xD2:
return new MPInteger(bytes(in, 4).getInt());
case 0xD3:
return new MPInteger(bytes(in, 8).getLong());
default:
throw new IllegalArgumentException(String.format("Unexpected first byte 0x%02x", firstByte));
}
}
}
}
}

View File

@ -1,185 +0,0 @@
package ch.dissem.msgpack.types;
import ch.dissem.msgpack.Reader;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.util.*;
/**
* Representation of a msgpack encoded map. It is recommended to use a {@link LinkedHashMap} to ensure the order
* of entries. For convenience, it also implements the {@link Map} interface.
*
* @param <K>
* @param <V>
*/
public class MPMap<K extends MPType, V extends MPType> implements MPType<Map<K, V>>, Map<K, V> {
private Map<K, V> map;
public MPMap() {
this.map = new LinkedHashMap<>();
}
public MPMap(Map<K, V> map) {
this.map = map;
}
@Override
public Map<K, V> getValue() {
return map;
}
public void pack(OutputStream out) throws IOException {
int size = map.size();
if (size < 16) {
out.write(0x80 + size);
} else if (size < 65536) {
out.write(0xDE);
out.write(ByteBuffer.allocate(2).putShort((short) size).array());
} else {
out.write(0xDF);
out.write(ByteBuffer.allocate(4).putInt(size).array());
}
for (Map.Entry<K, V> e : map.entrySet()) {
e.getKey().pack(out);
e.getValue().pack(out);
}
}
@Override
public int size() {
return map.size();
}
@Override
public boolean isEmpty() {
return map.isEmpty();
}
@Override
public boolean containsKey(Object o) {
return map.containsKey(o);
}
@Override
public boolean containsValue(Object o) {
return map.containsValue(o);
}
@Override
public V get(Object o) {
return map.get(o);
}
@Override
public V put(K k, V v) {
return map.put(k, v);
}
@Override
public V remove(Object o) {
return map.remove(o);
}
@Override
public void putAll(Map<? extends K, ? extends V> map) {
this.map.putAll(map);
}
@Override
public void clear() {
map.clear();
}
@Override
public Set<K> keySet() {
return map.keySet();
}
@Override
public Collection<V> values() {
return map.values();
}
@Override
public Set<Entry<K, V>> entrySet() {
return map.entrySet();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MPMap<?, ?> mpMap = (MPMap<?, ?>) o;
return Objects.equals(map, mpMap.map);
}
@Override
public int hashCode() {
return Objects.hash(map);
}
@Override
public String toString() {
return toJson();
}
String toJson(String indent) {
StringBuilder result = new StringBuilder();
result.append("{\n");
Iterator<Map.Entry<K, V>> iterator = map.entrySet().iterator();
String indent2 = indent + " ";
while (iterator.hasNext()) {
Map.Entry<K, V> item = iterator.next();
result.append(indent2);
result.append(Utils.toJson(item.getKey(), indent2));
result.append(": ");
result.append(Utils.toJson(item.getValue(), indent2));
if (iterator.hasNext()) {
result.append(',');
}
result.append('\n');
}
result.append(indent).append("}");
return result.toString();
}
@Override
public String toJson() {
return toJson("");
}
public static class Unpacker implements MPType.Unpacker<MPMap> {
private final Reader reader;
public Unpacker(Reader reader) {
this.reader = reader;
}
public boolean is(int firstByte) {
return firstByte == 0xDE || firstByte == 0xDF || (firstByte & 0xF0) == 0x80;
}
public MPMap<MPType<?>, MPType<?>> unpack(int firstByte, InputStream in) throws IOException {
int size;
if ((firstByte & 0xF0) == 0x80) {
size = firstByte & 0x0F;
} else if (firstByte == 0xDE) {
size = in.read() << 8 | in.read();
} else if (firstByte == 0xDF) {
size = in.read() << 24 | in.read() << 16 | in.read() << 8 | in.read();
} else {
throw new IllegalArgumentException(String.format("Unexpected first byte 0x%02x", firstByte));
}
Map<MPType<?>, MPType<?>> map = new LinkedHashMap<>();
for (int i = 0; i < size; i++) {
MPType key = reader.read(in);
MPType value = reader.read(in);
map.put(key, value);
}
return new MPMap<>(map);
}
}
}

View File

@ -1,70 +0,0 @@
/*
* Copyright 2017 Christian Basler
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ch.dissem.msgpack.types;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* Representation of msgpack encoded nil / null.
*/
public class MPNil implements MPType<Void> {
private final static int NIL = 0xC0;
public Void getValue() {
return null;
}
public void pack(OutputStream out) throws IOException {
out.write(NIL);
}
@Override
public int hashCode() {
return 0;
}
@Override
public boolean equals(Object o) {
return o instanceof MPNil;
}
@Override
public String toString() {
return "null";
}
@Override
public String toJson() {
return "null";
}
public static class Unpacker implements MPType.Unpacker<MPNil> {
public boolean is(int firstByte) {
return firstByte == NIL;
}
public MPNil unpack(int firstByte, InputStream in) {
if (firstByte != NIL) {
throw new IllegalArgumentException(String.format("0xC0 expected but was 0x%02x", firstByte));
}
return new MPNil();
}
}
}

View File

@ -1,185 +0,0 @@
/*
* Copyright 2017 Christian Basler
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ch.dissem.msgpack.types;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.util.Objects;
import static ch.dissem.msgpack.types.Utils.bytes;
/**
* Representation of a msgpack encoded string. The encoding is automatically selected according to the string's length.
* <p>
* The default encoding is UTF-8.
* </p>
*/
public class MPString implements MPType<String>, CharSequence {
private static final int FIXSTR_PREFIX = 0b10100000;
private static final int FIXSTR_PREFIX_FILTER = 0b11100000;
private static final int STR8_PREFIX = 0xD9;
private static final int STR8_LIMIT = 256;
private static final int STR16_PREFIX = 0xDA;
private static final int STR16_LIMIT = 65536;
private static final int STR32_PREFIX = 0xDB;
private static final int FIXSTR_FILTER = 0b00011111;
private static Charset encoding = Charset.forName("UTF-8");
private final String value;
/**
* Use this method if for some messed up reason you really need to use something else than UTF-8.
* Ask yourself: why should I? Is this really necessary?
* <p>
* It will set the encoding for all {@link MPString}s, but if you have inconsistent encoding in your
* format you're lost anyway.
* </p>
*/
public static void setEncoding(Charset encoding) {
MPString.encoding = encoding;
}
public MPString(String value) {
this.value = value;
}
public String getValue() {
return value;
}
public void pack(OutputStream out) throws IOException {
byte[] bytes = value.getBytes(encoding);
int size = bytes.length;
if (size < 32) {
out.write(FIXSTR_PREFIX + size);
} else if (size < STR8_LIMIT) {
out.write(STR8_PREFIX);
out.write(size);
} else if (size < STR16_LIMIT) {
out.write(STR16_PREFIX);
out.write(ByteBuffer.allocate(2).putShort((short) size).array());
} else {
out.write(STR32_PREFIX);
out.write(ByteBuffer.allocate(4).putInt(size).array());
}
out.write(bytes);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MPString mpString = (MPString) o;
return Objects.equals(value, mpString.value);
}
@Override
public int hashCode() {
return Objects.hash(value);
}
@Override
public int length() {
return value.length();
}
@Override
public char charAt(int i) {
return value.charAt(i);
}
@Override
public CharSequence subSequence(int beginIndex, int endIndex) {
return value.subSequence(beginIndex, endIndex);
}
@Override
public String toString() {
return value;
}
@Override
public String toJson() {
StringBuilder result = new StringBuilder(value.length() + 4);
result.append('"');
for (int i = 0; i < value.length(); i++) {
char c = value.charAt(i);
switch (c) {
case '\\':
case '"':
case '/':
result.append('\\').append(c);
break;
case '\b':
result.append("\\b");
break;
case '\t':
result.append("\\t");
break;
case '\n':
result.append("\\n");
break;
case '\f':
result.append("\\f");
break;
case '\r':
result.append("\\r");
break;
default:
if (c < ' ') {
result.append("\\u");
String hex = Integer.toHexString(c);
for (int j = 0; j + hex.length() < 4; j++) {
result.append('0');
}
result.append(hex);
} else {
result.append(c);
}
}
}
result.append('"');
return result.toString();
}
public static class Unpacker implements MPType.Unpacker<MPString> {
public boolean is(int firstByte) {
return firstByte == STR8_PREFIX || firstByte == STR16_PREFIX || firstByte == STR32_PREFIX
|| (firstByte & FIXSTR_PREFIX_FILTER) == FIXSTR_PREFIX;
}
public MPString unpack(int firstByte, InputStream in) throws IOException {
int size;
if ((firstByte & FIXSTR_PREFIX_FILTER) == FIXSTR_PREFIX) {
size = firstByte & FIXSTR_FILTER;
} else if (firstByte == STR8_PREFIX) {
size = in.read();
} else if (firstByte == STR16_PREFIX) {
size = in.read() << 8 | in.read();
} else if (firstByte == STR32_PREFIX) {
size = in.read() << 24 | in.read() << 16 | in.read() << 8 | in.read();
} else {
throw new IllegalArgumentException(String.format("Unexpected first byte 0x%02x", firstByte));
}
return new MPString(new String(bytes(in, size).array(), encoding));
}
}
}

View File

@ -1,115 +0,0 @@
/*
* Copyright 2017 Christian Basler
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*