forked from MikeKovarik/exifr
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathBase64Reader.mjs
61 lines (53 loc) · 2.16 KB
/
Base64Reader.mjs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
import {fileReaders} from '../plugins.mjs'
import {ChunkedReader} from './ChunkedReader.mjs'
import * as platform from '../util/platform.mjs'
import {Buffer} from '../util/platform.mjs'
export class Base64Reader extends ChunkedReader {
constructor(...args) {
super(...args)
// Remove the mime type and base64 marker at the beginning so that we're left off with clear b64 string.
this.input = this.input.replace(/^data:([^;]+);base64,/gmi, '')
this.size = (this.input.length / 4) * 3
if (this.input.endsWith('==')) this.size -= 2
else if (this.input.endsWith('=')) this.size -= 1
}
// Accepts base64 or base64 URL and converts it to DataView and trims if needed.
async _readChunk(offset, length) {
let base64 = this.input
// Base64 encodes 3 bytes of data into string of 4 characters.
// To extract bytes at certain offset and length we need to take that into account,
// recalculate the offset and length into blocks of 4 characters, slice the input base64 string
// from these first and last of these blocks, and finally adjust correct offset in these blocks.
// NOTE: Each 4 character block of base64 string represents 3 bytes of data.
let blockStart, offsetInBlock
if (offset === undefined) {
// Start from begining of the 4-letter block.
offset = 0
blockStart = 0
offsetInBlock = 0
} else {
// Adjust offset from the start of the 4-letter block.
blockStart = Math.floor(offset / 3) * 4
offsetInBlock = offset - ((blockStart / 4) * 3)
}
if (length === undefined) {
length = this.size
}
let end = offset + length
let blockEnd = blockStart + Math.ceil(end / 3) * 4
base64 = base64.slice(blockStart, blockEnd)
let clampedLength = Math.min(length, this.size - offset)
if (platform.hasBuffer) {
let slice = Buffer.from(base64, 'base64').slice(offsetInBlock, offsetInBlock + clampedLength)
return this.set(slice, offset, true)
} else {
let chunk = this.subarray(offset, clampedLength, true)
let binary = atob(base64)
let uint8view = chunk.toUint8()
for (let i = 0; i < clampedLength; i++)
uint8view[i] = binary.charCodeAt(offsetInBlock + i)
return chunk
}
}
}
fileReaders.set('base64', Base64Reader)