1/* 2 * Copyright (c) 2025 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 */ 15interface ArkPrivate { 16 FastBuffer: number; 17 Load(key: number): Object; 18} 19let FastBufferInner = undefined; 20let arkPritvate: ArkPrivate = globalThis.ArkPrivate || undefined; 21FastBufferInner = arkPritvate.Load(arkPritvate.FastBuffer); 22 23function getTypeName(obj: unknown): string { 24 if (obj === null) { 25 return 'null'; 26 } 27 if (typeof obj !== 'object') { 28 return typeof obj; 29 } 30 if (obj != null && obj.constructor != null) { 31 return obj.constructor.name; 32 } 33 return 'unknown'; 34} 35 36class BusinessError extends Error { 37 code: number; 38 constructor(message: string, errorNumber: number) { 39 super(message); 40 this.name = 'BusinessError'; 41 this.code = errorNumber; 42 } 43} 44 45const ERROR_CODES = { 46 TYPE_ERROR: 401, // 401: TYPE_ ERROR code value 47 RANGE_ERROR: 10200001, // 10200001: RANGE_ERROR code value 48 BUFFER_SIZE_ERROR: 10200009, // 10200009: BUFFER_SIZE_ERROR code value 49 PROPERTY_TYPE_ERROR: 10200013, // 10200013: TYPE_ ERROR code value 50 ARRAY_BUFFER_IS_NULL_OR_DETACHED: 10200068 // 10200013: TYPE_ ERROR code value 51}; 52 53let errorMap = { 54 'typeError': ERROR_CODES.TYPE_ERROR, 55 'rangeError': ERROR_CODES.RANGE_ERROR, 56 'bufferSizeError': ERROR_CODES.BUFFER_SIZE_ERROR, 57 'typeErrorForProperty': ERROR_CODES.PROPERTY_TYPE_ERROR, 58 'arrayBufferIsDetachedError': ERROR_CODES.ARRAY_BUFFER_IS_NULL_OR_DETACHED 59}; 60 61enum TypeErrorCategories { 62 COMMON = 0, 63 SIZE, 64 ENCODING, 65 PROPERTY 66}; 67enum RangeErrorCategories { 68 WHOLE = 0, 69 LEFT 70}; 71 72const UINT32MAX = 4294967295; 73const INT64_MAX = 2n ** 63n - 1n; 74const UINT64_MAX = 2n ** 64n - 1n; 75 76class ErrorMessage { 77 public errorNumber: number = 0; 78 public argument: string = ''; 79 public types: string[] = []; 80 public receivedObj: unknown = ''; 81 public rangeLeft: string | bigint | number = 0; 82 public rangeRight: string | bigint | number = 0; 83 84 public typeErrorCat: TypeErrorCategories = TypeErrorCategories.COMMON; 85 public rangeErrorCat: RangeErrorCategories = RangeErrorCategories.WHOLE; 86 87 constructor(errNo: number, argument?: string) { 88 this.errorNumber = errNo; 89 this.argument = argument === undefined ? '' : argument; 90 } 91 92 public setTypeInfo(types: string[], receivedObj: unknown): ErrorMessage { 93 this.types = types; 94 this.receivedObj = receivedObj; 95 return this; 96 } 97 98 public setSizeTypeInfo(types: string[], receivedObj: unknown): ErrorMessage { 99 this.types = types; 100 this.receivedObj = receivedObj; 101 this.typeErrorCat = TypeErrorCategories.SIZE; 102 return this; 103 } 104 105 public setEncodingTypeInfo(types: string[], receivedObj: unknown): ErrorMessage { 106 this.types = types; 107 this.receivedObj = receivedObj; 108 this.typeErrorCat = TypeErrorCategories.ENCODING; 109 return this; 110 } 111 112 public setProperty(argument: string): ErrorMessage { 113 this.typeErrorCat = TypeErrorCategories.PROPERTY; 114 this.argument = argument; 115 return this; 116 } 117 118 public setRangeInfo(rangeLeft: string | bigint | number, rangeRight: string | bigint | number, receivedObj: unknown): ErrorMessage { 119 this.rangeLeft = rangeLeft; 120 this.rangeRight = rangeRight; 121 this.receivedObj = receivedObj; 122 return this; 123 } 124 125 public setRangeLeftInfo(rangeLeft: string | number, receivedObj: unknown): ErrorMessage { 126 this.rangeLeft = rangeLeft; 127 this.receivedObj = receivedObj; 128 this.rangeErrorCat = RangeErrorCategories.LEFT; 129 return this; 130 } 131 132 public setSizeInfo(receivedObj: string): ErrorMessage { 133 this.receivedObj = receivedObj; 134 return this; 135 } 136 137 private getErrorTypeStrings(types: string[]): string { 138 let ret = types.join(', '); 139 ret = ret.replace(',', ' or'); 140 return ret; 141 } 142 143 private getArgumentStr(flag: boolean): string { 144 if (flag) { 145 return 'Parameter error. The type of "' + this.argument + '" must be '; 146 } else { 147 return 'The type of "' + this.argument + '" must be '; 148 } 149 } 150 151 private getTypeString(flag: boolean): string { 152 let str = ''; 153 switch (this.typeErrorCat) { 154 case TypeErrorCategories.COMMON: 155 str += this.getArgumentStr(flag) + this.getErrorTypeStrings(this.types) + 156 '. Received value is: ' + getTypeName(this.receivedObj); 157 break; 158 case TypeErrorCategories.SIZE: 159 str += this.getArgumentStr(flag) + this.getErrorTypeStrings(this.types) + 160 ' and the value cannot be negative. Received value is: ' + getTypeName(this.receivedObj); 161 break; 162 case TypeErrorCategories.ENCODING: 163 str += this.getArgumentStr(flag) + this.getErrorTypeStrings(this.types) + 164 '. the encoding ' + this.receivedObj + ' is unknown'; 165 break; 166 case TypeErrorCategories.PROPERTY: 167 str += this.argument + ' cannot be set for the buffer that has only a getter'; 168 default: 169 break; 170 } 171 return str; 172 } 173 174 private getRangeString(): string { 175 let str = ''; 176 switch (this.rangeErrorCat) { 177 case RangeErrorCategories.WHOLE: 178 str += 'The value of "' + this.argument + '" is out of range. It must be >= ' + this.rangeLeft + 179 ' and <= ' + this.rangeRight + '. Received value is: ' + this.receivedObj; 180 break; 181 case RangeErrorCategories.LEFT: 182 str += 'The value of "' + this.argument + '" is out of range. It must be >= ' + this.rangeLeft + 183 '. Received value is: ' + this.receivedObj; 184 break; 185 default: 186 break; 187 } 188 return str; 189 } 190 191 public getString(): string { 192 let str = ''; 193 switch (this.errorNumber) { 194 case ERROR_CODES.TYPE_ERROR: 195 str = this.getTypeString(true); 196 break; 197 case ERROR_CODES.PROPERTY_TYPE_ERROR: 198 str = this.getTypeString(false); 199 break; 200 case ERROR_CODES.RANGE_ERROR: 201 str = this.getRangeString(); 202 break; 203 case ERROR_CODES.BUFFER_SIZE_ERROR: 204 str = 'The buffer size must be a multiple of ' + this.receivedObj; 205 break; 206 default: 207 break; 208 } 209 return str; 210 } 211} 212 213const initialPoolSize: number = 8 * 1024; // 8 * 1024 : initialPoolSize number 214let poolSize: number; 215let poolOffset: number; 216let pool: FastBuffer; 217const oneByte: number = 1; // 1 : one Byte 218const twoBytes: number = 2; // 2 : two Bytes 219const threeBytes: number = 3; // 3 : three Bytes 220const fourBytes: number = 4; // 4 : four Bytes 221const fiveBytes: number = 5; // 5 : five Bytes 222const sixBytes: number = 6; // 6 : six Bytes 223const sevenBytes: number = 7; // 7 : seven Bytes 224const eightBytes: number = 8; // 8 : eight Bytes 225 226type TypedArray = Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array | 227Int32Array | Uint32Array | Float32Array | Float64Array; 228type BackingType = FastBuffer | TypedArray | DataView | ArrayBuffer | SharedArrayBuffer; 229 230const bufferEncoding = ['ascii', 'utf8', 'utf-8', 'utf16le', 'utf-16le', 'ucs2', 'ucs-2', 231 'base64', 'base64url', 'latin1', 'binary', 'hex']; 232 233interface FastBuffer { 234 length: number; 235 buffer: ArrayBuffer; 236 byteOffset: number; 237 fill(value: string | FastBuffer | Uint8Array | number, offset?: number, end?: number, encoding?: string): FastBuffer; 238 compare(target: FastBuffer | Uint8Array, targetStart?: number, targetEnd?: number, sourceStart?: number, sourceEnd?: number): -1 | 0 | 1; 239 copy(target: FastBuffer | Uint8Array, targetStart?: number, sourceStart?: number, sourceEnd?: number): number; 240 equals(otherBuffer: Uint8Array | FastBuffer): boolean; 241 includes(value: string | number | FastBuffer | Uint8Array, byteOffset?: number, encoding?: string): boolean; 242 indexOf(value: string | number | FastBuffer | Uint8Array, byteOffset?: number, encoding?: string): number; 243 keys(): IterableIterator<number>; 244 values(): IterableIterator<number>; 245 entries(): IterableIterator<[ 246 number, 247 number 248 ]>; 249 lastIndexOf(value: string | number | FastBuffer | Uint8Array, byteOffset?: number, encoding?: string): number; 250 readBigInt64BE(offset?: number): bigint; 251 readBigInt64LE(offset?: number): bigint; 252 readBigUInt64BE(offset?: number): bigint; 253 readBigUInt64LE(offset?: number): bigint; 254 readDoubleBE(offset?: number): number; 255 readDoubleLE(offset?: number): number; 256 readFloatBE(offset?: number): number; 257 readFloatLE(offset?: number): number; 258 readInt8(offset?: number): number; 259 readInt16BE(offset?: number): number; 260 readInt16LE(offset?: number): number; 261 readInt32BE(offset?: number): number; 262 readInt32LE(offset?: number): number; 263 readIntBE(offset: number, byteLength: number): number; 264 readIntLE(offset: number, byteLength: number): number; 265 readUInt8(offset?: number): number; 266 readUInt16BE(offset?: number): number; 267 readUInt16LE(offset?: number): number; 268 readUInt32BE(offset?: number): number; 269 readUInt32LE(offset?: number): number; 270 readUIntBE(offset: number, byteLength: number): number; 271 readUIntLE(offset: number, byteLength: number): number; 272 subarray(start?: number, end?: number): FastBuffer; 273 swap16(): FastBuffer; 274 swap32(): FastBuffer; 275 swap64(): FastBuffer; 276 toJSON(): Object; 277 toString(encoding?: string, start?: number, end?: number): string; 278 write(str: string, offset?: number, length?: number, encoding?: string): number; 279 writeBigInt64BE(value: bigint, offset?: number): number; 280 writeBigInt64LE(value: bigint, offset?: number): number; 281 writeBigUInt64BE(value: bigint, offset?: number): number; 282 writeBigUInt64LE(value: bigint, offset?: number): number; 283 writeDoubleBE(value: number, offset?: number): number; 284 writeDoubleLE(value: number, offset?: number): number; 285 writeFloatBE(value: number, offset?: number): number; 286 writeFloatLE(value: number, offset?: number): number; 287 writeInt8(value: number, offset?: number): number; 288 writeInt16BE(value: number, offset?: number): number; 289 writeInt16LE(value: number, offset?: number): number; 290 writeInt32BE(value: number, offset?: number): number; 291 writeInt32LE(value: number, offset?: number): number; 292 writeIntBE(value: number, offset: number, byteLength: number): number; 293 writeIntLE(value: number, offset: number, byteLength: number): number; 294 writeUInt8(value: number, offset?: number): number; 295 writeUInt16BE(value: number, offset?: number): number; 296 writeUInt16LE(value: number, offset?: number): number; 297 writeUInt32BE(value: number, offset?: number): number; 298 writeUInt32LE(value: number, offset?: number): number; 299 writeUIntBE(value: number, offset: number, byteLength: number): number; 300 writeUIntLE(value: number, offset: number, byteLength: number): number; 301} 302 303class FastBuffer extends FastBufferInner { 304 constructor(value: number | FastBuffer | Uint8Array | ArrayBuffer | SharedArrayBuffer | Array<number> | string, 305 byteOffsetOrEncoding?: number | string, length?: number) { 306 super(value, byteOffsetOrEncoding, length); 307 } 308 309 toString(encoding: string = 'utf8', start: number = 0, end: number = this.length): string { 310 if (!encoding) { 311 encoding = 'utf8'; 312 } 313 let enc = encoding.toLowerCase(); 314 start = isNaN(start) ? 0 : (Number(start) < 0 ? 0 : Number(start)); 315 end = isNaN(end) ? 0 : Number(end); 316 if (start >= this.length || start > end) { 317 return ''; 318 } 319 return super.toString(enc, start, end); 320 } 321 322 indexOf(value: string | number | FastBuffer | Uint8Array, byteOffset: number = 0, encoding: string = 'utf8'): number { 323 if (typeof byteOffset === 'string') { 324 encoding = byteOffset; 325 } 326 if (typeof byteOffset !== 'number') { 327 byteOffset = 0; 328 } 329 if (!encoding) { 330 encoding = 'utf8'; 331 } 332 encoding = encoding.toLowerCase(); 333 return super.indexOf(value, byteOffset, encoding); 334 } 335 336 lastIndexOf(value: string | number | FastBuffer | Uint8Array, byteOffset: number = this.length, 337 encoding: string = 'utf8'): number { 338 if (typeof byteOffset === 'string') { 339 encoding = byteOffset; 340 } 341 if (typeof byteOffset !== 'number') { 342 byteOffset = 0; 343 } 344 if (!encoding) { 345 encoding = 'utf8'; 346 } 347 encoding = encoding.toLowerCase(); 348 return super.lastIndexOf(value, byteOffset, encoding); 349 } 350 351 copy(target: FastBuffer | Uint8Array, targetStart: number = 0, sourceStart: number = 0, 352 sourceEnd: number = this.length): number { 353 targetStart = isNaN(targetStart) ? 0 : Number(targetStart); 354 sourceStart = isNaN(sourceStart) ? 0 : Number(sourceStart); 355 sourceEnd = isNaN(sourceEnd) ? this.length : Number(sourceEnd); 356 return super.copy(target, targetStart, sourceStart, sourceEnd); 357 } 358 359 fill(value: string | FastBuffer | Uint8Array | number, offset: number = 0, end: number = this.length, 360 encoding: string = 'utf8'): FastBuffer { 361 return super.fill(value, offset, end, encoding); 362 } 363 364 compare(target: FastBuffer | Uint8Array, targetStart: number = 0, targetEnd: number = target.length, 365 sourceStart: number = 0, sourceEnd: number = this.length): 0 | 1 | -1 { 366 if (targetStart === null) { 367 targetStart = 0; 368 } 369 if (targetEnd === null) { 370 targetEnd = target.length; 371 } 372 if (sourceStart === null) { 373 sourceStart = 0; 374 } 375 if (sourceEnd === null) { 376 sourceEnd = this.length; 377 } 378 typeErrorCheck(target, ['FastBuffer', 'Uint8Array'], 'target'); 379 return super.compare(target, targetStart, targetEnd, sourceStart, sourceEnd); 380 } 381 382 toJSON(): Object { 383 if (this.length <= 0) { 384 return { type: 'FastBuffer', data: [] }; 385 } 386 let data = new Array<number>; 387 let len = this.length; 388 for (let i = 0; i < len; i++) { 389 data.push(this[i]); 390 } 391 return { type: 'FastBuffer', data: data }; 392 } 393 394 subarray(start: number = 0, end: number = this.length): FastBuffer { 395 let newBuf: FastBuffer = new FastBuffer(0); 396 start = isNaN(start) ? 0 : Number(start); 397 end = isNaN(end) ? 0 : Number(end); 398 end = (end > this.length) ? this.length : end; 399 if (start < 0 || end < 0 || end <= start) { 400 return newBuf; 401 } 402 return new FastBuffer(this.buffer, start, end - start); 403 } 404 405 writeBigInt64BE(value: bigint, offset: number = 0): number { 406 if (typeof value !== 'bigint') { 407 throw typeError(value, 'value', ['bigint']); 408 } 409 rangeErrorCheck(value, 'value', -INT64_MAX, INT64_MAX); 410 return super.writeBigInt64BE(value, offset); 411 } 412 413 writeBigInt64LE(value: bigint, offset: number = 0): number { 414 if (typeof value !== 'bigint') { 415 throw typeError(value, 'value', ['bigint']); 416 } 417 rangeErrorCheck(value, 'value', -INT64_MAX, INT64_MAX); 418 return super.writeBigInt64LE(value, offset); 419 } 420 421 writeBigUInt64BE(value: bigint, offset: number = 0): number { 422 if (typeof value !== 'bigint') { 423 throw typeError(value, 'value', ['bigint']); 424 } 425 rangeErrorCheck(value, 'value', 0, UINT64_MAX); 426 return super.writeBigUInt64BE(value, offset); 427 } 428 429 writeBigUInt64LE(value: bigint, offset: number = 0): number { 430 if (typeof value !== 'bigint') { 431 throw typeError(value, 'value', ['bigint']); 432 } 433 rangeErrorCheck(value, 'value', 0, UINT64_MAX); 434 return super.writeBigUInt64LE(value, offset); 435 } 436 437 swap16(): FastBuffer { 438 const len = this.length; 439 const dealLen: number = twoBytes; 440 if (len % dealLen !== 0) { 441 throw bufferSizeError('16-bits'); 442 } 443 return this.reverseBits(dealLen); 444 } 445 446 swap32(): FastBuffer { 447 const len = this.length; 448 const dealLen: number = 4; // Process every 4 bits 449 if (len % dealLen !== 0) { 450 throw bufferSizeError('32-bits'); 451 } 452 return this.reverseBits(dealLen); 453 } 454 455 swap64(): FastBuffer { 456 const len = this.length; 457 const dealLen: number = eightBytes; 458 if (len % dealLen !== 0) { 459 throw bufferSizeError('64-bits'); 460 } 461 return this.reverseBits(dealLen); 462 } 463 464 reverseBits(dealNum: number): FastBuffer { 465 const len: number = this.length; 466 const dealLen: number = dealNum; 467 for (let i = 0; i < len / dealLen; i++) { 468 let times: number = 0; 469 let startIndex: number = dealLen * i; 470 let endIndex: number = startIndex + dealLen - 1; 471 while (times < dealLen / twoBytes) { 472 let tmp = this[startIndex + times]; 473 this[startIndex + times] = this[endIndex - times]; 474 this[endIndex - times] = tmp; 475 times++; 476 } 477 } 478 return this; 479 } 480 481 [Symbol.iterator](): IterableIterator<[number, number]> { 482 return this.entries(); 483 } 484} 485 486function createBufferFromArrayBuffer(value: ArrayBuffer | SharedArrayBuffer, 487 offsetOrEncoding?: number | string, length?: number): FastBuffer { 488 offsetOrEncoding = isNaN(Number(offsetOrEncoding)) ? 0 : Number(offsetOrEncoding); 489 let valueLength = 0; 490 try { 491 valueLength = value.byteLength; 492 } catch(e) { 493 throw new BusinessError('The underlying ArrayBuffer is null or detached.', errorMap.arrayBufferIsDetachedError); 494 } 495 const maxLength: number = valueLength - offsetOrEncoding; 496 if (length === undefined) { 497 length = maxLength; 498 } else { 499 length = isNaN(Number(length)) ? 0 : Number(length); 500 } 501 rangeErrorCheck(offsetOrEncoding, 'byteOffset', 0, valueLength); 502 rangeErrorCheck(length, 'length', 0, maxLength); 503 return new FastBuffer(value, offsetOrEncoding, length); 504} 505 506function from(value: FastBuffer | Uint8Array | ArrayBuffer | SharedArrayBuffer | string | object | Array<number>, 507 offsetOrEncoding?: number | string, length?: number): FastBuffer { 508 if (typeof value === 'string') { 509 if (!offsetOrEncoding || typeof offsetOrEncoding === 'number') { 510 offsetOrEncoding = 'utf8'; 511 } 512 return fromString(value, offsetOrEncoding); 513 } 514 if (value instanceof FastBuffer || value instanceof Uint8Array || value instanceof Array) { 515 return new FastBuffer(value); 516 } 517 if (value instanceof ArrayBuffer || value instanceof SharedArrayBuffer) { 518 return createBufferFromArrayBuffer(value, offsetOrEncoding, length); 519 } 520 if (typeof value === 'object' && value !== null) { 521 const valueOf = value.valueOf && value.valueOf(); 522 if (valueOf != null && valueOf !== value && 523 (typeof valueOf === 'string' || typeof valueOf === 'object')) { 524 return from(valueOf, offsetOrEncoding, length); 525 } 526 if (typeof value[Symbol.toPrimitive] === 'function') { 527 const primitive = value[Symbol.toPrimitive]('string'); 528 if (typeof primitive === 'string' && typeof offsetOrEncoding === 'string') { 529 return fromString(primitive, offsetOrEncoding); 530 } 531 } 532 } 533 throw typeError(value, 'value', ['FastBuffer', 'ArrayBuffer', 'Array', 'Array-like', 'string', 'object']); 534} 535 536function alloc(size: number, fill?: string | FastBuffer | number, encoding?: string): FastBuffer { 537 if (size < 0 || size > UINT32MAX) { 538 let msg = 'Parameter error. The type of "size" must be ' + 'number' + 539 ' and the value cannot be negative. Received value is: ' + Number(size).toString(); 540 throw new BusinessError(msg, errorMap.typeError); 541 } 542 const buf = new FastBuffer(size); 543 if (arguments.length === twoBytes && fill !== undefined && fill !== 0) { 544 buf.fill(fill); 545 return buf; 546 } else if (arguments.length === 3) { // 3 is array->maxIndex 547 if (!encoding) { 548 encoding = 'utf-8'; 549 } 550 buf.fill(fill, 0, buf.length, encoding); 551 return buf; 552 } 553 buf.fill(0); 554 return buf; 555} 556 557function allocUninitialized(size: number): FastBuffer { 558 if (size < 0 || size > UINT32MAX) { 559 let msg = 'Parameter error. The type of "size" must be ' + 'number' + 560 ' and the value cannot be negative. Received value is: ' + Number(size).toString(); 561 throw new BusinessError(msg, errorMap.typeError); 562 } 563 const buf = new FastBuffer(size); 564 return buf; 565} 566 567function bufferSizeError(size: string): BusinessError { 568 let msg = new ErrorMessage(errorMap.bufferSizeError).setSizeInfo(size).getString(); 569 return new BusinessError(msg, errorMap.bufferSizeError); 570} 571 572function typeError(param: unknown, paramName: string, excludedTypes: string[]): BusinessError { 573 let msg = new ErrorMessage(errorMap.typeError, paramName).setTypeInfo(excludedTypes, param).getString(); 574 return new BusinessError(msg, errorMap.typeError); 575} 576 577function rangeErrorCheck(param: number | bigint, paramName: string, 578 rangeLeft: number | bigint, rangeRight: number | bigint): void { 579 if (param < rangeLeft || param > rangeRight) { 580 throw rangeError(paramName, rangeLeft, rangeRight, param); 581 } 582} 583 584function rangeError(paramName: string, rangeLeft: string | bigint | number, rangeRight: string | bigint | number, 585 receivedValue: number | bigint): BusinessError { 586 let msg = 587 new ErrorMessage(errorMap.rangeError, paramName).setRangeInfo(rangeLeft, rangeRight, receivedValue).getString(); 588 return new BusinessError(msg, errorMap.rangeError); 589} 590 591function fromString(value: string, encoding: string): FastBuffer { 592 let enc = encoding.toLowerCase(); 593 return new FastBuffer(value, enc); 594} 595 596function createPool(): void { 597 poolSize = initialPoolSize; 598 pool = new FastBuffer(poolSize); 599 poolOffset = 0; 600} 601 602function alignPool(): void { 603 if (poolOffset & 0x7) { 604 poolOffset |= 0x7; // 0x7 : align offset based of 8-bits 605 poolOffset++; 606 } 607} 608 609function allocUninitializedFromPool(size: number): FastBuffer { 610 if (size < 0 || size > UINT32MAX) { 611 let msg = 'Parameter error. The type of "size" must be ' + 'number' + 612 ' and the value cannot be negative. Received value is: ' + Number(size).toString(); 613 throw new BusinessError(msg, errorMap.typeError); 614 } 615 return new FastBuffer(size); 616} 617 618function getBase64ByteLength(str: string): number { 619 let bytes = str.length; 620 let pos = 0; 621 while (bytes > 1 && (pos = str.indexOf('=', pos)) !== -1) { // Find '=' in str and calculate the length of str 622 bytes--; 623 pos++; 624 } 625 return (bytes * threeBytes) >>> twoBytes; 626} 627 628function getUtf8ByteLength(str: string): number { 629 let byteLength = 0; 630 for (let i = 0; i < str.length; i++) { 631 const code = str.charCodeAt(i); 632 if (code >= 0xD800 && code <= 0xDBFF) { 633 const nextCode = str.charCodeAt(i + 1); 634 if (nextCode >= 0xDC00 && nextCode <= 0xDFFF) { 635 byteLength += 4; 636 i++; 637 continue; 638 } 639 } 640 if (code <= 0x7F) { 641 byteLength += 1; 642 } else if (code <= 0x7FF) { 643 byteLength += 2; 644 } else if (code <= 0xFFFF) { 645 byteLength += 3; 646 } 647 } 648 return byteLength; 649} 650 651function getEncodingByteLength(str: string, type: string): number { 652 type = type.toLowerCase(); 653 switch (type) { 654 case 'utf8': 655 case 'utf-8': 656 return getUtf8ByteLength(str); 657 case 'ucs2': 658 case 'ucs-2': 659 return str.length * twoBytes; 660 case 'ascii': 661 return str.length; 662 case 'binary': 663 case 'latin1': 664 return str.length; 665 case 'utf16le': 666 case 'utf-16le': 667 return str.length * twoBytes; 668 case 'base64': 669 case 'base64url': 670 return getBase64ByteLength(str); 671 case 'hex': 672 return str.length >>> 1; // 1 : one-half 673 default: 674 return undefined; 675 } 676} 677 678function isTypedArray(self: unknown): boolean { 679 let typeArr = [Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, 680 Int32Array, Uint32Array, Float32Array, Float64Array]; 681 for (let i = 0, len = typeArr.length; i < len; i++) { 682 if (self instanceof typeArr[i]) { 683 return true; 684 } 685 } 686 return false; 687} 688 689function byteLength(string: string | BackingType, encoding: string = 'utf8'): number { 690 if (string instanceof FastBuffer) { 691 return string.length; 692 } else if (typeof string === 'string') { 693 if (string.length === 0) { 694 return 0; 695 } 696 if (!encoding) { 697 encoding = 'utf8'; 698 } 699 return getEncodingByteLength(string, encoding); 700 } else { 701 if (isTypedArray(string) || string instanceof DataView || 702 string instanceof ArrayBuffer || string instanceof SharedArrayBuffer) { 703 return string.byteLength; 704 } 705 throw typeError(string, 'string', ['string', 'FastBuffer', 'ArrayBuffer']); 706 } 707} 708 709 710function isBuffer(obj: Object): boolean { 711 return obj instanceof FastBuffer; 712} 713 714function isEncoding(enc: string): boolean { 715 if (!enc) { 716 return false; 717 } 718 enc = enc.toLowerCase(); 719 if (bufferEncoding.includes(enc)) { 720 return true; 721 } 722 return false; 723} 724 725function transcode(source: FastBuffer | Uint8Array, fromEnc: string, toEnc: string): FastBuffer { 726 typeErrorCheck(source, ['FastBuffer', 'Uint8Array'], 'source'); 727 typeErrorCheck(fromEnc, ['string'], 'fromEnc'); 728 typeErrorCheck(toEnc, ['string'], 'toEnc'); 729 let from = source.toString(fromEnc); 730 return fromString(from, toEnc); 731} 732 733function compare(buf1: FastBuffer | Uint8Array, buf2: FastBuffer | Uint8Array): 1 | 0 | -1 { 734 if (!(buf1 instanceof FastBuffer) && !(buf1 instanceof Uint8Array)) { 735 throw new BusinessError(new ErrorMessage(errorMap.typeError, 'buf1').setTypeInfo(['FastBuffer', 'Uint8Array'], 736 getTypeName(buf1)).getString(), errorMap.typeError); 737 } 738 if (!(buf2 instanceof FastBuffer) && !(buf2 instanceof Uint8Array)) { 739 throw new BusinessError(new ErrorMessage(errorMap.typeError, 'buf2').setTypeInfo(['FastBuffer', 'Uint8Array'], 740 getTypeName(buf2)).getString(), errorMap.typeError); 741 } 742 743 let tempBuf: FastBuffer; 744 if (buf1 instanceof FastBuffer) { 745 return buf1.compare(buf2, 0, buf2.length, 0, buf1.length); 746 } else { 747 tempBuf = new FastBuffer(buf1); 748 return tempBuf.compare(buf2, 0, buf2.length, 0, tempBuf.length); 749 } 750} 751 752function typeErrorCheck(param: unknown, types: string[], paramName: string): void { 753 let typeName = getTypeName(param); 754 if (!types.includes(typeName)) { 755 throw typeError(param, paramName, types); 756 } 757} 758 759function concat(list: FastBuffer[] | Uint8Array[], totalLength?: number): FastBuffer { 760 typeErrorCheck(list, ['Array'], 'list'); 761 if (!(typeof totalLength === 'number' || typeof totalLength === 'undefined' || 'null')) { 762 throw typeError(totalLength, 'totalLength', ['number']); 763 } 764 if (list.length === 0) { 765 return new FastBuffer(0); 766 } 767 if (!totalLength) { 768 totalLength = 0; 769 for (let i = 0, len = list.length; i < len; i++) { 770 let buf = list[i]; 771 if (buf instanceof Uint8Array || buf instanceof FastBuffer) { 772 totalLength += list[i].length; 773 } 774 } 775 } 776 777 rangeErrorCheck(totalLength, 'totalLength', 0, UINT32MAX); 778 779 let buffer = allocUninitializedFromPool(totalLength); 780 let offset = 0; 781 for (let i = 0, len = list.length; i < len; i++) { 782 const buf = list[i]; 783 if (buf instanceof Uint8Array) { 784 buf.forEach((val) => buffer[offset++] = val); 785 } else if (buf instanceof FastBuffer) { 786 buf.copy(buffer, offset); 787 offset += buf.length; 788 } 789 } 790 return buffer; 791} 792 793export default { 794 FastBuffer, 795 from, 796 alloc, 797 allocUninitializedFromPool, 798 allocUninitialized, 799 byteLength, 800 isBuffer, 801 isEncoding, 802 compare, 803 concat, 804 transcode 805}; 806