@syncfusion/ej2-pdf
Version:
Feature-rich JavaScript PDF library with built-in support for loading and manipulating PDF document.
373 lines (372 loc) • 13.3 kB
JavaScript
import { _RealValueType } from './enumerator';
/**
* Convert a buffer to an integer.
*
* @private
* @param {Uint8Array} input - The input buffer as a Uint8Array.
* @returns {number} The integer value.
*/
export function _bufferToInteger(input) {
var length = input.length;
if (length === 0) {
return 0;
}
if (length > 4) {
throw new Error('Input too large to convert to number without BigInt.');
}
var value = 0;
for (var i = 0; i < length; i++) {
value = (value << 8) | input[i];
}
return value;
}
/**
* Converts an integer into a buffer (Uint8Array) representation.
*
* @private
* @param {number} int - The integer to convert to a Uint8Array.
* @returns {Uint8Array} A Uint8Array representing the integer in its encoded form.
* @throws {Error} Throws an error if the integer is out of range for 32-bit encoding without BigInt.
*/
export function _integerToBuffer(int) {
if (int >= -128 && int <= 127) {
var array = new Uint8Array(1);
var view = new DataView(array.buffer);
view.setInt8(0, int);
return array;
}
if (int >= -32768 && int <= 32767) {
var array = new Uint8Array(2);
var view = new DataView(array.buffer);
view.setInt16(0, int, false);
return array;
}
if (int >= -8388608 && int <= 8388607) {
var array = new Uint8Array(4);
var view = new DataView(array.buffer);
view.setInt32(0, int, false);
return array.subarray(1);
}
if (int >= -2147483648 && int <= 2147483647) {
var array = new Uint8Array(4);
var view = new DataView(array.buffer);
view.setInt32(0, int, false);
return array;
}
throw new Error('Integer out of range for 32-bit encoding without BigInt.');
}
/**
* Decodes a signed big-endian integer from a Uint8Array.
*
* @private
* @param {Uint8Array} value - The byte array representing the signed integer in big-endian format.
* @returns {number} The decoded signed integer.
* @throws {Error} Throws an error if the byte array is longer than 4 bytes
*/
export function _decodeSignedBigEndianInteger(value) {
var length = value.length;
if (length === 0) {
return 0;
}
if (length > 4) {
throw new Error('Number too long to decode.');
}
var padded = new Uint8Array(4);
var isNegative = (value[0] & 0x80) !== 0;
padded.fill(isNegative ? 0xFF : 0x00, 0, 4 - length);
padded.set(value, 4 - length);
var view = new DataView(padded.buffer);
return view.getInt32(0, false);
}
/**
* Decodes an unsigned big-endian integer from a Uint8Array.
*
* @private
* @param {Uint8Array} value - The byte array representing the unsigned integer in big-endian format.
* @returns {number} The decoded unsigned integer.
* @throws {Error} Throws an error if the byte array is longer than 4 bytes, which cannot be decoded.
*/
export function _decodeUnsignedBigEndianInteger(value) {
var length = value.length;
if (length === 0) {
return 0;
}
if (length > 4) {
throw new Error("Number on " + length + " bytes is too long to decode.");
}
var padded = new Uint8Array(4);
padded.set(value, 4 - length);
var view = new DataView(padded.buffer);
return view.getUint32(0, false);
}
/**
* Dissects a floating-point number into its sign, exponent, and mantissa components.
*
* @private
* @param {number} value - The floating-point number to dissect.
* @returns {{ negative: boolean, exponent: number, mantissa: number }} An object.
*/
export function _dissectFloat(value) {
var float = new Float64Array([value]);
var exponentBitMask = 2146435072;
var uints = new Uint32Array(float.buffer);
var exponent = (((uints[1] & exponentBitMask) >>> 20) - 1023 - 31);
var mantissa = 2147483648 + ((((uints[1] & 1048575) << 11)
| ((uints[0] & 4292870144) >>> 21)));
return {
negative: (value < 0),
exponent: exponent,
mantissa: mantissa
};
}
/**
* Encodes a signed 32-bit integer to a big-endian Uint8Array.
*
* @private
* @param {number} value - The signed integer to encode. Must be within the range -2147483648 to 2147483647.
* @returns {Uint8Array} A Uint8Array representing the number in big-endian format.
* @throws {Error} Throws an error if the number is outside the valid 32-bit signed integer range.
*/
export function _encodeBigEndianSignedInteger(value) {
var minSint32 = -0x80000000;
var maxSint32 = 0x7FFFFFFF;
if (value < minSint32) {
throw Error("Number " + value + " too small to be encoded as a big-endian signed integer.");
}
if (value > maxSint32) {
throw Error("Number " + value + " too big to be encoded as a big-endian signed integer.");
}
if (value <= 127 && value >= -128) {
return new Uint8Array([
(value & 255)
]);
}
else if (value <= 32767 && value >= -32768) {
return new Uint8Array([
((value >> 8) & 255),
(value & 255)
]);
}
else if (value <= 8388607 && value >= -8388608) {
return new Uint8Array([
((value >> 16) & 255),
((value >> 8) & 255),
(value & 255)
]);
}
else {
return new Uint8Array([
((value >> 24) & 255),
((value >> 16) & 255),
((value >> 8) & 255),
(value & 255)
]);
}
}
/**
* Encodes an unsigned 32-bit integer into a big-endian Uint8Array.
*
* @private
* @param {number} value - The unsigned integer to encode. Must be within the range 0 to 4294967295.
* @returns {Uint8Array} A Uint8Array representing the number in big-endian format.
* @throws {Error} Throws an error if the number is outside the valid 32-bit unsigned integer range.
*/
export function _encodeUnsignedBigEndianInteger(value) {
var maxUnit32 = 0x00FFFFFFFF;
var minUnit32 = 0x0000000000;
if (value < minUnit32) {
throw new Error("Number " + value + " too small to be encoded as a big-endian unsigned integer.");
}
if (value > maxUnit32) {
throw new Error("Number " + value + " too big to be encoded as a big-endian unsigned integer.");
}
var fullBytes = new Uint8Array(4);
var view = new DataView(fullBytes.buffer);
view.setUint32(0, value, false);
var startOfNonPadding = 0;
for (var i = 0; i < fullBytes.length - 1; i++) {
if (fullBytes[i] === 0x00) {
startOfNonPadding++;
}
else {
break;
}
}
return fullBytes.subarray(startOfNonPadding);
}
/**
* Encodes a floating-point number into an X690 binary real number format (as a Uint8Array).
*
* @private
* @param {number} value - The floating-point number to encode.
* @returns {Uint8Array} A Uint8Array representing the encoded X690 binary real number.
* @throws {Error} Throws an error if the number is too precise to encode.
*/
export function _encodeX690BinaryRealNumber(value) {
if (value === 0.0) {
return new Uint8Array(0);
}
else if (Number.isNaN(value)) {
return new Uint8Array([_RealValueType.notANumber]);
}
else if (value === Infinity) {
return new Uint8Array([_RealValueType.plusInfinity]);
}
else if (value === -Infinity) {
return new Uint8Array([_RealValueType.minusInfinity]);
}
var floatComponents = _dissectFloat(value);
while (floatComponents.mantissa !== 0 && (floatComponents.mantissa % 2) === 0) {
floatComponents.mantissa = floatComponents.mantissa >>> 1;
floatComponents.exponent++;
}
if (floatComponents.exponent <= -1020) {
throw new Error("Real number " + value + " (having exponent " + floatComponents.exponent + ") "
+ 'is too precise to encode.');
}
var singleByteExponent = ((floatComponents.exponent <= 127)
&& (floatComponents.exponent >= -128));
var firstByte = (128
| (value >= 0 ? 0 : 64)
| (singleByteExponent ? 0 : 1));
var exponentBytes = _encodeBigEndianSignedInteger(floatComponents.exponent);
var mantissaBytes = _encodeUnsignedBigEndianInteger(floatComponents.mantissa);
var ret = new Uint8Array(1 + exponentBytes.length + mantissaBytes.length);
ret[0] = firstByte;
ret.set(exponentBytes, 1);
ret.set(mantissaBytes, (1 + exponentBytes.length));
return ret;
}
/**
* Retrieves the value of a specific bit from a Uint8Array.
*
* @private
* @param {Uint8Array} from - The Uint8Array from which the bit value is extracted.
* @param {number} bitIndex - The index of the bit to retrieve (0-indexed).
* @returns {boolean} `true` if the bit is set (1), otherwise `false`.
*/
export function _getBit(from, bitIndex) {
return ((from[from.length - (Math.floor(bitIndex / 8) + 1)] & (0x01 << (bitIndex % 8))) > 0);
}
/**
* Packs a Uint8ClampedArray of bits into a Uint8Array of bytes.
*
* @private
* @param {Uint8ClampedArray} bits - The array of bits to be packed. Each bit should be 0 or 1.
* @returns {Uint8Array} A Uint8Array representing the packed bits into bytes.
*/
export function _packBits(bits) {
var bytesNeeded = Math.ceil(bits.length / 8);
var ret = new Uint8Array(bytesNeeded);
var byte = -1;
for (var bit = 0; bit < bits.length; bit++) {
var bitMod8 = bit % 8;
if (bitMod8 === 0) {
byte++;
}
if (bits[bit] !== 0) {
ret[byte] |= (0x01 << (7 - bitMod8));
}
}
return ret;
}
/**
* Sets or clears a bit at a specific index in a Uint8Array.
*
* @private
* @param {Uint8Array} to - The Uint8Array into which the bit will be set or cleared.
* @param {number} bitIndex - The index of the bit to set or clear, 0-indexed.
* @param {boolean} value - A boolean indicating whether to set (true) or clear (false) the bit.
* @returns {void} This function does not return a value.
*/
export function _setBit(to, bitIndex, value) {
var byteIndex = to.length - (Math.floor(bitIndex / 7) + 1);
if (value) {
to[byteIndex] |= (0x01 << (bitIndex % 7));
}
else {
to[byteIndex] &= ~(0x01 << (bitIndex % 7));
}
}
/**
* Sets or clears a bit at a specific index in a Uint8Array for Base-256 encoding.
*
* @private
* @param {Uint8Array} to - The Uint8Array into which the bit will be set or cleared.
* @param {number} bitIndex - The index of the bit to set or clear, 0-indexed.
* @param {boolean} value - A boolean indicating whether to set (true) or clear (false) the bit.
* @returns {void} This function does not return a value.
*/
export function _setBitInBase256(to, bitIndex, value) {
var byteIndex = (to.length - (Math.floor(bitIndex / 8) + 1));
if (value) {
to[byteIndex] |= (0x01 << (bitIndex % 8));
}
else {
to[byteIndex] &= ~(0x01 << (bitIndex % 8));
}
}
/**
* Decodes a Uint8Array to a string using the specified text encoding.
*
* @private
* @param {Uint8Array} bytes - The byte array to decode into a string.
* @param {string} [encoding ='utf-8'] - The text encoding to use for decoding. Defaults to 'utf-8'.
* @returns {string} The decoded string.
* @throws {Error} Throws an error if `TextDecoder` is not available.
*/
export function _convertBytesToText(bytes, encoding) {
if (encoding === void 0) { encoding = 'utf-8'; }
if (encoding !== 'utf-8') {
throw new Error('Only utf-8 encoding is supported in fallback.');
}
var result = '';
var i = 0;
while (i < bytes.length) {
var byte1 = bytes[i++];
if (byte1 < 0x80) {
result += String.fromCharCode(byte1);
}
else if (byte1 >= 0xC0 && byte1 < 0xE0) {
var byte2 = bytes[i++];
result += String.fromCharCode(((byte1 & 0x1F) << 6) | (byte2 & 0x3F));
}
else if (byte1 >= 0xE0 && byte1 < 0xF0) {
var byte2 = bytes[i++];
var byte3 = bytes[i++];
result += String.fromCharCode(((byte1 & 0x0F) << 12) |
((byte2 & 0x3F) << 6) |
(byte3 & 0x3F));
}
else if (byte1 >= 0xF0) {
var byte2 = bytes[i++];
var byte3 = bytes[i++];
var byte4 = bytes[i++];
var codePoint = ((byte1 & 0x07) << 18) |
((byte2 & 0x3F) << 12) |
((byte3 & 0x3F) << 6) |
(byte4 & 0x3F);
var highSurrogate = ((codePoint - 0x10000) >> 10) + 0xD800;
var lowSurrogate = ((codePoint - 0x10000) & 0x3FF) + 0xDC00;
result += String.fromCharCode(highSurrogate, lowSurrogate);
}
}
return result;
}
/**
* Checks whether a given Uint8Array is BER-encoded.
*
* BER (Basic Encoding Rules) encoding for a sequence starts with the bytes 0x30 0x80
*
* @private
* @param {Uint8Array} input - The input byte array to check.
* @returns {boolean} True if the input starts with BER indefinite-length encoding; otherwise, false.
*/
export function _isBasicEncodingElement(input) {
for (var i = 0; i < input.length - 1; i++) {
if (input[i] === 0x30 && input[i + 1] === 0x80) {
return true;
}
}
return false;
}