3 import java.io.BufferedInputStream;
4 import java.io.InputStream;
5 import java.util.Hashtable;
8 import javajs.api.GenericBinaryDocumentReader;
11 * A simple MessagePack reader. See https://github.com/msgpack/msgpack/blob/master/spec.md
12 * with very few dependencies.
16 * Does not implement unsigned int32 or int64 (delivers simple integers in all cases).
17 * Does not use doubles; just floats
21 * homogeneousArrays == true will deliver null for empty array.
27 * BufferedInputStream bs = [whatever]
29 * GenericBinaryDocument binaryDoc = new javajs.util.BinaryDocument();
31 * binaryDoc.setStream(bs, true);
34 * map = (new MessagePackReader(binaryDoc, true)).readMap();
36 * entities = (Object[]) map.get("entityList");
38 * float[] x = (float[]) decode((byte[]) map.get("xCoordList"))
41 * @author Bob Hanson hansonr@stolaf.edu
44 public class MessagePackReader {
46 private GenericBinaryDocumentReader doc;
48 private boolean isHomo;// homogeneous arrays -- use int[] not Integer
50 // these maps must be checked for the specific number of bits, in the following order:
51 private final static int POSITIVEFIXINT_x80 = 0x80; //0xxxxxxx
52 private final static int FIXMAP_xF0 = 0x80; //1000xxxx
53 // private final static int FIXARRAY_xF0 = 0x90; //1001xxxx
54 private final static int FIXSTR_xE0 = 0xa0; //101xxxxx
55 private final static int NEGATIVEFIXINT_xE0 = 0xe0; //111xxxxx
56 private final static int DEFINITE_xE0 = 0xc0; //110xxxxx
58 private final static int NIL = 0xc0;
59 // private final static int (NEVERUSED) = 0xc1;
60 private final static int FALSE = 0xc2;
61 private final static int TRUE = 0xc3;
62 private final static int BIN8 = 0xc4;
63 private final static int BIN16 = 0xc5;
64 private final static int BIN32 = 0xc6;
65 private final static int EXT8 = 0xc7;
66 private final static int EXT16 = 0xc8;
67 private final static int EXT32 = 0xc9;
68 private final static int FLOAT32 = 0xca;
69 private final static int FLOAT64 = 0xcb;
70 private final static int UINT8 = 0xcc;
71 private final static int UINT16 = 0xcd;
72 private final static int UINT32 = 0xce;
73 private final static int UINT64 = 0xcf;
74 private final static int INT8 = 0xd0;
75 private final static int INT16 = 0xd1;
76 private final static int INT32 = 0xd2;
77 private final static int INT64 = 0xd3;
78 private final static int FIXEXT1 = 0xd4;
79 private final static int FIXEXT2 = 0xd5;
80 private final static int FIXEXT4 = 0xd6;
81 private final static int FIXEXT8 = 0xd7;
82 private final static int FIXEXT16 = 0xd8;
83 private final static int STR8 = 0xd9;
84 private final static int STR16 = 0xda;
85 private final static int STR32 = 0xdb;
86 private final static int ARRAY16 = 0xdc;
87 private final static int ARRAY32 = 0xdd;
88 private final static int MAP16 = 0xde;
89 private final static int MAP32 = 0xdf;
91 public MessagePackReader(GenericBinaryDocumentReader binaryDoc, boolean isHomogeneousArrays) {
92 isHomo = isHomogeneousArrays;
96 public MessagePackReader() {
100 public Map<String, Object> getMapForStream(BufferedInputStream is) throws Exception {
101 doc = new BinaryDocument().setStream(is, true);
102 Map<String, Object> map = readMap();
107 @SuppressWarnings("unchecked")
108 public Map<String, Object> readMap() throws Exception {
109 return (Map<String, Object>) getNext(null, 0);
112 public Object getNext(Object array, int pt) throws Exception {
113 int b = doc.readByte() & 0xFF;
115 if ((b & POSITIVEFIXINT_x80) == 0) {
117 ((int[]) array)[pt] = b;
120 return Integer.valueOf(b);
123 case NEGATIVEFIXINT_xE0:
124 b = BC.intToSignedInt(b | 0xFFFFFF00);
126 ((int[]) array)[pt] = b;
129 return Integer.valueOf(b);
131 String s = doc.readString(b & 0x1F);
133 ((String[]) array)[pt] = s;
139 return ((b & 0xF0) == FIXMAP_xF0 ? getMap(b & 0x0F) : getArray(b & 0x0F));
145 return Boolean.FALSE;
149 return getObject(doc.readUInt8());
151 return getObject(doc.readUnsignedShort());
153 return getObject(doc.readInt()); // should be unsigned int
163 return getObject(16);
165 return getArray(doc.readUnsignedShort());
167 return getArray(doc.readInt());
169 return getMap(doc.readUnsignedShort());
171 return getMap(doc.readInt());
176 return doc.readBytes(doc.readUInt8());
178 return doc.readBytes(doc.readUnsignedShort());
180 return doc.readBytes(doc.readInt());
185 return Float.valueOf(doc.readFloat());
187 return Float.valueOf((float) doc.readDouble());
189 return Integer.valueOf(doc.readUInt8());
191 return Integer.valueOf(doc.readUnsignedShort());
193 return Integer.valueOf(doc.readInt()); // technically should be UInt32
195 return Long.valueOf(doc.readLong()); // should be unsigned long; incompatible with JavaScript!
197 return Integer.valueOf(doc.readByte());
199 return Integer.valueOf(doc.readShort());
201 return Integer.valueOf(doc.readInt()); // should be Unsigned Int here
203 return Long.valueOf(doc.readLong());
205 return doc.readString(doc.readUInt8());
207 return doc.readString(doc.readShort());
209 return doc.readString(doc.readInt());
214 ((float[]) array)[pt] = doc.readFloat();
217 ((float[]) array)[pt] = (float) doc.readDouble();
220 ((int[]) array)[pt] = doc.readUInt8();
223 ((int[]) array)[pt] = doc.readUnsignedShort();
226 ((int[]) array)[pt] = doc.readInt(); // should be unsigned int
229 ((int[]) array)[pt] = (int) doc.readLong(); // should be unsigned long; incompatible with JavaScript!
232 ((int[]) array)[pt] = doc.readByte();
235 ((int[]) array)[pt] = doc.readShort();
238 ((int[]) array)[pt] = doc.readInt(); // should be Unsigned Int here
241 ((int[]) array)[pt] = (int) doc.readLong();
244 ((String[]) array)[pt] = doc.readString(doc.readUInt8());
247 ((String[]) array)[pt] = doc.readString(doc.readShort());
250 ((String[]) array)[pt] = doc.readString(doc.readInt());
258 private Object getObject(int n) throws Exception {
259 return new Object[] { Integer.valueOf(doc.readUInt8()), doc.readBytes(n) };
262 private Object getArray(int n) throws Exception {
266 Object v = getNext(null, 0);
267 if (v instanceof Integer) {
268 int[] a = new int[n];
269 a[0] = ((Integer) v).intValue();
271 } else if (v instanceof Float) {
272 float[] a = new float[n];
273 a[0] = ((Float) v).floatValue();
275 } else if (v instanceof String) {
276 String[] a = new String[n];
280 Object[] o = new Object[n];
282 for (int i = 1; i < n; i++)
283 o[i] = getNext(null, 0);
286 for (int i = 1; i < n; i++)
290 Object[] o = new Object[n];
291 for (int i = 0; i < n; i++)
292 o[i] = getNext(null, 0);
296 private Object getMap(int n) throws Exception {
297 Map<String, Object> map = new Hashtable<String, Object>();
298 for (int i = 0; i < n; i++) {
299 String key = getNext(null, 0).toString();
302 Object value = getNext(null, 0);
304 //Logger.info("null value for " + key);
312 /////////////// MMTF MessagePack decoding ///////////////
315 * This single method takes care of all MMTF needs.
317 * See https://github.com/rcsb/mmtf/blob/master/spec.md
321 * @return array of int, char, or float, depending upon the type
323 public static Object decode(byte[] b) {
324 int type = BC.bytesToInt(b, 0, true);
325 int n = BC.bytesToInt(b, 4, true);
326 int param = BC.bytesToInt(b, 8, true);
329 return getFloats(b, n, 1);
333 return getInts(b, n);
335 return rldecode32ToStr(b);
337 return rldecode32ToChar(b, n);
339 return rldecode32(b, n);
341 return rldecode32Delta(b, n);
343 return rldecodef(b, n, param);
345 return unpack16Deltaf(b, n, param);
347 return getFloats(b, n, param);
350 return unpackf(b, 14 - type, n, param);
353 return unpack(b, 16 - type, n);
355 System.out.println("MMTF type " + type + " not found!");
368 * @return array of floats
370 public static float[] getFloats(byte[] b, int n, float divisor) {
373 float[] a = new float[n];
375 switch ((b.length - 12) / n) {
377 for (int i = 0, j = 12; i < n; i++, j += 2)
378 a[i] = BC.bytesToShort(b, j, false) / divisor;
381 for (int i = 0, j = 12; i < n; i++, j += 4)
382 a[i] = BC.bytesToFloat(b, j, false);
385 } catch (Exception e) {
393 * Decode a byte array into a byte, short, or int array.
398 * @return array of integers
400 public static int[] getInts(byte[] b, int n) {
403 int[] a = new int[n];
404 switch ((b.length - 12) / n) {
406 for (int i = 0, j = 12; i < n; i++, j++)
410 for (int i = 0, j = 12; i < n; i++, j += 2)
411 a[i] = BC.bytesToShort(b, j, true);
414 for (int i = 0, j = 12; i < n; i++, j += 4)
415 a[i] = BC.bytesToInt(b, j, true);
424 * Decode each four bytes as a 1- to 4-character string label where a 0 byte
425 * indicates end-of-string.
431 public static String[] rldecode32ToStr(byte[] b) {
432 String[] id = new String[(b.length - 12) / 4];
433 out: for (int i = 0, len = id.length, pt = 12; i < len; i++) {
435 for (int j = 0; j < 4; j++) {
438 id[i] = sb.toString();
442 sb.appendC((char) b[pt++]);
444 id[i] = sb.toString();
455 * Decode an array of int32 using run-length decoding to one char per int.
459 * @return array of characters
461 public static char[] rldecode32ToChar(byte[] b, int n) {
464 char[] ret = new char[n];
465 for (int i = 0, pt = 3; i < n;) {
466 char val = (char) b[((pt++) << 2) + 3];
467 for (int j = BC.bytesToInt(b, (pt++) << 2, true); --j >= 0;)
476 * Decode an array of int32 using run-length decoding.
480 * @return array of integers
482 public static int[] rldecode32(byte[] b, int n) {
485 int[] ret = new int[n];
486 for (int i = 0, pt = 3; i < n;) {
487 int val = BC.bytesToInt(b, (pt++) << 2, true);
488 for (int j = BC.bytesToInt(b, (pt++) << 2, true); --j >= 0;)
497 * Decode an array of int32 using run-length decoding of a difference array.
501 * @return array of integers
503 public static int[] rldecode32Delta(byte[] b, int n) {
506 int[] ret = new int[n];
507 for (int i = 0, pt = 3, val = 0; i < n;) {
508 int diff = BC.bytesToInt(b, (pt++) << 2, true);
509 for (int j = BC.bytesToInt(b, (pt++) << 2, true); --j >= 0;)
510 ret[i++] = (val = val + diff);
518 * Decode an array of int32 using run-length decoding and divide by a divisor
524 * @return array of floats
526 public static float[] rldecodef(byte[] b, int n, float divisor) {
529 float[] ret = new float[n];
530 for (int i = 0, pt = 3; i < n;) {
531 int val = BC.bytesToInt(b, (pt++) << 2, true);
532 for (int j = BC.bytesToInt(b, (pt++) << 2, true); --j >= 0;)
533 ret[i++] = val / divisor;
542 * Decode an array of int16 using run-length decoding of a difference array.
547 * @return array of floats
549 public static float[] unpack16Deltaf(byte[] b, int n, float divisor) {
552 float[] ret = new float[n];
553 for (int i = 0, pt = 6, val = 0, buf = 0; i < n;) {
554 int diff = BC.bytesToShort(b, (pt++) << 1, true);
555 if (diff == Short.MAX_VALUE || diff == Short.MIN_VALUE) {
558 ret[i++] = (val = val + diff + buf) / divisor;
567 * mmtf type 12 and 13
569 * Unpack an array of int8 or int16 to int32 and divide to give a float32.
577 * @return array of floats
579 public static float[] unpackf(byte[] b, int nBytes, int n, float divisor) {
582 float[] ret = new float[n];
585 for (int i = 0, pt = 12, offset = 0; i < n;) {
587 if (val == Byte.MAX_VALUE || val == Byte.MIN_VALUE) {
590 ret[i++] = (val + offset) / divisor;
596 for (int i = 0, pt = 6, offset = 0; i < n;) {
597 int val = BC.bytesToShort(b, (pt++) << 1, true);
598 if (val == Short.MAX_VALUE || val == Short.MIN_VALUE) {
601 ret[i++] = (val + offset) / divisor;
612 * mmtf type 14 and 15
614 * Unpack an array of int8 or int16 to int32.
621 * @return array of integers
623 public static int[] unpack(byte[] b, int nBytes, int n) {
626 int[] ret = new int[n];
629 for (int i = 0, pt = 12, offset = 0; i < n;) {
631 if (val == Byte.MAX_VALUE || val == Byte.MIN_VALUE) {
634 ret[i++] = val + offset;
640 for (int i = 0, pt = 6, offset = 0; i < n;) {
641 int val = BC.bytesToShort(b, (pt++) << 1, true);
642 if (val == Short.MAX_VALUE || val == Short.MIN_VALUE) {
645 ret[i++] = val + offset;
655 //* Decode an array of int16 using run-length decoding
656 //* of a difference array.
661 //* @return array of integers
663 //public static int[] rldecode16Delta(byte[] b, int n, int i0) {
666 //int[] ret = new int[n];
667 //for (int i = 0, pt = i0 / 2, val = 0; i < n;) {
668 //int diff = BC.bytesToShort(b, (pt++) << 1, true);
669 //for (int j = BC.bytesToShort(b, (pt++) << 1, true); --j >= 0;)
670 //ret[i++] = (val = val + diff);
676 //* Do a split delta to a float[] array
677 //* @param xyz label "x", "y", "z", or "bFactor"
678 //* @param factor for dividing in the end -- 1000f or 100f
682 //public static float[] getFloatsSplit(String xyz, float factor) {
683 //byte[] big = (byte[]) map.get(xyz + "Big");
684 //return (big == null ? null : splitDelta(big,
685 //(byte[]) map.get(xyz + "Small"), fileAtomCount, factor));
689 //* Do a split delta to a float[] array
692 //* [n m n m n m...] where n is a "big delta" and m is a number of
695 //* array containing the small deltas
697 //* the size of the final array
699 //* to divide the final result by -- 1000f or 100f here
702 //public static float[] splitDelta(byte[] big, byte[] small, int n, float factor) {
703 //float[] ret = new float[n];
704 //for (int i = 0, smallpt = 0, val = 0, datapt = 0, len = big.length >> 2; i < len; i++) {
705 //ret[datapt++] = (val = val + BC.bytesToInt(big, i << 2, true)) / factor;
707 //for (int j = BC.bytesToInt(big, i << 2, true); --j >= 0; smallpt++)
708 //ret[datapt++] = (val = val + BC.bytesToShort(small, smallpt << 1, true))