UNPKG

extract-base-iterator

Version:

Base iterator for extract iterators like tar-iterator and zip-iterator

449 lines 16.4 kB
/** * Buffer Compatibility Layer for Node.js 0.8+ * * Provides buffer utilities that work across all Node.js versions * WITHOUT modifying global Buffer object. * * Version history: * - Node 0.8-4.4: Only has `new Buffer()`, no `Buffer.alloc/from` * - Node 4.5+: Has `Buffer.alloc/from`, deprecates `new Buffer()` * - Node 10+: Warns or errors on `new Buffer()` * * Solution: Feature detection with graceful fallback in both directions. */ // ESM-compatible require - works in both CJS and ESM "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: Object.getOwnPropertyDescriptor(all, name).get }); } _export(exports, { get MAX_SAFE_BUFFER_LENGTH () { return MAX_SAFE_BUFFER_LENGTH; }, get PassThrough () { return PassThrough; }, get Readable () { return Readable; }, get Transform () { return Transform; }, get Writable () { return Writable; }, get allocBuffer () { return allocBuffer; }, get allocBufferUnsafe () { return allocBufferUnsafe; }, get bufferCompare () { return bufferCompare; }, get bufferConcat () { return bufferConcat; }, get bufferEquals () { return bufferEquals; }, get bufferFrom () { return bufferFrom; }, get bufferSliceCopy () { return bufferSliceCopy; }, get canAllocateBufferSize () { return canAllocateBufferSize; }, get createInflateRawStream () { return createInflateRawStream; }, get inflateRaw () { return inflateRaw; }, get isNaN () { return isNaN; }, get objectAssign () { return objectAssign; }, get readUInt64LE () { return readUInt64LE; }, get stringStartsWith () { return stringStartsWith; }, get writeUInt64LE () { return writeUInt64LE; } }); var _module = /*#__PURE__*/ _interop_require_default(require("module")); function _instanceof(left, right) { "@swc/helpers - instanceof"; if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) { return !!right[Symbol.hasInstance](left); } else { return left instanceof right; } } function _interop_require_default(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var _require = typeof require === 'undefined' ? _module.default.createRequire(require("url").pathToFileURL(__filename).toString()) : require; // Feature detection (runs once at module load) var hasBufferAlloc = typeof Buffer.alloc === 'function'; var hasBufferAllocUnsafe = typeof Buffer.allocUnsafe === 'function'; var hasBufferFrom = typeof Buffer.from === 'function' && Buffer.from !== Uint8Array.from; var MAX_SAFE_BUFFER_LENGTH = 256 * 1024 * 1024; // 256MB // Try to detect the actual kMaxLength for this Node version // If we can't detect it (older Node), assume conservative limit var DETECTED_MAX_LENGTH = null; function getMaxBufferLength() { if (DETECTED_MAX_LENGTH !== null) return DETECTED_MAX_LENGTH; // kMaxLength may not exist at runtime on very old or very new Node // Modern Node (v8+) doesn't expose kMaxLength but allows large buffers var maxLen = Buffer.kMaxLength; if (maxLen !== undefined) { DETECTED_MAX_LENGTH = maxLen; } else { // Node 0.8-4.x: use conservative limit // Node 8+: can allocate up to ~2GB (v8 array buffer limit) // Use the higher limit for modern Node var nodeVersion = parseInt(process.version.slice(1).split('.')[0], 10); if (nodeVersion >= 8) { DETECTED_MAX_LENGTH = Number.MAX_SAFE_INTEGER; // Effectively unlimited } else { DETECTED_MAX_LENGTH = 0x3fffffff; // ~1073MB for older Node } } return DETECTED_MAX_LENGTH; } function canAllocateBufferSize(size) { return size >= 0 && size <= MAX_SAFE_BUFFER_LENGTH; } /** * Create a single chunk of the specified size */ function createChunk(size, zeroFill) { if (hasBufferAlloc) { return Buffer.alloc(size); } var buf = new Buffer(size); if (zeroFill) buf.fill(0); return buf; } /** * Combine an array of buffers into one by iterative concatenation * Stays under the actual kMaxLength for each Node version * Uses a "fill and continue" approach */ function combineBuffersPairwise(buffers) { var maxLength = getMaxBufferLength(); // Calculate total size var totalSize = 0; for(var i = 0; i < buffers.length; i++){ totalSize += buffers[i].length; } // If total exceeds this Node version's limit, we cannot combine // LZMA1 requires a single contiguous Buffer input if (totalSize > maxLength) { throw new Error("Cannot combine buffers: total size (".concat(totalSize, " bytes) exceeds Node.js buffer limit (").concat(maxLength, " bytes). LZMA1 archives with folders larger than ").concat(Math.floor(maxLength / 1024 / 1024), "MB cannot be processed on this Node version.")); } // If everything fits in a single allocation, do it directly var result = createChunk(totalSize, false); var offset = 0; for(var i1 = 0; i1 < buffers.length; i1++){ buffers[i1].copy(result, offset); offset += buffers[i1].length; } return result; } /** * Allocate a large buffer by allocating in chunks and combining them * Handles both zero-filled (safe) and uninitialized (unsafe) variants */ function allocBufferLarge(size, zeroFill) { // For large sizes, allocate smaller chunks and combine them var numChunks = Math.ceil(size / MAX_SAFE_BUFFER_LENGTH); var chunks = []; // Allocate individual chunks (each <= MAX_SAFE_BUFFER_LENGTH) for(var i = 0; i < numChunks; i++){ var chunkSize = Math.min(MAX_SAFE_BUFFER_LENGTH, size - i * MAX_SAFE_BUFFER_LENGTH); chunks.push(createChunk(chunkSize, zeroFill)); } // Combine chunks iteratively using pairwise combination return combineBuffersPairwise(chunks); } function allocBuffer(size) { if (size === 0) { return new Buffer(0); } // Use native allocation for sizes within safe limits if (canAllocateBufferSize(size)) { if (hasBufferAlloc) { return Buffer.alloc(size); } // Legacy fallback: new Buffer() is uninitialized, must zero-fill var buf = new Buffer(size); buf.fill(0); return buf; } // For large sizes, allocate in chunks with zero-filling return allocBufferLarge(size, true); } function allocBufferUnsafe(size) { if (size === 0) { return new Buffer(0); } // Use native allocation for sizes within safe limits if (canAllocateBufferSize(size)) { if (hasBufferAllocUnsafe) { return Buffer.allocUnsafe(size); } return new Buffer(size); } // For large sizes, allocate in chunks without zero-filling return allocBufferLarge(size, false); } function bufferFrom(data, encoding) { if (hasBufferFrom) { if (typeof data === 'string') { return Buffer.from(data, encoding); } return Buffer.from(data); } // Node 0.8 compatibility - deprecated Buffer constructor // For Uint8Array, convert to array first (needed for crypto output in Node 0.8) if (_instanceof(data, Uint8Array) && !_instanceof(data, Buffer)) { var arr = []; for(var i = 0; i < data.length; i++){ arr.push(data[i]); } return new Buffer(arr); } return new Buffer(data, encoding); } function bufferCompare(source, target, targetStart, targetEnd, sourceStart, sourceEnd) { sourceStart = sourceStart || 0; sourceEnd = sourceEnd || source.length; targetStart = targetStart || 0; targetEnd = targetEnd || target.length; // Check if native compare with offset support exists (Node 5.10+) if (source.compare && source.compare.length >= 5) { return source.compare(target, targetStart, targetEnd, sourceStart, sourceEnd); } // Manual comparison for older Node versions var sourceLen = sourceEnd - sourceStart; var targetLen = targetEnd - targetStart; var len = Math.min(sourceLen, targetLen); for(var i = 0; i < len; i++){ var s = source[sourceStart + i]; var t = target[targetStart + i]; if (s !== t) return s < t ? -1 : 1; } return sourceLen - targetLen; } function bufferEquals(buf, offset, expected) { if (offset + expected.length > buf.length) return false; for(var i = 0; i < expected.length; i++){ if (buf[offset + i] !== expected[i]) return false; } return true; } function bufferSliceCopy(buf, start, end) { var result = allocBuffer(end - start); buf.copy(result, 0, start, end); return result; } function readUInt64LE(buf, offset) { var low = buf.readUInt32LE(offset); var high = buf.readUInt32LE(offset + 4); return high * 0x100000000 + low; } function writeUInt64LE(buf, value, offset) { var low = value >>> 0; var high = value / 0x100000000 >>> 0; buf.writeUInt32LE(low, offset); buf.writeUInt32LE(high, offset + 4); } function bufferConcat(list, totalLength) { // Calculate actual total length first var actualLength = 0; for(var i = 0; i < list.length; i++){ actualLength += list[i].length; } // Use specified totalLength or actual length var targetLength = totalLength !== undefined ? totalLength : actualLength; // Handle empty list if (list.length === 0) { return new Buffer(0); } // Handle very large concatenations that would exceed buffer limits // Use native Buffer.concat for smaller sizes (faster) if (targetLength <= MAX_SAFE_BUFFER_LENGTH) { // Check if all items are proper Buffers AND no truncation needed // (Node 0.8's Buffer.concat doesn't handle truncation well) var allBuffers = true; for(var j = 0; j < list.length; j++){ if (!_instanceof(list[j], Buffer)) { allBuffers = false; break; } } if (allBuffers && targetLength >= actualLength) { return Buffer.concat(list, targetLength); } } // For large or complex concatenations, use chunked approach // This will use allocBuffer which handles large sizes via chunking var result = allocBuffer(targetLength); var offset = 0; for(var k = 0; k < list.length && offset < targetLength; k++){ var buf = list[k]; var toCopy = Math.min(buf.length, targetLength - offset); if (_instanceof(buf, Buffer)) { buf.copy(result, offset, 0, toCopy); } else { // Uint8Array - need to copy byte by byte for(var l = 0; l < toCopy; l++){ result[offset + l] = buf[l]; } } offset += toCopy; } return result; } function isNaN(value) { // biome-ignore lint/suspicious/noSelfCompare: NaN check pattern return value !== value; } /** * String.prototype.startsWith wrapper for Node.js 0.8+ * - Uses native startsWith on Node 4.0+ / ES2015+ * - Falls back to indexOf on Node 0.8-3.x */ var hasStartsWith = typeof String.prototype.startsWith === 'function'; function stringStartsWith(str, search, position) { if (hasStartsWith) return str.startsWith(search, position); position = position || 0; return str.indexOf(search, position) === position; } /** * Decompress raw DEFLATE data (no zlib/gzip header) * - Uses native zlib.inflateRawSync() on Node 0.11.12+ * - Falls back to pako for Node 0.8-0.10 * * Version history: * - Node 0.8-0.10: No zlib sync methods, use pako * - Node 0.11.12+: zlib.inflateRawSync available */ // Feature detection for native zlib sync methods (Node 0.11.12+) var zlib = null; try { zlib = _require('zlib'); } catch (_e) { // zlib not available (shouldn't happen in Node.js) } var hasNativeInflateRaw = zlib !== null && typeof zlib.inflateRawSync === 'function'; function inflateRaw(input) { if (hasNativeInflateRaw && zlib) { return zlib.inflateRawSync(input); } // Fallback to pako for Node 0.8-0.10 var pako = _require('pako'); return bufferFrom(pako.inflateRaw(input)); } /** * Create a streaming raw DEFLATE decompressor (Transform stream) * Decompresses data incrementally to avoid holding full output in memory. * * - Uses native zlib.createInflateRaw() on Node 0.11.12+ * - Falls back to pako-based Transform for Node 0.8-0.10 * * @returns A Transform stream that decompresses raw DEFLATE data */ // Check for native streaming inflate (Node 0.11.12+ has createInflateRaw) // biome-ignore lint/suspicious/noExplicitAny: createInflateRaw not in older TS definitions var hasNativeStreamingInflate = zlib !== null && typeof zlib.createInflateRaw === 'function'; function createInflateRawStream() { if (hasNativeStreamingInflate && zlib) { // Use native zlib streaming Transform // biome-ignore lint/suspicious/noExplicitAny: createInflateRaw not in older TS definitions return zlib.createInflateRaw(); } // Fallback to pako-based Transform for Node 0.8-0.10 // Use readable-stream for Node 0.8 compatibility var Transform = _require('readable-stream').Transform; var pako = _require('pako'); var inflate = new pako.Inflate({ raw: true, chunkSize: 16384 }); var transform = new Transform(); var pendingChunks = []; var ended = false; // Pako calls onData synchronously during push() inflate.onData = function(chunk) { pendingChunks.push(bufferFrom(chunk)); }; inflate.onEnd = function(status) { ended = true; if (status !== 0) { transform.emit('error', new Error("Inflate error: ".concat(inflate.msg || 'unknown'))); } }; transform._transform = function(chunk, _encoding, callback) { try { inflate.push(chunk, false); // Push any pending decompressed chunks while(pendingChunks.length > 0){ this.push(pendingChunks.shift()); } callback(); } catch (err) { callback(err); } }; transform._flush = function(callback) { try { inflate.push(new Uint8Array(0), true); // Signal end // Push any remaining decompressed chunks while(pendingChunks.length > 0){ this.push(pendingChunks.shift()); } if (ended && inflate.err) { callback(new Error("Inflate error: ".concat(inflate.msg || 'unknown'))); } else { callback(); } } catch (err) { callback(err); } }; return transform; } /** * Object.assign wrapper for Node.js 0.8+ * - Uses native Object.assign on Node 4.0+ * - Falls back to manual property copy on Node 0.8-3.x */ var hasObjectAssign = typeof Object.assign === 'function'; var _hasOwnProperty = Object.prototype.hasOwnProperty; function objectAssign(target, source) { if (hasObjectAssign) return Object.assign(target, source); for(var key in source){ if (_hasOwnProperty.call(source, key)) target[key] = source[key]; } return target; } /** * Stream compatibility - Transform class * - Uses native stream.Transform on Node 0.10+ * - Falls back to readable-stream for Node 0.8 */ var major = +process.versions.node.split('.')[0]; var Readable = major > 0 ? _require('stream').Readable : _require('readable-stream').Readable; var Writable = major > 0 ? _require('stream').Writable : _require('readable-stream').Writable; var Transform = major > 0 ? _require('stream').Transform : _require('readable-stream').Transform; var PassThrough = major > 0 ? _require('stream').PassThrough : _require('readable-stream').PassThrough; /* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (var key in exports) { exports.default[key] = exports[key]; } } catch (_) {}; module.exports = exports.default; }