| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248 |
- //------------------------------------------------------------------------------
- // <copyright file="CommandBuilder.cs" company="Microsoft">
- // Copyright (c) Microsoft Corporation. All rights reserved.
- // </copyright>
- // <owner current="true" primary="true">Microsoft</owner>
- // <owner current="true" primary="false">Microsoft</owner>
- //------------------------------------------------------------------------------
- namespace System.Data.Common {
- using System.Diagnostics;
- using System.Text;
- using System.Globalization;
- internal class MultipartIdentifier {
- private const int MaxParts = 4;
- internal const int ServerIndex = 0;
- internal const int CatalogIndex = 1;
- internal const int SchemaIndex = 2;
- internal const int TableIndex = 3;
- /*
- Left quote strings need to correspond 1 to 1 with the right quote strings
- example: "ab" "cd", passed in for the left and the right quote
- would set a or b as a starting quote character.
- If a is the starting quote char then c would be the ending quote char
- otherwise if b is the starting quote char then d would be the ending quote character.
- */
- internal static string[] ParseMultipartIdentifier(string name, string leftQuote, string rightQuote, string property, bool ThrowOnEmptyMultipartName) {
- return ParseMultipartIdentifier(name, leftQuote, rightQuote,'.', MaxParts, true, property, ThrowOnEmptyMultipartName);
- }
- private enum MPIState {
- MPI_Value,
- MPI_ParseNonQuote,
- MPI_LookForSeparator,
- MPI_LookForNextCharOrSeparator,
- MPI_ParseQuote,
- MPI_RightQuote,
- }
-
- /* Core function for parsing the multipart identifer string.
- * paramaters: name - string to parse
- * leftquote: set of characters which are valid quoteing characters to initiate a quote
- * rightquote: set of characters which are valid to stop a quote, array index's correspond to the the leftquote array.
- * separator: separator to use
- * limit: number of names to parse out
- * removequote:to remove the quotes on the returned string
- */
- private static void IncrementStringCount (string name, string[] ary, ref int position, string property) {
- ++position;
- int limit = ary.Length;
- if (position >= limit) {
- throw ADP.InvalidMultipartNameToManyParts (property, name, limit);
- }
- ary[position] = string.Empty;
- }
- private static bool IsWhitespace (char ch) {
- return Char.IsWhiteSpace (ch);
- }
-
- internal static string[] ParseMultipartIdentifier(string name, string leftQuote, string rightQuote, char separator, int limit, bool removequotes, string property, bool ThrowOnEmptyMultipartName) {
-
- if (limit <= 0) {
- throw ADP.InvalidMultipartNameToManyParts (property, name, limit);
- }
- if (-1 != leftQuote.IndexOf(separator) || -1 != rightQuote.IndexOf(separator) || leftQuote.Length != rightQuote.Length) {
- throw ADP.InvalidMultipartNameIncorrectUsageOfQuotes (property, name);
- }
- string[] parsedNames = new string[limit]; // return string array
- int stringCount = 0; // index of current string in the buffer
- MPIState state = MPIState.MPI_Value; // Initalize the starting state
-
- StringBuilder sb = new StringBuilder (name.Length); // String buffer to hold the string being currently built, init the string builder so it will never be resized
- StringBuilder whitespaceSB = null; // String buffer to hold white space used when parsing nonquoted strings 'a b . c d' = 'a b' and 'c d'
- char rightQuoteChar = ' '; // Right quote character to use given the left quote character found.
- for (int index = 0; index < name.Length; ++index) {
- char testchar = name[index];
- switch (state) {
- case MPIState.MPI_Value : {
- int quoteIndex;
- if (IsWhitespace (testchar)) { // Is White Space then skip the whitespace
- continue;
- }
- else
- if (testchar == separator) { // If we found a separator, no string was found, initalize the string we are parsing to Empty and the next one to Empty.
- // This is NOT a redundent setting of string.Empty it solves the case where we are parsing ".foo" and we should be returning null, null, empty, foo
- parsedNames[stringCount] = string.Empty;
- IncrementStringCount (name, parsedNames, ref stringCount, property);
- }
- else
- if (-1 != (quoteIndex = leftQuote.IndexOf(testchar))) { // If we are a left quote
- rightQuoteChar = rightQuote[quoteIndex]; // record the corresponding right quote for the left quote
- sb.Length = 0;
- if (!removequotes) {
- sb.Append (testchar);
- }
- state = MPIState.MPI_ParseQuote;
- }
- else
- if (-1 != rightQuote.IndexOf(testchar)) { // If we shouldn't see a right quote
- throw ADP.InvalidMultipartNameIncorrectUsageOfQuotes (property, name);
- }
- else {
- sb.Length = 0;
- sb.Append (testchar);
- state = MPIState.MPI_ParseNonQuote;
- }
- break;
- }
-
- case MPIState.MPI_ParseNonQuote: {
- if (testchar == separator) {
- parsedNames[stringCount] = sb.ToString (); // set the currently parsed string
- IncrementStringCount (name, parsedNames, ref stringCount, property);
- state = MPIState.MPI_Value;
- }
- else // Quotes are not valid inside a non-quoted name
- if (-1 != rightQuote.IndexOf (testchar)) {
- throw ADP.InvalidMultipartNameIncorrectUsageOfQuotes (property, name);
- }
- else
- if (-1 != leftQuote.IndexOf(testchar)) {
- throw ADP.InvalidMultipartNameIncorrectUsageOfQuotes (property, name);
- }
- else
- if (IsWhitespace (testchar)) { // If it is Whitespace
- parsedNames[stringCount] = sb.ToString (); // Set the currently parsed string
- if (null == whitespaceSB) {
- whitespaceSB = new StringBuilder ();
- }
- whitespaceSB.Length = 0;
- whitespaceSB.Append (testchar); // start to record the white space, if we are parsing a name like "foo bar" we should return "foo bar"
- state = MPIState.MPI_LookForNextCharOrSeparator;
- }
- else {
- sb.Append (testchar);
- }
- break;
- }
-
- case MPIState.MPI_LookForNextCharOrSeparator : {
- if (!IsWhitespace (testchar)) { // If it is not whitespace
- if (testchar == separator) {
- IncrementStringCount (name, parsedNames, ref stringCount, property);
- state = MPIState.MPI_Value;
- }
- else { // If its not a separator and not whitespace
- sb.Append (whitespaceSB);
- sb.Append (testchar);
- parsedNames[stringCount] = sb.ToString (); // Need to set the name here in case the string ends here.
- state = MPIState.MPI_ParseNonQuote;
- }
- }
- else {
- whitespaceSB.Append (testchar);
- }
- break;
- }
-
- case MPIState.MPI_ParseQuote: {
- if (testchar == rightQuoteChar) { // if se are on a right quote see if we are escapeing the right quote or ending the quoted string
- if (!removequotes) {
- sb.Append (testchar);
- }
- state = MPIState.MPI_RightQuote;
- }
- else {
- sb.Append (testchar); // Append what we are currently parsing
- }
- break;
- }
- case MPIState.MPI_RightQuote : {
- if (testchar == rightQuoteChar) { // If the next char is a another right quote then we were escapeing the right quote
- sb.Append (testchar);
- state = MPIState.MPI_ParseQuote;
- }
- else
- if (testchar == separator) { // If its a separator then record what we've parsed
- parsedNames[stringCount] = sb.ToString ();
- IncrementStringCount (name, parsedNames, ref stringCount, property);
- state = MPIState.MPI_Value;
- }
- else
- if (!IsWhitespace (testchar)) { // If it is not white space we got problems
- throw ADP.InvalidMultipartNameIncorrectUsageOfQuotes (property, name);
- }
- else { // It is a whitespace character so the following char should be whitespace, separator, or end of string anything else is bad
- parsedNames[stringCount] = sb.ToString ();
- state = MPIState.MPI_LookForSeparator;
- }
- break;
- }
-
- case MPIState.MPI_LookForSeparator : {
- if (!IsWhitespace (testchar)) { // If it is not whitespace
- if (testchar == separator) { // If it is a separator
- IncrementStringCount (name, parsedNames, ref stringCount, property);
- state = MPIState.MPI_Value;
- }
- else { // Othewise not a separator
- throw ADP.InvalidMultipartNameIncorrectUsageOfQuotes (property, name);
- }
- }
- break;
- }
- }
- }
- // Resolve final states after parsing the string
- switch (state) {
- case MPIState.MPI_Value : // These states require no extra action
- case MPIState.MPI_LookForSeparator :
- case MPIState.MPI_LookForNextCharOrSeparator :
- break;
-
- case MPIState.MPI_ParseNonQuote: // Dump what ever was parsed
- case MPIState.MPI_RightQuote :
- parsedNames[stringCount] = sb.ToString ();
- break;
-
- case MPIState.MPI_ParseQuote: // Invalid Ending States
- default:
- throw ADP.InvalidMultipartNameIncorrectUsageOfQuotes (property, name);
- }
-
- if (parsedNames[0] == null) {
- if (ThrowOnEmptyMultipartName) {
- throw ADP.InvalidMultipartName (property, name); // Name is entirely made up of whitespace
- }
- }
- else {
- // Shuffle the parsed name, from left justification to right justification, ie [a][b][null][null] goes to [null][null][a][b]
- int offset = limit - stringCount - 1;
- if (offset > 0) {
- for (int x = limit - 1; x >= offset; --x) {
- parsedNames[x] = parsedNames[x - offset];
- parsedNames[x - offset] = null;
- }
- }
- }
- return parsedNames;
- }
- }
- }
|