瀏覽代碼

Implemenet fs.hash() -- https://github.com/wkh237/react-native-fetch-blob/issues/439 "Feature: Calculate file hash" (#476)

KittenWithHerbs 6 年之前
父節點
當前提交
67649da8be

+ 1
- 0
README.md 查看文件

@@ -594,6 +594,7 @@ File Access APIs
594 594
 - [readFile (0.6.0)](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#readfilepath-encodingpromise)
595 595
 - [readStream](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#readstreampath-encoding-buffersizepromise)
596 596
 - [writeStream](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#writestreampathstring-encodingstring-appendbooleanpromise)
597
+- [hash](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#hashpath-algorithmpromise)
597 598
 - [unlink](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#unlinkpathstringpromise)
598 599
 - [mkdir](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#mkdirpathstringpromise)
599 600
 - [ls](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#lspathstringpromise)

+ 10
- 0
android/src/main/java/com/RNFetchBlob/RNFetchBlob.java 查看文件

@@ -267,11 +267,21 @@ public class RNFetchBlob extends ReactContextBaseJavaModule {
267 267
     }
268 268
 
269 269
     @ReactMethod
270
+    public void hash(final String path, final String algorithm, final Promise promise) {
271
+        threadPool.execute(new Runnable() {
272
+            @Override
273
+            public void run() {
274
+                RNFetchBlobFS.hash(path, algorithm, promise);
275
+            }
276
+        });
277
+    }
278
+
270 279
     /**
271 280
      * @param path Stream file path
272 281
      * @param encoding Stream encoding, should be one of `base64`, `ascii`, and `utf8`
273 282
      * @param bufferSize Stream buffer size, default to 4096 or 4095(base64).
274 283
      */
284
+    @ReactMethod
275 285
     public void readStream(final String path, final String encoding, final int bufferSize, final int tick, final String streamId) {
276 286
         final ReactApplicationContext ctx = this.getReactApplicationContext();
277 287
         fsThreadPool.execute(new Runnable() {

+ 47
- 0
android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java 查看文件

@@ -31,6 +31,7 @@ import java.io.OutputStream;
31 31
 import java.nio.ByteBuffer;
32 32
 import java.nio.charset.Charset;
33 33
 import java.nio.charset.CharsetEncoder;
34
+import java.security.MessageDigest;
34 35
 import java.util.HashMap;
35 36
 import java.util.Map;
36 37
 import java.util.UUID;
@@ -696,6 +697,52 @@ public class RNFetchBlobFS {
696 697
         }
697 698
     }
698 699
 
700
+    static void hash(String path, String algorithm, Promise promise) {
701
+        try {
702
+            Map<String, String> algorithms = new HashMap<>();
703
+
704
+            algorithms.put("md5", "MD5");
705
+            algorithms.put("sha1", "SHA-1");
706
+            algorithms.put("sha224", "SHA-224");
707
+            algorithms.put("sha256", "SHA-256");
708
+            algorithms.put("sha384", "SHA-384");
709
+            algorithms.put("sha512", "SHA-512");
710
+
711
+            if (!algorithms.containsKey(algorithm)) throw new Exception("Invalid hash algorithm");
712
+
713
+            File file = new File(path);
714
+
715
+            if (file.isDirectory()) {
716
+                promise.reject("hash error", "EISDIR: illegal operation on a directory, read");
717
+                return;
718
+            }
719
+
720
+            if (!file.exists()) {
721
+                promise.reject("hash error", "ENOENT: no such file or directory, open '" + path + "'");
722
+                return;
723
+            }
724
+
725
+            MessageDigest md = MessageDigest.getInstance(algorithms.get(algorithm));
726
+
727
+            FileInputStream inputStream = new FileInputStream(path);
728
+            byte[] buffer = new byte[(int)file.length()];
729
+
730
+            int read;
731
+            while ((read = inputStream.read(buffer)) != -1) {
732
+                md.update(buffer, 0, read);
733
+            }
734
+
735
+            StringBuilder hexString = new StringBuilder();
736
+            for (byte digestByte : md.digest())
737
+                hexString.append(String.format("%02x", digestByte));
738
+
739
+            promise.resolve(hexString.toString());
740
+        } catch (Exception ex) {
741
+            ex.printStackTrace();
742
+            promise.reject("hash error", ex.getLocalizedMessage());
743
+        }
744
+    }
745
+
699 746
     /**
700 747
      * Create new file at path
701 748
      * @param path The destination path of the new file.

+ 10
- 0
fs.js 查看文件

@@ -239,6 +239,15 @@ function scanFile(pairs:any):Promise {
239 239
   })
240 240
 }
241 241
 
242
+function hash(path: string, algorithm: string): Promise<string> {
243
+  if(typeof path !== 'string')
244
+    return Promise.reject(new Error('Invalid argument "path" '))
245
+  if(typeof algorithm !== 'string')
246
+    return Promise.reject(new Error('Invalid argument "algorithm" '))
247
+
248
+  return RNFetchBlob.hash(path, algorithm)
249
+}
250
+
242 251
 function cp(path:string, dest:string):Promise<boolean> {
243 252
   return new Promise((resolve, reject) => {
244 253
     RNFetchBlob.cp(path, dest, (err, res) => {
@@ -379,6 +388,7 @@ export default {
379 388
   appendFile,
380 389
   pathForAppGroup,
381 390
   readFile,
391
+  hash,
382 392
   exists,
383 393
   createFile,
384 394
   isDir,

+ 9
- 0
ios/RNFetchBlob/RNFetchBlob.m 查看文件

@@ -461,6 +461,15 @@ RCT_EXPORT_METHOD(readFile:(NSString *)path
461 461
     }];
462 462
 }
463 463
 
464
+#pragma mark - fs.hash
465
+RCT_EXPORT_METHOD(hash:(NSString *)path
466
+                  algorithm:(NSString *)algorithm
467
+                  resolver:(RCTPromiseResolveBlock)resolve
468
+                  rejecter:(RCTPromiseRejectBlock)reject)
469
+{
470
+    [RNFetchBlobFS hash:path algorithm:[NSString stringWithString:algorithm] resolver:resolve rejecter:reject];
471
+}
472
+
464 473
 #pragma mark - fs.readStream
465 474
 RCT_EXPORT_METHOD(readStream:(NSString *)path withEncoding:(NSString *)encoding bufferSize:(int)bufferSize tick:(int)tick streamId:(NSString *)streamId)
466 475
 {

+ 70
- 0
ios/RNFetchBlobFS.m 查看文件

@@ -489,6 +489,76 @@ NSMutableDictionary *fileStreams = nil;
489 489
     }];
490 490
 }
491 491
 
492
+# pragma mark - hash
493
+
494
+RCT_EXPORT_METHOD(hash:(NSString *)filepath
495
+                  algorithm:(NSString *)algorithm
496
+                  resolver:(RCTPromiseResolveBlock)resolve
497
+                  rejecter:(RCTPromiseRejectBlock)reject)
498
+{
499
+  BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:filepath];
500
+
501
+  if (!fileExists) {
502
+    return reject(@"ENOENT", [NSString stringWithFormat:@"ENOENT: no such file or directory, open '%@'", filepath], nil);
503
+  }
504
+
505
+  NSError *error = nil;
506
+
507
+  NSDictionary *attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:filepath error:&error];
508
+
509
+  if (error) {
510
+    return [self reject:reject withError:error];
511
+  }
512
+
513
+  if ([attributes objectForKey:NSFileType] == NSFileTypeDirectory) {
514
+    return reject(@"EISDIR", @"EISDIR: illegal operation on a directory, read", nil);
515
+  }
516
+
517
+  NSData *content = [[NSFileManager defaultManager] contentsAtPath:filepath];
518
+
519
+  NSArray *keys = [NSArray arrayWithObjects:@"md5", @"sha1", @"sha224", @"sha256", @"sha384", @"sha512", nil];
520
+
521
+  NSArray *digestLengths = [NSArray arrayWithObjects:
522
+    @CC_MD5_DIGEST_LENGTH,
523
+    @CC_SHA1_DIGEST_LENGTH,
524
+    @CC_SHA224_DIGEST_LENGTH,
525
+    @CC_SHA256_DIGEST_LENGTH,
526
+    @CC_SHA384_DIGEST_LENGTH,
527
+    @CC_SHA512_DIGEST_LENGTH,
528
+    nil];
529
+
530
+  NSDictionary *keysToDigestLengths = [NSDictionary dictionaryWithObjects:digestLengths forKeys:keys];
531
+
532
+  int digestLength = [[keysToDigestLengths objectForKey:algorithm] intValue];
533
+
534
+  if (!digestLength) {
535
+    return reject(@"Error", [NSString stringWithFormat:@"Invalid hash algorithm '%@'", algorithm], nil);
536
+  }
537
+
538
+  unsigned char buffer[digestLength];
539
+
540
+  if ([algorithm isEqualToString:@"md5"]) {
541
+    CC_MD5(content.bytes, (CC_LONG)content.length, buffer);
542
+  } else if ([algorithm isEqualToString:@"sha1"]) {
543
+    CC_SHA1(content.bytes, (CC_LONG)content.length, buffer);
544
+  } else if ([algorithm isEqualToString:@"sha224"]) {
545
+    CC_SHA224(content.bytes, (CC_LONG)content.length, buffer);
546
+  } else if ([algorithm isEqualToString:@"sha256"]) {
547
+    CC_SHA256(content.bytes, (CC_LONG)content.length, buffer);
548
+  } else if ([algorithm isEqualToString:@"sha384"]) {
549
+    CC_SHA384(content.bytes, (CC_LONG)content.length, buffer);
550
+  } else if ([algorithm isEqualToString:@"sha512"]) {
551
+    CC_SHA512(content.bytes, (CC_LONG)content.length, buffer);
552
+  } else {
553
+    return reject(@"Error", [NSString stringWithFormat:@"Invalid hash algorithm '%@'", algorithm], nil);
554
+  }
555
+
556
+  NSMutableString *output = [NSMutableString stringWithCapacity:digestLength * 2];
557
+  for(int i = 0; i < digestLength; i++)
558
+    [output appendFormat:@"%02x",buffer[i]];
559
+
560
+  resolve(output);
561
+}
492 562
 
493 563
 # pragma mark - mkdir
494 564