react-native-blob-util 0.13.17 → 0.14.1

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 (25) hide show
  1. package/README.md +472 -407
  2. package/android/build.gradle +1 -0
  3. package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtil.java +85 -21
  4. package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilBody.java +14 -15
  5. package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilConfig.java +8 -6
  6. package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilFS.java +92 -292
  7. package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilMediaCollection.java +299 -0
  8. package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilPackage.java +6 -2
  9. package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilReq.java +17 -21
  10. package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilStream.java +287 -0
  11. package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilUtils.java +57 -2
  12. package/android/src/main/java/com/ReactNativeBlobUtil/Response/ReactNativeBlobUtilFileResp.java +5 -0
  13. package/android/src/main/java/com/ReactNativeBlobUtil/Utils/FileDescription.java +19 -0
  14. package/android/src/main/java/com/ReactNativeBlobUtil/Utils/MimeType.java +70 -0
  15. package/fs.js +2 -1
  16. package/index.d.ts +107 -2
  17. package/index.js +2 -0
  18. package/ios/ReactNativeBlobUtil/ReactNativeBlobUtil.m +2 -1
  19. package/ios/ReactNativeBlobUtilFS.h +1 -0
  20. package/ios/ReactNativeBlobUtilFS.m +4 -0
  21. package/ios/ReactNativeBlobUtilReqBuilder.m +1 -0
  22. package/mediacollection.js +33 -0
  23. package/package.json +1 -1
  24. package/scripts/prelink.js +1 -1
  25. package/types.js +3 -0
@@ -7,10 +7,8 @@ import android.os.AsyncTask;
7
7
  import android.os.Build;
8
8
  import android.os.Environment;
9
9
  import android.os.StatFs;
10
- import android.os.SystemClock;
11
10
  import android.util.Base64;
12
11
 
13
- import com.ReactNativeBlobUtil.Utils.PathResolver;
14
12
  import com.facebook.react.bridge.Arguments;
15
13
  import com.facebook.react.bridge.Callback;
16
14
  import com.facebook.react.bridge.Promise;
@@ -20,13 +18,18 @@ import com.facebook.react.bridge.WritableArray;
20
18
  import com.facebook.react.bridge.WritableMap;
21
19
  import com.facebook.react.modules.core.DeviceEventManagerModule;
22
20
 
23
- import java.io.*;
24
- import java.nio.charset.Charset;
21
+ import java.io.File;
22
+ import java.io.FileInputStream;
23
+ import java.io.FileNotFoundException;
24
+ import java.io.FileOutputStream;
25
+ import java.io.IOException;
26
+ import java.io.InputStream;
27
+ import java.io.OutputStream;
25
28
  import java.security.MessageDigest;
26
29
  import java.util.ArrayList;
27
30
  import java.util.HashMap;
31
+ import java.util.Locale;
28
32
  import java.util.Map;
29
- import java.util.UUID;
30
33
 
31
34
  class ReactNativeBlobUtilFS {
32
35
 
@@ -41,6 +44,75 @@ class ReactNativeBlobUtilFS {
41
44
  this.emitter = ctx.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class);
42
45
  }
43
46
 
47
+ /**
48
+ * Write string with encoding to file (used for mediastore)
49
+ *
50
+ * @param path Destination file path.
51
+ * @param encoding Encoding of the string.
52
+ * @param data Array passed from JS context.
53
+ */
54
+ static boolean writeFile(String path, String encoding, String data, final boolean append) {
55
+ try {
56
+ int written;
57
+ File f = new File(path);
58
+ File dir = f.getParentFile();
59
+ if (!f.exists()) {
60
+ if (dir != null && !dir.exists()) {
61
+ if (!dir.mkdirs() && !dir.exists()) {
62
+ return false;
63
+ }
64
+ }
65
+ if (!f.createNewFile()) {
66
+ return false;
67
+ }
68
+ }
69
+
70
+ // write data from a file
71
+ if (encoding.equalsIgnoreCase(ReactNativeBlobUtilConst.DATA_ENCODE_URI)) {
72
+ String normalizedData = ReactNativeBlobUtilUtils.normalizePath(data);
73
+ File src = new File(normalizedData);
74
+ if (!src.exists()) {
75
+ return false;
76
+ }
77
+ byte[] buffer = new byte[10240];
78
+ int read;
79
+ written = 0;
80
+ FileInputStream fin = null;
81
+ FileOutputStream fout = null;
82
+ try {
83
+ fin = new FileInputStream(src);
84
+ fout = new FileOutputStream(f, append);
85
+ while ((read = fin.read(buffer)) > 0) {
86
+ fout.write(buffer, 0, read);
87
+ written += read;
88
+ }
89
+ } finally {
90
+ if (fin != null) {
91
+ fin.close();
92
+ }
93
+ if (fout != null) {
94
+ fout.close();
95
+ }
96
+ }
97
+ } else {
98
+ byte[] bytes = ReactNativeBlobUtilUtils.stringToBytes(data, encoding);
99
+ FileOutputStream fout = new FileOutputStream(f, append);
100
+ try {
101
+ fout.write(bytes);
102
+ written = bytes.length;
103
+ } finally {
104
+ fout.close();
105
+ }
106
+ }
107
+ return true;
108
+ } catch (FileNotFoundException e) {
109
+ // According to https://docs.oracle.com/javase/7/docs/api/java/io/FileOutputStream.html
110
+ return false;
111
+ } catch (Exception e) {
112
+ return false;
113
+ }
114
+ }
115
+
44
116
  /**
45
117
  * Write string with encoding to file
46
118
  *
@@ -54,10 +126,9 @@ class ReactNativeBlobUtilFS {
54
126
  int written;
55
127
  File f = new File(path);
56
128
  File dir = f.getParentFile();
57
-
58
129
  if (!f.exists()) {
59
130
  if (dir != null && !dir.exists()) {
60
- if (!dir.mkdirs()) {
131
+ if (!dir.mkdirs() && !dir.exists()) {
61
132
  promise.reject("EUNSPECIFIED", "Failed to create parent directory of '" + path + "'");
62
133
  return;
63
134
  }
@@ -70,7 +141,7 @@ class ReactNativeBlobUtilFS {
70
141
 
71
142
  // write data from a file
72
143
  if (encoding.equalsIgnoreCase(ReactNativeBlobUtilConst.DATA_ENCODE_URI)) {
73
- String normalizedData = normalizePath(data);
144
+ String normalizedData = ReactNativeBlobUtilUtils.normalizePath(data);
74
145
  File src = new File(normalizedData);
75
146
  if (!src.exists()) {
76
147
  promise.reject("ENOENT", "No such file '" + path + "' " + "('" + normalizedData + "')");
@@ -97,7 +168,7 @@ class ReactNativeBlobUtilFS {
97
168
  }
98
169
  }
99
170
  } else {
100
- byte[] bytes = stringToBytes(data, encoding);
171
+ byte[] bytes = ReactNativeBlobUtilUtils.stringToBytes(data, encoding);
101
172
  FileOutputStream fout = new FileOutputStream(f, append);
102
173
  try {
103
174
  fout.write(bytes);
@@ -129,7 +200,7 @@ class ReactNativeBlobUtilFS {
129
200
 
130
201
  if (!f.exists()) {
131
202
  if (dir != null && !dir.exists()) {
132
- if (!dir.mkdirs()) {
203
+ if (!dir.mkdirs() && !dir.exists()) {
133
204
  promise.reject("ENOTDIR", "Failed to create parent directory of '" + path + "'");
134
205
  return;
135
206
  }
@@ -167,7 +238,7 @@ class ReactNativeBlobUtilFS {
167
238
  * @param promise JS promise
168
239
  */
169
240
  static void readFile(String path, String encoding, final Promise promise) {
170
- String resolved = normalizePath(path);
241
+ String resolved = ReactNativeBlobUtilUtils.normalizePath(path);
171
242
  if (resolved != null)
172
243
  path = resolved;
173
244
  try {
@@ -209,7 +280,7 @@ class ReactNativeBlobUtilFS {
209
280
  return;
210
281
  }
211
282
 
212
- switch (encoding.toLowerCase()) {
283
+ switch (encoding.toLowerCase(Locale.ROOT)) {
213
284
  case "base64":
214
285
  promise.resolve(Base64.encodeToString(bytes, Base64.NO_WRAP));
215
286
  break;
@@ -329,205 +400,6 @@ class ReactNativeBlobUtilFS {
329
400
  return ReactNativeBlobUtil.RCTContext.getFilesDir() + "/ReactNativeBlobUtilTmp_" + taskId;
330
401
  }
331
402
 
332
- /**
333
- * Create a file stream for read
334
- *
335
- * @param path File stream target path
336
- * @param encoding File stream decoder, should be one of `base64`, `utf8`, `ascii`
337
- * @param bufferSize Buffer size of read stream, default to 4096 (4095 when encode is `base64`)
338
- */
339
- void readStream(String path, String encoding, int bufferSize, int tick, final String streamId) {
340
- String resolved = normalizePath(path);
341
- if (resolved != null)
342
- path = resolved;
343
-
344
- try {
345
- int chunkSize = encoding.equalsIgnoreCase("base64") ? 4095 : 4096;
346
- if (bufferSize > 0)
347
- chunkSize = bufferSize;
348
-
349
- InputStream fs;
350
-
351
- if (resolved != null && path.startsWith(ReactNativeBlobUtilConst.FILE_PREFIX_BUNDLE_ASSET)) {
352
- fs = ReactNativeBlobUtil.RCTContext.getAssets().open(path.replace(ReactNativeBlobUtilConst.FILE_PREFIX_BUNDLE_ASSET, ""));
353
- }
354
- // fix issue 287
355
- else if (resolved == null) {
356
- fs = ReactNativeBlobUtil.RCTContext.getContentResolver().openInputStream(Uri.parse(path));
357
- } else {
358
- fs = new FileInputStream(new File(path));
359
- }
360
-
361
- int cursor = 0;
362
- boolean error = false;
363
-
364
- if (encoding.equalsIgnoreCase("utf8")) {
365
- InputStreamReader isr = new InputStreamReader(fs, Charset.forName("UTF-8"));
366
- BufferedReader reader = new BufferedReader(isr, chunkSize);
367
- char[] buffer = new char[chunkSize];
368
- // read chunks of the string
369
- while (reader.read(buffer, 0, chunkSize) != -1) {
370
- String chunk = new String(buffer);
371
- emitStreamEvent(streamId, "data", chunk);
372
- if (tick > 0)
373
- SystemClock.sleep(tick);
374
- }
375
-
376
- reader.close();
377
- isr.close();
378
- } else if (encoding.equalsIgnoreCase("ascii")) {
379
- byte[] buffer = new byte[chunkSize];
380
- while ((cursor = fs.read(buffer)) != -1) {
381
- WritableArray chunk = Arguments.createArray();
382
- for (int i = 0; i < cursor; i++) {
383
- chunk.pushInt((int) buffer[i]);
384
- }
385
- emitStreamEvent(streamId, "data", chunk);
386
- if (tick > 0)
387
- SystemClock.sleep(tick);
388
- }
389
- } else if (encoding.equalsIgnoreCase("base64")) {
390
- byte[] buffer = new byte[chunkSize];
391
- while ((cursor = fs.read(buffer)) != -1) {
392
- if (cursor < chunkSize) {
393
- byte[] copy = new byte[cursor];
394
- System.arraycopy(buffer, 0, copy, 0, cursor);
395
- emitStreamEvent(streamId, "data", Base64.encodeToString(copy, Base64.NO_WRAP));
396
- } else
397
- emitStreamEvent(streamId, "data", Base64.encodeToString(buffer, Base64.NO_WRAP));
398
- if (tick > 0)
399
- SystemClock.sleep(tick);
400
- }
401
- } else {
402
- emitStreamEvent(
403
- streamId,
404
- "error",
405
- "EINVAL",
406
- "Unrecognized encoding `" + encoding + "`, should be one of `base64`, `utf8`, `ascii`"
407
- );
408
- error = true;
409
- }
410
-
411
- if (!error)
412
- emitStreamEvent(streamId, "end", "");
413
- fs.close();
414
-
415
- } catch (FileNotFoundException err) {
416
- emitStreamEvent(
417
- streamId,
418
- "error",
419
- "ENOENT",
420
- "No such file '" + path + "'"
421
- );
422
- } catch (Exception err) {
423
- emitStreamEvent(
424
- streamId,
425
- "error",
426
- "EUNSPECIFIED",
427
- "Failed to convert data to " + encoding + " encoded string. This might be because this encoding cannot be used for this data."
428
- );
429
- err.printStackTrace();
430
- }
431
- }
432
-
433
- /**
434
- * Create a write stream and store its instance in ReactNativeBlobUtilFS.fileStreams
435
- *
436
- * @param path Target file path
437
- * @param encoding Should be one of `base64`, `utf8`, `ascii`
438
- * @param append Flag represents if the file stream overwrite existing content
439
- * @param callback Callback
440
- */
441
- void writeStream(String path, String encoding, boolean append, Callback callback) {
442
- try {
443
- File dest = new File(path);
444
- File dir = dest.getParentFile();
445
-
446
- if (!dest.exists()) {
447
- if (dir != null && !dir.exists()) {
448
- if (!dir.mkdirs()) {
449
- callback.invoke("ENOTDIR", "Failed to create parent directory of '" + path + "'");
450
- return;
451
- }
452
- }
453
- if (!dest.createNewFile()) {
454
- callback.invoke("ENOENT", "File '" + path + "' does not exist and could not be created");
455
- return;
456
- }
457
- } else if (dest.isDirectory()) {
458
- callback.invoke("EISDIR", "Expecting a file but '" + path + "' is a directory");
459
- return;
460
- }
461
-
462
- OutputStream fs = new FileOutputStream(path, append);
463
- this.encoding = encoding;
464
- String streamId = UUID.randomUUID().toString();
465
- ReactNativeBlobUtilFS.fileStreams.put(streamId, this);
466
- this.writeStreamInstance = fs;
467
- callback.invoke(null, null, streamId);
468
- } catch (Exception err) {
469
- callback.invoke("EUNSPECIFIED", "Failed to create write stream at path `" + path + "`; " + err.getLocalizedMessage());
470
- }
471
- }
472
-
473
- /**
474
- * Write a chunk of data into a file stream.
475
- *
476
- * @param streamId File stream ID
477
- * @param data Data chunk in string format
478
- * @param callback JS context callback
479
- */
480
- static void writeChunk(String streamId, String data, Callback callback) {
481
- ReactNativeBlobUtilFS fs = fileStreams.get(streamId);
482
- OutputStream stream = fs.writeStreamInstance;
483
- byte[] chunk = ReactNativeBlobUtilFS.stringToBytes(data, fs.encoding);
484
- try {
485
- stream.write(chunk);
486
- callback.invoke();
487
- } catch (Exception e) {
488
- callback.invoke(e.getLocalizedMessage());
489
- }
490
- }
491
-
492
- /**
493
- * Write data using ascii array
494
- *
495
- * @param streamId File stream ID
496
- * @param data Data chunk in ascii array format
497
- * @param callback JS context callback
498
- */
499
- static void writeArrayChunk(String streamId, ReadableArray data, Callback callback) {
500
- try {
501
- ReactNativeBlobUtilFS fs = fileStreams.get(streamId);
502
- OutputStream stream = fs.writeStreamInstance;
503
- byte[] chunk = new byte[data.size()];
504
- for (int i = 0; i < data.size(); i++) {
505
- chunk[i] = (byte) data.getInt(i);
506
- }
507
- stream.write(chunk);
508
- callback.invoke();
509
- } catch (Exception e) {
510
- callback.invoke(e.getLocalizedMessage());
511
- }
512
- }
513
-
514
- /**
515
- * Close file write stream by ID
516
- *
517
- * @param streamId Stream ID
518
- * @param callback JS context callback
519
- */
520
- static void closeStream(String streamId, Callback callback) {
521
- try {
522
- ReactNativeBlobUtilFS fs = fileStreams.get(streamId);
523
- OutputStream stream = fs.writeStreamInstance;
524
- fileStreams.remove(streamId);
525
- stream.close();
526
- callback.invoke();
527
- } catch (Exception err) {
528
- callback.invoke(err.getLocalizedMessage());
529
- }
530
- }
531
403
 
532
404
  /**
533
405
  * Unlink file at path
@@ -537,7 +409,7 @@ class ReactNativeBlobUtilFS {
537
409
  */
538
410
  static void unlink(String path, Callback callback) {
539
411
  try {
540
- String normalizedPath = normalizePath(path);
412
+ String normalizedPath = ReactNativeBlobUtilUtils.normalizePath(path);
541
413
  ReactNativeBlobUtilFS.deleteRecursive(new File(normalizedPath));
542
414
  callback.invoke(null, true);
543
415
  } catch (Exception err) {
@@ -595,7 +467,7 @@ class ReactNativeBlobUtilFS {
595
467
  * @param callback JS context callback
596
468
  */
597
469
  static void cp(String path, String dest, Callback callback) {
598
- path = normalizePath(path);
470
+ path = ReactNativeBlobUtilUtils.normalizePath(path);
599
471
  InputStream in = null;
600
472
  OutputStream out = null;
601
473
  String message = "";
@@ -700,7 +572,7 @@ class ReactNativeBlobUtilFS {
700
572
  callback.invoke(false, false);
701
573
  }
702
574
  } else {
703
- path = normalizePath(path);
575
+ path = ReactNativeBlobUtilUtils.normalizePath(path);
704
576
  if (path != null) {
705
577
  boolean exist = new File(path).exists();
706
578
  boolean isDir = new File(path).isDirectory();
@@ -719,7 +591,7 @@ class ReactNativeBlobUtilFS {
719
591
  */
720
592
  static void ls(String path, Promise promise) {
721
593
  try {
722
- path = normalizePath(path);
594
+ path = ReactNativeBlobUtilUtils.normalizePath(path);
723
595
  File src = new File(path);
724
596
  if (!src.exists()) {
725
597
  promise.reject("ENOENT", "No such file '" + path + "'");
@@ -754,7 +626,7 @@ class ReactNativeBlobUtilFS {
754
626
  */
755
627
  static void slice(String path, String dest, int start, int end, String encode, Promise promise) {
756
628
  try {
757
- path = normalizePath(path);
629
+ path = ReactNativeBlobUtilUtils.normalizePath(path);
758
630
  File source = new File(path);
759
631
  if (source.isDirectory()) {
760
632
  promise.reject("EISDIR", "Expecting a file but '" + path + "' is a directory");
@@ -796,7 +668,7 @@ class ReactNativeBlobUtilFS {
796
668
  }
797
669
 
798
670
  static void lstat(String path, final Callback callback) {
799
- path = normalizePath(path);
671
+ path = ReactNativeBlobUtilUtils.normalizePath(path);
800
672
 
801
673
  new AsyncTask<String, Integer, Integer>() {
802
674
  @Override
@@ -835,7 +707,7 @@ class ReactNativeBlobUtilFS {
835
707
  */
836
708
  static void stat(String path, Callback callback) {
837
709
  try {
838
- path = normalizePath(path);
710
+ path = ReactNativeBlobUtilUtils.normalizePath(path);
839
711
  WritableMap result = statFile(path);
840
712
  if (result == null)
841
713
  callback.invoke("failed to stat path `" + path + "` because it does not exist or it is not a folder", null);
@@ -854,7 +726,7 @@ class ReactNativeBlobUtilFS {
854
726
  */
855
727
  static WritableMap statFile(String path) {
856
728
  try {
857
- path = normalizePath(path);
729
+ path = ReactNativeBlobUtilUtils.normalizePath(path);
858
730
  WritableMap stat = Arguments.createMap();
859
731
  if (isAsset(path)) {
860
732
  String name = path.replace(ReactNativeBlobUtilConst.FILE_PREFIX_BUNDLE_ASSET, "");
@@ -990,7 +862,7 @@ class ReactNativeBlobUtilFS {
990
862
  return;
991
863
  }
992
864
  OutputStream ostream = new FileOutputStream(dest);
993
- ostream.write(ReactNativeBlobUtilFS.stringToBytes(data, encoding));
865
+ ostream.write(ReactNativeBlobUtilUtils.stringToBytes(data, encoding));
994
866
  }
995
867
  promise.resolve(path);
996
868
  } catch (Exception err) {
@@ -1085,56 +957,6 @@ class ReactNativeBlobUtilFS {
1085
957
  task.execute(paths);
1086
958
  }
1087
959
 
1088
- /**
1089
- * String to byte converter method
1090
- *
1091
- * @param data Raw data in string format
1092
- * @param encoding Decoder name
1093
- * @return Converted data byte array
1094
- */
1095
- private static byte[] stringToBytes(String data, String encoding) {
1096
- if (encoding.equalsIgnoreCase("ascii")) {
1097
- return data.getBytes(Charset.forName("US-ASCII"));
1098
- } else if (encoding.toLowerCase().contains("base64")) {
1099
- return Base64.decode(data, Base64.NO_WRAP);
1100
-
1101
- } else if (encoding.equalsIgnoreCase("utf8")) {
1102
- return data.getBytes(Charset.forName("UTF-8"));
1103
- }
1104
- return data.getBytes(Charset.forName("US-ASCII"));
1105
- }
1106
-
1107
- /**
1108
- * Private method for emit read stream event.
1109
- *
1110
- * @param streamName ID of the read stream
1111
- * @param event Event name, `data`, `end`, `error`, etc.
1112
- * @param data Event data
1113
- */
1114
- private void emitStreamEvent(String streamName, String event, String data) {
1115
- WritableMap eventData = Arguments.createMap();
1116
- eventData.putString("event", event);
1117
- eventData.putString("detail", data);
1118
- this.emitter.emit(streamName, eventData);
1119
- }
1120
-
1121
- // "event" always is "data"...
1122
- private void emitStreamEvent(String streamName, String event, WritableArray data) {
1123
- WritableMap eventData = Arguments.createMap();
1124
- eventData.putString("event", event);
1125
- eventData.putArray("detail", data);
1126
- this.emitter.emit(streamName, eventData);
1127
- }
1128
-
1129
- // "event" always is "error"...
1130
- private void emitStreamEvent(String streamName, String event, String code, String message) {
1131
- WritableMap eventData = Arguments.createMap();
1132
- eventData.putString("event", event);
1133
- eventData.putString("code", code);
1134
- eventData.putString("detail", message);
1135
- this.emitter.emit(streamName, eventData);
1136
- }
1137
-
1138
960
  /**
1139
961
  * Get input stream of the given path, when the path is a string starts with bundle-assets://
1140
962
  * the stream is created by Assets Manager, otherwise use FileInputStream.
@@ -1174,26 +996,4 @@ class ReactNativeBlobUtilFS {
1174
996
  return path != null && path.startsWith(ReactNativeBlobUtilConst.FILE_PREFIX_BUNDLE_ASSET);
1175
997
  }
1176
998
 
1177
- /**
1178
- * Normalize the path, remove URI scheme (xxx://) so that we can handle it.
1179
- *
1180
- * @param path URI string.
1181
- * @return Normalized string
1182
- */
1183
- static String normalizePath(String path) {
1184
- if (path == null)
1185
- return null;
1186
- if (!path.matches("\\w+\\:.*"))
1187
- return path;
1188
- if (path.startsWith("file://")) {
1189
- return path.replace("file://", "");
1190
- }
1191
-
1192
- Uri uri = Uri.parse(path);
1193
- if (path.startsWith(ReactNativeBlobUtilConst.FILE_PREFIX_BUNDLE_ASSET)) {
1194
- return path;
1195
- } else
1196
- return PathResolver.getRealPathFromURI(ReactNativeBlobUtil.RCTContext, uri);
1197
- }
1198
-
1199
999
  }