msgpack-js.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600
  1. ( // Module boilerplate to support browser globals and browserify and AMD.
  2. typeof define === "function" ? function (m) { define("msgpack-js", m); } :
  3. typeof exports === "object" ? function (m) { module.exports = m(); } :
  4. function(m){ this.msgpack = m(); }
  5. )(function () {
  6. "use strict";
  7. var exports = {};
  8. exports.inspect = inspect;
  9. function inspect(buffer) {
  10. if (buffer === undefined) return "undefined";
  11. var view;
  12. var type;
  13. if (buffer instanceof ArrayBuffer) {
  14. type = "ArrayBuffer";
  15. view = new DataView(buffer);
  16. }
  17. else if (buffer instanceof DataView) {
  18. type = "DataView";
  19. view = buffer;
  20. }
  21. if (!view) return JSON.stringify(buffer);
  22. var bytes = [];
  23. for (var i = 0; i < buffer.byteLength; i++) {
  24. if (i > 20) {
  25. bytes.push("...");
  26. break;
  27. }
  28. var byte = view.getUint8(i).toString(16);
  29. if (byte.length === 1) byte = "0" + byte;
  30. bytes.push(byte);
  31. }
  32. return "<" + type + " " + bytes.join(" ") + ">";
  33. }
  34. // Encode string as utf8 into dataview at offset
  35. exports.utf8Write = utf8Write;
  36. function utf8Write(view, offset, string) {
  37. var byteLength = view.byteLength;
  38. for(var i = 0, l = string.length; i < l; i++) {
  39. var codePoint = string.charCodeAt(i);
  40. // One byte of UTF-8
  41. if (codePoint < 0x80) {
  42. view.setUint8(offset++, codePoint >>> 0 & 0x7f | 0x00);
  43. continue;
  44. }
  45. // Two bytes of UTF-8
  46. if (codePoint < 0x800) {
  47. view.setUint8(offset++, codePoint >>> 6 & 0x1f | 0xc0);
  48. view.setUint8(offset++, codePoint >>> 0 & 0x3f | 0x80);
  49. continue;
  50. }
  51. // Three bytes of UTF-8.
  52. if (codePoint < 0x10000) {
  53. view.setUint8(offset++, codePoint >>> 12 & 0x0f | 0xe0);
  54. view.setUint8(offset++, codePoint >>> 6 & 0x3f | 0x80);
  55. view.setUint8(offset++, codePoint >>> 0 & 0x3f | 0x80);
  56. continue;
  57. }
  58. // Four bytes of UTF-8
  59. if (codePoint < 0x110000) {
  60. view.setUint8(offset++, codePoint >>> 18 & 0x07 | 0xf0);
  61. view.setUint8(offset++, codePoint >>> 12 & 0x3f | 0x80);
  62. view.setUint8(offset++, codePoint >>> 6 & 0x3f | 0x80);
  63. view.setUint8(offset++, codePoint >>> 0 & 0x3f | 0x80);
  64. continue;
  65. }
  66. throw new Error("bad codepoint " + codePoint);
  67. }
  68. }
  69. exports.utf8Read = utf8Read;
  70. function utf8Read(view, offset, length) {
  71. var string = "";
  72. for (var i = offset, end = offset + length; i < end; i++) {
  73. var byte = view.getUint8(i);
  74. // One byte character
  75. if ((byte & 0x80) === 0x00) {
  76. string += String.fromCharCode(byte);
  77. continue;
  78. }
  79. // Two byte character
  80. if ((byte & 0xe0) === 0xc0) {
  81. string += String.fromCharCode(
  82. ((byte & 0x0f) << 6) |
  83. (view.getUint8(++i) & 0x3f)
  84. );
  85. continue;
  86. }
  87. // Three byte character
  88. if ((byte & 0xf0) === 0xe0) {
  89. string += String.fromCharCode(
  90. ((byte & 0x0f) << 12) |
  91. ((view.getUint8(++i) & 0x3f) << 6) |
  92. ((view.getUint8(++i) & 0x3f) << 0)
  93. );
  94. continue;
  95. }
  96. // Four byte character
  97. if ((byte & 0xf8) === 0xf0) {
  98. string += String.fromCharCode(
  99. ((byte & 0x07) << 18) |
  100. ((view.getUint8(++i) & 0x3f) << 12) |
  101. ((view.getUint8(++i) & 0x3f) << 6) |
  102. ((view.getUint8(++i) & 0x3f) << 0)
  103. );
  104. continue;
  105. }
  106. throw new Error("Invalid byte " + byte.toString(16));
  107. }
  108. return string;
  109. }
  110. exports.utf8ByteCount = utf8ByteCount;
  111. function utf8ByteCount(string) {
  112. var count = 0;
  113. for(var i = 0, l = string.length; i < l; i++) {
  114. var codePoint = string.charCodeAt(i);
  115. if (codePoint < 0x80) {
  116. count += 1;
  117. continue;
  118. }
  119. if (codePoint < 0x800) {
  120. count += 2;
  121. continue;
  122. }
  123. if (codePoint < 0x10000) {
  124. count += 3;
  125. continue;
  126. }
  127. if (codePoint < 0x110000) {
  128. count += 4;
  129. continue;
  130. }
  131. throw new Error("bad codepoint " + codePoint);
  132. }
  133. return count;
  134. }
  135. exports.encode = function (value) {
  136. var buffer = new ArrayBuffer(sizeof(value));
  137. var view = new DataView(buffer);
  138. encode(value, view, 0);
  139. return buffer;
  140. };
  141. exports.decode = decode;
  142. // http://wiki.msgpack.org/display/MSGPACK/Format+specification
  143. // I've extended the protocol to have two new types that were previously reserved.
  144. // buffer 16 11011000 0xd8
  145. // buffer 32 11011001 0xd9
  146. // These work just like raw16 and raw32 except they are node buffers instead of strings.
  147. //
  148. // Also I've added a type for `undefined`
  149. // undefined 11000100 0xc4
  150. function Decoder(view, offset) {
  151. this.offset = offset || 0;
  152. this.view = view;
  153. }
  154. Decoder.prototype.map = function (length) {
  155. var value = {};
  156. for (var i = 0; i < length; i++) {
  157. var key = this.parse();
  158. value[key] = this.parse();
  159. }
  160. return value;
  161. };
  162. Decoder.prototype.buf = function (length) {
  163. var value = new ArrayBuffer(length);
  164. (new Uint8Array(value)).set(new Uint8Array(this.view.buffer, this.offset, length), 0);
  165. this.offset += length;
  166. return value;
  167. };
  168. Decoder.prototype.raw = function (length) {
  169. var value = utf8Read(this.view, this.offset, length);
  170. this.offset += length;
  171. return value;
  172. };
  173. Decoder.prototype.array = function (length) {
  174. var value = new Array(length);
  175. for (var i = 0; i < length; i++) {
  176. value[i] = this.parse();
  177. }
  178. return value;
  179. };
  180. Decoder.prototype.parse = function () {
  181. var type = this.view.getUint8(this.offset);
  182. var value, length;
  183. // FixRaw
  184. if ((type & 0xe0) === 0xa0) {
  185. length = type & 0x1f;
  186. this.offset++;
  187. return this.raw(length);
  188. }
  189. // FixMap
  190. if ((type & 0xf0) === 0x80) {
  191. length = type & 0x0f;
  192. this.offset++;
  193. return this.map(length);
  194. }
  195. // FixArray
  196. if ((type & 0xf0) === 0x90) {
  197. length = type & 0x0f;
  198. this.offset++;
  199. return this.array(length);
  200. }
  201. // Positive FixNum
  202. if ((type & 0x80) === 0x00) {
  203. this.offset++;
  204. return type;
  205. }
  206. // Negative Fixnum
  207. if ((type & 0xe0) === 0xe0) {
  208. value = this.view.getInt8(this.offset);
  209. this.offset++;
  210. return value;
  211. }
  212. switch (type) {
  213. // raw 16
  214. case 0xda:
  215. length = this.view.getUint16(this.offset + 1);
  216. this.offset += 3;
  217. return this.raw(length);
  218. // raw 32
  219. case 0xdb:
  220. length = this.view.getUint32(this.offset + 1);
  221. this.offset += 5;
  222. return this.raw(length);
  223. // nil
  224. case 0xc0:
  225. this.offset++;
  226. return null;
  227. // false
  228. case 0xc2:
  229. this.offset++;
  230. return false;
  231. // true
  232. case 0xc3:
  233. this.offset++;
  234. return true;
  235. // undefined
  236. case 0xc4:
  237. this.offset++;
  238. return undefined;
  239. // uint8
  240. case 0xcc:
  241. value = this.view.getUint8(this.offset + 1);
  242. this.offset += 2;
  243. return value;
  244. // uint 16
  245. case 0xcd:
  246. value = this.view.getUint16(this.offset + 1);
  247. this.offset += 3;
  248. return value;
  249. // uint 32
  250. case 0xce:
  251. value = this.view.getUint32(this.offset + 1);
  252. this.offset += 5;
  253. return value;
  254. // int 8
  255. case 0xd0:
  256. value = this.view.getInt8(this.offset + 1);
  257. this.offset += 2;
  258. return value;
  259. // int 16
  260. case 0xd1:
  261. value = this.view.getInt16(this.offset + 1);
  262. this.offset += 3;
  263. return value;
  264. // int 32
  265. case 0xd2:
  266. value = this.view.getInt32(this.offset + 1);
  267. this.offset += 5;
  268. return value;
  269. // map 16
  270. case 0xde:
  271. length = this.view.getUint16(this.offset + 1);
  272. this.offset += 3;
  273. return this.map(length);
  274. // map 32
  275. case 0xdf:
  276. length = this.view.getUint32(this.offset + 1);
  277. this.offset += 5;
  278. return this.map(length);
  279. // array 16
  280. case 0xdc:
  281. length = this.view.getUint16(this.offset + 1);
  282. this.offset += 3;
  283. return this.array(length);
  284. // array 32
  285. case 0xdd:
  286. length = this.view.getUint32(this.offset + 1);
  287. this.offset += 5;
  288. return this.array(length);
  289. // buffer 16
  290. case 0xd8:
  291. length = this.view.getUint16(this.offset + 1);
  292. this.offset += 3;
  293. return this.buf(length);
  294. // buffer 32
  295. case 0xd9:
  296. length = this.view.getUint32(this.offset + 1);
  297. this.offset += 5;
  298. return this.buf(length);
  299. // float
  300. case 0xca:
  301. value = this.view.getFloat32(this.offset + 1);
  302. this.offset += 5;
  303. return value;
  304. // double
  305. case 0xcb:
  306. value = this.view.getFloat64(this.offset + 1);
  307. this.offset += 9;
  308. return value;
  309. }
  310. throw new Error("Unknown type 0x" + type.toString(16));
  311. };
  312. function decode(buffer) {
  313. var view = new DataView(buffer);
  314. var decoder = new Decoder(view);
  315. var value = decoder.parse();
  316. if (decoder.offset !== buffer.byteLength) throw new Error((buffer.byteLength - decoder.offset) + " trailing bytes");
  317. return value;
  318. }
  319. function encode(value, view, offset) {
  320. var type = typeof value;
  321. // Strings Bytes
  322. if (type === "string") {
  323. var length = utf8ByteCount(value);
  324. // fix raw
  325. if (length < 0x20) {
  326. view.setUint8(offset, length | 0xa0);
  327. utf8Write(view, offset + 1, value);
  328. return 1 + length;
  329. }
  330. // raw 16
  331. if (length < 0x10000) {
  332. view.setUint8(offset, 0xda);
  333. view.setUint16(offset + 1, length);
  334. utf8Write(view, offset + 3, value);
  335. return 3 + length;
  336. }
  337. // raw 32
  338. if (length < 0x100000000) {
  339. view.setUint8(offset, 0xdb);
  340. view.setUint32(offset + 1, length);
  341. utf8Write(view, offset + 5, value);
  342. return 5 + length;
  343. }
  344. }
  345. if (value instanceof ArrayBuffer) {
  346. var length = value.byteLength;
  347. // buffer 16
  348. if (length < 0x10000) {
  349. view.setUint8(offset, 0xd8);
  350. view.setUint16(offset + 1, length);
  351. (new Uint8Array(view.buffer)).set(new Uint8Array(value), offset + 3);
  352. return 3 + length;
  353. }
  354. // buffer 32
  355. if (length < 0x100000000) {
  356. view.setUint8(offset, 0xd9);
  357. view.setUint32(offset + 1, length);
  358. (new Uint8Array(view.buffer)).set(new Uint8Array(value), offset + 5);
  359. return 5 + length;
  360. }
  361. }
  362. if (type === "number") {
  363. // Floating Point
  364. if ((value << 0) !== value) {
  365. view.setUint8(offset, 0xcb);
  366. view.setFloat64(offset + 1, value);
  367. return 9;
  368. }
  369. // Integers
  370. if (value >=0) {
  371. // positive fixnum
  372. if (value < 0x80) {
  373. view.setUint8(offset, value);
  374. return 1;
  375. }
  376. // uint 8
  377. if (value < 0x100) {
  378. view.setUint8(offset, 0xcc);
  379. view.setUint8(offset + 1, value);
  380. return 2;
  381. }
  382. // uint 16
  383. if (value < 0x10000) {
  384. view.setUint8(offset, 0xcd);
  385. view.setUint16(offset + 1, value);
  386. return 3;
  387. }
  388. // uint 32
  389. if (value < 0x100000000) {
  390. view.setUint8(offset, 0xce);
  391. view.setUint32(offset + 1, value);
  392. return 5;
  393. }
  394. throw new Error("Number too big 0x" + value.toString(16));
  395. }
  396. // negative fixnum
  397. if (value >= -0x20) {
  398. view.setInt8(offset, value);
  399. return 1;
  400. }
  401. // int 8
  402. if (value >= -0x80) {
  403. view.setUint8(offset, 0xd0);
  404. view.setInt8(offset + 1, value);
  405. return 2;
  406. }
  407. // int 16
  408. if (value >= -0x8000) {
  409. view.setUint8(offset, 0xd1);
  410. view.setInt16(offset + 1, value);
  411. return 3;
  412. }
  413. // int 32
  414. if (value >= -0x80000000) {
  415. view.setUint8(offset, 0xd2);
  416. view.setInt32(offset + 1, value);
  417. return 5;
  418. }
  419. throw new Error("Number too small -0x" + (-value).toString(16).substr(1));
  420. }
  421. // undefined
  422. if (type === "undefined") {
  423. view.setUint8(offset, 0xc4);
  424. return 1;
  425. }
  426. // null
  427. if (value === null) {
  428. view.setUint8(offset, 0xc0);
  429. return 1;
  430. }
  431. // Boolean
  432. if (type === "boolean") {
  433. view.setUint8(offset, value ? 0xc3 : 0xc2);
  434. return 1;
  435. }
  436. // Container Types
  437. if (type === "object") {
  438. var length, size = 0;
  439. var isArray = Array.isArray(value);
  440. if (isArray) {
  441. length = value.length;
  442. }
  443. else {
  444. var keys = Object.keys(value);
  445. length = keys.length;
  446. }
  447. var size;
  448. if (length < 0x10) {
  449. view.setUint8(offset, length | (isArray ? 0x90 : 0x80));
  450. size = 1;
  451. }
  452. else if (length < 0x10000) {
  453. view.setUint8(offset, isArray ? 0xdc : 0xde);
  454. view.setUint16(offset + 1, length);
  455. size = 3;
  456. }
  457. else if (length < 0x100000000) {
  458. view.setUint8(offset, isArray ? 0xdd : 0xdf);
  459. view.setUint32(offset + 1, length);
  460. size = 5;
  461. }
  462. if (isArray) {
  463. for (var i = 0; i < length; i++) {
  464. size += encode(value[i], view, offset + size);
  465. }
  466. }
  467. else {
  468. for (var i = 0; i < length; i++) {
  469. var key = keys[i];
  470. size += encode(key, view, offset + size);
  471. size += encode(value[key], view, offset + size);
  472. }
  473. }
  474. return size;
  475. }
  476. throw new Error("Unknown type " + type);
  477. }
  478. function sizeof(value) {
  479. var type = typeof value;
  480. // Raw Bytes
  481. if (type === "string") {
  482. var length = utf8ByteCount(value);
  483. if (length < 0x20) {
  484. return 1 + length;
  485. }
  486. if (length < 0x10000) {
  487. return 3 + length;
  488. }
  489. if (length < 0x100000000) {
  490. return 5 + length;
  491. }
  492. }
  493. if (value instanceof ArrayBuffer) {
  494. var length = value.byteLength;
  495. if (length < 0x10000) {
  496. return 3 + length;
  497. }
  498. if (length < 0x100000000) {
  499. return 5 + length;
  500. }
  501. }
  502. if (type === "number") {
  503. // Floating Point
  504. // double
  505. if (value << 0 !== value) return 9;
  506. // Integers
  507. if (value >=0) {
  508. // positive fixnum
  509. if (value < 0x80) return 1;
  510. // uint 8
  511. if (value < 0x100) return 2;
  512. // uint 16
  513. if (value < 0x10000) return 3;
  514. // uint 32
  515. if (value < 0x100000000) return 5;
  516. // uint 64
  517. if (value < 0x10000000000000000) return 9;
  518. throw new Error("Number too big 0x" + value.toString(16));
  519. }
  520. // negative fixnum
  521. if (value >= -0x20) return 1;
  522. // int 8
  523. if (value >= -0x80) return 2;
  524. // int 16
  525. if (value >= -0x8000) return 3;
  526. // int 32
  527. if (value >= -0x80000000) return 5;
  528. // int 64
  529. if (value >= -0x8000000000000000) return 9;
  530. throw new Error("Number too small -0x" + value.toString(16).substr(1));
  531. }
  532. // Boolean, null, undefined
  533. if (type === "boolean" || type === "undefined" || value === null) return 1;
  534. // Container Types
  535. if (type === "object") {
  536. var length, size = 0;
  537. if (Array.isArray(value)) {
  538. length = value.length;
  539. for (var i = 0; i < length; i++) {
  540. size += sizeof(value[i]);
  541. }
  542. }
  543. else {
  544. var keys = Object.keys(value);
  545. length = keys.length;
  546. for (var i = 0; i < length; i++) {
  547. var key = keys[i];
  548. size += sizeof(key) + sizeof(value[key]);
  549. }
  550. }
  551. if (length < 0x10) {
  552. return 1 + size;
  553. }
  554. if (length < 0x10000) {
  555. return 3 + size;
  556. }
  557. if (length < 0x100000000) {
  558. return 5 + size;
  559. }
  560. throw new Error("Array or object too long 0x" + length.toString(16));
  561. }
  562. throw new Error("Unknown type " + type);
  563. }
  564. return exports;
  565. });