split-hash 0.3.2 → 0.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/nodejs/split-hash-validator.d.ts +3 -3
- package/lib/nodejs/split-hash-validator.js +22 -16
- package/lib/nodejs/split-hash-validator.js.map +1 -1
- package/lib/nodejs/split-hash.js +11 -10
- package/lib/nodejs/split-hash.js.map +1 -1
- package/lib/whatwg/split-hash.js +11 -9
- package/lib/whatwg/split-hash.js.map +1 -1
- package/package.json +3 -2
- package/src/nodejs/split-hash-validator.ts +31 -16
- package/src/nodejs/split-hash.ts +13 -10
- package/src/whatwg/split-hash.ts +12 -9
|
@@ -5,13 +5,13 @@ import { CustomError } from '@blackglory/errors';
|
|
|
5
5
|
import { ProgressiveHashFactory } from './types.js';
|
|
6
6
|
export declare class SplitHashValidator<T> extends Transform {
|
|
7
7
|
private digests;
|
|
8
|
-
private
|
|
8
|
+
private blockSizeBytes;
|
|
9
9
|
private createHash;
|
|
10
10
|
private equals;
|
|
11
11
|
private hash;
|
|
12
|
-
private
|
|
12
|
+
private currentBlockBytes;
|
|
13
13
|
private digestIndex;
|
|
14
|
-
constructor(digests: T[],
|
|
14
|
+
constructor(digests: T[], blockSizeBytes: number, createHash: ProgressiveHashFactory<T>, equals?: (a: T, b: T) => boolean);
|
|
15
15
|
_transform(chunk: Buffer, encoding: BufferEncoding, callback: TransformCallback): void;
|
|
16
16
|
_flush(callback: TransformCallback): void;
|
|
17
17
|
}
|
|
@@ -1,40 +1,44 @@
|
|
|
1
1
|
import { Transform } from 'stream';
|
|
2
|
-
import { CustomError } from '@blackglory/errors';
|
|
2
|
+
import { assert, CustomError } from '@blackglory/errors';
|
|
3
|
+
import { isUndefined } from 'extra-utils';
|
|
3
4
|
export class SplitHashValidator extends Transform {
|
|
4
|
-
constructor(digests,
|
|
5
|
+
constructor(digests, blockSizeBytes, createHash, equals = Object.is) {
|
|
6
|
+
assert(blockSizeBytes > 0, 'The parameter blockSizeBytes must be greater than zero');
|
|
5
7
|
super();
|
|
6
8
|
this.digests = digests;
|
|
7
|
-
this.
|
|
9
|
+
this.blockSizeBytes = blockSizeBytes;
|
|
8
10
|
this.createHash = createHash;
|
|
9
11
|
this.equals = equals;
|
|
10
12
|
this.hash = this.createHash();
|
|
11
|
-
this.
|
|
13
|
+
this.currentBlockBytes = 0;
|
|
12
14
|
this.digestIndex = 0;
|
|
13
15
|
}
|
|
14
16
|
_transform(chunk, encoding, callback) {
|
|
15
|
-
if (this.
|
|
17
|
+
if (this.currentBlockBytes + chunk.length < this.blockSizeBytes) {
|
|
16
18
|
this.hash.update(chunk);
|
|
17
|
-
this.
|
|
19
|
+
this.currentBlockBytes += chunk.length;
|
|
18
20
|
}
|
|
19
21
|
else {
|
|
20
22
|
let offset = 0;
|
|
21
23
|
while (true) {
|
|
22
|
-
const
|
|
23
|
-
const slice = chunk.slice(offset, offset +
|
|
24
|
-
if (slice.length ===
|
|
24
|
+
const remainingBlockBytes = this.blockSizeBytes - this.currentBlockBytes;
|
|
25
|
+
const slice = chunk.slice(offset, offset + remainingBlockBytes);
|
|
26
|
+
if (slice.length === remainingBlockBytes) {
|
|
25
27
|
this.hash.update(slice);
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
+
const currentBlockBytes = this.hash.digest();
|
|
29
|
+
const correctDigest = this.digests[this.digestIndex];
|
|
30
|
+
if (isUndefined(correctDigest) ||
|
|
31
|
+
!this.equals(correctDigest, currentBlockBytes)) {
|
|
28
32
|
return callback(new NotMatchedError());
|
|
29
33
|
}
|
|
30
34
|
this.digestIndex++;
|
|
31
35
|
this.hash = this.createHash();
|
|
32
|
-
this.
|
|
36
|
+
this.currentBlockBytes = 0;
|
|
33
37
|
offset += slice.length;
|
|
34
38
|
}
|
|
35
39
|
else {
|
|
36
40
|
this.hash.update(slice);
|
|
37
|
-
this.
|
|
41
|
+
this.currentBlockBytes += slice.length;
|
|
38
42
|
break;
|
|
39
43
|
}
|
|
40
44
|
}
|
|
@@ -42,9 +46,11 @@ export class SplitHashValidator extends Transform {
|
|
|
42
46
|
callback(null, chunk);
|
|
43
47
|
}
|
|
44
48
|
_flush(callback) {
|
|
45
|
-
if (this.
|
|
46
|
-
const
|
|
47
|
-
|
|
49
|
+
if (this.currentBlockBytes > 0) {
|
|
50
|
+
const currentBlockDigest = this.hash.digest();
|
|
51
|
+
const correctDigest = this.digests[this.digestIndex];
|
|
52
|
+
if (isUndefined(correctDigest) ||
|
|
53
|
+
!this.equals(correctDigest, currentBlockDigest)) {
|
|
48
54
|
return callback(new NotMatchedError());
|
|
49
55
|
}
|
|
50
56
|
this.digestIndex++;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"split-hash-validator.js","sourceRoot":"","sources":["../../src/nodejs/split-hash-validator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAqB,MAAM,QAAQ,CAAA;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;
|
|
1
|
+
{"version":3,"file":"split-hash-validator.js","sourceRoot":"","sources":["../../src/nodejs/split-hash-validator.ts"],"names":[],"mappings":"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"}
|
package/lib/nodejs/split-hash.js
CHANGED
|
@@ -1,36 +1,37 @@
|
|
|
1
|
-
import { CustomError } from '@blackglory/errors';
|
|
1
|
+
import { assert, CustomError } from '@blackglory/errors';
|
|
2
2
|
export async function* splitHash(stream, blockSizeBytes, createHash) {
|
|
3
|
+
assert(blockSizeBytes > 0, 'The parameter blockSizeBytes must be greater than zero');
|
|
3
4
|
let hash = createHash();
|
|
4
|
-
let
|
|
5
|
+
let currentBlockBytes = 0;
|
|
5
6
|
for await (const chunk of stream) {
|
|
6
7
|
if (!Buffer.isBuffer(chunk))
|
|
7
8
|
throw new StreamEncodingError();
|
|
8
|
-
if (
|
|
9
|
+
if (currentBlockBytes + chunk.length < blockSizeBytes) {
|
|
9
10
|
hash.update(chunk);
|
|
10
|
-
|
|
11
|
+
currentBlockBytes += chunk.length;
|
|
11
12
|
}
|
|
12
13
|
else {
|
|
13
14
|
let offset = 0;
|
|
14
15
|
while (true) {
|
|
15
|
-
const
|
|
16
|
-
const slice = chunk.slice(offset, offset +
|
|
17
|
-
if (slice.length ===
|
|
16
|
+
const remainingBlockBytes = blockSizeBytes - currentBlockBytes;
|
|
17
|
+
const slice = chunk.slice(offset, offset + remainingBlockBytes);
|
|
18
|
+
if (slice.length === remainingBlockBytes) {
|
|
18
19
|
hash.update(slice);
|
|
19
20
|
const digest = hash.digest();
|
|
20
21
|
yield digest;
|
|
21
22
|
hash = createHash();
|
|
22
|
-
|
|
23
|
+
currentBlockBytes = 0;
|
|
23
24
|
offset += slice.length;
|
|
24
25
|
}
|
|
25
26
|
else {
|
|
26
27
|
hash.update(slice);
|
|
27
|
-
|
|
28
|
+
currentBlockBytes += slice.length;
|
|
28
29
|
break;
|
|
29
30
|
}
|
|
30
31
|
}
|
|
31
32
|
}
|
|
32
33
|
}
|
|
33
|
-
if (
|
|
34
|
+
if (currentBlockBytes > 0)
|
|
34
35
|
yield hash.digest();
|
|
35
36
|
}
|
|
36
37
|
export class StreamEncodingError extends CustomError {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"split-hash.js","sourceRoot":"","sources":["../../src/nodejs/split-hash.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;
|
|
1
|
+
{"version":3,"file":"split-hash.js","sourceRoot":"","sources":["../../src/nodejs/split-hash.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAGxD,MAAM,CAAC,KAAK,SAAS,CAAC,CAAC,SAAS,CAC9B,MAA6B,EAC7B,cAAsB,EACtB,UAAqC;IAErC,MAAM,CAAC,cAAc,GAAG,CAAC,EAAE,wDAAwD,CAAC,CAAA;IAEpF,IAAI,IAAI,GAAG,UAAU,EAAE,CAAA;IACvB,IAAI,iBAAiB,GAAG,CAAC,CAAA;IACzB,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,MAAM,EAAE;QAChC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;YAAE,MAAM,IAAI,mBAAmB,EAAE,CAAA;QAE5D,IAAI,iBAAiB,GAAG,KAAK,CAAC,MAAM,GAAG,cAAc,EAAE;YACrD,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;YAClB,iBAAiB,IAAI,KAAK,CAAC,MAAM,CAAA;SAClC;aAAM;YACL,IAAI,MAAM,GAAG,CAAC,CAAA;YACd,OAAO,IAAI,EAAE;gBACX,MAAM,mBAAmB,GAAG,cAAc,GAAG,iBAAiB,CAAA;gBAC9D,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,mBAAmB,CAAC,CAAA;gBAC/D,IAAI,KAAK,CAAC,MAAM,KAAK,mBAAmB,EAAE;oBACxC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;oBAClB,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,CAAA;oBAC5B,MAAM,MAAM,CAAA;oBAEZ,IAAI,GAAG,UAAU,EAAE,CAAA;oBACnB,iBAAiB,GAAG,CAAC,CAAA;oBACrB,MAAM,IAAI,KAAK,CAAC,MAAM,CAAA;iBACvB;qBAAM;oBAEL,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;oBAClB,iBAAiB,IAAI,KAAK,CAAC,MAAM,CAAA;oBACjC,MAAK;iBACN;aACF;SACF;KACF;IAED,IAAI,iBAAiB,GAAG,CAAC;QAAE,MAAM,IAAI,CAAC,MAAM,EAAE,CAAA;AAChD,CAAC;AAED,MAAM,OAAO,mBAAoB,SAAQ,WAAW;IAClD;QACE,KAAK,CAAC,iCAAiC,CAAC,CAAA;IAC1C,CAAC;CACF"}
|
package/lib/whatwg/split-hash.js
CHANGED
|
@@ -1,34 +1,36 @@
|
|
|
1
1
|
import { toAsyncIterableIterator } from 'extra-stream';
|
|
2
|
+
import { assert } from '@blackglory/errors';
|
|
2
3
|
export async function* splitHash(stream, blockSizeBytes, createHash) {
|
|
4
|
+
assert(blockSizeBytes > 0, 'The parameter blockSizeBytes must be greater than zero');
|
|
3
5
|
let hash = createHash();
|
|
4
|
-
let
|
|
6
|
+
let currentBlockBytes = 0;
|
|
5
7
|
for await (const chunk of toAsyncIterableIterator(stream)) {
|
|
6
|
-
if (
|
|
8
|
+
if (currentBlockBytes + chunk.length < blockSizeBytes) {
|
|
7
9
|
hash.update(chunk);
|
|
8
|
-
|
|
10
|
+
currentBlockBytes += chunk.length;
|
|
9
11
|
}
|
|
10
12
|
else {
|
|
11
13
|
let offset = 0;
|
|
12
14
|
while (true) {
|
|
13
|
-
const
|
|
14
|
-
const slice = chunk.slice(offset, offset +
|
|
15
|
-
if (slice.length ===
|
|
15
|
+
const remainingBlockBytes = blockSizeBytes - currentBlockBytes;
|
|
16
|
+
const slice = chunk.slice(offset, offset + remainingBlockBytes);
|
|
17
|
+
if (slice.length === remainingBlockBytes) {
|
|
16
18
|
hash.update(slice);
|
|
17
19
|
const digest = await hash.digest();
|
|
18
20
|
yield digest;
|
|
19
21
|
hash = createHash();
|
|
20
|
-
|
|
22
|
+
currentBlockBytes = 0;
|
|
21
23
|
offset += slice.length;
|
|
22
24
|
}
|
|
23
25
|
else {
|
|
24
26
|
hash.update(slice);
|
|
25
|
-
|
|
27
|
+
currentBlockBytes += slice.length;
|
|
26
28
|
break;
|
|
27
29
|
}
|
|
28
30
|
}
|
|
29
31
|
}
|
|
30
32
|
}
|
|
31
|
-
if (
|
|
33
|
+
if (currentBlockBytes > 0)
|
|
32
34
|
yield await hash.digest();
|
|
33
35
|
}
|
|
34
36
|
//# sourceMappingURL=split-hash.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"split-hash.js","sourceRoot":"","sources":["../../src/whatwg/split-hash.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"split-hash.js","sourceRoot":"","sources":["../../src/whatwg/split-hash.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAA;AACtD,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAA;AAG3C,MAAM,CAAC,KAAK,SAAS,CAAC,CAAC,SAAS,CAC9B,MAAsB,EACtB,cAAsB,EACtB,UAAqC;IAErC,MAAM,CAAC,cAAc,GAAG,CAAC,EAAE,wDAAwD,CAAC,CAAA;IAEpF,IAAI,IAAI,GAAG,UAAU,EAAE,CAAA;IACvB,IAAI,iBAAiB,GAAG,CAAC,CAAA;IACzB,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,uBAAuB,CAAC,MAAM,CAAC,EAAE;QACzD,IAAI,iBAAiB,GAAG,KAAK,CAAC,MAAM,GAAG,cAAc,EAAE;YACrD,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;YAClB,iBAAiB,IAAI,KAAK,CAAC,MAAM,CAAA;SAClC;aAAM;YACL,IAAI,MAAM,GAAG,CAAC,CAAA;YACd,OAAO,IAAI,EAAE;gBACX,MAAM,mBAAmB,GAAG,cAAc,GAAG,iBAAiB,CAAA;gBAC9D,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,mBAAmB,CAAC,CAAA;gBAC/D,IAAI,KAAK,CAAC,MAAM,KAAK,mBAAmB,EAAE;oBACxC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;oBAClB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,EAAE,CAAA;oBAClC,MAAM,MAAM,CAAA;oBAEZ,IAAI,GAAG,UAAU,EAAE,CAAA;oBACnB,iBAAiB,GAAG,CAAC,CAAA;oBACrB,MAAM,IAAI,KAAK,CAAC,MAAM,CAAA;iBACvB;qBAAM;oBAGL,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;oBAClB,iBAAiB,IAAI,KAAK,CAAC,MAAM,CAAA;oBACjC,MAAK;iBACN;aACF;SACF;KACF;IAED,IAAI,iBAAiB,GAAG,CAAC;QAAE,MAAM,MAAM,IAAI,CAAC,MAAM,EAAE,CAAA;AACtD,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "split-hash",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.4",
|
|
4
4
|
"description": "Split the stream based on bytes and get digests from each part.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"split",
|
|
@@ -70,6 +70,7 @@
|
|
|
70
70
|
},
|
|
71
71
|
"dependencies": {
|
|
72
72
|
"@blackglory/errors": "^3.0.0",
|
|
73
|
-
"extra-stream": "^0.2.0"
|
|
73
|
+
"extra-stream": "^0.2.0",
|
|
74
|
+
"extra-utils": "^5.21.0"
|
|
74
75
|
}
|
|
75
76
|
}
|
|
@@ -1,51 +1,62 @@
|
|
|
1
1
|
import { Transform, TransformCallback } from 'stream'
|
|
2
|
-
import { CustomError } from '@blackglory/errors'
|
|
2
|
+
import { assert, CustomError } from '@blackglory/errors'
|
|
3
3
|
import { ProgressiveHashFactory, IProgressiveHash } from './types.js'
|
|
4
|
+
import { isUndefined } from 'extra-utils'
|
|
4
5
|
|
|
5
6
|
export class SplitHashValidator<T> extends Transform {
|
|
6
7
|
private hash: IProgressiveHash<T> = this.createHash()
|
|
7
|
-
private
|
|
8
|
+
private currentBlockBytes = 0
|
|
8
9
|
private digestIndex = 0
|
|
9
10
|
|
|
10
11
|
constructor(
|
|
11
12
|
private digests: T[]
|
|
12
|
-
, private
|
|
13
|
+
, private blockSizeBytes: number
|
|
13
14
|
, private createHash: ProgressiveHashFactory<T>
|
|
14
15
|
, private equals: (a: T, b: T) => boolean = Object.is
|
|
15
16
|
) {
|
|
17
|
+
assert(blockSizeBytes > 0, 'The parameter blockSizeBytes must be greater than zero')
|
|
18
|
+
|
|
16
19
|
super()
|
|
17
20
|
}
|
|
18
21
|
|
|
19
22
|
_transform(
|
|
23
|
+
// 总是Buffer
|
|
20
24
|
chunk: Buffer
|
|
25
|
+
// 总是"buffer".
|
|
21
26
|
, encoding: BufferEncoding
|
|
22
27
|
, callback: TransformCallback
|
|
23
28
|
): void {
|
|
24
|
-
// chunk
|
|
29
|
+
// 由于接收到的chunk总是Buffer, 且encoding总是"buffer", 无法在此处检测chunk是否经过编码.
|
|
25
30
|
|
|
26
|
-
if (this.
|
|
31
|
+
if (this.currentBlockBytes + chunk.length < this.blockSizeBytes) {
|
|
27
32
|
this.hash.update(chunk)
|
|
28
|
-
this.
|
|
33
|
+
this.currentBlockBytes += chunk.length
|
|
29
34
|
} else {
|
|
30
35
|
let offset = 0
|
|
31
36
|
while (true) {
|
|
32
|
-
const
|
|
33
|
-
const slice = chunk.slice(offset, offset +
|
|
34
|
-
if (slice.length ===
|
|
37
|
+
const remainingBlockBytes = this.blockSizeBytes - this.currentBlockBytes
|
|
38
|
+
const slice = chunk.slice(offset, offset + remainingBlockBytes)
|
|
39
|
+
if (slice.length === remainingBlockBytes) {
|
|
35
40
|
this.hash.update(slice)
|
|
36
|
-
const
|
|
37
|
-
|
|
41
|
+
const currentBlockBytes = this.hash.digest()
|
|
42
|
+
const correctDigest = this.digests[this.digestIndex]
|
|
43
|
+
if (
|
|
44
|
+
isUndefined(correctDigest) ||
|
|
45
|
+
!this.equals(correctDigest, currentBlockBytes)
|
|
46
|
+
) {
|
|
38
47
|
return callback(new NotMatchedError())
|
|
39
48
|
}
|
|
49
|
+
|
|
40
50
|
this.digestIndex++
|
|
51
|
+
|
|
41
52
|
// prepare for the next round
|
|
42
53
|
this.hash = this.createHash()
|
|
43
|
-
this.
|
|
54
|
+
this.currentBlockBytes = 0
|
|
44
55
|
offset += slice.length
|
|
45
56
|
} else {
|
|
46
57
|
// if the length does not match, the remaining data is not long enough, update the remaining data and exit the loop.
|
|
47
58
|
this.hash.update(slice)
|
|
48
|
-
this.
|
|
59
|
+
this.currentBlockBytes += slice.length
|
|
49
60
|
break
|
|
50
61
|
}
|
|
51
62
|
}
|
|
@@ -55,9 +66,13 @@ export class SplitHashValidator<T> extends Transform {
|
|
|
55
66
|
}
|
|
56
67
|
|
|
57
68
|
_flush(callback: TransformCallback): void {
|
|
58
|
-
if (this.
|
|
59
|
-
const
|
|
60
|
-
|
|
69
|
+
if (this.currentBlockBytes > 0) {
|
|
70
|
+
const currentBlockDigest = this.hash.digest()
|
|
71
|
+
const correctDigest = this.digests[this.digestIndex]
|
|
72
|
+
if (
|
|
73
|
+
isUndefined(correctDigest) ||
|
|
74
|
+
!this.equals(correctDigest, currentBlockDigest)
|
|
75
|
+
) {
|
|
61
76
|
return callback(new NotMatchedError())
|
|
62
77
|
}
|
|
63
78
|
this.digestIndex++
|
package/src/nodejs/split-hash.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CustomError } from '@blackglory/errors'
|
|
1
|
+
import { assert, CustomError } from '@blackglory/errors'
|
|
2
2
|
import { ProgressiveHashFactory } from './types.js'
|
|
3
3
|
|
|
4
4
|
export async function* splitHash<T>(
|
|
@@ -6,37 +6,40 @@ export async function* splitHash<T>(
|
|
|
6
6
|
, blockSizeBytes: number
|
|
7
7
|
, createHash: ProgressiveHashFactory<T>
|
|
8
8
|
): AsyncIterableIterator<T> {
|
|
9
|
+
assert(blockSizeBytes > 0, 'The parameter blockSizeBytes must be greater than zero')
|
|
10
|
+
|
|
9
11
|
let hash = createHash()
|
|
10
|
-
let
|
|
12
|
+
let currentBlockBytes = 0
|
|
11
13
|
for await (const chunk of stream) {
|
|
12
14
|
if (!Buffer.isBuffer(chunk)) throw new StreamEncodingError()
|
|
13
|
-
|
|
15
|
+
|
|
16
|
+
if (currentBlockBytes + chunk.length < blockSizeBytes) {
|
|
14
17
|
hash.update(chunk)
|
|
15
|
-
|
|
18
|
+
currentBlockBytes += chunk.length
|
|
16
19
|
} else {
|
|
17
20
|
let offset = 0
|
|
18
21
|
while (true) {
|
|
19
|
-
const
|
|
20
|
-
const slice = chunk.slice(offset, offset +
|
|
21
|
-
if (slice.length ===
|
|
22
|
+
const remainingBlockBytes = blockSizeBytes - currentBlockBytes
|
|
23
|
+
const slice = chunk.slice(offset, offset + remainingBlockBytes)
|
|
24
|
+
if (slice.length === remainingBlockBytes) {
|
|
22
25
|
hash.update(slice)
|
|
23
26
|
const digest = hash.digest()
|
|
24
27
|
yield digest
|
|
25
28
|
// prepare for the next round
|
|
26
29
|
hash = createHash()
|
|
27
|
-
|
|
30
|
+
currentBlockBytes = 0
|
|
28
31
|
offset += slice.length
|
|
29
32
|
} else {
|
|
30
33
|
// if the length does not match, the remaining data is not long enough, update the remaining data and exit the loop.
|
|
31
34
|
hash.update(slice)
|
|
32
|
-
|
|
35
|
+
currentBlockBytes += slice.length
|
|
33
36
|
break
|
|
34
37
|
}
|
|
35
38
|
}
|
|
36
39
|
}
|
|
37
40
|
}
|
|
38
41
|
// digest remaining data if it exists
|
|
39
|
-
if (
|
|
42
|
+
if (currentBlockBytes > 0) yield hash.digest()
|
|
40
43
|
}
|
|
41
44
|
|
|
42
45
|
export class StreamEncodingError extends CustomError {
|
package/src/whatwg/split-hash.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { toAsyncIterableIterator } from 'extra-stream'
|
|
2
|
+
import { assert } from '@blackglory/errors'
|
|
2
3
|
import { ProgressiveHashFactory } from './types.js'
|
|
3
4
|
|
|
4
5
|
export async function* splitHash<T>(
|
|
@@ -6,35 +7,37 @@ export async function* splitHash<T>(
|
|
|
6
7
|
, blockSizeBytes: number
|
|
7
8
|
, createHash: ProgressiveHashFactory<T>
|
|
8
9
|
): AsyncIterableIterator<T> {
|
|
10
|
+
assert(blockSizeBytes > 0, 'The parameter blockSizeBytes must be greater than zero')
|
|
11
|
+
|
|
9
12
|
let hash = createHash()
|
|
10
|
-
let
|
|
13
|
+
let currentBlockBytes = 0
|
|
11
14
|
for await (const chunk of toAsyncIterableIterator(stream)) {
|
|
12
|
-
if (
|
|
15
|
+
if (currentBlockBytes + chunk.length < blockSizeBytes) {
|
|
13
16
|
hash.update(chunk)
|
|
14
|
-
|
|
17
|
+
currentBlockBytes += chunk.length
|
|
15
18
|
} else {
|
|
16
19
|
let offset = 0
|
|
17
20
|
while (true) {
|
|
18
|
-
const
|
|
19
|
-
const slice = chunk.slice(offset, offset +
|
|
20
|
-
if (slice.length ===
|
|
21
|
+
const remainingBlockBytes = blockSizeBytes - currentBlockBytes
|
|
22
|
+
const slice = chunk.slice(offset, offset + remainingBlockBytes)
|
|
23
|
+
if (slice.length === remainingBlockBytes) {
|
|
21
24
|
hash.update(slice)
|
|
22
25
|
const digest = await hash.digest()
|
|
23
26
|
yield digest
|
|
24
27
|
// prepare for the next round
|
|
25
28
|
hash = createHash()
|
|
26
|
-
|
|
29
|
+
currentBlockBytes = 0
|
|
27
30
|
offset += slice.length
|
|
28
31
|
} else {
|
|
29
32
|
// if the length does not match,
|
|
30
33
|
// the remaining data is not long enough, update the remaining data and exit the loop.
|
|
31
34
|
hash.update(slice)
|
|
32
|
-
|
|
35
|
+
currentBlockBytes += slice.length
|
|
33
36
|
break
|
|
34
37
|
}
|
|
35
38
|
}
|
|
36
39
|
}
|
|
37
40
|
}
|
|
38
41
|
// digest remaining data if it exists
|
|
39
|
-
if (
|
|
42
|
+
if (currentBlockBytes > 0) yield await hash.digest()
|
|
40
43
|
}
|