/** * Buffer manipulation utilities for protocol detection */ // Import from protocols import { HttpParser } from '../../protocols/http/index.js'; /** * BufferAccumulator class for handling fragmented data */ export class BufferAccumulator { private chunks: Buffer[] = []; private totalLength = 0; /** * Append data to the accumulator */ append(data: Buffer): void { this.chunks.push(data); this.totalLength += data.length; } /** * Get the accumulated buffer */ getBuffer(): Buffer { if (this.chunks.length === 0) { return Buffer.alloc(0); } if (this.chunks.length === 1) { return this.chunks[0]; } return Buffer.concat(this.chunks, this.totalLength); } /** * Get current buffer length */ length(): number { return this.totalLength; } /** * Clear all accumulated data */ clear(): void { this.chunks = []; this.totalLength = 0; } /** * Check if accumulator has minimum bytes */ hasMinimumBytes(minBytes: number): boolean { return this.totalLength >= minBytes; } } /** * Read a big-endian 16-bit integer from buffer */ export function readUInt16BE(buffer: Buffer, offset: number): number { if (offset + 2 > buffer.length) { throw new Error('Buffer too short for UInt16BE read'); } return (buffer[offset] << 8) | buffer[offset + 1]; } /** * Read a big-endian 24-bit integer from buffer */ export function readUInt24BE(buffer: Buffer, offset: number): number { if (offset + 3 > buffer.length) { throw new Error('Buffer too short for UInt24BE read'); } return (buffer[offset] << 16) | (buffer[offset + 1] << 8) | buffer[offset + 2]; } /** * Find a byte sequence in a buffer */ export function findSequence(buffer: Buffer, sequence: Buffer, startOffset = 0): number { if (sequence.length === 0) { return startOffset; } const searchLength = buffer.length - sequence.length + 1; for (let i = startOffset; i < searchLength; i++) { let found = true; for (let j = 0; j < sequence.length; j++) { if (buffer[i + j] !== sequence[j]) { found = false; break; } } if (found) { return i; } } return -1; } /** * Extract a line from buffer (up to CRLF or LF) */ export function extractLine(buffer: Buffer, startOffset = 0): { line: string; nextOffset: number } | null { // Delegate to protocol parser return HttpParser.extractLine(buffer, startOffset); } /** * Check if buffer starts with a string (case-insensitive) */ export function startsWithString(buffer: Buffer, str: string, offset = 0): boolean { if (offset + str.length > buffer.length) { return false; } const bufferStr = buffer.slice(offset, offset + str.length).toString('utf8'); return bufferStr.toLowerCase() === str.toLowerCase(); } /** * Safe buffer slice that doesn't throw on out-of-bounds */ export function safeSlice(buffer: Buffer, start: number, end?: number): Buffer { const safeStart = Math.max(0, Math.min(start, buffer.length)); const safeEnd = end === undefined ? buffer.length : Math.max(safeStart, Math.min(end, buffer.length)); return buffer.slice(safeStart, safeEnd); } /** * Check if buffer contains printable ASCII */ export function isPrintableAscii(buffer: Buffer, length?: number): boolean { // Delegate to protocol parser return HttpParser.isPrintableAscii(buffer, length); }