index.js 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. var createBlob_1 = require("./createBlob");
  4. var BLOB_TYPE_PREFIX_REGEX = /^~~local_forage_type~([^~]+)~/;
  5. var SERIALIZED_MARKER_LENGTH = "__lfsc__:" /* SERIALIZED_MARKER */.length;
  6. var TYPE_SERIALIZED_MARKER_LENGTH = SERIALIZED_MARKER_LENGTH + "arbf" /* TYPE_ARRAYBUFFER */.length;
  7. //tslint:disable:no-magic-numbers no-bitwise prefer-switch no-unbound-method
  8. var toString = Object.prototype.toString;
  9. function stringToBuffer(serializedString) {
  10. // Fill the string into a ArrayBuffer.
  11. var bufferLength = serializedString.length * 0.75;
  12. var len = serializedString.length;
  13. if (serializedString[serializedString.length - 1] === '=') {
  14. bufferLength--;
  15. if (serializedString[serializedString.length - 2] === '=') {
  16. bufferLength--;
  17. }
  18. }
  19. var buffer = new ArrayBuffer(bufferLength);
  20. var bytes = new Uint8Array(buffer);
  21. for (var i = 0, p = 0; i < len; i += 4) {
  22. var encoded1 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" /* BASE_CHARS */.indexOf(serializedString[i]);
  23. var encoded2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" /* BASE_CHARS */.indexOf(serializedString[i + 1]);
  24. var encoded3 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" /* BASE_CHARS */.indexOf(serializedString[i + 2]);
  25. var encoded4 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" /* BASE_CHARS */.indexOf(serializedString[i + 3]);
  26. bytes[p++] = (encoded1 << 2) | (encoded2 >> 4);
  27. bytes[p++] = ((encoded2 & 15) << 4) | (encoded3 >> 2);
  28. bytes[p++] = ((encoded3 & 3) << 6) | (encoded4 & 63);
  29. }
  30. return buffer;
  31. }
  32. exports.stringToBuffer = stringToBuffer;
  33. /**
  34. * Converts a buffer to a string to store, serialized, in the backend
  35. * storage library.
  36. */
  37. function bufferToString(buffer) {
  38. // base64-arraybuffer
  39. var bytes = new Uint8Array(buffer);
  40. var base64String = '';
  41. for (var i = 0; i < bytes.length; i += 3) {
  42. /*jslint bitwise: true */
  43. base64String += "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" /* BASE_CHARS */[bytes[i] >> 2];
  44. base64String += "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" /* BASE_CHARS */[((bytes[i] & 3) << 4) | (bytes[i + 1] >> 4)];
  45. base64String +=
  46. "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" /* BASE_CHARS */[((bytes[i + 1] & 15) << 2) | (bytes[i + 2] >> 6)];
  47. base64String += "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" /* BASE_CHARS */[bytes[i + 2] & 63];
  48. }
  49. if (bytes.length % 3 === 2) {
  50. base64String = base64String.substring(0, base64String.length - 1) + '=';
  51. }
  52. else if (bytes.length % 3 === 1) {
  53. base64String = base64String.substring(0, base64String.length - 2) + '==';
  54. }
  55. return base64String;
  56. }
  57. exports.bufferToString = bufferToString;
  58. /**
  59. * Serialize a value, afterwards executing a callback (which usually
  60. * instructs the `setItem()` callback/promise to be executed). This is how
  61. * we store binary data with localStorage.
  62. * @param value
  63. * @param callback
  64. */
  65. function serialize(value, callback) {
  66. var valueType = '';
  67. if (value) {
  68. valueType = toString.call(value);
  69. }
  70. // Cannot use `value instanceof ArrayBuffer` or such here, as these
  71. // checks fail when running the tests using casper.js...
  72. if (value && (valueType === '[object ArrayBuffer]' ||
  73. (value.buffer && toString.call(value.buffer) === '[object ArrayBuffer]'))) {
  74. // Convert binary arrays to a string and prefix the string with
  75. // a special marker.
  76. var buffer = void 0;
  77. var marker = "__lfsc__:" /* SERIALIZED_MARKER */;
  78. if (value instanceof ArrayBuffer) {
  79. buffer = value;
  80. marker += "arbf" /* TYPE_ARRAYBUFFER */;
  81. }
  82. else {
  83. buffer = value.buffer;
  84. if (valueType === '[object Int8Array]') {
  85. marker += "si08" /* TYPE_INT8ARRAY */;
  86. }
  87. else if (valueType === '[object Uint8Array]') {
  88. marker += "ui08" /* TYPE_UINT8ARRAY */;
  89. }
  90. else if (valueType === '[object Uint8ClampedArray]') {
  91. marker += "uic8" /* TYPE_UINT8CLAMPEDARRAY */;
  92. }
  93. else if (valueType === '[object Int16Array]') {
  94. marker += "si16" /* TYPE_INT16ARRAY */;
  95. }
  96. else if (valueType === '[object Uint16Array]') {
  97. marker += "ur16" /* TYPE_UINT16ARRAY */;
  98. }
  99. else if (valueType === '[object Int32Array]') {
  100. marker += "si32" /* TYPE_INT32ARRAY */;
  101. }
  102. else if (valueType === '[object Uint32Array]') {
  103. marker += "ui32" /* TYPE_UINT32ARRAY */;
  104. }
  105. else if (valueType === '[object Float32Array]') {
  106. marker += "fl32" /* TYPE_FLOAT32ARRAY */;
  107. }
  108. else if (valueType === '[object Float64Array]') {
  109. marker += "fl64" /* TYPE_FLOAT64ARRAY */;
  110. }
  111. else {
  112. callback(new Error('Failed to get type for BinaryArray'));
  113. }
  114. }
  115. callback(marker + bufferToString(buffer));
  116. }
  117. else if (valueType === '[object Blob]') {
  118. // Convert the blob to a binaryArray and then to a string.
  119. var fileReader = new FileReader();
  120. fileReader.onload = function () {
  121. // Backwards-compatible prefix for the blob type.
  122. //tslint:disable-next-line:restrict-plus-operands
  123. var str = "~~local_forage_type~" /* BLOB_TYPE_PREFIX */ + value.type + "~" + bufferToString(this.result);
  124. callback("__lfsc__:" /* SERIALIZED_MARKER */ + "blob" /* TYPE_BLOB */ + str);
  125. };
  126. fileReader.readAsArrayBuffer(value);
  127. }
  128. else {
  129. try {
  130. callback(JSON.stringify(value));
  131. }
  132. catch (e) {
  133. console.error('Couldn\'t convert value into a JSON string: ', value);
  134. callback(null, e);
  135. }
  136. }
  137. }
  138. exports.serialize = serialize;
  139. /**
  140. * Deserialize data we've inserted into a value column/field. We place
  141. * special markers into our strings to mark them as encoded; this isn't
  142. * as nice as a meta field, but it's the only sane thing we can do whilst
  143. * keeping localStorage support intact.
  144. *
  145. * Oftentimes this will just deserialize JSON content, but if we have a
  146. * special marker (SERIALIZED_MARKER, defined above), we will extract
  147. * some kind of arraybuffer/binary data/typed array out of the string.
  148. * @param value
  149. */
  150. function deserialize(value) {
  151. // If we haven't marked this string as being specially serialized (i.e.
  152. // something other than serialized JSON), we can just return it and be
  153. // done with it.
  154. if (value.substring(0, SERIALIZED_MARKER_LENGTH) !== "__lfsc__:" /* SERIALIZED_MARKER */) {
  155. return JSON.parse(value);
  156. }
  157. // The following code deals with deserializing some kind of Blob or
  158. // TypedArray. First we separate out the type of data we're dealing
  159. // with from the data itself.
  160. var serializedString = value.substring(TYPE_SERIALIZED_MARKER_LENGTH);
  161. var type = value.substring(SERIALIZED_MARKER_LENGTH, TYPE_SERIALIZED_MARKER_LENGTH);
  162. var blobType;
  163. // Backwards-compatible blob type serialization strategy.
  164. // DBs created with older versions of localForage will simply not have the blob type.
  165. if (type === "blob" /* TYPE_BLOB */ && BLOB_TYPE_PREFIX_REGEX.test(serializedString)) {
  166. var matcher = serializedString.match(BLOB_TYPE_PREFIX_REGEX);
  167. blobType = matcher[1];
  168. serializedString = serializedString.substring(matcher[0].length);
  169. }
  170. var buffer = stringToBuffer(serializedString);
  171. // Return the right type based on the code/type set during
  172. // serialization.
  173. switch (type) {
  174. case "arbf" /* TYPE_ARRAYBUFFER */:
  175. return buffer;
  176. case "blob" /* TYPE_BLOB */:
  177. return createBlob_1.createBlob([buffer], { type: blobType });
  178. case "si08" /* TYPE_INT8ARRAY */:
  179. return new Int8Array(buffer);
  180. case "ui08" /* TYPE_UINT8ARRAY */:
  181. return new Uint8Array(buffer);
  182. case "uic8" /* TYPE_UINT8CLAMPEDARRAY */:
  183. return new Uint8ClampedArray(buffer);
  184. case "si16" /* TYPE_INT16ARRAY */:
  185. return new Int16Array(buffer);
  186. case "ur16" /* TYPE_UINT16ARRAY */:
  187. return new Uint16Array(buffer);
  188. case "si32" /* TYPE_INT32ARRAY */:
  189. return new Int32Array(buffer);
  190. case "ui32" /* TYPE_UINT32ARRAY */:
  191. return new Uint32Array(buffer);
  192. case "fl32" /* TYPE_FLOAT32ARRAY */:
  193. return new Float32Array(buffer);
  194. case "fl64" /* TYPE_FLOAT64ARRAY */:
  195. return new Float64Array(buffer);
  196. default:
  197. throw new Error('Unkown type: ' + type);
  198. }
  199. }
  200. exports.deserialize = deserialize;
  201. //# sourceMappingURL=index.js.map