UNPKG

browserfs

Version:

A filesystem in your browser!

179 lines (164 loc) 5.01 kB
/** * Grab bag of utility functions used across the code. */ import {FileSystem} from './file_system'; import path = require('path'); const SUPPORTS_TYPED_ARRAYS = typeof(ArrayBuffer) !== 'undefined'; /** * Checks for any IE version, including IE11 which removed MSIE from the * userAgent string. */ export var isIE: boolean = typeof navigator !== "undefined" && (/(msie) ([\w.]+)/.exec(navigator.userAgent.toLowerCase()) != null || navigator.userAgent.indexOf('Trident') !== -1); /** * Check if we're in a web worker. */ export var isWebWorker: boolean = typeof window === "undefined"; export interface Arrayish<T> { [idx: number]: T; length: number; } /** * Synchronous recursive makedir. */ export function mkdirpSync(p: string, mode: number, fs: FileSystem): void { if (!fs.existsSync(p)) { mkdirpSync(path.dirname(p), mode, fs); fs.mkdirSync(p, mode); } } /** * Converts a buffer into an array buffer. Attempts to do so in a * zero-copy manner, e.g. the array references the same memory. */ export function buffer2ArrayBuffer(buff: Buffer): ArrayBuffer { var u8 = buffer2Uint8array(buff), u8offset = u8.byteOffset, u8Len = u8.byteLength; if (u8offset === 0 && u8Len === u8.buffer.byteLength) { return u8.buffer; } else { return u8.buffer.slice(u8offset, u8offset + u8Len) } } /** * Converts a buffer into a Uint8Array. Attempts to do so in a * zero-copy manner, e.g. the array references the same memory. */ export function buffer2Uint8array(buff: Buffer): Uint8Array { if (buff['toUint8Array']) { return (<any> buff).toUint8Array(); } else if (buff instanceof Uint8Array) { // Node v4.0 buffers *are* Uint8Arrays. return <any> buff; } else { // Uint8Arrays can be constructed from arrayish numbers. // At this point, we assume this isn't a BFS array. return new Uint8Array(buff); } } /** * Converts the given buffer into a Uint8 arrayish form. Attempts * to be zero-copy. * * Required for BrowserFS buffers, which do not support indexing. */ export function buffer2Arrayish(buff: Buffer): Arrayish<number> { if (typeof(buff[0]) === 'number') { return buff; } else if (SUPPORTS_TYPED_ARRAYS) { return buffer2Uint8array(buff); } else { return buff.toJSON().data; } } /** * Converts the given arrayish object into a Buffer. Attempts to * be zero-copy. */ export function arrayish2Buffer(arr: Arrayish<number>): Buffer { if (SUPPORTS_TYPED_ARRAYS && arr instanceof Uint8Array) { return uint8Array2Buffer(arr); } else if (arr instanceof Buffer) { return arr; } else { return new Buffer(<number[]> arr); } } /** * Converts the given Uint8Array into a Buffer. Attempts to be zero-copy. */ export function uint8Array2Buffer(u8: Uint8Array): Buffer { if (u8.byteOffset === 0 && u8.byteLength === u8.buffer.byteLength) { return arrayBuffer2Buffer(u8); } else { return new Buffer(u8); } } /** * Converts the given array buffer into a Buffer. Attempts to be * zero-copy. */ export function arrayBuffer2Buffer(ab: ArrayBuffer): Buffer { try { // Works in BFS and Node v4.2. return new Buffer(<any> ab); } catch (e) { // I believe this copies, but there's no avoiding it in Node < v4.2 return new Buffer(new Uint8Array(ab)); } } // Polyfill for Uint8Array.prototype.slice. // Safari and some other browsers do not define it. if (typeof(ArrayBuffer) !== 'undefined' && typeof(Uint8Array) !== 'undefined') { if (!Uint8Array.prototype['slice']) { Uint8Array.prototype.slice = function(start: number = 0, end: number = this.length): Uint8Array { let self: Uint8Array = this; if (start < 0) { start = this.length + start; if (start < 0) { start = 0; } } if (end < 0) { end = this.length + end; if (end < 0) { end = 0; } } if (end < start) { end = start; } return new Uint8Array(self.buffer, self.byteOffset + start, end - start); }; } } /** * Copies a slice of the given buffer */ export function copyingSlice(buff: Buffer, start: number = 0, end = buff.length): Buffer { if (start < 0 || end < 0 || end > buff.length || start > end) { throw new TypeError(`Invalid slice bounds on buffer of length ${buff.length}: [${start}, ${end}]`); } if (buff.length === 0) { // Avoid s0 corner case in ArrayBuffer case. return new Buffer(0); } else if (SUPPORTS_TYPED_ARRAYS) { var u8 = buffer2Uint8array(buff), s0 = buff.readUInt8(0), newS0 = (s0 + 1) % 0xFF; buff.writeUInt8(newS0, 0); if (u8[0] === newS0) { // Same memory. Revert & copy. u8[0] = s0; return uint8Array2Buffer(u8.slice(start, end)); } else { // Revert. buff.writeUInt8(s0, 0); return uint8Array2Buffer(u8.subarray(start, end)); } } else { var buffSlice = new Buffer(end - start); buff.copy(buffSlice, 0, start, end); return buffSlice; } }