You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

406 lines
12 KiB

  1. /*
  2. * The MIT License (MIT)
  3. *
  4. * Copyright (c) 2014-2016 Patrick Gansterer <paroga@paroga.com>
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a copy
  7. * of this software and associated documentation files (the "Software"), to deal
  8. * in the Software without restriction, including without limitation the rights
  9. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. * copies of the Software, and to permit persons to whom the Software is
  11. * furnished to do so, subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be included in all
  14. * copies or substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  22. * SOFTWARE.
  23. */
  24. (function(global, undefined) { "use strict";
  25. var POW_2_24 = 5.960464477539063e-8,
  26. POW_2_32 = 4294967296,
  27. POW_2_53 = 9007199254740992;
  28. function encode(value) {
  29. var data = new ArrayBuffer(256);
  30. var dataView = new DataView(data);
  31. var lastLength;
  32. var offset = 0;
  33. function prepareWrite(length) {
  34. var newByteLength = data.byteLength;
  35. var requiredLength = offset + length;
  36. while (newByteLength < requiredLength)
  37. newByteLength <<= 1;
  38. if (newByteLength !== data.byteLength) {
  39. var oldDataView = dataView;
  40. data = new ArrayBuffer(newByteLength);
  41. dataView = new DataView(data);
  42. var uint32count = (offset + 3) >> 2;
  43. for (var i = 0; i < uint32count; ++i)
  44. dataView.setUint32(i << 2, oldDataView.getUint32(i << 2));
  45. }
  46. lastLength = length;
  47. return dataView;
  48. }
  49. function commitWrite() {
  50. offset += lastLength;
  51. }
  52. function writeFloat64(value) {
  53. commitWrite(prepareWrite(8).setFloat64(offset, value));
  54. }
  55. function writeUint8(value) {
  56. commitWrite(prepareWrite(1).setUint8(offset, value));
  57. }
  58. function writeUint8Array(value) {
  59. var dataView = prepareWrite(value.length);
  60. for (var i = 0; i < value.length; ++i)
  61. dataView.setUint8(offset + i, value[i]);
  62. commitWrite();
  63. }
  64. function writeUint16(value) {
  65. commitWrite(prepareWrite(2).setUint16(offset, value));
  66. }
  67. function writeUint32(value) {
  68. commitWrite(prepareWrite(4).setUint32(offset, value));
  69. }
  70. function writeUint64(value) {
  71. var low = value % POW_2_32;
  72. var high = (value - low) / POW_2_32;
  73. var dataView = prepareWrite(8);
  74. dataView.setUint32(offset, high);
  75. dataView.setUint32(offset + 4, low);
  76. commitWrite();
  77. }
  78. function writeTypeAndLength(type, length) {
  79. if (length < 24) {
  80. writeUint8(type << 5 | length);
  81. } else if (length < 0x100) {
  82. writeUint8(type << 5 | 24);
  83. writeUint8(length);
  84. } else if (length < 0x10000) {
  85. writeUint8(type << 5 | 25);
  86. writeUint16(length);
  87. } else if (length < 0x100000000) {
  88. writeUint8(type << 5 | 26);
  89. writeUint32(length);
  90. } else {
  91. writeUint8(type << 5 | 27);
  92. writeUint64(length);
  93. }
  94. }
  95. function encodeItem(value) {
  96. var i;
  97. if (value === false)
  98. return writeUint8(0xf4);
  99. if (value === true)
  100. return writeUint8(0xf5);
  101. if (value === null)
  102. return writeUint8(0xf6);
  103. if (value === undefined)
  104. return writeUint8(0xf7);
  105. switch (typeof value) {
  106. case "number":
  107. if (Math.floor(value) === value) {
  108. if (0 <= value && value <= POW_2_53)
  109. return writeTypeAndLength(0, value);
  110. if (-POW_2_53 <= value && value < 0)
  111. return writeTypeAndLength(1, -(value + 1));
  112. }
  113. writeUint8(0xfb);
  114. return writeFloat64(value);
  115. case "string":
  116. var utf8data = [];
  117. for (i = 0; i < value.length; ++i) {
  118. var charCode = value.charCodeAt(i);
  119. if (charCode < 0x80) {
  120. utf8data.push(charCode);
  121. } else if (charCode < 0x800) {
  122. utf8data.push(0xc0 | charCode >> 6);
  123. utf8data.push(0x80 | charCode & 0x3f);
  124. } else if (charCode < 0xd800) {
  125. utf8data.push(0xe0 | charCode >> 12);
  126. utf8data.push(0x80 | (charCode >> 6) & 0x3f);
  127. utf8data.push(0x80 | charCode & 0x3f);
  128. } else {
  129. charCode = (charCode & 0x3ff) << 10;
  130. charCode |= value.charCodeAt(++i) & 0x3ff;
  131. charCode += 0x10000;
  132. utf8data.push(0xf0 | charCode >> 18);
  133. utf8data.push(0x80 | (charCode >> 12) & 0x3f);
  134. utf8data.push(0x80 | (charCode >> 6) & 0x3f);
  135. utf8data.push(0x80 | charCode & 0x3f);
  136. }
  137. }
  138. writeTypeAndLength(3, utf8data.length);
  139. return writeUint8Array(utf8data);
  140. default:
  141. var length;
  142. if (Array.isArray(value)) {
  143. length = value.length;
  144. writeTypeAndLength(4, length);
  145. for (i = 0; i < length; ++i)
  146. encodeItem(value[i]);
  147. } else if (value instanceof Uint8Array) {
  148. writeTypeAndLength(2, value.length);
  149. writeUint8Array(value);
  150. } else {
  151. var keys = Object.keys(value);
  152. length = keys.length;
  153. writeTypeAndLength(5, length);
  154. for (i = 0; i < length; ++i) {
  155. var key = keys[i];
  156. encodeItem(key);
  157. encodeItem(value[key]);
  158. }
  159. }
  160. }
  161. }
  162. encodeItem(value);
  163. if ("slice" in data)
  164. return data.slice(0, offset);
  165. var ret = new ArrayBuffer(offset);
  166. var retView = new DataView(ret);
  167. for (var i = 0; i < offset; ++i)
  168. retView.setUint8(i, dataView.getUint8(i));
  169. return ret;
  170. }
  171. function decode(data, tagger, simpleValue) {
  172. var dataView = new DataView(data);
  173. var offset = 0;
  174. if (typeof tagger !== "function")
  175. tagger = function(value) { return value; };
  176. if (typeof simpleValue !== "function")
  177. simpleValue = function() { return undefined; };
  178. function commitRead(length, value) {
  179. offset += length;
  180. return value;
  181. }
  182. function readArrayBuffer(length) {
  183. return commitRead(length, new Uint8Array(data, offset, length));
  184. }
  185. function readFloat16() {
  186. var tempArrayBuffer = new ArrayBuffer(4);
  187. var tempDataView = new DataView(tempArrayBuffer);
  188. var value = readUint16();
  189. var sign = value & 0x8000;
  190. var exponent = value & 0x7c00;
  191. var fraction = value & 0x03ff;
  192. if (exponent === 0x7c00)
  193. exponent = 0xff << 10;
  194. else if (exponent !== 0)
  195. exponent += (127 - 15) << 10;
  196. else if (fraction !== 0)
  197. return (sign ? -1 : 1) * fraction * POW_2_24;
  198. tempDataView.setUint32(0, sign << 16 | exponent << 13 | fraction << 13);
  199. return tempDataView.getFloat32(0);
  200. }
  201. function readFloat32() {
  202. return commitRead(4, dataView.getFloat32(offset));
  203. }
  204. function readFloat64() {
  205. return commitRead(8, dataView.getFloat64(offset));
  206. }
  207. function readUint8() {
  208. return commitRead(1, dataView.getUint8(offset));
  209. }
  210. function readUint16() {
  211. return commitRead(2, dataView.getUint16(offset));
  212. }
  213. function readUint32() {
  214. return commitRead(4, dataView.getUint32(offset));
  215. }
  216. function readUint64() {
  217. return readUint32() * POW_2_32 + readUint32();
  218. }
  219. function readBreak() {
  220. if (dataView.getUint8(offset) !== 0xff)
  221. return false;
  222. offset += 1;
  223. return true;
  224. }
  225. function readLength(additionalInformation) {
  226. if (additionalInformation < 24)
  227. return additionalInformation;
  228. if (additionalInformation === 24)
  229. return readUint8();
  230. if (additionalInformation === 25)
  231. return readUint16();
  232. if (additionalInformation === 26)
  233. return readUint32();
  234. if (additionalInformation === 27)
  235. return readUint64();
  236. if (additionalInformation === 31)
  237. return -1;
  238. throw "Invalid length encoding";
  239. }
  240. function readIndefiniteStringLength(majorType) {
  241. var initialByte = readUint8();
  242. if (initialByte === 0xff)
  243. return -1;
  244. var length = readLength(initialByte & 0x1f);
  245. if (length < 0 || (initialByte >> 5) !== majorType)
  246. throw "Invalid indefinite length element";
  247. return length;
  248. }
  249. function appendUtf16Data(utf16data, length) {
  250. for (var i = 0; i < length; ++i) {
  251. var value = readUint8();
  252. if (value & 0x80) {
  253. if (value < 0xe0) {
  254. value = (value & 0x1f) << 6
  255. | (readUint8() & 0x3f);
  256. length -= 1;
  257. } else if (value < 0xf0) {
  258. value = (value & 0x0f) << 12
  259. | (readUint8() & 0x3f) << 6
  260. | (readUint8() & 0x3f);
  261. length -= 2;
  262. } else {
  263. value = (value & 0x0f) << 18
  264. | (readUint8() & 0x3f) << 12
  265. | (readUint8() & 0x3f) << 6
  266. | (readUint8() & 0x3f);
  267. length -= 3;
  268. }
  269. }
  270. if (value < 0x10000) {
  271. utf16data.push(value);
  272. } else {
  273. value -= 0x10000;
  274. utf16data.push(0xd800 | (value >> 10));
  275. utf16data.push(0xdc00 | (value & 0x3ff));
  276. }
  277. }
  278. }
  279. function decodeItem() {
  280. var initialByte = readUint8();
  281. var majorType = initialByte >> 5;
  282. var additionalInformation = initialByte & 0x1f;
  283. var i;
  284. var length;
  285. if (majorType === 7) {
  286. switch (additionalInformation) {
  287. case 25:
  288. return readFloat16();
  289. case 26:
  290. return readFloat32();
  291. case 27:
  292. return readFloat64();
  293. }
  294. }
  295. length = readLength(additionalInformation);
  296. if (length < 0 && (majorType < 2 || 6 < majorType))
  297. throw "Invalid length";
  298. switch (majorType) {
  299. case 0:
  300. return length;
  301. case 1:
  302. return -1 - length;
  303. case 2:
  304. if (length < 0) {
  305. var elements = [];
  306. var fullArrayLength = 0;
  307. while ((length = readIndefiniteStringLength(majorType)) >= 0) {
  308. fullArrayLength += length;
  309. elements.push(readArrayBuffer(length));
  310. }
  311. var fullArray = new Uint8Array(fullArrayLength);
  312. var fullArrayOffset = 0;
  313. for (i = 0; i < elements.length; ++i) {
  314. fullArray.set(elements[i], fullArrayOffset);
  315. fullArrayOffset += elements[i].length;
  316. }
  317. return fullArray;
  318. }
  319. return readArrayBuffer(length);
  320. case 3:
  321. var utf16data = [];
  322. if (length < 0) {
  323. while ((length = readIndefiniteStringLength(majorType)) >= 0)
  324. appendUtf16Data(utf16data, length);
  325. } else
  326. appendUtf16Data(utf16data, length);
  327. return String.fromCharCode.apply(null, utf16data);
  328. case 4:
  329. var retArray;
  330. if (length < 0) {
  331. retArray = [];
  332. while (!readBreak())
  333. retArray.push(decodeItem());
  334. } else {
  335. retArray = new Array(length);
  336. for (i = 0; i < length; ++i)
  337. retArray[i] = decodeItem();
  338. }
  339. return retArray;
  340. case 5:
  341. var retObject = {};
  342. for (i = 0; i < length || length < 0 && !readBreak(); ++i) {
  343. var key = decodeItem();
  344. retObject[key] = decodeItem();
  345. }
  346. return retObject;
  347. case 6:
  348. return tagger(decodeItem(), length);
  349. case 7:
  350. switch (length) {
  351. case 20:
  352. return false;
  353. case 21:
  354. return true;
  355. case 22:
  356. return null;
  357. case 23:
  358. return undefined;
  359. default:
  360. return simpleValue(length);
  361. }
  362. }
  363. }
  364. var ret = decodeItem();
  365. if (offset !== data.byteLength)
  366. throw "Remaining bytes";
  367. return ret;
  368. }
  369. var obj = { encode: encode, decode: decode };
  370. if (typeof define === "function" && define.amd)
  371. define("cbor/cbor", obj);
  372. else if (typeof module !== "undefined" && module.exports)
  373. module.exports = obj;
  374. else if (!global.CBOR)
  375. global.CBOR = obj;
  376. })(this);