react-native-blob-util 0.14.0 → 0.16.0

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 (29) hide show
  1. package/README.md +100 -0
  2. package/android/src/main/AndroidManifest.xml +0 -3
  3. package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtil.java +11 -12
  4. package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilBody.java +30 -6
  5. package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilConfig.java +2 -0
  6. package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilFS.java +94 -3
  7. package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilFileTransformer.java +10 -0
  8. package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilMediaCollection.java +123 -87
  9. package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilReq.java +99 -1
  10. package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilUtils.java +5 -17
  11. package/android/src/main/java/com/ReactNativeBlobUtil/Response/ReactNativeBlobUtilFileResp.java +4 -0
  12. package/class/ReactNativeBlobUtilBlobResponse.js +1 -1
  13. package/fs.js +42 -3
  14. package/index.d.ts +30 -1
  15. package/ios/ReactNativeBlobUtil/ReactNativeBlobUtil.m +4 -3
  16. package/ios/ReactNativeBlobUtil.xcodeproj/project.pbxproj +6 -2
  17. package/ios/ReactNativeBlobUtilConst.h +1 -0
  18. package/ios/ReactNativeBlobUtilConst.m +1 -0
  19. package/ios/ReactNativeBlobUtilFS.h +2 -1
  20. package/ios/ReactNativeBlobUtilFS.m +30 -2
  21. package/ios/ReactNativeBlobUtilFileTransformer.h +24 -0
  22. package/ios/ReactNativeBlobUtilFileTransformer.m +21 -0
  23. package/ios/ReactNativeBlobUtilReqBuilder.m +3 -4
  24. package/ios/ReactNativeBlobUtilRequest.m +35 -7
  25. package/mediacollection.js +6 -1
  26. package/package.json +1 -1
  27. package/polyfill/Fetch.js +4 -2
  28. package/types.js +1 -0
  29. package/ios/IOS7Polyfill.h +0 -27
@@ -10,11 +10,10 @@ import android.os.ParcelFileDescriptor;
10
10
  import android.provider.MediaStore;
11
11
  import android.util.Base64;
12
12
 
13
- import androidx.annotation.RequiresApi;
14
-
15
13
  import com.ReactNativeBlobUtil.Utils.FileDescription;
16
14
  import com.facebook.react.bridge.Arguments;
17
15
  import com.facebook.react.bridge.Promise;
16
+ import com.facebook.react.bridge.ReactApplicationContext;
18
17
  import com.facebook.react.bridge.WritableArray;
19
18
 
20
19
  import java.io.File;
@@ -62,21 +61,29 @@ public class ReactNativeBlobUtilMediaCollection {
62
61
  return res;
63
62
  }
64
63
 
65
- private static String getRelativePath(MediaType mt) {
66
- if (mt == MediaType.Audio) return Environment.DIRECTORY_MUSIC;
67
- if (mt == MediaType.Video) return Environment.DIRECTORY_MOVIES;
68
- if (mt == MediaType.Image) return Environment.DIRECTORY_PICTURES;
69
- if (mt == MediaType.Download) return Environment.DIRECTORY_DOWNLOADS;
70
- return Environment.DIRECTORY_DOWNLOADS;
64
+ private static String getRelativePath(MediaType mt, ReactApplicationContext ctx) {
65
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
66
+ if (mt == MediaType.Audio) return Environment.DIRECTORY_MUSIC;
67
+ if (mt == MediaType.Video) return Environment.DIRECTORY_MOVIES;
68
+ if (mt == MediaType.Image) return Environment.DIRECTORY_PICTURES;
69
+ if (mt == MediaType.Download) return Environment.DIRECTORY_DOWNLOADS;
70
+ return Environment.DIRECTORY_DOWNLOADS;
71
+ } else {
72
+ if (mt == MediaType.Audio) return ReactNativeBlobUtilFS.getExternalFilesDirPath(ctx, Environment.DIRECTORY_MUSIC);
73
+ if (mt == MediaType.Video) return ReactNativeBlobUtilFS.getExternalFilesDirPath(ctx, Environment.DIRECTORY_MOVIES);
74
+ if (mt == MediaType.Image) return ReactNativeBlobUtilFS.getExternalFilesDirPath(ctx, Environment.DIRECTORY_PICTURES);
75
+ if (mt == MediaType.Download) return ReactNativeBlobUtilFS.getExternalFilesDirPath(ctx, Environment.DIRECTORY_DOWNLOADS);
76
+ return ReactNativeBlobUtilFS.getExternalFilesDirPath(ctx, Environment.DIRECTORY_DOWNLOADS);
77
+ }
71
78
  }
72
79
 
73
- public static Uri createNewMediaFile(FileDescription file, MediaType mt) {
80
+ public static Uri createNewMediaFile(FileDescription file, MediaType mt, ReactApplicationContext ctx) {
74
81
  // Add a specific media item.
75
82
  Context appCtx = ReactNativeBlobUtil.RCTContext.getApplicationContext();
76
83
  ContentResolver resolver = appCtx.getContentResolver();
77
84
 
78
85
  ContentValues fileDetails = new ContentValues();
79
- String relativePath = getRelativePath(mt);
86
+ String relativePath = getRelativePath(mt, ctx);
80
87
  String mimeType = file.mimeType;
81
88
 
82
89
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
@@ -91,12 +98,24 @@ public class ReactNativeBlobUtilMediaCollection {
91
98
  // Keeps a handle to the new file's URI in case we need to modify it later.
92
99
  return resolver.insert(mediauri, fileDetails);
93
100
  } else {
94
- File directory = Environment.getExternalStoragePublicDirectory(relativePath);
95
- if (directory.canWrite()) {
96
- File f = new File(relativePath + '/' + file.getFullPath());
101
+ File f = new File(relativePath + file.getFullPath());
102
+ if (true) {
97
103
  if (!f.exists()) {
98
- boolean result = f.mkdirs();
99
- if (result) return Uri.fromFile(f);
104
+ File parent = f.getParentFile();
105
+ if (parent != null && !parent.exists() && !parent.mkdirs()) {
106
+ return null;
107
+ }
108
+ try {
109
+ if (f.createNewFile()) ;
110
+ {
111
+ return Uri.fromFile(f);
112
+ }
113
+ } catch (IOException ioException) {
114
+ return null;
115
+ }
116
+
117
+ } else {
118
+ return Uri.fromFile(f);
100
119
  }
101
120
 
102
121
  }
@@ -105,83 +124,99 @@ public class ReactNativeBlobUtilMediaCollection {
105
124
  return null;
106
125
  }
107
126
 
108
- @RequiresApi(api = Build.VERSION_CODES.Q)
109
- public static boolean writeToMediaFile(Uri fileUri, String data, Promise promise) {
110
- try {
111
- Context appCtx = ReactNativeBlobUtil.RCTContext.getApplicationContext();
112
- ContentResolver resolver = appCtx.getContentResolver();
127
+ public static boolean writeToMediaFile(Uri fileUri, String data, boolean transformFile, Promise promise) {
128
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
129
+ try {
130
+ Context appCtx = ReactNativeBlobUtil.RCTContext.getApplicationContext();
131
+ ContentResolver resolver = appCtx.getContentResolver();
113
132
 
114
- // set pending
115
- ContentValues contentValues = new ContentValues();
116
- contentValues.put(MediaStore.MediaColumns.IS_PENDING, 1);
117
- resolver.update(fileUri, contentValues, null, null);
133
+ // set pending doesn't work right now. We would have to requery for the item
134
+ //ContentValues contentValues = new ContentValues();
135
+ //contentValues.put(MediaStore.MediaColumns.IS_PENDING, 1);
136
+ //resolver.update(fileUri, contentValues, null, null);
118
137
 
119
- // write data
120
- OutputStream stream = null;
121
- Uri uri = null;
138
+ // write data
139
+ OutputStream stream = null;
140
+ Uri uri = null;
122
141
 
123
- try {
124
- ParcelFileDescriptor descr;
125
142
  try {
126
- assert fileUri != null;
127
- descr = appCtx.getContentResolver().openFileDescriptor(fileUri, "w");
128
- assert descr != null;
129
- String normalizedData = ReactNativeBlobUtilUtils.normalizePath(data);
130
- File src = new File(normalizedData);
131
- if (!src.exists()) {
132
- promise.reject("ENOENT", "No such file ('" + normalizedData + "')");
143
+ ParcelFileDescriptor descr;
144
+ try {
145
+ assert fileUri != null;
146
+ descr = appCtx.getContentResolver().openFileDescriptor(fileUri, "w");
147
+ assert descr != null;
148
+ String normalizedData = ReactNativeBlobUtilUtils.normalizePath(data);
149
+ File src = new File(normalizedData);
150
+ if (!src.exists()) {
151
+ promise.reject("ENOENT", "No such file ('" + normalizedData + "')");
152
+ return false;
153
+ }
154
+
155
+
156
+ FileInputStream fin = new FileInputStream(src);
157
+ FileOutputStream out = new FileOutputStream(descr.getFileDescriptor());
158
+
159
+ if (transformFile) {
160
+ // in order to transform file, we must load the entire file onto memory
161
+ int length = (int) src.length();
162
+ byte[] bytes = new byte[length];
163
+ fin.read(bytes);
164
+ if (ReactNativeBlobUtilFileTransformer.sharedFileTransformer == null) {
165
+ throw new IllegalStateException("Write to media file with transform was specified but the shared file transformer is not set");
166
+ }
167
+ byte[] transformedBytes = ReactNativeBlobUtilFileTransformer.sharedFileTransformer.onWriteFile(bytes);
168
+ out.write(transformedBytes);
169
+ } else {
170
+ byte[] buf = new byte[10240];
171
+ int read;
172
+
173
+ while ((read = fin.read(buf)) > 0) {
174
+ out.write(buf, 0, read);
175
+ }
176
+ }
177
+
178
+
179
+ fin.close();
180
+ out.close();
181
+ descr.close();
182
+ } catch (Exception e) {
183
+ e.printStackTrace();
184
+ promise.reject(new IOException("Failed to get output stream."));
133
185
  return false;
134
186
  }
135
- byte[] buf = new byte[10240];
136
- int read;
137
- int written = 0;
138
-
139
- FileInputStream fin = new FileInputStream(src);
140
- FileOutputStream out = new FileOutputStream(descr.getFileDescriptor());
141
187
 
142
- while ((read = fin.read(buf)) > 0) {
143
- out.write(buf, 0, read);
188
+ //contentValues.clear();
189
+ //contentValues.put(MediaStore.Video.Media.IS_PENDING, 0);
190
+ //appCtx.getContentResolver().update(fileUri, contentValues, null, null);
191
+ stream = resolver.openOutputStream(fileUri);
192
+ if (stream == null) {
193
+ promise.reject(new IOException("Failed to get output stream."));
194
+ return false;
144
195
  }
145
-
146
- fin.close();
147
- out.close();
148
- descr.close();
149
- } catch (Exception e) {
150
- e.printStackTrace();
151
- promise.reject(new IOException("Failed to get output stream."));
196
+ } catch (IOException e) {
197
+ // Don't leave an orphan entry in the MediaStore
198
+ resolver.delete(uri, null, null);
199
+ promise.reject(e);
152
200
  return false;
201
+ } finally {
202
+ if (stream != null) {
203
+ stream.close();
204
+ }
153
205
  }
154
206
 
155
- contentValues.clear();
156
- contentValues.put(MediaStore.Video.Media.IS_PENDING, 0);
157
- appCtx.getContentResolver().update(fileUri, contentValues, null, null);
158
- stream = resolver.openOutputStream(fileUri);
159
- if (stream == null) {
160
- promise.reject(new IOException("Failed to get output stream."));
161
- return false;
162
- }
207
+ // remove pending
208
+ //contentValues = new ContentValues();
209
+ //contentValues.put(MediaStore.MediaColumns.IS_PENDING, 0);
210
+ //resolver.update(fileUri, contentValues, null, null);
211
+
163
212
  } catch (IOException e) {
164
- // Don't leave an orphan entry in the MediaStore
165
- resolver.delete(uri, null, null);
166
- promise.reject(e);
213
+ promise.reject("ReactNativeBlobUtil.createMediaFile", "Cannot write to file, file might not exist");
167
214
  return false;
168
- } finally {
169
- if (stream != null) {
170
- stream.close();
171
- return true;
172
- }
173
215
  }
174
-
175
- // remove pending
176
- contentValues = new ContentValues();
177
- contentValues.put(MediaStore.MediaColumns.IS_PENDING, 0);
178
- resolver.update(fileUri, contentValues, null, null);
179
-
180
- } catch (IOException e) {
181
- promise.reject("ReactNativeBlobUtil.createMediaFile", "Cannot write to file, file might not exist");
182
- return false;
216
+ return true;
217
+ } else {
218
+ return ReactNativeBlobUtilFS.writeFile(ReactNativeBlobUtilUtils.normalizePath(fileUri.toString()), ReactNativeBlobUtilConst.DATA_ENCODE_URI, data, false);
183
219
  }
184
- return true;
185
220
  }
186
221
 
187
222
  public static void copyToInternal(Uri contenturi, String destpath, Promise promise) {
@@ -190,10 +225,16 @@ public class ReactNativeBlobUtilMediaCollection {
190
225
 
191
226
  InputStream in = null;
192
227
  OutputStream out = null;
228
+ File f = new File((destpath));
193
229
 
194
- if (!new File(destpath).exists()) {
230
+ if (!f.exists()) {
195
231
  try {
196
- boolean result = new File(destpath).createNewFile();
232
+ File parent = f.getParentFile();
233
+ if (parent != null && !parent.exists() && !parent.mkdirs()) {
234
+ promise.reject("ReactNativeBlobUtil.copyToInternal: Cannot create parent folders<'" + destpath);
235
+ return;
236
+ }
237
+ boolean result = f.createNewFile();
197
238
  if (!result) {
198
239
  promise.reject("ReactNativeBlobUtil.copyToInternal: Destination file at '" + destpath + "' already exists");
199
240
  return;
@@ -240,9 +281,7 @@ public class ReactNativeBlobUtilMediaCollection {
240
281
  ContentResolver resolver = appCtx.getContentResolver();
241
282
  try {
242
283
  InputStream in = resolver.openInputStream(contentUri);
243
- int length = 0;
244
-
245
- length = in.available();
284
+ int length = in.available();
246
285
 
247
286
  byte[] bytes = new byte[length];
248
287
  int bytesRead = in.read(bytes);
@@ -260,14 +299,11 @@ public class ReactNativeBlobUtilMediaCollection {
260
299
  case "ascii":
261
300
  WritableArray asciiResult = Arguments.createArray();
262
301
  for (byte b : bytes) {
263
- asciiResult.pushInt((int) b);
302
+ asciiResult.pushInt(b);
264
303
  }
265
304
  promise.resolve(asciiResult);
266
305
  break;
267
- case "utf8":
268
- promise.resolve(new String(bytes));
269
- break;
270
- default:
306
+ default: // covers utf-8
271
307
  promise.resolve(new String(bytes));
272
308
  break;
273
309
  }
@@ -12,6 +12,9 @@ import android.net.NetworkCapabilities;
12
12
  import android.net.NetworkInfo;
13
13
  import android.net.Uri;
14
14
  import android.os.Build;
15
+ import android.os.Bundle;
16
+ import android.os.Handler;
17
+ import android.os.Message;
15
18
  import android.util.Base64;
16
19
  import android.webkit.CookieManager;
17
20
 
@@ -48,6 +51,9 @@ import java.util.HashMap;
48
51
 
49
52
  import java.util.List;
50
53
  import java.util.Locale;
54
+ import java.util.concurrent.Executors;
55
+ import java.util.concurrent.Future;
56
+ import java.util.concurrent.ScheduledExecutorService;
51
57
  import java.util.concurrent.TimeUnit;
52
58
 
53
59
  import javax.net.ssl.SSLContext;
@@ -87,6 +93,12 @@ public class ReactNativeBlobUtilReq extends BroadcastReceiver implements Runnabl
87
93
  BASE64
88
94
  }
89
95
 
96
+ private boolean shouldTransformFile() {
97
+ return this.options.transformFile &&
98
+ // Can only process if it's written to a file
99
+ (this.options.fileCache || this.options.path != null);
100
+ }
101
+
90
102
  public static HashMap<String, Call> taskTable = new HashMap<>();
91
103
  public static HashMap<String, Long> androidDownloadManagerTaskTable = new HashMap<>();
92
104
  static HashMap<String, ReactNativeBlobUtilProgressConfig> progressReport = new HashMap<>();
@@ -124,7 +136,9 @@ public class ReactNativeBlobUtilReq extends BroadcastReceiver implements Runnabl
124
136
  this.rawRequestBodyArray = arrayBody;
125
137
  this.client = client;
126
138
 
127
- if (this.options.fileCache || this.options.path != null)
139
+ // If transformFile is specified, we first want to get the response back in memory so we can
140
+ // encrypt it wholesale and at that point, write it into the file storage.
141
+ if((this.options.fileCache || this.options.path != null) && !this.shouldTransformFile())
128
142
  responseType = ResponseType.FileStorage;
129
143
  else
130
144
  responseType = ResponseType.KeepInMemory;
@@ -153,6 +167,59 @@ public class ReactNativeBlobUtilReq extends BroadcastReceiver implements Runnabl
153
167
  }
154
168
  }
155
169
 
170
+ private final int QUERY = 1314;
171
+ private ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
172
+ private Future<?> future;
173
+ private Handler mHandler = new Handler(new Handler.Callback() {
174
+ public boolean handleMessage(Message msg) {
175
+ switch (msg.what) {
176
+
177
+ case QUERY:
178
+
179
+ Bundle data = msg.getData();
180
+ long id = data.getLong("downloadManagerId");
181
+ if (id == downloadManagerId) {
182
+
183
+ Context appCtx = ReactNativeBlobUtil.RCTContext.getApplicationContext();
184
+
185
+ DownloadManager downloadManager = (DownloadManager) appCtx.getSystemService(Context.DOWNLOAD_SERVICE);
186
+
187
+ DownloadManager.Query query = new DownloadManager.Query();
188
+
189
+ Cursor cursor = downloadManager.query(query);
190
+
191
+ if (cursor != null && cursor.moveToFirst()) {
192
+
193
+ long written = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
194
+
195
+ long total = cursor.getLong(cursor.getColumnIndex(
196
+ DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
197
+ cursor.close();
198
+
199
+ ReactNativeBlobUtilProgressConfig reportConfig = getReportProgress(taskId);
200
+ float progress = (total != -1) ? written / total : 0;
201
+
202
+ if (reportConfig != null && reportConfig.shouldReport(progress /* progress */)) {
203
+ WritableMap args = Arguments.createMap();
204
+ args.putString("taskId", String.valueOf(taskId));
205
+ args.putString("written", String.valueOf(written));
206
+ args.putString("total", String.valueOf(total));
207
+ args.putString("chunk", "");
208
+ ReactNativeBlobUtil.RCTContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
209
+ .emit(ReactNativeBlobUtilConst.EVENT_PROGRESS, args);
210
+
211
+ }
212
+
213
+ if (total == written) {
214
+ future.cancel(true);
215
+ }
216
+ }
217
+ }
218
+ }
219
+ return true;
220
+ }
221
+ });
222
+
156
223
  @Override
157
224
  public void run() {
158
225
 
@@ -204,6 +271,17 @@ public class ReactNativeBlobUtilReq extends BroadcastReceiver implements Runnabl
204
271
  downloadManagerId = dm.enqueue(req);
205
272
  androidDownloadManagerTaskTable.put(taskId, Long.valueOf(downloadManagerId));
206
273
  appCtx.registerReceiver(this, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
274
+ future = scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
275
+ @Override
276
+ public void run() {
277
+ Message msg = mHandler.obtainMessage();
278
+ Bundle data = new Bundle();
279
+ data.putLong("downloadManagerId", downloadManagerId);
280
+ msg.setData(data);
281
+ msg.what = QUERY;
282
+ mHandler.sendMessage(msg);
283
+ }
284
+ }, 0, 100, TimeUnit.MILLISECONDS);
207
285
  return;
208
286
  }
209
287
 
@@ -557,6 +635,26 @@ public class ReactNativeBlobUtilReq extends BroadcastReceiver implements Runnabl
557
635
  // response data directly pass to JS context as string.
558
636
  else {
559
637
  byte[] b = resp.body().bytes();
638
+ // If process file option is turned on, we first keep response in memory and then stream that content
639
+ // after processing
640
+ if (this.shouldTransformFile()) {
641
+ if (ReactNativeBlobUtilFileTransformer.sharedFileTransformer == null) {
642
+ throw new IllegalStateException("Write file with transform was specified but the shared file transformer is not set");
643
+ }
644
+ this.destPath = this.destPath.replace("?append=true", "");
645
+ File file = new File(this.destPath);
646
+ if (!file.exists()) {
647
+ file.createNewFile();
648
+ }
649
+ try (FileOutputStream fos = new FileOutputStream(file)) {
650
+ fos.write(ReactNativeBlobUtilFileTransformer.sharedFileTransformer.onWriteFile(b));
651
+ } catch(Exception e) {
652
+ callback.invoke("Error from file transformer:" + e.getLocalizedMessage(), null);
653
+ return;
654
+ }
655
+ callback.invoke(null, ReactNativeBlobUtilConst.RNFB_RESPONSE_PATH, this.destPath);
656
+ return;
657
+ }
560
658
  if (responseFormat == ResponseFormat.BASE64) {
561
659
  callback.invoke(null, ReactNativeBlobUtilConst.RNFB_RESPONSE_BASE64, android.util.Base64.encodeToString(b, Base64.NO_WRAP));
562
660
  return;
@@ -10,7 +10,6 @@ import com.facebook.react.modules.core.DeviceEventManagerModule;
10
10
 
11
11
  import java.nio.charset.Charset;
12
12
  import java.security.MessageDigest;
13
- import java.security.cert.CertificateException;
14
13
  import java.util.Locale;
15
14
 
16
15
  import javax.net.ssl.HostnameVerifier;
@@ -22,9 +21,10 @@ import javax.net.ssl.X509TrustManager;
22
21
 
23
22
  import okhttp3.OkHttpClient;
24
23
 
25
-
26
24
  public class ReactNativeBlobUtilUtils {
27
25
 
26
+ public static X509TrustManager sharedTrustManager;
27
+
28
28
  public static String getMD5(String input) {
29
29
  String result = null;
30
30
 
@@ -61,22 +61,10 @@ public class ReactNativeBlobUtilUtils {
61
61
 
62
62
  public static OkHttpClient.Builder getUnsafeOkHttpClient(OkHttpClient client) {
63
63
  try {
64
- // Create a trust manager that does not validate certificate chains
65
- final X509TrustManager x509TrustManager = new X509TrustManager() {
66
- @Override
67
- public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
68
- }
69
64
 
70
- @Override
71
- public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
72
- }
65
+ if (sharedTrustManager == null) throw new IllegalStateException("Use of own trust manager but none defined");
73
66
 
74
- @Override
75
- public java.security.cert.X509Certificate[] getAcceptedIssuers() {
76
- return new java.security.cert.X509Certificate[]{};
77
- }
78
- };
79
- final TrustManager[] trustAllCerts = new TrustManager[]{x509TrustManager};
67
+ final TrustManager[] trustAllCerts = new TrustManager[]{sharedTrustManager};
80
68
 
81
69
  // Install the all-trusting trust manager
82
70
  final SSLContext sslContext = SSLContext.getInstance("SSL");
@@ -85,7 +73,7 @@ public class ReactNativeBlobUtilUtils {
85
73
  final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
86
74
 
87
75
  OkHttpClient.Builder builder = client.newBuilder();
88
- builder.sslSocketFactory(sslSocketFactory, x509TrustManager);
76
+ builder.sslSocketFactory(sslSocketFactory, sharedTrustManager);
89
77
  builder.hostnameVerifier(new HostnameVerifier() {
90
78
  @Override
91
79
  public boolean verify(String hostname, SSLSession session) {
@@ -72,6 +72,10 @@ public class ReactNativeBlobUtilFileResp extends ResponseBody {
72
72
 
73
73
  @Override
74
74
  public long contentLength() {
75
+ if (originalBody.contentLength() > Integer.MAX_VALUE) {
76
+ // This is a workaround for a bug Okio buffer where it can't handle larger than int.
77
+ return Integer.MAX_VALUE;
78
+ }
75
79
  return originalBody.contentLength();
76
80
  }
77
81
 
@@ -3,7 +3,7 @@ import fs from "../fs";
3
3
  import Blob from "../polyfill/Blob";
4
4
  import ReactNativeBlobUtilSession from "./ReactNativeBlobUtilSession";
5
5
  import URIUtil from "../utils/uri";
6
-
6
+ import base64 from "base-64";
7
7
  /**
8
8
  * ReactNativeBlobUtil response object class.
9
9
  */
package/fs.js CHANGED
@@ -160,7 +160,20 @@ function readFile(path: string, encoding: string = 'utf8'): Promise<any> {
160
160
  if (typeof path !== 'string') {
161
161
  return Promise.reject(addCode('EINVAL', new TypeError('Missing argument "path" ')));
162
162
  }
163
- return ReactNativeBlobUtil.readFile(path, encoding);
163
+ return ReactNativeBlobUtil.readFile(path, encoding, false);
164
+ }
165
+
166
+ /**
167
+ * Reads the file, then transforms it before returning the content
168
+ * @param {string} path Path of the file.
169
+ * @param {'base64' | 'utf8' | 'ascii'} encoding Encoding of read stream.
170
+ * @return {Promise<Array<number> | string>}
171
+ */
172
+ function readFileWithTransform(path: string, encoding: string = 'utf8'): Promise<any> {
173
+ if (typeof path !== 'string') {
174
+ return Promise.reject(addCode('EINVAL', new TypeError('Missing argument "path" ')))
175
+ }
176
+ return ReactNativeBlobUtil.readFile(path, encoding, true);
164
177
  }
165
178
 
166
179
  /**
@@ -186,7 +199,31 @@ function writeFile(path: string, data: string | Array<number>, encoding: ?string
186
199
  return Promise.reject(addCode('EINVAL', new TypeError(`"data" must be a String when encoding is "utf8" or "base64", but it is "${typeof data}"`)));
187
200
  }
188
201
  else
189
- return ReactNativeBlobUtil.writeFile(path, encoding, data, false);
202
+ return ReactNativeBlobUtil.writeFile(path, encoding, data, false, false);
203
+ }
204
+ }
205
+
206
+ /**
207
+ * Transforms the data and then writes to the file.
208
+ * @param {string} path Path of the file.
209
+ * @param {string | number[]} data Data to write to the file.
210
+ * @param {string} encoding Encoding of data (Optional).
211
+ * @return {Promise}
212
+ */
213
+ function writeFileWithTransform(path: string, data: string | Array<number>, encoding: ?string = 'utf8'): Promise {
214
+ if (typeof path !== 'string') {
215
+ return Promise.reject(addCode('EINVAL', new TypeError('Missing argument "path" ')))
216
+ }
217
+ if (encoding.toLocaleLowerCase() === 'ascii') {
218
+ return Promise.reject(addCode('EINVAL', new TypeError('ascii is not supported for converted files')))
219
+ }
220
+ else {
221
+ if (typeof data !== 'string') {
222
+ return Promise.reject(addCode('EINVAL', new TypeError(`"data" must be a String when encoding is "utf8" or "base64", but it is "${typeof data}"`)))
223
+ }
224
+
225
+ else
226
+ return ReactNativeBlobUtil.writeFile(path, encoding, data, true, false)
190
227
  }
191
228
  }
192
229
 
@@ -206,7 +243,7 @@ function appendFile(path: string, data: string | Array<number>, encoding?: strin
206
243
  return Promise.reject(addCode('EINVAL'), new TypeError(`"data" must be a String when encoding is "utf8" or "base64", but it is "${typeof data}"`));
207
244
  }
208
245
  else
209
- return ReactNativeBlobUtil.writeFile(path, encoding, data, true);
246
+ return ReactNativeBlobUtil.writeFile(path, encoding, data, false, true);
210
247
  }
211
248
  }
212
249
 
@@ -415,6 +452,8 @@ export default {
415
452
  cp,
416
453
  writeStream,
417
454
  writeFile,
455
+ writeFileWithTransform,
456
+ readFileWithTransform,
418
457
  appendFile,
419
458
  pathForAppGroup,
420
459
  syncPathAppGroup,
package/index.d.ts CHANGED
@@ -399,6 +399,14 @@ export interface FS {
399
399
  */
400
400
  writeFile(path: string, data: string | number[], encoding?: Encoding): Promise<void>;
401
401
 
402
+ /**
403
+ * Processes the data and then writes to the file.
404
+ * @param path Path of the file.
405
+ * @param data Data to write to the file.
406
+ * @param encoding Encoding of data (Optional).
407
+ */
408
+ writeFileWithTransform(path: string, data: string | number[], encoding?: Encoding): Promise<void>;
409
+
402
410
  appendFile(path: string, data: string | number[], encoding?: Encoding | "uri"): Promise<number>;
403
411
 
404
412
  /**
@@ -408,6 +416,13 @@ export interface FS {
408
416
  */
409
417
  readFile(path: string, encoding: Encoding, bufferSize?: number): Promise<any>;
410
418
 
419
+ /**
420
+ * Reads from a file and then processes the data before returning
421
+ * @param path Path of the file.
422
+ * @param encoding Encoding of read stream.
423
+ */
424
+ readFileWithTransform(path: string, encoding: Encoding, bufferSize?: number): Promise<any>;
425
+
411
426
  /**
412
427
  * Check if file exists and if it is a folder.
413
428
  * @param path Path to check
@@ -475,7 +490,7 @@ export interface ReactNativeBlobUtilWriteStream {
475
490
 
476
491
  write(data: string): Promise<void>;
477
492
 
478
- close(): void;
493
+ close(): Promise<void>;
479
494
  }
480
495
 
481
496
  export interface ReactNativeBlobUtilReadStream {
@@ -698,6 +713,13 @@ export interface ReactNativeBlobUtilConfig {
698
713
  */
699
714
  fileCache?: boolean;
700
715
 
716
+ /**
717
+ * Set this property to true if you want the data to be processed before it gets written onto disk.
718
+ * This only has effect if the FileTransformer has been registered and the library is configured to write
719
+ * response onto disk.
720
+ */
721
+ transformFile?: boolean;
722
+
701
723
  /**
702
724
  * Set this property to change temp file extension that created by fetch response data.
703
725
  */
@@ -808,6 +830,13 @@ export interface MediaCollection {
808
830
  */
809
831
  writeToMediafile(uri: string, path: string): Promise<string>
810
832
 
833
+ /**
834
+ * Copies and transforms an existing file to a mediastore file. Make sure FileTransformer is set
835
+ * @param uri URI of the destination mediastore file
836
+ * @param path Path to the existing file which should be copied
837
+ */
838
+ writeToMediafileWithTransform(uri: string, path: string): Promise<string>
839
+
811
840
  /**
812
841
  * Copies a file from the mediastore to the apps internal storage
813
842
  * @param contenturi URI of the mediastore file