1/*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16function getTypeName(obj: unknown): string {
17  if (obj === null) {
18    return 'null';
19  }
20  if (typeof obj !== 'object') {
21    return typeof obj;
22  }
23  if (obj != null && obj.constructor != null) {
24    return obj.constructor.name;
25  }
26  return 'unknown';
27}
28
29class BusinessError extends Error {
30  code: number;
31  constructor(message: string, errorNumber: number) {
32    super(message);
33    this.name = 'BusinessError';
34    this.code = errorNumber;
35  }
36}
37
38const ERROR_CODES = {
39  TYPE_ERROR: 401, // 401: TYPE_ ERROR code value
40  RANGE_ERROR: 10200001, // 10200001: RANGE_ERROR code value
41  BUFFER_SIZE_ERROR: 10200009, // 10200009: BUFFER_SIZE_ERROR code value
42  PROPERTY_TYPE_ERROR: 10200013 // 10200013: TYPE_ ERROR code value
43};
44
45let errorMap = {
46  'typeError': ERROR_CODES.TYPE_ERROR,
47  'rangeError': ERROR_CODES.RANGE_ERROR,
48  'bufferSizeError': ERROR_CODES.BUFFER_SIZE_ERROR,
49  'typeErrorForProperty': ERROR_CODES.PROPERTY_TYPE_ERROR
50};
51
52enum TypeErrorCategories {
53  COMMON = 0,
54  SIZE,
55  ENCODING,
56  PROPERTY
57};
58enum RangeErrorCategories {
59  WHOLE = 0,
60  LEFT
61};
62
63const UINT32MAX = 4294967296;
64
65class ErrorMessage {
66  public errorNumber: number = 0;
67  public argument: string = '';
68  public types: string[] = [];
69  public receivedObj: unknown = '';
70  public rangeLeft: string | bigint | number = 0;
71  public rangeRight: string | bigint | number = 0;
72
73  public typeErrorCat: TypeErrorCategories = TypeErrorCategories.COMMON;
74  public rangeErrorCat: RangeErrorCategories = RangeErrorCategories.WHOLE;
75
76  constructor(errNo: number, argument?: string) {
77    this.errorNumber = errNo;
78    this.argument = argument === undefined ? '' : argument;
79  }
80
81  public setTypeInfo(types: string[], receivedObj: unknown): ErrorMessage {
82    this.types = types;
83    this.receivedObj = receivedObj;
84    return this;
85  }
86
87  public setSizeTypeInfo(types: string[], receivedObj: unknown): ErrorMessage {
88    this.types = types;
89    this.receivedObj = receivedObj;
90    this.typeErrorCat = TypeErrorCategories.SIZE;
91    return this;
92  }
93
94  public setEncodingTypeInfo(types: string[], receivedObj: unknown): ErrorMessage {
95    this.types = types;
96    this.receivedObj = receivedObj;
97    this.typeErrorCat = TypeErrorCategories.ENCODING;
98    return this;
99  }
100
101  public setProperty(argument: string): ErrorMessage {
102    this.typeErrorCat = TypeErrorCategories.PROPERTY;
103    this.argument = argument;
104    return this;
105  }
106
107  public setRangeInfo(rangeLeft: string | bigint | number, rangeRight: string | bigint | number, receivedObj: unknown): ErrorMessage {
108    this.rangeLeft = rangeLeft;
109    this.rangeRight = rangeRight;
110    this.receivedObj = receivedObj;
111    return this;
112  }
113
114  public setRangeLeftInfo(rangeLeft: string | number, receivedObj: unknown): ErrorMessage {
115    this.rangeLeft = rangeLeft;
116    this.receivedObj = receivedObj;
117    this.rangeErrorCat = RangeErrorCategories.LEFT;
118    return this;
119  }
120
121  public setSizeInfo(receivedObj: string): ErrorMessage {
122    this.receivedObj = receivedObj;
123    return this;
124  }
125
126  private getErrorTypeStrings(types: string[]): string {
127    let ret = types.join(', ');
128    ret = ret.replace(',', ' or');
129    return ret;
130  }
131
132  private getArgumentStr(flag: boolean): string {
133    if (flag) {
134      return 'Parameter error. The type of "' + this.argument + '" must be ';
135    } else {
136      return 'The type of "' + this.argument + '" must be ';
137    }
138  }
139
140  private getTypeString(flag: boolean): string {
141    let str = '';
142    switch (this.typeErrorCat) {
143      case TypeErrorCategories.COMMON:
144        str += this.getArgumentStr(flag) + this.getErrorTypeStrings(this.types) +
145          '. Received value is: ' + getTypeName(this.receivedObj);
146        break;
147      case TypeErrorCategories.SIZE:
148        str += this.getArgumentStr(flag) + this.getErrorTypeStrings(this.types) +
149          ' and the value cannot be negative. Received value is: ' + getTypeName(this.receivedObj);
150        break;
151      case TypeErrorCategories.ENCODING:
152        str += this.getArgumentStr(flag) + this.getErrorTypeStrings(this.types) +
153          '. the encoding ' + this.receivedObj + ' is unknown';
154        break;
155      case TypeErrorCategories.PROPERTY:
156        str += this.argument + ' cannot be set for the buffer that has only a getter';
157      default:
158        break;
159    }
160    return str;
161  }
162
163  private getRangeString(): string {
164    let str = '';
165    switch (this.rangeErrorCat) {
166      case RangeErrorCategories.WHOLE:
167        str += 'The value of "' + this.argument + '" is out of range. It must be >= ' + this.rangeLeft +
168          ' and <= ' + this.rangeRight + '. Received value is: ' + this.receivedObj;
169        break;
170      case RangeErrorCategories.LEFT:
171        str += 'The value of "' + this.argument + '" is out of range. It must be >= ' + this.rangeLeft +
172          '. Received value is: ' + this.receivedObj;
173        break;
174      default:
175        break;
176    }
177    return str;
178  }
179
180  public getString(): string {
181    let str = '';
182    switch (this.errorNumber) {
183      case ERROR_CODES.TYPE_ERROR:
184        str = this.getTypeString(true);
185        break;
186      case ERROR_CODES.PROPERTY_TYPE_ERROR:
187        str = this.getTypeString(false);
188        break;
189      case ERROR_CODES.RANGE_ERROR:
190        str = this.getRangeString();
191        break;
192      case ERROR_CODES.BUFFER_SIZE_ERROR:
193        str = 'The buffer size must be a multiple of ' + this.receivedObj;
194        break;
195      default:
196        break;
197    }
198    return str;
199  }
200}
201
202interface NativeBuffer {
203  new(type: number, length: number): NativeBuffer;
204  new(type: number, array: number[]): NativeBuffer;
205  new(type: number, raw: NativeBuffer): NativeBuffer;
206  new(type: number, str: string, encoding: string): NativeBuffer;
207  new(type: number, arrayBuffer: ArrayBuffer, byteOffset?: number, length?: number): NativeBuffer;
208  new(type: number, pool: NativeBuffer, poolOffset: number, length: number): NativeBuffer;
209  setArray(array: Array<number>): undefined;
210  getLength(): number;
211  getByteOffset(): number;
212  writeString(value: string, offset: number, length: number, encoding: string): number;
213  fromString(str: string, encoding: string, size: number): NativeBuffer;
214  fillString(value: string, offset: number, end: number, encoding: string): undefined;
215  fillNumbers(value: number[], offset: number, end: number): undefined;
216  fillBuffer(value: NativeBuffer, offset: number, end: number): undefined;
217  writeInt32BE(value: number, offset: number): number;
218  readInt32BE(offset: number): number;
219  writeInt32LE(value: number, offset: number): number;
220  readInt32LE(offset: number): number;
221  writeUInt32BE(value: number, offset: number): number;
222  readUInt32BE(offset: number): number;
223  writeUInt32LE(value: number, offset: number): number;
224  readUInt32LE(offset: number): number;
225  getBufferData(): Array<number>;
226  getArrayBuffer(): ArrayBufferLike;
227  get(index: number): number;
228  set(index: number, value: number): undefined;
229  subBuffer(target: NativeBuffer, start: number, end: number): undefined;
230  copy(target: NativeBuffer, targetStart: number, sourceStart: number, sourceEnd: number): number;
231  compare(target: NativeBuffer, targetStart: number, sourceStart: number, length: number): number;
232  toUtf8(start: number, end: number): string;
233  toBase64(start: number, end: number): string;
234  indexOf(value: string, byteOffset: number, encoding: string, isReverse: boolean): number;
235}
236interface NativeBlob {
237  new(src: Array<number>): NativeBlob;
238  new(blob: NativeBlob, start: number, end?: number): NativeBlob;
239  arraybuffer(): Promise<ArrayBuffer>;
240  text(): Promise<string>;
241  getBytes(): Array<number>;
242}
243interface IBuffer {
244  Buffer: NativeBuffer;
245  Blob: NativeBlob;
246  utf8ByteLength(str: string): number;
247  utf8StringToNumbers(str: string): Array<number>;
248}
249
250declare function requireInternal(s: string): IBuffer;
251const internalBuffer = requireInternal('buffer');
252const bufferSymbol = Symbol('bufferClass');
253const lengthSymbol = Symbol('bufferLength');
254const bufferEncoding = ['ascii', 'utf8', 'utf-8', 'utf16le', 'utf-16le', 'ucs2', 'ucs-2',
255  'base64', 'base64url', 'latin1', 'binary', 'hex'];
256
257enum ParaType {
258  NUMBER = 0,
259  BUFFER,
260  UINT8ARRAY,
261  ARRAYBUFFER,
262  NUMBERS,
263  STRING
264}
265const initialPoolSize: number = 8 * 1024; // 8 * 1024 : initialPoolSize number
266let poolSize: number;
267let poolOffset: number;
268let pool: Buffer;
269const MAX_LENGTH: number = Math.pow(2, 32); // 2 : 32 : MAX_LENGTH code
270const TWO_POW_FIFTEEN: number = Math.pow(2, 15); // 2 : 15 : two to power of fifteen code
271const TWO_POW_SEVEN: number = Math.pow(2, 7); // 2 : 7 : two to power of seven code
272const oneByte: number = 1; // 1 : one Byte
273const twoBytes: number = 2; // 2 : two Bytes
274const threeBytes: number = 3; // 3 : three Bytes
275const fourBytes: number = 4; // 4 : four Bytes
276const fiveBytes: number = 5; // 5 : five Bytes
277const sixBytes: number = 6; // 6 : six Bytes
278const sevenBytes: number = 7; // 7 : seven Bytes
279const eightBytes: number = 8; // 8 : eight Bytes
280
281
282type TypedArray = Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array |
283Int32Array | Uint32Array | Float32Array | Float64Array;
284type BackingType = Buffer | TypedArray | DataView | ArrayBuffer | SharedArrayBuffer;
285const float64Array: Float64Array = new Float64Array(1);
286const uInt8Float64Array: Uint8Array = new Uint8Array(float64Array.buffer);
287const float32Array: Float32Array = new Float32Array(1);
288const uInt8Float32Array: Uint8Array = new Uint8Array(float32Array.buffer);
289
290function createPool(): void {
291  poolSize = initialPoolSize;
292  pool = new Buffer(poolSize);
293  poolOffset = 0;
294}
295
296function alignPool(): void {
297  if (poolOffset & 0x7) {
298    poolOffset |= 0x7; // 0x7 : align offset based of 8-bits
299    poolOffset++;
300  }
301}
302type Options = {
303  type: string,
304  endings: string
305};
306
307const _log = console.log;
308
309console.log = function (...args) : void {
310  if (args.length === 1 && args[0] instanceof Buffer) {
311    let buf: Buffer = args[0];
312    let bufArr: Array<number> = buf[bufferSymbol].getBufferData();
313    let getStr = function (bufArr: Array<number>, len: number): string {
314      let str: string = '';
315      for (let i = 0; i < len; i++) {
316        let strTemp: string = bufArr[i].toString(16); // 16 : convert the element to a hexadecimal string
317        strTemp = (strTemp.length === 1) ? `0${strTemp}` : strTemp;
318        str += ` ${strTemp}`;
319      }
320      return str;
321    };
322    let msg: string = '';
323    if (bufArr.length > 50) {
324      let bufStr: string = getStr(bufArr, 50); // 50: Maximum number of log displays
325      msg = bufStr + ` ... ${bufArr.length - 50} more bytes`;
326    } else {
327      msg = getStr(bufArr, bufArr.length);
328    }
329    _log.call(console, `<Buffer ${msg}>`);
330  } else {
331    _log(...args);
332  }
333};
334
335class Blob {
336  blobClass: NativeBlob;
337  private _size: number;
338  private _type: string;
339
340  public get size(): number {
341    return this._size;
342  }
343
344  public get type(): string {
345    return this._type;
346  }
347
348  constructor(sources: string[] | ArrayBuffer[] | TypedArray[] | DataView[] | Blob[], options: Options) {
349    if (options === undefined || options === null) {
350      options = {
351        type: '',
352        endings: 'transparent'
353      };
354    }
355    typeErrorCheck(options, ['Object'], 'options');
356
357    let type = options.type ? options.type : '';
358    let endings = options.endings ? options.endings : 'transparent';
359    if (endings !== 'transparent' && endings !== 'native') {
360      throw new BusinessError('Parameter error. The value of endings is neither "transparent" nor "native"',
361                              errorMap.typeError);
362    }
363    let arr: Array<number> = [];
364    if (sources instanceof Array || isTypedArray(sources)) {
365      for (const value of sources) {
366        arr = arr.concat(this.normalizeSource(value));
367      }
368    } else {
369      throw typeError(sources, 'sources', ['Iterable']);
370    }
371    this._size = arr.length;
372    this._type = type;
373    this.blobClass = new internalBuffer.Blob(arr);
374  }
375
376  normalizeSource(source: string | ArrayBuffer | TypedArray | DataView | Blob | Buffer): Array<number> {
377    let ret: Array<number> = [];
378    if (typeof source === 'string') {
379      return internalBuffer.utf8StringToNumbers(source);
380    } else if (source instanceof ArrayBuffer) {
381      return Array.prototype.slice.call(new Uint8Array(source));
382    } else if (isTypedArray(source)) {
383      let numbers = Array.prototype.slice.call(source);
384      let str = '';
385      for (let i = 0, len = numbers.length; i < len; i++) {
386        str += numbers[i].toString();
387      }
388      let charCodeArr = [];
389      for (let i = 0, len = str.length; i < len; i++) {
390        let code = str.charCodeAt(i);
391        charCodeArr.push(code);
392      }
393      return charCodeArr;
394    } else if (source instanceof DataView) {
395      return Array.prototype.slice.call(new Uint8Array(source.buffer));
396    } else if (source instanceof Blob) {
397      return source.blobClass.getBytes();
398    } else if (source instanceof Buffer) {
399      for (let i = 0, len = source.length; i < len; i++) {
400        ret[i] = source[i];
401      }
402      return ret;
403    }
404    return [];
405  }
406
407  arrayBuffer(): Promise<ArrayBuffer> {
408    return this.blobClass.arraybuffer();
409  }
410
411  text(): Promise<string> {
412    return this.blobClass.text();
413  }
414
415  slice(start?: number, end?: number, type?: string): Blob {
416    let newBlob = Object.create(this);
417    if (type !== undefined) {
418      newBlob._type = type;
419    }
420    if (start === undefined || start === null) {
421      return newBlob;
422    }
423    if (end === undefined || end === null) {
424      newBlob.blobClass = new internalBuffer.Blob(this.blobClass, start);
425      return newBlob;
426    }
427    if (start > end) {
428      return newBlob;
429    }
430    if ((start > 0 && end < 0) || (start < 0 && end > 0)) {
431      return newBlob;
432    }
433    newBlob.blobClass = new internalBuffer.Blob(this.blobClass, start, end);
434    return newBlob;
435  }
436}
437
438let utils = {
439  eightBits: 0xFF,
440  sixtyFourBit: 0xFFFFFFFFn,
441
442  getLowerEight(value: number): number {
443    return value & this.eightBits;
444  },
445  getLowerSixtyFour(value: bigint): bigint {
446    return value & this.sixtyFourBit;
447  }
448};
449
450enum Style {
451  intBE = 0,
452  intLE,
453  uintBE,
454  uintLE
455};
456
457class HandlerBuffer {
458  get(obj: Buffer, prop: string): number | undefined {
459    if (typeof prop === 'number') {
460      if (prop >= obj.length) {
461        return obj[prop];
462      }
463      return obj[bufferSymbol].get(prop);
464    }
465    return obj[prop];
466  }
467  set(obj: Buffer, prop: string | symbol, value: number): boolean {
468    if (typeof prop === 'number') {
469      if (prop >= obj.length) {
470        return false;
471      }
472      value = utils.getLowerEight(value);
473      obj[bufferSymbol].set(prop, value);
474      return true;
475    }
476
477    if (prop === lengthSymbol || prop === bufferSymbol) {
478      obj[prop] = value;
479      return true;
480    } else if (prop === 'length' || prop === 'buffer' || prop === 'byteOffset') {
481      throw typeErrorForProperty(prop);
482    }
483    return false;
484  }
485  ownKeys(obj: Buffer): Array<string> {
486    let keys: Array<string> = [];
487    for (let i = 0, len = obj.length; i < len; i++) {
488      keys.push(i.toString());
489    }
490    return keys;
491  }
492}
493class Buffer {
494  private _arrayBuffer: ArrayBuffer | SharedArrayBuffer | undefined;
495
496  public get length(): number {
497    return this[lengthSymbol];
498  }
499
500  public get byteOffset(): number {
501    return this[bufferSymbol].getByteOffset();
502  }
503
504  public get buffer(): ArrayBufferLike {
505    if (this._arrayBuffer) {
506      return this._arrayBuffer;
507    }
508    let arr = this[bufferSymbol].getArrayBuffer();
509    return arr;
510  }
511
512  constructor(value: number | Buffer | Uint8Array | ArrayBuffer | SharedArrayBuffer | Array<number> | string,
513    byteOffsetOrEncoding?: number | string, length?: number) {
514    if (arguments.length === 1) {
515      if (typeof value === 'number') {
516        this[bufferSymbol] = new internalBuffer.Buffer(ParaType.NUMBER, value);
517      } else if (value instanceof Buffer) {
518        this[bufferSymbol] = new internalBuffer.Buffer(ParaType.BUFFER, value[bufferSymbol]);
519      } else if (value instanceof Uint8Array) {
520        this[bufferSymbol] = new internalBuffer.Buffer(ParaType.UINT8ARRAY, value);
521      } else if (value instanceof Array) {
522        this[bufferSymbol] = new internalBuffer.Buffer(ParaType.NUMBERS, value);
523      }
524    } else if (arguments.length === 3 && typeof byteOffsetOrEncoding === 'number' && typeof length === 'number') {
525      if (value instanceof ArrayBuffer || value instanceof SharedArrayBuffer) {
526        this[bufferSymbol] = new internalBuffer.Buffer(ParaType.ARRAYBUFFER, value, byteOffsetOrEncoding, length);
527        this._arrayBuffer = value;
528      } else if (value instanceof Buffer) {
529        this[bufferSymbol] = new internalBuffer.Buffer(ParaType.BUFFER, value[bufferSymbol], byteOffsetOrEncoding, length);
530      }
531    } else if (arguments.length === twoBytes && typeof value === 'string' && typeof byteOffsetOrEncoding === 'string') {
532      this[bufferSymbol] = new internalBuffer.Buffer(ParaType.STRING, value, byteOffsetOrEncoding);
533    } else {
534      this[bufferSymbol] = new internalBuffer.Buffer(ParaType.NUMBER, 0);
535    }
536    this[lengthSymbol] = this[bufferSymbol].getLength();
537    return new Proxy(this, new HandlerBuffer());
538  }
539
540  fillInner(value: string | Buffer | Uint8Array | number, offset: number = 0, end: number = this.length,
541    encoding: string = 'utf8'): Buffer {
542    const normalizedEncoding = encodingTypeErrorCheck(encoding);
543
544    rangeErrorCheck(offset, 'offset', 0, UINT32MAX);
545    rangeErrorCheck(end, 'end', 0, this.length);
546
547    if (offset > end - 1) {
548      return this;
549    }
550    if (typeof value === 'string') {
551      if (normalizedEncoding === 'hex') {
552        let numbers = hexStrtoNumbers(value);
553        this[bufferSymbol].fillNumbers(numbers, offset, end);
554      } else {
555        this[bufferSymbol].fillString(value, offset, end, normalizedEncoding);
556      }
557    }
558    if (typeof value === 'number') {
559      let nums: Array<number> = [];
560      nums.push(value & 0xFF); // 0xFF : get lower 8-bits
561      this[bufferSymbol].fillNumbers(nums, offset, end);
562    }
563    if (value instanceof Buffer) {
564      this[bufferSymbol].fillBuffer(value[bufferSymbol], offset, end);
565    }
566    if (value instanceof Uint8Array) {
567      let nums = Array.from(value);
568      this[bufferSymbol].fillNumbers(nums, offset, end);
569    }
570    return this;
571  }
572  /**
573   * Fills buf with the specified value. If the offset and end are not given, the entire buf will be filled.
574   * @since 9
575   * @syscap SystemCapability.Utils.Lang
576   * @param value The value with which to fill buf
577   * @param [offset = 0] Number of bytes to skip before starting to fill buf
578   * @param [end = buf.length] Where to stop filling buf (not inclusive)
579   * @param [encoding='utf8'] The encoding for value if value is a string
580   * @return A reference to buf
581   */
582  fill(value: string | Buffer | Uint8Array | number, offset: number = 0, end: number = this.length,
583    encoding: string = 'utf8'): Buffer {
584    if (this.length === 0) {
585      return this;
586    }
587    if (offset === null) {
588      offset = 0;
589    }
590    if (end === null) {
591      end = this.length;
592    }
593    if (encoding === null) {
594      encoding = 'utf8';
595    }
596    if (arguments.length === twoBytes) {
597      if (typeof offset === 'string') {
598        encoding = offset;
599        offset = 0;
600      }
601    } else if (arguments.length === 3) {
602      if (typeof end === 'string') {
603        encoding = end;
604        end = this.length;
605      }
606    }
607    if (typeof offset !== 'number') {
608      typeErrorCheck(offset, ['number'], 'offset');
609    }
610    if (typeof end === 'number') {
611      typeErrorCheck(end, ['number'], 'end');
612    }
613    if (typeof encoding !== 'string') {
614      typeErrorCheck(encoding, ['string'], 'encoding');
615    }
616    return this.fillInner(value, offset, end, encoding);
617  }
618
619  write(str: string, offset: number = 0, length: number = this.length - offset, encoding: string = 'utf8'): number {
620    typeErrorCheck(str, ['string'], 'str');
621    if (offset === null) {
622      offset = 0;
623    }
624    if (length === null) {
625      length = this.length - offset;
626    }
627    if (encoding === null) {
628      encoding = 'utf8';
629    }
630    if (arguments.length === 1) {
631      return this[bufferSymbol].writeString(str, 0, length, 'utf8');
632    } else if (arguments.length === twoBytes) {
633      if (typeof offset === 'string') {
634        encoding = offset;
635        let encode = encodingTypeErrorCheck(encoding);
636        return this[bufferSymbol].writeString(str, 0, this.length, encode);
637      } else if (typeof offset === 'number') {
638        rangeErrorCheck(offset, 'offset', 0, this.length - 1);
639        return this[bufferSymbol].writeString(str, offset, length, 'utf8');
640      } else {
641        throw typeError(offset, 'offset', ['number']);
642      }
643    } else if (arguments.length === 3) {
644      typeErrorCheck(offset, ['number'], 'offset');
645      rangeErrorCheck(offset, 'offset', 0, this.length - 1);
646      if (typeof length === 'number') {
647        rangeErrorCheck(length, 'length', 0, this.length);
648        length = (length > this.length - offset) ? (this.length - offset) : length;
649        return this[bufferSymbol].writeString(str, offset, length, 'utf8');
650      } else if (typeof length === 'string') {
651        encoding = length;
652        length = this.length - offset;
653        let encode = encodingTypeErrorCheck(encoding);
654        return this[bufferSymbol].writeString(str, offset, length, encode);
655      } else {
656        throw typeError(length, 'length', ['number']);
657      }
658    } else {
659      if (typeof offset !== 'number') {
660        throw typeError(offset, 'offset', ['number']);
661      } else if (typeof length !== 'number') {
662        throw typeError(length, 'length', ['number']);
663      } else {
664        rangeErrorCheck(offset, 'offset', 0, this.length - 1);
665        let encode = encodingTypeErrorCheck(encoding);
666        length = (length > this.length - offset) ? (this.length - offset) : length;
667        return this[bufferSymbol].writeString(str, offset, length, encode);
668      }
669    }
670  }
671
672  convertToBig64BE(value: bigint, offset: number): number {
673    let byteValue = Number(utils.getLowerSixtyFour(value));
674    let bitNum: number = eightBytes;
675    for (let i = bitNum - 1; i > 0; i--) {
676      this[offset + i] = byteValue;
677      if (i === fourBytes) {
678        byteValue = Number(utils.getLowerSixtyFour(value >> 32n));
679      } else {
680        byteValue = byteValue >> eightBytes;
681      }
682    }
683    this[offset] = byteValue;
684    return offset + eightBytes;
685  }
686
687  convertToBig64LE(value: bigint, offset: number): number {
688    let byteValue = Number(utils.getLowerSixtyFour(value));
689    let bitNum = eightBytes;
690    for (let i = 0; i < bitNum - 1; i++) {
691      this[offset++] = byteValue;
692      if (i === 3) {
693        byteValue = Number(utils.getLowerSixtyFour(value >> 32n)); // 32 means offset 32-bits
694      } else {
695        byteValue = byteValue >> eightBytes;
696      }
697    }
698    this[offset++] = byteValue;
699    return offset;
700  }
701
702  private readIntBEType(offset: number, byteLength: number): number | undefined {
703    switch (byteLength) {
704      case oneByte:
705        return this.readInt8(offset);
706      case twoBytes:
707        return this.readInt16BE(offset);
708      case threeBytes:
709        return this.readInt24BE(offset);
710      case fourBytes:
711        return this.readInt32BE(offset);
712      case fiveBytes:
713        return this.readInt40BE(offset);
714      case sixBytes:
715        return this.readInt48BE(offset);
716      default:
717        break;
718    }
719    return undefined;
720  }
721
722  private readIntLEType(offset: number, byteLength: number): number | undefined {
723    switch (byteLength) {
724      case oneByte:
725        return this.readInt8(offset);
726      case twoBytes:
727        return this.readInt16LE(offset);
728      case threeBytes:
729        return this.readInt24LE(offset);
730      case fourBytes:
731        return this.readInt32LE(offset);
732      case fiveBytes:
733        return this.readInt40LE(offset);
734      case sixBytes:
735        return this.readInt48LE(offset);
736      default:
737        break;
738    }
739    return undefined;
740  }
741
742  private readUIntBEType(offset: number, byteLength: number): number | undefined {
743    switch (byteLength) {
744      case oneByte:
745        return this.readUInt8(offset);
746      case twoBytes:
747        return this.readUInt16BE(offset);
748      case threeBytes:
749        return this.readUInt24BE(offset);
750      case fourBytes:
751        return this.readUInt32BE(offset);
752      case fiveBytes:
753        return this.readUInt40BE(offset);
754      case sixBytes:
755        return this.readUInt48BE(offset);
756      default:
757        break;
758    }
759    return undefined;
760  }
761
762  private readUIntLEType(offset: number, byteLength: number): number | undefined {
763    switch (byteLength) {
764      case oneByte:
765        return this.readUInt8(offset);
766      case twoBytes:
767        return this.readUInt16LE(offset);
768      case threeBytes:
769        return this.readUInt24LE(offset);
770      case fourBytes:
771        return this.readUInt32LE(offset);
772      case fiveBytes:
773        return this.readUInt40LE(offset);
774      case sixBytes:
775        return this.readUInt48LE(offset);
776      default:
777        break;
778    }
779    return undefined;
780  }
781
782  private readData(offset: number, byteLength: number, style: Style): number | undefined {
783    rangeErrorCheck(byteLength, 'byteLength', oneByte, sixBytes);
784    if (style === Style.intBE) {
785      return this.readIntBEType(offset, byteLength);
786    } else if (style === Style.intLE) {
787      return this.readIntLEType(offset, byteLength);
788    } else if (style === Style.uintLE) {
789      return this.readUIntLEType(offset, byteLength);
790    } else if (style === Style.uintBE) {
791      return this.readUIntBEType(offset, byteLength);
792    }
793    return undefined;
794  }
795
796  private writeIntBEType(value: number, offset: number, byteLength: number): number | undefined {
797    switch (byteLength) {
798      case oneByte:
799        return this.writeInt8(value, offset);
800      case twoBytes:
801        return this.writeInt16BE(value, offset);
802      case threeBytes:
803        return this.writeUInt24BE(value, offset);
804      case fourBytes:
805        return this.writeInt32BE(value, offset);
806      case fiveBytes:
807        return this.writeUInt40BE(value, offset);
808      case sixBytes:
809        return this.writeUInt48BE(value, offset);
810      default:
811        break;
812    }
813    return undefined;
814  }
815
816  private writeUIntBEType(value: number, offset: number, byteLength: number): number | undefined {
817    switch (byteLength) {
818      case oneByte:
819        return this.writeUInt8(value, offset);
820      case twoBytes:
821        return this.writeUInt16BE(value, offset);
822      case threeBytes:
823        return this.writeUInt24BE(value, offset);
824      case fourBytes:
825        return this.writeUInt32BE(value, offset);
826      case fiveBytes:
827        return this.writeUInt40BE(value, offset);
828      case sixBytes:
829        return this.writeUInt48BE(value, offset);
830      default:
831        break;
832    }
833    return undefined;
834  }
835
836  private writeUIntLEType(value: number, offset: number, byteLength: number): number | undefined {
837    switch (byteLength) {
838      case oneByte:
839        return this.writeUInt8(value, offset);
840      case twoBytes:
841        return this.writeUInt16LE(value, offset);
842      case threeBytes:
843        return this.writeUInt24LE(value, offset);
844      case fourBytes:
845        return this.writeUInt32LE(value, offset);
846      case fiveBytes:
847        return this.writeUInt40LE(value, offset);
848      case sixBytes:
849        return this.writeUInt48LE(value, offset);
850      default:
851        break;
852    }
853    return undefined;
854  }
855
856  private writeData(value: number, offset: number, byteLength: number, style: Style): number | undefined {
857    rangeErrorCheck(byteLength, 'byteLength', oneByte, sixBytes);
858    if (style === Style.intBE) {
859      return this.writeIntBEType(value, offset, byteLength);
860    } else if (style === Style.intLE || style === Style.uintLE) {
861      return this.writeUIntLEType(value, offset, byteLength);
862    } else if (style === Style.uintBE) {
863      return this.writeUIntBEType(value, offset, byteLength);
864    }
865    return undefined;
866  }
867
868  writeBigInt64BE(value: bigint, offset: number = 0): number {
869    typeErrorCheck(value, ['bigint'], 'value');
870    if (offset === null) {
871      offset = 0;
872    }
873    typeErrorCheck(offset, ['number'], 'offset');
874    this.checkOffsetRange(offset, eightBytes);
875    // 2n : 63n : 1n : The range of 64-bit BigInt value is from negative the 63st power of 2 to the 63st power of 2 minus 1
876    rangeErrorCheck(value, 'value', -(2n ** 63n), 2n ** 63n, '-(2n ** 63n)', '2n ** 63n');
877    return this.convertToBig64BE(value, offset);
878  }
879
880  readBigInt64BE(offset: number = 0): bigint {
881    if (offset === null) {
882      offset = 0;
883    }
884    typeErrorCheck(offset, ['number'], 'offset');
885    this.checkOffsetRange(offset, eightBytes);
886    const val = (this[offset] << 24) + this.calculationBE(offset + 1, threeBytes); // 24 : the first val for this[offset]
887    return (BigInt(val) << 32n) + // 32 means offset 32-bits left
888      BigInt(this.calculationBE(offset + fourBytes, fourBytes));
889  }
890
891  writeBigInt64LE(value: bigint, offset: number = 0): number {
892    typeErrorCheck(value, ['bigint'], 'value');
893    if (offset === null) {
894      offset = 0;
895    }
896    typeErrorCheck(offset, ['number'], 'offset');
897    this.checkOffsetRange(offset, eightBytes);
898    // 2n : 63n : 1n : The range of 64-bit BigInt value is from negative the 63st power of 2 to the 63st power of 2 minus 1
899    rangeErrorCheck(value, 'value', -(2n ** 63n), 2n ** 63n, '-(2n ** 63n)', '2n ** 63n');
900
901    return this.convertToBig64LE(value, offset);
902  }
903
904  private calculationLE(offset: number, count: number): number {
905    let result: number = 0;
906    for (let i = 0; i < count; i++) {
907      result += this[offset++] * Math.pow(twoBytes, eightBytes * i);
908    }
909    return result;
910  }
911
912  private calculationBE(offset: number, count: number): number {
913    let result: number = 0;
914    for (let i = count - 1; i >= 0; i--) {
915      result += this[offset++] * Math.pow(twoBytes, eightBytes * i);
916    }
917    return result;
918  }
919
920  readBigInt64LE(offset: number = 0): bigint {
921    if (offset === null) {
922      offset = 0;
923    }
924    typeErrorCheck(offset, ['number'], 'offset');
925    this.checkOffsetRange(offset, eightBytes);
926    const val = this.calculationLE(offset + fourBytes, threeBytes) + (this[offset + sevenBytes] << 24); // 24 means offset 24-bits left
927    return (BigInt(val) << 32n) + BigInt(this.calculationLE(offset, fourBytes)); // 32 means offset 32-bits left
928  }
929
930  writeBigUInt64BE(value: bigint, offset: number = 0): number {
931    typeErrorCheck(value, ['bigint'], 'value');
932    if (offset === null) {
933      offset = 0;
934    }
935    typeErrorCheck(offset, ['number'], 'offset');
936    this.checkOffsetRange(offset, eightBytes);
937    // 2n : 64n : 1n : The range of 64-bit BigUInt value is from 0 to the 64st power of 2 minus 1
938    rangeErrorCheck(value, 'value', 0, 2n ** 64n - 1n, '0', '2n ** 64n - 1n');
939
940    return this.convertToBig64BE(value, offset);
941  }
942
943  readBigUInt64BE(offset: number = 0): bigint {
944    if (offset === null) {
945      offset = 0;
946    }
947    typeErrorCheck(offset, ['number'], 'offset');
948    this.checkOffsetRange(offset, eightBytes);
949    const hi = this.calculationBE(offset, fourBytes);
950
951    const lo = this.calculationBE(offset + fourBytes, fourBytes);
952    return (BigInt(hi) << 32n) + BigInt(lo); // 32 means offset 32-bits left
953  }
954
955  writeBigUInt64LE(value: bigint, offset: number = 0): number {
956    typeErrorCheck(value, ['bigint'], 'value');
957    if (offset === null) {
958      offset = 0;
959    }
960    typeErrorCheck(offset, ['number'], 'offset');
961    this.checkOffsetRange(offset, eightBytes);
962    rangeErrorCheck(value, 'value', 0, 2n ** 64n - 1n, '0', '2n ** 64n - 1n'); // 2n : 64n : 1n : The range of BigUInt
963
964    return this.convertToBig64LE(value, offset);
965  }
966
967  readBigUInt64LE(offset: number = 0): bigint {
968    if (offset === null) {
969      offset = 0;
970    }
971    typeErrorCheck(offset, ['number'], 'offset');
972    this.checkOffsetRange(offset, eightBytes);
973    const lo = this.calculationLE(offset, fourBytes);
974    const hi = this.calculationLE(offset + fourBytes, fourBytes);
975    return BigInt(lo) + (BigInt(hi) << 32n); // 32 means offset 32-bits left
976  }
977
978  writeInt8(value: number, offset: number = 0): number {
979    typeErrorCheck(value, ['number'], 'value');
980    if (offset === null) {
981      offset = 0;
982    }
983    typeErrorCheck(offset, ['number'], 'offset');
984    this.checkOffsetRange(offset, oneByte);
985    rangeErrorCheck(value, 'value', - (TWO_POW_SEVEN), (TWO_POW_SEVEN - 1));
986    value = +value;
987
988    this[offset] = value;
989    return offset + 1;
990  }
991
992  readInt8(offset: number = 0): number {
993    if (offset === null) {
994      offset = 0;
995    }
996    typeErrorCheck(offset, ['number'], 'offset');
997    this.checkOffsetRange(offset, oneByte);
998    const val = this[offset];
999
1000    return val | (val & TWO_POW_SEVEN) * 0x1fffffe; // 0x1fffffe mean the decimal value is 33554430"
1001  }
1002
1003  writeInt16BE(value: number, offset: number = 0): number {
1004    typeErrorCheck(value, ['number'], 'value');
1005    if (offset === null) {
1006      offset = 0;
1007    }
1008    typeErrorCheck(offset, ['number'], 'offset');
1009    this.checkOffsetRange(offset, twoBytes);
1010    rangeErrorCheck(value, 'value', - (TWO_POW_FIFTEEN), (TWO_POW_FIFTEEN - 1));
1011    value = +value;
1012    this[offset++] = (value >>> eightBytes);
1013    this[offset++] = value;
1014    return offset;
1015  }
1016
1017  readInt16BE(offset: number = 0): number {
1018    if (offset === null) {
1019      offset = 0;
1020    }
1021    typeErrorCheck(offset, ['number'], 'offset');
1022    this.checkOffsetRange(offset, twoBytes);
1023    const val = this.calculationBE(offset, twoBytes);
1024    return val | (val & TWO_POW_FIFTEEN) * 0x1fffe; // 0x1fffe mean the decimal value is 131070"
1025  }
1026
1027  writeInt16LE(value: number, offset: number = 0): number {
1028    typeErrorCheck(value, ['number'], 'value');
1029    if (offset === null) {
1030      offset = 0;
1031    }
1032    typeErrorCheck(offset, ['number'], 'offset');
1033    this.checkOffsetRange(offset, twoBytes);
1034    rangeErrorCheck(value, 'value', -(TWO_POW_FIFTEEN), (TWO_POW_FIFTEEN - 1));
1035    value = +value;
1036    this[offset++] = value;
1037    this[offset++] = (value >>> eightBytes);
1038    return offset;
1039  }
1040
1041  readInt16LE(offset: number = 0): number {
1042    if (offset === null) {
1043      offset = 0;
1044    }
1045    typeErrorCheck(offset, ['number'], 'offset');
1046    this.checkOffsetRange(offset, twoBytes);
1047    const val = this[offset] + this[offset + 1] * Math.pow(twoBytes, eightBytes);
1048    return val | (val & TWO_POW_FIFTEEN) * 0x1fffe; // 0x1fffe mean the decimal value is 131070"
1049  }
1050
1051  readUInt16LE(offset: number = 0): number {
1052    if (offset === null) {
1053      offset = 0;
1054    }
1055    typeErrorCheck(offset, ['number'], 'offset');
1056    this.checkOffsetRange(offset, twoBytes);
1057    return this[offset] + this[offset + 1] * Math.pow(twoBytes, eightBytes); // 8 means offset 8 bits
1058  }
1059
1060  writeUInt8(value: number, offset: number = 0): number {
1061    typeErrorCheck(value, ['number'], 'value');
1062    if (offset === null) {
1063      offset = 0;
1064    }
1065    typeErrorCheck(offset, ['number'], 'offset');
1066    this.checkOffsetRange(offset, oneByte);
1067    rangeErrorCheck(value, 'value', 0, 255); // 255 : The range of 8-bit UInt value is from 0 to the 255
1068    value = +value;
1069
1070    this[offset] = value;
1071    return offset + 1;
1072  }
1073
1074  readUInt8(offset: number = 0): number {
1075    if (offset === null) {
1076      offset = 0;
1077    }
1078    typeErrorCheck(offset, ['number'], 'offset');
1079    this.checkOffsetRange(offset, oneByte);
1080    const val = this[offset];
1081    return val;
1082  }
1083
1084  writeIntBE(value: number, offset: number, byteLength: number): number | undefined {
1085    typeErrorCheck(value, ['number'], 'value');
1086    typeErrorCheck(offset, ['number'], 'offset');
1087    typeErrorCheck(byteLength, ['number'], 'byteLength');
1088    return this.writeData(value, offset, byteLength, Style.intBE);
1089  }
1090
1091  private writeUInt24BE(value: number, offset: number = 0): number {
1092    this.checkOffsetRange(offset, threeBytes);
1093    // 24 : The range of 24-bit UInt value is from 0 to the 24st power of 2 minus 1
1094    rangeErrorCheck(value, 'value', 0, twoBytes ** 24 - 1, '0', '2**24 - 1');
1095    value = +value;
1096    for (let i: number = twoBytes; i > 0; i--) {
1097      this[offset + i] = value;
1098      value = value >>> eightBytes;
1099    }
1100    this[offset] = value;
1101    return offset + threeBytes;
1102  }
1103
1104  private writeUInt40BE(value: number, offset: number = 0): number {
1105    this.checkOffsetRange(offset, fiveBytes);
1106    // 2 : 40 : The range of 40-bit UInt value is from 0 to the 40st power of 2 minus 1
1107    rangeErrorCheck(value, 'value', 0, twoBytes ** 40 - 1, '0', '2**40 - 1');
1108    value = +value;
1109    this[offset++] = Math.floor(value * Math.pow(twoBytes, -32)); // -32 means offset 32 bits to left
1110    for (let i: number = 3; i > 0; i--) { // 3 is array->maxIndex
1111      this[offset + i] = value;
1112      value = value >>> eightBytes;
1113    }
1114    this[offset] = value;
1115    return offset + fourBytes;
1116  }
1117
1118  private writeUInt48BE(value: number, offset: number = 0): number {
1119    this.checkOffsetRange(offset, sixBytes);
1120    // 48 : The range of 48-bit UInt value is from 0 to the 48st power of 2 minus 1
1121    rangeErrorCheck(value, 'value', 0, twoBytes ** 48 - 1, '0', '2**48 - 1');
1122    value = +value;
1123    const newVal = Math.floor(value * Math.pow(twoBytes, -32)); // -32 means offset 32 bits to left
1124    this[offset++] = (newVal >>> eightBytes);
1125    this[offset++] = newVal;
1126    for (let i: number = 3; i > 0; i--) { // 3 is array->maxIndex
1127      this[offset + i] = value;
1128      value = value >>> eightBytes;
1129    }
1130    this[offset] = value;
1131    return offset + fourBytes;
1132  }
1133
1134  readIntBE(offset: number, byteLength: number): number | undefined {
1135    typeErrorCheck(offset, ['number'], 'offset');
1136    typeErrorCheck(byteLength, ['number'], 'byteLength');
1137    return this.readData(offset, byteLength, Style.intBE);
1138  }
1139
1140  private readInt48BE(offset: number = 0): number {
1141    this.checkOffsetRange(offset, sixBytes);
1142    const val = this.calculationBE(offset, twoBytes);
1143    return (val | (val & TWO_POW_FIFTEEN) * 0x1fffe) * MAX_LENGTH + this.calculationBE(offset + twoBytes, fourBytes);
1144  }
1145
1146  private readInt40BE(offset: number = 0): number {
1147    this.checkOffsetRange(offset, fiveBytes);
1148    const first = this[offset];
1149    const last = this[offset + fourBytes];
1150    return (this[offset] | (this[offset] & TWO_POW_SEVEN) * 0x1fffffe) * MAX_LENGTH +
1151      this.calculationBE(++offset, fourBytes);
1152  }
1153
1154
1155  private readInt24BE(offset: number = 0): number {
1156    this.checkOffsetRange(offset, threeBytes);
1157    const val = this.calculationBE(offset, threeBytes);
1158    // 23 : 0x1fe : The number of 3 bytes changes to 4 bytes, positive high fill 0, negative high fill 1.
1159    return val | (val & Math.pow(twoBytes, 23)) * 0x1fe;
1160  }
1161
1162  writeIntLE(value: number, offset: number, byteLength: number): number | undefined {
1163    typeErrorCheck(value, ['number'], 'value');
1164    typeErrorCheck(offset, ['number'], 'offset');
1165    typeErrorCheck(byteLength, ['number'], 'byteLength');
1166    return this.writeData(value, offset, byteLength, Style.intLE);
1167  }
1168
1169  private writeUInt48LE(value: number, offset: number = 0): number {
1170    this.checkOffsetRange(offset, sixBytes);
1171    // 2 : 48 : The range of 48-bit UInt value is from 0 to the 48st power of 2 minus 1
1172    rangeErrorCheck(value, 'value', 0, twoBytes ** 48 - 1, '0', '2**48 - 1');
1173    value = +value;
1174    const newVal = Math.floor(value * Math.pow(twoBytes, -32)); // -32 means offset 32 bits to left
1175    for (let i: number = 3; i > 0; i--) {
1176      this[offset++] = value;
1177      value = value >>> eightBytes;
1178    }
1179    this[offset++] = value;
1180    this[offset++] = newVal;
1181    this[offset++] = (newVal >>> eightBytes);
1182    return offset;
1183  }
1184
1185  private writeUInt40LE(value: number, offset: number = 0): number {
1186    this.checkOffsetRange(offset, fiveBytes);
1187    // 2 : 40 : The range of 40-bit UInt value is from 0 to the 40st power of 2 minus 1
1188    rangeErrorCheck(value, 'value', 0, twoBytes ** 40 - 1, '0', '2**40 - 1');
1189    value = +value;
1190    const newVal = value;
1191    for (let i: number = 3; i > 0; i--) {
1192      this[offset++] = value;
1193      value = value >>> eightBytes;
1194    }
1195    this[offset++] = value;
1196    this[offset++] = Math.floor(newVal * Math.pow(twoBytes, -32)); // -32 means offset 32 bits to left
1197    return offset;
1198  }
1199
1200  private writeUInt24LE(value: number, offset: number = 0): number {
1201    this.checkOffsetRange(offset, threeBytes);
1202    // 2 : 24 : The range of 24-bit UInt value is from 0 to the 24st power of 2 minus 1
1203    rangeErrorCheck(value, 'value', 0, twoBytes ** 24 - 1, '0', '2**24 - 1');
1204    value = +value;
1205    for (let i: number = twoBytes; i > 0; i--) {
1206      this[offset++] = value;
1207      value = value >>> eightBytes;
1208    }
1209    this[offset++] = value;
1210    return offset;
1211  }
1212
1213  readIntLE(offset: number, byteLength: number): number | undefined {
1214    typeErrorCheck(offset, ['number'], 'offset');
1215    typeErrorCheck(byteLength, ['number'], 'byteLength');
1216    return this.readData(offset, byteLength, Style.intLE);
1217  }
1218
1219  private readInt48LE(offset: number = 0): number {
1220    this.checkOffsetRange(offset, sixBytes);
1221    const val = this.calculationLE(offset + fourBytes, twoBytes);
1222    return (val | (val & TWO_POW_FIFTEEN) * 0x1fffe) * MAX_LENGTH + this.calculationLE(offset, fourBytes);
1223  }
1224
1225  private readInt40LE(offset: number = 0): number {
1226    this.checkOffsetRange(offset, fiveBytes);
1227    return (this[offset + fourBytes] | (this[offset + fourBytes] & TWO_POW_SEVEN) * 0x1fffffe) * MAX_LENGTH +
1228      this.calculationLE(offset, fourBytes);
1229  }
1230
1231  private readInt24LE(offset: number = 0): number {
1232    this.checkOffsetRange(offset, threeBytes);
1233    const val = this.calculationLE(offset, threeBytes);
1234    // 2 : 23 : 0x1fe : The number of 3 bytes changes to 4 bytes, positive high fill 0, negative high fill 1.
1235    return val | (val & Math.pow(twoBytes, 23)) * 0x1fe;
1236  }
1237
1238  writeUIntLE(value: number, offset: number, byteLength: number): number | undefined {
1239    typeErrorCheck(value, ['number'], 'value');
1240    typeErrorCheck(offset, ['number'], 'offset');
1241    typeErrorCheck(byteLength, ['number'], 'byteLength');
1242    return this.writeData(value, offset, byteLength, Style.uintLE);
1243  }
1244
1245  readUIntLE(offset: number, byteLength: number): number | undefined {
1246    typeErrorCheck(offset, ['number'], 'offset');
1247    typeErrorCheck(byteLength, ['number'], 'byteLength');
1248    return this.readData(offset, byteLength, Style.uintLE);
1249  }
1250
1251  private readUInt48LE(offset: number = 0): number {
1252    this.checkOffsetRange(offset, sixBytes);
1253    return this.calculationLE(offset, fourBytes) +
1254      (this.calculationLE(offset + fourBytes, twoBytes)) * MAX_LENGTH;
1255  }
1256
1257  private readUInt40LE(offset: number = 0): number {
1258    this.checkOffsetRange(offset, fiveBytes);
1259    return this.calculationLE(offset, fiveBytes);
1260  }
1261
1262  private readUInt24LE(offset: number = 0): number {
1263    this.checkOffsetRange(offset, threeBytes);
1264    return this.calculationLE(offset, threeBytes);
1265  }
1266
1267  writeUIntBE(value: number, offset: number, byteLength: number): number | undefined {
1268    typeErrorCheck(value, ['number'], 'value');
1269    typeErrorCheck(offset, ['number'], 'offset');
1270    typeErrorCheck(byteLength, ['number'], 'byteLength');
1271    return this.writeData(value, offset, byteLength, Style.uintBE);
1272  }
1273
1274  readUIntBE(offset: number, byteLength: number): number | undefined {
1275    typeErrorCheck(offset, ['number'], 'offset');
1276    typeErrorCheck(byteLength, ['number'], 'byteLength');
1277    return this.readData(offset, byteLength, Style.uintBE);
1278  }
1279
1280  private readUInt48BE(offset: number = 0): number {
1281    this.checkOffsetRange(offset, sixBytes);
1282    return (this.calculationBE(offset, twoBytes)) * MAX_LENGTH + this.calculationBE(offset + twoBytes, fourBytes);
1283  }
1284
1285  private readUInt40BE(offset: number = 0): number {
1286    this.checkOffsetRange(offset, fiveBytes);
1287    return this.calculationBE(offset, fiveBytes);
1288  }
1289
1290  private readUInt24BE(offset: number = 0): number {
1291    this.checkOffsetRange(offset, threeBytes);
1292    return this.calculationBE(offset, threeBytes);
1293  }
1294
1295  writeInt32BE(value: number, offset: number = 0): number {
1296    typeErrorCheck(value, ['number'], 'value');
1297    if (offset === null) {
1298      offset = 0;
1299    }
1300    typeErrorCheck(offset, ['number'], 'offset');
1301    this.checkOffsetRange(offset, fourBytes);
1302    // 2 : 31 : The range of 32-bit Int value is from negative the 31st power of 2 to the 31st power of 2 minus 1
1303    rangeErrorCheck(value, 'value', - (Math.pow(twoBytes, 31)), (Math.pow(twoBytes, 31) - 1));
1304
1305    value = +value;
1306    this[bufferSymbol].writeInt32BE(value, offset);
1307    return offset + fourBytes;
1308  }
1309
1310  private checkOffsetRange(offset: number, size: number): void {
1311    rangeErrorCheck(offset, 'offset', 0, this.length - size);
1312  }
1313
1314  readInt32BE(offset: number = 0): number {
1315    if (offset === null) {
1316      offset = 0;
1317    }
1318    typeErrorCheck(offset, ['number'], 'offset');
1319    this.checkOffsetRange(offset, fourBytes);
1320    return this[bufferSymbol].readInt32BE(offset);
1321  }
1322
1323  writeInt32LE(value: number, offset: number = 0): number {
1324    typeErrorCheck(value, ['number'], 'value');
1325    if (offset === null) {
1326      offset = 0;
1327    }
1328    typeErrorCheck(offset, ['number'], 'offset');
1329    this.checkOffsetRange(offset, fourBytes);
1330    // 2 : 31 : The range of 32-bit Int value is from negative the 31st power of 2 to the 31st power of 2 minus 1
1331    rangeErrorCheck(value, 'value', - (Math.pow(twoBytes, 31)), (Math.pow(twoBytes, 31) - 1));
1332
1333    value = +value;
1334    this[bufferSymbol].writeInt32LE(value, offset);
1335    return offset + fourBytes;
1336  }
1337
1338  readInt32LE(offset: number = 0): number {
1339    if (offset === null) {
1340      offset = 0;
1341    }
1342    typeErrorCheck(offset, ['number'], 'offset');
1343    this.checkOffsetRange(offset, fourBytes);
1344    return this[bufferSymbol].readInt32LE(offset);
1345  }
1346
1347  writeUInt32BE(value: number, offset: number = 0): number {
1348    typeErrorCheck(value, ['number'], 'value');
1349    if (offset === null) {
1350      offset = 0;
1351    }
1352    typeErrorCheck(offset, ['number'], 'offset');
1353    this.checkOffsetRange(offset, fourBytes);
1354    // 2 : 32 : The range of 32-bit UInt value is from zero to the 32st power of 2 minus 1
1355    rangeErrorCheck(value, 'value', 0, (MAX_LENGTH - 1));
1356    value = +value;
1357    this[bufferSymbol].writeUInt32BE(value, offset);
1358    return offset + fourBytes;
1359  }
1360
1361  readUInt32BE(offset: number = 0): number {
1362    if (offset === null) {
1363      offset = 0;
1364    }
1365    typeErrorCheck(offset, ['number'], 'offset');
1366    this.checkOffsetRange(offset, fourBytes);
1367    return this[bufferSymbol].readUInt32BE(offset);
1368  }
1369
1370  writeUInt32LE(value: number, offset: number = 0): number {
1371    typeErrorCheck(value, ['number'], 'value');
1372    if (offset === null) {
1373      offset = 0;
1374    }
1375    typeErrorCheck(offset, ['number'], 'offset');
1376    this.checkOffsetRange(offset, fourBytes);
1377    rangeErrorCheck(value, 'value', 0, (MAX_LENGTH - 1));
1378    value = +value;
1379    this[bufferSymbol].writeUInt32LE(value, offset);
1380    return offset + fourBytes;
1381  }
1382
1383  readUInt32LE(offset: number = 0): number {
1384    if (offset === null) {
1385      offset = 0;
1386    }
1387    typeErrorCheck(offset, ['number'], 'offset');
1388    this.checkOffsetRange(offset, fourBytes);
1389    return this[bufferSymbol].readUInt32LE(offset);
1390  }
1391
1392  writeDoubleBE(value: number, offset: number = 0): number {
1393    typeErrorCheck(value, ['number'], 'value');
1394    if (offset === null) {
1395      offset = 0;
1396    }
1397    typeErrorCheck(offset, ['number'], 'offset');
1398    this.checkOffsetRange(offset, eightBytes);
1399
1400    value = +value;
1401    float64Array[0] = value;
1402    let i: number = 7; // 7 is uInt8Float64Array->maxIndex
1403    while (i >= 0) {
1404      this[offset++] = uInt8Float64Array[i--];
1405    }
1406    return offset;
1407  }
1408
1409  readDoubleBE(offset: number = 0): number {
1410    if (offset === null) {
1411      offset = 0;
1412    }
1413    typeErrorCheck(offset, ['number'], 'offset');
1414    this.checkOffsetRange(offset, eightBytes);
1415
1416    let i: number = 7; // 7 is uInt8Float64Array->maxIndex
1417    while (i >= 0) {
1418      uInt8Float64Array[i--] = this[offset++];
1419    }
1420    return float64Array[0];
1421  }
1422
1423  writeDoubleLE(value: number, offset: number = 0): number {
1424    typeErrorCheck(value, ['number'], 'value');
1425    if (offset === null) {
1426      offset = 0;
1427    }
1428    typeErrorCheck(offset, ['number'], 'offset');
1429    this.checkOffsetRange(offset, eightBytes);
1430
1431    value = +value;
1432    float64Array[0] = value;
1433    let i: number = 0;
1434    while (i <= 7) { // 7 is uInt8Float64Array->maxIndex
1435      this[offset++] = uInt8Float64Array[i++];
1436    }
1437    return offset;
1438  }
1439
1440  readDoubleLE(offset: number = 0): number {
1441    if (offset === null) {
1442      offset = 0;
1443    }
1444    typeErrorCheck(offset, ['number'], 'offset');
1445    this.checkOffsetRange(offset, eightBytes);
1446
1447    let i: number = 0;
1448    while (i <= 7) { // 7 is uInt8Float64Array->maxIndex
1449      uInt8Float64Array[i++] = this[offset++];
1450    }
1451    return float64Array[0];
1452  }
1453
1454  writeFloatBE(value: number, offset: number = 0): number {
1455    typeErrorCheck(value, ['number'], 'value');
1456    if (offset === null) {
1457      offset = 0;
1458    }
1459    typeErrorCheck(offset, ['number'], 'offset');
1460    this.checkOffsetRange(offset, fourBytes);
1461
1462    value = +value;
1463    float32Array[0] = value;
1464    let i: number = 3; // 3 is uInt8Float32Array->maxIndex
1465    while (i >= 0) {
1466      this[offset++] = uInt8Float32Array[i--];
1467    }
1468    return offset;
1469  }
1470
1471  readFloatBE(offset: number = 0): number {
1472    if (offset === null) {
1473      offset = 0;
1474    }
1475    typeErrorCheck(offset, ['number'], 'offset');
1476    this.checkOffsetRange(offset, fourBytes);
1477
1478    let i: number = 3; // 3 is uInt8Float32Array->maxIndex
1479    while (i >= 0) {
1480      uInt8Float32Array[i--] = this[offset++];
1481    }
1482    return float32Array[0];
1483  }
1484
1485  writeFloatLE(value: number, offset: number = 0): number {
1486    typeErrorCheck(value, ['number'], 'value');
1487    if (offset === null) {
1488      offset = 0;
1489    }
1490    typeErrorCheck(offset, ['number'], 'offset');
1491    this.checkOffsetRange(offset, fourBytes);
1492
1493    value = +value;
1494    float32Array[0] = value;
1495    let i: number = 0;
1496    while (i <= 3) { // 3 is uInt8Float32Array->maxIndex
1497      this[offset++] = uInt8Float32Array[i++];
1498    }
1499    return offset;
1500  }
1501
1502  readFloatLE(offset: number): number {
1503    if (offset === undefined || offset === null) {
1504      offset = 0;
1505    }
1506    typeErrorCheck(offset, ['number'], 'offset');
1507    this.checkOffsetRange(offset, fourBytes);
1508    let i: number = 0;
1509    while (i <= 3) { // 3 is uInt8Float32Array->maxIndex
1510      uInt8Float32Array[i++] = this[offset++];
1511    }
1512    return float32Array[0];
1513  }
1514
1515  writeUInt16BE(value: number, offset: number = 0): number {
1516    typeErrorCheck(value, ['number'], 'value');
1517    if (offset === null) {
1518      offset = 0;
1519    }
1520    typeErrorCheck(offset, ['number'], 'offset');
1521    this.checkOffsetRange(offset, twoBytes);
1522    // 2 : 16 : The range of 32-bit Int value is from zero to the 16st power of 2 minus 1
1523    rangeErrorCheck(value, 'value', 0, Math.pow(twoBytes, 16) - 1);
1524    value = +value;
1525    this[offset++] = (value >>> eightBytes);
1526    this[offset++] = value;
1527    return offset;
1528  }
1529
1530  readUInt16BE(offset: number = 0): number {
1531    if (offset === null) {
1532      offset = 0;
1533    }
1534    typeErrorCheck(offset, ['number'], 'offset');
1535    this.checkOffsetRange(offset, twoBytes);
1536    const first = this[offset];
1537    const last = this[offset + 1];
1538    return first * Math.pow(twoBytes, eightBytes) + last;
1539  }
1540
1541  writeUInt16LE(value: number, offset: number = 0): number {
1542    typeErrorCheck(value, ['number'], 'value');
1543    if (offset === null) {
1544      offset = 0;
1545    }
1546    typeErrorCheck(offset, ['number'], 'offset');
1547    this.checkOffsetRange(offset, twoBytes);
1548    // 2 : 16 : The range of 32-bit Int value is from zero to the 16st power of 2 minus 1
1549    rangeErrorCheck(value, 'value', 0, Math.pow(twoBytes, 16) - 1);
1550    value = +value;
1551    this[offset++] = value;
1552    this[offset++] = (value >>> eightBytes);
1553    return offset;
1554  }
1555
1556  compareInner(target: Buffer | Uint8Array, targetStart: number = 0, targetEnd: number = target.length,
1557    sourceStart: number = 0, sourceEnd: number = this.length): number {
1558      let length1: number = sourceEnd - sourceStart;
1559      let length2: number = targetEnd - targetStart;
1560      let length: number = length1 > length2 ? length2 : length1;
1561      if (target instanceof Buffer) {
1562        let val = this[bufferSymbol].compare(target[bufferSymbol], targetStart, sourceStart, length);
1563        if (val === 0) {
1564          if (length1 === length2) {
1565            return 0;
1566          }
1567          return length1 < length2 ? -1 : 1;
1568        } else {
1569          return val < 0 ? 1 : -1;
1570        }
1571      } else {
1572        let bufData1 = this[bufferSymbol].getBufferData();
1573        for (let i = 0; i < length; i++) {
1574          let value1 = +bufData1[i + sourceStart];
1575          let value2 = +target[i + targetStart];
1576          if (value1 === value2) {
1577            continue;
1578          }
1579          return value1 < value2 ? -1 : 1;
1580        }
1581        if (length1 === length2) {
1582          return 0;
1583        }
1584        return length1 < length2 ? -1 : 1;
1585      }
1586    }
1587
1588  compare(target: Buffer | Uint8Array, targetStart: number = 0, targetEnd: number = target.length,
1589    sourceStart: number = 0, sourceEnd: number = this.length): number {
1590    if (targetStart === null) {
1591      targetStart = 0;
1592    }
1593    if (targetEnd === null) {
1594      targetEnd = target.length;
1595    }
1596    if (sourceStart === null) {
1597      sourceStart = 0;
1598    }
1599    if (sourceEnd === null) {
1600      sourceEnd = this.length;
1601    }
1602    typeErrorCheck(target, ['Buffer', 'Uint8Array'], 'target');
1603    typeErrorCheck(targetStart, ['number'], 'targetStart');
1604    typeErrorCheck(targetEnd, ['number'], 'targetEnd');
1605    typeErrorCheck(sourceStart, ['number'], 'sourceStart');
1606    typeErrorCheck(sourceEnd, ['number'], 'sourceEnd');
1607    rangeErrorCheck(targetStart, 'targetStart', 0, UINT32MAX);
1608    rangeErrorCheck(sourceStart, 'sourceStart', 0, UINT32MAX);
1609    rangeErrorCheck(targetEnd, 'targetEnd', 0, target.length);
1610    rangeErrorCheck(sourceEnd, 'sourceEnd', 0, this.length);
1611    if (sourceStart >= sourceEnd) {
1612      return (targetStart >= targetEnd ? 0 : -1);
1613    }
1614    if (targetStart >= targetEnd) {
1615      return 1;
1616    }
1617    return this.compareInner(target, targetStart, targetEnd, sourceStart, sourceEnd);
1618  }
1619
1620  equals(otherBuffer: Uint8Array | Buffer): boolean {
1621    typeErrorCheck(otherBuffer, ['Buffer', 'Uint8Array'], 'otherBuffer');
1622    let res = this.compare(otherBuffer, 0, otherBuffer.length, 0, this.length);
1623    return res === 0 ? true : false;
1624  }
1625
1626  subarray(start: number = 0, end: number = this.length): Buffer {
1627    let newBuf: Buffer = new Buffer(0);
1628    start = isNaN(start) ? 0 : Number(start);
1629    end = isNaN(end) ? 0 : Number(end);
1630    end = (end > this.length) ? this.length : end;
1631    if (start < 0 || end < 0 || end <= start) {
1632      return newBuf;
1633    }
1634    newBuf[bufferSymbol].subBuffer(this[bufferSymbol], start, end);
1635    newBuf[lengthSymbol] = (end - start);
1636    return newBuf;
1637  }
1638
1639  copy(target: Buffer | Uint8Array, targetStart: number = 0, sourceStart: number = 0,
1640    sourceEnd: number = this.length): number {
1641    typeErrorCheck(target, ['Buffer', 'Uint8Array'], 'target');
1642    targetStart = isNaN(targetStart) ? 0 : Number(targetStart);
1643    sourceStart = isNaN(sourceStart) ? 0 : Number(sourceStart);
1644    sourceEnd = isNaN(sourceEnd) ? this.length : Number(sourceEnd);
1645    rangeLeftErrorCheck(targetStart, 'targetStart', 0);
1646    rangeLeftErrorCheck(sourceStart, 'sourceStart', 0);
1647    rangeLeftErrorCheck(sourceEnd, 'sourceEnd', 0);
1648    if (targetStart >= target.length) {
1649      return 0;
1650    }
1651    if (sourceEnd <= sourceStart || sourceStart >= this.length) {
1652      return 0;
1653    }
1654    if (target instanceof Buffer) {
1655      sourceEnd = sourceEnd > this.length ? this.length : sourceEnd;
1656      return this[bufferSymbol].copy(target[bufferSymbol], targetStart, sourceStart, sourceEnd);
1657    }
1658    if (sourceEnd - sourceStart > target.length - targetStart) {
1659        sourceEnd = target.length - targetStart + sourceStart;
1660    }
1661    let sLength = sourceEnd - sourceStart;
1662    let res = sLength > this.length - sourceStart ? this.length - sourceStart : sLength;
1663    for (let i = 0; i < res; i++) {
1664      target[targetStart++] = this[sourceStart++];
1665    }
1666    return res;
1667  }
1668
1669  toString(encoding: string = 'utf8', start: number = 0, end: number = this.length): string {
1670    if (encoding === null) {
1671      encoding = 'utf8';
1672    }
1673    let encodObj = getEncodingByType(encoding);
1674    if (!encodObj) {
1675      throw typeErrorForEncoding(encoding, 'encoding');
1676    }
1677    start = isNaN(start) ? 0 : (Number(start) < 0 ? 0 : Number(start));
1678    end = isNaN(end) ? 0 : Number(end);
1679    let bufLength = this.length;
1680    if (start >= bufLength || start > end) {
1681      return '';
1682    }
1683    end = end > bufLength ? bufLength : end;
1684    return encodObj.toString(this, start, end);
1685  }
1686
1687  toJSON(): Object {
1688    if (this.length <= 0) {
1689      return { type: 'Buffer', data: [] };
1690    }
1691    let data = this[bufferSymbol].getBufferData();
1692    return { type: 'Buffer', data };
1693  }
1694
1695  indexOf(value: string | number | Buffer | Uint8Array, byteOffset: number = 0, encoding: string = 'utf8'): number {
1696    typeErrorCheck(value, ['string', 'number', 'Buffer', 'Uint8Array'], 'value');
1697    if (typeof value === 'string') {
1698      const length = this[lengthSymbol];
1699      if (typeof byteOffset === 'string') {
1700        encoding = byteOffset;
1701      }
1702      if (typeof byteOffset !== 'number') {
1703        byteOffset = 0;
1704      }
1705      if (encoding === null) {
1706        encoding = 'utf8';
1707      }
1708      encoding = encodingTypeErrorCheck(encoding);
1709      if (byteOffset > length) {
1710        return -1;
1711      }
1712      if (byteOffset < 0) {
1713        let offsetResult = Math.abs(byteOffset);
1714        if (offsetResult > length) {
1715          byteOffset = 0;
1716        } else {
1717          byteOffset = length - offsetResult;
1718        }
1719      }
1720      return this[bufferSymbol].indexOf(value, byteOffset, encoding, false);
1721    } else if (typeof value === 'number') {
1722      value = +value;
1723      if (value < 0 || value > utils.eightBits) {
1724        return -1;
1725      }
1726      let data = this[bufferSymbol].getBufferData();
1727      return data.indexOf(value, byteOffset);
1728    } else {
1729      let sourceData = this[bufferSymbol].getBufferData();
1730      if (value instanceof Buffer) {
1731        let targetData = value[bufferSymbol].getBufferData();
1732        return sourceData.join(',').indexOf(targetData.join(','), byteOffset);
1733      }
1734      return sourceData.join(',').indexOf(value.join(','), byteOffset);
1735    }
1736  }
1737
1738  lastIndexOf(value: string | number | Buffer | Uint8Array, byteOffset: number = this.length,
1739    encoding: string = 'utf8'): number {
1740    typeErrorCheck(value, ['string', 'number', 'Buffer', 'Uint8Array'], 'value');
1741    if (typeof value === 'string') {
1742      if (value.length === 0) {
1743        return -1;
1744      }
1745      if (typeof byteOffset === null) {
1746        byteOffset = 0;
1747      }
1748      if (encoding === null) {
1749        encoding = 'utf8';
1750      }
1751      encoding = encodingTypeErrorCheck(encoding);
1752      let str = this.toString(encoding);
1753      byteOffset = byteOffset < 0 ? str.length + byteOffset : byteOffset;
1754      return str.lastIndexOf(value, byteOffset);
1755    } else if (typeof value === 'number') {
1756      value = +value;
1757      if (value < 0 || value > utils.eightBits) {
1758        return -1;
1759      }
1760      let data = this[bufferSymbol].getBufferData();
1761      return data.lastIndexOf(value, byteOffset);
1762    } else {
1763      let sourceData = this[bufferSymbol].getBufferData();
1764      if (value instanceof Buffer) {
1765        let targetData = value[bufferSymbol].getBufferData();
1766        return sourceData.join(',').lastIndexOf(targetData.join(','), byteOffset);
1767      }
1768      return sourceData.join(',').lastIndexOf(value.join(','), byteOffset);
1769    }
1770  }
1771
1772  includes(value: string | number | Buffer | Uint8Array, byteOffset: number = 0, encoding: string = 'utf8'): boolean {
1773    typeErrorCheck(value, ['string', 'number', 'Buffer', 'Uint8Array'], 'value');
1774    if (encoding === null) {
1775      encoding = 'utf8';
1776    }
1777    encoding = encodingTypeErrorCheck(encoding);
1778    if (typeof value === 'string') {
1779      const length = this[lengthSymbol];
1780      if (byteOffset > length) {
1781        return false;
1782      }
1783      if (byteOffset < 0) {
1784        let byteOffsetAbs: number = Math.abs(byteOffset);
1785        if (byteOffsetAbs <= length) {
1786          byteOffset = length - byteOffsetAbs;
1787        } else {
1788          byteOffset = 0;
1789        }
1790      }
1791    }
1792    return this.indexOf(value, byteOffset, encoding) !== -1;
1793  }
1794
1795  reverseBits(dealNum: number): Buffer {
1796    const len: number = this.length;
1797    const dealLen: number = dealNum;
1798    for (let i = 0; i < len / dealLen; i++) {
1799      let times: number = 0;
1800      let startIndex: number = dealLen * i;
1801      let endIndex: number = startIndex + dealLen - 1;
1802      while (times < dealLen / twoBytes) {
1803        let tmp = this[startIndex + times];
1804        this[startIndex + times] = this[endIndex - times];
1805        this[endIndex - times] = tmp;
1806        times++;
1807      }
1808    }
1809    return this;
1810  }
1811
1812  swap16(): Buffer {
1813    const len = this.length;
1814    const dealLen: number = twoBytes;
1815    if (len % dealLen !== 0) {
1816      throw bufferSizeError('16-bits');
1817    }
1818    return this.reverseBits(dealLen);
1819  }
1820
1821  swap32(): Buffer {
1822    const len = this.length;
1823    const dealLen: number = 4; // Process every 4 bits
1824    if (len % dealLen !== 0) {
1825      throw bufferSizeError('32-bits');
1826    }
1827    return this.reverseBits(dealLen);
1828  }
1829
1830  swap64(): Buffer {
1831    const len = this.length;
1832    const dealLen: number = eightBytes;
1833    if (len % dealLen !== 0) {
1834      throw bufferSizeError('64-bits');
1835    }
1836    return this.reverseBits(dealLen);
1837  }
1838
1839  keys(): IterableIterator<number> {
1840    return this[bufferSymbol].getBufferData().keys();
1841  }
1842
1843  values(): IterableIterator<number> {
1844    return this[bufferSymbol].getBufferData().values();
1845  }
1846
1847  entries(): IterableIterator<[number, number]> {
1848    return this[bufferSymbol].getBufferData().entries();
1849  }
1850
1851  [Symbol.iterator](): IterableIterator<[number, number]> {
1852    return this[bufferSymbol].getBufferData().entries();
1853  }
1854}
1855
1856function typeError(param: unknown, paramName: string, excludedTypes: string[]): BusinessError {
1857  let msg = new ErrorMessage(errorMap.typeError, paramName).setTypeInfo(excludedTypes, param).getString();
1858  return new BusinessError(msg, errorMap.typeError);
1859}
1860
1861function typeErrorForEncoding(param: unknown, paramName: string): BusinessError {
1862  let msg = new ErrorMessage(errorMap.typeError, paramName).setEncodingTypeInfo(['BufferEncoding'], param).getString();
1863  return new BusinessError(msg, errorMap.typeError);
1864}
1865
1866function typeErrorForProperty(typeName: string): BusinessError {
1867  let msg = new ErrorMessage(errorMap.typeErrorForProperty).setProperty(typeName).getString();
1868  return new BusinessError(msg, errorMap.typeErrorForProperty);
1869}
1870
1871function typeErrorForSize(param: unknown, paramName: string, excludedTypes: string[]): BusinessError {
1872  let msg = new ErrorMessage(errorMap.typeError, paramName).setSizeTypeInfo(excludedTypes, param).getString();
1873  return new BusinessError(msg, errorMap.typeError);
1874}
1875
1876function rangeError(paramName: string, rangeLeft: string | bigint | number, rangeRight: string | bigint | number,
1877  receivedValue: number | bigint): BusinessError {
1878  let msg =
1879    new ErrorMessage(errorMap.rangeError, paramName).setRangeInfo(rangeLeft, rangeRight, receivedValue).getString();
1880  return new BusinessError(msg, errorMap.rangeError);
1881}
1882
1883function rangeLeftError(paramName: string, rangeLeft: number, receivedValue: number): BusinessError {
1884  let msg = new ErrorMessage(errorMap.rangeError, paramName).setRangeLeftInfo(rangeLeft, receivedValue).getString();
1885  return new BusinessError(msg, errorMap.rangeError);
1886}
1887
1888function bufferSizeError(size: string): BusinessError {
1889  let msg = new ErrorMessage(errorMap.bufferSizeError).setSizeInfo(size).getString();
1890  return new BusinessError(msg, errorMap.bufferSizeError);
1891}
1892
1893function typeErrorCheck(param: unknown, types: string[], paramName: string): void {
1894  let typeName = getTypeName(param);
1895  if (!types.includes(typeName)) {
1896    throw typeError(param, paramName, types);
1897  }
1898}
1899
1900function sizeErrorCheck(param: unknown, paramName: string, types: string[],
1901  rangeLeft: number, rangeRight: number): void {
1902  let typeName = getTypeName(param);
1903  if (!types.includes(typeName)) {
1904    throw typeErrorForSize(param, paramName, types);
1905  }
1906  if (Number(param) < rangeLeft || Number(param) > rangeRight) {
1907    let typeString = types.join(', ');
1908    typeString = typeString.replace(',', ' or');
1909    let msg = 'Parameter error. The type of "' + paramName + '" must be ' + typeString +
1910      ' and the value cannot be negative. Received value is: ' + Number(param).toString();
1911    throw new BusinessError(msg, errorMap.typeError);
1912  }
1913}
1914
1915function encodingTypeErrorCheck(encoding: string): string {
1916  const normalizedEncoding = normalizeEncoding(encoding);
1917  if (normalizedEncoding === undefined) {
1918    throw typeErrorForEncoding(encoding, 'encoding');
1919  }
1920  return normalizedEncoding;
1921}
1922
1923function rangeErrorCheck(param: number | bigint, paramName: string, rangeLeft: bigint | number,
1924  rangeRight: bigint | number, rangeLeftExpr: string = '', rangeRightExpr: string = ''): void {
1925  let left : bigint | number;
1926  let right : bigint | number;
1927  if (Number.isInteger(rangeLeft) && Number.isInteger(rangeRight)) {
1928    left = BigInt(rangeLeft);
1929    right = BigInt(rangeRight);
1930  } else {
1931    left = rangeLeft;
1932    right = rangeRight;
1933  }
1934  if (param < left || param > right) {
1935    throw rangeError(paramName, rangeLeftExpr === '' ? rangeLeft : rangeLeftExpr,
1936      rangeRightExpr === '' ? rangeRight : rangeRightExpr, param);
1937  }
1938}
1939
1940function rangeLeftErrorCheck(param: number, paramName: string, rangeLeft: number): void {
1941  if (param < rangeLeft) {
1942    throw rangeLeftError(paramName, rangeLeft, param);
1943  }
1944}
1945
1946function concat(list: Buffer[] | Uint8Array[], totalLength?: number): Buffer {
1947  typeErrorCheck(list, ['Array'], 'list');
1948  if (!(typeof totalLength === 'number' || typeof totalLength === 'undefined' || 'null')) {
1949    throw typeError(totalLength, 'totalLength', ['number']);
1950  }
1951  if (list.length === 0) {
1952    return new Buffer(0);
1953  }
1954  if (!totalLength) {
1955    totalLength = 0;
1956    for (let i = 0, len = list.length; i < len; i++) {
1957      let buf = list[i];
1958      if (buf instanceof Uint8Array || buf instanceof Buffer) {
1959        totalLength += list[i].length;
1960      }
1961    }
1962  }
1963
1964  rangeErrorCheck(totalLength, 'totalLength', 0, UINT32MAX);
1965
1966  let buffer = allocUninitializedFromPool(totalLength);
1967  let offset = 0;
1968  for (let i = 0, len = list.length; i < len; i++) {
1969    const buf = list[i];
1970    if (buf instanceof Uint8Array) {
1971      buf.forEach((val) => buffer[offset++] = val);
1972    } else if (buf instanceof Buffer) {
1973      buf.copy(buffer, offset);
1974      offset += buf.length;
1975    }
1976  }
1977  return buffer;
1978}
1979
1980function alloc(size: number, fill?: string | Buffer | number, encoding?: string): Buffer {
1981  sizeErrorCheck(size, 'size', ['number'], 0, MAX_LENGTH);
1982  const buf = new Buffer(size);
1983  buf.fill(0);
1984  if (arguments.length === twoBytes && fill !== undefined && fill !== 0) {
1985    buf.fill(fill);
1986  } else if (arguments.length === 3) { // 3 is array->maxIndex
1987    if (encoding === undefined || encoding === null) {
1988      encoding = 'utf-8';
1989    }
1990    typeErrorCheck(encoding, ['string'], 'encoding');
1991    if (fill !== undefined && fill !== 0) {
1992      buf.fill(fill, undefined, undefined, encoding);
1993    }
1994  }
1995  return buf;
1996}
1997
1998function allocUninitializedFromPool(size: number): Buffer {
1999  sizeErrorCheck(size, 'size', ['number'], 0, MAX_LENGTH);
2000  if (!pool) {
2001    createPool();
2002  }
2003  if (size < (poolSize >>> 1)) {
2004    if (size > (poolSize - poolOffset)) {
2005      createPool();
2006    }
2007    const b = new Buffer(pool, poolOffset, size);
2008    poolOffset += size;
2009    alignPool();
2010    return b;
2011  }
2012  return new Buffer(size);
2013}
2014
2015function allocUninitialized(size: number): Buffer {
2016  sizeErrorCheck(size, 'size', ['number'], 0, MAX_LENGTH);
2017  const buf = new Buffer(size);
2018  return buf;
2019}
2020
2021function normalizeEncoding(enc: string): string | undefined {
2022  enc = enc.toLowerCase();
2023  if (bufferEncoding.includes(enc)) {
2024    if (enc === 'ucs2' || enc === 'ucs-2' || enc === 'utf-16le') {
2025      enc = 'utf16le';
2026    }
2027    if (enc === 'utf-8') {
2028      enc = 'utf8';
2029    }
2030    return enc;
2031  } else {
2032    return undefined;
2033  }
2034}
2035
2036function from(value: Buffer | Uint8Array | ArrayBuffer | SharedArrayBuffer | string | object | Array<number>,
2037  offsetOrEncoding?: number | string, length?: number): Buffer {
2038  if (value === null || value === undefined) {
2039    throw typeError(value, 'value', ['Buffer', 'ArrayBuffer', 'Array', 'Array-like', 'string', 'object']);
2040  }
2041  if (value instanceof ArrayBuffer || value instanceof SharedArrayBuffer) {
2042    return createBufferFromArrayBuffer(value, offsetOrEncoding, length);
2043  }
2044  if (value instanceof Buffer || value instanceof Uint8Array) {
2045    return new Buffer(value);
2046  }
2047  if (value instanceof Array) {
2048    return createBufferFromArray(value);
2049  }
2050  let encoding = checkEncodeing(value, offsetOrEncoding);
2051  if (typeof value === 'string') {
2052    return fromString(value, encoding);
2053  }
2054  if (typeof value === 'object' && value !== null) {
2055    const valueOf = value.valueOf && value.valueOf();
2056    if (valueOf != null && valueOf !== value &&
2057      (typeof valueOf === 'string' || typeof valueOf === 'object')) {
2058      return from(valueOf, offsetOrEncoding, length);
2059    }
2060    if (typeof value[Symbol.toPrimitive] === 'function') {
2061      const primitive = value[Symbol.toPrimitive]('string');
2062      if (typeof primitive === 'string') {
2063        return fromString(primitive, encoding);
2064      }
2065    }
2066  }
2067  throw typeError(value, 'value', ['Buffer', 'ArrayBuffer', 'Array', 'Array-like']);
2068}
2069
2070function checkEncodeing(value: string | object, offsetOrEncoding: string | number | undefined): string {
2071  if (typeof value === 'string' || typeof value[Symbol.toPrimitive] === 'function') {
2072    offsetOrEncoding = offsetOrEncoding ? offsetOrEncoding : 'utf8';
2073    if (typeof offsetOrEncoding === 'number') {
2074      offsetOrEncoding = 'utf8';
2075    }
2076    return encodingTypeErrorCheck(offsetOrEncoding);
2077  }
2078  return '';
2079}
2080
2081function createBufferFromArrayBuffer(value: ArrayBuffer | SharedArrayBuffer,
2082  offsetOrEncoding?: number | string, length?: number): Buffer {
2083  offsetOrEncoding = isNaN(Number(offsetOrEncoding)) ? 0 : Number(offsetOrEncoding);
2084  const maxLength: number = value.byteLength - offsetOrEncoding;
2085  if (length === undefined) {
2086    length = maxLength;
2087  } else {
2088    length = isNaN(Number(length)) ? 0 : Number(length);
2089  }
2090  rangeErrorCheck(offsetOrEncoding, 'byteOffset', 0, value.byteLength);
2091  rangeErrorCheck(length, 'length', 0, maxLength);
2092  return new Buffer(value, offsetOrEncoding, length);
2093}
2094
2095function createBufferFromArray(value: Array<number>): Buffer {
2096  if (value.length <= 0) {
2097    return new Buffer(0);
2098  }
2099  const buffer = allocUninitializedFromPool(value.length);
2100  buffer[bufferSymbol].setArray(value);
2101  return buffer;
2102}
2103
2104function hexStrtoNumbers(hex: string): Array<number> {
2105  let arr = hex.split('');
2106  let nums: Array<number> = [];
2107  for (let i = 0, len = arr.length; i < len / twoBytes; i++) {
2108    let tmp = '0x' + arr[i * twoBytes] + arr[i * twoBytes + 1];
2109    let hexNum = Number(tmp);
2110    if (isNaN(hexNum)) {
2111      if (i === 0) {
2112        throw new Error(`The argument 'value' is invalid. Received "${hex}"`);
2113      }
2114      break;
2115    }
2116    nums[i] = Number(tmp);
2117  }
2118  return nums;
2119}
2120
2121function fromString(value: string, encoding: string): Buffer {
2122  if (encoding === 'base64') {
2123    value = value.replace(/[\r\n]/g, '');
2124  }
2125  let enc = normalizeEncoding(encoding);
2126  if (!enc) {
2127    throw typeErrorForEncoding(encoding, 'encoding');
2128  }
2129  let size = byteLength(value, enc);
2130  let buffer = allocUninitializedFromPool(size);
2131  buffer[bufferSymbol].fromString(value, enc, size);
2132  buffer[lengthSymbol] = buffer[bufferSymbol].getLength();
2133  return buffer;
2134}
2135
2136function isTypedArray(self: unknown): boolean {
2137  let typeArr = [Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array,
2138    Int32Array, Uint32Array, Float32Array, Float64Array];
2139  for (let i = 0, len = typeArr.length; i < len; i++) {
2140    if (self instanceof typeArr[i]) {
2141      return true;
2142    }
2143  }
2144  return false;
2145}
2146
2147function isBuffer(obj: Object): boolean {
2148  return obj instanceof Buffer;
2149}
2150
2151function isEncoding(encoding: string): boolean {
2152  if (typeof encoding !== 'string' || encoding.length === 0) {
2153    return false;
2154  }
2155  return getEncodingByType(encoding) ? true : false;
2156}
2157
2158function byteLength(string: string | BackingType, encoding: string = 'utf8'): number {
2159  if (typeof string === 'string' || isTypedArray(string) || string instanceof DataView ||
2160      string instanceof ArrayBuffer || string instanceof SharedArrayBuffer || string instanceof Buffer) {
2161    if (string instanceof Buffer) {
2162      return string.length;
2163    } else if (typeof string === 'string') {
2164      if (string.length === 0) {
2165        return 0;
2166      }
2167      if (encoding === null) {
2168        encoding = 'utf8';
2169      }
2170      let encodRes = getEncodingByType(encoding);
2171      if (!encodRes) {
2172        return getUtf8ByteLength(string);
2173      }
2174      return encodRes.byteLength(string);
2175    } else {
2176      return string.byteLength;
2177    }
2178  } else {
2179    throw typeError(string, 'string', ['string', 'Buffer', 'ArrayBuffer']);
2180  }
2181}
2182
2183function transcode(source: Buffer | Uint8Array, fromEnc: string, toEnc: string): Buffer {
2184  typeErrorCheck(source, ['Buffer', 'Uint8Array'], 'source');
2185  typeErrorCheck(fromEnc, ['string'], 'fromEnc');
2186  typeErrorCheck(toEnc, ['string'], 'toEnc');
2187  let from = source.toString(fromEnc);
2188  return fromString(from, toEnc);
2189}
2190
2191function toUtf8(self: Buffer, start: number, end: number): string {
2192  return self[bufferSymbol].toUtf8(start, end);
2193}
2194
2195function toAscii(self: Buffer, start: number, end: number): string {
2196  let bufData = self[bufferSymbol].getBufferData();
2197  let val = '';
2198  for (let i = start; i < end; i++) {
2199    val += String.fromCharCode(+bufData[i] & 0x7F); // 0x7F : get the lower 15-bits
2200  }
2201  return val;
2202}
2203
2204function toBinary(self: Buffer, start: number, end: number): string {
2205  let bufData = self[bufferSymbol].getBufferData();
2206  let val = '';
2207  for (let i = start; i < end; i++) {
2208    val += String.fromCharCode(+bufData[i]);
2209  }
2210  return val;
2211}
2212
2213function toHex(self: Buffer, start: number, end: number): string {
2214  let bufData = self[bufferSymbol].getBufferData();
2215  let str = '';
2216  for (let i = start, len = end; i < len; i++) {
2217    let tmpstr = Number(bufData[i]).toString(16); // 16 : 16 decimal
2218    tmpstr = (tmpstr.length === 1) ? `0${tmpstr}` : tmpstr;
2219    str += tmpstr;
2220  }
2221  return str;
2222}
2223
2224function toUtf16LE(self: Buffer, start: number, end: number): string {
2225  let bufData: Array<number> = self[bufferSymbol].getBufferData();
2226  let val = '';
2227  for (let i = start; i + 1 < end; i += 2) { // 2 is array->NextIndex
2228    val += String.fromCodePoint((bufData[i + 1] << eightBytes) + (bufData[i]));
2229  }
2230  return val;
2231}
2232
2233function toBase64(self: Buffer, start: number, end: number): string {
2234  let str = self[bufferSymbol].toBase64(start, end);
2235  return str;
2236}
2237
2238function toBase64Url(self: Buffer, start: number, end: number): string {
2239  let str = self[bufferSymbol].toBase64Url(start, end);
2240  return str;
2241}
2242
2243function getEncodingByType(type: string): {
2244  byteLength: (str: string) => number;
2245  toString: (self: Buffer, start: number, end: number) => string;
2246} | undefined {
2247  type = type.toLowerCase();
2248  switch (type) {
2249    case 'utf8':
2250    case 'utf-8':
2251      return {
2252        byteLength: getUtf8ByteLength,
2253        toString: toUtf8
2254      };
2255    case 'ucs2':
2256    case 'ucs-2':
2257      return {
2258        byteLength: (str: string) => str.length * twoBytes, // 2 : 2 times of ascii
2259        toString: toUtf16LE
2260      };
2261    case 'ascii':
2262      return {
2263        byteLength: (str: string) => str.length,
2264        toString: toAscii
2265      };
2266    case 'binary':
2267    case 'latin1':
2268      return {
2269        byteLength: (str: string) => str.length,
2270        toString: toBinary
2271      };
2272    case 'utf16le':
2273    case 'utf-16le':
2274      return {
2275        byteLength: (str: string) => str.length * twoBytes,
2276        toString: toUtf16LE
2277      };
2278    case 'base64':
2279      return {
2280        byteLength: getBase64ByteLength,
2281        toString: toBase64
2282      };
2283    case 'base64url':
2284      return {
2285        byteLength: getBase64ByteLength,
2286        toString: toBase64Url
2287      };
2288    case 'hex':
2289      return {
2290        byteLength: (str: string) => str.length >>> 1, // 1 : one-half
2291        toString: toHex
2292      };
2293    default:
2294      return undefined;
2295  }
2296}
2297
2298function getUtf8ByteLength(str: string): number {
2299  return internalBuffer.utf8ByteLength(str);
2300}
2301
2302function getBase64ByteLength(str: string): number {
2303  let bytes = str.length;
2304  let pos = 0;
2305  while (bytes > 1 && (pos = str.indexOf('=', pos)) !== -1) { // Find '=' in str and calculate the length of str
2306    bytes--;
2307    pos++;
2308  }
2309  return (bytes * threeBytes) >>> twoBytes;
2310}
2311
2312function compare(buf1: Buffer | Uint8Array, buf2: Buffer | Uint8Array): 1 | 0 | -1 {
2313  if (!(buf1 instanceof Buffer) && !(buf1 instanceof Uint8Array)) {
2314    throw new BusinessError(new ErrorMessage(errorMap.typeError, 'buf1').setTypeInfo(['Buffer', 'Uint8Array'],
2315      getTypeName(buf1)).getString(), errorMap.typeError);
2316  }
2317  if (!(buf2 instanceof Buffer) && !(buf2 instanceof Uint8Array)) {
2318    throw new BusinessError(new ErrorMessage(errorMap.typeError, 'buf2').setTypeInfo(['Buffer', 'Uint8Array'],
2319      getTypeName(buf2)).getString(), errorMap.typeError);
2320  }
2321
2322  let bufData1: Array<number> | Uint8Array;
2323  let bufData2: Array<number> | Uint8Array;
2324  if (buf1 instanceof Buffer) {
2325    bufData1 = buf1[bufferSymbol].getBufferData();
2326  } else {
2327    bufData1 = buf1;
2328  }
2329  if (buf2 instanceof Buffer) {
2330    bufData2 = buf2[bufferSymbol].getBufferData();
2331  } else {
2332    bufData2 = buf2;
2333  }
2334  let length1: number = bufData1.length;
2335  let length2: number = bufData2.length;
2336  let length: number = length1 > length2 ? length2 : length1;
2337  for (let i = 0; i < length; i++) {
2338    let value1 = +bufData1[i];
2339    let value2 = +bufData2[i];
2340    if (value1 > value2) {
2341      return 1;
2342    } else if (value1 < value2) {
2343      return -1;
2344    }
2345  }
2346  if (length1 > length2) {
2347    return 1;
2348  } else if (length1 < length2) {
2349    return -1;
2350  }
2351  return 0;
2352}
2353
2354export default {
2355  Buffer,
2356  Blob,
2357  from,
2358  alloc,
2359  allocUninitializedFromPool,
2360  allocUninitialized,
2361  byteLength,
2362  isBuffer,
2363  isEncoding,
2364  compare,
2365  concat,
2366  transcode
2367};
2368