123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256 |
- (function (global, factory) {
- if (typeof define === "function" && define.amd) {
- define('localforageSerializer', ['module', 'exports', './createBlob'], factory);
- } else if (typeof exports !== "undefined") {
- factory(module, exports, require('./createBlob'));
- } else {
- var mod = {
- exports: {}
- };
- factory(mod, mod.exports, global.createBlob);
- global.localforageSerializer = mod.exports;
- }
- })(this, function (module, exports, _createBlob) {
- 'use strict';
-
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
-
- var _createBlob2 = _interopRequireDefault(_createBlob);
-
- function _interopRequireDefault(obj) {
- return obj && obj.__esModule ? obj : {
- default: obj
- };
- }
-
- // Sadly, the best way to save binary data in WebSQL/localStorage is serializing
- // it to Base64, so this is how we store it to prevent very strange errors with less
- // verbose ways of binary <-> string data storage.
- var BASE_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; /* eslint-disable no-bitwise */
-
-
- var BLOB_TYPE_PREFIX = '~~local_forage_type~';
- var BLOB_TYPE_PREFIX_REGEX = /^~~local_forage_type~([^~]+)~/;
-
- var SERIALIZED_MARKER = '__lfsc__:';
- var SERIALIZED_MARKER_LENGTH = SERIALIZED_MARKER.length;
-
- // OMG the serializations!
- var TYPE_ARRAYBUFFER = 'arbf';
- var TYPE_BLOB = 'blob';
- var TYPE_INT8ARRAY = 'si08';
- var TYPE_UINT8ARRAY = 'ui08';
- var TYPE_UINT8CLAMPEDARRAY = 'uic8';
- var TYPE_INT16ARRAY = 'si16';
- var TYPE_INT32ARRAY = 'si32';
- var TYPE_UINT16ARRAY = 'ur16';
- var TYPE_UINT32ARRAY = 'ui32';
- var TYPE_FLOAT32ARRAY = 'fl32';
- var TYPE_FLOAT64ARRAY = 'fl64';
- var TYPE_SERIALIZED_MARKER_LENGTH = SERIALIZED_MARKER_LENGTH + TYPE_ARRAYBUFFER.length;
-
- var toString = Object.prototype.toString;
-
- function stringToBuffer(serializedString) {
- // Fill the string into a ArrayBuffer.
- var bufferLength = serializedString.length * 0.75;
- var len = serializedString.length;
- var i;
- var p = 0;
- var encoded1, encoded2, encoded3, encoded4;
-
- if (serializedString[serializedString.length - 1] === '=') {
- bufferLength--;
- if (serializedString[serializedString.length - 2] === '=') {
- bufferLength--;
- }
- }
-
- var buffer = new ArrayBuffer(bufferLength);
- var bytes = new Uint8Array(buffer);
-
- for (i = 0; i < len; i += 4) {
- encoded1 = BASE_CHARS.indexOf(serializedString[i]);
- encoded2 = BASE_CHARS.indexOf(serializedString[i + 1]);
- encoded3 = BASE_CHARS.indexOf(serializedString[i + 2]);
- encoded4 = BASE_CHARS.indexOf(serializedString[i + 3]);
-
- /*jslint bitwise: true */
- bytes[p++] = encoded1 << 2 | encoded2 >> 4;
- bytes[p++] = (encoded2 & 15) << 4 | encoded3 >> 2;
- bytes[p++] = (encoded3 & 3) << 6 | encoded4 & 63;
- }
- return buffer;
- }
-
- // Converts a buffer to a string to store, serialized, in the backend
- // storage library.
- function bufferToString(buffer) {
- // base64-arraybuffer
- var bytes = new Uint8Array(buffer);
- var base64String = '';
- var i;
-
- for (i = 0; i < bytes.length; i += 3) {
- /*jslint bitwise: true */
- base64String += BASE_CHARS[bytes[i] >> 2];
- base64String += BASE_CHARS[(bytes[i] & 3) << 4 | bytes[i + 1] >> 4];
- base64String += BASE_CHARS[(bytes[i + 1] & 15) << 2 | bytes[i + 2] >> 6];
- base64String += BASE_CHARS[bytes[i + 2] & 63];
- }
-
- if (bytes.length % 3 === 2) {
- base64String = base64String.substring(0, base64String.length - 1) + '=';
- } else if (bytes.length % 3 === 1) {
- base64String = base64String.substring(0, base64String.length - 2) + '==';
- }
-
- return base64String;
- }
-
- // Serialize a value, afterwards executing a callback (which usually
- // instructs the `setItem()` callback/promise to be executed). This is how
- // we store binary data with localStorage.
- function serialize(value, callback) {
- var valueType = '';
- if (value) {
- valueType = toString.call(value);
- }
-
- // Cannot use `value instanceof ArrayBuffer` or such here, as these
- // checks fail when running the tests using casper.js...
- //
- // TODO: See why those tests fail and use a better solution.
- if (value && (valueType === '[object ArrayBuffer]' || value.buffer && toString.call(value.buffer) === '[object ArrayBuffer]')) {
- // Convert binary arrays to a string and prefix the string with
- // a special marker.
- var buffer;
- var marker = SERIALIZED_MARKER;
-
- if (value instanceof ArrayBuffer) {
- buffer = value;
- marker += TYPE_ARRAYBUFFER;
- } else {
- buffer = value.buffer;
-
- if (valueType === '[object Int8Array]') {
- marker += TYPE_INT8ARRAY;
- } else if (valueType === '[object Uint8Array]') {
- marker += TYPE_UINT8ARRAY;
- } else if (valueType === '[object Uint8ClampedArray]') {
- marker += TYPE_UINT8CLAMPEDARRAY;
- } else if (valueType === '[object Int16Array]') {
- marker += TYPE_INT16ARRAY;
- } else if (valueType === '[object Uint16Array]') {
- marker += TYPE_UINT16ARRAY;
- } else if (valueType === '[object Int32Array]') {
- marker += TYPE_INT32ARRAY;
- } else if (valueType === '[object Uint32Array]') {
- marker += TYPE_UINT32ARRAY;
- } else if (valueType === '[object Float32Array]') {
- marker += TYPE_FLOAT32ARRAY;
- } else if (valueType === '[object Float64Array]') {
- marker += TYPE_FLOAT64ARRAY;
- } else {
- callback(new Error('Failed to get type for BinaryArray'));
- }
- }
-
- callback(marker + bufferToString(buffer));
- } else if (valueType === '[object Blob]') {
- // Conver the blob to a binaryArray and then to a string.
- var fileReader = new FileReader();
-
- fileReader.onload = function () {
- // Backwards-compatible prefix for the blob type.
- var str = BLOB_TYPE_PREFIX + value.type + '~' + bufferToString(this.result);
-
- callback(SERIALIZED_MARKER + TYPE_BLOB + str);
- };
-
- fileReader.readAsArrayBuffer(value);
- } else {
- try {
- callback(JSON.stringify(value));
- } catch (e) {
- console.error("Couldn't convert value into a JSON string: ", value);
-
- callback(null, e);
- }
- }
- }
-
- // Deserialize data we've inserted into a value column/field. We place
- // special markers into our strings to mark them as encoded; this isn't
- // as nice as a meta field, but it's the only sane thing we can do whilst
- // keeping localStorage support intact.
- //
- // Oftentimes this will just deserialize JSON content, but if we have a
- // special marker (SERIALIZED_MARKER, defined above), we will extract
- // some kind of arraybuffer/binary data/typed array out of the string.
- function deserialize(value) {
- // If we haven't marked this string as being specially serialized (i.e.
- // something other than serialized JSON), we can just return it and be
- // done with it.
- if (value.substring(0, SERIALIZED_MARKER_LENGTH) !== SERIALIZED_MARKER) {
- return JSON.parse(value);
- }
-
- // The following code deals with deserializing some kind of Blob or
- // TypedArray. First we separate out the type of data we're dealing
- // with from the data itself.
- var serializedString = value.substring(TYPE_SERIALIZED_MARKER_LENGTH);
- var type = value.substring(SERIALIZED_MARKER_LENGTH, TYPE_SERIALIZED_MARKER_LENGTH);
-
- var blobType;
- // Backwards-compatible blob type serialization strategy.
- // DBs created with older versions of localForage will simply not have the blob type.
- if (type === TYPE_BLOB && BLOB_TYPE_PREFIX_REGEX.test(serializedString)) {
- var matcher = serializedString.match(BLOB_TYPE_PREFIX_REGEX);
- blobType = matcher[1];
- serializedString = serializedString.substring(matcher[0].length);
- }
- var buffer = stringToBuffer(serializedString);
-
- // Return the right type based on the code/type set during
- // serialization.
- switch (type) {
- case TYPE_ARRAYBUFFER:
- return buffer;
- case TYPE_BLOB:
- return (0, _createBlob2.default)([buffer], { type: blobType });
- case TYPE_INT8ARRAY:
- return new Int8Array(buffer);
- case TYPE_UINT8ARRAY:
- return new Uint8Array(buffer);
- case TYPE_UINT8CLAMPEDARRAY:
- return new Uint8ClampedArray(buffer);
- case TYPE_INT16ARRAY:
- return new Int16Array(buffer);
- case TYPE_UINT16ARRAY:
- return new Uint16Array(buffer);
- case TYPE_INT32ARRAY:
- return new Int32Array(buffer);
- case TYPE_UINT32ARRAY:
- return new Uint32Array(buffer);
- case TYPE_FLOAT32ARRAY:
- return new Float32Array(buffer);
- case TYPE_FLOAT64ARRAY:
- return new Float64Array(buffer);
- default:
- throw new Error('Unkown type: ' + type);
- }
- }
-
- var localforageSerializer = {
- serialize: serialize,
- deserialize: deserialize,
- stringToBuffer: stringToBuffer,
- bufferToString: bufferToString
- };
-
- exports.default = localforageSerializer;
- module.exports = exports['default'];
- });
|