Skip to content
This repository was archived by the owner on Mar 16, 2019. It is now read-only.

Commit 67649da

Browse files
LionessTesterwkh237
authored andcommitted
Implemenet fs.hash() -- #439 "Feature: Calculate file hash" (#476)
1 parent 873cb80 commit 67649da

File tree

6 files changed

+147
-0
lines changed

6 files changed

+147
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,7 @@ File Access APIs
594594
- [readFile (0.6.0)](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#readfilepath-encodingpromise)
595595
- [readStream](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#readstreampath-encoding-buffersizepromise)
596596
- [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)
597598
- [unlink](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#unlinkpathstringpromise)
598599
- [mkdir](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#mkdirpathstringpromise)
599600
- [ls](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#lspathstringpromise)

android/src/main/java/com/RNFetchBlob/RNFetchBlob.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,11 +267,21 @@ public void run() {
267267
}
268268

269269
@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+
270279
/**
271280
* @param path Stream file path
272281
* @param encoding Stream encoding, should be one of `base64`, `ascii`, and `utf8`
273282
* @param bufferSize Stream buffer size, default to 4096 or 4095(base64).
274283
*/
284+
@ReactMethod
275285
public void readStream(final String path, final String encoding, final int bufferSize, final int tick, final String streamId) {
276286
final ReactApplicationContext ctx = this.getReactApplicationContext();
277287
fsThreadPool.execute(new Runnable() {

android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import java.nio.ByteBuffer;
3232
import java.nio.charset.Charset;
3333
import java.nio.charset.CharsetEncoder;
34+
import java.security.MessageDigest;
3435
import java.util.HashMap;
3536
import java.util.Map;
3637
import java.util.UUID;
@@ -696,6 +697,52 @@ public void onScanCompleted(String s, Uri uri) {
696697
}
697698
}
698699

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+
699746
/**
700747
* Create new file at path
701748
* @param path The destination path of the new file.

fs.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,15 @@ function scanFile(pairs:any):Promise {
239239
})
240240
}
241241

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+
242251
function cp(path:string, dest:string):Promise<boolean> {
243252
return new Promise((resolve, reject) => {
244253
RNFetchBlob.cp(path, dest, (err, res) => {
@@ -379,6 +388,7 @@ export default {
379388
appendFile,
380389
pathForAppGroup,
381390
readFile,
391+
hash,
382392
exists,
383393
createFile,
384394
isDir,

ios/RNFetchBlob/RNFetchBlob.m

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,15 @@ - (NSDictionary *)constantsToExport
461461
}];
462462
}
463463

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+
464473
#pragma mark - fs.readStream
465474
RCT_EXPORT_METHOD(readStream:(NSString *)path withEncoding:(NSString *)encoding bufferSize:(int)bufferSize tick:(int)tick streamId:(NSString *)streamId)
466475
{

ios/RNFetchBlobFS.m

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,76 @@ + (void) readFile:(NSString *)path
489489
}];
490490
}
491491

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+
}
492562

493563
# pragma mark - mkdir
494564

0 commit comments

Comments
 (0)