extract-base-iterator
Version:
Base iterator for extract iterators like tar-iterator and zip-iterator
449 lines • 16.4 kB
JavaScript
/**
* 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; }