src/vs/base/common/buffer.ts

499 LOC · 469 covered · 30 uncovered · 133 ranges · 13454 concepts · 58 introducers · 6883 tests

File neighbourhood

The centred file is linked to every concept that introduces one of its ranges, every test that runs code from the file, and the gray connector concepts standing between those tests and the file's own introducer concepts. Undirected links join concepts to every file where they introduce source and concepts to the tests they introduce; arrows show specialization between the displayed concepts and bridge only concepts omitted from this view. Concept colors match the source ranges below; connector concepts have no source color and are shown in gray.

Focused file, its introducer and connector concepts, their introduced files, and tests that run code from the file

In the embedded map, ordinary wheel input scrolls the page; use the visible controls to zoom and drag to pan. Open the full-screen map for canvas navigation: wheel pans, Ctrl/Command plus wheel zooms, and arrow keys pan when this region is focused. On touch screens, open the full-screen map to pan or pinch. If JavaScript or WebGL is unavailable, use the related-file, concept, and source links on this page.

Graph controls are ready.

Interactive rendering requires JavaScript and WebGL. Use the related-file, concept, and source links on this page while the interactive map is unavailable.

1 > /*--------------------------------------------------------------------------------------------- buffer.ts ×42
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { Lazy } from './lazy.js';
7 > import * as streams from './stream.js';
8 >
9 > interface NodeBuffer {
10 > allocUnsafe(size: number): Uint8Array;
11 > isBuffer(obj: unknown): obj is NodeBuffer;
12 > from(arrayBuffer: ArrayBufferLike, byteOffset?: number, length?: number): Uint8Array;
13 > from(data: string): Uint8Array;
14 > }
15 >
16 > declare const Buffer: NodeBuffer;
17 >
18 > const hasBuffer = (typeof Buffer !== 'undefined');
19 > const indexOfTable = new Lazy(() => new Uint8Array(256));
20 >
21 > let textEncoder: { encode: (input: string) => Uint8Array } | null;
22 > let textDecoder: { decode: (input: Uint8Array) => string } | null;
23 >
24 > export class VSBuffer {
25 >
26 > /**
27 > * When running in a nodejs context, the backing store for the returned `VSBuffer` instance
28 > * might use a nodejs Buffer allocated from node's Buffer pool, which is not transferrable.
29 > */
30 > static alloc(byteLength: number): VSBuffer {
31 > if (hasBuffer) { buffer.ts ×2
32 > return new VSBuffer(Buffer.allocUnsafe(byteLength));
33 > } else {
34 return new VSBuffer(new Uint8Array(byteLength));
35 }
36 > } buffer.ts ×2
38 > /**
39 > * When running in a nodejs context, if `actual` is not a nodejs Buffer, the backing store for
40 > * the returned `VSBuffer` instance might use a nodejs Buffer allocated from node's Buffer pool,
41 > * which is not transferrable.
42 > */
43 > static wrap(actual: Uint8Array): VSBuffer {
44 > if (hasBuffer && !(Buffer.isBuffer(actual))) { buffer.ts ×2
45 > // https://nodejs.org/dist/latest-v10.x/docs/api/buffer.html#buffer_class_method_buffer_from_arraybuffer_byteoffset_length buffer.ts ×1
46 > // Create a zero-copy Buffer wrapper around the ArrayBuffer pointed to by the Uint8Array
47 > actual = Buffer.from(actual.buffer, actual.byteOffset, actual.byteLength);
48 > }
49 > return new VSBuffer(actual); buffer.ts ×2
50 > }
52 > /**
53 > * When running in a nodejs context, the backing store for the returned `VSBuffer` instance
54 > * might use a nodejs Buffer allocated from node's Buffer pool, which is not transferrable.
55 > */
56 > static fromString(source: string, options?: { dontUseNodeBuffer?: boolean }): VSBuffer {
57 > const dontUseNodeBuffer = options?.dontUseNodeBuffer || false; buffer.ts ×2
58 > if (!dontUseNodeBuffer && hasBuffer) {
59 > return new VSBuffer(Buffer.from(source));
60 > } else {
61 if (!textEncoder) {
62 textEncoder = new TextEncoder();
63 }
64 return new VSBuffer(textEncoder.encode(source));
65 }
66 > } buffer.ts ×2
68 > /**
69 > * When running in a nodejs context, the backing store for the returned `VSBuffer` instance
70 > * might use a nodejs Buffer allocated from node's Buffer pool, which is not transferrable.
71 > */
72 > static fromByteArray(source: number[]): VSBuffer {
73 > const result = VSBuffer.alloc(source.length); buffer.ts ×1
74 > for (let i = 0, len = source.length; i < len; i++) {
75 > result.buffer[i] = source[i];
76 > }
77 > return result;
78 > }
80 > /**
81 > * When running in a nodejs context, the backing store for the returned `VSBuffer` instance
82 > * might use a nodejs Buffer allocated from node's Buffer pool, which is not transferrable.
83 > */
84 > static concat(buffers: VSBuffer[], totalLength?: number): VSBuffer {
85 > if (typeof totalLength === 'undefined') { buffer.ts ×3
86 > totalLength = 0; buffer.ts ×2
87 > for (let i = 0, len = buffers.length; i < len; i++) {
88 > totalLength += buffers[i].byteLength; buffer.ts ×1
89 > }
90 > } buffer.ts ×2
92 > const ret = VSBuffer.alloc(totalLength);
93 > let offset = 0;
94 > for (let i = 0, len = buffers.length; i < len; i++) {
95 > const element = buffers[i]; buffer.ts ×1
96 > ret.set(element, offset);
97 > offset += element.byteLength;
98 > }
100 > return ret;
101 > }
103 > static isNativeBuffer(buffer: unknown): boolean {
104 > return hasBuffer && Buffer.isBuffer(buffer); ipc.ts ×43
105 > }
107 > readonly buffer: Uint8Array;
108 > readonly byteLength: number;
109 >
110 > private constructor(buffer: Uint8Array) {
111 > this.buffer = buffer; buffer.ts ×1
112 > this.byteLength = this.buffer.byteLength;
113 > }
115 > /**
116 > * When running in a nodejs context, the backing store for the returned `VSBuffer` instance
117 > * might use a nodejs Buffer allocated from node's Buffer pool, which is not transferrable.
118 > */
119 > clone(): VSBuffer {
120 > const result = VSBuffer.alloc(this.byteLength); buffer.ts ×1
121 > result.set(this);
122 > return result;
123 > }
125 > toString(): string {
126 > if (hasBuffer) { buffer.ts ×2
127 > return this.buffer.toString();
128 > } else {
129 if (!textDecoder) {
130 textDecoder = new TextDecoder(undefined, { ignoreBOM: true });
131 }
132 return textDecoder.decode(this.buffer);
133 }
134 > } buffer.ts ×2
136 > slice(start?: number, end?: number): VSBuffer {
137 > // IMPORTANT: use subarray instead of slice because TypedArray#slice buffer.ts ×1
138 > // creates shallow copy and NodeBuffer#slice doesn't. The use of subarray
139 > // ensures the same, performance, behaviour.
140 > return new VSBuffer(this.buffer.subarray(start, end));
141 > }
143 > set(array: VSBuffer, offset?: number): void;
144 > set(array: Uint8Array, offset?: number): void;
145 > set(array: ArrayBuffer, offset?: number): void;
146 > set(array: ArrayBufferView, offset?: number): void;
147 > set(array: VSBuffer | Uint8Array | ArrayBuffer | ArrayBufferView, offset?: number): void;
148 > set(array: VSBuffer | Uint8Array | ArrayBuffer | ArrayBufferView, offset?: number): void {
149 > if (array instanceof VSBuffer) { buffer.ts ×2
150 > this.buffer.set(array.buffer, offset);
151 > } else if (array instanceof Uint8Array) {
152 > this.buffer.set(array, offset); buffer.ts ×3
153 > } else if (array instanceof ArrayBuffer) {
154 this.buffer.set(new Uint8Array(array), offset);
155 > } else if (ArrayBuffer.isView(array)) { buffer.ts ×3
156 this.buffer.set(new Uint8Array(array.buffer, array.byteOffset, array.byteLength), offset);
157 > } else { buffer.ts ×3
158 > throw new Error(`Unknown argument 'array'`);
159 > }
160 > } buffer.ts ×2
162 > readUInt32BE(offset: number): number {
163 > return readUInt32BE(this.buffer, offset); buffer.ts ×2
164 > }
166 > writeUInt32BE(value: number, offset: number): void {
167 > writeUInt32BE(this.buffer, value, offset); buffer.ts ×2
168 > }
170 > readUInt32LE(offset: number): number {
171 > return readUInt32LE(this.buffer, offset); buffer.ts ×4
172 > }
174 > writeUInt32LE(value: number, offset: number): void {
175 > writeUInt32LE(this.buffer, value, offset); buffer.ts ×4
176 > }
178 > readUInt8(offset: number): number {
179 > return readUInt8(this.buffer, offset); buffer.ts ×1
180 > }
182 > writeUInt8(value: number, offset: number): void {
183 > writeUInt8(this.buffer, value, offset); buffer.ts ×1
184 > }
186 > indexOf(subarray: VSBuffer | Uint8Array, offset = 0) {
187 > return binaryIndexOf(this.buffer, subarray instanceof VSBuffer ? subarray.buffer : subarray, offset); buffer.ts ×2
188 > }
190 > equals(other: VSBuffer): boolean {
191 > if (this === other) { buffer.ts ×1
192 > return true;
193 > }
194 >
195 > if (this.byteLength !== other.byteLength) {
196 > return false;
197 > }
198 >
199 > return this.buffer.every((value, index) => value === other.buffer[index]);
200 > }
201 > } buffer.ts ×42
202 >
203 > /**
204 > * Like String.indexOf, but works on Uint8Arrays.
205 > * Uses the boyer-moore-horspool algorithm to be reasonably speedy.
206 > */
207 > export function binaryIndexOf(haystack: Uint8Array, needle: Uint8Array, offset = 0): number {
208 > const needleLen = needle.byteLength; buffer.ts ×2
209 > const haystackLen = haystack.byteLength;
210 >
211 > if (needleLen === 0) {
212 > return 0; buffer.ts ×1
213 > }
215 > if (needleLen === 1) {
216 > return haystack.indexOf(needle[0], offset); buffer.ts ×2
217 > }
219 > if (needleLen > haystackLen - offset) {
220 > return -1;
221 > }
222 >
223 > // find index of the subarray using boyer-moore-horspool algorithm
224 > const table = indexOfTable.value;
225 > table.fill(needle.length);
226 > for (let i = 0; i < needle.length; i++) {
227 > table[needle[i]] = needle.length - i - 1;
228 > }
229 >
230 > let i = offset + needle.length - 1;
231 > let j = i;
232 > let result = -1;
233 > while (i < haystackLen) {
234 > if (haystack[i] === needle[j]) {
235 > if (j === 0) {
236 > result = i;
237 > break;
238 > }
239 >
240 > i--;
241 > j--;
242 > } else {
243 > i += Math.max(needle.length - j, table[haystack[i]]);
244 > j = needle.length - 1;
245 > }
246 > }
247 >
248 > return result;
249 > }
251 > export function readUInt16LE(source: Uint8Array, offset: number): number {
252 > return ( stringBuilder.ts ×2
253 > ((source[offset + 0] << 0) >>> 0) |
254 > ((source[offset + 1] << 8) >>> 0)
255 > );
256 > }
258 > export function writeUInt16LE(destination: Uint8Array, value: number, offset: number): void {
259 > destination[offset + 0] = (value & 0b11111111); buffer.ts ×1
260 > value = value >>> 8;
261 > destination[offset + 1] = (value & 0b11111111);
262 > }
264 > export function readUInt32BE(source: Uint8Array, offset: number): number {
265 > return ( buffer.ts ×1
266 > source[offset] * 2 ** 24
267 > + source[offset + 1] * 2 ** 16
268 > + source[offset + 2] * 2 ** 8
269 > + source[offset + 3]
270 > );
271 > }
273 > export function writeUInt32BE(destination: Uint8Array, value: number, offset: number): void {
274 > destination[offset + 3] = value; buffer.ts ×1
275 > value = value >>> 8;
276 > destination[offset + 2] = value;
277 > value = value >>> 8;
278 > destination[offset + 1] = value;
279 > value = value >>> 8;
280 > destination[offset] = value;
281 > }
283 > export function readUInt32LE(source: Uint8Array, offset: number): number {
284 > return ( buffer.ts ×4
285 > ((source[offset + 0] << 0) >>> 0) |
286 > ((source[offset + 1] << 8) >>> 0) |
287 > ((source[offset + 2] << 16) >>> 0) |
288 > ((source[offset + 3] << 24) >>> 0)
289 > );
290 > }
292 > export function writeUInt32LE(destination: Uint8Array, value: number, offset: number): void {
293 > destination[offset + 0] = (value & 0b11111111); buffer.ts ×4
294 > value = value >>> 8;
295 > destination[offset + 1] = (value & 0b11111111);
296 > value = value >>> 8;
297 > destination[offset + 2] = (value & 0b11111111);
298 > value = value >>> 8;
299 > destination[offset + 3] = (value & 0b11111111);
300 > }
302 > export function readUInt8(source: Uint8Array, offset: number): number {
303 > return source[offset]; buffer.ts ×1
304 > }
306 > export function writeUInt8(destination: Uint8Array, value: number, offset: number): void {
307 > destination[offset] = value; buffer.ts ×1
308 > }
310 > export interface VSBufferReadable extends streams.Readable<VSBuffer> { }
311 >
312 > export interface VSBufferReadableStream extends streams.ReadableStream<VSBuffer> { }
313 >
314 > export interface VSBufferWriteableStream extends streams.WriteableStream<VSBuffer> { }
315 >
316 > export interface VSBufferReadableBufferedStream extends streams.ReadableBufferedStream<VSBuffer> { }
317 >
318 > export function readableToBuffer(readable: VSBufferReadable): VSBuffer {
319 > return streams.consumeReadable<VSBuffer>(readable, chunks => VSBuffer.concat(chunks)); buffer.ts ×1
320 > }
322 > export function bufferToReadable(buffer: VSBuffer): VSBufferReadable {
323 > return streams.toReadable<VSBuffer>(buffer); buffer.ts ×1
324 > }
326 > export function streamToBuffer(stream: streams.ReadableStream<VSBuffer>): Promise<VSBuffer> {
327 > return streams.consumeStream<VSBuffer>(stream, chunks => VSBuffer.concat(chunks)); buffer.ts ×1
328 > }
330 > export async function bufferedStreamToBuffer(bufferedStream: streams.ReadableBufferedStream<VSBuffer>): Promise<VSBuffer> { buffer.ts ×1
331 > if (bufferedStream.ended) {
332 > return VSBuffer.concat(bufferedStream.buffer);
333 > }
334
335 return VSBuffer.concat([
336
337 // Include already read chunks...
338 ...bufferedStream.buffer,
339
340 // ...and all additional chunks
341 await streamToBuffer(bufferedStream.stream)
342 ]);
343 }
345 > export function bufferToStream(buffer: VSBuffer): streams.ReadableStream<VSBuffer> {
346 > return streams.toStream<VSBuffer>(buffer, chunks => VSBuffer.concat(chunks)); buffer.ts ×1
347 > }
349 > export function streamToBufferReadableStream(stream: streams.ReadableStreamEvents<Uint8Array | string>): streams.ReadableStream<VSBuffer> {
350 > return streams.transform<Uint8Array | string, VSBuffer>(stream, { data: data => typeof data === 'string' ? VSBuffer.fromString(data) : VSBuffer.wrap(data) }, chunks => VSBuffer.concat(chunks)); buffer.ts ×1
351 > }
353 > export function newWriteableBufferStream(options?: streams.WriteableStreamOptions): streams.WriteableStream<VSBuffer> {
354 > return streams.newWriteableStream<VSBuffer>(chunks => VSBuffer.concat(chunks), options); buffer.ts ×1
355 > }
357 > export function prefixedBufferReadable(prefix: VSBuffer, readable: VSBufferReadable): VSBufferReadable {
358 return streams.prefixedReadable(prefix, readable, chunks => VSBuffer.concat(chunks));
359 }
361 > export function prefixedBufferStream(prefix: VSBuffer, stream: VSBufferReadableStream): VSBufferReadableStream {
362 return streams.prefixedStream(prefix, stream, chunks => VSBuffer.concat(chunks));
363 }
365 > /** Decodes base64 to a uint8 array. URL-encoded and unpadded base64 is allowed. */
366 > export function decodeBase64(encoded: string) {
367 > let building = 0; buffer.ts ×3
368 > let remainder = 0;
369 > let bufi = 0;
370 >
371 > // The simpler way to do this is `Uint8Array.from(atob(str), c => c.charCodeAt(0))`,
372 > // but that's about 10-20x slower than this function in current Chromium versions.
373 >
374 > const buffer = new Uint8Array(Math.floor(encoded.length / 4 * 3));
375 > const append = (value: number) => {
376 > switch (remainder) {
377 > case 3:
378 > buffer[bufi++] = building | value;
379 > remainder = 0;
380 > break;
381 > case 2:
382 > buffer[bufi++] = building | (value >>> 2);
383 > building = value << 6;
384 > remainder = 3;
385 > break;
386 > case 1:
387 > buffer[bufi++] = building | (value >>> 4);
388 > building = value << 4;
389 > remainder = 2;
390 > break;
391 > default:
392 > building = value << 2;
393 > remainder = 1;
394 > }
395 > };
396 >
397 > for (let i = 0; i < encoded.length; i++) {
398 > const code = encoded.charCodeAt(i);
399 > // See https://datatracker.ietf.org/doc/html/rfc4648#section-4
400 > // This branchy code is about 3x faster than an indexOf on a base64 char string.
401 > if (code >= 65 && code <= 90) {
402 > append(code - 65); // A-Z starts ranges from char code 65 to 90 buffer.ts ×3
403 > } else if (code >= 97 && code <= 122) { buffer.ts ×3
404 > append(code - 97 + 26); // a-z starts ranges from char code 97 to 122, starting at byte 26 buffer.ts ×2
405 > } else if (code >= 48 && code <= 57) {
406 > append(code - 48 + 52); // 0-9 starts ranges from char code 48 to 58, starting at byte 52 buffer.ts ×1
407 > } else if (code === 43 || code === 45) { buffer.ts ×2
408 > append(62); // "+" or "-" for URLS buffer.ts ×2
409 > } else if (code === 47 || code === 95) { buffer.ts ×3
410 > append(63); // "/" or "_" for URLS buffer.ts ×2
411 > } else if (code === 61) { buffer.ts ×3
412 > break; // "=" buffer.ts ×1
413 > } else { buffer.ts ×3
414 > throw new SyntaxError(`Unexpected base64 character ${encoded[i]}`); buffer.ts ×2
415 > }
416 > } buffer.ts ×3
418 > const unpadded = bufi;
419 > while (remainder > 0) {
420 > append(0); buffer.ts ×1
421 > }
423 > // slice is needed to account for overestimation due to padding
424 > return VSBuffer.wrap(buffer).slice(0, unpadded);
425 > }
427 > const base64Alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
428 > const base64UrlSafeAlphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';
429 >
430 > /** Encodes a buffer to a base64 string. */
431 > export function encodeBase64({ buffer }: VSBuffer, padded = true, urlSafe = false) {
432 > const dictionary = urlSafe ? base64UrlSafeAlphabet : base64Alphabet; buffer.ts ×4
433 > let output = '';
434 >
435 > const remainder = buffer.byteLength % 3;
436 >
437 > let i = 0;
438 > for (; i < buffer.byteLength - remainder; i += 3) {
439 > const a = buffer[i + 0]; buffer.ts ×1
440 > const b = buffer[i + 1];
441 > const c = buffer[i + 2];
442 >
443 > output += dictionary[a >>> 2];
444 > output += dictionary[(a << 4 | b >>> 4) & 0b111111];
445 > output += dictionary[(b << 2 | c >>> 6) & 0b111111];
446 > output += dictionary[c & 0b111111];
447 > }
449 > if (remainder === 1) {
450 > const a = buffer[i + 0]; buffer.ts ×1
451 > output += dictionary[a >>> 2];
452 > output += dictionary[(a << 4) & 0b111111];
453 > if (padded) { output += '=='; }
454 > } else if (remainder === 2) { buffer.ts ×4
455 > const a = buffer[i + 0]; buffer.ts ×1
456 > const b = buffer[i + 1];
457 > output += dictionary[a >>> 2];
458 > output += dictionary[(a << 4 | b >>> 4) & 0b111111];
459 > output += dictionary[(b << 2) & 0b111111];
460 > if (padded) { output += '='; }
461 > }
463 > return output;
464 > }
466 > const hexChars = '0123456789abcdef';
467 > export function encodeHex({ buffer }: VSBuffer): string {
468 > let result = ''; buffer.ts ×1
469 > for (let i = 0; i < buffer.length; i++) {
470 > const byte = buffer[i];
471 > result += hexChars[byte >>> 4];
472 > result += hexChars[byte & 0x0f];
473 > }
474 > return result;
475 > }
477 > export function decodeHex(hex: string): VSBuffer {
478 > if (hex.length % 2 !== 0) { buffer.ts ×6
479 throw new SyntaxError('Hex string must have an even length');
480 }
481 > const out = new Uint8Array(hex.length >> 1); buffer.ts ×6
482 > for (let i = 0; i < hex.length;) {
483 > out[i >> 1] = (decodeHexChar(hex, i++) << 4) | decodeHexChar(hex, i++);
484 > }
485 > return VSBuffer.wrap(out); buffer.ts ×2
486 > }
488 > function decodeHexChar(str: string, position: number) { buffer.ts ×6
489 > const s = str.charCodeAt(position);
490 > if (s >= 48 && s <= 57) { // '0'-'9'
491 > return s - 48; buffer.ts ×2
492 > } else if (s >= 97 && s <= 102) { // 'a'-'f' buffer.ts ×6
493 > return s - 87; buffer.ts ×1
494 > } else if (s >= 65 && s <= 70) { // 'A'-'F' buffer.ts ×6
495 > return s - 55; mcpServer.ts ×36
496 > } else { buffer.ts ×1
497 > throw new SyntaxError(`Invalid hex character at position ${position}`); buffer.ts ×2
498 > }
499 > } buffer.ts ×6