|  | @@ -42,6 +42,7 @@ NSString *const FS_EVENT_ERROR = @"error";
 | 
	
		
			
			| 42 | 42 |  @synthesize callback;
 | 
	
		
			
			| 43 | 43 |  @synthesize taskId;
 | 
	
		
			
			| 44 | 44 |  @synthesize path;
 | 
	
		
			
			|  | 45 | +@synthesize appendData;
 | 
	
		
			
			| 45 | 46 |  @synthesize bufferSize;
 | 
	
		
			
			| 46 | 47 |  
 | 
	
		
			
			| 47 | 48 |  // static member getter
 | 
	
	
		
			
			|  | @@ -120,8 +121,10 @@ NSString *const FS_EVENT_ERROR = @"error";
 | 
	
		
			
			| 120 | 121 |      return self;
 | 
	
		
			
			| 121 | 122 |  }
 | 
	
		
			
			| 122 | 123 |  
 | 
	
		
			
			| 123 |  | -- (NSString *)openWithPath:(NSString *)destPath {
 | 
	
		
			
			| 124 |  | -    self.outStream = [[NSOutputStream alloc] initToFileAtPath:destPath append:YES];
 | 
	
		
			
			|  | 124 | +// Create file stream for write data
 | 
	
		
			
			|  | 125 | +- (NSString *)openWithPath:(NSString *)destPath encode:(nullable NSString *)encode appendData:(BOOL)append {
 | 
	
		
			
			|  | 126 | +    self.outStream = [[NSOutputStream alloc] initToFileAtPath:destPath append:append];
 | 
	
		
			
			|  | 127 | +    self.encoding = encode;
 | 
	
		
			
			| 125 | 128 |      [self.outStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
 | 
	
		
			
			| 126 | 129 |      [self.outStream open];
 | 
	
		
			
			| 127 | 130 |      NSString *uuid = [[NSUUID UUID] UUIDString];
 | 
	
	
		
			
			|  | @@ -130,6 +133,30 @@ NSString *const FS_EVENT_ERROR = @"error";
 | 
	
		
			
			| 130 | 133 |      return uuid;
 | 
	
		
			
			| 131 | 134 |  }
 | 
	
		
			
			| 132 | 135 |  
 | 
	
		
			
			|  | 136 | +// Write file chunk into an opened stream
 | 
	
		
			
			|  | 137 | +- (void)writeEncodeChunk:(NSString *) chunk {
 | 
	
		
			
			|  | 138 | +    NSMutableData * decodedData = [NSData alloc];
 | 
	
		
			
			|  | 139 | +    if([[self.encoding lowercaseString] isEqualToString:@"base64"]) {
 | 
	
		
			
			|  | 140 | +        decodedData = [chunk dataUsingEncoding:NSUTF8StringEncoding];
 | 
	
		
			
			|  | 141 | +    }
 | 
	
		
			
			|  | 142 | +    if([[self.encoding lowercaseString] isEqualToString:@"utf8"]) {
 | 
	
		
			
			|  | 143 | +        decodedData = [chunk dataUsingEncoding:NSUTF8StringEncoding];
 | 
	
		
			
			|  | 144 | +    }
 | 
	
		
			
			|  | 145 | +    else if([[self.encoding lowercaseString] isEqualToString:@"ascii"]) {
 | 
	
		
			
			|  | 146 | +        decodedData = [chunk dataUsingEncoding:NSASCIIStringEncoding];
 | 
	
		
			
			|  | 147 | +    }
 | 
	
		
			
			|  | 148 | +    NSUInteger left = [chunk length];
 | 
	
		
			
			|  | 149 | +    NSUInteger nwr = 0;
 | 
	
		
			
			|  | 150 | +    do {
 | 
	
		
			
			|  | 151 | +        nwr = [self.outStream write:[decodedData bytes] maxLength:left];
 | 
	
		
			
			|  | 152 | +        if (-1 == nwr) break;
 | 
	
		
			
			|  | 153 | +        left -= nwr;
 | 
	
		
			
			|  | 154 | +    } while (left > 0);
 | 
	
		
			
			|  | 155 | +    if (left) {
 | 
	
		
			
			|  | 156 | +        NSLog(@"stream error: %@", [self.outStream streamError]);
 | 
	
		
			
			|  | 157 | +    }
 | 
	
		
			
			|  | 158 | +}
 | 
	
		
			
			|  | 159 | +
 | 
	
		
			
			| 133 | 160 |  // Write file chunk into an opened stream
 | 
	
		
			
			| 134 | 161 |  - (void)write:(NSData *) chunk {
 | 
	
		
			
			| 135 | 162 |      NSUInteger left = [chunk length];
 | 
	
	
		
			
			|  | @@ -342,11 +369,11 @@ void runOnMainQueueWithoutDeadlocking(void (^block)(void))
 | 
	
		
			
			| 342 | 369 |      // open file stream for write
 | 
	
		
			
			| 343 | 370 |      if( path != nil) {
 | 
	
		
			
			| 344 | 371 |          self.fileStream = [[FetchBlobFS alloc]initWithCallback:self.callback];
 | 
	
		
			
			| 345 |  | -        [self.fileStream openWithPath:path];
 | 
	
		
			
			|  | 372 | +        [self.fileStream openWithPath:path encode:@"ascii" appendData:YES ];
 | 
	
		
			
			| 346 | 373 |      }
 | 
	
		
			
			| 347 | 374 |      else if ( [self.options valueForKey:CONFIG_USE_TEMP]!= nil ) {
 | 
	
		
			
			| 348 | 375 |          self.fileStream = [[FetchBlobFS alloc]initWithCallback:self.callback];
 | 
	
		
			
			| 349 |  | -        [self.fileStream openWithPath:[FetchBlobFS getTempPath:taskId withExtension:ext]];
 | 
	
		
			
			|  | 376 | +        [self.fileStream openWithPath:[FetchBlobFS getTempPath:taskId withExtension:ext] encode:@"ascii" appendData:YES];
 | 
	
		
			
			| 350 | 377 |      }
 | 
	
		
			
			| 351 | 378 |      
 | 
	
		
			
			| 352 | 379 |      NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:req delegate:self startImmediately:NO];
 | 
	
	
		
			
			|  | @@ -620,29 +647,36 @@ RCT_EXPORT_METHOD(fetchBlob:(NSDictionary *)options
 | 
	
		
			
			| 620 | 647 |      });
 | 
	
		
			
			| 621 | 648 |  }
 | 
	
		
			
			| 622 | 649 |  
 | 
	
		
			
			|  | 650 | +RCT_EXPORT_METHOD(exists:(NSString *)path callback:(RCTResponseSenderBlock)callback) {
 | 
	
		
			
			|  | 651 | +    BOOL isDir = NO;
 | 
	
		
			
			|  | 652 | +    BOOL exists = NO;
 | 
	
		
			
			|  | 653 | +    exists = [[NSFileManager defaultManager] fileExistsAtPath:path isDirectory: &isDir];
 | 
	
		
			
			|  | 654 | +    callback(@[@(exists), @(isDir)]);
 | 
	
		
			
			|  | 655 | +
 | 
	
		
			
			|  | 656 | +}
 | 
	
		
			
			|  | 657 | +
 | 
	
		
			
			| 623 | 658 |  RCT_EXPORT_METHOD(readStream:(NSString *)path withEncoding:(NSString *)encoding bufferSize:(int)bufferSize) {
 | 
	
		
			
			| 624 | 659 |      FetchBlobFS *fileStream = [[FetchBlobFS alloc] initWithBridgeRef:self.bridge];
 | 
	
		
			
			| 625 | 660 |      [fileStream readWithPath:path useEncoding:encoding bufferSize:bufferSize];
 | 
	
		
			
			| 626 | 661 |  }
 | 
	
		
			
			| 627 | 662 |  
 | 
	
		
			
			| 628 |  | -RCT_EXPORT_METHOD(writeStream:(NSString *)path withEncoding:(NSString *)encoding callback:(RCTResponseSenderBlock)callback) {
 | 
	
		
			
			| 629 |  | -    FetchBlobFS *fileStream = [[FetchBlobFS alloc] initWithBridgeRef:self.bridge];
 | 
	
		
			
			| 630 |  | -    NSString * streamId = [fileStream openWithPath:path];
 | 
	
		
			
			| 631 |  | -    callback(@[streamId]);
 | 
	
		
			
			|  | 663 | +RCT_EXPORT_METHOD(writeStream:(NSString *)path withEncoding:(NSString *)encoding appendData:(BOOL)append callback:(RCTResponseSenderBlock)callback) {
 | 
	
		
			
			|  | 664 | +    FetchBlobFS * fileStream = [[FetchBlobFS alloc] initWithBridgeRef:self.bridge];
 | 
	
		
			
			|  | 665 | +    NSFileManager * fm = [NSFileManager defaultManager];
 | 
	
		
			
			|  | 666 | +    BOOL isDir = nil;
 | 
	
		
			
			|  | 667 | +    BOOL exist = ![fm fileExistsAtPath:path isDirectory:&isDir];
 | 
	
		
			
			|  | 668 | +    if( exist == NO || isDir == YES) {
 | 
	
		
			
			|  | 669 | +        callback(@[[NSString stringWithFormat:@"target path `%@` may not exists or it's a folder", path]]);
 | 
	
		
			
			|  | 670 | +        return;
 | 
	
		
			
			|  | 671 | +    }
 | 
	
		
			
			|  | 672 | +    NSString * streamId = [fileStream openWithPath:path encode:encoding appendData:append];
 | 
	
		
			
			|  | 673 | +    callback(@[[NSNull null], streamId]);
 | 
	
		
			
			| 632 | 674 |  }
 | 
	
		
			
			| 633 | 675 |  
 | 
	
		
			
			| 634 |  | -RCT_EXPORT_METHOD(writeChunk:(NSString *)streamId withData:(NSString *)data encoding:(NSString *)encode callback:(RCTResponseSenderBlock) callback) {
 | 
	
		
			
			|  | 676 | +RCT_EXPORT_METHOD(writeChunk:(NSString *)streamId withData:(NSString *)data callback:(RCTResponseSenderBlock) callback) {
 | 
	
		
			
			| 635 | 677 |      FetchBlobFS *fs = [[FetchBlobFS getFileStreams] valueForKey:streamId];
 | 
	
		
			
			| 636 |  | -    NSMutableData * decodedData = [NSData alloc];
 | 
	
		
			
			| 637 |  | -    if([[encode lowercaseString] isEqualToString:@"base64"]) {
 | 
	
		
			
			| 638 |  | -        [fs write:[data dataUsingEncoding:NSUTF8StringEncoding]];
 | 
	
		
			
			| 639 |  | -    }
 | 
	
		
			
			| 640 |  | -    if([[encode lowercaseString] isEqualToString:@"utf8"]) {
 | 
	
		
			
			| 641 |  | -        [fs write:[data dataUsingEncoding:NSUTF8StringEncoding]];
 | 
	
		
			
			| 642 |  | -    }
 | 
	
		
			
			| 643 |  | -    else if([[encode lowercaseString] isEqualToString:@"ascii"]) {
 | 
	
		
			
			| 644 |  | -        [fs write:[data dataUsingEncoding:NSASCIIStringEncoding]];
 | 
	
		
			
			| 645 |  | -    }
 | 
	
		
			
			|  | 678 | +    [fs writeEncodeChunk:data];
 | 
	
		
			
			|  | 679 | +    callback(@[[NSNull null]]);
 | 
	
		
			
			| 646 | 680 |  }
 | 
	
		
			
			| 647 | 681 |  
 | 
	
		
			
			| 648 | 682 |  RCT_EXPORT_METHOD(closeStream:(NSString *)streamId callback:(RCTResponseSenderBlock) callback) {
 | 
	
	
		
			
			|  | @@ -720,8 +754,6 @@ RCT_EXPORT_METHOD(mkdir:(NSString *)path callback:(RCTResponseSenderBlock) callb
 | 
	
		
			
			| 720 | 754 |  RCT_EXPORT_METHOD(getEnvironmentDirs:(RCTResponseSenderBlock) callback) {
 | 
	
		
			
			| 721 | 755 |      
 | 
	
		
			
			| 722 | 756 |      callback(@[
 | 
	
		
			
			| 723 |  | -               [FetchBlobFS getPictureDir],
 | 
	
		
			
			| 724 |  | -               [FetchBlobFS getMovieDir],
 | 
	
		
			
			| 725 | 757 |                 [FetchBlobFS getDocumentDir],
 | 
	
		
			
			| 726 | 758 |                 [FetchBlobFS getCacheDir],
 | 
	
		
			
			| 727 | 759 |              ]);
 |