react-native-blob-util 0.13.18 → 0.15.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.
- package/README.md +542 -401
- package/android/build.gradle +1 -0
- package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtil.java +89 -25
- package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilBody.java +14 -15
- package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilConfig.java +10 -6
- package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilFS.java +115 -289
- package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilFileTransformer.java +10 -0
- package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilMediaCollection.java +314 -0
- package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilPackage.java +6 -2
- package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilReq.java +46 -22
- package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilStream.java +287 -0
- package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilUtils.java +57 -2
- package/android/src/main/java/com/ReactNativeBlobUtil/Response/ReactNativeBlobUtilFileResp.java +9 -0
- package/android/src/main/java/com/ReactNativeBlobUtil/Utils/FileDescription.java +19 -0
- package/android/src/main/java/com/ReactNativeBlobUtil/Utils/MimeType.java +70 -0
- package/class/ReactNativeBlobUtilBlobResponse.js +1 -1
- package/fs.js +44 -4
- package/index.d.ts +121 -1
- package/index.js +2 -0
- package/ios/ReactNativeBlobUtil/ReactNativeBlobUtil.m +6 -4
- package/ios/ReactNativeBlobUtil.xcodeproj/project.pbxproj +6 -0
- package/ios/ReactNativeBlobUtilConst.h +1 -0
- package/ios/ReactNativeBlobUtilConst.m +1 -0
- package/ios/ReactNativeBlobUtilFS.h +3 -1
- package/ios/ReactNativeBlobUtilFS.m +33 -0
- package/ios/ReactNativeBlobUtilFileTransformer.h +24 -0
- package/ios/ReactNativeBlobUtilFileTransformer.m +21 -0
- package/ios/ReactNativeBlobUtilReqBuilder.m +2 -2
- package/ios/ReactNativeBlobUtilRequest.m +30 -1
- package/mediacollection.js +38 -0
- package/package.json +1 -1
- package/polyfill/Fetch.js +4 -2
- package/scripts/prelink.js +1 -1
- package/types.js +4 -0
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
package com.ReactNativeBlobUtil;
|
|
2
|
+
|
|
3
|
+
import android.net.Uri;
|
|
4
|
+
import android.os.SystemClock;
|
|
5
|
+
import android.util.Base64;
|
|
6
|
+
|
|
7
|
+
import com.facebook.react.bridge.Arguments;
|
|
8
|
+
import com.facebook.react.bridge.Callback;
|
|
9
|
+
import com.facebook.react.bridge.ReactApplicationContext;
|
|
10
|
+
import com.facebook.react.bridge.ReadableArray;
|
|
11
|
+
import com.facebook.react.bridge.WritableArray;
|
|
12
|
+
import com.facebook.react.bridge.WritableMap;
|
|
13
|
+
import com.facebook.react.modules.core.DeviceEventManagerModule;
|
|
14
|
+
|
|
15
|
+
import java.io.BufferedReader;
|
|
16
|
+
import java.io.File;
|
|
17
|
+
import java.io.FileInputStream;
|
|
18
|
+
import java.io.FileNotFoundException;
|
|
19
|
+
import java.io.FileOutputStream;
|
|
20
|
+
import java.io.IOException;
|
|
21
|
+
import java.io.InputStream;
|
|
22
|
+
import java.io.InputStreamReader;
|
|
23
|
+
import java.io.OutputStream;
|
|
24
|
+
import java.nio.charset.Charset;
|
|
25
|
+
import java.util.HashMap;
|
|
26
|
+
import java.util.UUID;
|
|
27
|
+
|
|
28
|
+
public class ReactNativeBlobUtilStream {
|
|
29
|
+
private final DeviceEventManagerModule.RCTDeviceEventEmitter emitter;
|
|
30
|
+
private String encoding = "base64";
|
|
31
|
+
private OutputStream writeStreamInstance = null;
|
|
32
|
+
private static final HashMap<String, ReactNativeBlobUtilStream> fileStreams = new HashMap<>();
|
|
33
|
+
|
|
34
|
+
ReactNativeBlobUtilStream(ReactApplicationContext ctx) {
|
|
35
|
+
this.emitter = ctx.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Create a file stream for read
|
|
40
|
+
*
|
|
41
|
+
* @param path File stream target path
|
|
42
|
+
* @param encoding File stream decoder, should be one of `base64`, `utf8`, `ascii`
|
|
43
|
+
* @param bufferSize Buffer size of read stream, default to 4096 (4095 when encode is `base64`)
|
|
44
|
+
*/
|
|
45
|
+
void readStream(String path, String encoding, int bufferSize, int tick, final String streamId) {
|
|
46
|
+
String resolved = ReactNativeBlobUtilUtils.normalizePath(path);
|
|
47
|
+
if (resolved != null)
|
|
48
|
+
path = resolved;
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
int chunkSize = encoding.equalsIgnoreCase("base64") ? 4095 : 4096;
|
|
52
|
+
if (bufferSize > 0)
|
|
53
|
+
chunkSize = bufferSize;
|
|
54
|
+
|
|
55
|
+
InputStream fs;
|
|
56
|
+
|
|
57
|
+
if (resolved != null && path.startsWith(ReactNativeBlobUtilConst.FILE_PREFIX_BUNDLE_ASSET)) {
|
|
58
|
+
fs = ReactNativeBlobUtil.RCTContext.getAssets().open(path.replace(ReactNativeBlobUtilConst.FILE_PREFIX_BUNDLE_ASSET, ""));
|
|
59
|
+
}
|
|
60
|
+
// fix issue 287
|
|
61
|
+
else if (resolved == null) {
|
|
62
|
+
fs = ReactNativeBlobUtil.RCTContext.getContentResolver().openInputStream(Uri.parse(path));
|
|
63
|
+
} else {
|
|
64
|
+
fs = new FileInputStream(new File(path));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
int cursor = 0;
|
|
68
|
+
boolean error = false;
|
|
69
|
+
|
|
70
|
+
if (encoding.equalsIgnoreCase("utf8")) {
|
|
71
|
+
InputStreamReader isr = new InputStreamReader(fs, Charset.forName("UTF-8"));
|
|
72
|
+
BufferedReader reader = new BufferedReader(isr, chunkSize);
|
|
73
|
+
char[] buffer = new char[chunkSize];
|
|
74
|
+
// read chunks of the string
|
|
75
|
+
while (reader.read(buffer, 0, chunkSize) != -1) {
|
|
76
|
+
String chunk = new String(buffer);
|
|
77
|
+
emitStreamEvent(streamId, "data", chunk);
|
|
78
|
+
if (tick > 0)
|
|
79
|
+
SystemClock.sleep(tick);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
reader.close();
|
|
83
|
+
isr.close();
|
|
84
|
+
} else if (encoding.equalsIgnoreCase("ascii")) {
|
|
85
|
+
byte[] buffer = new byte[chunkSize];
|
|
86
|
+
while ((cursor = fs.read(buffer)) != -1) {
|
|
87
|
+
WritableArray chunk = Arguments.createArray();
|
|
88
|
+
for (int i = 0; i < cursor; i++) {
|
|
89
|
+
chunk.pushInt((int) buffer[i]);
|
|
90
|
+
}
|
|
91
|
+
emitStreamEvent(streamId, "data", chunk);
|
|
92
|
+
if (tick > 0)
|
|
93
|
+
SystemClock.sleep(tick);
|
|
94
|
+
}
|
|
95
|
+
} else if (encoding.equalsIgnoreCase("base64")) {
|
|
96
|
+
byte[] buffer = new byte[chunkSize];
|
|
97
|
+
while ((cursor = fs.read(buffer)) != -1) {
|
|
98
|
+
if (cursor < chunkSize) {
|
|
99
|
+
byte[] copy = new byte[cursor];
|
|
100
|
+
System.arraycopy(buffer, 0, copy, 0, cursor);
|
|
101
|
+
emitStreamEvent(streamId, "data", Base64.encodeToString(copy, Base64.NO_WRAP));
|
|
102
|
+
} else
|
|
103
|
+
emitStreamEvent(streamId, "data", Base64.encodeToString(buffer, Base64.NO_WRAP));
|
|
104
|
+
if (tick > 0)
|
|
105
|
+
SystemClock.sleep(tick);
|
|
106
|
+
}
|
|
107
|
+
} else {
|
|
108
|
+
emitStreamEvent(
|
|
109
|
+
streamId,
|
|
110
|
+
"error",
|
|
111
|
+
"EINVAL",
|
|
112
|
+
"Unrecognized encoding `" + encoding + "`, should be one of `base64`, `utf8`, `ascii`"
|
|
113
|
+
);
|
|
114
|
+
error = true;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (!error)
|
|
118
|
+
emitStreamEvent(streamId, "end", "");
|
|
119
|
+
fs.close();
|
|
120
|
+
|
|
121
|
+
} catch (FileNotFoundException err) {
|
|
122
|
+
emitStreamEvent(
|
|
123
|
+
streamId,
|
|
124
|
+
"error",
|
|
125
|
+
"ENOENT",
|
|
126
|
+
"No such file '" + path + "'"
|
|
127
|
+
);
|
|
128
|
+
} catch (Exception err) {
|
|
129
|
+
emitStreamEvent(
|
|
130
|
+
streamId,
|
|
131
|
+
"error",
|
|
132
|
+
"EUNSPECIFIED",
|
|
133
|
+
"Failed to convert data to " + encoding + " encoded string. This might be because this encoding cannot be used for this data."
|
|
134
|
+
);
|
|
135
|
+
err.printStackTrace();
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Create a write stream and store its instance in ReactNativeBlobUtilFS.fileStreams
|
|
141
|
+
*
|
|
142
|
+
* @param path Target file path
|
|
143
|
+
* @param encoding Should be one of `base64`, `utf8`, `ascii`
|
|
144
|
+
* @param append Flag represents if the file stream overwrite existing content
|
|
145
|
+
* @param callback Callback
|
|
146
|
+
*/
|
|
147
|
+
void writeStream(String path, String encoding, boolean append, Callback callback) {
|
|
148
|
+
try {
|
|
149
|
+
File dest = new File(path);
|
|
150
|
+
File dir = dest.getParentFile();
|
|
151
|
+
|
|
152
|
+
if (!dest.exists()) {
|
|
153
|
+
if (dir != null && !dir.exists()) {
|
|
154
|
+
if (!dir.mkdirs()) {
|
|
155
|
+
callback.invoke("ENOTDIR", "Failed to create parent directory of '" + path + "'");
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
if (!dest.createNewFile()) {
|
|
160
|
+
callback.invoke("ENOENT", "File '" + path + "' does not exist and could not be created");
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
} else if (dest.isDirectory()) {
|
|
164
|
+
callback.invoke("EISDIR", "Expecting a file but '" + path + "' is a directory");
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
OutputStream fs = new FileOutputStream(path, append);
|
|
169
|
+
this.encoding = encoding;
|
|
170
|
+
String streamId = UUID.randomUUID().toString();
|
|
171
|
+
ReactNativeBlobUtilStream.fileStreams.put(streamId, this);
|
|
172
|
+
this.writeStreamInstance = fs;
|
|
173
|
+
callback.invoke(null, null, streamId);
|
|
174
|
+
} catch (Exception err) {
|
|
175
|
+
callback.invoke("EUNSPECIFIED", "Failed to create write stream at path `" + path + "`; " + err.getLocalizedMessage());
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Write a chunk of data into a file stream.
|
|
181
|
+
*
|
|
182
|
+
* @param streamId File stream ID
|
|
183
|
+
* @param data Data chunk in string format
|
|
184
|
+
* @param callback JS context callback
|
|
185
|
+
*/
|
|
186
|
+
static void writeChunk(String streamId, String data, Callback callback) {
|
|
187
|
+
ReactNativeBlobUtilStream fs = fileStreams.get(streamId);
|
|
188
|
+
assert fs != null;
|
|
189
|
+
OutputStream stream = fs.writeStreamInstance;
|
|
190
|
+
byte[] chunk = ReactNativeBlobUtilUtils.stringToBytes(data, fs.encoding);
|
|
191
|
+
try {
|
|
192
|
+
stream.write(chunk);
|
|
193
|
+
callback.invoke();
|
|
194
|
+
} catch (Exception e) {
|
|
195
|
+
callback.invoke(e.getLocalizedMessage());
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Write data using ascii array
|
|
201
|
+
*
|
|
202
|
+
* @param streamId File stream ID
|
|
203
|
+
* @param data Data chunk in ascii array format
|
|
204
|
+
* @param callback JS context callback
|
|
205
|
+
*/
|
|
206
|
+
static void writeArrayChunk(String streamId, ReadableArray data, Callback callback) {
|
|
207
|
+
try {
|
|
208
|
+
ReactNativeBlobUtilStream fs = fileStreams.get(streamId);
|
|
209
|
+
assert fs != null;
|
|
210
|
+
OutputStream stream = fs.writeStreamInstance;
|
|
211
|
+
byte[] chunk = new byte[data.size()];
|
|
212
|
+
for (int i = 0; i < data.size(); i++) {
|
|
213
|
+
chunk[i] = (byte) data.getInt(i);
|
|
214
|
+
}
|
|
215
|
+
stream.write(chunk);
|
|
216
|
+
callback.invoke();
|
|
217
|
+
} catch (Exception e) {
|
|
218
|
+
callback.invoke(e.getLocalizedMessage());
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Close file write stream by ID
|
|
224
|
+
*
|
|
225
|
+
* @param streamId Stream ID
|
|
226
|
+
* @param callback JS context callback
|
|
227
|
+
*/
|
|
228
|
+
static void closeStream(String streamId, Callback callback) {
|
|
229
|
+
try {
|
|
230
|
+
ReactNativeBlobUtilStream fs = fileStreams.get(streamId);
|
|
231
|
+
assert fs != null;
|
|
232
|
+
OutputStream stream = fs.writeStreamInstance;
|
|
233
|
+
fileStreams.remove(streamId);
|
|
234
|
+
stream.close();
|
|
235
|
+
callback.invoke();
|
|
236
|
+
} catch (Exception err) {
|
|
237
|
+
callback.invoke(err.getLocalizedMessage());
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Private method for emit read stream event.
|
|
243
|
+
*
|
|
244
|
+
* @param streamName ID of the read stream
|
|
245
|
+
* @param event Event name, `data`, `end`, `error`, etc.
|
|
246
|
+
* @param data Event data
|
|
247
|
+
*/
|
|
248
|
+
private void emitStreamEvent(String streamName, String event, String data) {
|
|
249
|
+
WritableMap eventData = Arguments.createMap();
|
|
250
|
+
eventData.putString("event", event);
|
|
251
|
+
eventData.putString("detail", data);
|
|
252
|
+
this.emitter.emit(streamName, eventData);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// "event" always is "data"...
|
|
256
|
+
private void emitStreamEvent(String streamName, String event, WritableArray data) {
|
|
257
|
+
WritableMap eventData = Arguments.createMap();
|
|
258
|
+
eventData.putString("event", event);
|
|
259
|
+
eventData.putArray("detail", data);
|
|
260
|
+
this.emitter.emit(streamName, eventData);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// "event" always is "error"...
|
|
264
|
+
private void emitStreamEvent(String streamName, String event, String code, String message) {
|
|
265
|
+
WritableMap eventData = Arguments.createMap();
|
|
266
|
+
eventData.putString("event", event);
|
|
267
|
+
eventData.putString("code", code);
|
|
268
|
+
eventData.putString("detail", message);
|
|
269
|
+
this.emitter.emit(streamName, eventData);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Get input stream of the given path, when the path is a string starts with bundle-assets://
|
|
274
|
+
* the stream is created by Assets Manager, otherwise use FileInputStream.
|
|
275
|
+
*
|
|
276
|
+
* @param path The file to open stream
|
|
277
|
+
* @return InputStream instance
|
|
278
|
+
* @throws IOException If the given file does not exist or is a directory FileInputStream will throw a FileNotFoundException
|
|
279
|
+
*/
|
|
280
|
+
public static InputStream inputStreamFromPath(String path) throws IOException {
|
|
281
|
+
if (path.startsWith(ReactNativeBlobUtilConst.FILE_PREFIX_BUNDLE_ASSET)) {
|
|
282
|
+
return ReactNativeBlobUtil.RCTContext.getAssets().open(path.replace(ReactNativeBlobUtilConst.FILE_PREFIX_BUNDLE_ASSET, ""));
|
|
283
|
+
}
|
|
284
|
+
return new FileInputStream(new File(path));
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
}
|
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
package com.ReactNativeBlobUtil;
|
|
2
2
|
|
|
3
|
+
import android.net.Uri;
|
|
4
|
+
import android.util.Base64;
|
|
5
|
+
|
|
6
|
+
import com.ReactNativeBlobUtil.Utils.PathResolver;
|
|
3
7
|
import com.facebook.react.bridge.Arguments;
|
|
4
8
|
import com.facebook.react.bridge.WritableMap;
|
|
5
9
|
import com.facebook.react.modules.core.DeviceEventManagerModule;
|
|
6
10
|
|
|
11
|
+
import java.nio.charset.Charset;
|
|
7
12
|
import java.security.MessageDigest;
|
|
8
13
|
import java.security.cert.CertificateException;
|
|
14
|
+
import java.util.Locale;
|
|
9
15
|
|
|
10
16
|
import javax.net.ssl.HostnameVerifier;
|
|
11
17
|
import javax.net.ssl.SSLContext;
|
|
@@ -30,7 +36,7 @@ public class ReactNativeBlobUtilUtils {
|
|
|
30
36
|
StringBuilder sb = new StringBuilder();
|
|
31
37
|
|
|
32
38
|
for (byte b : digest) {
|
|
33
|
-
sb.append(String.format("%02x", b & 0xff));
|
|
39
|
+
sb.append(String.format(Locale.ROOT, "%02x", b & 0xff));
|
|
34
40
|
}
|
|
35
41
|
|
|
36
42
|
result = sb.toString();
|
|
@@ -75,7 +81,7 @@ public class ReactNativeBlobUtilUtils {
|
|
|
75
81
|
// Install the all-trusting trust manager
|
|
76
82
|
final SSLContext sslContext = SSLContext.getInstance("SSL");
|
|
77
83
|
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
|
|
78
|
-
// Create an ssl
|
|
84
|
+
// Create an ssl socLket factory with our all-trusting manager
|
|
79
85
|
final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
|
|
80
86
|
|
|
81
87
|
OkHttpClient.Builder builder = client.newBuilder();
|
|
@@ -92,4 +98,53 @@ public class ReactNativeBlobUtilUtils {
|
|
|
92
98
|
throw new RuntimeException(e);
|
|
93
99
|
}
|
|
94
100
|
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* String to byte converter method
|
|
104
|
+
*
|
|
105
|
+
* @param data Raw data in string format
|
|
106
|
+
* @param encoding Decoder name
|
|
107
|
+
* @return Converted data byte array
|
|
108
|
+
*/
|
|
109
|
+
public static byte[] stringToBytes(String data, String encoding) {
|
|
110
|
+
if (encoding.equalsIgnoreCase("ascii")) {
|
|
111
|
+
return data.getBytes(Charset.forName("US-ASCII"));
|
|
112
|
+
} else if (encoding.toLowerCase(Locale.ROOT).contains("base64")) {
|
|
113
|
+
return Base64.decode(data, Base64.NO_WRAP);
|
|
114
|
+
|
|
115
|
+
} else if (encoding.equalsIgnoreCase("utf8")) {
|
|
116
|
+
return data.getBytes(Charset.forName("UTF-8"));
|
|
117
|
+
}
|
|
118
|
+
return data.getBytes(Charset.forName("US-ASCII"));
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Normalize the path, remove URI scheme (xxx://) so that we can handle it.
|
|
123
|
+
*
|
|
124
|
+
* @param path URI string.
|
|
125
|
+
* @return Normalized string
|
|
126
|
+
*/
|
|
127
|
+
public static String normalizePath(String path) {
|
|
128
|
+
if (path == null)
|
|
129
|
+
return null;
|
|
130
|
+
if (!path.matches("\\w+\\:.*"))
|
|
131
|
+
return path;
|
|
132
|
+
if (path.startsWith("file://")) {
|
|
133
|
+
return path.replace("file://", "");
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
Uri uri = Uri.parse(path);
|
|
137
|
+
if (path.startsWith(ReactNativeBlobUtilConst.FILE_PREFIX_BUNDLE_ASSET)) {
|
|
138
|
+
return path;
|
|
139
|
+
} else
|
|
140
|
+
return PathResolver.getRealPathFromURI(ReactNativeBlobUtil.RCTContext, uri);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
public static boolean isAsset(String path) {
|
|
144
|
+
return path != null && path.startsWith(ReactNativeBlobUtilConst.FILE_PREFIX_BUNDLE_ASSET);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
public static boolean isContentUri(String path) {
|
|
148
|
+
return path != null && path.startsWith(ReactNativeBlobUtilConst.FILE_PREFIX_CONTENT);
|
|
149
|
+
}
|
|
95
150
|
}
|
package/android/src/main/java/com/ReactNativeBlobUtil/Response/ReactNativeBlobUtilFileResp.java
CHANGED
|
@@ -35,6 +35,11 @@ public class ReactNativeBlobUtilFileResp extends ResponseBody {
|
|
|
35
35
|
FileOutputStream ofStream;
|
|
36
36
|
boolean isEndMarkerReceived;
|
|
37
37
|
|
|
38
|
+
public ReactNativeBlobUtilFileResp(ResponseBody body) {
|
|
39
|
+
super();
|
|
40
|
+
this.originalBody = body;
|
|
41
|
+
}
|
|
42
|
+
|
|
38
43
|
public ReactNativeBlobUtilFileResp(ReactApplicationContext ctx, String taskId, ResponseBody body, String path, boolean overwrite) throws IOException {
|
|
39
44
|
super();
|
|
40
45
|
this.rctContext = ctx;
|
|
@@ -67,6 +72,10 @@ public class ReactNativeBlobUtilFileResp extends ResponseBody {
|
|
|
67
72
|
|
|
68
73
|
@Override
|
|
69
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
|
+
}
|
|
70
79
|
return originalBody.contentLength();
|
|
71
80
|
}
|
|
72
81
|
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
package com.ReactNativeBlobUtil.Utils;
|
|
2
|
+
|
|
3
|
+
import android.webkit.MimeTypeMap;
|
|
4
|
+
|
|
5
|
+
public class FileDescription {
|
|
6
|
+
public String name;
|
|
7
|
+
public String partentFolder;
|
|
8
|
+
public String mimeType;
|
|
9
|
+
|
|
10
|
+
public FileDescription(String n, String mT, String pF) {
|
|
11
|
+
name = n;
|
|
12
|
+
partentFolder = pF != null ? pF : "";
|
|
13
|
+
mimeType = mT;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
public String getFullPath(){
|
|
17
|
+
return partentFolder + "/" + MimeType.getFullFileName(name, mimeType);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
package com.ReactNativeBlobUtil.Utils;
|
|
2
|
+
|
|
3
|
+
import android.webkit.MimeTypeMap;
|
|
4
|
+
|
|
5
|
+
import org.apache.commons.lang3.StringUtils;
|
|
6
|
+
|
|
7
|
+
public class MimeType {
|
|
8
|
+
static String UNKNOWN = "*/*";
|
|
9
|
+
static String BINARY_FILE = "application/octet-stream";
|
|
10
|
+
static String IMAGE = "image/*";
|
|
11
|
+
static String AUDIO = "audio/*";
|
|
12
|
+
static String VIDEO = "video/*";
|
|
13
|
+
static String TEXT = "text/*";
|
|
14
|
+
static String FONT = "font/*";
|
|
15
|
+
static String APPLICATION = "application/*";
|
|
16
|
+
static String CHEMICAL = "chemical/*";
|
|
17
|
+
static String MODEL = "model/*";
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* * Given `name` = `ABC` AND `mimeType` = `video/mp4`, then return `ABC.mp4`
|
|
21
|
+
* * Given `name` = `ABC` AND `mimeType` = `null`, then return `ABC`
|
|
22
|
+
* * Given `name` = `ABC.mp4` AND `mimeType` = `video/mp4`, then return `ABC.mp4`
|
|
23
|
+
*
|
|
24
|
+
* @param name can have file extension or not
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
public static String getFullFileName(String name, String mimeType) {
|
|
28
|
+
// Prior to API 29, MimeType.BINARY_FILE has no file extension
|
|
29
|
+
String ext = MimeType.getExtensionFromMimeType(mimeType);
|
|
30
|
+
if (ext.isEmpty() || name.endsWith("." + "ext")) return name;
|
|
31
|
+
else {
|
|
32
|
+
String fn = name + "." + ext;
|
|
33
|
+
if (fn.endsWith(".")) return StringUtils.stripEnd(fn, ".");
|
|
34
|
+
else return fn;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Some mime types return no file extension on older API levels. This function adds compatibility accross API levels.
|
|
40
|
+
*
|
|
41
|
+
* @see this.getExtensionFromMimeTypeOrFileName
|
|
42
|
+
*/
|
|
43
|
+
|
|
44
|
+
public static String getExtensionFromMimeType(String mimeType) {
|
|
45
|
+
if (mimeType != null) {
|
|
46
|
+
if (mimeType.equals(BINARY_FILE)) return "bin";
|
|
47
|
+
else return MimeTypeMap.getSingleton().getExtensionFromMimeType(mimeType);
|
|
48
|
+
} else return "";
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* @see this.getExtensionFromMimeType
|
|
53
|
+
*/
|
|
54
|
+
public static String getExtensionFromMimeTypeOrFileName(String mimeType, String filename) {
|
|
55
|
+
if (mimeType == null || mimeType.equals(UNKNOWN)) return StringUtils.substringAfterLast(filename, ".");
|
|
56
|
+
else return getExtensionFromMimeType(mimeType);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Some file types return no mime type on older API levels. This function adds compatibility across API levels.
|
|
61
|
+
*/
|
|
62
|
+
public static String getMimeTypeFromExtension(String fileExtension) {
|
|
63
|
+
if (fileExtension.equals("bin")) return BINARY_FILE;
|
|
64
|
+
else {
|
|
65
|
+
String mt = MimeTypeMap.getSingleton().getMimeTypeFromExtension(fileExtension);
|
|
66
|
+
if (mt != null) return mt;
|
|
67
|
+
else return UNKNOWN;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
package/fs.js
CHANGED
|
@@ -23,7 +23,8 @@ const dirs = {
|
|
|
23
23
|
SDCardDir: ReactNativeBlobUtil.SDCardDir, // Depracated
|
|
24
24
|
SDCardApplicationDir: ReactNativeBlobUtil.SDCardApplicationDir, // Deprecated
|
|
25
25
|
MainBundleDir: ReactNativeBlobUtil.MainBundleDir,
|
|
26
|
-
LibraryDir: ReactNativeBlobUtil.LibraryDir
|
|
26
|
+
LibraryDir: ReactNativeBlobUtil.LibraryDir,
|
|
27
|
+
ApplicationSupportDir: ReactNativeBlobUtil.ApplicationSupportDir
|
|
27
28
|
};
|
|
28
29
|
|
|
29
30
|
function addCode(code: string, error: Error): Error {
|
|
@@ -159,7 +160,20 @@ function readFile(path: string, encoding: string = 'utf8'): Promise<any> {
|
|
|
159
160
|
if (typeof path !== 'string') {
|
|
160
161
|
return Promise.reject(addCode('EINVAL', new TypeError('Missing argument "path" ')));
|
|
161
162
|
}
|
|
162
|
-
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);
|
|
163
177
|
}
|
|
164
178
|
|
|
165
179
|
/**
|
|
@@ -185,7 +199,31 @@ function writeFile(path: string, data: string | Array<number>, encoding: ?string
|
|
|
185
199
|
return Promise.reject(addCode('EINVAL', new TypeError(`"data" must be a String when encoding is "utf8" or "base64", but it is "${typeof data}"`)));
|
|
186
200
|
}
|
|
187
201
|
else
|
|
188
|
-
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)
|
|
189
227
|
}
|
|
190
228
|
}
|
|
191
229
|
|
|
@@ -205,7 +243,7 @@ function appendFile(path: string, data: string | Array<number>, encoding?: strin
|
|
|
205
243
|
return Promise.reject(addCode('EINVAL'), new TypeError(`"data" must be a String when encoding is "utf8" or "base64", but it is "${typeof data}"`));
|
|
206
244
|
}
|
|
207
245
|
else
|
|
208
|
-
return ReactNativeBlobUtil.writeFile(path, encoding, data, true);
|
|
246
|
+
return ReactNativeBlobUtil.writeFile(path, encoding, data, false, true);
|
|
209
247
|
}
|
|
210
248
|
}
|
|
211
249
|
|
|
@@ -414,6 +452,8 @@ export default {
|
|
|
414
452
|
cp,
|
|
415
453
|
writeStream,
|
|
416
454
|
writeFile,
|
|
455
|
+
writeFileWithTransform,
|
|
456
|
+
readFileWithTransform,
|
|
417
457
|
appendFile,
|
|
418
458
|
pathForAppGroup,
|
|
419
459
|
syncPathAppGroup,
|