Browse Source

Implement ios ASCII encoded data fs method

Ben Hsieh 8 years ago
parent
commit
516d11bab8
2 changed files with 89 additions and 10 deletions
  1. 29
    8
      src/fs.js
  2. 60
    2
      src/ios/RNFetchBlob/RNFetchBlob.m

+ 29
- 8
src/fs.js View File

@@ -56,13 +56,23 @@ function session(name:string):RNFetchBlobSession {
56 56
 }
57 57
 
58 58
 function createFile(path:string, data:string, encoding: 'base64' | 'ascii' | 'utf8'):Promise {
59
+  encoding = encoding || 'utf8'
59 60
   return new Promise((resolve, reject) => {
60
-    RNFetchBlob.createFile(path, data, encoding, (err) => {
61
+    let handler = (err) => {
61 62
       if(err)
62
-        reject(err)
63
+      reject(err)
63 64
       else
64
-        resolve()
65
-    })
65
+      resolve()
66
+    }
67
+    if(encoding.toLowerCase() === 'ascii') {
68
+      if(Array.isArray(data))
69
+        RNFetchBlob.createFileASCII(path, data, handler)
70
+      else
71
+        reject('`data` of ASCII file must be an array contains numbers')
72
+    }
73
+    else {
74
+      RNFetchBlob.createFile(path, data, encoding, handler)
75
+    }
66 76
   })
67 77
 }
68 78
 
@@ -80,13 +90,13 @@ function writeStream(
80 90
 ):Promise<WriteStream> {
81 91
   if(!path)
82 92
     throw Error('RNFetchBlob could not open file stream with empty `path`')
83
-  encoding = encoding || 'base64'
93
+
84 94
   return new Promise((resolve, reject) => {
85 95
     RNFetchBlob.writeStream(path, encoding || 'base64', append || false, (err, streamId:string) => {
86 96
       if(err)
87 97
         reject(err)
88 98
       else
89
-        resolve(new WriteStream(streamId))
99
+        resolve(new WriteStream(streamId, encoding))
90 100
     })
91 101
   })
92 102
 }
@@ -108,8 +118,14 @@ function readStream(
108 118
     throw Error('RNFetchBlob could not open file stream with empty `path`')
109 119
   encoding = encoding || 'utf8'
110 120
   let stream:RNFetchBlobStream = {
121
+    // parse JSON array when encoding is ASCII
111 122
     onData : function(fn) {
112
-      this._onData = fn
123
+      if(encoding.toLowerCase() === 'ascii')
124
+        this._onData = (data) => {
125
+          fn(JSON.parse(data))
126
+        }
127
+      else
128
+        this._onData = fn
113 129
     },
114 130
     onError : function(fn) {
115 131
       this._onError = fn
@@ -313,7 +329,12 @@ class WriteStream {
313 329
   write(data:string) {
314 330
     return new Promise((resolve, reject) => {
315 331
       try {
316
-        RNFetchBlob.writeChunk(this.id, data, (error) => {
332
+        let method = this.encoding === 'ascii' ? 'writeArrayChunk' : 'writeChunk'
333
+        if(this.encoding.toLocaleLowerCase() === 'ascii' && !Array.isArray(data)) {
334
+            reject('ascii input data must be an Array')
335
+            return
336
+        }
337
+        RNFetchBlob[method](this.id, data, (error) => {
317 338
           if(error)
318 339
             reject(error)
319 340
           else

+ 60
- 2
src/ios/RNFetchBlob/RNFetchBlob.m View File

@@ -261,18 +261,44 @@ void runOnMainQueueWithoutDeadlocking(void (^block)(void))
261 261
             // still have data in stream
262 262
             if(len) {
263 263
                 [chunkData appendBytes:(const void *)buf length:len];
264
-                // TODO : file read progress ?
265 264
                 // dispatch data event
266 265
                 NSString * encodedChunk = [NSString alloc];
267 266
                 if( [[self.encoding lowercaseString] isEqualToString:@"utf8"] ) {
268 267
                     encodedChunk = [encodedChunk initWithData:chunkData encoding:NSUTF8StringEncoding];
269 268
                 }
269
+                // when encoding is ASCII, send byte array data
270 270
                 else if ( [[self.encoding lowercaseString] isEqualToString:@"ascii"] ) {
271
-                    encodedChunk = [encodedChunk initWithData:chunkData encoding:NSASCIIStringEncoding];
271
+                    // RCTBridge only emits string data, so we have to create JSON byte array string
272
+                    NSString * asciiStr = @"[";
273
+                    if (chunkData.length > 0)
274
+                    {
275
+                        unsigned char *bytePtr = (unsigned char *)[chunkData bytes];
276
+                        NSInteger byteLen = chunkData.length/sizeof(uint8_t);
277
+                        for (int i = 0; i < byteLen; i++)
278
+                        {
279
+                            uint8_t * byteFromArray = chunkData.bytes;
280
+                            NSInteger val = bytePtr[i];
281
+                            if(i+1 < byteLen)
282
+                                asciiStr = [asciiStr stringByAppendingFormat:@"%d,", val];
283
+                            else
284
+                                asciiStr = [asciiStr stringByAppendingFormat:@"%d", val];
285
+                        }
286
+                    }
287
+                    asciiStr = [asciiStr stringByAppendingString:@"]"];
288
+                    [self.bridge.eventDispatcher
289
+                     sendDeviceEventWithName:streamEventCode
290
+                     body:@{
291
+                            @"event": FS_EVENT_DATA,
292
+                            @"detail": asciiStr
293
+                        }
294
+                     ];
295
+                    return;
272 296
                 }
297
+                // convert byte array to base64 data chunks
273 298
                 else if ( [[self.encoding lowercaseString] isEqualToString:@"base64"] ) {
274 299
                     encodedChunk = [chunkData base64EncodedStringWithOptions:0];
275 300
                 }
301
+                // unknown encoding, send erro event
276 302
                 else {
277 303
                     [self.bridge.eventDispatcher
278 304
                         sendDeviceEventWithName:streamEventCode
@@ -676,6 +702,26 @@ RCT_EXPORT_METHOD(createFile:(NSString *)path data:(NSString *)data encoding:(NS
676 702
 
677 703
 }
678 704
 
705
+// method for create file with ASCII content
706
+RCT_EXPORT_METHOD(createFileASCII:(NSString *)path data:(NSArray *)dataArray callback:(RCTResponseSenderBlock)callback) {
707
+    
708
+    NSFileManager * fm = [NSFileManager defaultManager];
709
+    NSMutableData * fileContent = [NSMutableData alloc];
710
+    
711
+    char bytes[[dataArray count]];
712
+    for(int i = 0; i < dataArray.count; i++) {
713
+        bytes[i] = [[dataArray objectAtIndex:i] charValue];
714
+    }
715
+    [fileContent appendBytes:bytes length:dataArray.count];
716
+    BOOL success = [fm createFileAtPath:path contents:fileContent attributes:NULL];
717
+    
718
+    if(success == YES)
719
+        callback(@[[NSNull null]]);
720
+    else
721
+        callback(@[[NSString stringWithFormat:@"failed to create new file at path %@ please ensure the folder exists"]]);
722
+    
723
+}
724
+
679 725
 
680 726
 RCT_EXPORT_METHOD(exists:(NSString *)path callback:(RCTResponseSenderBlock)callback) {
681 727
     BOOL isDir = NO;
@@ -709,6 +755,18 @@ RCT_EXPORT_METHOD(writeStream:(NSString *)path withEncoding:(NSString *)encoding
709 755
     callback(@[[NSNull null], streamId]);
710 756
 }
711 757
 
758
+RCT_EXPORT_METHOD(writeArrayChunk:(NSString *)streamId withArray:(NSArray *)dataArray callback:(RCTResponseSenderBlock) callback) {
759
+    FetchBlobFS *fs = [[FetchBlobFS getFileStreams] valueForKey:streamId];
760
+    char bytes[[dataArray count]];
761
+    for(int i = 0; i < dataArray.count; i++) {
762
+        bytes[i] = [[dataArray objectAtIndex:i] charValue];
763
+    }
764
+    NSMutableData * data = [NSMutableData alloc];
765
+    [data appendBytes:bytes length:dataArray.count];
766
+    [fs write:data];
767
+    callback(@[[NSNull null]]);
768
+}
769
+
712 770
 RCT_EXPORT_METHOD(writeChunk:(NSString *)streamId withData:(NSString *)data callback:(RCTResponseSenderBlock) callback) {
713 771
     FetchBlobFS *fs = [[FetchBlobFS getFileStreams] valueForKey:streamId];
714 772
     [fs writeEncodeChunk:data];