@@ -49,26 +49,27 @@ export default class CSI extends IndexFile {
49
49
throw new Error ( 'CSI indexes do not support indexcov' )
50
50
}
51
51
52
- parseAuxData ( bytes : Buffer , offset : number ) {
53
- const formatFlags = bytes . readInt32LE ( offset )
52
+ parseAuxData ( bytes : Uint8Array , offset : number ) {
53
+ const dataView = new DataView ( bytes . buffer )
54
+ const formatFlags = dataView . getInt32 ( offset , true )
54
55
const coordinateType =
55
56
formatFlags & 0x10000 ? 'zero-based-half-open' : '1-based-closed'
56
57
const format = { 0 : 'generic' , 1 : 'SAM' , 2 : 'VCF' } [ formatFlags & 0xf ]
57
58
if ( ! format ) {
58
59
throw new Error ( `invalid Tabix preset format flags ${ formatFlags } ` )
59
60
}
60
61
const columnNumbers = {
61
- ref : bytes . readInt32LE ( offset + 4 ) ,
62
- start : bytes . readInt32LE ( offset + 8 ) ,
63
- end : bytes . readInt32LE ( offset + 12 ) ,
62
+ ref : dataView . getInt32 ( offset + 4 , true ) ,
63
+ start : dataView . getInt32 ( offset + 8 , true ) ,
64
+ end : dataView . getInt32 ( offset + 12 , true ) ,
64
65
}
65
- const metaValue = bytes . readInt32LE ( offset + 16 )
66
+ const metaValue = dataView . getInt32 ( offset + 16 , true )
66
67
const metaChar = metaValue ? String . fromCharCode ( metaValue ) : null
67
- const skipLines = bytes . readInt32LE ( offset + 20 )
68
- const nameSectionLength = bytes . readInt32LE ( offset + 24 )
68
+ const skipLines = dataView . getInt32 ( offset + 20 , true )
69
+ const nameSectionLength = dataView . getInt32 ( offset + 24 , true )
69
70
70
71
const { refIdToName, refNameToId } = this . _parseNameBytes (
71
- bytes . slice ( offset + 28 , offset + 28 + nameSectionLength ) ,
72
+ bytes . subarray ( offset + 28 , offset + 28 + nameSectionLength ) ,
72
73
)
73
74
74
75
return {
@@ -82,15 +83,16 @@ export default class CSI extends IndexFile {
82
83
}
83
84
}
84
85
85
- _parseNameBytes ( namesBytes : Buffer ) {
86
+ _parseNameBytes ( namesBytes : Uint8Array ) {
86
87
let currRefId = 0
87
88
let currNameStart = 0
88
89
const refIdToName = [ ]
89
90
const refNameToId : Record < string , number > = { }
91
+ const decoder = new TextDecoder ( 'utf8' )
90
92
for ( let i = 0 ; i < namesBytes . length ; i += 1 ) {
91
93
if ( ! namesBytes [ i ] ) {
92
94
if ( currNameStart < i ) {
93
- let refName = namesBytes . toString ( 'utf8' , currNameStart , i )
95
+ let refName = decoder . decode ( namesBytes . subarray ( currNameStart , i ) )
94
96
refName = this . renameRefSeq ( refName )
95
97
refIdToName [ currRefId ] = refName
96
98
refNameToId [ refName ] = currRefId
@@ -99,30 +101,34 @@ export default class CSI extends IndexFile {
99
101
currRefId += 1
100
102
}
101
103
}
102
- return { refNameToId, refIdToName }
104
+ return {
105
+ refNameToId,
106
+ refIdToName,
107
+ }
103
108
}
104
109
105
110
// fetch and parse the index
106
111
107
112
async _parse ( opts : Options = { } ) {
108
113
const bytes = await unzip ( await this . filehandle . readFile ( opts ) )
114
+ const dataView = new DataView ( bytes . buffer )
109
115
110
116
// check TBI magic numbers
111
117
let csiVersion
112
- if ( bytes . readUInt32LE ( 0 ) === CSI1_MAGIC ) {
118
+ if ( dataView . getUint32 ( 0 , true ) === CSI1_MAGIC ) {
113
119
csiVersion = 1
114
- } else if ( bytes . readUInt32LE ( 0 ) === CSI2_MAGIC ) {
120
+ } else if ( dataView . getUint32 ( 0 , true ) === CSI2_MAGIC ) {
115
121
csiVersion = 2
116
122
} else {
117
123
throw new Error ( 'Not a CSI file' )
118
124
// TODO: do we need to support big-endian CSI files?
119
125
}
120
126
121
- this . minShift = bytes . readInt32LE ( 4 )
122
- this . depth = bytes . readInt32LE ( 8 )
127
+ this . minShift = dataView . getInt32 ( 4 , true )
128
+ this . depth = dataView . getInt32 ( 8 , true )
123
129
this . maxBinNumber = ( ( 1 << ( ( this . depth + 1 ) * 3 ) ) - 1 ) / 7
124
130
const maxRefLength = 2 ** ( this . minShift + this . depth * 3 )
125
- const auxLength = bytes . readInt32LE ( 12 )
131
+ const auxLength = dataView . getInt32 ( 12 , true )
126
132
const aux =
127
133
auxLength && auxLength >= 30
128
134
? this . parseAuxData ( bytes , 16 )
@@ -134,19 +140,19 @@ export default class CSI extends IndexFile {
134
140
coordinateType : 'zero-based-half-open' ,
135
141
format : 'generic' ,
136
142
}
137
- const refCount = bytes . readInt32LE ( 16 + auxLength )
143
+ const refCount = dataView . getInt32 ( 16 + auxLength , true )
138
144
139
145
// read the indexes for each reference sequence
140
146
let firstDataLine : VirtualOffset | undefined
141
147
let currOffset = 16 + auxLength + 4
142
148
const indices = new Array ( refCount ) . fill ( 0 ) . map ( ( ) => {
143
149
// the binning index
144
- const binCount = bytes . readInt32LE ( currOffset )
150
+ const binCount = dataView . getInt32 ( currOffset , true )
145
151
currOffset += 4
146
152
const binIndex : Record < string , Chunk [ ] > = { }
147
153
let stats // < provided by parsing a pseudo-bin, if present
148
154
for ( let j = 0 ; j < binCount ; j += 1 ) {
149
- const bin = bytes . readUInt32LE ( currOffset )
155
+ const bin = dataView . getUint32 ( currOffset , true )
150
156
if ( bin > this . maxBinNumber ) {
151
157
// this is a fake bin that actually has stats information
152
158
// about the reference sequence in it
@@ -155,7 +161,7 @@ export default class CSI extends IndexFile {
155
161
} else {
156
162
const loffset = fromBytes ( bytes , currOffset + 4 )
157
163
firstDataLine = this . _findFirstData ( firstDataLine , loffset )
158
- const chunkCount = bytes . readInt32LE ( currOffset + 12 )
164
+ const chunkCount = dataView . getInt32 ( currOffset + 12 , true )
159
165
currOffset += 16
160
166
const chunks = new Array ( chunkCount )
161
167
for ( let k = 0 ; k < chunkCount ; k += 1 ) {
@@ -186,14 +192,15 @@ export default class CSI extends IndexFile {
186
192
}
187
193
}
188
194
189
- parsePseudoBin ( bytes : Buffer , offset : number ) {
190
- const lineCount = longToNumber (
191
- Long . fromBytesLE (
192
- bytes . slice ( offset + 28 , offset + 36 ) as unknown as number [ ] ,
193
- true ,
195
+ parsePseudoBin ( bytes : Uint8Array , offset : number ) {
196
+ return {
197
+ lineCount : longToNumber (
198
+ Long . fromBytesLE (
199
+ bytes . slice ( offset + 28 , offset + 36 ) as unknown as number [ ] ,
200
+ true ,
201
+ ) ,
194
202
) ,
195
- )
196
- return { lineCount }
203
+ }
197
204
}
198
205
199
206
async blocksForRange (
0 commit comments