bert.js 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. // Micro BERT encoder/decoder
  2. // Copyright (c) Maxim Sokhatsky (@5HT)
  3. function atom(o) { return { type: "Atom", value: o, toString: function() { return this.value; } }; };
  4. function bin(o) { return { type: "Binary", value: o, toString: function() { return "<<\'"+this.value+"'>>"; } }; };
  5. function tuple() {
  6. return { type: "Tuple", value: arguments, toString: function() { var s = "";
  7. for (var i=0;i<this.value.length;i++) { if (s!=="") s+=","; s+=this.value[i]; }
  8. return "{" + s + "}"; } }; };
  9. function dec(S) { return decode(ltoa(new Uint8Array(S))); };
  10. function enc(s) {
  11. var ori = encode(s), buf = new Uint8Array(new ArrayBuffer(ori.length)), s = "";
  12. for (var i=0; i < buf.length; i++) { buf[i] = ori.charCodeAt(i); s+=","+buf[i]; }
  13. return new Blob([buf.buffer]); };
  14. BERT = itoa(131);
  15. SATOM = itoa(115);
  16. ATOM = itoa(100);
  17. BINARY = itoa(109);
  18. SINT = itoa(97);
  19. INT = itoa(98);
  20. SBIG = itoa(110);
  21. LBIG = itoa(111);
  22. FLOAT = itoa(99);
  23. STR = itoa(107);
  24. LIST = itoa(108);
  25. TUPLE = itoa(104);
  26. LTUPLE = itoa(105);
  27. NIL = itoa(106);
  28. ZERO = itoa(0);
  29. function itoa(x) { return String.fromCharCode(x); }
  30. function ltoa(a) { for (var i = 0,s=""; i < a.length; i++) s += itoa(a[i]); return s; };
  31. function itol(Int, Length) {
  32. var isNegative, OriginalInt, i, Rem, s = "";
  33. isNegative = (Int < 0);
  34. if (isNegative) { Int = Int * (0 - 1); }
  35. OriginalInt = Int;
  36. for (i = 0; i < Length; i++) {
  37. Rem = Int % 256;
  38. if (isNegative) { Rem = 255 - Rem; }
  39. s = String.fromCharCode(Rem) + s;
  40. Int = Math.floor(Int / 256);
  41. }
  42. if (Int > 0) { throw ("BERT: Range: " + OriginalInt); }
  43. return s; };
  44. function ltoi(S, Length) {
  45. var isNegative, i, n, Num = 0;
  46. isNegative = (S.charCodeAt(0) > 128);
  47. for (i = 0; i < Length; i++) {
  48. n = S.charCodeAt(i);
  49. if (isNegative) { n = 255 - n; }
  50. if (Num === 0) { Num = n; }
  51. else { Num = Num * 256 + n; }
  52. }
  53. if (isNegative) { Num = Num * (0 - 1); }
  54. return Num; };
  55. function btol(Int) {
  56. var isNegative, Rem, s = "";
  57. isNegative = Int < 0;
  58. if (isNegative) { Int *= -1; s += itoa(1); } else { s += itoa(0); }
  59. while (Int !== 0) { Rem = Int % 256; s += itoa(Rem); Int = Math.floor(Int / 256); }
  60. return s; };
  61. function ltob(S, Count) {
  62. var isNegative, i, n, Num = 0;
  63. isNegative = (S.charCodeAt(0) === 1);
  64. S = S.substring(1);
  65. for (i = Count - 1; i >= 0; i--) {
  66. n = S.charCodeAt(i);
  67. if (Num === 0) { Num = n; } else { Num = Num * 256 + n; } }
  68. if (isNegative) { return Num * -1; }
  69. return Num; };
  70. function encode(o) { return BERT + en_inner(o); };
  71. function en_inner(Obj) { if(Obj === undefined) return NIL; var func = 'en_' + typeof(Obj); return eval(func)(Obj); };
  72. function en_string(Obj) { return STR + itol(Obj.length, 2) + Obj; };
  73. function en_boolean(Obj) { if (Obj) return en_inner(atom("true")); else return en_inner(atom("false")); };
  74. function en_number(Obj) {
  75. var s, isi = (Obj % 1 === 0);
  76. if (!isi) { return en_float(Obj); }
  77. if (isi && Obj >= 0 && Obj < 256) { return SINT + itol(Obj, 1); }
  78. return INT + itol(Obj, 4); };
  79. function en_float(Obj) { var s = Obj.toExponential(); while (s.length < 31) { s += ZERO; } return FLOAT + s; };
  80. function en_object(Obj) {
  81. if (Obj.type === "Atom") return en_atom(Obj);
  82. if (Obj.type === "Binary") return en_bin(Obj);
  83. if (Obj.type === "Tuple") return en_tuple(Obj);
  84. if (Obj.constructor.toString().indexOf("Array") !== -1) return en_array(Obj);
  85. return en_associative_array(Obj); };
  86. function en_atom(Obj) { return ATOM + itol(Obj.value.length, 2) + Obj.value; };
  87. function en_bin(Obj) { return BINARY + itol(Obj.value.length, 4) + Obj.value; };
  88. function en_tuple(Obj) {
  89. var i, s = "";
  90. if (Obj.value.length < 256) { s += TUPLE + itol(Obj.value.length, 1); }
  91. else { s += LTUPLE + itol(Obj.value.length, 4); }
  92. for (i = 0; i < Obj.value.length; i++) { s += en_inner(Obj.value[i]); }
  93. return s; };
  94. function en_array(Obj) {
  95. var i, s = LIST + itol(Obj.length, 4);
  96. for (i = 0; i < Obj.length; i++) { s += en_inner(Obj[i]); }
  97. s += NIL;
  98. return s; };
  99. function en_associative_array(Obj) {
  100. var key, Arr = [];
  101. for (key in Obj) { if (Obj.hasOwnProperty(key)) { Arr.push(tuple(atom(key), Obj[key])); } }
  102. return en_array(Arr); };
  103. function decode(S) {
  104. if (S[0] !== BERT) { throw ("Not a valid BERT."); }
  105. var Obj = de_inner(S.substring(1));
  106. if (Obj.rest !== "") { throw ("Invalid BERT."); }
  107. return Obj.value; };
  108. function de_inner(S) {
  109. var Type = S[0];
  110. S = S.substring(1);
  111. switch (Type) {
  112. case SATOM: de_atom(S, 1);
  113. case ATOM: return de_atom(S, 2);
  114. case BINARY: return de_bin(S);
  115. case SINT: return de_integer(S, 1);
  116. case INT: return de_integer(S, 4);
  117. case SBIG: return de_big(S, 1);
  118. case LBIG: return de_big(S, 4);
  119. case FLOAT: return de_float(S);
  120. case STR: return de_string(S);
  121. case LIST: return de_list(S);
  122. case TUPLE: return de_tuple(S, 1);
  123. case NIL: return de_nil(S);
  124. default: throw ("BERT: " + S.charCodeAt(0) + " DECODE string: "+S); } };
  125. function de_atom(S, Count) {
  126. var Size, Value;
  127. Size = ltoi(S, Count);
  128. S = S.substring(Count);
  129. Value = S.substring(0, Size);
  130. if (Value === "true") { Value = true; }
  131. else if (Value === "false") { Value = false; }
  132. return { value: atom(Value), rest: S.substring(Size) }; };
  133. function de_bin(S) {
  134. var Size = ltoi(S, 4);
  135. S = S.substring(4);
  136. return { value: bin(S.substring(0, Size)), rest: S.substring(Size) }; };
  137. function de_integer(S, Count) {
  138. var Value = ltoi(S, Count);
  139. S = S.substring(Count);
  140. return { value: Value, rest: S }; };
  141. function de_float(S) {
  142. var Size = 31;
  143. return { value: parseFloat(S.substring(0, Size)), rest: S.substring(Size) }; };
  144. function de_string(S) {
  145. var Size = ltoi(S, 2);
  146. S = S.substring(2);
  147. return { value: S.substring(0, Size), rest: S.substring(Size) }; };
  148. function de_list(S) {
  149. var Size, i, El, LastChar, Arr = [];
  150. Size = ltoi(S, 4);
  151. S = S.substring(4);
  152. for (i = 0; i < Size; i++) { El = de_inner(S); Arr.push(El.value); S = El.rest; }
  153. LastChar = S[0];
  154. if (LastChar !== NIL) { throw ("BERT: Wrong NIL."); }
  155. S = S.substring(1);
  156. return { value: Arr, rest: S }; };
  157. function de_tuple(S, Count) {
  158. var Size, i, El, Arr = [];
  159. Size = ltoi(S, Count);
  160. S = S.substring(Count);
  161. for (i = 0; i < Size; i++) { El = de_inner(S); Arr.push(El.value); S = El.rest; }
  162. return { value: tuple(Arr), rest: S }; };
  163. function de_nil(S) { return { value: [], rest: S }; };
  164. function de_big(S, Count) {
  165. var Size, Value;
  166. Size = ltoi(S, Count);
  167. S = S.substring(Count);
  168. Value = ltob(S, Size);
  169. return { value : Value, rest: S.substring(Size + 1) }; };
  170. function utf8toByteArray(str) {
  171. var byteArray = [];
  172. if (str !== undefined && str !== null)
  173. for (var i = 0; i < str.length; i++)
  174. if (str.charCodeAt(i) <= 0x7F)
  175. byteArray.push(str.charCodeAt(i));
  176. else {
  177. var h = encodeURIComponent(str.charAt(i)).substr(1).split('%');
  178. for (var j = 0; j < h.length; j++)
  179. byteArray.push(parseInt(h[j], 16));
  180. }
  181. return byteArray;
  182. }
  183. function utf8decode(utftext) {
  184. var string = "";
  185. var i = 0;
  186. var c = c1 = c2 = 0;
  187. while ( i < utftext.length ) {
  188. c = utftext.charCodeAt(i);
  189. if (c < 128) {string += String.fromCharCode(c); i++;}
  190. else if((c > 191) && (c < 224)) {
  191. c2 = utftext.charCodeAt(i+1);
  192. string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
  193. i += 2;
  194. }
  195. else {
  196. c2 = utftext.charCodeAt(i+1);
  197. c3 = utftext.charCodeAt(i+2);
  198. string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
  199. i += 3;
  200. }
  201. }
  202. return string;
  203. }