File: MultipartIdentifier.cs

package info (click to toggle)
mono 6.14.1%2Bds2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,282,732 kB
  • sloc: cs: 11,182,461; xml: 2,850,281; ansic: 699,123; cpp: 122,919; perl: 58,604; javascript: 30,841; asm: 21,845; makefile: 19,602; sh: 10,973; python: 4,772; pascal: 925; sql: 859; sed: 16; php: 1
file content (248 lines) | stat: -rw-r--r-- 14,037 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
//------------------------------------------------------------------------------
// <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;
        }               
    }
}