react-native-blob-util 0.22.0 → 0.22.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/.eslintrc.js +56 -56
  2. package/LICENSE +21 -21
  3. package/Migration.md +41 -41
  4. package/NuGet.config +11 -11
  5. package/README.md +1109 -1104
  6. package/android/gradle.properties +1 -1
  7. package/android/src/main/AndroidManifest.xml +37 -37
  8. package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilConfig.java +57 -57
  9. package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilConst.java +20 -20
  10. package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilFileTransformer.java +9 -9
  11. package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilImpl.java +431 -431
  12. package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilProgressConfig.java +39 -39
  13. package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilReq.java +1014 -1014
  14. package/android/src/main/java/com/ReactNativeBlobUtil/Response/ReactNativeBlobUtilDefaultResp.java +98 -98
  15. package/android/src/main/java/com/ReactNativeBlobUtil/Response/ReactNativeBlobUtilFileResp.java +166 -166
  16. package/android/src/main/java/com/ReactNativeBlobUtil/Utils/FileDescription.java +19 -19
  17. package/android/src/main/java/com/ReactNativeBlobUtil/Utils/FileProvider.java +4 -4
  18. package/android/src/main/java/com/ReactNativeBlobUtil/Utils/MimeType.java +70 -70
  19. package/android/src/main/java/com/ReactNativeBlobUtil/Utils/PathResolver.java +223 -223
  20. package/android/src/main/java/com/ReactNativeBlobUtil/Utils/Tls12SocketFactory.java +68 -68
  21. package/android/src/main/res/values/strings.xml +3 -3
  22. package/android/src/main/res/xml/provider_paths.xml +12 -12
  23. package/android.js +58 -58
  24. package/class/ReactNativeBlobUtilCanceledFetchError.js +9 -9
  25. package/class/ReactNativeBlobUtilFile.js +5 -5
  26. package/class/ReactNativeBlobUtilReadStream.js +84 -84
  27. package/class/ReactNativeBlobUtilSession.js +68 -68
  28. package/class/ReactNativeBlobUtilWriteStream.js +50 -50
  29. package/class/StatefulPromise.js +7 -7
  30. package/codegenSpecs/NativeBlobUtils.js +86 -86
  31. package/components/Fetch.onPress.js +10 -10
  32. package/components/Fetch.when.js +15 -15
  33. package/fetch.js +350 -350
  34. package/fs.js +480 -480
  35. package/index.js +64 -64
  36. package/index.js.flow +192 -192
  37. package/index.web.js +1 -1
  38. package/ios/PrivacyInfo.xcprivacy +28 -28
  39. package/ios/ReactNativeBlobUtil/ReactNativeBlobUtil.h +55 -55
  40. package/ios/ReactNativeBlobUtil/ReactNativeBlobUtil.mm +992 -992
  41. package/ios/ReactNativeBlobUtil.xcodeproj/project.pbxproj +405 -405
  42. package/ios/ReactNativeBlobUtilConst.h +58 -58
  43. package/ios/ReactNativeBlobUtilConst.mm +47 -47
  44. package/ios/ReactNativeBlobUtilFS.h +108 -108
  45. package/ios/ReactNativeBlobUtilFS.mm +1064 -1064
  46. package/ios/ReactNativeBlobUtilFileTransformer.h +23 -23
  47. package/ios/ReactNativeBlobUtilFileTransformer.mm +20 -20
  48. package/ios/ReactNativeBlobUtilNetwork.h +49 -49
  49. package/ios/ReactNativeBlobUtilNetwork.mm +159 -159
  50. package/ios/ReactNativeBlobUtilProgress.h +32 -32
  51. package/ios/ReactNativeBlobUtilProgress.mm +57 -57
  52. package/ios/ReactNativeBlobUtilReqBuilder.h +37 -37
  53. package/ios/ReactNativeBlobUtilReqBuilder.mm +292 -292
  54. package/ios/ReactNativeBlobUtilRequest.h +48 -48
  55. package/ios/ReactNativeBlobUtilRequest.mm +584 -584
  56. package/ios.js +61 -61
  57. package/json-stream.js +42 -42
  58. package/lib/oboe-browser.js +2703 -2703
  59. package/mediacollection.js +36 -36
  60. package/package.json +68 -68
  61. package/polyfill/Blob.js +362 -362
  62. package/polyfill/Event.js +11 -11
  63. package/polyfill/EventTarget.js +78 -78
  64. package/polyfill/Fetch.js +219 -219
  65. package/polyfill/File.js +27 -27
  66. package/polyfill/FileReader.js +91 -91
  67. package/polyfill/ProgressEvent.js +32 -32
  68. package/polyfill/XMLHttpRequest.js +466 -466
  69. package/polyfill/XMLHttpRequestEventTarget.js +126 -126
  70. package/polyfill/index.js +11 -11
  71. package/react-native-blob-util.podspec +48 -48
  72. package/types.js +69 -69
  73. package/utils/log.js +40 -40
  74. package/utils/unicode.js +7 -7
  75. package/utils/uri.js +33 -33
  76. package/utils/uuid.js +4 -4
  77. package/windows/ExperimentalFeatures.props +33 -33
  78. package/windows/README.md +2 -2
  79. package/windows/ReactNativeBlobUtil/PropertySheet.props +15 -15
  80. package/windows/ReactNativeBlobUtil/ReactNativeBlobUtil.cpp +1836 -1836
  81. package/windows/ReactNativeBlobUtil/ReactNativeBlobUtil.def +3 -3
  82. package/windows/ReactNativeBlobUtil/ReactNativeBlobUtil.h +372 -372
  83. package/windows/ReactNativeBlobUtil/ReactNativeBlobUtil.vcxproj +139 -139
  84. package/windows/ReactNativeBlobUtil/ReactNativeBlobUtil.vcxproj.filters +43 -43
  85. package/windows/ReactNativeBlobUtil/ReactPackageProvider.cpp +20 -20
  86. package/windows/ReactNativeBlobUtil/ReactPackageProvider.h +24 -24
  87. package/windows/ReactNativeBlobUtil/ReactPackageProvider.idl +9 -9
  88. package/windows/ReactNativeBlobUtil/codegen/.clang-format +1 -1
  89. package/windows/ReactNativeBlobUtil/codegen/NativeBlobUtilsDataTypes.g.h +42 -42
  90. package/windows/ReactNativeBlobUtil/codegen/NativeBlobUtilsSpec.g.h +353 -353
  91. package/windows/ReactNativeBlobUtil/packages.config +3 -3
  92. package/windows/ReactNativeBlobUtil/packages.lock.json +59 -59
  93. package/windows/ReactNativeBlobUtil/pch.cpp +1 -1
  94. package/windows/ReactNativeBlobUtil/pch.h +30 -30
  95. package/windows/ReactNativeBlobUtil/resource.h +5 -5
  96. package/windows/ReactNativeBlobUtil/targetver.h +8 -8
  97. package/windows/ReactNativeBlobUtil.sln +43 -43
package/polyfill/Blob.js CHANGED
@@ -1,362 +1,362 @@
1
- // Copyright 2016 wkh237@github. All rights reserved.
2
- // Use of this source code is governed by a MIT-style license that can be
3
- // found in the LICENSE file.
4
-
5
- import fs from '../fs.js';
6
- import getUUID from '../utils/uuid';
7
- import Log from '../utils/log.js';
8
- import URIUtil from "../utils/uri";
9
- import EventTarget from './EventTarget';
10
-
11
- const log = new Log('Blob');
12
- const blobCacheDir = fs.dirs.DocumentDir + '/ReactNativeBlobUtil-blobs/';
13
-
14
- log.disable();
15
- // log.level(3)
16
-
17
- /**
18
- * A ReactNativeBlobUtil style Blob polyfill class, this is a Blob which compatible to
19
- * Response object attain fron ReactNativeBlobUtil.fetch.
20
- */
21
- export default class Blob extends EventTarget {
22
-
23
- cacheName: string;
24
- type: string;
25
- size: number;
26
- isReactNativeBlobUtilPolyfill: boolean = true;
27
- multipartBoundary: string = null;
28
-
29
- _ref: string = null;
30
- _blobCreated: boolean = false;
31
- _onCreated: Array<any> = [];
32
- _closed: boolean = false;
33
-
34
- /**
35
- * Static method that remove all files in Blob cache folder.
36
- * @nonstandard
37
- * @return {Promise}
38
- */
39
- static clearCache() {
40
- return fs.unlink(blobCacheDir).then(() => fs.mkdir(blobCacheDir));
41
- }
42
-
43
- static build(data: any, cType: any): Promise<Blob> {
44
- return new Promise((resolve, reject) => {
45
- new Blob(data, cType).onCreated(resolve);
46
- });
47
- }
48
-
49
- get blobPath() {
50
- return this._ref;
51
- }
52
-
53
- static setLog(level: number) {
54
- if (level === -1)
55
- log.disable();
56
- else
57
- log.level(level);
58
- }
59
-
60
- /**
61
- * ReactNativeBlobUtil Blob polyfill, create a Blob directly from file path, BASE64
62
- * encoded data, and string. The conversion is done implicitly according to
63
- * given `mime`. However, the blob creation is asynchronously, to register
64
- * event `onCreated` is need to ensure the Blob is creadted.
65
- * @param {any} data Content of Blob object
66
- * @param {any} mime Content type settings of Blob object, `text/plain`
67
- * by default
68
- * @param {boolean} defer When this argument set to `true`, blob constructor
69
- * will not invoke blob created event automatically.
70
- */
71
- constructor(data: any, cType: any, defer: boolean) {
72
- super();
73
- cType = cType || {};
74
- this.cacheName = getBlobName();
75
- this.isReactNativeBlobUtilPolyfill = true;
76
- this.isDerived = defer;
77
- this.type = cType.type || 'text/plain';
78
- log.verbose('Blob constructor called', 'mime', this.type, 'type', typeof data, 'length', data ? data.length : 0);
79
- this._ref = blobCacheDir + this.cacheName;
80
- let p = null;
81
- if (!data)
82
- data = '';
83
- if (data.isReactNativeBlobUtilPolyfill) {
84
- log.verbose('create Blob cache file from Blob object');
85
- let size = 0;
86
- this._ref = String(data.getReactNativeBlobUtilRef());
87
- let orgPath = this._ref;
88
-
89
- p = fs.exists(orgPath)
90
- .then((exist) => {
91
- if (exist)
92
- return fs.writeFile(orgPath, data, 'uri')
93
- .then((size) => Promise.resolve(size))
94
- .catch((err) => {
95
- throw `ReactNativeBlobUtil Blob file creation error, ${err}`;
96
- });
97
- else
98
- throw `could not create Blob from path ${orgPath}, file not exists`;
99
- });
100
- }
101
- // process FormData
102
- else if (data instanceof FormData) {
103
- log.verbose('create Blob cache file from FormData', data);
104
- let boundary = `ReactNativeBlobUtil-${this.cacheName}-${Date.now()}`;
105
- this.multipartBoundary = boundary;
106
- let parts = data.getParts();
107
- let formArray = [];
108
- if (!parts) {
109
- p = fs.writeFile(this._ref, '', 'utf8');
110
- }
111
- else {
112
- for (let i in parts) {
113
- formArray.push('\r\n--' + boundary + '\r\n');
114
- let part = parts[i];
115
- for (let j in part.headers) {
116
- formArray.push(j + ': ' + part.headers[j] + '\r\n');
117
- }
118
- formArray.push('\r\n');
119
- if (part.isReactNativeBlobUtilPolyfill)
120
- formArray.push(part);
121
- else
122
- formArray.push(part.string);
123
- }
124
- log.verbose('FormData array', formArray);
125
- formArray.push('\r\n--' + boundary + '--\r\n');
126
- p = createMixedBlobData(this._ref, formArray);
127
- }
128
- }
129
- // if the data is a string starts with `ReactNativeBlobUtil-file://`, append the
130
- // Blob data from file path
131
- else if (typeof data === 'string' && data.startsWith('ReactNativeBlobUtil-file://')) {
132
- log.verbose('create Blob cache file from file path', data);
133
- // set this flag so that we know this blob is a wrapper of an existing file
134
- this._isReference = true;
135
- this._ref = String(data).replace('ReactNativeBlobUtil-file://', '');
136
- let orgPath = this._ref;
137
- if (defer)
138
- return;
139
- else {
140
- p = fs.stat(orgPath)
141
- .then((stat) => {
142
- return Promise.resolve(stat.size);
143
- });
144
- }
145
- }
146
- // content from variable need create file
147
- else if (typeof data === 'string') {
148
- let encoding = 'utf8';
149
- let mime = String(this.type);
150
- // when content type contains application/octet* or *;base64, ReactNativeBlobUtil
151
- // fs will treat it as BASE64 encoded string binary data
152
- if (/(application\/octet|\;base64)/i.test(mime))
153
- encoding = 'base64';
154
- else
155
- data = data.toString();
156
- // create cache file
157
- this.type = String(this.type).replace(/;base64/ig, '');
158
- log.verbose('create Blob cache file from string', 'encode', encoding);
159
- p = fs.writeFile(this._ref, data, encoding)
160
- .then((size) => {
161
- return Promise.resolve(size);
162
- });
163
-
164
- }
165
- // TODO : ArrayBuffer support
166
- // else if (data instanceof ArrayBuffer ) {
167
- //
168
- // }
169
- // when input is an array of mixed data types, create a file cache
170
- else if (Array.isArray(data)) {
171
- log.verbose('create Blob cache file from mixed array', data);
172
- p = createMixedBlobData(this._ref, data);
173
- }
174
- else {
175
- data = data.toString();
176
- p = fs.writeFile(this._ref, data, 'utf8')
177
- .then((size) => Promise.resolve(size));
178
- }
179
- p && p.then((size) => {
180
- this.size = size;
181
- this._invokeOnCreateEvent();
182
- })
183
- .catch((err) => {
184
- log.error('ReactNativeBlobUtil could not create Blob : ' + this._ref, err);
185
- });
186
-
187
- }
188
-
189
- /**
190
- * Since Blob content will asynchronously write to a file during creation,
191
- * use this method to register an event handler for Blob initialized event.
192
- * @nonstandard
193
- * @param {(b:Blob) => void} An event handler invoked when Blob created
194
- * @return {Blob} The Blob object instance itself
195
- */
196
- onCreated(fn: () => void): Blob {
197
- log.verbose('#register blob onCreated', this._blobCreated);
198
- if (!this._blobCreated)
199
- this._onCreated.push(fn);
200
- else {
201
- fn(this);
202
- }
203
- return this;
204
- }
205
-
206
- markAsDerived() {
207
- this._isDerived = true;
208
- }
209
-
210
- get isDerived() {
211
- return this._isDerived || false;
212
- }
213
-
214
- /**
215
- * Get file reference of the Blob object.
216
- * @nonstandard
217
- * @return {string} Blob file reference which can be consumed by ReactNativeBlobUtil fs
218
- */
219
- getReactNativeBlobUtilRef() {
220
- return this._ref;
221
- }
222
-
223
- /**
224
- * Create a Blob object which is sliced from current object
225
- * @param {number} start Start byte number
226
- * @param {number} end End byte number
227
- * @param {string} contentType Optional, content type of new Blob object
228
- * @return {Blob}
229
- */
230
- slice(start: ?number, end: ?number, contentType: ?string = ''): Blob {
231
- if (this._closed)
232
- throw 'Blob has been released.';
233
- log.verbose('slice called', start, end, contentType);
234
-
235
-
236
- let resPath = blobCacheDir + getBlobName();
237
- let pass = false;
238
- log.debug('fs.slice new blob will at', resPath);
239
- let result = new Blob(URIUtil.wrap(resPath), {type: contentType}, true);
240
- fs.exists(blobCacheDir)
241
- .then((exist) => {
242
- if (exist)
243
- return Promise.resolve();
244
- return fs.mkdir(blobCacheDir);
245
- })
246
- .then(() => fs.slice(this._ref, resPath, start, end))
247
- .then((dest) => {
248
- log.debug('fs.slice done', dest);
249
- result._invokeOnCreateEvent();
250
- pass = true;
251
- })
252
- .catch((err) => {
253
- console.warn('Blob.slice failed:', err);
254
- pass = true;
255
- });
256
- log.debug('slice returning new Blob');
257
-
258
- return result;
259
- }
260
-
261
- /**
262
- * Read data of the Blob object, this is not standard method.
263
- * @nonstandard
264
- * @param {string} encoding Read data with encoding
265
- * @return {Promise}
266
- */
267
- readBlob(encoding: string): Promise<any> {
268
- if (this._closed)
269
- throw 'Blob has been released.';
270
- return fs.readFile(this._ref, encoding || 'utf8');
271
- }
272
-
273
- /**
274
- * Release the resource of the Blob object.
275
- * @nonstandard
276
- * @return {Promise}
277
- */
278
- close() {
279
- if (this._closed)
280
- return Promise.reject('Blob has been released.');
281
- this._closed = true;
282
- return fs.unlink(this._ref).catch((err) => {
283
- console.warn(err);
284
- });
285
- }
286
-
287
- safeClose() {
288
- if (this._closed)
289
- return Promise.reject('Blob has been released.');
290
- this._closed = true;
291
- if (!this._isReference) {
292
- return fs.unlink(this._ref).catch((err) => {
293
- console.warn(err);
294
- });
295
- }
296
- else {
297
- return Promise.resolve();
298
- }
299
- }
300
-
301
- _invokeOnCreateEvent() {
302
- log.verbose('invoke create event', this._onCreated);
303
- this._blobCreated = true;
304
- let fns = this._onCreated;
305
- for (let i in fns) {
306
- if (typeof fns[i] === 'function') {
307
- fns[i](this);
308
- }
309
- }
310
- delete this._onCreated;
311
- }
312
-
313
- }
314
-
315
- /**
316
- * Get a temp filename for Blob object
317
- * @return {string} Temporary filename
318
- */
319
- function getBlobName() {
320
- return 'blob-' + getUUID();
321
- }
322
-
323
- /**
324
- * Create a file according to given array. The element in array can be a number,
325
- * Blob, String, Array.
326
- * @param {string} ref File path reference
327
- * @param {Array} dataArray An array contains different types of data.
328
- * @return {Promise}
329
- */
330
- function createMixedBlobData(ref, dataArray) {
331
- // create an empty file for store blob data
332
- let p = fs.writeFile(ref, '');
333
- let args = [];
334
- let size = 0;
335
- for (let i in dataArray) {
336
- let part = dataArray[i];
337
- if (!part)
338
- continue;
339
- if (part.isReactNativeBlobUtilPolyfill) {
340
- args.push([ref, part._ref, 'uri']);
341
- }
342
- else if (typeof part === 'string')
343
- args.push([ref, part, 'utf8']);
344
- // TODO : ArrayBuffer
345
- // else if (part instanceof ArrayBuffer) {
346
- //
347
- // }
348
- else if (Array.isArray(part))
349
- args.push([ref, part, 'ascii']);
350
- }
351
- // start write blob data
352
- for (let i in args) {
353
- p = p.then(function (written) {
354
- let arg = this;
355
- if (written)
356
- size += written;
357
- log.verbose('mixed blob write', args[i], written);
358
- return fs.appendFile(...arg);
359
- }.bind(args[i]));
360
- }
361
- return p.then(() => Promise.resolve(size));
362
- }
1
+ // Copyright 2016 wkh237@github. All rights reserved.
2
+ // Use of this source code is governed by a MIT-style license that can be
3
+ // found in the LICENSE file.
4
+
5
+ import fs from '../fs.js';
6
+ import getUUID from '../utils/uuid';
7
+ import Log from '../utils/log.js';
8
+ import URIUtil from "../utils/uri";
9
+ import EventTarget from './EventTarget';
10
+
11
+ const log = new Log('Blob');
12
+ const blobCacheDir = fs.dirs.DocumentDir + '/ReactNativeBlobUtil-blobs/';
13
+
14
+ log.disable();
15
+ // log.level(3)
16
+
17
+ /**
18
+ * A ReactNativeBlobUtil style Blob polyfill class, this is a Blob which compatible to
19
+ * Response object attain fron ReactNativeBlobUtil.fetch.
20
+ */
21
+ export default class Blob extends EventTarget {
22
+
23
+ cacheName: string;
24
+ type: string;
25
+ size: number;
26
+ isReactNativeBlobUtilPolyfill: boolean = true;
27
+ multipartBoundary: string = null;
28
+
29
+ _ref: string = null;
30
+ _blobCreated: boolean = false;
31
+ _onCreated: Array<any> = [];
32
+ _closed: boolean = false;
33
+
34
+ /**
35
+ * Static method that remove all files in Blob cache folder.
36
+ * @nonstandard
37
+ * @return {Promise}
38
+ */
39
+ static clearCache() {
40
+ return fs.unlink(blobCacheDir).then(() => fs.mkdir(blobCacheDir));
41
+ }
42
+
43
+ static build(data: any, cType: any): Promise<Blob> {
44
+ return new Promise((resolve, reject) => {
45
+ new Blob(data, cType).onCreated(resolve);
46
+ });
47
+ }
48
+
49
+ get blobPath() {
50
+ return this._ref;
51
+ }
52
+
53
+ static setLog(level: number) {
54
+ if (level === -1)
55
+ log.disable();
56
+ else
57
+ log.level(level);
58
+ }
59
+
60
+ /**
61
+ * ReactNativeBlobUtil Blob polyfill, create a Blob directly from file path, BASE64
62
+ * encoded data, and string. The conversion is done implicitly according to
63
+ * given `mime`. However, the blob creation is asynchronously, to register
64
+ * event `onCreated` is need to ensure the Blob is creadted.
65
+ * @param {any} data Content of Blob object
66
+ * @param {any} mime Content type settings of Blob object, `text/plain`
67
+ * by default
68
+ * @param {boolean} defer When this argument set to `true`, blob constructor
69
+ * will not invoke blob created event automatically.
70
+ */
71
+ constructor(data: any, cType: any, defer: boolean) {
72
+ super();
73
+ cType = cType || {};
74
+ this.cacheName = getBlobName();
75
+ this.isReactNativeBlobUtilPolyfill = true;
76
+ this.isDerived = defer;
77
+ this.type = cType.type || 'text/plain';
78
+ log.verbose('Blob constructor called', 'mime', this.type, 'type', typeof data, 'length', data ? data.length : 0);
79
+ this._ref = blobCacheDir + this.cacheName;
80
+ let p = null;
81
+ if (!data)
82
+ data = '';
83
+ if (data.isReactNativeBlobUtilPolyfill) {
84
+ log.verbose('create Blob cache file from Blob object');
85
+ let size = 0;
86
+ this._ref = String(data.getReactNativeBlobUtilRef());
87
+ let orgPath = this._ref;
88
+
89
+ p = fs.exists(orgPath)
90
+ .then((exist) => {
91
+ if (exist)
92
+ return fs.writeFile(orgPath, data, 'uri')
93
+ .then((size) => Promise.resolve(size))
94
+ .catch((err) => {
95
+ throw `ReactNativeBlobUtil Blob file creation error, ${err}`;
96
+ });
97
+ else
98
+ throw `could not create Blob from path ${orgPath}, file not exists`;
99
+ });
100
+ }
101
+ // process FormData
102
+ else if (data instanceof FormData) {
103
+ log.verbose('create Blob cache file from FormData', data);
104
+ let boundary = `ReactNativeBlobUtil-${this.cacheName}-${Date.now()}`;
105
+ this.multipartBoundary = boundary;
106
+ let parts = data.getParts();
107
+ let formArray = [];
108
+ if (!parts) {
109
+ p = fs.writeFile(this._ref, '', 'utf8');
110
+ }
111
+ else {
112
+ for (let i in parts) {
113
+ formArray.push('\r\n--' + boundary + '\r\n');
114
+ let part = parts[i];
115
+ for (let j in part.headers) {
116
+ formArray.push(j + ': ' + part.headers[j] + '\r\n');
117
+ }
118
+ formArray.push('\r\n');
119
+ if (part.isReactNativeBlobUtilPolyfill)
120
+ formArray.push(part);
121
+ else
122
+ formArray.push(part.string);
123
+ }
124
+ log.verbose('FormData array', formArray);
125
+ formArray.push('\r\n--' + boundary + '--\r\n');
126
+ p = createMixedBlobData(this._ref, formArray);
127
+ }
128
+ }
129
+ // if the data is a string starts with `ReactNativeBlobUtil-file://`, append the
130
+ // Blob data from file path
131
+ else if (typeof data === 'string' && data.startsWith('ReactNativeBlobUtil-file://')) {
132
+ log.verbose('create Blob cache file from file path', data);
133
+ // set this flag so that we know this blob is a wrapper of an existing file
134
+ this._isReference = true;
135
+ this._ref = String(data).replace('ReactNativeBlobUtil-file://', '');
136
+ let orgPath = this._ref;
137
+ if (defer)
138
+ return;
139
+ else {
140
+ p = fs.stat(orgPath)
141
+ .then((stat) => {
142
+ return Promise.resolve(stat.size);
143
+ });
144
+ }
145
+ }
146
+ // content from variable need create file
147
+ else if (typeof data === 'string') {
148
+ let encoding = 'utf8';
149
+ let mime = String(this.type);
150
+ // when content type contains application/octet* or *;base64, ReactNativeBlobUtil
151
+ // fs will treat it as BASE64 encoded string binary data
152
+ if (/(application\/octet|\;base64)/i.test(mime))
153
+ encoding = 'base64';
154
+ else
155
+ data = data.toString();
156
+ // create cache file
157
+ this.type = String(this.type).replace(/;base64/ig, '');
158
+ log.verbose('create Blob cache file from string', 'encode', encoding);
159
+ p = fs.writeFile(this._ref, data, encoding)
160
+ .then((size) => {
161
+ return Promise.resolve(size);
162
+ });
163
+
164
+ }
165
+ // TODO : ArrayBuffer support
166
+ // else if (data instanceof ArrayBuffer ) {
167
+ //
168
+ // }
169
+ // when input is an array of mixed data types, create a file cache
170
+ else if (Array.isArray(data)) {
171
+ log.verbose('create Blob cache file from mixed array', data);
172
+ p = createMixedBlobData(this._ref, data);
173
+ }
174
+ else {
175
+ data = data.toString();
176
+ p = fs.writeFile(this._ref, data, 'utf8')
177
+ .then((size) => Promise.resolve(size));
178
+ }
179
+ p && p.then((size) => {
180
+ this.size = size;
181
+ this._invokeOnCreateEvent();
182
+ })
183
+ .catch((err) => {
184
+ log.error('ReactNativeBlobUtil could not create Blob : ' + this._ref, err);
185
+ });
186
+
187
+ }
188
+
189
+ /**
190
+ * Since Blob content will asynchronously write to a file during creation,
191
+ * use this method to register an event handler for Blob initialized event.
192
+ * @nonstandard
193
+ * @param {(b:Blob) => void} An event handler invoked when Blob created
194
+ * @return {Blob} The Blob object instance itself
195
+ */
196
+ onCreated(fn: () => void): Blob {
197
+ log.verbose('#register blob onCreated', this._blobCreated);
198
+ if (!this._blobCreated)
199
+ this._onCreated.push(fn);
200
+ else {
201
+ fn(this);
202
+ }
203
+ return this;
204
+ }
205
+
206
+ markAsDerived() {
207
+ this._isDerived = true;
208
+ }
209
+
210
+ get isDerived() {
211
+ return this._isDerived || false;
212
+ }
213
+
214
+ /**
215
+ * Get file reference of the Blob object.
216
+ * @nonstandard
217
+ * @return {string} Blob file reference which can be consumed by ReactNativeBlobUtil fs
218
+ */
219
+ getReactNativeBlobUtilRef() {
220
+ return this._ref;
221
+ }
222
+
223
+ /**
224
+ * Create a Blob object which is sliced from current object
225
+ * @param {number} start Start byte number
226
+ * @param {number} end End byte number
227
+ * @param {string} contentType Optional, content type of new Blob object
228
+ * @return {Blob}
229
+ */
230
+ slice(start: ?number, end: ?number, contentType: ?string = ''): Blob {
231
+ if (this._closed)
232
+ throw 'Blob has been released.';
233
+ log.verbose('slice called', start, end, contentType);
234
+
235
+
236
+ let resPath = blobCacheDir + getBlobName();
237
+ let pass = false;
238
+ log.debug('fs.slice new blob will at', resPath);
239
+ let result = new Blob(URIUtil.wrap(resPath), {type: contentType}, true);
240
+ fs.exists(blobCacheDir)
241
+ .then((exist) => {
242
+ if (exist)
243
+ return Promise.resolve();
244
+ return fs.mkdir(blobCacheDir);
245
+ })
246
+ .then(() => fs.slice(this._ref, resPath, start, end))
247
+ .then((dest) => {
248
+ log.debug('fs.slice done', dest);
249
+ result._invokeOnCreateEvent();
250
+ pass = true;
251
+ })
252
+ .catch((err) => {
253
+ console.warn('Blob.slice failed:', err);
254
+ pass = true;
255
+ });
256
+ log.debug('slice returning new Blob');
257
+
258
+ return result;
259
+ }
260
+
261
+ /**
262
+ * Read data of the Blob object, this is not standard method.
263
+ * @nonstandard
264
+ * @param {string} encoding Read data with encoding
265
+ * @return {Promise}
266
+ */
267
+ readBlob(encoding: string): Promise<any> {
268
+ if (this._closed)
269
+ throw 'Blob has been released.';
270
+ return fs.readFile(this._ref, encoding || 'utf8');
271
+ }
272
+
273
+ /**
274
+ * Release the resource of the Blob object.
275
+ * @nonstandard
276
+ * @return {Promise}
277
+ */
278
+ close() {
279
+ if (this._closed)
280
+ return Promise.reject('Blob has been released.');
281
+ this._closed = true;
282
+ return fs.unlink(this._ref).catch((err) => {
283
+ console.warn(err);
284
+ });
285
+ }
286
+
287
+ safeClose() {
288
+ if (this._closed)
289
+ return Promise.reject('Blob has been released.');
290
+ this._closed = true;
291
+ if (!this._isReference) {
292
+ return fs.unlink(this._ref).catch((err) => {
293
+ console.warn(err);
294
+ });
295
+ }
296
+ else {
297
+ return Promise.resolve();
298
+ }
299
+ }
300
+
301
+ _invokeOnCreateEvent() {
302
+ log.verbose('invoke create event', this._onCreated);
303
+ this._blobCreated = true;
304
+ let fns = this._onCreated;
305
+ for (let i in fns) {
306
+ if (typeof fns[i] === 'function') {
307
+ fns[i](this);
308
+ }
309
+ }
310
+ delete this._onCreated;
311
+ }
312
+
313
+ }
314
+
315
+ /**
316
+ * Get a temp filename for Blob object
317
+ * @return {string} Temporary filename
318
+ */
319
+ function getBlobName() {
320
+ return 'blob-' + getUUID();
321
+ }
322
+
323
+ /**
324
+ * Create a file according to given array. The element in array can be a number,
325
+ * Blob, String, Array.
326
+ * @param {string} ref File path reference
327
+ * @param {Array} dataArray An array contains different types of data.
328
+ * @return {Promise}
329
+ */
330
+ function createMixedBlobData(ref, dataArray) {
331
+ // create an empty file for store blob data
332
+ let p = fs.writeFile(ref, '');
333
+ let args = [];
334
+ let size = 0;
335
+ for (let i in dataArray) {
336
+ let part = dataArray[i];
337
+ if (!part)
338
+ continue;
339
+ if (part.isReactNativeBlobUtilPolyfill) {
340
+ args.push([ref, part._ref, 'uri']);
341
+ }
342
+ else if (typeof part === 'string')
343
+ args.push([ref, part, 'utf8']);
344
+ // TODO : ArrayBuffer
345
+ // else if (part instanceof ArrayBuffer) {
346
+ //
347
+ // }
348
+ else if (Array.isArray(part))
349
+ args.push([ref, part, 'ascii']);
350
+ }
351
+ // start write blob data
352
+ for (let i in args) {
353
+ p = p.then(function (written) {
354
+ let arg = this;
355
+ if (written)
356
+ size += written;
357
+ log.verbose('mixed blob write', args[i], written);
358
+ return fs.appendFile(...arg);
359
+ }.bind(args[i]));
360
+ }
361
+ return p.then(() => Promise.resolve(size));
362
+ }