-
-
Notifications
You must be signed in to change notification settings - Fork 297
feat: eliminate Buffer polyfill for browser builds #384
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,206 @@ | ||
| "use strict" | ||
|
|
||
| // Minimal Buffer shim for iconv-lite browser usage. | ||
| // Implements only the subset of Buffer API used by iconv-lite codecs. | ||
| // Extends Uint8Array so instanceof checks and standard web APIs work. | ||
|
|
||
| var textEncoder = new TextEncoder() | ||
| var textDecoder = new TextDecoder() | ||
|
|
||
| class BufferShim extends Uint8Array { | ||
| // Prevent inherited methods (like map, filter) from creating BufferShim instances. | ||
| static get [Symbol.species] () { return Uint8Array } | ||
|
|
||
| static alloc (size, fill) { | ||
| var buf = new BufferShim(size) | ||
| if (fill !== undefined && fill !== 0) { | ||
| buf.fill(fill) | ||
| } | ||
| return buf | ||
| } | ||
|
|
||
| static from (arg, encoding) { | ||
| if (typeof arg === "string") { | ||
| return BufferShim._fromString(arg, encoding) | ||
| } | ||
| // Uint8Array, Array, or other array-like | ||
| var result = new BufferShim(arg.length) | ||
| result.set(arg) | ||
| return result | ||
| } | ||
|
|
||
| static _fromString (str, encoding) { | ||
| if (!encoding || encoding === "utf8" || encoding === "utf-8") { | ||
| var encoded = textEncoder.encode(str) | ||
| var buf = new BufferShim(encoded.length) | ||
| buf.set(encoded) | ||
| return buf | ||
| } | ||
|
|
||
| if (encoding === "ucs2" || encoding === "ucs-2" || | ||
| encoding === "utf16le" || encoding === "utf-16le") { | ||
| var buf = new BufferShim(str.length * 2) | ||
| for (var i = 0; i < str.length; i++) { | ||
| var code = str.charCodeAt(i) | ||
| buf[i * 2] = code & 0xFF | ||
| buf[i * 2 + 1] = (code >> 8) & 0xFF | ||
| } | ||
| return buf | ||
| } | ||
|
|
||
| if (encoding === "binary" || encoding === "latin1") { | ||
| var buf = new BufferShim(str.length) | ||
| for (var i = 0; i < str.length; i++) { | ||
| buf[i] = str.charCodeAt(i) & 0xFF | ||
| } | ||
| return buf | ||
| } | ||
|
|
||
| if (encoding === "base64") { | ||
| // Node.js is lenient with base64 - strip invalid chars and add padding | ||
| var cleaned = str.replace(/[^A-Za-z0-9+/]/g, "") | ||
| while (cleaned.length % 4 !== 0) cleaned += "=" | ||
| var binaryStr | ||
| try { binaryStr = atob(cleaned) } catch (e) { binaryStr = "" } | ||
| var buf = new BufferShim(binaryStr.length) | ||
| for (var i = 0; i < binaryStr.length; i++) { | ||
| buf[i] = binaryStr.charCodeAt(i) | ||
| } | ||
| return buf | ||
| } | ||
|
|
||
| if (encoding === "hex") { | ||
| var len = str.length >> 1 | ||
| var buf = new BufferShim(len) | ||
| for (var i = 0; i < len; i++) { | ||
| buf[i] = parseInt(str.substr(i * 2, 2), 16) | ||
| } | ||
| return buf | ||
| } | ||
|
|
||
| if (encoding === "ascii") { | ||
| var buf = new BufferShim(str.length) | ||
| for (var i = 0; i < str.length; i++) { | ||
| buf[i] = str.charCodeAt(i) & 0x7F | ||
| } | ||
| return buf | ||
| } | ||
|
|
||
| // Fallback to utf8 | ||
| return BufferShim._fromString(str, "utf8") | ||
| } | ||
|
|
||
| static concat (list) { | ||
| var totalLength = 0 | ||
| for (var i = 0; i < list.length; i++) { | ||
| totalLength += list[i].length | ||
| } | ||
| var result = new BufferShim(totalLength) | ||
| var offset = 0 | ||
| for (var i = 0; i < list.length; i++) { | ||
| result.set(list[i], offset) | ||
| offset += list[i].length | ||
| } | ||
| return result | ||
| } | ||
|
|
||
| static isBuffer (obj) { | ||
| return obj instanceof BufferShim | ||
| } | ||
|
|
||
| toString (encoding) { | ||
| if (!encoding || encoding === "utf8" || encoding === "utf-8") { | ||
| return textDecoder.decode(this) | ||
| } | ||
|
|
||
| if (encoding === "ucs2" || encoding === "ucs-2" || | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. try browser's built in decoder first to check weather it has support for given encoding? |
||
| encoding === "utf16le" || encoding === "utf-16le") { | ||
| var result = "" | ||
| var CHUNK = 8192 | ||
| var count = this.length >> 1 | ||
| for (var start = 0; start < count; start += CHUNK) { | ||
| var end = Math.min(start + CHUNK, count) | ||
| var codes = new Array(end - start) | ||
| for (var i = start; i < end; i++) { | ||
| codes[i - start] = this[i * 2] | (this[i * 2 + 1] << 8) | ||
| } | ||
| result += String.fromCharCode.apply(null, codes) | ||
| } | ||
| return result | ||
| } | ||
|
|
||
| if (encoding === "base64") { | ||
| var binaryStr = "" | ||
| for (var i = 0; i < this.length; i++) { | ||
| binaryStr += String.fromCharCode(this[i]) | ||
| } | ||
| return btoa(binaryStr) | ||
| } | ||
|
|
||
| if (encoding === "binary" || encoding === "latin1") { | ||
| var result = "" | ||
| for (var i = 0; i < this.length; i++) { | ||
| result += String.fromCharCode(this[i]) | ||
| } | ||
| return result | ||
| } | ||
|
|
||
| if (encoding === "hex") { | ||
| var result = "" | ||
| for (var i = 0; i < this.length; i++) { | ||
| result += (this[i] < 16 ? "0" : "") + this[i].toString(16) | ||
| } | ||
| return result | ||
| } | ||
|
|
||
| if (encoding === "ascii") { | ||
| var result = "" | ||
| for (var i = 0; i < this.length; i++) { | ||
| result += String.fromCharCode(this[i] & 0x7F) | ||
| } | ||
| return result | ||
| } | ||
|
|
||
| // Fallback to utf8 | ||
| return textDecoder.decode(this) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same here, throw unsupported encoding |
||
| } | ||
|
|
||
| slice (start, end) { | ||
| var sliced = Uint8Array.prototype.slice.call(this, start, end) | ||
| Object.setPrototypeOf(sliced, BufferShim.prototype) | ||
| return sliced | ||
| } | ||
|
|
||
| write (str, offset) { | ||
| // Only used in utf7.js for writing ASCII strings at an offset. | ||
| // Returns number of bytes written. | ||
| if (offset === undefined) offset = 0 | ||
| var len = Math.min(str.length, this.length - offset) | ||
| for (var i = 0; i < len; i++) { | ||
| this[offset + i] = str.charCodeAt(i) & 0xFF | ||
| } | ||
| return len | ||
| } | ||
|
|
||
| readUInt16LE (offset) { | ||
| return this[offset] | (this[offset + 1] << 8) | ||
| } | ||
|
|
||
| writeUInt32LE (value, offset) { | ||
| this[offset] = value & 0xFF | ||
| this[offset + 1] = (value >>> 8) & 0xFF | ||
| this[offset + 2] = (value >>> 16) & 0xFF | ||
| this[offset + 3] = (value >>> 24) & 0xFF | ||
| return offset + 4 | ||
| } | ||
|
|
||
| writeUInt32BE (value, offset) { | ||
| this[offset] = (value >>> 24) & 0xFF | ||
| this[offset + 1] = (value >>> 16) & 0xFF | ||
| this[offset + 2] = (value >>> 8) & 0xFF | ||
| this[offset + 3] = value & 0xFF | ||
| return offset + 4 | ||
| } | ||
| } | ||
|
|
||
| module.exports = { Buffer: BufferShim } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,142 @@ | ||
| "use strict" | ||
|
|
||
| // Minimal StringDecoder shim for iconv-lite browser usage. | ||
| // Replaces Node.js string_decoder module. | ||
| // Supports only the encodings used by iconv-lite's internal.js: utf8, ucs2, binary, base64, hex. | ||
|
|
||
| function BrowserStringDecoder (encoding) { | ||
| this.encoding = normalizeEncoding(encoding) | ||
|
|
||
| if (this.encoding === "utf8") { | ||
| this._decoder = new TextDecoder("utf-8", { fatal: false }) | ||
| } else if (this.encoding === "ucs2") { | ||
| this._lastByte = -1 | ||
| } else if (this.encoding === "base64") { | ||
| this._remainder = null | ||
| } | ||
| // binary, hex, and ascii need no state | ||
| } | ||
|
|
||
| function normalizeEncoding (enc) { | ||
| enc = (enc || "utf8").toLowerCase().replace(/[^a-z0-9]/g, "") | ||
| if (enc === "utf8") return "utf8" | ||
| if (enc === "ucs2" || enc === "utf16le") return "ucs2" | ||
| if (enc === "binary" || enc === "latin1") return "binary" | ||
| if (enc === "base64") return "base64" | ||
| if (enc === "hex") return "hex" | ||
| if (enc === "ascii") return "ascii" | ||
| return "utf8" // fallback | ||
| } | ||
|
|
||
| BrowserStringDecoder.prototype.write = function (buf) { | ||
| if (!buf || buf.length === 0) return "" | ||
|
|
||
| switch (this.encoding) { | ||
| case "utf8": | ||
| return this._decoder.decode(buf, { stream: true }) | ||
|
|
||
| case "ucs2": { | ||
| var str = "" | ||
| var i = 0 | ||
| if (this._lastByte !== -1) { | ||
| if (buf.length > 0) { | ||
| str += String.fromCharCode(this._lastByte | (buf[0] << 8)) | ||
| i = 1 | ||
| } | ||
| this._lastByte = -1 | ||
| } | ||
| var end = buf.length | ||
| if ((end - i) % 2 !== 0) { | ||
| this._lastByte = buf[end - 1] | ||
| end-- | ||
| } | ||
| for (; i < end; i += 2) { | ||
| str += String.fromCharCode(buf[i] | (buf[i + 1] << 8)) | ||
| } | ||
| return str | ||
| } | ||
|
|
||
| case "binary": { | ||
| var str = "" | ||
| for (var i = 0; i < buf.length; i++) { | ||
| str += String.fromCharCode(buf[i]) | ||
| } | ||
| return str | ||
| } | ||
|
|
||
| case "base64": { | ||
| var data = buf | ||
| if (this._remainder) { | ||
| var combined = new Uint8Array(this._remainder.length + buf.length) | ||
| combined.set(this._remainder) | ||
| combined.set(buf, this._remainder.length) | ||
| data = combined | ||
| this._remainder = null | ||
| } | ||
| var leftover = data.length % 3 | ||
| if (leftover > 0) { | ||
| this._remainder = data.slice(data.length - leftover) | ||
| data = data.slice(0, data.length - leftover) | ||
| } | ||
| if (data.length === 0) return "" | ||
| var binaryStr = "" | ||
| for (var i = 0; i < data.length; i++) { | ||
| binaryStr += String.fromCharCode(data[i]) | ||
| } | ||
| return btoa(binaryStr) | ||
| } | ||
|
|
||
| case "hex": { | ||
| var str = "" | ||
| for (var i = 0; i < buf.length; i++) { | ||
| str += (buf[i] < 16 ? "0" : "") + buf[i].toString(16) | ||
| } | ||
| return str | ||
| } | ||
|
|
||
| case "ascii": { | ||
| var str = "" | ||
| for (var i = 0; i < buf.length; i++) { | ||
| str += String.fromCharCode(buf[i] & 0x7F) | ||
| } | ||
| return str | ||
| } | ||
|
|
||
| default: | ||
| return "" | ||
| } | ||
| } | ||
|
|
||
| BrowserStringDecoder.prototype.end = function (buf) { | ||
| var res = "" | ||
|
|
||
| if (buf && buf.length > 0) { | ||
| if (this.encoding === "utf8") { | ||
| // Final call without stream:true to flush | ||
| res = this._decoder.decode(buf) | ||
| } else { | ||
| res = this.write(buf) | ||
| } | ||
| } else if (this.encoding === "utf8") { | ||
| // Flush any remaining incomplete bytes | ||
| res = this._decoder.decode() | ||
| } | ||
|
|
||
| // Flush buffered state | ||
| if (this.encoding === "ucs2" && this._lastByte !== -1) { | ||
| this._lastByte = -1 | ||
| } | ||
|
|
||
| if (this.encoding === "base64" && this._remainder) { | ||
| var binaryStr = "" | ||
| for (var i = 0; i < this._remainder.length; i++) { | ||
| binaryStr += String.fromCharCode(this._remainder[i]) | ||
| } | ||
| res += btoa(binaryStr) | ||
| this._remainder = null | ||
| } | ||
|
|
||
| return res | ||
| } | ||
|
|
||
| module.exports = { StringDecoder: BrowserStringDecoder } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
throw unsupported encoding?