package com.ripple.core.serialized; import com.ripple.core.fields.Field; import com.ripple.core.fields.Type; import java.util.Arrays; public class BinarySerializer { private final BytesSink sink; public BinarySerializer(BytesSink sink) { this.sink = sink; } public void add(byte[] n) { sink.add(n); } public void addLengthEncoded(byte[] n) { add(encodeVL(n.length)); add(n); } public static byte[] encodeVL(int length) { // TODO: bytes byte[] lenBytes = new byte[4]; if (length <= 192) { lenBytes[0] = (byte) (length); return Arrays.copyOf(lenBytes, 1); } else if (length <= 12480) { length -= 193; lenBytes[0] = (byte) (193 + (length >>> 8)); lenBytes[1] = (byte) (length & 0xff); return Arrays.copyOf(lenBytes, 2); } else if (length <= 918744) { length -= 12481; lenBytes[0] = (byte) (241 + (length >>> 16)); lenBytes[1] = (byte) ((length >> 8) & 0xff); lenBytes[2] = (byte) (length & 0xff); return Arrays.copyOf(lenBytes, 3); } else { throw new RuntimeException("Overflow error"); } } public void add(BytesList bl) { for (byte[] bytes : bl.rawList()) { sink.add(bytes); } } public int addFieldHeader(Field f) { if (!f.isSerialized()) { throw new IllegalStateException(String.format("Field %s is a discardable field", f)); } byte[] n = f.getBytes(); add(n); return n.length; } public void add(byte type) { sink.add(type); } public void addLengthEncoded(BytesList bytes) { add(encodeVL(bytes.bytesLength())); add(bytes); } public void add(Field field, SerializedType value) { addFieldHeader(field); if (field.isVLEncoded()) { addLengthEncoded(value); } else { value.toBytesSink(sink); if (field.getType() == Type.STObject) { addFieldHeader(Field.ObjectEndMarker); } else if (field.getType() == Type.STArray) { addFieldHeader(Field.ArrayEndMarker); } } } public void addLengthEncoded(SerializedType value) { BytesList bytes = new BytesList(); value.toBytesSink(bytes); addLengthEncoded(bytes); } }