react-native-blob-util 0.19.9 → 0.19.10

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.
@@ -680,8 +680,7 @@ RCT_EXPORT_METHOD(readFile:(NSString *)path
680
680
  }
681
681
  if([encoding isEqualToString:@"ascii"]) {
682
682
  resolve((NSMutableArray *)content);
683
- }
684
- if([encoding isEqualToString:@"base64"]) {
683
+ } else if([encoding isEqualToString:@"base64"]) {
685
684
  resolve([content base64EncodedStringWithOptions:0]);
686
685
  } else {
687
686
  resolve([[NSString alloc] initWithData:content encoding:NSUTF8StringEncoding]);
@@ -581,6 +581,15 @@ NSMutableDictionary *fileStreams = nil;
581
581
 
582
582
  # pragma mark - hash
583
583
 
584
+ typedef enum {
585
+ HashAlgorithmMD5,
586
+ HashAlgorithmSHA1,
587
+ HashAlgorithmSHA224,
588
+ HashAlgorithmSHA256,
589
+ HashAlgorithmSHA384,
590
+ HashAlgorithmSHA512,
591
+ } HashAlgorithm;
592
+
584
593
  + (void) hash:(NSString *)path
585
594
  algorithm:(NSString *)algorithm
586
595
  resolver:(RCTPromiseResolveBlock)resolve
@@ -611,7 +620,11 @@ NSMutableDictionary *fileStreams = nil;
611
620
  return;
612
621
  }
613
622
 
614
- NSData *content = [[NSFileManager defaultManager] contentsAtPath:path];
623
+ NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingAtPath:path];
624
+ if (fileHandle == nil) {
625
+ reject(@"EUNKNOWN", [NSString stringWithFormat:@"Error opening '%@' for reading", path], error);
626
+ return;
627
+ }
615
628
 
616
629
  NSArray *keys = [NSArray arrayWithObjects:@"md5", @"sha1", @"sha224", @"sha256", @"sha384", @"sha512", nil];
617
630
 
@@ -634,23 +647,97 @@ NSMutableDictionary *fileStreams = nil;
634
647
 
635
648
  unsigned char buffer[digestLength];
636
649
 
650
+ const NSUInteger chunkSize = 1024 * 1024; // 1 Megabyte
651
+ NSData *dataChunk;
652
+
653
+ CC_MD5_CTX md5Context;
654
+ CC_SHA1_CTX sha1Context;
655
+ CC_SHA256_CTX sha256Context;
656
+ CC_SHA512_CTX sha512Context;
657
+ HashAlgorithm hashAlgorithm;
658
+
637
659
  if ([algorithm isEqualToString:@"md5"]) {
638
- CC_MD5(content.bytes, (CC_LONG)content.length, buffer);
660
+ CC_MD5_Init(&md5Context);
661
+ hashAlgorithm = HashAlgorithmMD5;
639
662
  } else if ([algorithm isEqualToString:@"sha1"]) {
640
- CC_SHA1(content.bytes, (CC_LONG)content.length, buffer);
663
+ CC_SHA1_Init(&sha1Context);
664
+ hashAlgorithm = HashAlgorithmSHA1;
641
665
  } else if ([algorithm isEqualToString:@"sha224"]) {
642
- CC_SHA224(content.bytes, (CC_LONG)content.length, buffer);
666
+ CC_SHA224_Init(&sha256Context);
667
+ hashAlgorithm = HashAlgorithmSHA224;
643
668
  } else if ([algorithm isEqualToString:@"sha256"]) {
644
- CC_SHA256(content.bytes, (CC_LONG)content.length, buffer);
669
+ CC_SHA256_Init(&sha256Context);
670
+ hashAlgorithm = HashAlgorithmSHA256;
645
671
  } else if ([algorithm isEqualToString:@"sha384"]) {
646
- CC_SHA384(content.bytes, (CC_LONG)content.length, buffer);
672
+ CC_SHA384_Init(&sha512Context);
673
+ hashAlgorithm = HashAlgorithmSHA384;
647
674
  } else if ([algorithm isEqualToString:@"sha512"]) {
648
- CC_SHA512(content.bytes, (CC_LONG)content.length, buffer);
675
+ CC_SHA512_Init(&sha512Context);
676
+ hashAlgorithm = HashAlgorithmSHA512;
649
677
  } else {
650
678
  reject(@"EINVAL", [NSString stringWithFormat:@"Invalid algorithm '%@', must be one of md5, sha1, sha224, sha256, sha384, sha512", algorithm], nil);
651
679
  return;
652
680
  }
653
681
 
682
+ while (true) {
683
+ @autoreleasepool {
684
+ dataChunk = [fileHandle readDataUpToLength:chunkSize error:&error];
685
+
686
+ if (error) {
687
+ return reject(@"EREAD", [NSString stringWithFormat:@"Error reading file '%@'", path], error);
688
+ break;
689
+ }
690
+
691
+ if (dataChunk == nil || dataChunk.length == 0) {
692
+ break;
693
+ }
694
+
695
+ switch(hashAlgorithm) {
696
+ case HashAlgorithmMD5:
697
+ CC_MD5_Update(&md5Context, [dataChunk bytes], CC_LONG([dataChunk length]));
698
+ break;
699
+ case HashAlgorithmSHA1:
700
+ CC_SHA1_Update(&sha1Context, [dataChunk bytes], CC_LONG([dataChunk length]));
701
+ break;
702
+ case HashAlgorithmSHA224:
703
+ CC_SHA224_Update(&sha256Context, [dataChunk bytes], CC_LONG([dataChunk length]));
704
+ break;
705
+ case HashAlgorithmSHA256:
706
+ CC_SHA256_Update(&sha256Context, [dataChunk bytes], CC_LONG([dataChunk length]));
707
+ break;
708
+ case HashAlgorithmSHA384:
709
+ CC_SHA384_Update(&sha512Context, [dataChunk bytes], CC_LONG([dataChunk length]));
710
+ break;
711
+ case HashAlgorithmSHA512:
712
+ CC_SHA512_Update(&sha512Context, [dataChunk bytes], CC_LONG([dataChunk length]));
713
+ break;
714
+ }
715
+
716
+ dataChunk = nil;
717
+ }
718
+ }
719
+
720
+ switch(hashAlgorithm) {
721
+ case HashAlgorithmMD5:
722
+ CC_MD5_Final(buffer, &md5Context);
723
+ break;
724
+ case HashAlgorithmSHA1:
725
+ CC_SHA1_Final(buffer, &sha1Context);
726
+ break;
727
+ case HashAlgorithmSHA224:
728
+ CC_SHA224_Final(buffer, &sha256Context);
729
+ break;
730
+ case HashAlgorithmSHA256:
731
+ CC_SHA256_Final(buffer, &sha256Context);
732
+ break;
733
+ case HashAlgorithmSHA384:
734
+ CC_SHA384_Final(buffer, &sha512Context);
735
+ break;
736
+ case HashAlgorithmSHA512:
737
+ CC_SHA512_Final(buffer, &sha512Context);
738
+ break;
739
+ }
740
+
654
741
  NSMutableString *output = [NSMutableString stringWithCapacity:digestLength * 2];
655
742
  for(int i = 0; i < digestLength; i++)
656
743
  [output appendFormat:@"%02x",buffer[i]];
@@ -20,7 +20,7 @@
20
20
  #import "RCTBridgeModule.h"
21
21
  #endif
22
22
 
23
- @interface ReactNativeBlobUtilRequest : NSObject <NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDataDelegate>
23
+ @interface ReactNativeBlobUtilRequest : NSObject <NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDataDelegate, NSURLSessionDownloadDelegate>
24
24
 
25
25
  @property (nullable, nonatomic) NSString * taskId;
26
26
  @property (nonatomic) long long expectedBytes;
@@ -33,7 +33,7 @@
33
33
  @property (nullable, nonatomic) NSError * error;
34
34
  @property (nullable, nonatomic) ReactNativeBlobUtilProgress *progressConfig;
35
35
  @property (nullable, nonatomic) ReactNativeBlobUtilProgress *uploadProgressConfig;
36
- @property (nullable, nonatomic, weak) NSURLSessionDataTask *task;
36
+ @property (nullable, nonatomic, weak) NSURLSessionTask *task;
37
37
 
38
38
  - (void) sendRequest:(NSDictionary * _Nullable )options
39
39
  contentLength:(long)contentLength
@@ -167,9 +167,15 @@ typedef NS_ENUM(NSUInteger, ResponseFormat) {
167
167
  respFile = NO;
168
168
  }
169
169
 
170
- NSURLSessionDataTask *task = [session dataTaskWithRequest:req];
171
- [task resume];
172
- self.task = task;
170
+ if(backgroundTask) {
171
+ NSURLSessionDownloadTask *task = [session downloadTaskWithRequest:req];
172
+ [task resume];
173
+ self.task = task;
174
+ } else {
175
+ NSURLSessionDataTask *task = [session dataTaskWithRequest:req];
176
+ [task resume];
177
+ self.task = task;
178
+ }
173
179
 
174
180
  // network status indicator
175
181
  if ([[options objectForKey:CONFIG_INDICATOR] boolValue]) {
@@ -188,6 +194,52 @@ typedef NS_ENUM(NSUInteger, ResponseFormat) {
188
194
 
189
195
  #pragma mark NSURLSession delegate methods
190
196
 
197
+ - (void)configureWriteStream {
198
+ if (respFile)
199
+ {
200
+ @try{
201
+ NSFileManager * fm = [NSFileManager defaultManager];
202
+ NSString * folder = [destPath stringByDeletingLastPathComponent];
203
+
204
+ if (![fm fileExistsAtPath:folder]) {
205
+ [fm createDirectoryAtPath:folder withIntermediateDirectories:YES attributes:NULL error:nil];
206
+ }
207
+
208
+ // if not set overwrite in options, defaults to TRUE
209
+ BOOL overwrite = [options valueForKey:@"overwrite"] == nil ? YES : [[options valueForKey:@"overwrite"] boolValue];
210
+ BOOL appendToExistingFile = [destPath containsString:@"?append=true"];
211
+
212
+ appendToExistingFile = !overwrite;
213
+
214
+ // For solving #141 append response data if the file already exists
215
+ // base on PR#139 @kejinliang
216
+ if (appendToExistingFile) {
217
+ destPath = [destPath stringByReplacingOccurrencesOfString:@"?append=true" withString:@""];
218
+ }
219
+
220
+ if (![fm fileExistsAtPath:destPath]) {
221
+ [fm createFileAtPath:destPath contents:[[NSData alloc] init] attributes:nil];
222
+ }
223
+
224
+ writeStream = [[NSOutputStream alloc] initToFileAtPath:destPath append:appendToExistingFile];
225
+ [writeStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
226
+ [writeStream open];
227
+ }
228
+ @catch(NSException * ex)
229
+ {
230
+ NSLog(@"write file error");
231
+ }
232
+ }
233
+ }
234
+
235
+ - (void)processData:(NSData *)data {
236
+ if (respFile && ![self ShouldTransformFile]) {
237
+ [writeStream write:(const uint8_t *)[data bytes] maxLength:[data length]];
238
+ } else {
239
+ [respData appendData:data];
240
+ }
241
+ }
242
+
191
243
 
192
244
  #pragma mark - Received Response
193
245
  // set expected content length on response received
@@ -278,41 +330,7 @@ typedef NS_ENUM(NSUInteger, ResponseFormat) {
278
330
  NSLog(@"oops");
279
331
  }
280
332
 
281
- if (respFile)
282
- {
283
- @try{
284
- NSFileManager * fm = [NSFileManager defaultManager];
285
- NSString * folder = [destPath stringByDeletingLastPathComponent];
286
-
287
- if (![fm fileExistsAtPath:folder]) {
288
- [fm createDirectoryAtPath:folder withIntermediateDirectories:YES attributes:NULL error:nil];
289
- }
290
-
291
- // if not set overwrite in options, defaults to TRUE
292
- BOOL overwrite = [options valueForKey:@"overwrite"] == nil ? YES : [[options valueForKey:@"overwrite"] boolValue];
293
- BOOL appendToExistingFile = [destPath containsString:@"?append=true"];
294
-
295
- appendToExistingFile = !overwrite;
296
-
297
- // For solving #141 append response data if the file already exists
298
- // base on PR#139 @kejinliang
299
- if (appendToExistingFile) {
300
- destPath = [destPath stringByReplacingOccurrencesOfString:@"?append=true" withString:@""];
301
- }
302
-
303
- if (![fm fileExistsAtPath:destPath]) {
304
- [fm createFileAtPath:destPath contents:[[NSData alloc] init] attributes:nil];
305
- }
306
-
307
- writeStream = [[NSOutputStream alloc] initToFileAtPath:destPath append:appendToExistingFile];
308
- [writeStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
309
- [writeStream open];
310
- }
311
- @catch(NSException * ex)
312
- {
313
- NSLog(@"write file error");
314
- }
315
- }
333
+ [self configureWriteStream];
316
334
 
317
335
  completionHandler(NSURLSessionResponseAllow);
318
336
  }
@@ -339,11 +357,7 @@ typedef NS_ENUM(NSUInteger, ResponseFormat) {
339
357
 
340
358
  // If we need to process the data, we defer writing into the file until the we have all the data, at which point
341
359
  // we can perform the processing and then write into the file
342
- if (respFile && ![self ShouldTransformFile]) {
343
- [writeStream write:(const uint8_t *)[data bytes] maxLength:[data length]];
344
- } else {
345
- [respData appendData:data];
346
- }
360
+ [self processData:data];
347
361
 
348
362
  if (expectedBytes == 0) {
349
363
  return;
@@ -535,5 +549,36 @@ typedef NS_ENUM(NSUInteger, ResponseFormat) {
535
549
  }
536
550
  }
537
551
 
552
+ // NSURLSessionDownloadTask delegates
553
+
554
+ #pragma mark NSURLSessionDownloadTask delegate methods
555
+
556
+ - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location {
557
+
558
+ NSFileManager *fm = [NSFileManager defaultManager];
559
+ NSData *data = [fm contentsAtPath:location.path];
560
+
561
+ [self configureWriteStream];
562
+
563
+ [self processData:data];
564
+
565
+ }
566
+
567
+ - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite {
568
+ if (totalBytesExpectedToWrite == 0) {
569
+ return;
570
+ }
571
+
572
+ NSNumber * now =[NSNumber numberWithFloat:((float)totalBytesWritten/(float)totalBytesExpectedToWrite)];
573
+ if ([self.progressConfig shouldReport:now]) {
574
+ [self.baseModule emitEventDict:EVENT_PROGRESS
575
+ body:@{
576
+ @"taskId": taskId,
577
+ @"written": [NSString stringWithFormat:@"%lld", (long long) totalBytesWritten],
578
+ @"total": [NSString stringWithFormat:@"%lld", (long long) totalBytesExpectedToWrite]
579
+ }
580
+ ];
581
+ }
582
+ }
538
583
 
539
584
  @end
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-blob-util",
3
- "version": "0.19.9",
3
+ "version": "0.19.10",
4
4
  "description": "A module provides upload, download, and files access API. Supports file stream read/write for process large files.",
5
5
  "main": "index",
6
6
  "scripts": {
@@ -10,7 +10,7 @@ Pod::Spec.new do |s|
10
10
  s.requires_arc = true
11
11
  s.license = 'MIT'
12
12
  s.homepage = 'n/a'
13
- s.source = { :git => "https://github.com/RonRadtke/react-native-blob-util" }
13
+ s.source = { :git => "https://github.com/RonRadtke/react-native-blob-util", :tag => "v#{s.version.to_s}" }
14
14
  s.author = 'RonRadtke'
15
15
  s.source_files = 'ios/**/*.{h,m,mm,swift}'
16
16
  s.resource_bundles = {