| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644 |
- export class ByteStream {
- constructor(parameters = {}) {
- if ("view" in parameters) {
- this.fromUint8Array(parameters.view);
- }
- else if ("buffer" in parameters) {
- this.fromArrayBuffer(parameters.buffer);
- }
- else if ("string" in parameters) {
- this.fromString(parameters.string);
- }
- else if ("hexstring" in parameters) {
- this.fromHexString(parameters.hexstring);
- }
- else {
- if ("length" in parameters && parameters.length > 0) {
- this.length = parameters.length;
- if (parameters.stub) {
- for (let i = 0; i < this._view.length; i++) {
- this._view[i] = parameters.stub;
- }
- }
- }
- else {
- this.length = 0;
- }
- }
- }
- set buffer(value) {
- this._buffer = value;
- this._view = new Uint8Array(this._buffer);
- }
- get buffer() {
- return this._buffer;
- }
- set view(value) {
- this._buffer = new ArrayBuffer(value.length);
- this._view = new Uint8Array(this._buffer);
- this._view.set(value);
- }
- get view() {
- return this._view;
- }
- get length() {
- return this.view.byteLength;
- }
- set length(value) {
- this._buffer = new ArrayBuffer(value);
- this._view = new Uint8Array(this._buffer);
- }
- clear() {
- this._buffer = new ArrayBuffer(0);
- this._view = new Uint8Array(this._buffer);
- }
- fromArrayBuffer(array) {
- this._buffer = array;
- this._view = new Uint8Array(this._buffer);
- }
- fromUint8Array(array) {
- this.fromArrayBuffer(new Uint8Array(array).buffer);
- }
- fromString(string) {
- const stringLength = string.length;
- this.length = stringLength;
- for (let i = 0; i < stringLength; i++)
- this.view[i] = string.charCodeAt(i);
- }
- toString(start = 0, length = (this.view.length - start)) {
- let result = "";
- if ((start >= this.view.length) || (start < 0)) {
- start = 0;
- }
- if ((length >= this.view.length) || (length < 0)) {
- length = this.view.length - start;
- }
- for (let i = start; i < (start + length); i++)
- result += String.fromCharCode(this.view[i]);
- return result;
- }
- fromHexString(hexString) {
- const stringLength = hexString.length;
- this.buffer = new ArrayBuffer(stringLength >> 1);
- this.view = new Uint8Array(this.buffer);
- const hexMap = new Map();
- hexMap.set("0", 0x00);
- hexMap.set("1", 0x01);
- hexMap.set("2", 0x02);
- hexMap.set("3", 0x03);
- hexMap.set("4", 0x04);
- hexMap.set("5", 0x05);
- hexMap.set("6", 0x06);
- hexMap.set("7", 0x07);
- hexMap.set("8", 0x08);
- hexMap.set("9", 0x09);
- hexMap.set("A", 0x0A);
- hexMap.set("a", 0x0A);
- hexMap.set("B", 0x0B);
- hexMap.set("b", 0x0B);
- hexMap.set("C", 0x0C);
- hexMap.set("c", 0x0C);
- hexMap.set("D", 0x0D);
- hexMap.set("d", 0x0D);
- hexMap.set("E", 0x0E);
- hexMap.set("e", 0x0E);
- hexMap.set("F", 0x0F);
- hexMap.set("f", 0x0F);
- let j = 0;
- let temp = 0x00;
- for (let i = 0; i < stringLength; i++) {
- if (!(i % 2)) {
- temp = hexMap.get(hexString.charAt(i)) << 4;
- }
- else {
- temp |= hexMap.get(hexString.charAt(i));
- this.view[j] = temp;
- j++;
- }
- }
- }
- toHexString(start = 0, length = (this.view.length - start)) {
- let result = "";
- if ((start >= this.view.length) || (start < 0)) {
- start = 0;
- }
- if ((length >= this.view.length) || (length < 0)) {
- length = this.view.length - start;
- }
- for (let i = start; i < (start + length); i++) {
- const str = this.view[i].toString(16).toUpperCase();
- result = result + ((str.length == 1) ? "0" : "") + str;
- }
- return result;
- }
- copy(start = 0, length = (this.length - start)) {
- if (!start && !this.length) {
- return new ByteStream();
- }
- if ((start < 0) || (start > (this.length - 1))) {
- throw new Error(`Wrong start position: ${start}`);
- }
- const stream = new ByteStream({
- buffer: this._buffer.slice(start, start + length)
- });
- return stream;
- }
- slice(start = 0, end = this.length) {
- if (!start && !this.length) {
- return new ByteStream();
- }
- if ((start < 0) || (start > (this.length - 1))) {
- throw new Error(`Wrong start position: ${start}`);
- }
- const stream = new ByteStream({
- buffer: this._buffer.slice(start, end),
- });
- return stream;
- }
- realloc(size) {
- const buffer = new ArrayBuffer(size);
- const view = new Uint8Array(buffer);
- if (size > this._view.length)
- view.set(this._view);
- else {
- view.set(new Uint8Array(this._buffer, 0, size));
- }
- this._buffer = buffer;
- this._view = new Uint8Array(this._buffer);
- }
- append(stream) {
- const initialSize = this.length;
- const streamViewLength = stream.length;
- const subarrayView = stream._view.subarray();
- this.realloc(initialSize + streamViewLength);
- this._view.set(subarrayView, initialSize);
- }
- insert(stream, start = 0, length = (this.length - start)) {
- if (start > (this.length - 1))
- return false;
- if (length > (this.length - start)) {
- length = this.length - start;
- }
- if (length > stream.length) {
- length = stream.length;
- }
- if (length == stream.length)
- this._view.set(stream._view, start);
- else {
- this._view.set(stream._view.subarray(0, length), start);
- }
- return true;
- }
- isEqual(stream) {
- if (this.length != stream.length)
- return false;
- for (let i = 0; i < stream.length; i++) {
- if (this.view[i] != stream.view[i])
- return false;
- }
- return true;
- }
- isEqualView(view) {
- if (view.length != this.view.length)
- return false;
- for (let i = 0; i < view.length; i++) {
- if (this.view[i] != view[i])
- return false;
- }
- return true;
- }
- findPattern(pattern, start_, length_, backward_) {
- const { start, length, backward } = this.prepareFindParameters(start_, length_, backward_);
- const patternLength = pattern.length;
- if (patternLength > length) {
- return (-1);
- }
- const patternArray = [];
- for (let i = 0; i < patternLength; i++)
- patternArray.push(pattern.view[i]);
- for (let i = 0; i <= (length - patternLength); i++) {
- let equal = true;
- const equalStart = (backward) ? (start - patternLength - i) : (start + i);
- for (let j = 0; j < patternLength; j++) {
- if (this.view[j + equalStart] != patternArray[j]) {
- equal = false;
- break;
- }
- }
- if (equal) {
- return (backward) ? (start - patternLength - i) : (start + patternLength + i);
- }
- }
- return (-1);
- }
- findFirstIn(patterns, start_, length_, backward_) {
- const { start, length, backward } = this.prepareFindParameters(start_, length_, backward_);
- const result = {
- id: (-1),
- position: (backward) ? 0 : (start + length),
- length: 0
- };
- for (let i = 0; i < patterns.length; i++) {
- const position = this.findPattern(patterns[i], start, length, backward);
- if (position != (-1)) {
- let valid = false;
- const patternLength = patterns[i].length;
- if (backward) {
- if ((position - patternLength) >= (result.position - result.length))
- valid = true;
- }
- else {
- if ((position - patternLength) <= (result.position - result.length))
- valid = true;
- }
- if (valid) {
- result.position = position;
- result.id = i;
- result.length = patternLength;
- }
- }
- }
- return result;
- }
- findAllIn(patterns, start_, length_) {
- let { start, length } = this.prepareFindParameters(start_, length_);
- const result = [];
- let patternFound = {
- id: (-1),
- position: start
- };
- do {
- const position = patternFound.position;
- patternFound = this.findFirstIn(patterns, patternFound.position, length);
- if (patternFound.id == (-1)) {
- break;
- }
- length -= (patternFound.position - position);
- result.push({
- id: patternFound.id,
- position: patternFound.position
- });
- } while (true);
- return result;
- }
- findAllPatternIn(pattern, start_, length_) {
- const { start, length } = this.prepareFindParameters(start_, length_);
- const result = [];
- const patternLength = pattern.length;
- if (patternLength > length) {
- return (-1);
- }
- const patternArray = Array.from(pattern.view);
- for (let i = 0; i <= (length - patternLength); i++) {
- let equal = true;
- const equalStart = start + i;
- for (let j = 0; j < patternLength; j++) {
- if (this.view[j + equalStart] != patternArray[j]) {
- equal = false;
- break;
- }
- }
- if (equal) {
- result.push(start + patternLength + i);
- i += (patternLength - 1);
- }
- }
- return result;
- }
- findFirstNotIn(patterns, start_, length_, backward_) {
- let { start, length, backward } = this.prepareFindParameters(start_, length_, backward_);
- const result = {
- left: {
- id: (-1),
- position: start
- },
- right: {
- id: (-1),
- position: 0
- },
- value: new ByteStream()
- };
- let currentLength = length;
- while (currentLength > 0) {
- result.right = this.findFirstIn(patterns, (backward) ? (start - length + currentLength) : (start + length - currentLength), currentLength, backward);
- if (result.right.id == (-1)) {
- length = currentLength;
- if (backward) {
- start -= length;
- }
- else {
- start = result.left.position;
- }
- result.value = new ByteStream({
- buffer: this._buffer.slice(start, start + length),
- });
- break;
- }
- if (result.right.position != ((backward) ? (result.left.position - patterns[result.right.id].length) : (result.left.position + patterns[result.right.id].length))) {
- if (backward) {
- start = result.right.position + patterns[result.right.id].length;
- length = result.left.position - result.right.position - patterns[result.right.id].length;
- }
- else {
- start = result.left.position;
- length = result.right.position - result.left.position - patterns[result.right.id].length;
- }
- result.value = new ByteStream({
- buffer: this._buffer.slice(start, start + length),
- });
- break;
- }
- result.left = result.right;
- currentLength -= patterns[result.right.id].length;
- }
- if (backward) {
- const temp = result.right;
- result.right = result.left;
- result.left = temp;
- }
- return result;
- }
- findAllNotIn(patterns, start_, length_) {
- let { start, length } = this.prepareFindParameters(start_, length_);
- const result = [];
- let patternFound = {
- left: {
- id: (-1),
- position: start
- },
- right: {
- id: (-1),
- position: start
- },
- value: new ByteStream()
- };
- do {
- const position = patternFound.right.position;
- patternFound = this.findFirstNotIn(patterns, patternFound.right.position, length);
- length -= (patternFound.right.position - position);
- result.push({
- left: {
- id: patternFound.left.id,
- position: patternFound.left.position
- },
- right: {
- id: patternFound.right.id,
- position: patternFound.right.position
- },
- value: patternFound.value
- });
- } while (patternFound.right.id != (-1));
- return result;
- }
- findFirstSequence(patterns, start_, length_, backward_) {
- let { start, length, backward } = this.prepareFindParameters(start_, length_, backward_);
- const firstIn = this.skipNotPatterns(patterns, start, length, backward);
- if (firstIn == (-1)) {
- return {
- position: (-1),
- value: new ByteStream()
- };
- }
- const firstNotIn = this.skipPatterns(patterns, firstIn, length - ((backward) ? (start - firstIn) : (firstIn - start)), backward);
- if (backward) {
- start = firstNotIn;
- length = (firstIn - firstNotIn);
- }
- else {
- start = firstIn;
- length = (firstNotIn - firstIn);
- }
- const value = new ByteStream({
- buffer: this._buffer.slice(start, start + length),
- });
- return {
- position: firstNotIn,
- value
- };
- }
- findAllSequences(patterns, start_, length_) {
- let { start, length } = this.prepareFindParameters(start_, length_);
- const result = [];
- let patternFound = {
- position: start,
- value: new ByteStream()
- };
- do {
- const position = patternFound.position;
- patternFound = this.findFirstSequence(patterns, patternFound.position, length);
- if (patternFound.position != (-1)) {
- length -= (patternFound.position - position);
- result.push({
- position: patternFound.position,
- value: patternFound.value,
- });
- }
- } while (patternFound.position != (-1));
- return result;
- }
- findPairedPatterns(leftPattern, rightPattern, start_, length_) {
- const result = [];
- if (leftPattern.isEqual(rightPattern))
- return result;
- const { start, length } = this.prepareFindParameters(start_, length_);
- let currentPositionLeft = 0;
- const leftPatterns = this.findAllPatternIn(leftPattern, start, length);
- if (!Array.isArray(leftPatterns) || leftPatterns.length == 0) {
- return result;
- }
- const rightPatterns = this.findAllPatternIn(rightPattern, start, length);
- if (!Array.isArray(rightPatterns) || rightPatterns.length == 0) {
- return result;
- }
- while (currentPositionLeft < leftPatterns.length) {
- if (rightPatterns.length == 0) {
- break;
- }
- if (leftPatterns[0] == rightPatterns[0]) {
- result.push({
- left: leftPatterns[0],
- right: rightPatterns[0]
- });
- leftPatterns.splice(0, 1);
- rightPatterns.splice(0, 1);
- continue;
- }
- if (leftPatterns[currentPositionLeft] > rightPatterns[0]) {
- break;
- }
- while (leftPatterns[currentPositionLeft] < rightPatterns[0]) {
- currentPositionLeft++;
- if (currentPositionLeft >= leftPatterns.length) {
- break;
- }
- }
- result.push({
- left: leftPatterns[currentPositionLeft - 1],
- right: rightPatterns[0]
- });
- leftPatterns.splice(currentPositionLeft - 1, 1);
- rightPatterns.splice(0, 1);
- currentPositionLeft = 0;
- }
- result.sort((a, b) => (a.left - b.left));
- return result;
- }
- findPairedArrays(inputLeftPatterns, inputRightPatterns, start_, length_) {
- const { start, length } = this.prepareFindParameters(start_, length_);
- const result = [];
- let currentPositionLeft = 0;
- const leftPatterns = this.findAllIn(inputLeftPatterns, start, length);
- if (leftPatterns.length == 0)
- return result;
- const rightPatterns = this.findAllIn(inputRightPatterns, start, length);
- if (rightPatterns.length == 0)
- return result;
- while (currentPositionLeft < leftPatterns.length) {
- if (rightPatterns.length == 0) {
- break;
- }
- if (leftPatterns[0].position == rightPatterns[0].position) {
- result.push({
- left: leftPatterns[0],
- right: rightPatterns[0]
- });
- leftPatterns.splice(0, 1);
- rightPatterns.splice(0, 1);
- continue;
- }
- if (leftPatterns[currentPositionLeft].position > rightPatterns[0].position) {
- break;
- }
- while (leftPatterns[currentPositionLeft].position < rightPatterns[0].position) {
- currentPositionLeft++;
- if (currentPositionLeft >= leftPatterns.length) {
- break;
- }
- }
- result.push({
- left: leftPatterns[currentPositionLeft - 1],
- right: rightPatterns[0]
- });
- leftPatterns.splice(currentPositionLeft - 1, 1);
- rightPatterns.splice(0, 1);
- currentPositionLeft = 0;
- }
- result.sort((a, b) => (a.left.position - b.left.position));
- return result;
- }
- replacePattern(searchPattern, replacePattern, start_, length_, findAllResult = null) {
- let result = [];
- let i;
- const output = {
- status: (-1),
- searchPatternPositions: [],
- replacePatternPositions: []
- };
- const { start, length } = this.prepareFindParameters(start_, length_);
- if (findAllResult == null) {
- result = this.findAllIn([searchPattern], start, length);
- if (result.length == 0) {
- return output;
- }
- }
- else {
- result = findAllResult;
- }
- output.searchPatternPositions.push(...Array.from(result, element => element.position));
- const patternDifference = searchPattern.length - replacePattern.length;
- const changedBuffer = new ArrayBuffer(this.view.length - (result.length * patternDifference));
- const changedView = new Uint8Array(changedBuffer);
- changedView.set(new Uint8Array(this.buffer, 0, start));
- for (i = 0; i < result.length; i++) {
- const currentPosition = (i == 0) ? start : result[i - 1].position;
- changedView.set(new Uint8Array(this.buffer, currentPosition, result[i].position - searchPattern.length - currentPosition), currentPosition - i * patternDifference);
- changedView.set(replacePattern.view, result[i].position - searchPattern.length - i * patternDifference);
- output.replacePatternPositions.push(result[i].position - searchPattern.length - i * patternDifference);
- }
- i--;
- changedView.set(new Uint8Array(this.buffer, result[i].position, this.length - result[i].position), result[i].position - searchPattern.length + replacePattern.length - i * patternDifference);
- this.buffer = changedBuffer;
- this.view = new Uint8Array(this.buffer);
- output.status = 1;
- return output;
- }
- skipPatterns(patterns, start_, length_, backward_) {
- const { start, length, backward } = this.prepareFindParameters(start_, length_, backward_);
- let result = start;
- for (let k = 0; k < patterns.length; k++) {
- const patternLength = patterns[k].length;
- const equalStart = (backward) ? (result - patternLength) : (result);
- let equal = true;
- for (let j = 0; j < patternLength; j++) {
- if (this.view[j + equalStart] != patterns[k].view[j]) {
- equal = false;
- break;
- }
- }
- if (equal) {
- k = (-1);
- if (backward) {
- result -= patternLength;
- if (result <= 0)
- return result;
- }
- else {
- result += patternLength;
- if (result >= (start + length))
- return result;
- }
- }
- }
- return result;
- }
- skipNotPatterns(patterns, start_, length_, backward_) {
- const { start, length, backward } = this.prepareFindParameters(start_, length_, backward_);
- let result = (-1);
- for (let i = 0; i < length; i++) {
- for (let k = 0; k < patterns.length; k++) {
- const patternLength = patterns[k].length;
- const equalStart = (backward) ? (start - i - patternLength) : (start + i);
- let equal = true;
- for (let j = 0; j < patternLength; j++) {
- if (this.view[j + equalStart] != patterns[k].view[j]) {
- equal = false;
- break;
- }
- }
- if (equal) {
- result = (backward) ? (start - i) : (start + i);
- break;
- }
- }
- if (result != (-1)) {
- break;
- }
- }
- return result;
- }
- prepareFindParameters(start = null, length = null, backward = false) {
- if (start === null) {
- start = (backward) ? this.length : 0;
- }
- if (start > this.length) {
- start = this.length;
- }
- if (backward) {
- if (length === null) {
- length = start;
- }
- if (length > start) {
- length = start;
- }
- }
- else {
- if (length === null) {
- length = this.length - start;
- }
- if (length > (this.length - start)) {
- length = this.length - start;
- }
- }
- return { start, length, backward };
- }
- }
|