2 * Copyright (c) 2019 The xterm.js authors. All rights reserved.
6 import { IDisposable } from 'common/Types';
7 import { IDcsHandler, IParams, IHandlerCollection, IDcsParser, DcsFallbackHandlerType } from 'common/parser/Types';
8 import { utf32ToString } from 'common/input/TextDecoder';
9 import { Params } from 'common/parser/Params';
10 import { PAYLOAD_LIMIT } from 'common/parser/Constants';
12 const EMPTY_HANDLERS: IDcsHandler[] = [];
14 export class DcsParser implements IDcsParser {
15 private _handlers: IHandlerCollection<IDcsHandler> = Object.create(null);
16 private _active: IDcsHandler[] = EMPTY_HANDLERS;
17 private _ident: number = 0;
18 private _handlerFb: DcsFallbackHandlerType = () => {};
20 public dispose(): void {
21 this._handlers = Object.create(null);
22 this._handlerFb = () => {};
25 public addHandler(ident: number, handler: IDcsHandler): IDisposable {
26 if (this._handlers[ident] === undefined) {
27 this._handlers[ident] = [];
29 const handlerList = this._handlers[ident];
30 handlerList.push(handler);
33 const handlerIndex = handlerList.indexOf(handler);
34 if (handlerIndex !== -1) {
35 handlerList.splice(handlerIndex, 1);
41 public setHandler(ident: number, handler: IDcsHandler): void {
42 this._handlers[ident] = [handler];
45 public clearHandler(ident: number): void {
46 if (this._handlers[ident]) delete this._handlers[ident];
49 public setHandlerFallback(handler: DcsFallbackHandlerType): void {
50 this._handlerFb = handler;
53 public reset(): void {
54 if (this._active.length) {
57 this._active = EMPTY_HANDLERS;
61 public hook(ident: number, params: IParams): void {
62 // always reset leftover handlers
65 this._active = this._handlers[ident] || EMPTY_HANDLERS;
66 if (!this._active.length) {
67 this._handlerFb(this._ident, 'HOOK', params);
69 for (let j = this._active.length - 1; j >= 0; j--) {
70 this._active[j].hook(params);
75 public put(data: Uint32Array, start: number, end: number): void {
76 if (!this._active.length) {
77 this._handlerFb(this._ident, 'PUT', utf32ToString(data, start, end));
79 for (let j = this._active.length - 1; j >= 0; j--) {
80 this._active[j].put(data, start, end);
85 public unhook(success: boolean): void {
86 if (!this._active.length) {
87 this._handlerFb(this._ident, 'UNHOOK', success);
89 let j = this._active.length - 1;
91 if (this._active[j].unhook(success) !== false) {
96 // cleanup left over handlers
98 this._active[j].unhook(false);
101 this._active = EMPTY_HANDLERS;
107 * Convenient class to create a DCS handler from a single callback function.
108 * Note: The payload is currently limited to 50 MB (hardcoded).
110 export class DcsHandler implements IDcsHandler {
112 private _params: IParams | undefined;
113 private _hitLimit: boolean = false;
115 constructor(private _handler: (data: string, params: IParams) => any) {}
117 public hook(params: IParams): void {
118 this._params = params.clone();
120 this._hitLimit = false;
123 public put(data: Uint32Array, start: number, end: number): void {
124 if (this._hitLimit) {
127 this._data += utf32ToString(data, start, end);
128 if (this._data.length > PAYLOAD_LIMIT) {
130 this._hitLimit = true;
134 public unhook(success: boolean): any {
136 if (this._hitLimit) {
138 } else if (success) {
139 ret = this._handler(this._data, this._params ? this._params : new Params());
141 this._params = undefined;
143 this._hitLimit = false;