/// <summary> /// Handles the special SPARQL escapes that can occur in a local name /// </summary> /// <remarks> /// Unlike <see cref="BaseTokeniser.HandleEscapes()">HandleEscapes()</see> this only unescapes unicode escapes, other escapes are simply validated and passed through for later unescaping /// </remarks> protected void HandleSparqlLocalNameEscapes() { //Grab the first character which must be a \ or % char next = this.SkipCharacter(); //Stuff for Unicode/Hex escapes StringBuilder localOutput; if (next == '\\') { //Backslash based escape next = this.Peek(); switch (next) { case '_': case '-': case '.': case '|': case '$': case '&': case '\'': case '(': case ')': case '*': case '+': case ',': case ';': case '=': case ':': case '/': case '?': case '#': case '@': case '%': //Escapable Characters this._output.Append('\\'); this.ConsumeCharacter(); return; case 'u': //Need to consume the u first localOutput = new StringBuilder(); this.SkipCharacter(); next = this.Peek(); //Try to get Four Hex Digits while (localOutput.Length < 4 && this.IsHexDigit(next)) { localOutput.Append(next); this.SkipCharacter(); next = this.Peek(); } //Did we get four Hex Digits if (localOutput.Length != 4) { throw Error("Unexpected Character (Code " + (int)next + "): " + next + " encountered while trying to parse Unicode Escape from Content:\n" + this._output.ToString() + "\nThe \\u Escape must be followed by four Hex Digits"); } else if (localOutput.ToString().Equals("0000")) { //Ignore the null escape } else { this._output.Append(UnicodeSpecsHelper.ConvertToChar(localOutput.ToString())); } return; case 'U': //Need to consume the U first localOutput = new StringBuilder(); this.SkipCharacter(); next = this.Peek(); //Try to get Eight Hex Digits while (localOutput.Length < 8 && this.IsHexDigit(next)) { localOutput.Append(next); this.SkipCharacter(); next = this.Peek(); } //Did we get eight Hex Digits if (localOutput.Length != 8) { throw Error("Unexpected Character (Code " + (int)next + "): " + next + " encountered while trying to parse Unicode Escape from Content:\n" + this._output.ToString() + "\nThe \\U Escape must be followed by eight Hex Digits"); } else if (localOutput.ToString().Equals("00000000")) { //Ignore the null escape } else { this._output.Append(UnicodeSpecsHelper.ConvertToChar(localOutput.ToString())); } return; default: throw Error("Unexpected Backslash Character encountered in a Local Name, the Backslash Character can only be used for Unicode escapes (\\u and \\U) and a limited set of special characters (_-.|&'()*+,;=/?#@%) in Local Names"); } } else if (next == '%') { localOutput = new StringBuilder(); localOutput.Append(next); next = this.Peek(); while (localOutput.Length < 3 && this.IsHexDigit(next)) { localOutput.Append(next); this.SkipCharacter(); next = this.Peek(); } //Did we get % followed by two hex digits if (localOutput.Length != 3) { throw Error("Encountered a % character in a Local Name but the required two hex digits were not present after it, please use \\% if you wish to represent the percent character"); } #if !SILVERLIGHT else if (!Uri.IsHexEncoding(localOutput.ToString(), 0)) #else else if (SilverlightExtensions.IsHexEncoding(localOutput.ToString(), 0)) #endif { throw Error("Invalid % encoded character encountered"); } else { this._output.Append(localOutput.ToString()); } } else { throw Error("HandleSparqlLocalNameEscapes() was called but the next character is not a % or \\ as expected"); } }
/// <summary> /// Handles the complex escapes that can occur in a local name /// </summary> /// <remarks> /// Unlike <see cref="BaseTokeniser.HandleEscapes(TokeniserEscapeMode)">HandleEscapes()</see> this only unescapes unicode escapes, other escapes are simply validated and passed through for later unescaping /// </remarks> protected void HandleComplexLocalNameEscapes() { //Grab the first character which must be a \ or % char next = this.SkipCharacter(); //Stuff for Unicode/Hex escapes if (next == '\\') { //Backslash based escape next = this.Peek(); switch (next) { case '_': case '~': case '-': case '.': case '!': case '$': case '&': case '\'': case '(': case ')': case '*': case '+': case ',': case ';': case '=': case '/': case '?': case '#': case '@': case '%': //Escapable Characters this._output.Append('\\'); this.ConsumeCharacter(); return; case 'u': case 'U': throw Error("Illegal unicode escape (\\u or \\U) in local name portion of a prefixed name"); default: throw Error("Unexpected Backslash Character encountered in a Local Name, the Backslash Character can only be used for Unicode escapes (\\u and \\U) and a limited set of special characters (_~-.!$&'()*+,;=/?#@%) in Local Names"); } } if (next != '%') { throw Error("HandleComplexLocalNameEscapes() was called but the next character is not a % or \\ as expected"); } StringBuilder localOutput = new StringBuilder(); localOutput.Append(next); next = this.Peek(); while (localOutput.Length < 3 && this.IsHexDigit(next)) { localOutput.Append(next); this.SkipCharacter(); next = this.Peek(); } //Did we get % followed by two hex digits if (localOutput.Length != 3) { throw Error("Encountered a % character in a Local Name but the required two hex digits were not present after it, please use \\% if you wish to represent the percent character itself"); } #if !SILVERLIGHT if (!Uri.IsHexEncoding(localOutput.ToString(), 0)) #else if (SilverlightExtensions.IsHexEncoding(localOutput.ToString(), 0)) #endif { throw Error("Invalid % encoded character encountered"); } this._output.Append(localOutput.ToString()); }