14
14
#import " RCTEventDispatcher.h"
15
15
#import " RNFetchBlobFS.h"
16
16
#import " RNFetchBlobConst.h"
17
+ @import AssetsLibrary;
17
18
18
19
NSMutableDictionary *fileStreams = nil ;
19
20
@@ -49,6 +50,18 @@ +(void) setFileStream:(RNFetchBlobFS *) instance withId:(NSString *) uuid {
49
50
[fileStreams setValue: instance forKey: uuid];
50
51
}
51
52
53
+ +(NSString *) getPathOfAsset : (NSString *)assetURI
54
+ {
55
+ // get file path of an app asset
56
+ if ([assetURI hasPrefix: @" bundle-assets://" ])
57
+ {
58
+ assetURI = [assetURI stringByReplacingOccurrencesOfString: @" bundle-assets://" withString: @" " ];
59
+ assetURI = [[NSBundle mainBundle ] pathForResource: [assetURI stringByDeletingPathExtension ]
60
+ ofType: [assetURI pathExtension ]];
61
+ }
62
+ return assetURI;
63
+ }
64
+
52
65
+ (NSString *) getCacheDir {
53
66
return [NSSearchPathForDirectoriesInDomains (NSCachesDirectory, NSUserDomainMask, YES ) firstObject ];
54
67
}
@@ -84,6 +97,121 @@ + (NSString *) getTempPath:(NSString*)taskId withExtension:(NSString *)ext {
84
97
return tempPath;
85
98
}
86
99
100
+ - (void ) startAssetReadStream : (NSData *)assetUrl
101
+ {
102
+ ALAssetsLibraryAssetForURLResultBlock resultblock = ^(ALAsset *myasset)
103
+ {
104
+ dispatch_queue_t queue = dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT,0 );
105
+ dispatch_async (queue, ^ {
106
+ NSString * streamEventCode = [NSString stringWithFormat: @" RNFetchBlobStream+%@ " , self .path];
107
+ ALAssetRepresentation *rep = [myasset defaultRepresentation ];
108
+ Byte *buffer = (Byte*)malloc (self.bufferSize );
109
+ NSUInteger cursor = [rep getBytes: buffer fromOffset: 0 length: self .bufferSize error: nil ];
110
+ while (cursor > 0 )
111
+ {
112
+ cursor += [rep getBytes: buffer fromOffset: cursor length: self .bufferSize error: nil ];
113
+ NSData * chunkData = [NSData dataWithBytes: buffer length: self .bufferSize];
114
+ NSString * encodedChunk = @" " ;
115
+ // emit data
116
+ if ( [[self .encoding lowercaseString ] isEqualToString: @" utf8" ] ) {
117
+ encodedChunk = [encodedChunk initWithData: chunkData encoding: NSUTF8StringEncoding];
118
+ }
119
+ // when encoding is ASCII, send byte array data
120
+ else if ( [[self .encoding lowercaseString ] isEqualToString: @" ascii" ] ) {
121
+ // RCTBridge only emits string data, so we have to create JSON byte array string
122
+ NSMutableArray * asciiArray = [NSMutableArray array ];
123
+ unsigned char *bytePtr;
124
+ if (chunkData.length > 0 )
125
+ {
126
+ bytePtr = (unsigned char *)[chunkData bytes ];
127
+ NSInteger byteLen = chunkData.length /sizeof (uint8_t );
128
+ for (int i = 0 ; i < byteLen; i++)
129
+ {
130
+ [asciiArray addObject: [NSNumber numberWithChar: bytePtr[i]]];
131
+ }
132
+ }
133
+
134
+ [self .bridge.eventDispatcher
135
+ sendDeviceEventWithName: streamEventCode
136
+ body: @{
137
+ @" event" : FS_EVENT_DATA,
138
+ @" detail" : asciiArray
139
+ }
140
+ ];
141
+ return ;
142
+ }
143
+ // convert byte array to base64 data chunks
144
+ else if ( [[self .encoding lowercaseString ] isEqualToString: @" base64" ] ) {
145
+ encodedChunk = [chunkData base64EncodedStringWithOptions: 0 ];
146
+ }
147
+ // unknown encoding, send error event
148
+ else {
149
+ [self .bridge.eventDispatcher
150
+ sendDeviceEventWithName: streamEventCode
151
+ body: @{
152
+ @" event" : FS_EVENT_ERROR,
153
+ @" detail" : @" unrecognized encoding"
154
+ }
155
+ ];
156
+ return ;
157
+ }
158
+
159
+ [self .bridge.eventDispatcher
160
+ sendDeviceEventWithName: streamEventCode
161
+ body: @{
162
+ @" event" : FS_EVENT_DATA,
163
+ @" detail" : encodedChunk
164
+ }
165
+ ];
166
+ }
167
+ free (buffer);
168
+ });
169
+
170
+ };
171
+
172
+ ALAssetsLibraryAccessFailureBlock failureblock = ^(NSError *error)
173
+ {
174
+
175
+ };
176
+
177
+ if (assetUrl && [assetUrl length ])
178
+ {
179
+ NSURL *asseturl = [NSURL URLWithString: assetUrl];
180
+ ALAssetsLibrary* assetslibrary = [[ALAssetsLibrary alloc ] init ];
181
+ [assetslibrary assetForURL: asseturl
182
+ resultBlock: resultblock
183
+ failureBlock: failureblock];
184
+ }
185
+ }
186
+
187
+ // read system asset file
188
+ + (void ) readAssetFile : (NSData *)assetUrl completionBlock : (void (^)(NSData * content))completionBlock failBlock : (void (^)(NSError * err))failBlock
189
+ {
190
+
191
+ ALAssetsLibraryAssetForURLResultBlock resultblock = ^(ALAsset *myasset)
192
+ {
193
+ ALAssetRepresentation *rep = [myasset defaultRepresentation ];
194
+ Byte *buffer = (Byte*)malloc (rep.size );
195
+ NSUInteger buffered = [rep getBytes: buffer fromOffset: 0.0 length: rep.size error: nil ];
196
+ NSData *data = [NSData dataWithBytesNoCopy: buffer length: buffered freeWhenDone: YES ];
197
+ completionBlock (data);
198
+ };
199
+
200
+ ALAssetsLibraryAccessFailureBlock failureblock = ^(NSError *error)
201
+ {
202
+ failBlock (error);
203
+ };
204
+
205
+ if (assetUrl && [assetUrl length ])
206
+ {
207
+ NSURL *asseturl = [NSURL URLWithString: assetUrl];
208
+ ALAssetsLibrary* assetslibrary = [[ALAssetsLibrary alloc ] init ];
209
+ [assetslibrary assetForURL: asseturl
210
+ resultBlock: resultblock
211
+ failureBlock: failureblock];
212
+ }
213
+ }
214
+
87
215
+ (void ) writeFile : (NSString *)path encoding : (NSString *)encoding data : (NSString *)data append : (BOOL )append resolver : (RCTPromiseResolveBlock)resolve rejecter : (RCTPromiseRejectBlock)reject {
88
216
@try {
89
217
NSFileManager * fm = [NSFileManager defaultManager ];
@@ -175,6 +303,37 @@ + (void) writeFileArray:(NSString *)path data:(NSArray *)data append:(BOOL)appen
175
303
+ (void ) readFile : (NSString *)path encoding : (NSString *)encoding resolver : (RCTPromiseResolveBlock)resolve rejecter : (RCTPromiseRejectBlock)reject {
176
304
@try
177
305
{
306
+ // before start reading file, we have to check if the `path` contains any special prefix
307
+ // if the `path` begins with the following prefix then it will need special handling.
308
+ // "assets-library://" this kind of path usually comes from camera roll, should use it's own readFile implementation
309
+ // "bundle-assets://" this means an asset inside app bundle, usually we only have to convert it into normal file path
310
+ if ([path hasPrefix: @" assets-library://" ])
311
+ {
312
+ [[self class ] readAssetFile: path completionBlock: ^(NSData * content)
313
+ {
314
+ if ([[encoding lowercaseString ] isEqualToString: @" utf8" ]) {
315
+ resolve ([[NSString alloc ] initWithData: content encoding: NSUTF8StringEncoding]);
316
+ }
317
+ else if ([[encoding lowercaseString ] isEqualToString: @" base64" ]) {
318
+ resolve ([content base64EncodedStringWithOptions: 0 ]);
319
+ }
320
+ else if ([[encoding lowercaseString ] isEqualToString: @" ascii" ]) {
321
+ NSMutableArray * resultArray = [NSMutableArray array ];
322
+ char * bytes = [content bytes ];
323
+ for (int i=0 ;i<[content length ];i++) {
324
+ [resultArray addObject: [NSNumber numberWithChar: bytes[i]]];
325
+ }
326
+ resolve (resultArray);
327
+ }
328
+ } failBlock: ^(NSError *err) {
329
+ @throw @" RNFetchBlobFS readFile error" , @" failed to read asset" , path;
330
+ }];
331
+ return ;
332
+ }
333
+
334
+ // normalize the file path
335
+ path = [[self class ]getPathOfAsset:path];
336
+
178
337
NSFileManager * fm = [NSFileManager defaultManager ];
179
338
NSError *err = nil ;
180
339
BOOL exists = [fm fileExistsAtPath: path];
@@ -325,7 +484,16 @@ - (void)readWithPath:(NSString *)path useEncoding:(NSString *)encoding bufferSiz
325
484
self.encoding = encoding;
326
485
self.path = path;
327
486
self.bufferSize = bufferSize;
328
-
487
+
488
+ if ([path hasPrefix: @" assets-library://" ])
489
+ {
490
+
491
+ return ;
492
+ }
493
+
494
+ // normalize file path
495
+ path = [[self class ] getPathOfAsset: path];
496
+
329
497
// NSStream needs a runloop so let's create a run loop for it
330
498
dispatch_queue_t queue = dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT,0 );
331
499
// start NSStream is a runloop
@@ -334,7 +502,7 @@ - (void)readWithPath:(NSString *)path useEncoding:(NSString *)encoding bufferSiz
334
502
forMode: NSDefaultRunLoopMode ];
335
503
[inStream open ];
336
504
[[NSRunLoop currentRunLoop ] run ];
337
-
505
+
338
506
});
339
507
}
340
508
@@ -349,19 +517,6 @@ - (void)closeInStream {
349
517
350
518
}
351
519
352
- void runOnMainQueueWithoutDeadlocking (void (^block)(void ))
353
- {
354
- if ([NSThread isMainThread ])
355
- {
356
- block ();
357
- }
358
- else
359
- {
360
- dispatch_sync (dispatch_get_main_queue (), block);
361
- }
362
- }
363
-
364
-
365
520
#pragma mark RNFetchBlobFS read stream delegate
366
521
367
522
- (void )stream : (NSStream *)stream handleEvent : (NSStreamEvent )eventCode {
0 commit comments