3 import java.util.Hashtable;
6 import javajs.api.GenericBinaryDocumentReader;
9 * A simple MessagePack reader. See https://github.com/msgpack/msgpack/blob/master/spec.md
10 * with very few dependencies.
14 * Does not implement unsigned int32 or int64 (delivers simple integers in all cases).
15 * Does not use doubles; just floats
19 * homogeneousArrays == true will deliver null for empty array.
25 * BufferedInputStream bs = [whatever]
27 * GenericBinaryDocument binaryDoc = new javajs.util.BinaryDocument();
29 * binaryDoc.setStream(bs, true);
32 * map = (new MessagePackReader(binaryDoc, true)).readMap();
34 * entities = (Object[]) map.get("entityList");
36 * float[] x = (float[]) decode((byte[]) map.get("xCoordList"))
39 * @author Bob Hanson hansonr@stolaf.edu
42 public class MessagePackReader {
44 private GenericBinaryDocumentReader doc;
46 private boolean isHomo;// homogeneous arrays -- use int[] not Integer
48 // these maps must be checked for the specific number of bits, in the following order:
49 private final static int POSITIVEFIXINT_x80 = 0x80; //0xxxxxxx
50 private final static int FIXMAP_xF0 = 0x80; //1000xxxx
51 // private final static int FIXARRAY_xF0 = 0x90; //1001xxxx
52 private final static int FIXSTR_xE0 = 0xa0; //101xxxxx
53 private final static int NEGATIVEFIXINT_xE0 = 0xe0; //111xxxxx
54 private final static int DEFINITE_xE0 = 0xc0; //110xxxxx
56 private final static int NIL = 0xc0;
57 // private final static int (NEVERUSED) = 0xc1;
58 private final static int FALSE = 0xc2;
59 private final static int TRUE = 0xc3;
60 private final static int BIN8 = 0xc4;
61 private final static int BIN16 = 0xc5;
62 private final static int BIN32 = 0xc6;
63 private final static int EXT8 = 0xc7;
64 private final static int EXT16 = 0xc8;
65 private final static int EXT32 = 0xc9;
66 private final static int FLOAT32 = 0xca;
67 private final static int FLOAT64 = 0xcb;
68 private final static int UINT8 = 0xcc;
69 private final static int UINT16 = 0xcd;
70 private final static int UINT32 = 0xce;
71 private final static int UINT64 = 0xcf;
72 private final static int INT8 = 0xd0;
73 private final static int INT16 = 0xd1;
74 private final static int INT32 = 0xd2;
75 private final static int INT64 = 0xd3;
76 private final static int FIXEXT1 = 0xd4;
77 private final static int FIXEXT2 = 0xd5;
78 private final static int FIXEXT4 = 0xd6;
79 private final static int FIXEXT8 = 0xd7;
80 private final static int FIXEXT16 = 0xd8;
81 private final static int STR8 = 0xd9;
82 private final static int STR16 = 0xda;
83 private final static int STR32 = 0xdb;
84 private final static int ARRAY16 = 0xdc;
85 private final static int ARRAY32 = 0xdd;
86 private final static int MAP16 = 0xde;
87 private final static int MAP32 = 0xdf;
89 public MessagePackReader(GenericBinaryDocumentReader binaryDoc, boolean isHomogeneousArrays) {
90 isHomo = isHomogeneousArrays;
94 @SuppressWarnings("unchecked")
95 public Map<String, Object> readMap() throws Exception {
96 return (Map<String, Object>) getNext(null, 0);
99 public Object getNext(Object array, int pt) throws Exception {
100 int b = doc.readByte() & 0xFF;
102 if ((b & POSITIVEFIXINT_x80) == 0) {
104 ((int[]) array)[pt] = b;
107 return Integer.valueOf(b);
110 case NEGATIVEFIXINT_xE0:
111 b = BC.intToSignedInt(b | 0xFFFFFF00);
113 ((int[]) array)[pt] = b;
116 return Integer.valueOf(b);
118 String s = doc.readString(b & 0x1F);
120 ((String[]) array)[pt] = s;
126 return ((b & 0xF0) == FIXMAP_xF0 ? getMap(b & 0x0F) : getArray(b & 0x0F));
132 return Boolean.FALSE;
136 return getObject(doc.readUInt8());
138 return getObject(doc.readUnsignedShort());
140 return getObject(doc.readInt()); // should be unsigned int
150 return getObject(16);
152 return getArray(doc.readUnsignedShort());
154 return getArray(doc.readInt());
156 return getMap(doc.readUnsignedShort());
158 return getMap(doc.readInt());
163 return doc.readBytes(doc.readUInt8());
165 return doc.readBytes(doc.readUnsignedShort());
167 return doc.readBytes(doc.readInt());
172 return Float.valueOf(doc.readFloat());
174 return Float.valueOf((float) doc.readDouble());
176 return Integer.valueOf(doc.readUInt8());
178 return Integer.valueOf(doc.readUnsignedShort());
180 return Integer.valueOf(doc.readInt()); // technically should be UInt32
182 return Long.valueOf(doc.readLong()); // should be unsigned long; incompatible with JavaScript!
184 return Integer.valueOf(doc.readByte());
186 return Integer.valueOf(doc.readShort());
188 return Integer.valueOf(doc.readInt()); // should be Unsigned Int here
190 return Long.valueOf(doc.readLong());
192 return doc.readString(doc.readUInt8());
194 return doc.readString(doc.readShort());
196 return doc.readString(doc.readInt());
201 ((float[]) array)[pt] = doc.readFloat();
204 ((float[]) array)[pt] = (float) doc.readDouble();
207 ((int[]) array)[pt] = doc.readUInt8();
210 ((int[]) array)[pt] = doc.readUnsignedShort();
213 ((int[]) array)[pt] = doc.readInt(); // should be unsigned int
216 ((int[]) array)[pt] = (int) doc.readLong(); // should be unsigned long; incompatible with JavaScript!
219 ((int[]) array)[pt] = doc.readByte();
222 ((int[]) array)[pt] = doc.readShort();
225 ((int[]) array)[pt] = doc.readInt(); // should be Unsigned Int here
228 ((int[]) array)[pt] = (int) doc.readLong();
231 ((String[]) array)[pt] = doc.readString(doc.readUInt8());
234 ((String[]) array)[pt] = doc.readString(doc.readShort());
237 ((String[]) array)[pt] = doc.readString(doc.readInt());
245 private Object getObject(int n) throws Exception {
246 return new Object[] { Integer.valueOf(doc.readUInt8()), doc.readBytes(n) };
249 private Object getArray(int n) throws Exception {
253 Object v = getNext(null, 0);
254 if (v instanceof Integer) {
255 int[] a = new int[n];
256 a[0] = ((Integer) v).intValue();
258 } else if (v instanceof Float) {
259 float[] a = new float[n];
260 a[0] = ((Float) v).floatValue();
262 } else if (v instanceof String) {
263 String[] a = new String[n];
267 Object[] o = new Object[n];
269 for (int i = 1; i < n; i++)
270 o[i] = getNext(null, 0);
273 for (int i = 1; i < n; i++)
277 Object[] o = new Object[n];
278 for (int i = 0; i < n; i++)
279 o[i] = getNext(null, 0);
283 private Object getMap(int n) throws Exception {
284 Map<String, Object> map = new Hashtable<String, Object>();
285 for (int i = 0; i < n; i++) {
286 String key = getNext(null, 0).toString();
289 Object value = getNext(null, 0);
291 //Logger.info("null value for " + key);
299 /////////////// MMTF MessagePack decoding ///////////////
302 * This single method takes care of all MMTF needs.
304 * See https://github.com/rcsb/mmtf/blob/master/spec.md
308 * @return array of int, char, or float, depending upon the type
310 public static Object decode(byte[] b) {
311 int type = BC.bytesToInt(b, 0, true);
312 int n = BC.bytesToInt(b, 4, true);
313 int param = BC.bytesToInt(b, 8, true);
316 return getFloats(b, n, 1);
320 return getInts(b, n);
322 return rldecode32ToStr(b);
324 return rldecode32ToChar(b, n);
326 return rldecode32(b, n);
328 return rldecode32Delta(b, n);
330 return rldecodef(b, n, param);
332 return unpack16Deltaf(b, n, param);
334 return getFloats(b, n, param);
337 return unpackf(b, 14 - type, n, param);
340 return unpack(b, 16 - type, n);
342 System.out.println("MMTF type " + type + " not found!");
355 * @return array of floats
357 public static float[] getFloats(byte[] b, int n, float divisor) {
360 float[] a = new float[n];
362 switch ((b.length - 12) / n) {
364 for (int i = 0, j = 12; i < n; i++, j += 2)
365 a[i] = BC.bytesToShort(b, j, false) / divisor;
368 for (int i = 0, j = 12; i < n; i++, j += 4)
369 a[i] = BC.bytesToFloat(b, j, false);
372 } catch (Exception e) {
380 * Decode a byte array into a byte, short, or int array.
385 * @return array of integers
387 public static int[] getInts(byte[] b, int n) {
390 int[] a = new int[n];
391 switch ((b.length - 12) / n) {
393 for (int i = 0, j = 12; i < n; i++, j++)
397 for (int i = 0, j = 12; i < n; i++, j += 2)
398 a[i] = BC.bytesToShort(b, j, true);
401 for (int i = 0, j = 12; i < n; i++, j += 4)
402 a[i] = BC.bytesToInt(b, j, true);
411 * Decode each four bytes as a 1- to 4-character string label where a 0 byte
412 * indicates end-of-string.
418 public static String[] rldecode32ToStr(byte[] b) {
419 String[] id = new String[(b.length - 12) / 4];
420 out: for (int i = 0, len = id.length, pt = 12; i < len; i++) {
422 for (int j = 0; j < 4; j++) {
425 id[i] = sb.toString();
429 sb.appendC((char) b[pt++]);
431 id[i] = sb.toString();
442 * Decode an array of int32 using run-length decoding to one char per int.
446 * @return array of characters
448 public static char[] rldecode32ToChar(byte[] b, int n) {
451 char[] ret = new char[n];
452 for (int i = 0, pt = 3; i < n;) {
453 char val = (char) b[((pt++) << 2) + 3];
454 for (int j = BC.bytesToInt(b, (pt++) << 2, true); --j >= 0;)
463 * Decode an array of int32 using run-length decoding.
467 * @return array of integers
469 public static int[] rldecode32(byte[] b, int n) {
472 int[] ret = new int[n];
473 for (int i = 0, pt = 3; i < n;) {
474 int val = BC.bytesToInt(b, (pt++) << 2, true);
475 for (int j = BC.bytesToInt(b, (pt++) << 2, true); --j >= 0;)
484 * Decode an array of int32 using run-length decoding of a difference array.
488 * @return array of integers
490 public static int[] rldecode32Delta(byte[] b, int n) {
493 int[] ret = new int[n];
494 for (int i = 0, pt = 3, val = 0; i < n;) {
495 int diff = BC.bytesToInt(b, (pt++) << 2, true);
496 for (int j = BC.bytesToInt(b, (pt++) << 2, true); --j >= 0;)
497 ret[i++] = (val = val + diff);
505 * Decode an array of int32 using run-length decoding and divide by a divisor
511 * @return array of floats
513 public static float[] rldecodef(byte[] b, int n, float divisor) {
516 float[] ret = new float[n];
517 for (int i = 0, pt = 3; i < n;) {
518 int val = BC.bytesToInt(b, (pt++) << 2, true);
519 for (int j = BC.bytesToInt(b, (pt++) << 2, true); --j >= 0;)
520 ret[i++] = val / divisor;
529 * Decode an array of int16 using run-length decoding of a difference array.
534 * @return array of floats
536 public static float[] unpack16Deltaf(byte[] b, int n, float divisor) {
539 float[] ret = new float[n];
540 for (int i = 0, pt = 6, val = 0, buf = 0; i < n;) {
541 int diff = BC.bytesToShort(b, (pt++) << 1, true);
542 if (diff == Short.MAX_VALUE || diff == Short.MIN_VALUE) {
545 ret[i++] = (val = val + diff + buf) / divisor;
554 * mmtf type 12 and 13
556 * Unpack an array of int8 or int16 to int32 and divide to give a float32.
564 * @return array of floats
566 public static float[] unpackf(byte[] b, int nBytes, int n, float divisor) {
569 float[] ret = new float[n];
572 for (int i = 0, pt = 12, offset = 0; i < n;) {
574 if (val == Byte.MAX_VALUE || val == Byte.MIN_VALUE) {
577 ret[i++] = (val + offset) / divisor;
583 for (int i = 0, pt = 6, offset = 0; i < n;) {
584 int val = BC.bytesToShort(b, (pt++) << 1, true);
585 if (val == Short.MAX_VALUE || val == Short.MIN_VALUE) {
588 ret[i++] = (val + offset) / divisor;
599 * mmtf type 14 and 15
601 * Unpack an array of int8 or int16 to int32.
608 * @return array of integers
610 public static int[] unpack(byte[] b, int nBytes, int n) {
613 int[] ret = new int[n];
616 for (int i = 0, pt = 12, offset = 0; i < n;) {
618 if (val == Byte.MAX_VALUE || val == Byte.MIN_VALUE) {
621 ret[i++] = val + offset;
627 for (int i = 0, pt = 6, offset = 0; i < n;) {
628 int val = BC.bytesToShort(b, (pt++) << 1, true);
629 if (val == Short.MAX_VALUE || val == Short.MIN_VALUE) {
632 ret[i++] = val + offset;
642 //* Decode an array of int16 using run-length decoding
643 //* of a difference array.
648 //* @return array of integers
650 //public static int[] rldecode16Delta(byte[] b, int n, int i0) {
653 //int[] ret = new int[n];
654 //for (int i = 0, pt = i0 / 2, val = 0; i < n;) {
655 //int diff = BC.bytesToShort(b, (pt++) << 1, true);
656 //for (int j = BC.bytesToShort(b, (pt++) << 1, true); --j >= 0;)
657 //ret[i++] = (val = val + diff);
663 //* Do a split delta to a float[] array
664 //* @param xyz label "x", "y", "z", or "bFactor"
665 //* @param factor for dividing in the end -- 1000f or 100f
669 //public static float[] getFloatsSplit(String xyz, float factor) {
670 //byte[] big = (byte[]) map.get(xyz + "Big");
671 //return (big == null ? null : splitDelta(big,
672 //(byte[]) map.get(xyz + "Small"), fileAtomCount, factor));
676 //* Do a split delta to a float[] array
679 //* [n m n m n m...] where n is a "big delta" and m is a number of
682 //* array containing the small deltas
684 //* the size of the final array
686 //* to divide the final result by -- 1000f or 100f here
689 //public static float[] splitDelta(byte[] big, byte[] small, int n, float factor) {
690 //float[] ret = new float[n];
691 //for (int i = 0, smallpt = 0, val = 0, datapt = 0, len = big.length >> 2; i < len; i++) {
692 //ret[datapt++] = (val = val + BC.bytesToInt(big, i << 2, true)) / factor;
694 //for (int j = BC.bytesToInt(big, i << 2, true); --j >= 0; smallpt++)
695 //ret[datapt++] = (val = val + BC.bytesToShort(small, smallpt << 1, true))