JAL-3032 adds Java 8 functionality (2/2)
[jalview.git] / src2 / javajs / util / MessagePackReader.java
1 package javajs.util;
2
3 import java.io.BufferedInputStream;
4 import java.io.InputStream;
5 import java.util.Hashtable;
6 import java.util.Map;
7
8 import javajs.api.GenericBinaryDocumentReader;
9
10 /**
11  * A simple MessagePack reader. See https://github.com/msgpack/msgpack/blob/master/spec.md
12  * with very few dependencies.
13  * 
14  * Nuances: 
15  * 
16  *  Does not implement unsigned int32 or int64 (delivers simple integers in all cases).
17  *  Does not use doubles; just floats
18  *  
19  * Note: 
20  * 
21  *  homogeneousArrays == true will deliver null for empty array.
22  * 
23  * 
24  * Use in MMTF:
25  * 
26  * 
27  *     BufferedInputStream bs = [whatever]
28  *     
29  *      GenericBinaryDocument binaryDoc =  new javajs.util.BinaryDocument();
30  *   
31  *      binaryDoc.setStream(bs, true);
32  * 
33  * 
34  *     map = (new MessagePackReader(binaryDoc, true)).readMap();
35  * 
36  *     entities = (Object[]) map.get("entityList");
37  *
38  *     float[] x = (float[]) decode((byte[]) map.get("xCoordList"))
39  *     
40  * 
41  * @author Bob Hanson hansonr@stolaf.edu
42  */
43
44 public class MessagePackReader {
45
46   private GenericBinaryDocumentReader doc;
47
48   private boolean isHomo;// homogeneous arrays -- use int[] not Integer
49
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
57   
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;
90
91   public MessagePackReader(GenericBinaryDocumentReader binaryDoc, boolean isHomogeneousArrays) {
92     isHomo = isHomogeneousArrays;
93     doc = binaryDoc;
94   }
95
96   public MessagePackReader() {
97     // for reflection
98   }
99   
100   public Map<String, Object> getMapForStream(BufferedInputStream is) throws Exception {
101     doc = new BinaryDocument().setStream(is, true);
102     Map<String, Object> map = readMap();
103     is.close();
104     return map;
105   }
106   
107   @SuppressWarnings("unchecked")
108   public Map<String, Object> readMap() throws Exception {
109     return (Map<String, Object>) getNext(null, 0);
110   }
111   
112   public Object getNext(Object array, int pt) throws Exception {
113     int b = doc.readByte() & 0xFF;
114     int be0 = b & 0xE0;
115     if ((b & POSITIVEFIXINT_x80) == 0) {
116       if (array != null) {
117         ((int[]) array)[pt] = b;
118         return null;
119       }
120       return Integer.valueOf(b);
121     }
122     switch (be0) {
123     case NEGATIVEFIXINT_xE0:
124       b = BC.intToSignedInt(b | 0xFFFFFF00);
125       if (array != null) {
126         ((int[]) array)[pt] = b;
127         return null;
128       }
129       return Integer.valueOf(b);
130     case FIXSTR_xE0: {
131       String s = doc.readString(b & 0x1F);
132       if (array != null) {
133         ((String[]) array)[pt] = s; 
134         return null;
135       } 
136       return s;
137     }
138     case FIXMAP_xF0:
139       return ((b & 0xF0) == FIXMAP_xF0 ? getMap(b & 0x0F) : getArray(b & 0x0F));
140     case DEFINITE_xE0:
141       switch (b) {
142       case NIL:
143         return null;
144       case FALSE:
145         return Boolean.FALSE;
146       case TRUE:
147         return Boolean.TRUE;
148       case EXT8:
149         return getObject(doc.readUInt8());
150       case EXT16:
151         return getObject(doc.readUnsignedShort());
152       case EXT32:
153         return getObject(doc.readInt()); // should be unsigned int
154       case FIXEXT1:
155         return getObject(1);
156       case FIXEXT2:
157         return getObject(2);
158       case FIXEXT4:
159         return getObject(4);
160       case FIXEXT8:
161         return getObject(8);
162       case FIXEXT16:
163         return getObject(16);
164       case ARRAY16:
165         return getArray(doc.readUnsignedShort());
166       case ARRAY32:
167         return getArray(doc.readInt());
168       case MAP16:
169         return getMap(doc.readUnsignedShort());
170       case MAP32:
171         return getMap(doc.readInt());
172
173         // binary arrays:
174
175       case BIN8:
176         return doc.readBytes(doc.readUInt8());
177       case BIN16:
178         return doc.readBytes(doc.readUnsignedShort());
179       case BIN32:
180         return doc.readBytes(doc.readInt());
181       }
182       if (array == null) {
183         switch (b) {
184         case FLOAT32:
185           return Float.valueOf(doc.readFloat());
186         case FLOAT64:
187           return Float.valueOf((float) doc.readDouble());
188         case UINT8:
189           return Integer.valueOf(doc.readUInt8());
190         case UINT16:
191           return Integer.valueOf(doc.readUnsignedShort());
192         case UINT32:
193           return Integer.valueOf(doc.readInt()); // technically should be UInt32
194         case UINT64:
195           return Long.valueOf(doc.readLong()); // should be unsigned long; incompatible with JavaScript!
196         case INT8:
197           return Integer.valueOf(doc.readByte());
198         case INT16:
199           return Integer.valueOf(doc.readShort());
200         case INT32:
201           return Integer.valueOf(doc.readInt()); // should be Unsigned Int here
202         case INT64:
203           return Long.valueOf(doc.readLong());
204         case STR8:
205           return doc.readString(doc.readUInt8());
206         case STR16:
207           return doc.readString(doc.readShort());
208         case STR32:
209           return doc.readString(doc.readInt());
210         }
211       } else {
212         switch (b) {
213         case FLOAT32:
214           ((float[]) array)[pt] = doc.readFloat();
215           break;
216         case FLOAT64:
217           ((float[]) array)[pt] = (float) doc.readDouble();
218           break;
219         case UINT8:
220           ((int[]) array)[pt] = doc.readUInt8();
221           break;
222         case UINT16:
223           ((int[]) array)[pt] = doc.readUnsignedShort();
224           break;
225         case UINT32:
226           ((int[]) array)[pt] =  doc.readInt(); // should be unsigned int
227           break;
228         case UINT64:
229           ((int[]) array)[pt] =  (int) doc.readLong(); // should be unsigned long; incompatible with JavaScript!
230           break;
231         case INT8:
232           ((int[]) array)[pt] =  doc.readByte();
233           break;
234         case INT16:
235           ((int[]) array)[pt] = doc.readShort();
236           break;
237         case INT32:
238           ((int[]) array)[pt] =  doc.readInt(); // should be Unsigned Int here
239           break;
240         case INT64:
241           ((int[]) array)[pt] =  (int) doc.readLong();
242           break;
243         case STR8:
244           ((String[]) array)[pt] = doc.readString(doc.readUInt8());
245           break;
246         case STR16:
247           ((String[]) array)[pt] = doc.readString(doc.readShort());
248           break;
249         case STR32:
250           ((String[]) array)[pt] = doc.readString(doc.readInt());
251           break;
252         }
253       }
254     }
255     return null;
256   }
257
258   private Object getObject(int n) throws Exception {
259     return new Object[] { Integer.valueOf(doc.readUInt8()), doc.readBytes(n) };
260   }
261
262   private Object getArray(int n) throws Exception {
263     if (isHomo) {
264       if (n == 0)
265         return null;
266       Object v = getNext(null, 0);
267       if (v instanceof Integer) {
268         int[] a = new int[n];
269         a[0] = ((Integer) v).intValue();
270         v = a;
271       } else if (v instanceof Float) {
272         float[] a = new float[n];
273         a[0] = ((Float) v).floatValue();
274         v = a;
275       } else if (v instanceof String) {
276         String[] a = new String[n];
277         a[0] = (String) v;
278         v = a;
279       } else {
280         Object[] o = new Object[n];
281         o[0] = v;
282         for (int i = 1; i < n; i++)
283           o[i] = getNext(null, 0);
284         return o;
285       }
286       for (int i = 1; i < n; i++)
287         getNext(v, i);
288       return v;
289     }
290     Object[] o = new Object[n];
291     for (int i = 0; i < n; i++)
292       o[i] = getNext(null, 0);
293     return o;
294   }
295
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();
300       //Logger.info(key);
301
302       Object value = getNext(null, 0);
303       if (value == null) {
304         //Logger.info("null value for " + key);
305       } else {
306         map.put(key, value);
307       }
308     }
309     return map;
310   }
311
312   /////////////// MMTF MessagePack decoding ///////////////
313
314   /**
315    * This single method takes care of all MMTF needs.
316    * 
317    * See https://github.com/rcsb/mmtf/blob/master/spec.md
318    * 
319    * @param b
320    * 
321    * @return array of int, char, or float, depending upon the type
322    */
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);
327     switch (type) {
328     case 1:
329       return getFloats(b, n, 1);
330     case 2: // 1-byte
331     case 3: // 2-byte
332     case 4: // 4-byte
333       return getInts(b, n);
334     case 5:
335       return rldecode32ToStr(b);
336     case 6:
337       return rldecode32ToChar(b, n);
338     case 7:
339       return rldecode32(b, n);
340     case 8:
341       return rldecode32Delta(b, n);
342     case 9:
343       return rldecodef(b, n, param);
344     case 10:
345       return unpack16Deltaf(b, n, param);
346     case 11:
347       return getFloats(b, n, param);
348     case 12: // two-byte
349     case 13: // one-byte
350       return unpackf(b, 14 - type, n, param);
351     case 14: // two-byte
352     case 15: // one-byte
353       return unpack(b, 16 - type, n);
354     default:
355       System.out.println("MMTF type " + type + " not found!");
356       return null;
357    }
358   }
359
360   /**
361    * mmtf type 1 and 11
362    * 
363    * byte[4] to float32
364    * 
365    * @param b
366    * @param n
367    * @param divisor
368    * @return array of floats
369    */
370   public static float[] getFloats(byte[] b, int n, float divisor) {
371     if (b == null)
372       return null;
373     float[] a = new float[n];
374     try {
375       switch ((b.length - 12) / n) {  
376       case 2:
377         for (int i = 0, j = 12; i < n; i++, j += 2)
378           a[i] = BC.bytesToShort(b, j, false) / divisor;
379         break;
380       case 4:
381         for (int i = 0, j = 12; i < n; i++, j += 4)
382           a[i] = BC.bytesToFloat(b, j, false);
383         break;
384       }
385     } catch (Exception e) {
386     }
387     return a;
388   }
389
390   /**
391    * mmtf types 2-4
392    * 
393    * Decode a byte array into a byte, short, or int array.
394    * 
395    * @param b
396    * @param n
397    *        
398    * @return array of integers
399    */
400   public static int[] getInts(byte[] b, int n) {
401     if (b == null)
402       return null;
403     int[] a = new int[n];
404     switch ((b.length - 12) / n) {
405     case 1:
406       for (int i = 0, j = 12; i < n; i++, j++)
407         a[i] = b[j];
408       break;
409     case 2:
410       for (int i = 0, j = 12; i < n; i++, j += 2)
411         a[i] = BC.bytesToShort(b, j, true);
412       break;
413     case 4:
414       for (int i = 0, j = 12; i < n; i++, j += 4)
415         a[i] = BC.bytesToInt(b, j, true);
416       break;
417     }
418     return a;
419   }
420
421   /**
422    * mmtf type 5
423    * 
424    * Decode each four bytes as a 1- to 4-character string label where a 0 byte
425    * indicates end-of-string.
426    * 
427    * @param b
428    *        a byte array
429    * @return String[]
430    */
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++) {
434       SB sb = new SB();
435       for (int j = 0; j < 4; j++) {
436         switch (b[pt]) {
437         case 0:
438           id[i] = sb.toString();
439           pt += 4 - j;
440           continue out;
441         default:
442           sb.appendC((char) b[pt++]);
443           if (j == 3)
444             id[i] = sb.toString();
445           continue;
446         }
447       }
448     }
449     return id;
450   }
451
452   /**
453    * mmtf type 6
454    * 
455    * Decode an array of int32 using run-length decoding to one char per int.
456    * 
457    * @param b
458    * @param n
459    * @return array of characters
460    */
461   public static char[] rldecode32ToChar(byte[] b, int n) {
462     if (b == null)
463       return null;
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;)
468         ret[i++] = val;
469     }
470     return ret;
471   }
472
473   /**
474    * mmtf type 7
475    * 
476    * Decode an array of int32 using run-length decoding.
477    * 
478    * @param b
479    * @param n
480    * @return array of integers
481    */
482   public static int[] rldecode32(byte[] b, int n) {
483     if (b == null)
484       return null;
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;)
489         ret[i++] = val;
490     }
491     return ret;
492   }
493
494   /**
495    * mmtf type 8
496    * 
497    * Decode an array of int32 using run-length decoding of a difference array.
498    * 
499    * @param b
500    * @param n
501    * @return array of integers
502    */
503   public static int[] rldecode32Delta(byte[] b, int n) {
504     if (b == null)
505       return null;
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);
511     }
512     return ret;
513   }
514
515   /**
516    * mmtf type 9
517    * 
518    * Decode an array of int32 using run-length decoding and divide by a divisor
519    * to give a float32.
520    * 
521    * @param b
522    * @param n
523    * @param divisor
524    * @return array of floats
525    */
526   public static float[] rldecodef(byte[] b, int n, float divisor) {
527     if (b == null)
528       return null;
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;
534     }
535     return ret;
536   }
537
538   /**
539    * 
540    * mmtf type 10
541    * 
542    * Decode an array of int16 using run-length decoding of a difference array.
543    * 
544    * @param b
545    * @param n
546    * @param divisor
547    * @return array of floats
548    */
549   public static float[] unpack16Deltaf(byte[] b, int n, float divisor) {
550     if (b == null)
551       return null;
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) {
556         buf += diff;
557       } else {
558         ret[i++] = (val = val + diff + buf) / divisor;
559         buf = 0;
560       }
561     }
562     return ret;
563   }
564
565   /**
566    * 
567    * mmtf type 12 and 13
568    * 
569    * Unpack an array of int8 or int16 to int32 and divide to give a float32.
570    * 
571    * untested
572    * 
573    * @param b
574    * @param nBytes 
575    * @param n
576    * @param divisor 
577    * @return array of floats
578    */
579   public static float[] unpackf(byte[] b, int nBytes, int n, float divisor) {
580     if (b == null)
581       return null;
582     float[] ret = new float[n];
583     switch (nBytes) {
584     case 1:
585       for (int i = 0, pt = 12, offset = 0; i < n;) {
586         int val = b[pt++];
587         if (val == Byte.MAX_VALUE || val == Byte.MIN_VALUE) {
588           offset += val;
589         } else {
590           ret[i++] = (val + offset) / divisor;
591           offset = 0;
592         }
593       }
594       break;
595     case 2:
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) {
599           offset += val;
600         } else {
601           ret[i++] = (val + offset) / divisor;
602           offset = 0;
603         }
604       }
605       break;
606     }
607     return ret;
608   }
609
610   /**
611    * 
612    * mmtf type 14 and 15
613    * 
614    * Unpack an array of int8 or int16 to int32.
615    * 
616    * untested
617    * 
618    * @param b
619    * @param nBytes 
620    * @param n
621    * @return array of integers
622    */
623   public static int[] unpack(byte[] b, int nBytes, int n) {
624     if (b == null)
625       return null;
626     int[] ret = new int[n];
627     switch (nBytes) {
628     case 1:
629       for (int i = 0, pt = 12, offset = 0; i < n;) {
630         int val = b[pt++];
631         if (val == Byte.MAX_VALUE || val == Byte.MIN_VALUE) {
632           offset += val;
633         } else {
634           ret[i++] = val + offset;
635           offset = 0;
636         }
637       }
638       break;
639     case 2:
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) {
643           offset += val;
644         } else {
645           ret[i++] = val + offset;
646           offset = 0;
647         }
648       }
649       break;
650     }
651     return ret;
652   }
653
654   ///**
655   //* Decode an array of int16 using run-length decoding
656   //* of a difference array.
657   //* 
658   //* @param b
659   //* @param n
660   //* @param i0 
661   //* @return array of integers
662   //*/
663   //public static int[] rldecode16Delta(byte[] b, int n, int i0) {
664   //if (b == null)
665   //return null;
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);
671   //}
672   //return ret;
673   //}
674
675   ///**
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 
679   //* @return float[]
680   //* 
681   //*/ 
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));
686   //}
687
688   ///**
689   //* Do a split delta to a float[] array
690   //* 
691   //* @param big
692   //*        [n m n m n m...] where n is a "big delta" and m is a number of
693   //*        "small deltas
694   //* @param small
695   //*        array containing the small deltas
696   //* @param n
697   //*        the size of the final array
698   //* @param factor
699   //*        to divide the final result by -- 1000f or 100f here
700   //* @return float[]
701   //*/
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;
706   //if (++i < len)
707   //for (int j = BC.bytesToInt(big, i << 2, true); --j >= 0; smallpt++)
708   //ret[datapt++] = (val = val + BC.bytesToShort(small, smallpt << 1, true))
709   //  / factor;
710   //}
711   //return ret;
712   //}
713   //
714
715
716 }