Skip to content

Commit 1488919

Browse files
LionessTesterRick Terrill
authored and
Rick Terrill
committed
Implemenet fs.hash() -- wkh237#439 "Feature: Calculate file hash" (wkh237#476)
# Conflicts: # android/src/main/java/com/RNFetchBlob/RNFetchBlob.java
1 parent 4390b97 commit 1488919

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
@@ -284,11 +284,21 @@ public void run() {
284284
}
285285

286286
@ReactMethod
287+
public void hash(final String path, final String algorithm, final Promise promise) {
288+
threadPool.execute(new Runnable() {
289+
@Override
290+
public void run() {
291+
RNFetchBlobFS.hash(path, algorithm, promise);
292+
}
293+
});
294+
}
295+
287296
/**
288297
* @param path Stream file path
289298
* @param encoding Stream encoding, should be one of `base64`, `ascii`, and `utf8`
290299
* @param bufferSize Stream buffer size, default to 4096 or 4095(base64).
291300
*/
301+
@ReactMethod
292302
public void readStream(final String path, final String encoding, final int bufferSize, final int tick,
293303
final String streamId) {
294304
final ReactApplicationContext ctx = this.getReactApplicationContext();

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;
@@ -694,6 +695,52 @@ public void onScanCompleted(String s, Uri uri) {
694695
}
695696
}
696697

698+
static void hash(String path, String algorithm, Promise promise) {
699+
try {
700+
Map<String, String> algorithms = new HashMap<>();
701+
702+
algorithms.put("md5", "MD5");
703+
algorithms.put("sha1", "SHA-1");
704+
algorithms.put("sha224", "SHA-224");
705+
algorithms.put("sha256", "SHA-256");
706+
algorithms.put("sha384", "SHA-384");
707+
algorithms.put("sha512", "SHA-512");
708+
709+
if (!algorithms.containsKey(algorithm)) throw new Exception("Invalid hash algorithm");
710+
711+
File file = new File(path);
712+
713+
if (file.isDirectory()) {
714+
promise.reject("hash error", "EISDIR: illegal operation on a directory, read");
715+
return;
716+
}
717+
718+
if (!file.exists()) {
719+
promise.reject("hash error", "ENOENT: no such file or directory, open '" + path + "'");
720+
return;
721+
}
722+
723+
MessageDigest md = MessageDigest.getInstance(algorithms.get(algorithm));
724+
725+
FileInputStream inputStream = new FileInputStream(path);
726+
byte[] buffer = new byte[(int)file.length()];
727+
728+
int read;
729+
while ((read = inputStream.read(buffer)) != -1) {
730+
md.update(buffer, 0, read);
731+
}
732+
733+
StringBuilder hexString = new StringBuilder();
734+
for (byte digestByte : md.digest())
735+
hexString.append(String.format("%02x", digestByte));
736+
737+
promise.resolve(hexString.toString());
738+
} catch (Exception ex) {
739+
ex.printStackTrace();
740+
promise.reject("hash error", ex.getLocalizedMessage());
741+
}
742+
}
743+
697744
/**
698745
* Create new file at path
699746
* @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
@@ -238,6 +238,15 @@ function scanFile(pairs:any):Promise {
238238
})
239239
}
240240

241+
function hash(path: string, algorithm: string): Promise<string> {
242+
if(typeof path !== 'string')
243+
return Promise.reject(new Error('Invalid argument "path" '))
244+
if(typeof algorithm !== 'string')
245+
return Promise.reject(new Error('Invalid argument "algorithm" '))
246+
247+
return RNFetchBlob.hash(path, algorithm)
248+
}
249+
241250
function cp(path:string, dest:string):Promise<boolean> {
242251
return new Promise((resolve, reject) => {
243252
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)