2017-07-26 15:12:12 +00:00
|
|
|
/**
|
|
|
|
* Copyright (c) 2013-present, Facebook, Inc.
|
|
|
|
*
|
2018-02-17 02:24:55 +00:00
|
|
|
* This source code is licensed under the MIT license found in the
|
|
|
|
* LICENSE file in the root directory of this source tree.
|
2017-07-26 15:12:12 +00:00
|
|
|
*
|
|
|
|
* @providesModule Blob
|
|
|
|
* @flow
|
2018-01-26 17:06:14 +00:00
|
|
|
* @format
|
2017-07-26 15:12:12 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
'use strict';
|
|
|
|
|
2018-01-26 17:06:14 +00:00
|
|
|
import type {BlobData, BlobOptions} from 'BlobTypes';
|
2017-07-26 15:12:12 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Opaque JS representation of some binary data in native.
|
|
|
|
*
|
|
|
|
* The API is modeled after the W3C Blob API, with one caveat
|
|
|
|
* regarding explicit deallocation. Refer to the `close()`
|
|
|
|
* method for further details.
|
|
|
|
*
|
|
|
|
* Example usage in a React component:
|
|
|
|
*
|
|
|
|
* class WebSocketImage extends React.Component {
|
|
|
|
* state = {blob: null};
|
|
|
|
* componentDidMount() {
|
|
|
|
* let ws = this.ws = new WebSocket(...);
|
|
|
|
* ws.binaryType = 'blob';
|
|
|
|
* ws.onmessage = (event) => {
|
|
|
|
* if (this.state.blob) {
|
|
|
|
* this.state.blob.close();
|
|
|
|
* }
|
|
|
|
* this.setState({blob: event.data});
|
|
|
|
* };
|
|
|
|
* }
|
|
|
|
* componentUnmount() {
|
|
|
|
* if (this.state.blob) {
|
|
|
|
* this.state.blob.close();
|
|
|
|
* }
|
|
|
|
* this.ws.close();
|
|
|
|
* }
|
|
|
|
* render() {
|
|
|
|
* if (!this.state.blob) {
|
|
|
|
* return <View />;
|
|
|
|
* }
|
|
|
|
* return <Image source={{uri: URL.createObjectURL(this.state.blob)}} />;
|
|
|
|
* }
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* Reference: https://developer.mozilla.org/en-US/docs/Web/API/Blob
|
|
|
|
*/
|
|
|
|
class Blob {
|
2018-01-26 17:06:14 +00:00
|
|
|
_data: ?BlobData;
|
2017-07-26 15:12:12 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Constructor for JS consumers.
|
|
|
|
* Currently we only support creating Blobs from other Blobs.
|
|
|
|
* Reference: https://developer.mozilla.org/en-US/docs/Web/API/Blob/Blob
|
|
|
|
*/
|
2018-01-26 17:06:14 +00:00
|
|
|
constructor(parts: Array<Blob | string> = [], options?: BlobOptions) {
|
|
|
|
const BlobManager = require('BlobManager');
|
|
|
|
this.data = BlobManager.createFromParts(parts, options).data;
|
2017-07-26 15:12:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This method is used to create a new Blob object containing
|
|
|
|
* the data in the specified range of bytes of the source Blob.
|
|
|
|
* Reference: https://developer.mozilla.org/en-US/docs/Web/API/Blob/slice
|
|
|
|
*/
|
2018-01-26 17:06:14 +00:00
|
|
|
set data(data: ?BlobData) {
|
|
|
|
this._data = data;
|
|
|
|
}
|
|
|
|
|
|
|
|
get data(): BlobData {
|
|
|
|
if (!this._data) {
|
|
|
|
throw new Error('Blob has been closed and is no longer available');
|
|
|
|
}
|
|
|
|
|
|
|
|
return this._data;
|
|
|
|
}
|
|
|
|
|
2017-07-26 15:12:12 +00:00
|
|
|
slice(start?: number, end?: number): Blob {
|
2018-01-26 17:06:14 +00:00
|
|
|
const BlobManager = require('BlobManager');
|
|
|
|
let {offset, size} = this.data;
|
|
|
|
|
2017-07-26 15:12:12 +00:00
|
|
|
if (typeof start === 'number') {
|
|
|
|
if (start > size) {
|
|
|
|
start = size;
|
|
|
|
}
|
|
|
|
offset += start;
|
|
|
|
size -= start;
|
|
|
|
|
|
|
|
if (typeof end === 'number') {
|
|
|
|
if (end < 0) {
|
|
|
|
end = this.size + end;
|
|
|
|
}
|
|
|
|
size = end - start;
|
|
|
|
}
|
|
|
|
}
|
2018-01-26 17:06:14 +00:00
|
|
|
return BlobManager.createFromOptions({
|
|
|
|
blobId: this.data.blobId,
|
2017-07-26 15:12:12 +00:00
|
|
|
offset,
|
|
|
|
size,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This method is in the standard, but not actually implemented by
|
|
|
|
* any browsers at this point. It's important for how Blobs work in
|
|
|
|
* React Native, however, since we cannot de-allocate resources automatically,
|
|
|
|
* so consumers need to explicitly de-allocate them.
|
|
|
|
*
|
|
|
|
* Note that the semantics around Blobs created via `blob.slice()`
|
|
|
|
* and `new Blob([blob])` are different. `blob.slice()` creates a
|
|
|
|
* new *view* onto the same binary data, so calling `close()` on any
|
|
|
|
* of those views is enough to deallocate the data, whereas
|
|
|
|
* `new Blob([blob, ...])` actually copies the data in memory.
|
|
|
|
*/
|
|
|
|
close() {
|
2018-01-26 17:06:14 +00:00
|
|
|
const BlobManager = require('BlobManager');
|
|
|
|
BlobManager.release(this.data.blobId);
|
|
|
|
this.data = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Size of the data contained in the Blob object, in bytes.
|
|
|
|
*/
|
|
|
|
get size(): number {
|
|
|
|
return this.data.size;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* String indicating the MIME type of the data contained in the Blob.
|
|
|
|
* If the type is unknown, this string is empty.
|
|
|
|
*/
|
|
|
|
get type(): string {
|
|
|
|
return this.data.type || '';
|
2017-07-26 15:12:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = Blob;
|