@ipld/car 5.0.3 → 5.1.1
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/README.md +124 -14
- package/dist/index.min.js +3 -3
- package/dist/src/api.d.ts +16 -0
- package/dist/src/api.d.ts.map +1 -1
- package/dist/src/buffer-decoder.d.ts +67 -0
- package/dist/src/buffer-decoder.d.ts.map +1 -0
- package/dist/src/buffer-reader-browser.d.ts +116 -0
- package/dist/src/buffer-reader-browser.d.ts.map +1 -0
- package/dist/src/buffer-reader.d.ts +31 -0
- package/dist/src/buffer-reader.d.ts.map +1 -0
- package/dist/src/coding.d.ts +10 -3
- package/dist/src/coding.d.ts.map +1 -1
- package/dist/src/decoder-common.d.ts +43 -0
- package/dist/src/decoder-common.d.ts.map +1 -0
- package/dist/src/decoder.d.ts +10 -0
- package/dist/src/decoder.d.ts.map +1 -1
- package/dist/src/index-browser.d.ts +3 -1
- package/dist/src/index.d.ts +2 -1
- package/package.json +8 -2
- package/src/api.ts +18 -0
- package/src/buffer-decoder.js +226 -0
- package/src/buffer-reader-browser.js +150 -0
- package/src/buffer-reader.js +53 -0
- package/src/coding.ts +13 -3
- package/src/decoder-common.js +86 -0
- package/src/decoder.js +31 -93
- package/src/index-browser.js +5 -1
- package/src/index.js +2 -0
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import * as BufferDecoder from './buffer-decoder.js'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @typedef {import('multiformats').CID} CID
|
|
5
|
+
* @typedef {import('./api').Block} Block
|
|
6
|
+
* @typedef {import('./api').CarBufferReader} ICarBufferReader
|
|
7
|
+
* @typedef {import('./coding').CarHeader} CarHeader
|
|
8
|
+
* @typedef {import('./coding').CarV2Header} CarV2Header
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Provides blockstore-like access to a CAR.
|
|
13
|
+
*
|
|
14
|
+
* Implements the `RootsBufferReader` interface:
|
|
15
|
+
* {@link ICarBufferReader.getRoots `getRoots()`}. And the `BlockBufferReader` interface:
|
|
16
|
+
* {@link ICarBufferReader.get `get()`}, {@link ICarBufferReader.has `has()`},
|
|
17
|
+
* {@link ICarBufferReader.blocks `blocks()`} and
|
|
18
|
+
* {@link ICarBufferReader.cids `cids()`}.
|
|
19
|
+
*
|
|
20
|
+
* Load this class with either `import { CarBufferReader } from '@ipld/car/buffer-reader'`
|
|
21
|
+
* (`const { CarBufferReader } = require('@ipld/car/buffer-reader')`). Or
|
|
22
|
+
* `import { CarBufferReader } from '@ipld/car'` (`const { CarBufferReader } = require('@ipld/car')`).
|
|
23
|
+
* The former will likely result in smaller bundle sizes where this is
|
|
24
|
+
* important.
|
|
25
|
+
*
|
|
26
|
+
* @name CarBufferReader
|
|
27
|
+
* @class
|
|
28
|
+
* @implements {ICarBufferReader}
|
|
29
|
+
* @property {number} version The version number of the CAR referenced by this
|
|
30
|
+
* reader (should be `1` or `2`).
|
|
31
|
+
*/
|
|
32
|
+
export class CarBufferReader {
|
|
33
|
+
/**
|
|
34
|
+
* @constructs CarBufferReader
|
|
35
|
+
* @param {CarHeader|CarV2Header} header
|
|
36
|
+
* @param {Block[]} blocks
|
|
37
|
+
*/
|
|
38
|
+
constructor (header, blocks) {
|
|
39
|
+
this._header = header
|
|
40
|
+
this._blocks = blocks
|
|
41
|
+
this._cids = undefined
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* @property version
|
|
46
|
+
* @memberof CarBufferReader
|
|
47
|
+
* @instance
|
|
48
|
+
*/
|
|
49
|
+
get version () {
|
|
50
|
+
return this._header.version
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Get the list of roots defined by the CAR referenced by this reader. May be
|
|
55
|
+
* zero or more `CID`s.
|
|
56
|
+
*
|
|
57
|
+
* @function
|
|
58
|
+
* @memberof CarBufferReader
|
|
59
|
+
* @instance
|
|
60
|
+
* @returns {CID[]}
|
|
61
|
+
*/
|
|
62
|
+
getRoots () {
|
|
63
|
+
return this._header.roots
|
|
64
|
+
/* c8 ignore next 2 */
|
|
65
|
+
// Node.js 12 c8 bug
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Check whether a given `CID` exists within the CAR referenced by this
|
|
70
|
+
* reader.
|
|
71
|
+
*
|
|
72
|
+
* @function
|
|
73
|
+
* @memberof CarBufferReader
|
|
74
|
+
* @instance
|
|
75
|
+
* @param {CID} key
|
|
76
|
+
* @returns {boolean}
|
|
77
|
+
*/
|
|
78
|
+
has (key) {
|
|
79
|
+
return this._blocks.some(b => b.cid.equals(key))
|
|
80
|
+
/* c8 ignore next 2 */
|
|
81
|
+
// Node.js 12 c8 bug
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Fetch a `Block` (a `{ cid:CID, bytes:Uint8Array }` pair) from the CAR
|
|
86
|
+
* referenced by this reader matching the provided `CID`. In the case where
|
|
87
|
+
* the provided `CID` doesn't exist within the CAR, `undefined` will be
|
|
88
|
+
* returned.
|
|
89
|
+
*
|
|
90
|
+
* @function
|
|
91
|
+
* @memberof CarBufferReader
|
|
92
|
+
* @instance
|
|
93
|
+
* @param {CID} key
|
|
94
|
+
* @returns {Block | undefined}
|
|
95
|
+
*/
|
|
96
|
+
get (key) {
|
|
97
|
+
return this._blocks.find(b => b.cid.equals(key))
|
|
98
|
+
/* c8 ignore next 2 */
|
|
99
|
+
// Node.js 12 c8 bug
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Returns a `Block[]` of the `Block`s (`{ cid:CID, bytes:Uint8Array }` pairs) contained within
|
|
104
|
+
* the CAR referenced by this reader.
|
|
105
|
+
*
|
|
106
|
+
* @function
|
|
107
|
+
* @memberof CarBufferReader
|
|
108
|
+
* @instance
|
|
109
|
+
* @returns {Block[]}
|
|
110
|
+
*/
|
|
111
|
+
blocks () {
|
|
112
|
+
return this._blocks
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Returns a `CID[]` of the `CID`s contained within the CAR referenced by this reader.
|
|
117
|
+
*
|
|
118
|
+
* @function
|
|
119
|
+
* @memberof CarBufferReader
|
|
120
|
+
* @instance
|
|
121
|
+
* @returns {CID[]}
|
|
122
|
+
*/
|
|
123
|
+
cids () {
|
|
124
|
+
if (!this._cids) {
|
|
125
|
+
this._cids = this._blocks.map(b => b.cid)
|
|
126
|
+
}
|
|
127
|
+
return this._cids
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Instantiate a {@link CarBufferReader} from a `Uint8Array` blob. This performs a
|
|
132
|
+
* decode fully in memory and maintains the decoded state in memory for full
|
|
133
|
+
* access to the data via the `CarReader` API.
|
|
134
|
+
*
|
|
135
|
+
* @static
|
|
136
|
+
* @memberof CarBufferReader
|
|
137
|
+
* @param {Uint8Array} bytes
|
|
138
|
+
* @returns {CarBufferReader}
|
|
139
|
+
*/
|
|
140
|
+
static fromBytes (bytes) {
|
|
141
|
+
if (!(bytes instanceof Uint8Array)) {
|
|
142
|
+
throw new TypeError('fromBytes() requires a Uint8Array')
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const { header, blocks } = BufferDecoder.fromBytes(bytes)
|
|
146
|
+
return new CarBufferReader(header, blocks)
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export const __browser = true
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import fs from 'fs'
|
|
2
|
+
import { CarBufferReader as BrowserCarBufferReader } from './buffer-reader-browser.js'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @typedef {import('./api').Block} Block
|
|
6
|
+
* @typedef {import('./api').BlockIndex} BlockIndex
|
|
7
|
+
* @typedef {import('./api').CarBufferReader} ICarBufferReader
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const fsread = fs.readSync
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @class
|
|
14
|
+
* @implements {ICarBufferReader}
|
|
15
|
+
*/
|
|
16
|
+
export class CarBufferReader extends BrowserCarBufferReader {
|
|
17
|
+
/**
|
|
18
|
+
* Reads a block directly from a file descriptor for an open CAR file. This
|
|
19
|
+
* function is **only available in Node.js** and not a browser environment.
|
|
20
|
+
*
|
|
21
|
+
* This function can be used in connection with {@link CarIndexer} which emits
|
|
22
|
+
* the `BlockIndex` objects that are required by this function.
|
|
23
|
+
*
|
|
24
|
+
* The user is responsible for opening and closing the file used in this call.
|
|
25
|
+
*
|
|
26
|
+
* @static
|
|
27
|
+
* @memberof CarBufferReader
|
|
28
|
+
* @param {number} fd - A file descriptor from the
|
|
29
|
+
* Node.js `fs` module. An integer, from `fs.open()`.
|
|
30
|
+
* @param {BlockIndex} blockIndex - An index pointing to the location of the
|
|
31
|
+
* Block required. This `BlockIndex` should take the form:
|
|
32
|
+
* `{cid:CID, blockLength:number, blockOffset:number}`.
|
|
33
|
+
* @returns {Block} A `{ cid:CID, bytes:Uint8Array }` pair.
|
|
34
|
+
*/
|
|
35
|
+
static readRaw (fd, blockIndex) {
|
|
36
|
+
const { cid, blockLength, blockOffset } = blockIndex
|
|
37
|
+
const bytes = new Uint8Array(blockLength)
|
|
38
|
+
let read
|
|
39
|
+
if (typeof fd === 'number') {
|
|
40
|
+
read = fsread(fd, bytes, 0, blockLength, blockOffset)
|
|
41
|
+
} else {
|
|
42
|
+
throw new TypeError('Bad fd')
|
|
43
|
+
}
|
|
44
|
+
if (read !== blockLength) {
|
|
45
|
+
throw new Error(`Failed to read entire block (${read} instead of ${blockLength})`)
|
|
46
|
+
}
|
|
47
|
+
return { cid, bytes }
|
|
48
|
+
/* c8 ignore next 2 */
|
|
49
|
+
// Node.js 12 c8 bug
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export const __browser = false
|
package/src/coding.ts
CHANGED
|
@@ -45,12 +45,22 @@ export interface CarDecoder {
|
|
|
45
45
|
blocksIndex: () => AsyncGenerator<BlockIndex>
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
export interface
|
|
48
|
+
export interface Seekable {
|
|
49
|
+
seek: (length: number) => void
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface BytesReader extends Seekable {
|
|
49
53
|
upTo: (length: number) => Promise<Uint8Array>
|
|
50
54
|
|
|
51
|
-
exactly: (length: number) => Promise<Uint8Array>
|
|
55
|
+
exactly: (length: number, seek?: boolean) => Promise<Uint8Array>
|
|
52
56
|
|
|
53
|
-
|
|
57
|
+
pos: number
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface BytesBufferReader extends Seekable{
|
|
61
|
+
upTo: (length: number) => Uint8Array
|
|
62
|
+
|
|
63
|
+
exactly: (length: number, seek?: boolean) => Uint8Array
|
|
54
64
|
|
|
55
65
|
pos: number
|
|
56
66
|
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import varint from 'varint'
|
|
2
|
+
|
|
3
|
+
export const CIDV0_BYTES = {
|
|
4
|
+
SHA2_256: 0x12,
|
|
5
|
+
LENGTH: 0x20,
|
|
6
|
+
DAG_PB: 0x70
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const V2_HEADER_LENGTH = /* characteristics */ 16 /* v1 offset */ + 8 /* v1 size */ + 8 /* index offset */ + 8
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Decodes varint and seeks the buffer
|
|
13
|
+
*
|
|
14
|
+
* ```js
|
|
15
|
+
* // needs bytes to be read first
|
|
16
|
+
* const bytes = reader.upTo(8) // maybe async
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* @param {Uint8Array} bytes
|
|
20
|
+
* @param {import('./coding').Seekable} seeker
|
|
21
|
+
* @returns {number}
|
|
22
|
+
*/
|
|
23
|
+
export function decodeVarint (bytes, seeker) {
|
|
24
|
+
if (!bytes.length) {
|
|
25
|
+
throw new Error('Unexpected end of data')
|
|
26
|
+
}
|
|
27
|
+
const i = varint.decode(bytes)
|
|
28
|
+
seeker.seek(/** @type {number} */(varint.decode.bytes))
|
|
29
|
+
return i
|
|
30
|
+
/* c8 ignore next 2 */
|
|
31
|
+
// Node.js 12 c8 bug
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Decode v2 header
|
|
36
|
+
*
|
|
37
|
+
* ```js
|
|
38
|
+
* // needs bytes to be read first
|
|
39
|
+
* const bytes = reader.exactly(V2_HEADER_LENGTH, true) // maybe async
|
|
40
|
+
* ```
|
|
41
|
+
*
|
|
42
|
+
* @param {Uint8Array} bytes
|
|
43
|
+
* @returns {import('./coding').CarV2FixedHeader}
|
|
44
|
+
*/
|
|
45
|
+
export function decodeV2Header (bytes) {
|
|
46
|
+
const dv = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength)
|
|
47
|
+
let offset = 0
|
|
48
|
+
const header = {
|
|
49
|
+
version: 2,
|
|
50
|
+
/** @type {[bigint, bigint]} */
|
|
51
|
+
characteristics: [
|
|
52
|
+
dv.getBigUint64(offset, true),
|
|
53
|
+
dv.getBigUint64(offset += 8, true)
|
|
54
|
+
],
|
|
55
|
+
dataOffset: Number(dv.getBigUint64(offset += 8, true)),
|
|
56
|
+
dataSize: Number(dv.getBigUint64(offset += 8, true)),
|
|
57
|
+
indexOffset: Number(dv.getBigUint64(offset += 8, true))
|
|
58
|
+
}
|
|
59
|
+
return header
|
|
60
|
+
/* c8 ignore next 2 */
|
|
61
|
+
// Node.js 12 c8 bug
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Checks the length of the multihash to be read afterwards
|
|
66
|
+
*
|
|
67
|
+
* ```js
|
|
68
|
+
* // needs bytes to be read first
|
|
69
|
+
* const bytes = reader.upTo(8) // maybe async
|
|
70
|
+
* ```
|
|
71
|
+
*
|
|
72
|
+
* @param {Uint8Array} bytes
|
|
73
|
+
*/
|
|
74
|
+
export function getMultihashLength (bytes) {
|
|
75
|
+
// | code | length | .... |
|
|
76
|
+
// where both code and length are varints, so we have to decode
|
|
77
|
+
// them first before we can know total length
|
|
78
|
+
|
|
79
|
+
varint.decode(bytes) // code
|
|
80
|
+
const codeLength = /** @type {number} */(varint.decode.bytes)
|
|
81
|
+
const length = varint.decode(bytes.subarray(varint.decode.bytes))
|
|
82
|
+
const lengthLength = /** @type {number} */(varint.decode.bytes)
|
|
83
|
+
const mhLength = codeLength + lengthLength + length
|
|
84
|
+
|
|
85
|
+
return mhLength
|
|
86
|
+
}
|
package/src/decoder.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import varint from 'varint'
|
|
2
1
|
import { CID } from 'multiformats/cid'
|
|
3
2
|
import * as Digest from 'multiformats/hashes/digest'
|
|
4
3
|
import { decode as decodeDagCbor } from '@ipld/dag-cbor'
|
|
5
4
|
import { CarHeader as headerValidator } from './header-validator.js'
|
|
5
|
+
import { CIDV0_BYTES, decodeV2Header, decodeVarint, getMultihashLength, V2_HEADER_LENGTH } from './decoder-common.js'
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* @typedef {import('./api').Block} Block
|
|
@@ -15,56 +15,6 @@ import { CarHeader as headerValidator } from './header-validator.js'
|
|
|
15
15
|
* @typedef {import('./coding').CarDecoder} CarDecoder
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
-
const CIDV0_BYTES = {
|
|
19
|
-
SHA2_256: 0x12,
|
|
20
|
-
LENGTH: 0x20,
|
|
21
|
-
DAG_PB: 0x70
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const V2_HEADER_LENGTH = /* characteristics */ 16 /* v1 offset */ + 8 /* v1 size */ + 8 /* index offset */ + 8
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* @param {BytesReader} reader
|
|
28
|
-
* @returns {Promise<number>}
|
|
29
|
-
*/
|
|
30
|
-
async function readVarint (reader) {
|
|
31
|
-
const bytes = await reader.upTo(8)
|
|
32
|
-
if (!bytes.length) {
|
|
33
|
-
throw new Error('Unexpected end of data')
|
|
34
|
-
}
|
|
35
|
-
const i = varint.decode(bytes)
|
|
36
|
-
reader.seek(/** @type {number} */(varint.decode.bytes))
|
|
37
|
-
return i
|
|
38
|
-
/* c8 ignore next 2 */
|
|
39
|
-
// Node.js 12 c8 bug
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* @param {BytesReader} reader
|
|
44
|
-
* @returns {Promise<CarV2FixedHeader>}
|
|
45
|
-
*/
|
|
46
|
-
async function readV2Header (reader) {
|
|
47
|
-
/** @type {Uint8Array} */
|
|
48
|
-
const bytes = await reader.exactly(V2_HEADER_LENGTH)
|
|
49
|
-
const dv = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength)
|
|
50
|
-
let offset = 0
|
|
51
|
-
const header = {
|
|
52
|
-
version: 2,
|
|
53
|
-
/** @type {[bigint, bigint]} */
|
|
54
|
-
characteristics: [
|
|
55
|
-
dv.getBigUint64(offset, true),
|
|
56
|
-
dv.getBigUint64(offset += 8, true)
|
|
57
|
-
],
|
|
58
|
-
dataOffset: Number(dv.getBigUint64(offset += 8, true)),
|
|
59
|
-
dataSize: Number(dv.getBigUint64(offset += 8, true)),
|
|
60
|
-
indexOffset: Number(dv.getBigUint64(offset += 8, true))
|
|
61
|
-
}
|
|
62
|
-
reader.seek(V2_HEADER_LENGTH)
|
|
63
|
-
return header
|
|
64
|
-
/* c8 ignore next 2 */
|
|
65
|
-
// Node.js 12 c8 bug
|
|
66
|
-
}
|
|
67
|
-
|
|
68
18
|
/**
|
|
69
19
|
* Reads header data from a `BytesReader`. The header may either be in the form
|
|
70
20
|
* of a `CarHeader` or `CarV2Header` depending on the CAR being read.
|
|
@@ -75,12 +25,11 @@ async function readV2Header (reader) {
|
|
|
75
25
|
* @returns {Promise<CarHeader|CarV2Header>}
|
|
76
26
|
*/
|
|
77
27
|
export async function readHeader (reader, strictVersion) {
|
|
78
|
-
const length = await
|
|
28
|
+
const length = decodeVarint(await reader.upTo(8), reader)
|
|
79
29
|
if (length === 0) {
|
|
80
30
|
throw new Error('Invalid CAR header (zero length)')
|
|
81
31
|
}
|
|
82
|
-
const header = await reader.exactly(length)
|
|
83
|
-
reader.seek(length)
|
|
32
|
+
const header = await reader.exactly(length, true)
|
|
84
33
|
const block = decodeDagCbor(header)
|
|
85
34
|
if (!headerValidator(block)) {
|
|
86
35
|
throw new Error('Invalid CAR header format')
|
|
@@ -98,7 +47,7 @@ export async function readHeader (reader, strictVersion) {
|
|
|
98
47
|
return block
|
|
99
48
|
}
|
|
100
49
|
// version 2
|
|
101
|
-
const v2Header = await
|
|
50
|
+
const v2Header = decodeV2Header(await reader.exactly(V2_HEADER_LENGTH, true))
|
|
102
51
|
reader.seek(v2Header.dataOffset - reader.pos)
|
|
103
52
|
const v1Header = await readHeader(reader, 1)
|
|
104
53
|
return Object.assign(v1Header, v2Header)
|
|
@@ -106,48 +55,25 @@ export async function readHeader (reader, strictVersion) {
|
|
|
106
55
|
// Node.js 12 c8 bug
|
|
107
56
|
}
|
|
108
57
|
|
|
109
|
-
/**
|
|
110
|
-
* @param {BytesReader} reader
|
|
111
|
-
* @returns {Promise<Uint8Array>}
|
|
112
|
-
*/
|
|
113
|
-
async function readMultihash (reader) {
|
|
114
|
-
// | code | length | .... |
|
|
115
|
-
// where both code and length are varints, so we have to decode
|
|
116
|
-
// them first before we can know total length
|
|
117
|
-
|
|
118
|
-
const bytes = await reader.upTo(8)
|
|
119
|
-
varint.decode(bytes) // code
|
|
120
|
-
const codeLength = /** @type {number} */(varint.decode.bytes)
|
|
121
|
-
const length = varint.decode(bytes.subarray(varint.decode.bytes))
|
|
122
|
-
const lengthLength = /** @type {number} */(varint.decode.bytes)
|
|
123
|
-
const mhLength = codeLength + lengthLength + length
|
|
124
|
-
const multihash = await reader.exactly(mhLength)
|
|
125
|
-
reader.seek(mhLength)
|
|
126
|
-
return multihash
|
|
127
|
-
/* c8 ignore next 2 */
|
|
128
|
-
// Node.js 12 c8 bug
|
|
129
|
-
}
|
|
130
|
-
|
|
131
58
|
/**
|
|
132
59
|
* @param {BytesReader} reader
|
|
133
60
|
* @returns {Promise<CID>}
|
|
134
61
|
*/
|
|
135
62
|
async function readCid (reader) {
|
|
136
|
-
const first = await reader.exactly(2)
|
|
63
|
+
const first = await reader.exactly(2, false)
|
|
137
64
|
if (first[0] === CIDV0_BYTES.SHA2_256 && first[1] === CIDV0_BYTES.LENGTH) {
|
|
138
65
|
// cidv0 32-byte sha2-256
|
|
139
|
-
const bytes = await reader.exactly(34)
|
|
140
|
-
reader.seek(34)
|
|
66
|
+
const bytes = await reader.exactly(34, true)
|
|
141
67
|
const multihash = Digest.decode(bytes)
|
|
142
68
|
return CID.create(0, CIDV0_BYTES.DAG_PB, multihash)
|
|
143
69
|
}
|
|
144
70
|
|
|
145
|
-
const version = await
|
|
71
|
+
const version = decodeVarint(await reader.upTo(8), reader)
|
|
146
72
|
if (version !== 1) {
|
|
147
73
|
throw new Error(`Unexpected CID version (${version})`)
|
|
148
74
|
}
|
|
149
|
-
const codec = await
|
|
150
|
-
const bytes = await
|
|
75
|
+
const codec = decodeVarint(await reader.upTo(8), reader)
|
|
76
|
+
const bytes = await reader.exactly(getMultihashLength(await reader.upTo(8)), true)
|
|
151
77
|
const multihash = Digest.decode(bytes)
|
|
152
78
|
return CID.create(version, codec, multihash)
|
|
153
79
|
/* c8 ignore next 2 */
|
|
@@ -168,7 +94,7 @@ export async function readBlockHead (reader) {
|
|
|
168
94
|
// length includes a CID + Binary, where CID has a variable length
|
|
169
95
|
// we have to deal with
|
|
170
96
|
const start = reader.pos
|
|
171
|
-
let length = await
|
|
97
|
+
let length = decodeVarint(await reader.upTo(8), reader)
|
|
172
98
|
if (length === 0) {
|
|
173
99
|
throw new Error('Invalid CAR section (zero length)')
|
|
174
100
|
}
|
|
@@ -187,8 +113,7 @@ export async function readBlockHead (reader) {
|
|
|
187
113
|
*/
|
|
188
114
|
async function readBlock (reader) {
|
|
189
115
|
const { cid, blockLength } = await readBlockHead(reader)
|
|
190
|
-
const bytes = await reader.exactly(blockLength)
|
|
191
|
-
reader.seek(blockLength)
|
|
116
|
+
const bytes = await reader.exactly(blockLength, true)
|
|
192
117
|
return { bytes, cid }
|
|
193
118
|
/* c8 ignore next 2 */
|
|
194
119
|
// Node.js 12 c8 bug
|
|
@@ -261,16 +186,21 @@ export function bytesReader (bytes) {
|
|
|
261
186
|
/** @type {BytesReader} */
|
|
262
187
|
return {
|
|
263
188
|
async upTo (length) {
|
|
264
|
-
|
|
189
|
+
const out = bytes.subarray(pos, pos + Math.min(length, bytes.length - pos))
|
|
265
190
|
/* c8 ignore next 2 */
|
|
191
|
+
return out
|
|
266
192
|
// Node.js 12 c8 bug
|
|
267
193
|
},
|
|
268
194
|
|
|
269
|
-
async exactly (length) {
|
|
195
|
+
async exactly (length, seek = false) {
|
|
270
196
|
if (length > bytes.length - pos) {
|
|
271
197
|
throw new Error('Unexpected end of data')
|
|
272
198
|
}
|
|
273
|
-
|
|
199
|
+
const out = bytes.subarray(pos, pos + length)
|
|
200
|
+
if (seek) {
|
|
201
|
+
pos += length
|
|
202
|
+
}
|
|
203
|
+
return out
|
|
274
204
|
/* c8 ignore next 2 */
|
|
275
205
|
// Node.js 12 c8 bug
|
|
276
206
|
},
|
|
@@ -340,14 +270,19 @@ export function chunkReader (readChunk /*, closer */) {
|
|
|
340
270
|
// Node.js 12 c8 bug
|
|
341
271
|
},
|
|
342
272
|
|
|
343
|
-
async exactly (length) {
|
|
273
|
+
async exactly (length, seek = false) {
|
|
344
274
|
if (currentChunk.length - offset < length) {
|
|
345
275
|
await read(length)
|
|
346
276
|
}
|
|
347
277
|
if (currentChunk.length - offset < length) {
|
|
348
278
|
throw new Error('Unexpected end of data')
|
|
349
279
|
}
|
|
350
|
-
|
|
280
|
+
const out = currentChunk.subarray(offset, offset + length)
|
|
281
|
+
if (seek) {
|
|
282
|
+
pos += length
|
|
283
|
+
offset += length
|
|
284
|
+
}
|
|
285
|
+
return out
|
|
351
286
|
/* c8 ignore next 2 */
|
|
352
287
|
// Node.js 12 c8 bug
|
|
353
288
|
},
|
|
@@ -412,11 +347,14 @@ export function limitReader (reader, byteLimit) {
|
|
|
412
347
|
// Node.js 12 c8 bug
|
|
413
348
|
},
|
|
414
349
|
|
|
415
|
-
async exactly (length) {
|
|
416
|
-
const bytes = await reader.exactly(length)
|
|
350
|
+
async exactly (length, seek = false) {
|
|
351
|
+
const bytes = await reader.exactly(length, seek)
|
|
417
352
|
if (bytes.length + bytesRead > byteLimit) {
|
|
418
353
|
throw new Error('Unexpected end of data')
|
|
419
354
|
}
|
|
355
|
+
if (seek) {
|
|
356
|
+
bytesRead += length
|
|
357
|
+
}
|
|
420
358
|
return bytes
|
|
421
359
|
/* c8 ignore next 2 */
|
|
422
360
|
// Node.js 12 c8 bug
|
package/src/index-browser.js
CHANGED
|
@@ -3,6 +3,8 @@ import { CarIndexer } from './indexer.js'
|
|
|
3
3
|
import { CarBlockIterator, CarCIDIterator } from './iterator.js'
|
|
4
4
|
import { CarWriter } from './writer-browser.js'
|
|
5
5
|
import { CarIndexedReader } from './indexed-reader-browser.js'
|
|
6
|
+
import { CarBufferReader } from './buffer-reader.js'
|
|
7
|
+
import * as CarBufferWriter from './buffer-writer.js'
|
|
6
8
|
|
|
7
9
|
export {
|
|
8
10
|
CarReader,
|
|
@@ -10,5 +12,7 @@ export {
|
|
|
10
12
|
CarBlockIterator,
|
|
11
13
|
CarCIDIterator,
|
|
12
14
|
CarWriter,
|
|
13
|
-
CarIndexedReader
|
|
15
|
+
CarIndexedReader,
|
|
16
|
+
CarBufferReader,
|
|
17
|
+
CarBufferWriter
|
|
14
18
|
}
|
package/src/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { CarReader } from './reader.js'
|
|
2
|
+
import { CarBufferReader } from './buffer-reader.js'
|
|
2
3
|
import { CarIndexer } from './indexer.js'
|
|
3
4
|
import { CarBlockIterator, CarCIDIterator } from './iterator.js'
|
|
4
5
|
import { CarWriter } from './writer.js'
|
|
@@ -7,6 +8,7 @@ import * as CarBufferWriter from './buffer-writer.js'
|
|
|
7
8
|
|
|
8
9
|
export {
|
|
9
10
|
CarReader,
|
|
11
|
+
CarBufferReader,
|
|
10
12
|
CarIndexer,
|
|
11
13
|
CarBlockIterator,
|
|
12
14
|
CarCIDIterator,
|