/// <summary> /// 状態をクリアします。 /// </summary> public void Clear() { this.stat = EscapeState.Normal; this.seq = ""; this.csiargs.Clear(); this.build.Length = 0; }
public override void StartFSM() { _idleState = new IdleState <states>(this, flags, _treeStartPoint); _followState = new FollowState <states>(this, myLeader, flags, _treeStartPoint, stopDist); _attackState = new AttackState <states>(this, flags, _treeStartPoint); _escapeState = new EscapeState <states>(this, flags, _treeStartPoint); _reloadState = new ReloadState <states>(this, flags, _treeStartPoint); fsm = new FSM <states>(_idleState); _idleState.AddTransition(states.Follow, _followState); _idleState.AddTransition(states.Attack, _attackState); _idleState.AddTransition(states.Escape, _escapeState); _idleState.AddTransition(states.Reload, _reloadState); _followState.AddTransition(states.Idle, _idleState); _followState.AddTransition(states.Attack, _attackState); _followState.AddTransition(states.Escape, _escapeState); _followState.AddTransition(states.Reload, _reloadState); _attackState.AddTransition(states.Idle, _idleState); _attackState.AddTransition(states.Follow, _followState); _attackState.AddTransition(states.Escape, _escapeState); _attackState.AddTransition(states.Reload, _reloadState); _reloadState.AddTransition(states.Idle, _idleState); _reloadState.AddTransition(states.Attack, _attackState); _reloadState.AddTransition(states.Follow, _followState); _reloadState.AddTransition(states.Escape, _escapeState); _escapeState.AddTransition(states.Idle, _idleState); _escapeState.AddTransition(states.Follow, _followState); fsm.SetState(_idleState); }
public void ResetEscapeState(EscapeState s) { _doubleQuoteReplace = s.DoubleQuote; _singleQuoteReplace = s.SingleQuote; _backslashReplace = s.Backslash; _doubleQuoteReplaceString = s.DoubleQuoteString; _singleQuoteReplaceString = s.SingleQuoteString; _backslashReplaceString = s.BackslashString; }
public static bool CheckProgression(EscapeState escapeState) { if (progression.ContainsKey(escapeState)) { return(progression[escapeState]); } else { return(false); } }
private void InitStates() { istate = new IState[9]; istate[0] = new IdleState(gameObject); istate[1] = new PatrolState(gameObject); istate[2] = new SuspiciousState(gameObject); istate[3] = new DetectionState(gameObject); istate[4] = new AlertState(gameObject); istate[5] = new AttackState(gameObject); istate[6] = new EscapeState(gameObject); istate[7] = new StunState(gameObject); istate[8] = new DeadState(gameObject); }
public override void StartFSM() { _leadState = new LeadState <states>(this, flags, leadStopDistance, _treeStartPoint); _attackState = new AttackState <states>(this, flags, _treeStartPoint); _buffState = new BuffState <states>(this, flags, _treeStartPoint); _escapeState = new EscapeState <states>(this, flags, _treeStartPoint); _idleState = new IdleState <states>(this, flags, _treeStartPoint); _reloadState = new ReloadState <states>(this, flags, _treeStartPoint); fsm = new FSM <states>(_idleState); _idleState.AddTransition(states.Attack, _attackState); _idleState.AddTransition(states.Buff, _buffState); _idleState.AddTransition(states.Lead, _leadState); _idleState.AddTransition(states.Escape, _escapeState); _idleState.AddTransition(states.Reload, _reloadState); _leadState.AddTransition(states.Attack, _attackState); _leadState.AddTransition(states.Buff, _buffState); _leadState.AddTransition(states.Escape, _escapeState); _leadState.AddTransition(states.Idle, _idleState); _leadState.AddTransition(states.Reload, _reloadState); _attackState.AddTransition(states.Lead, _leadState); _attackState.AddTransition(states.Buff, _buffState); _attackState.AddTransition(states.Escape, _escapeState); _attackState.AddTransition(states.Idle, _idleState); _attackState.AddTransition(states.Reload, _reloadState); _reloadState.AddTransition(states.Idle, _idleState); _reloadState.AddTransition(states.Attack, _attackState); _reloadState.AddTransition(states.Buff, _buffState); _reloadState.AddTransition(states.Lead, _leadState); _reloadState.AddTransition(states.Escape, _escapeState); _buffState.AddTransition(states.Lead, _leadState); _buffState.AddTransition(states.Attack, _attackState); _buffState.AddTransition(states.Escape, _escapeState); _buffState.AddTransition(states.Idle, _idleState); _buffState.AddTransition(states.Reload, _reloadState); _escapeState.AddTransition(states.Idle, _idleState); _escapeState.AddTransition(states.Lead, _leadState); fsm.SetState(_idleState); }
private void EvalEscapeState(char token) { switch (escapeState) { case EscapeState.None: if(token == '\\') { escapeState = EscapeState.Escape; escapeStartIndex = currentIndex; } else { EvalCommentsState(token, false); } break; case EscapeState.Escape: // \ if (token == 'k') { escapeState = EscapeState.StartNamedBackReference; } else if (char.IsDigit(token)) { escapeState = EscapeState.NumberedBackReference; number = int.Parse(token.ToString()); EvalCommentsState(token, true); } else { EvalCommentsState(token, true); escapeState = EscapeState.None; } break; case EscapeState.NumberedBackReference: // \number if (char.IsDigit(token)) { number = 10 * number + int.Parse(token.ToString()); } else { NumberedBackReferenceFound(escapeStartIndex, currentIndex, number); escapeState = EscapeState.None; EvalCommentsState(token, false); } break; case EscapeState.StartNamedBackReference: if(token == '<') { escapeState = EscapeState.NamedBackReference; startNamedIndex = currentIndex+1; } else { escapeState = EscapeState.None; EvalCommentsState(token, false); } break; case EscapeState.NamedBackReference: // \k<name> if(token == '>') { NamedBackReferenceFound(escapeStartIndex, currentIndex+1, GetName(startNamedIndex, currentIndex)); escapeState = EscapeState.None; } //else we are inside the name, continue break; } }
public override async Task AddByte(byte b) { switch (_escapeState) { case EscapeState.Normal: if (b == 0x1b) { _escapeState = EscapeState.Escape; break; } else { await base.AddByte(b); } break; case EscapeState.Escape: switch ((char)b) { case 'P': // Start Device Control String _escapeState = EscapeState.DcsSequence; break; case ']': // Start Operating System Command _escapeState = EscapeState.OscSequence; break; case '^': // Start Privacy Message _escapeState = EscapeState.PmSequence; break; case '_': // Start Application Program Command _escapeState = EscapeState.ApcSequence; break; default: // Send the escape byte and this byte to the client await base.AddByte(0x1b); await base.AddByte(b); _escapeState = EscapeState.Normal; break; } break; default: if (_escapeState.HasFlag(EscapeState.Escape)) { // Previous byte was escape _escapeState &= ~EscapeState.Escape; b = (byte)((b >= 0x40 && b <= 0x5f) ? (b + 0x40) : 0); } if ((b >= 0x08 && b <= 0x0d) || (b >= 0x20 && b <= 0x7e)) { _commandStringBuilder.Append((char)b); } else if (b == 0x1b) { _escapeState |= EscapeState.Escape; } else if (b == 0x9C || b == 0x07) { // Finalise command with String Terminator or Bell. var commandString = _commandStringBuilder.ToString(); switch (_escapeState) { case EscapeState.DcsSequence: await _terminal.Dcs(commandString); break; case EscapeState.OscSequence: await _terminal.Osc(commandString); break; case EscapeState.PmSequence: await _terminal.Pm(commandString); break; case EscapeState.ApcSequence: await _terminal.Apc(commandString); break; } _commandStringBuilder.Clear(); _escapeState = EscapeState.Normal; } else { await _terminal.Error("Unexpected character in " + _escapeState.ToString()); _commandStringBuilder.Clear(); _escapeState = EscapeState.Normal; } break; } }
public static string Unescape(this string text) { if (text == null) { return(text); } if (text.IndexOf('\\') < 0) { return(text); } var result = new StringBuilder(text.Length); char ch = ' '; EscapeState state = EscapeState.Normal; for (int i = 0; i < text.Length; i++) { ch = text[i]; switch (state) { case EscapeState.Normal: if (ch != '\\') { result.Append(ch); } else { state = EscapeState.Slash; } break; case EscapeState.Slash: if (ch == '\\') { result.Append(ch); } else { switch (ch) { case 'r': result.Append("\r"); break; case 'n': result.Append("\n"); break; case 't': result.Append("\t"); break; default: result.Append("\\").Append(ch); break; } } state = EscapeState.Normal; break; } } if (state == EscapeState.Slash) { result.Append(ch); } return(result.ToString()); }
// DO NOT CALL THIS IF YOU'RE ON THE SERVER. // Instead call EscapeRoomController.Instance.UpdateSingleEscapeStateOnClients(). public static void UpdateProgression(EscapeState escapeState, bool progressed) { progression[escapeState] = progressed; }
// Start is called before the first frame update void Start() { escapestate = GetComponent <EscapeState>(); }
private void EvalEscapeState(char token) { switch (escapeState) { case EscapeState.None: if (token == '\\') { escapeState = EscapeState.Escape; escapeStartIndex = currentIndex; } else { EvalCommentsState(token, false); } break; case EscapeState.Escape: // \ if (token == 'k') { escapeState = EscapeState.StartNamedBackReference; } else if (char.IsDigit(token)) { escapeState = EscapeState.NumberedBackReference; number = int.Parse(token.ToString()); EvalCommentsState(token, true); } else { EvalCommentsState(token, true); escapeState = EscapeState.None; } break; case EscapeState.NumberedBackReference: // \number if (char.IsDigit(token)) { number = 10 * number + int.Parse(token.ToString()); } else { NumberedBackReferenceFound(escapeStartIndex, currentIndex, number); escapeState = EscapeState.None; EvalCommentsState(token, false); } break; case EscapeState.StartNamedBackReference: if (token == '<') { escapeState = EscapeState.NamedBackReference; startNamedIndex = currentIndex + 1; } else { escapeState = EscapeState.None; EvalCommentsState(token, false); } break; case EscapeState.NamedBackReference: // \k<name> if (token == '>') { NamedBackReferenceFound(escapeStartIndex, currentIndex + 1, GetName(startNamedIndex, currentIndex)); escapeState = EscapeState.None; } //else we are inside the name, continue break; } }
private void InsertInternal(int index, ConsoleChar item) { if (item.Value == '\x1b') { _currentEscape.Append(item.Value); _escapeState = EscapeState.Escape; return; } if (_escapeState != EscapeState.None) { bool isCharInvalidValid = false; // All sequences start with followed by a char in the range 0x40–0x5F: (ASCII @A–Z[\]^_) var c = item.Value; if (_escapeState >= EscapeState.EscapeCsiParameterBytes) { // CSI: ESC [ followed by // - by any number (including none) of "parameter bytes", char in the 0x30–0x3F: (ASCII 0–9:;<=>?) // - then by any number of "intermediate bytes" in the range 0x20–0x2F (ASCII space and !"#$%&'()*+,-./), // - then finally by a single "final byte" in the range 0x40–0x7E (ASCII @A–Z[\]^_`a–z{|}~) switch (_escapeState) { case EscapeState.EscapeCsiParameterBytes: if (c >= 0x30 && c <= 0x3F) { _currentEscape.Append(c); } else { goto case EscapeState.EscapeCsiIntermediateBytes; } break; case EscapeState.EscapeCsiIntermediateBytes: if (c >= 0x20 && c <= 0x2F) { _escapeState = EscapeState.EscapeCsiIntermediateBytes; _currentEscape.Append(c); } else { goto case EscapeState.EscapeCsiFinalByte; } break; case EscapeState.EscapeCsiFinalByte: if (c >= 0x40 && c <= 0x7E) { _currentEscape.Append(c); } else { isCharInvalidValid = true; } var styleAsText = _currentEscape.ToString(); _currentEscape.Length = 0; _escapeState = EscapeState.None; InsertInternal(index, new ConsoleStyleMarker(Inline(styleAsText), true)); break; } } else { if (_currentEscape.Length == 1) { _currentEscape.Append(c); if (c == '[') { _escapeState = EscapeState.EscapeCsiParameterBytes; } else { var styleAsText = _currentEscape.ToString(); _currentEscape.Length = 0; _escapeState = EscapeState.None; InsertInternal(index, new ConsoleStyleMarker(Inline(styleAsText), true)); } } } if (!isCharInvalidValid) { return; } // otherwise the character hasn't been consumed, so we propagate it as a real char. } // Copy any leading/trailing escapes bool isFirstInsert = index == 0 && Count == 0; bool isLastInsert = Count > 0 && index == Count; List <ConsoleStyleMarker> copyFrom = isFirstInsert ? _leadingStyles : isLastInsert ? _trailingStyles : null; if (copyFrom != null && copyFrom.Count > 0) { var escapes = item.StyleMarkers; if (escapes == null) { escapes = new List <ConsoleStyleMarker>(); item.StyleMarkers = escapes; } for (int i = 0; i < copyFrom.Count; i++) { escapes.Insert(i, copyFrom[i]); } copyFrom.Clear(); } _chars.Insert(index, item); }
/// <summary> /// 受信した文字をエスケープシーケンスの一部か判定し処理します。 /// </summary> /// <param name="c">入力する文字を指定します。</param> /// <returns> /// 通常の文字と判定された場合には Normal を返します。 /// エスケープシーケンスの一部として処理した場合に Escape を返します。 /// エスケープシーケンスが完成し、処理を要する場合には、シーケンスの種類に応じた値を返します。 /// </returns> public EscapeState ProcessChar(char c) { if (this.stat == EscapeState.Normal) { if (c < 0x20) { switch (c) { case CH_ESC: this.stat = EscapeState.Escape; this.build.Length = 0; return(EscapeState.Intermediate); default: return(EscapeState.Control); } } else if (c >= 0x80 && c <= 0x9F) { switch (c) { case CH_CSI: this.stat = EscapeState.CSI; this.csiargs.Clear(); return(EscapeState.Intermediate); case CH_OSC: this.stat = EscapeState.OSC_Pre; this.csiargs.Clear(); return(EscapeState.Intermediate); case CH_PM: this.stat = EscapeState.PM; return(EscapeState.Intermediate); case CH_APC: this.stat = EscapeState.APC; return(EscapeState.Intermediate); default: return(EscapeState.Control); } } return(EscapeState.Normal); } else { // NULL 文字は無視 if (c == '\0') { return(EscapeState.Intermediate); } switch (this.stat) { case EscapeState.Escape: switch (c) { case '[': //this.stat=EscapeState.Normal; //return ProcessChar(CH_CSI); this.stat = EscapeState.CSI; this.csiargs.Clear(); return(EscapeState.Intermediate); case ']': //this.stat=EscapeState.Normal; //return ProcessChar(CH_OSC); this.stat = EscapeState.OSC_Pre; this.csiargs.Clear(); return(EscapeState.Intermediate); case '^': //this.stat=EscapeState.Normal; //return ProcessChar(CH_PM); this.stat = EscapeState.PM; return(EscapeState.Intermediate); case '_': //this.stat=EscapeState.Normal; //return ProcessChar(CH_APC); this.stat = EscapeState.APC; return(EscapeState.Intermediate); //TODO: TerminalBase.cs:524/EscapeSequenceTerminal は // \e@0 \e@1 に対する処理も実行している。 } if ('0' <= c && c <= '~') { // DONE: Escape Sequence Completed this.build.Append(c); goto EscapeCompleted; } break; case EscapeState.CSI: if (c >= '@') { // DONE: Escape Sequence Completed build.Append(c); goto EscapeCompleted; } if (!this.csiargs.AddChar(c)) { this.build.Append(c); } break; //------------------------------------------------ case EscapeState.OSC_Pre: if (c == ';') { this.stat = EscapeState.OSC; break; } if (!this.csiargs.AddChar(c)) { this.stat = EscapeState.OSC; goto case EscapeState.OSC; } break; case EscapeState.OSC: // 本来 BEL で終わる OSC: if (c == CH_BEL || c == CH_ST) { goto EscapeCompleted; } else if (c == CH_ESC) { this.stat = EscapeState.OSC_Reach; } else { this.build.Append(c); } break; case EscapeState.OSC_Reach: this.stat = EscapeState.OSC; if (c == CH_eST) { goto EscapeCompleted; } else { this.build.Append(CH_ESC); goto OSC; } //------------------------------------------------ case EscapeState.APC: // 本来 ST で終わる if (c == CH_BEL || c == CH_ST) { goto EscapeCompleted; } else if (c == CH_ESC) { this.stat = EscapeState.APC_Reach; } else { this.build.Append(c); } break; case EscapeState.APC_Reach: this.stat = EscapeState.APC; if (c == CH_eST) { goto EscapeCompleted; } else { build.Append(c); } break; //------------------------------------------------ case EscapeState.PM: // 本来 ST で終わる if (c == CH_BEL || c == CH_ST) { goto EscapeCompleted; } else if (c == CH_ESC) { this.stat = EscapeState.PM_Reach; } else { this.build.Append(c); } break; case EscapeState.PM_Reach: this.stat = EscapeState.PM; if (c == CH_eST) { goto EscapeCompleted; } else { build.Append(c); } break; //------------------------------------------------ default: throw new System.InvalidProgramException("Fatal:this.state: 不定状態。"); EscapeCompleted : { this.seq = build.ToString(); EscapeState r = this.stat; this.stat = EscapeState.Normal; return(r); } } return(EscapeState.Intermediate); } }
private void WriteNode(XmlNode node, TextWriter writer, HtmlRendererEscapeBehaviour behaviour) { switch (node.NodeType) { case XmlNodeType.Element: XmlElement element = node as XmlElement; writer.Write("<"); writer.Write(element.Name); if (element.Name.ToLower() == "style" && behaviour == HtmlRendererEscapeBehaviour.IgnoreStyleElements) { _escapeState = EscapeState.Ignore; } foreach (XmlAttribute attribute in node.Attributes) { writer.Write(" {0}=\"{1}\"", attribute.Name, _escapeState == EscapeState.Escape ? EscapeHtml(attribute.Value) : attribute.Value ); } writer.Write(">"); foreach (XmlNode child in element.ChildNodes) { WriteNode(child, writer, behaviour); } if (!(element.ChildNodes.Count == 0 && _noEndTags.Contains(element.Name.ToLower()))) { writer.Write("</"); writer.Write(element.Name); writer.Write(">"); } _escapeState = EscapeState.Escape; break; case XmlNodeType.Text: writer.Write( _escapeState == EscapeState.Escape ? EscapeHtml((node as XmlText).Value) : (node as XmlText).Value ); break; } }
public static void MapEscape(byte[] dataIn, int offsetIn, int lengthIn, Escape escape) { int num = 0; EscapeState state = escape.State; int num2 = offsetIn; while (lengthIn > 0) { byte b = dataIn[offsetIn]; EscapeSequence sequence; switch (escape.State) { case EscapeState.Begin: if (b == 27) { escape.State = EscapeState.Esc_1; } else { if (b == 14) { sequence = EscapeSequence.ShiftOut; goto IL_33B; } if (b == 15) { sequence = EscapeSequence.ShiftIn; goto IL_33B; } escape.BytesInCurrentBuffer = 0; escape.TotalBytes = 0; escape.Sequence = EscapeSequence.None; return; } break; case EscapeState.Esc_1: if (b == 36) { escape.State = EscapeState.Esc_Dollar_2; } else if (b == 40) { escape.State = EscapeState.Esc_OpenParen_2; } else { if (b == 72) { sequence = EscapeSequence.NECKanjiIn; goto IL_33B; } if (b == 75) { sequence = EscapeSequence.JisX0208_Nec; goto IL_33B; } if (b == 38) { escape.State = EscapeState.Esc_Ampersand_2; } else { if (b == 27) { goto IL_2C6; } if (b == 14 || b == 15) { goto IL_2CF; } if (b == 0) { goto IL_366; } goto IL_366; } } break; case EscapeState.Esc_Dollar_2: if (b == 64) { sequence = EscapeSequence.JisX0208_1983; goto IL_33B; } if (b == 65) { sequence = EscapeSequence.Gb2312_1980; goto IL_33B; } if (b == 66) { sequence = EscapeSequence.JisX0208_1978; goto IL_33B; } if (b == 40) { escape.State = EscapeState.Esc_Dollar_OpenParen_3; } else if (b == 41) { escape.State = EscapeState.Esc_Dollar_CloseParen_3; } else { if (b == 27) { goto IL_2C6; } if (b == 14) { goto IL_2CF; } if (b == 15) { goto IL_2CF; } goto IL_366; } break; case EscapeState.Esc_OpenParen_2: if (b == 73) { sequence = EscapeSequence.JisX0201K_1976; goto IL_33B; } if (b == 74) { sequence = EscapeSequence.JisX0201_1976; goto IL_33B; } if (b == 68) { sequence = EscapeSequence.JisX0212_1990; goto IL_33B; } if (b == 66) { sequence = EscapeSequence.Iso646Irv; goto IL_33B; } if (b == 27) { goto IL_2C6; } if (b == 14) { goto IL_2CF; } if (b == 15) { goto IL_2CF; } goto IL_366; case EscapeState.Esc_Ampersand_2: if (b == 64) { escape.State = EscapeState.Esc_Ampersand_At_3; } else { if (b == 27) { goto IL_2C6; } if (b == 14) { goto IL_2CF; } if (b == 15) { goto IL_2CF; } goto IL_366; } break; case EscapeState.Esc_K_2: goto IL_2F9; case EscapeState.Esc_Dollar_OpenParen_3: if (b == 71) { sequence = EscapeSequence.Cns11643_1992_1; goto IL_33B; } if (b == 67) { sequence = EscapeSequence.Kcs5601_1987; goto IL_33B; } if (b == 72) { sequence = EscapeSequence.Cns11643_1992_1; goto IL_33B; } if (b == 81) { sequence = EscapeSequence.Unknown_1; goto IL_33B; } if (b == 27) { goto IL_2C6; } if (b == 14) { goto IL_2CF; } if (b == 15) { goto IL_2CF; } goto IL_366; case EscapeState.Esc_Dollar_CloseParen_3: if (b == 67) { sequence = EscapeSequence.EucKsc; goto IL_33B; } if (b == 27) { goto IL_2C6; } if (b == 14) { goto IL_2CF; } if (b == 15) { goto IL_2CF; } goto IL_366; case EscapeState.Esc_Ampersand_At_3: if (b == 27) { escape.State = EscapeState.Esc_Ampersand_At_Esc_4; } else { if (b == 14) { goto IL_2CF; } if (b == 15) { goto IL_2CF; } goto IL_366; } break; case EscapeState.Esc_Ampersand_At_Esc_4: if (b == 36) { escape.State = EscapeState.Esc_Ampersand_At_Esc_Dollar_5; } else { if (b == 27) { goto IL_2C6; } if (b == 14) { goto IL_2CF; } if (b == 15) { goto IL_2CF; } goto IL_366; } break; case EscapeState.Esc_Ampersand_At_Esc_Dollar_5: if (b == 66) { sequence = EscapeSequence.JisX0208_1990; goto IL_33B; } if (b == 27) { goto IL_2C6; } if (b == 14) { goto IL_2CF; } if (b == 15) { goto IL_2CF; } goto IL_366; case EscapeState.Esc_Esc_Reset: goto IL_2C6; case EscapeState.Esc_SISO_Reset: goto IL_2CF; default: goto IL_2F9; } IL_304: lengthIn--; offsetIn++; num++; continue; IL_2C6: escape.State = EscapeState.Esc_1; goto IL_304; IL_2CF: if (b == 14) { sequence = EscapeSequence.ShiftOut; goto IL_33B; } if (b == 15) { sequence = EscapeSequence.ShiftIn; goto IL_33B; } throw new InvalidOperationException(string.Format("MapEscape: at Esc_SISO_Reset with {0}", (int)b)); IL_2F9: throw new InvalidOperationException("MapEscape: unrecognized state!"); IL_33B: escape.BytesInCurrentBuffer = num + 1; escape.TotalBytes += escape.BytesInCurrentBuffer; escape.State = EscapeState.Begin; escape.Sequence = sequence; return; IL_366: string text = string.Empty; while (num2 <= offsetIn && num2 < offsetIn + lengthIn) { text += dataIn[num2++].ToString("X2"); } string.Format("Unrecognized escape sequence {0}, initial state {1}, current state {2}", text, state.ToString(), escape.State.ToString()); escape.State = EscapeState.Begin; escape.Sequence = EscapeSequence.NotRecognized; escape.BytesInCurrentBuffer = num; escape.TotalBytes += num; return; } escape.BytesInCurrentBuffer = num; escape.TotalBytes += escape.BytesInCurrentBuffer; escape.Sequence = EscapeSequence.Incomplete; }
/// <summary> /// Reads a string and parses escape sequences /// </summary> /// <example> /// <code> /// ParseEscapes("\\r\\n\\0"); // Returns "\r\n\0" /// ParseEscapes("\\uFE"); // Returns "\uFE" /// </code> /// </example> public static string ParseEscapes(this string stringIn) { // What is returned string strOut = ""; // Index correlates with value string hexidecimal = "0123456789abcdef"; // State of parser EscapeState escape = EscapeState.Unescaped; int unicodeDepth = 0; int unicodeValue = 0; foreach (char letter in stringIn) { switch (escape) { case EscapeState.Unescaped: if (letter == '\\') { escape = EscapeState.RegularEscape; } else { strOut += letter; } break; case EscapeState.RegularEscape: switch (letter) { case '\'': strOut += '\''; escape = EscapeState.Unescaped; break; case '"': strOut += '"'; escape = EscapeState.Unescaped; break; case '\\': strOut += '\\'; escape = EscapeState.Unescaped; break; case '0': strOut += '\0'; escape = EscapeState.Unescaped; break; case 'a': strOut += '\a'; escape = EscapeState.Unescaped; break; case 'b': strOut += '\b'; escape = EscapeState.Unescaped; break; case 'f': strOut += '\f'; escape = EscapeState.Unescaped; break; case 'n': strOut += '\n'; escape = EscapeState.Unescaped; break; case 'r': strOut += '\r'; escape = EscapeState.Unescaped; break; case 't': strOut += '\t'; escape = EscapeState.Unescaped; break; case 'v': strOut += '\v'; escape = EscapeState.Unescaped; break; case 'u': unicodeDepth = 4; unicodeValue = 0; escape = EscapeState.UnicodeEscape; break; case 'U': unicodeDepth = 8; unicodeValue = 0; escape = EscapeState.UnicodeEscape; break; case 'x': unicodeDepth = 0; unicodeValue = 0; escape = EscapeState.VariableEscape; break; default: throw new FormatException($"Unrecognized escape '\\{letter}'"); } break; case EscapeState.UnicodeEscape: unicodeDepth--; if (!hexidecimal.Contains(letter)) { throw new FormatException($"Invalid hex value '{letter}'"); } unicodeValue += hexidecimal.IndexOf(letter) << (4 * unicodeDepth); if (unicodeDepth == 0) { escape = EscapeState.Unescaped; strOut += char.ConvertFromUtf32(unicodeValue); } break; case EscapeState.VariableEscape: unicodeDepth++; // A hexidecimal character adds 4 bits. the value is shifted to accomodate unicodeValue <<= 4; if (hexidecimal.Contains(letter)) { unicodeValue += hexidecimal.IndexOf(letter); } else { if (unicodeDepth == 1) { throw new FormatException($"Invalid hex value '{letter}'"); } unicodeValue >>= 4; strOut += char.ConvertFromUtf32(unicodeValue); escape = EscapeState.Unescaped; } if (unicodeDepth == 4 && escape == EscapeState.VariableEscape) { strOut += char.ConvertFromUtf32(unicodeValue); escape = EscapeState.Unescaped; } break; } } // Text is finished processing and a variable unicode escape is closed if (escape == EscapeState.VariableEscape && unicodeDepth != 0) { strOut += char.ConvertFromUtf32(unicodeValue); } // Text is finished processing and an escape was not finalised else if (escape != EscapeState.Unescaped) { throw new FormatException("Unfinished escape"); } return(strOut); }