|
@@ -1,7 +1,5 @@
|
1
|
1
|
package com.RNFetchBlob;
|
2
|
2
|
|
3
|
|
-import android.content.pm.PackageInfo;
|
4
|
|
-import android.content.pm.PackageManager;
|
5
|
3
|
import android.content.res.AssetFileDescriptor;
|
6
|
4
|
import android.media.MediaScannerConnection;
|
7
|
5
|
import android.net.Uri;
|
|
@@ -22,42 +20,29 @@ import com.facebook.react.bridge.WritableArray;
|
22
|
20
|
import com.facebook.react.bridge.WritableMap;
|
23
|
21
|
import com.facebook.react.modules.core.DeviceEventManagerModule;
|
24
|
22
|
|
25
|
|
-import java.io.File;
|
26
|
|
-import java.io.FileInputStream;
|
27
|
|
-import java.io.FileOutputStream;
|
28
|
|
-import java.io.IOException;
|
29
|
|
-import java.io.InputStream;
|
30
|
|
-import java.io.OutputStream;
|
|
23
|
+import java.io.*;
|
31
|
24
|
import java.nio.ByteBuffer;
|
32
|
25
|
import java.nio.charset.Charset;
|
33
|
26
|
import java.nio.charset.CharsetEncoder;
|
|
27
|
+import java.security.MessageDigest;
|
|
28
|
+import java.util.ArrayList;
|
34
|
29
|
import java.util.HashMap;
|
35
|
30
|
import java.util.Map;
|
36
|
31
|
import java.util.UUID;
|
37
|
32
|
|
38
|
|
-public class RNFetchBlobFS {
|
|
33
|
+class RNFetchBlobFS {
|
39
|
34
|
|
40
|
|
- ReactApplicationContext mCtx;
|
41
|
|
- DeviceEventManagerModule.RCTDeviceEventEmitter emitter;
|
42
|
|
- String encoding = "base64";
|
43
|
|
- boolean append = false;
|
44
|
|
- OutputStream writeStreamInstance = null;
|
45
|
|
- static HashMap<String, RNFetchBlobFS> fileStreams = new HashMap<>();
|
|
35
|
+ private ReactApplicationContext mCtx;
|
|
36
|
+ private DeviceEventManagerModule.RCTDeviceEventEmitter emitter;
|
|
37
|
+ private String encoding = "base64";
|
|
38
|
+ private OutputStream writeStreamInstance = null;
|
|
39
|
+ private static HashMap<String, RNFetchBlobFS> fileStreams = new HashMap<>();
|
46
|
40
|
|
47
|
41
|
RNFetchBlobFS(ReactApplicationContext ctx) {
|
48
|
42
|
this.mCtx = ctx;
|
49
|
43
|
this.emitter = ctx.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class);
|
50
|
44
|
}
|
51
|
45
|
|
52
|
|
- static String getExternalFilePath(ReactApplicationContext ctx, String taskId, RNFetchBlobConfig config) {
|
53
|
|
- if(config.path != null)
|
54
|
|
- return config.path;
|
55
|
|
- else if(config.fileCache && config.appendExt != null)
|
56
|
|
- return RNFetchBlobFS.getTmpPath(ctx, taskId) + "." + config.appendExt;
|
57
|
|
- else
|
58
|
|
- return RNFetchBlobFS.getTmpPath(ctx, taskId);
|
59
|
|
- }
|
60
|
|
-
|
61
|
46
|
/**
|
62
|
47
|
* Write string with encoding to file
|
63
|
48
|
* @param path Destination file path.
|
|
@@ -65,25 +50,37 @@ public class RNFetchBlobFS {
|
65
|
50
|
* @param data Array passed from JS context.
|
66
|
51
|
* @param promise RCT Promise
|
67
|
52
|
*/
|
68
|
|
- static public void writeFile(String path, String encoding, String data, final boolean append, final Promise promise) {
|
|
53
|
+ static void writeFile(String path, String encoding, String data, final boolean append, final Promise promise) {
|
69
|
54
|
try {
|
70
|
|
- int written = 0;
|
|
55
|
+ int written;
|
71
|
56
|
File f = new File(path);
|
72
|
57
|
File dir = f.getParentFile();
|
73
|
|
- if(!dir.exists())
|
74
|
|
- dir.mkdirs();
|
|
58
|
+
|
|
59
|
+ if(!f.exists()) {
|
|
60
|
+ if(dir != null && !dir.exists()) {
|
|
61
|
+ if (!dir.mkdirs()) {
|
|
62
|
+ promise.reject("EUNSPECIFIED", "Failed to create parent directory of '" + path + "'");
|
|
63
|
+ return;
|
|
64
|
+ }
|
|
65
|
+ }
|
|
66
|
+ if(!f.createNewFile()) {
|
|
67
|
+ promise.reject("ENOENT", "File '" + path + "' does not exist and could not be created");
|
|
68
|
+ return;
|
|
69
|
+ }
|
|
70
|
+ }
|
|
71
|
+
|
75
|
72
|
FileOutputStream fout = new FileOutputStream(f, append);
|
76
|
73
|
// write data from a file
|
77
|
74
|
if(encoding.equalsIgnoreCase(RNFetchBlobConst.DATA_ENCODE_URI)) {
|
78
|
|
- data = normalizePath(data);
|
79
|
|
- File src = new File(data);
|
80
|
|
- if(!src.exists()) {
|
81
|
|
- promise.reject("RNfetchBlob writeFileError", "source file : " + data + "not exists");
|
|
75
|
+ String normalizedData = normalizePath(data);
|
|
76
|
+ File src = new File(normalizedData);
|
|
77
|
+ if (!src.exists()) {
|
|
78
|
+ promise.reject("ENOENT", "No such file '" + path + "' " + "('" + normalizedData + "')");
|
82
|
79
|
fout.close();
|
83
|
|
- return ;
|
|
80
|
+ return;
|
84
|
81
|
}
|
85
|
82
|
FileInputStream fin = new FileInputStream(src);
|
86
|
|
- byte [] buffer = new byte [10240];
|
|
83
|
+ byte[] buffer = new byte [10240];
|
87
|
84
|
int read;
|
88
|
85
|
written = 0;
|
89
|
86
|
while((read = fin.read(buffer)) > 0) {
|
|
@@ -99,8 +96,11 @@ public class RNFetchBlobFS {
|
99
|
96
|
}
|
100
|
97
|
fout.close();
|
101
|
98
|
promise.resolve(written);
|
|
99
|
+ } catch (FileNotFoundException e) {
|
|
100
|
+ // According to https://docs.oracle.com/javase/7/docs/api/java/io/FileOutputStream.html
|
|
101
|
+ promise.reject("ENOENT", "File '" + path + "' does not exist and could not be created, or it is a directory");
|
102
|
102
|
} catch (Exception e) {
|
103
|
|
- promise.reject("RNFetchBlob writeFileError", e.getLocalizedMessage());
|
|
103
|
+ promise.reject("EUNSPECIFIED", e.getLocalizedMessage());
|
104
|
104
|
}
|
105
|
105
|
}
|
106
|
106
|
|
|
@@ -110,24 +110,37 @@ public class RNFetchBlobFS {
|
110
|
110
|
* @param data Array passed from JS context.
|
111
|
111
|
* @param promise RCT Promise
|
112
|
112
|
*/
|
113
|
|
- static public void writeFile(String path, ReadableArray data, final boolean append, final Promise promise) {
|
114
|
|
-
|
|
113
|
+ static void writeFile(String path, ReadableArray data, final boolean append, final Promise promise) {
|
115
|
114
|
try {
|
116
|
|
-
|
117
|
115
|
File f = new File(path);
|
118
|
116
|
File dir = f.getParentFile();
|
119
|
|
- if(!dir.exists())
|
120
|
|
- dir.mkdirs();
|
|
117
|
+
|
|
118
|
+ if(!f.exists()) {
|
|
119
|
+ if(dir != null && !dir.exists()) {
|
|
120
|
+ if (!dir.mkdirs()) {
|
|
121
|
+ promise.reject("ENOTDIR", "Failed to create parent directory of '" + path + "'");
|
|
122
|
+ return;
|
|
123
|
+ }
|
|
124
|
+ }
|
|
125
|
+ if(!f.createNewFile()) {
|
|
126
|
+ promise.reject("ENOENT", "File '" + path + "' does not exist and could not be created");
|
|
127
|
+ return;
|
|
128
|
+ }
|
|
129
|
+ }
|
|
130
|
+
|
121
|
131
|
FileOutputStream os = new FileOutputStream(f, append);
|
122
|
|
- byte [] bytes = new byte[data.size()];
|
|
132
|
+ byte[] bytes = new byte[data.size()];
|
123
|
133
|
for(int i=0;i<data.size();i++) {
|
124
|
134
|
bytes[i] = (byte) data.getInt(i);
|
125
|
135
|
}
|
126
|
136
|
os.write(bytes);
|
127
|
137
|
os.close();
|
128
|
138
|
promise.resolve(data.size());
|
|
139
|
+ } catch (FileNotFoundException e) {
|
|
140
|
+ // According to https://docs.oracle.com/javase/7/docs/api/java/io/FileOutputStream.html
|
|
141
|
+ promise.reject("ENOENT", "File '" + path + "' does not exist and could not be created");
|
129
|
142
|
} catch (Exception e) {
|
130
|
|
- promise.reject("RNFetchBlob writeFileError", e.getLocalizedMessage());
|
|
143
|
+ promise.reject("EUNSPECIFIED", e.getLocalizedMessage());
|
131
|
144
|
}
|
132
|
145
|
}
|
133
|
146
|
|
|
@@ -135,48 +148,60 @@ public class RNFetchBlobFS {
|
135
|
148
|
* Read file with a buffer that has the same size as the target file.
|
136
|
149
|
* @param path Path of the file.
|
137
|
150
|
* @param encoding Encoding of read stream.
|
138
|
|
- * @param promise
|
|
151
|
+ * @param promise JS promise
|
139
|
152
|
*/
|
140
|
|
- static public void readFile(String path, String encoding, final Promise promise ) {
|
|
153
|
+ static void readFile(String path, String encoding, final Promise promise) {
|
141
|
154
|
String resolved = normalizePath(path);
|
142
|
155
|
if(resolved != null)
|
143
|
156
|
path = resolved;
|
144
|
157
|
try {
|
145
|
158
|
byte[] bytes;
|
|
159
|
+ int bytesRead;
|
|
160
|
+ int length; // max. array length limited to "int", also see https://stackoverflow.com/a/10787175/544779
|
146
|
161
|
|
147
|
162
|
if(resolved != null && resolved.startsWith(RNFetchBlobConst.FILE_PREFIX_BUNDLE_ASSET)) {
|
148
|
163
|
String assetName = path.replace(RNFetchBlobConst.FILE_PREFIX_BUNDLE_ASSET, "");
|
149
|
|
- long length = RNFetchBlob.RCTContext.getAssets().openFd(assetName).getLength();
|
150
|
|
- bytes = new byte[(int) length];
|
|
164
|
+ // This fails should an asset file be >2GB
|
|
165
|
+ length = (int) RNFetchBlob.RCTContext.getAssets().openFd(assetName).getLength();
|
|
166
|
+ bytes = new byte[length];
|
151
|
167
|
InputStream in = RNFetchBlob.RCTContext.getAssets().open(assetName);
|
152
|
|
- in.read(bytes, 0, (int) length);
|
|
168
|
+ bytesRead = in.read(bytes, 0, length);
|
153
|
169
|
in.close();
|
154
|
170
|
}
|
155
|
171
|
// issue 287
|
156
|
172
|
else if(resolved == null) {
|
157
|
173
|
InputStream in = RNFetchBlob.RCTContext.getContentResolver().openInputStream(Uri.parse(path));
|
158
|
|
- int length = (int) in.available();
|
|
174
|
+ // TODO See https://developer.android.com/reference/java/io/InputStream.html#available()
|
|
175
|
+ // Quote: "Note that while some implementations of InputStream will return the total number of bytes
|
|
176
|
+ // in the stream, many will not. It is never correct to use the return value of this method to
|
|
177
|
+ // allocate a buffer intended to hold all data in this stream."
|
|
178
|
+ length = in.available();
|
159
|
179
|
bytes = new byte[length];
|
160
|
|
- in.read(bytes);
|
|
180
|
+ bytesRead = in.read(bytes);
|
161
|
181
|
in.close();
|
162
|
182
|
}
|
163
|
183
|
else {
|
164
|
184
|
File f = new File(path);
|
165
|
|
- int length = (int) f.length();
|
|
185
|
+ length = (int) f.length();
|
166
|
186
|
bytes = new byte[length];
|
167
|
187
|
FileInputStream in = new FileInputStream(f);
|
168
|
|
- in.read(bytes);
|
|
188
|
+ bytesRead = in.read(bytes);
|
169
|
189
|
in.close();
|
170
|
190
|
}
|
171
|
191
|
|
|
192
|
+ if (bytesRead < length) {
|
|
193
|
+ promise.reject("EUNSPECIFIED", "Read only " + bytesRead + " bytes of " + length);
|
|
194
|
+ return;
|
|
195
|
+ }
|
|
196
|
+
|
172
|
197
|
switch (encoding.toLowerCase()) {
|
173
|
198
|
case "base64" :
|
174
|
199
|
promise.resolve(Base64.encodeToString(bytes, Base64.NO_WRAP));
|
175
|
200
|
break;
|
176
|
201
|
case "ascii" :
|
177
|
202
|
WritableArray asciiResult = Arguments.createArray();
|
178
|
|
- for(byte b : bytes) {
|
179
|
|
- asciiResult.pushInt((int)b);
|
|
203
|
+ for (byte b : bytes) {
|
|
204
|
+ asciiResult.pushInt((int) b);
|
180
|
205
|
}
|
181
|
206
|
promise.resolve(asciiResult);
|
182
|
207
|
break;
|
|
@@ -188,8 +213,16 @@ public class RNFetchBlobFS {
|
188
|
213
|
break;
|
189
|
214
|
}
|
190
|
215
|
}
|
|
216
|
+ catch(FileNotFoundException err) {
|
|
217
|
+ String msg = err.getLocalizedMessage();
|
|
218
|
+ if (msg.contains("EISDIR")) {
|
|
219
|
+ promise.reject("EISDIR", "Expecting a file but '" + path + "' is a directory; " + msg);
|
|
220
|
+ } else {
|
|
221
|
+ promise.reject("ENOENT", "No such file '" + path + "'; " + msg);
|
|
222
|
+ }
|
|
223
|
+ }
|
191
|
224
|
catch(Exception err) {
|
192
|
|
- promise.reject("ReadFile Error", err.getLocalizedMessage());
|
|
225
|
+ promise.reject("EUNSPECIFIED", err.getLocalizedMessage());
|
193
|
226
|
}
|
194
|
227
|
|
195
|
228
|
}
|
|
@@ -198,7 +231,7 @@ public class RNFetchBlobFS {
|
198
|
231
|
* Static method that returns system folders to JS context
|
199
|
232
|
* @param ctx React Native application context
|
200
|
233
|
*/
|
201
|
|
- static public Map<String, Object> getSystemfolders(ReactApplicationContext ctx) {
|
|
234
|
+ static Map<String, Object> getSystemfolders(ReactApplicationContext ctx) {
|
202
|
235
|
Map<String, Object> res = new HashMap<>();
|
203
|
236
|
|
204
|
237
|
res.put("DocumentDir", ctx.getFilesDir().getAbsolutePath());
|
|
@@ -247,11 +280,10 @@ public class RNFetchBlobFS {
|
247
|
280
|
|
248
|
281
|
/**
|
249
|
282
|
* Static method that returns a temp file path
|
250
|
|
- * @param ctx React Native application context
|
251
|
283
|
* @param taskId An unique string for identify
|
252
|
|
- * @return
|
|
284
|
+ * @return String
|
253
|
285
|
*/
|
254
|
|
- static public String getTmpPath(ReactApplicationContext ctx, String taskId) {
|
|
286
|
+ static String getTmpPath(String taskId) {
|
255
|
287
|
return RNFetchBlob.RCTContext.getFilesDir() + "/RNFetchBlobTmp_" + taskId;
|
256
|
288
|
}
|
257
|
289
|
|
|
@@ -261,12 +293,12 @@ public class RNFetchBlobFS {
|
261
|
293
|
* @param encoding File stream decoder, should be one of `base64`, `utf8`, `ascii`
|
262
|
294
|
* @param bufferSize Buffer size of read stream, default to 4096 (4095 when encode is `base64`)
|
263
|
295
|
*/
|
264
|
|
- public void readStream(String path, String encoding, int bufferSize, int tick, final String streamId) {
|
|
296
|
+ void readStream(String path, String encoding, int bufferSize, int tick, final String streamId) {
|
265
|
297
|
String resolved = normalizePath(path);
|
266
|
298
|
if(resolved != null)
|
267
|
299
|
path = resolved;
|
268
|
|
- try {
|
269
|
300
|
|
|
301
|
+ try {
|
270
|
302
|
int chunkSize = encoding.equalsIgnoreCase("base64") ? 4095 : 4096;
|
271
|
303
|
if(bufferSize > 0)
|
272
|
304
|
chunkSize = bufferSize;
|
|
@@ -275,7 +307,6 @@ public class RNFetchBlobFS {
|
275
|
307
|
|
276
|
308
|
if(resolved != null && path.startsWith(RNFetchBlobConst.FILE_PREFIX_BUNDLE_ASSET)) {
|
277
|
309
|
fs = RNFetchBlob.RCTContext.getAssets().open(path.replace(RNFetchBlobConst.FILE_PREFIX_BUNDLE_ASSET, ""));
|
278
|
|
-
|
279
|
310
|
}
|
280
|
311
|
// fix issue 287
|
281
|
312
|
else if(resolved == null) {
|
|
@@ -312,10 +343,8 @@ public class RNFetchBlobFS {
|
312
|
343
|
} else if (encoding.equalsIgnoreCase("base64")) {
|
313
|
344
|
while ((cursor = fs.read(buffer)) != -1) {
|
314
|
345
|
if(cursor < chunkSize) {
|
315
|
|
- byte [] copy = new byte[cursor];
|
316
|
|
- for(int i =0;i<cursor;i++) {
|
317
|
|
- copy[i] = buffer[i];
|
318
|
|
- }
|
|
346
|
+ byte[] copy = new byte[cursor];
|
|
347
|
+ System.arraycopy(buffer, 0, copy, 0, cursor);
|
319
|
348
|
emitStreamEvent(streamId, "data", Base64.encodeToString(copy, Base64.NO_WRAP));
|
320
|
349
|
}
|
321
|
350
|
else
|
|
@@ -324,8 +353,12 @@ public class RNFetchBlobFS {
|
324
|
353
|
SystemClock.sleep(tick);
|
325
|
354
|
}
|
326
|
355
|
} else {
|
327
|
|
- String msg = "unrecognized encoding `" + encoding + "`";
|
328
|
|
- emitStreamEvent(streamId, "error", msg);
|
|
356
|
+ emitStreamEvent(
|
|
357
|
+ streamId,
|
|
358
|
+ "error",
|
|
359
|
+ "EINVAL",
|
|
360
|
+ "Unrecognized encoding `" + encoding + "`, should be one of `base64`, `utf8`, `ascii`"
|
|
361
|
+ );
|
329
|
362
|
error = true;
|
330
|
363
|
}
|
331
|
364
|
|
|
@@ -333,9 +366,20 @@ public class RNFetchBlobFS {
|
333
|
366
|
emitStreamEvent(streamId, "end", "");
|
334
|
367
|
fs.close();
|
335
|
368
|
buffer = null;
|
336
|
|
-
|
|
369
|
+ } catch (FileNotFoundException err) {
|
|
370
|
+ emitStreamEvent(
|
|
371
|
+ streamId,
|
|
372
|
+ "error",
|
|
373
|
+ "ENOENT",
|
|
374
|
+ "No such file '" + path + "'"
|
|
375
|
+ );
|
337
|
376
|
} catch (Exception err) {
|
338
|
|
- emitStreamEvent(streamId, "warn", "Failed to convert data to "+encoding+" encoded string, this might due to the source data is not able to convert using this encoding.");
|
|
377
|
+ emitStreamEvent(
|
|
378
|
+ streamId,
|
|
379
|
+ "error",
|
|
380
|
+ "EUNSPECIFIED",
|
|
381
|
+ "Failed to convert data to " + encoding + " encoded string. This might be because this encoding cannot be used for this data."
|
|
382
|
+ );
|
339
|
383
|
err.printStackTrace();
|
340
|
384
|
}
|
341
|
385
|
}
|
|
@@ -343,28 +387,40 @@ public class RNFetchBlobFS {
|
343
|
387
|
/**
|
344
|
388
|
* Create a write stream and store its instance in RNFetchBlobFS.fileStreams
|
345
|
389
|
* @param path Target file path
|
346
|
|
- * @param encoding Should be one of `base64`, `utf8`, `ascii`
|
347
|
|
- * @param append Flag represents if the file stream overwrite existing content
|
348
|
|
- * @param callback
|
|
390
|
+ * @param encoding Should be one of `base64`, `utf8`, `ascii`
|
|
391
|
+ * @param append Flag represents if the file stream overwrite existing content
|
|
392
|
+ * @param callback Callback
|
349
|
393
|
*/
|
350
|
|
- public void writeStream(String path, String encoding, boolean append, Callback callback) {
|
351
|
|
- File dest = new File(path);
|
352
|
|
- if(!dest.exists() || dest.isDirectory()) {
|
353
|
|
- callback.invoke("write stream error: target path `" + path + "` may not exists or it's a folder");
|
354
|
|
- return;
|
355
|
|
- }
|
|
394
|
+ void writeStream(String path, String encoding, boolean append, Callback callback) {
|
356
|
395
|
try {
|
|
396
|
+ File dest = new File(path);
|
|
397
|
+ File dir = dest.getParentFile();
|
|
398
|
+
|
|
399
|
+ if(!dest.exists()) {
|
|
400
|
+ if(dir != null && !dir.exists()) {
|
|
401
|
+ if (!dir.mkdirs()) {
|
|
402
|
+ callback.invoke("ENOTDIR", "Failed to create parent directory of '" + path + "'");
|
|
403
|
+ return;
|
|
404
|
+ }
|
|
405
|
+ }
|
|
406
|
+ if(!dest.createNewFile()) {
|
|
407
|
+ callback.invoke("ENOENT", "File '" + path + "' does not exist and could not be created");
|
|
408
|
+ return;
|
|
409
|
+ }
|
|
410
|
+ } else if(dest.isDirectory()) {
|
|
411
|
+ callback.invoke("EISDIR", "Expecting a file but '" + path + "' is a directory");
|
|
412
|
+ return;
|
|
413
|
+ }
|
|
414
|
+
|
357
|
415
|
OutputStream fs = new FileOutputStream(path, append);
|
358
|
416
|
this.encoding = encoding;
|
359
|
|
- this.append = append;
|
360
|
417
|
String streamId = UUID.randomUUID().toString();
|
361
|
418
|
RNFetchBlobFS.fileStreams.put(streamId, this);
|
362
|
419
|
this.writeStreamInstance = fs;
|
363
|
|
- callback.invoke(null, streamId);
|
|
420
|
+ callback.invoke(null, null, streamId);
|
364
|
421
|
} catch(Exception err) {
|
365
|
|
- callback.invoke("write stream error: failed to create write stream at path `"+path+"` "+ err.getLocalizedMessage());
|
|
422
|
+ callback.invoke("EUNSPECIFIED", "Failed to create write stream at path `" + path + "`; " + err.getLocalizedMessage());
|
366
|
423
|
}
|
367
|
|
-
|
368
|
424
|
}
|
369
|
425
|
|
370
|
426
|
/**
|
|
@@ -374,11 +430,9 @@ public class RNFetchBlobFS {
|
374
|
430
|
* @param callback JS context callback
|
375
|
431
|
*/
|
376
|
432
|
static void writeChunk(String streamId, String data, Callback callback) {
|
377
|
|
-
|
378
|
433
|
RNFetchBlobFS fs = fileStreams.get(streamId);
|
379
|
434
|
OutputStream stream = fs.writeStreamInstance;
|
380
|
|
- byte [] chunk = RNFetchBlobFS.stringToBytes(data, fs.encoding);
|
381
|
|
-
|
|
435
|
+ byte[] chunk = RNFetchBlobFS.stringToBytes(data, fs.encoding);
|
382
|
436
|
try {
|
383
|
437
|
stream.write(chunk);
|
384
|
438
|
callback.invoke();
|
|
@@ -394,11 +448,10 @@ public class RNFetchBlobFS {
|
394
|
448
|
* @param callback JS context callback
|
395
|
449
|
*/
|
396
|
450
|
static void writeArrayChunk(String streamId, ReadableArray data, Callback callback) {
|
397
|
|
-
|
398
|
451
|
try {
|
399
|
452
|
RNFetchBlobFS fs = fileStreams.get(streamId);
|
400
|
453
|
OutputStream stream = fs.writeStreamInstance;
|
401
|
|
- byte [] chunk = new byte[data.size()];
|
|
454
|
+ byte[] chunk = new byte[data.size()];
|
402
|
455
|
for(int i =0; i< data.size();i++) {
|
403
|
456
|
chunk[i] = (byte) data.getInt(i);
|
404
|
457
|
}
|
|
@@ -436,35 +489,51 @@ public class RNFetchBlobFS {
|
436
|
489
|
RNFetchBlobFS.deleteRecursive(new File(path));
|
437
|
490
|
callback.invoke(null, true);
|
438
|
491
|
} catch(Exception err) {
|
439
|
|
- if(err != null)
|
440
|
492
|
callback.invoke(err.getLocalizedMessage(), false);
|
441
|
493
|
}
|
442
|
494
|
}
|
443
|
495
|
|
444
|
|
- static void deleteRecursive(File fileOrDirectory) {
|
445
|
|
-
|
|
496
|
+ private static void deleteRecursive(File fileOrDirectory) throws IOException {
|
446
|
497
|
if (fileOrDirectory.isDirectory()) {
|
447
|
|
- for (File child : fileOrDirectory.listFiles()) {
|
448
|
|
- deleteRecursive(child);
|
|
498
|
+ File[] files = fileOrDirectory.listFiles();
|
|
499
|
+ if (files == null) {
|
|
500
|
+ throw new NullPointerException("Received null trying to list files of directory '" + fileOrDirectory + "'");
|
|
501
|
+ } else {
|
|
502
|
+ for (File child : files) {
|
|
503
|
+ deleteRecursive(child);
|
|
504
|
+ }
|
449
|
505
|
}
|
450
|
506
|
}
|
451
|
|
- fileOrDirectory.delete();
|
|
507
|
+ boolean result = fileOrDirectory.delete();
|
|
508
|
+ if (!result) {
|
|
509
|
+ throw new IOException("Failed to delete '" + fileOrDirectory + "'");
|
|
510
|
+ }
|
452
|
511
|
}
|
453
|
512
|
|
454
|
513
|
/**
|
455
|
514
|
* Make a folder
|
456
|
|
- * @param path Source path
|
457
|
|
- * @param callback JS context callback
|
|
515
|
+ * @param path Source path
|
|
516
|
+ * @param promise JS promise
|
458
|
517
|
*/
|
459
|
|
- static void mkdir(String path, Callback callback) {
|
|
518
|
+ static void mkdir(String path, Promise promise) {
|
460
|
519
|
File dest = new File(path);
|
461
|
520
|
if(dest.exists()) {
|
462
|
|
- callback.invoke("mkdir error: failed to create folder at `" + path + "` folder already exists");
|
|
521
|
+ promise.reject("EEXIST", dest.isDirectory() ? "Folder" : "File" + " '" + path + "' already exists");
|
463
|
522
|
return;
|
464
|
523
|
}
|
465
|
|
- dest.mkdirs();
|
466
|
|
- callback.invoke();
|
|
524
|
+ try {
|
|
525
|
+ boolean result = dest.mkdirs();
|
|
526
|
+ if (!result) {
|
|
527
|
+ promise.reject("EUNSPECIFIED", "mkdir failed to create some or all directories in '" + path + "'");
|
|
528
|
+ return;
|
|
529
|
+ }
|
|
530
|
+ } catch (Exception e) {
|
|
531
|
+ promise.reject("EUNSPECIFIED", e.getLocalizedMessage());
|
|
532
|
+ return;
|
|
533
|
+ }
|
|
534
|
+ promise.resolve(true);
|
467
|
535
|
}
|
|
536
|
+
|
468
|
537
|
/**
|
469
|
538
|
* Copy file to destination path
|
470
|
539
|
* @param path Source path
|
|
@@ -472,19 +541,22 @@ public class RNFetchBlobFS {
|
472
|
541
|
* @param callback JS context callback
|
473
|
542
|
*/
|
474
|
543
|
static void cp(String path, String dest, Callback callback) {
|
475
|
|
-
|
476
|
544
|
path = normalizePath(path);
|
477
|
545
|
InputStream in = null;
|
478
|
546
|
OutputStream out = null;
|
479
|
547
|
|
480
|
548
|
try {
|
481
|
|
-
|
482
|
549
|
if(!isPathExists(path)) {
|
483
|
|
- callback.invoke("cp error: source file at path`" + path + "` not exists");
|
|
550
|
+ callback.invoke("Source file at path`" + path + "` does not exist");
|
484
|
551
|
return;
|
485
|
552
|
}
|
486
|
|
- if(!new File(dest).exists())
|
487
|
|
- new File(dest).createNewFile();
|
|
553
|
+ if(!new File(dest).exists()) {
|
|
554
|
+ boolean result = new File(dest).createNewFile();
|
|
555
|
+ if (!result) {
|
|
556
|
+ callback.invoke("Destination file at '" + dest + "' already exists");
|
|
557
|
+ return;
|
|
558
|
+ }
|
|
559
|
+ }
|
488
|
560
|
|
489
|
561
|
in = inputStreamFromPath(path);
|
490
|
562
|
out = new FileOutputStream(dest);
|
|
@@ -494,7 +566,6 @@ public class RNFetchBlobFS {
|
494
|
566
|
while ((len = in.read(buf)) > 0) {
|
495
|
567
|
out.write(buf, 0, len);
|
496
|
568
|
}
|
497
|
|
-
|
498
|
569
|
} catch (Exception err) {
|
499
|
570
|
callback.invoke(err.getLocalizedMessage());
|
500
|
571
|
} finally {
|
|
@@ -521,10 +592,19 @@ public class RNFetchBlobFS {
|
521
|
592
|
static void mv(String path, String dest, Callback callback) {
|
522
|
593
|
File src = new File(path);
|
523
|
594
|
if(!src.exists()) {
|
524
|
|
- callback.invoke("mv error: source file at path `" + path + "` does not exists");
|
|
595
|
+ callback.invoke("Source file at path `" + path + "` does not exist");
|
|
596
|
+ return;
|
|
597
|
+ }
|
|
598
|
+ try {
|
|
599
|
+ boolean result = src.renameTo(new File(dest));
|
|
600
|
+ if (!result) {
|
|
601
|
+ callback.invoke("mv failed for unknown reasons");
|
|
602
|
+ return;
|
|
603
|
+ }
|
|
604
|
+ } catch (Exception e) {
|
|
605
|
+ callback.invoke(e.getLocalizedMessage());
|
525
|
606
|
return;
|
526
|
607
|
}
|
527
|
|
- src.renameTo(new File(dest));
|
528
|
608
|
callback.invoke();
|
529
|
609
|
}
|
530
|
610
|
|
|
@@ -534,11 +614,10 @@ public class RNFetchBlobFS {
|
534
|
614
|
* @param callback JS context callback
|
535
|
615
|
*/
|
536
|
616
|
static void exists(String path, Callback callback) {
|
537
|
|
-
|
538
|
617
|
if(isAsset(path)) {
|
539
|
618
|
try {
|
540
|
619
|
String filename = path.replace(RNFetchBlobConst.FILE_PREFIX_BUNDLE_ASSET, "");
|
541
|
|
- AssetFileDescriptor fd = RNFetchBlob.RCTContext.getAssets().openFd(filename);
|
|
620
|
+ com.RNFetchBlob.RNFetchBlob.RCTContext.getAssets().openFd(filename);
|
542
|
621
|
callback.invoke(true, false);
|
543
|
622
|
} catch (IOException e) {
|
544
|
623
|
callback.invoke(false, false);
|
|
@@ -557,48 +636,67 @@ public class RNFetchBlobFS {
|
557
|
636
|
* @param path Target folder
|
558
|
637
|
* @param callback JS context callback
|
559
|
638
|
*/
|
560
|
|
- static void ls(String path, Callback callback) {
|
561
|
|
- path = normalizePath(path);
|
562
|
|
- File src = new File(path);
|
563
|
|
- if (!src.exists() || !src.isDirectory()) {
|
564
|
|
- callback.invoke("ls error: failed to list path `" + path + "` for it is not exist or it is not a folder");
|
565
|
|
- return;
|
566
|
|
- }
|
567
|
|
- String[] files = new File(path).list();
|
568
|
|
- WritableArray arg = Arguments.createArray();
|
569
|
|
- for (String i : files) {
|
570
|
|
- arg.pushString(i);
|
|
639
|
+ static void ls(String path, Promise promise) {
|
|
640
|
+ try {
|
|
641
|
+ path = normalizePath(path);
|
|
642
|
+ File src = new File(path);
|
|
643
|
+ if (!src.exists()) {
|
|
644
|
+ promise.reject("ENOENT", "No such file '" + path + "'");
|
|
645
|
+ return;
|
|
646
|
+ }
|
|
647
|
+ if (!src.isDirectory()) {
|
|
648
|
+ promise.reject("ENOTDIR", "Not a directory '" + path + "'");
|
|
649
|
+ return;
|
|
650
|
+ }
|
|
651
|
+ String[] files = new File(path).list();
|
|
652
|
+ WritableArray arg = Arguments.createArray();
|
|
653
|
+ // File => list(): "If this abstract pathname does not denote a directory, then this method returns null."
|
|
654
|
+ // We excluded that possibility above - ignore the "can produce NullPointerException" warning of the IDE.
|
|
655
|
+ for (String i : files) {
|
|
656
|
+ arg.pushString(i);
|
|
657
|
+ }
|
|
658
|
+ promise.resolve(arg);
|
|
659
|
+ } catch (Exception e) {
|
|
660
|
+ e.printStackTrace();
|
|
661
|
+ promise.reject("EUNSPECIFIED", e.getLocalizedMessage());
|
571
|
662
|
}
|
572
|
|
- callback.invoke(null, arg);
|
573
|
663
|
}
|
574
|
664
|
|
575
|
665
|
/**
|
576
|
666
|
* Create a file by slicing given file path
|
577
|
|
- * @param src Source file path
|
|
667
|
+ * @param path Source file path
|
578
|
668
|
* @param dest Destination of created file
|
579
|
669
|
* @param start Start byte offset in source file
|
580
|
670
|
* @param end End byte offset
|
581
|
671
|
* @param encode NOT IMPLEMENTED
|
582
|
672
|
*/
|
583
|
|
- public static void slice(String src, String dest, int start, int end, String encode, Promise promise) {
|
|
673
|
+ static void slice(String path, String dest, int start, int end, String encode, Promise promise) {
|
584
|
674
|
try {
|
585
|
|
- src = normalizePath(src);
|
586
|
|
- File source = new File(src);
|
587
|
|
- if(!source.exists()) {
|
588
|
|
- promise.reject("RNFetchBlob.slice error", "source file : " + src + " not exists");
|
|
675
|
+ path = normalizePath(path);
|
|
676
|
+ File source = new File(path);
|
|
677
|
+ if(source.isDirectory()){
|
|
678
|
+ promise.reject("EISDIR", "Expecting a file but '" + path + "' is a directory");
|
|
679
|
+ return;
|
|
680
|
+ }
|
|
681
|
+ if(!source.exists()){
|
|
682
|
+ promise.reject("ENOENT", "No such file '" + path + "'");
|
589
|
683
|
return;
|
590
|
684
|
}
|
591
|
|
- long size = source.length();
|
592
|
|
- long max = Math.min(size, end);
|
593
|
|
- long expected = max - start;
|
594
|
|
- long now = 0;
|
595
|
|
- FileInputStream in = new FileInputStream(new File(src));
|
|
685
|
+ int size = (int) source.length();
|
|
686
|
+ int max = Math.min(size, end);
|
|
687
|
+ int expected = max - start;
|
|
688
|
+ int now = 0;
|
|
689
|
+ FileInputStream in = new FileInputStream(new File(path));
|
596
|
690
|
FileOutputStream out = new FileOutputStream(new File(dest));
|
597
|
|
- in.skip(start);
|
598
|
|
- byte [] buffer = new byte[10240];
|
|
691
|
+ int skipped = (int) in.skip(start);
|
|
692
|
+ if (skipped != start) {
|
|
693
|
+ promise.reject("EUNSPECIFIED", "Skipped " + skipped + " instead of the specified " + start + " bytes, size is " + size);
|
|
694
|
+ return;
|
|
695
|
+ }
|
|
696
|
+ byte[] buffer = new byte[10240];
|
599
|
697
|
while(now < expected) {
|
600
|
|
- long read = in.read(buffer, 0, 10240);
|
601
|
|
- long remain = expected - now;
|
|
698
|
+ int read = in.read(buffer, 0, 10240);
|
|
699
|
+ int remain = expected - now;
|
602
|
700
|
if(read <= 0) {
|
603
|
701
|
break;
|
604
|
702
|
}
|
|
@@ -611,7 +709,7 @@ public class RNFetchBlobFS {
|
611
|
709
|
promise.resolve(dest);
|
612
|
710
|
} catch (Exception e) {
|
613
|
711
|
e.printStackTrace();
|
614
|
|
- promise.reject(e.getLocalizedMessage());
|
|
712
|
+ promise.reject("EUNSPECIFIED", e.getLocalizedMessage());
|
615
|
713
|
}
|
616
|
714
|
}
|
617
|
715
|
|
|
@@ -623,18 +721,20 @@ public class RNFetchBlobFS {
|
623
|
721
|
protected Integer doInBackground(String ...args) {
|
624
|
722
|
WritableArray res = Arguments.createArray();
|
625
|
723
|
if(args[0] == null) {
|
626
|
|
- callback.invoke("lstat error: the path specified for lstat is either `null` or `undefined`.");
|
|
724
|
+ callback.invoke("the path specified for lstat is either `null` or `undefined`.");
|
627
|
725
|
return 0;
|
628
|
726
|
}
|
629
|
727
|
File src = new File(args[0]);
|
630
|
728
|
if(!src.exists()) {
|
631
|
|
- callback.invoke("lstat error: failed to list path `" + args[0] + "` for it is not exist or it is not a folder");
|
|
729
|
+ callback.invoke("failed to lstat path `" + args[0] + "` because it does not exist or it is not a folder");
|
632
|
730
|
return 0;
|
633
|
731
|
}
|
634
|
732
|
if(src.isDirectory()) {
|
635
|
733
|
String [] files = src.list();
|
|
734
|
+ // File => list(): "If this abstract pathname does not denote a directory, then this method returns null."
|
|
735
|
+ // We excluded that possibility above - ignore the "can produce NullPointerException" warning of the IDE.
|
636
|
736
|
for(String p : files) {
|
637
|
|
- res.pushMap(statFile ( src.getPath() + "/" + p));
|
|
737
|
+ res.pushMap(statFile(src.getPath() + "/" + p));
|
638
|
738
|
}
|
639
|
739
|
}
|
640
|
740
|
else {
|
|
@@ -648,15 +748,15 @@ public class RNFetchBlobFS {
|
648
|
748
|
|
649
|
749
|
/**
|
650
|
750
|
* show status of a file or directory
|
651
|
|
- * @param path
|
652
|
|
- * @param callback
|
|
751
|
+ * @param path Path
|
|
752
|
+ * @param callback Callback
|
653
|
753
|
*/
|
654
|
754
|
static void stat(String path, Callback callback) {
|
655
|
755
|
try {
|
656
|
756
|
path = normalizePath(path);
|
657
|
757
|
WritableMap result = statFile(path);
|
658
|
758
|
if(result == null)
|
659
|
|
- callback.invoke("stat error: failed to list path `" + path + "` for it is not exist or it is not a folder", null);
|
|
759
|
+ callback.invoke("failed to stat path `" + path + "` because it does not exist or it is not a folder", null);
|
660
|
760
|
else
|
661
|
761
|
callback.invoke(null, result);
|
662
|
762
|
} catch(Exception err) {
|
|
@@ -666,8 +766,8 @@ public class RNFetchBlobFS {
|
666
|
766
|
|
667
|
767
|
/**
|
668
|
768
|
* Basic stat method
|
669
|
|
- * @param path
|
670
|
|
- * @return Stat result of a file or path
|
|
769
|
+ * @param path Path
|
|
770
|
+ * @return Stat Result of a file or path
|
671
|
771
|
*/
|
672
|
772
|
static WritableMap statFile(String path) {
|
673
|
773
|
try {
|
|
@@ -703,9 +803,9 @@ public class RNFetchBlobFS {
|
703
|
803
|
|
704
|
804
|
/**
|
705
|
805
|
* Media scanner scan file
|
706
|
|
- * @param path
|
707
|
|
- * @param mimes
|
708
|
|
- * @param callback
|
|
806
|
+ * @param path Path to file
|
|
807
|
+ * @param mimes Array of MIME type strings
|
|
808
|
+ * @param callback Callback for results
|
709
|
809
|
*/
|
710
|
810
|
void scanFile(String [] path, String[] mimes, final Callback callback) {
|
711
|
811
|
try {
|
|
@@ -720,12 +820,61 @@ public class RNFetchBlobFS {
|
720
|
820
|
}
|
721
|
821
|
}
|
722
|
822
|
|
|
823
|
+ static void hash(String path, String algorithm, Promise promise) {
|
|
824
|
+ try {
|
|
825
|
+ Map<String, String> algorithms = new HashMap<>();
|
|
826
|
+
|
|
827
|
+ algorithms.put("md5", "MD5");
|
|
828
|
+ algorithms.put("sha1", "SHA-1");
|
|
829
|
+ algorithms.put("sha224", "SHA-224");
|
|
830
|
+ algorithms.put("sha256", "SHA-256");
|
|
831
|
+ algorithms.put("sha384", "SHA-384");
|
|
832
|
+ algorithms.put("sha512", "SHA-512");
|
|
833
|
+
|
|
834
|
+ if (!algorithms.containsKey(algorithm)) {
|
|
835
|
+ promise.reject("EINVAL", "Invalid algorithm '" + algorithm + "', must be one of md5, sha1, sha224, sha256, sha384, sha512");
|
|
836
|
+ return;
|
|
837
|
+ }
|
|
838
|
+
|
|
839
|
+ File file = new File(path);
|
|
840
|
+
|
|
841
|
+ if (file.isDirectory()) {
|
|
842
|
+ promise.reject("EISDIR", "Expecting a file but '" + path + "' is a directory");
|
|
843
|
+ return;
|
|
844
|
+ }
|
|
845
|
+
|
|
846
|
+ if (!file.exists()) {
|
|
847
|
+ promise.reject("ENOENT", "No such file '" + path + "'");
|
|
848
|
+ return;
|
|
849
|
+ }
|
|
850
|
+
|
|
851
|
+ MessageDigest md = MessageDigest.getInstance(algorithms.get(algorithm));
|
|
852
|
+
|
|
853
|
+ FileInputStream inputStream = new FileInputStream(path);
|
|
854
|
+ byte[] buffer = new byte[(int)file.length()];
|
|
855
|
+
|
|
856
|
+ int read;
|
|
857
|
+ while ((read = inputStream.read(buffer)) != -1) {
|
|
858
|
+ md.update(buffer, 0, read);
|
|
859
|
+ }
|
|
860
|
+
|
|
861
|
+ StringBuilder hexString = new StringBuilder();
|
|
862
|
+ for (byte digestByte : md.digest())
|
|
863
|
+ hexString.append(String.format("%02x", digestByte));
|
|
864
|
+
|
|
865
|
+ promise.resolve(hexString.toString());
|
|
866
|
+ } catch (Exception e) {
|
|
867
|
+ e.printStackTrace();
|
|
868
|
+ promise.reject("EUNSPECIFIED", e.getLocalizedMessage());
|
|
869
|
+ }
|
|
870
|
+ }
|
|
871
|
+
|
723
|
872
|
/**
|
724
|
873
|
* Create new file at path
|
725
|
874
|
* @param path The destination path of the new file.
|
726
|
875
|
* @param data Initial data of the new file.
|
727
|
876
|
* @param encoding Encoding of initial data.
|
728
|
|
- * @param callback RCT bridge callback.
|
|
877
|
+ * @param promise Promise for Javascript
|
729
|
878
|
*/
|
730
|
879
|
static void createFile(String path, String data, String encoding, Promise promise) {
|
731
|
880
|
try {
|
|
@@ -735,23 +884,22 @@ public class RNFetchBlobFS {
|
735
|
884
|
String orgPath = data.replace(RNFetchBlobConst.FILE_PREFIX, "");
|
736
|
885
|
File src = new File(orgPath);
|
737
|
886
|
if(!src.exists()) {
|
738
|
|
- promise.reject("RNfetchBlob writeFileError", "source file : " + data + "not exists");
|
|
887
|
+ promise.reject("ENOENT", "Source file : " + data + " does not exist");
|
739
|
888
|
return ;
|
740
|
889
|
}
|
741
|
890
|
FileInputStream fin = new FileInputStream(src);
|
742
|
891
|
OutputStream ostream = new FileOutputStream(dest);
|
743
|
|
- byte [] buffer = new byte [10240];
|
|
892
|
+ byte[] buffer = new byte[10240];
|
744
|
893
|
int read = fin.read(buffer);
|
745
|
|
- while(read > 0) {
|
|
894
|
+ while (read > 0) {
|
746
|
895
|
ostream.write(buffer, 0, read);
|
747
|
896
|
read = fin.read(buffer);
|
748
|
897
|
}
|
749
|
898
|
fin.close();
|
750
|
899
|
ostream.close();
|
751
|
|
- }
|
752
|
|
- else {
|
|
900
|
+ } else {
|
753
|
901
|
if (!created) {
|
754
|
|
- Promise.reject("create file error: failed to create file at path `" + path + "` for its parent path may not exists, or the file already exists. If you intended to overwrite the existing file use fs.writeFile instead.");
|
|
902
|
+ promise.reject("EEXIST", "File `" + path + "` already exists");
|
755
|
903
|
return;
|
756
|
904
|
}
|
757
|
905
|
OutputStream ostream = new FileOutputStream(dest);
|
|
@@ -759,7 +907,7 @@ public class RNFetchBlobFS {
|
759
|
907
|
}
|
760
|
908
|
promise.resolve(path);
|
761
|
909
|
} catch(Exception err) {
|
762
|
|
- promise.reject(err.getLocalizedMessage());
|
|
910
|
+ promise.reject("EUNSPECIFIED", err.getLocalizedMessage());
|
763
|
911
|
}
|
764
|
912
|
}
|
765
|
913
|
|
|
@@ -767,30 +915,25 @@ public class RNFetchBlobFS {
|
767
|
915
|
* Create file for ASCII encoding
|
768
|
916
|
* @param path Path of new file.
|
769
|
917
|
* @param data Content of new file
|
770
|
|
- * @param callback JS context callback
|
|
918
|
+ * @param promise JS Promise
|
771
|
919
|
*/
|
772
|
920
|
static void createFileASCII(String path, ReadableArray data, Promise promise) {
|
773
|
921
|
try {
|
774
|
922
|
File dest = new File(path);
|
775
|
|
- if(dest.exists()) {
|
776
|
|
- promise.reject("create file error: failed to create file at path `" + path + "`, file already exists.");
|
777
|
|
- return;
|
778
|
|
- }
|
779
|
923
|
boolean created = dest.createNewFile();
|
780
|
924
|
if(!created) {
|
781
|
|
- promise.reject("create file error: failed to create file at path `" + path + "` for its parent path may not exists");
|
|
925
|
+ promise.reject("EEXIST", "File at path `" + path + "` already exists");
|
782
|
926
|
return;
|
783
|
927
|
}
|
784
|
928
|
OutputStream ostream = new FileOutputStream(dest);
|
785
|
|
- byte [] chunk = new byte[data.size()];
|
786
|
|
- for(int i =0; i<data.size();i++) {
|
|
929
|
+ byte[] chunk = new byte[data.size()];
|
|
930
|
+ for(int i=0; i<data.size(); i++) {
|
787
|
931
|
chunk[i] = (byte) data.getInt(i);
|
788
|
932
|
}
|
789
|
933
|
ostream.write(chunk);
|
790
|
|
- chunk = null;
|
791
|
934
|
promise.resolve(path);
|
792
|
935
|
} catch(Exception err) {
|
793
|
|
- promise.reject(err.getLocalizedMessage());
|
|
936
|
+ promise.reject("EUNSPECIFIED", err.getLocalizedMessage());
|
794
|
937
|
}
|
795
|
938
|
}
|
796
|
939
|
|
|
@@ -814,17 +957,31 @@ public class RNFetchBlobFS {
|
814
|
957
|
* @param callback JS contest callback
|
815
|
958
|
*/
|
816
|
959
|
static void removeSession(ReadableArray paths, final Callback callback) {
|
817
|
|
-
|
818
|
960
|
AsyncTask<ReadableArray, Integer, Integer> task = new AsyncTask<ReadableArray, Integer, Integer>() {
|
819
|
961
|
@Override
|
820
|
962
|
protected Integer doInBackground(ReadableArray ...paths) {
|
821
|
963
|
try {
|
|
964
|
+ ArrayList<String> failuresToDelete = new ArrayList<>();
|
822
|
965
|
for (int i = 0; i < paths[0].size(); i++) {
|
823
|
|
- File f = new File(paths[0].getString(i));
|
824
|
|
- if (f.exists())
|
825
|
|
- f.delete();
|
|
966
|
+ String fileName = paths[0].getString(i);
|
|
967
|
+ File f = new File(fileName);
|
|
968
|
+ if (f.exists()) {
|
|
969
|
+ boolean result = f.delete();
|
|
970
|
+ if (!result) {
|
|
971
|
+ failuresToDelete.add(fileName);
|
|
972
|
+ }
|
|
973
|
+ }
|
|
974
|
+ }
|
|
975
|
+ if (failuresToDelete.isEmpty()) {
|
|
976
|
+ callback.invoke(null, true);
|
|
977
|
+ } else {
|
|
978
|
+ StringBuilder listString = new StringBuilder();
|
|
979
|
+ listString.append("Failed to delete: ");
|
|
980
|
+ for (String s : failuresToDelete) {
|
|
981
|
+ listString.append(s).append(", ");
|
|
982
|
+ }
|
|
983
|
+ callback.invoke(listString.toString());
|
826
|
984
|
}
|
827
|
|
- callback.invoke(null, true);
|
828
|
985
|
} catch(Exception err) {
|
829
|
986
|
callback.invoke(err.getLocalizedMessage());
|
830
|
987
|
}
|
|
@@ -867,6 +1024,7 @@ public class RNFetchBlobFS {
|
867
|
1024
|
this.emitter.emit(streamName, eventData);
|
868
|
1025
|
}
|
869
|
1026
|
|
|
1027
|
+ // "event" always is "data"...
|
870
|
1028
|
private void emitStreamEvent(String streamName, String event, WritableArray data) {
|
871
|
1029
|
WritableMap eventData = Arguments.createMap();
|
872
|
1030
|
eventData.putString("event", event);
|
|
@@ -874,12 +1032,13 @@ public class RNFetchBlobFS {
|
874
|
1032
|
this.emitter.emit(streamName, eventData);
|
875
|
1033
|
}
|
876
|
1034
|
|
877
|
|
- // TODO : should we remove this ?
|
878
|
|
- void emitFSData(String taskId, String event, String data) {
|
|
1035
|
+ // "event" always is "error"...
|
|
1036
|
+ private void emitStreamEvent(String streamName, String event, String code, String message) {
|
879
|
1037
|
WritableMap eventData = Arguments.createMap();
|
880
|
1038
|
eventData.putString("event", event);
|
881
|
|
- eventData.putString("detail", data);
|
882
|
|
- this.emitter.emit("RNFetchBlobStream" + taskId, eventData);
|
|
1039
|
+ eventData.putString("code", code);
|
|
1040
|
+ eventData.putString("detail", message);
|
|
1041
|
+ this.emitter.emit(streamName, eventData);
|
883
|
1042
|
}
|
884
|
1043
|
|
885
|
1044
|
/**
|
|
@@ -887,9 +1046,9 @@ public class RNFetchBlobFS {
|
887
|
1046
|
* the stream is created by Assets Manager, otherwise use FileInputStream.
|
888
|
1047
|
* @param path The file to open stream
|
889
|
1048
|
* @return InputStream instance
|
890
|
|
- * @throws IOException
|
|
1049
|
+ * @throws IOException If the given file does not exist or is a directory FileInputStream will throw a FileNotFoundException
|
891
|
1050
|
*/
|
892
|
|
- static InputStream inputStreamFromPath(String path) throws IOException {
|
|
1051
|
+ private static InputStream inputStreamFromPath(String path) throws IOException {
|
893
|
1052
|
if (path.startsWith(RNFetchBlobConst.FILE_PREFIX_BUNDLE_ASSET)) {
|
894
|
1053
|
return RNFetchBlob.RCTContext.getAssets().open(path.replace(RNFetchBlobConst.FILE_PREFIX_BUNDLE_ASSET, ""));
|
895
|
1054
|
}
|
|
@@ -901,10 +1060,10 @@ public class RNFetchBlobFS {
|
901
|
1060
|
* @param path A file path URI string
|
902
|
1061
|
* @return A boolean value represents if the path exists.
|
903
|
1062
|
*/
|
904
|
|
- static boolean isPathExists(String path) {
|
|
1063
|
+ private static boolean isPathExists(String path) {
|
905
|
1064
|
if(path.startsWith(RNFetchBlobConst.FILE_PREFIX_BUNDLE_ASSET)) {
|
906
|
1065
|
try {
|
907
|
|
- RNFetchBlob.RCTContext.getAssets().open(path.replace(RNFetchBlobConst.FILE_PREFIX_BUNDLE_ASSET, ""));
|
|
1066
|
+ RNFetchBlob.RCTContext.getAssets().open(path.replace(com.RNFetchBlob.RNFetchBlobConst.FILE_PREFIX_BUNDLE_ASSET, ""));
|
908
|
1067
|
} catch (IOException e) {
|
909
|
1068
|
return false;
|
910
|
1069
|
}
|
|
@@ -917,9 +1076,7 @@ public class RNFetchBlobFS {
|
917
|
1076
|
}
|
918
|
1077
|
|
919
|
1078
|
static boolean isAsset(String path) {
|
920
|
|
- if(path != null)
|
921
|
|
- return path.startsWith(RNFetchBlobConst.FILE_PREFIX_BUNDLE_ASSET);
|
922
|
|
- return false;
|
|
1079
|
+ return path != null && path.startsWith(RNFetchBlobConst.FILE_PREFIX_BUNDLE_ASSET);
|
923
|
1080
|
}
|
924
|
1081
|
|
925
|
1082
|
/**
|