Code:
/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Framework / MS / Internal / Data / PathParser.cs / 1305600 / PathParser.cs
//----------------------------------------------------------------------------
//
//
// Copyright (C) Microsoft Corporation. All rights reserved.
//
//
// Description: Parser for the Path of a (CLR) binding
//
//---------------------------------------------------------------------------
using System;
using System.Collections;
using System.Text; // StringBuilder
using System.Windows;
using MS.Utility; // FrugalList
namespace MS.Internal.Data
{
internal enum SourceValueType { Property, Indexer, Direct };
internal enum DrillIn { Never, IfNeeded, Always };
internal struct SourceValueInfo
{
public SourceValueType type;
public DrillIn drillIn;
public string name; // the name the user supplied - could be "(0)"
public FrugalObjectList paramList; // params for indexer
public string propertyName; // the real name - could be "Width"
public SourceValueInfo(SourceValueType t, DrillIn d, string n)
{
type = t;
drillIn = d;
name = n;
paramList = null;
propertyName = null;
}
public SourceValueInfo(SourceValueType t, DrillIn d, FrugalObjectList list)
{
type = t;
drillIn = d;
name = null;
paramList = list;
propertyName = null;
}
}
internal struct IndexerParamInfo
{
// parse each indexer param "(abc)xyz" into two pieces - either can be empty
public string parenString;
public string valueString;
public IndexerParamInfo(string paren, string value)
{
parenString = paren;
valueString = value;
}
}
internal class PathParser
{
string _error;
public String Error { get { return _error; } }
void SetError(string id, params object[] args) { _error = SR.Get(id, args); }
enum State { Init, DrillIn, Prop, Done };
// Each level of the path consists of
// a property or indexer:
// .propname
// /propname
// [index]
// /[index]
// (The . or / is optional in the very first level.)
// The parser is a finite-state machine with two states corresponding
// to the two-character lookahead above, plus two more states for the begining
// and end. The state transistions are done explicitly in the code below.
//
// The parser returns a 0-length array if it finds a syntax error.
// It sets the Error property, so the caller can find out what happened.
public SourceValueInfo[] Parse(string path)
{
_path = (path != null) ? path.Trim() : String.Empty;
_n = _path.Length;
if (_n == 0)
{
// When no path string is specified, use value directly and do not drill-in. (same as Path=".")
// ClrBindingWorker needs this information to tell XmlBindingWorker about collectionMode.
return new SourceValueInfo[] { new SourceValueInfo(SourceValueType.Direct, DrillIn.Never, (string)null) };
}
_index = 0;
_drillIn = DrillIn.IfNeeded;
_al.Clear();
_error = null;
_state = State.Init;
while (_state != State.Done)
{
char c = (_index<_n) ? _path[_index] : NullChar;
if (Char.IsWhiteSpace(c))
{
++ _index;
continue;
}
switch (_state)
{
case State.Init:
switch (c)
{
case '/':
case '.':
case NullChar:
_state = State.DrillIn;
break;
default:
_state = State.Prop;
break;
}
break;
case State.DrillIn:
switch (c)
{
case '/':
_drillIn = DrillIn.Always;
++ _index;
break;
case '.':
_drillIn = DrillIn.Never;
++ _index;
break;
case '[':
case NullChar:
break;
default:
SetError(SRID.PathSyntax, _path.Substring(0, _index), _path.Substring(_index));
return EmptyInfo;
}
_state = State.Prop;
break;
case State.Prop:
bool isIndexer = false;
switch (c)
{
case '[':
isIndexer = true;
break;
default:
break;
}
if (isIndexer)
AddIndexer();
else
AddProperty();
break;
}
}
SourceValueInfo[] result;
if (_error == null)
{
result = new SourceValueInfo[_al.Count];
_al.CopyTo(result);
}
else
{
result = EmptyInfo;
}
return result;
}
void AddProperty()
{
int start = _index;
int level = 0;
// include leading dots in the path (for XLinq)
while (_index < _n && _path[_index] == '.')
++ _index;
while (_index < _n && (level > 0 || SpecialChars.IndexOf(_path[_index]) < 0))
{
if (_path[_index] == '(')
++ level;
else if (_path[_index] == ')')
-- level;
++ _index;
}
if (level > 0)
{
SetError(SRID.UnmatchedParen, _path.Substring(start));
return;
}
if (level < 0)
{
SetError(SRID.UnmatchedParen, _path.Substring(0, _index));
return;
}
string name = _path.Substring(start, _index - start).Trim();
SourceValueInfo info = (name.Length > 0)
? new SourceValueInfo(SourceValueType.Property, _drillIn, name)
: new SourceValueInfo(SourceValueType.Direct, _drillIn, (string)null);
_al.Add(info);
StartNewLevel();
}
enum IndexerState { BeginParam, ParenString, ValueString, Done }
void AddIndexer()
{
// indexer args are parsed by a (sub-) state machine with four
// states. The string is a comma-separated list of params, each
// of which has two parts: a "paren string" and a "value string"
// (both parts are optional). The character ^ can be used to
// escape any of the special characters: comma, parens, ], ^,
// and white space.
int start = ++_index; // skip over initial [
int level = 1; // level of nested []
bool escaped = false; // true if current char is escaped
bool trimRight = false; // true if value string has trailing white space
StringBuilder parenStringBuilder = new StringBuilder();
StringBuilder valueStringBuilder = new StringBuilder();
FrugalObjectList paramList = new FrugalObjectList();
IndexerState state = IndexerState.BeginParam;
while (state != IndexerState.Done)
{
if (_index >= _n)
{
SetError(SRID.UnmatchedBracket, _path.Substring(start - 1));
return;
}
Char c = _path[_index++];
// handle the escape character - set the flag for the next character
if (c == EscapeChar && !escaped)
{
escaped = true;
continue;
}
switch (state)
{
case IndexerState.BeginParam: // look for optional (...)
if (escaped)
{
// no '(', go parse the value
state = IndexerState.ValueString;
goto case IndexerState.ValueString;
}
else if (c == '(')
{
// '(' introduces optional paren string
state = IndexerState.ParenString;
}
else if (Char.IsWhiteSpace(c))
{
// ignore leading white space
}
else
{
// no '(', go parse the value
state = IndexerState.ValueString;
goto case IndexerState.ValueString;
}
break;
case IndexerState.ParenString: // parse (...)
if (escaped)
{
// add an escaped character without question
parenStringBuilder.Append(c);
}
else if (c == ')')
{
// end of (...), start to parse value
state = IndexerState.ValueString;
}
else
{
// add normal characters inside (...)
parenStringBuilder.Append(c);
}
break;
case IndexerState.ValueString: // parse value
if (escaped)
{
// add an escaped character without question
valueStringBuilder.Append(c);
trimRight = false;
}
else if (level > 1)
{
// inside nested [], add characters without question
valueStringBuilder.Append(c);
trimRight = false;
if (c == ']')
{
--level;
}
}
else if (Char.IsWhiteSpace(c))
{
// add white space, but trim it later if it's trailing
valueStringBuilder.Append(c);
trimRight = true;
}
else if (c == ',' || c == ']')
{
// end of current paramater - assemble the two parts
string parenString = parenStringBuilder.ToString();
string valueString = valueStringBuilder.ToString();
if (trimRight)
{
valueString = valueString.TrimEnd();
}
// add the parts to the final result
paramList.Add(new IndexerParamInfo(parenString, valueString));
// reset for the next parameter
parenStringBuilder.Length = 0;
valueStringBuilder.Length = 0;
trimRight = false;
// after ',' parse next parameter; after ']' we're done
state = (c == ']') ? IndexerState.Done : IndexerState.BeginParam;
}
else
{
// add normal characters
valueStringBuilder.Append(c);
trimRight = false;
// keep track of nested []
if (c == '[')
{
++level;
}
}
break;
}
// after processing each character, clear the escape flag
escaped = false;
}
// assemble the final result
SourceValueInfo info = new SourceValueInfo(
SourceValueType.Indexer,
_drillIn, paramList);
_al.Add(info);
StartNewLevel();
}
void StartNewLevel()
{
_state = (_index < _n) ? State.DrillIn : State.Done;
_drillIn = DrillIn.Never;
}
State _state;
string _path;
int _index;
int _n;
DrillIn _drillIn;
ArrayList _al = new ArrayList();
const char NullChar = Char.MinValue;
const char EscapeChar = '^';
static SourceValueInfo[] EmptyInfo = new SourceValueInfo[0];
static string SpecialChars = @"./[]";
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
//----------------------------------------------------------------------------
//
//
// Copyright (C) Microsoft Corporation. All rights reserved.
//
//
// Description: Parser for the Path of a (CLR) binding
//
//---------------------------------------------------------------------------
using System;
using System.Collections;
using System.Text; // StringBuilder
using System.Windows;
using MS.Utility; // FrugalList
namespace MS.Internal.Data
{
internal enum SourceValueType { Property, Indexer, Direct };
internal enum DrillIn { Never, IfNeeded, Always };
internal struct SourceValueInfo
{
public SourceValueType type;
public DrillIn drillIn;
public string name; // the name the user supplied - could be "(0)"
public FrugalObjectList paramList; // params for indexer
public string propertyName; // the real name - could be "Width"
public SourceValueInfo(SourceValueType t, DrillIn d, string n)
{
type = t;
drillIn = d;
name = n;
paramList = null;
propertyName = null;
}
public SourceValueInfo(SourceValueType t, DrillIn d, FrugalObjectList list)
{
type = t;
drillIn = d;
name = null;
paramList = list;
propertyName = null;
}
}
internal struct IndexerParamInfo
{
// parse each indexer param "(abc)xyz" into two pieces - either can be empty
public string parenString;
public string valueString;
public IndexerParamInfo(string paren, string value)
{
parenString = paren;
valueString = value;
}
}
internal class PathParser
{
string _error;
public String Error { get { return _error; } }
void SetError(string id, params object[] args) { _error = SR.Get(id, args); }
enum State { Init, DrillIn, Prop, Done };
// Each level of the path consists of
// a property or indexer:
// .propname
// /propname
// [index]
// /[index]
// (The . or / is optional in the very first level.)
// The parser is a finite-state machine with two states corresponding
// to the two-character lookahead above, plus two more states for the begining
// and end. The state transistions are done explicitly in the code below.
//
// The parser returns a 0-length array if it finds a syntax error.
// It sets the Error property, so the caller can find out what happened.
public SourceValueInfo[] Parse(string path)
{
_path = (path != null) ? path.Trim() : String.Empty;
_n = _path.Length;
if (_n == 0)
{
// When no path string is specified, use value directly and do not drill-in. (same as Path=".")
// ClrBindingWorker needs this information to tell XmlBindingWorker about collectionMode.
return new SourceValueInfo[] { new SourceValueInfo(SourceValueType.Direct, DrillIn.Never, (string)null) };
}
_index = 0;
_drillIn = DrillIn.IfNeeded;
_al.Clear();
_error = null;
_state = State.Init;
while (_state != State.Done)
{
char c = (_index<_n) ? _path[_index] : NullChar;
if (Char.IsWhiteSpace(c))
{
++ _index;
continue;
}
switch (_state)
{
case State.Init:
switch (c)
{
case '/':
case '.':
case NullChar:
_state = State.DrillIn;
break;
default:
_state = State.Prop;
break;
}
break;
case State.DrillIn:
switch (c)
{
case '/':
_drillIn = DrillIn.Always;
++ _index;
break;
case '.':
_drillIn = DrillIn.Never;
++ _index;
break;
case '[':
case NullChar:
break;
default:
SetError(SRID.PathSyntax, _path.Substring(0, _index), _path.Substring(_index));
return EmptyInfo;
}
_state = State.Prop;
break;
case State.Prop:
bool isIndexer = false;
switch (c)
{
case '[':
isIndexer = true;
break;
default:
break;
}
if (isIndexer)
AddIndexer();
else
AddProperty();
break;
}
}
SourceValueInfo[] result;
if (_error == null)
{
result = new SourceValueInfo[_al.Count];
_al.CopyTo(result);
}
else
{
result = EmptyInfo;
}
return result;
}
void AddProperty()
{
int start = _index;
int level = 0;
// include leading dots in the path (for XLinq)
while (_index < _n && _path[_index] == '.')
++ _index;
while (_index < _n && (level > 0 || SpecialChars.IndexOf(_path[_index]) < 0))
{
if (_path[_index] == '(')
++ level;
else if (_path[_index] == ')')
-- level;
++ _index;
}
if (level > 0)
{
SetError(SRID.UnmatchedParen, _path.Substring(start));
return;
}
if (level < 0)
{
SetError(SRID.UnmatchedParen, _path.Substring(0, _index));
return;
}
string name = _path.Substring(start, _index - start).Trim();
SourceValueInfo info = (name.Length > 0)
? new SourceValueInfo(SourceValueType.Property, _drillIn, name)
: new SourceValueInfo(SourceValueType.Direct, _drillIn, (string)null);
_al.Add(info);
StartNewLevel();
}
enum IndexerState { BeginParam, ParenString, ValueString, Done }
void AddIndexer()
{
// indexer args are parsed by a (sub-) state machine with four
// states. The string is a comma-separated list of params, each
// of which has two parts: a "paren string" and a "value string"
// (both parts are optional). The character ^ can be used to
// escape any of the special characters: comma, parens, ], ^,
// and white space.
int start = ++_index; // skip over initial [
int level = 1; // level of nested []
bool escaped = false; // true if current char is escaped
bool trimRight = false; // true if value string has trailing white space
StringBuilder parenStringBuilder = new StringBuilder();
StringBuilder valueStringBuilder = new StringBuilder();
FrugalObjectList paramList = new FrugalObjectList();
IndexerState state = IndexerState.BeginParam;
while (state != IndexerState.Done)
{
if (_index >= _n)
{
SetError(SRID.UnmatchedBracket, _path.Substring(start - 1));
return;
}
Char c = _path[_index++];
// handle the escape character - set the flag for the next character
if (c == EscapeChar && !escaped)
{
escaped = true;
continue;
}
switch (state)
{
case IndexerState.BeginParam: // look for optional (...)
if (escaped)
{
// no '(', go parse the value
state = IndexerState.ValueString;
goto case IndexerState.ValueString;
}
else if (c == '(')
{
// '(' introduces optional paren string
state = IndexerState.ParenString;
}
else if (Char.IsWhiteSpace(c))
{
// ignore leading white space
}
else
{
// no '(', go parse the value
state = IndexerState.ValueString;
goto case IndexerState.ValueString;
}
break;
case IndexerState.ParenString: // parse (...)
if (escaped)
{
// add an escaped character without question
parenStringBuilder.Append(c);
}
else if (c == ')')
{
// end of (...), start to parse value
state = IndexerState.ValueString;
}
else
{
// add normal characters inside (...)
parenStringBuilder.Append(c);
}
break;
case IndexerState.ValueString: // parse value
if (escaped)
{
// add an escaped character without question
valueStringBuilder.Append(c);
trimRight = false;
}
else if (level > 1)
{
// inside nested [], add characters without question
valueStringBuilder.Append(c);
trimRight = false;
if (c == ']')
{
--level;
}
}
else if (Char.IsWhiteSpace(c))
{
// add white space, but trim it later if it's trailing
valueStringBuilder.Append(c);
trimRight = true;
}
else if (c == ',' || c == ']')
{
// end of current paramater - assemble the two parts
string parenString = parenStringBuilder.ToString();
string valueString = valueStringBuilder.ToString();
if (trimRight)
{
valueString = valueString.TrimEnd();
}
// add the parts to the final result
paramList.Add(new IndexerParamInfo(parenString, valueString));
// reset for the next parameter
parenStringBuilder.Length = 0;
valueStringBuilder.Length = 0;
trimRight = false;
// after ',' parse next parameter; after ']' we're done
state = (c == ']') ? IndexerState.Done : IndexerState.BeginParam;
}
else
{
// add normal characters
valueStringBuilder.Append(c);
trimRight = false;
// keep track of nested []
if (c == '[')
{
++level;
}
}
break;
}
// after processing each character, clear the escape flag
escaped = false;
}
// assemble the final result
SourceValueInfo info = new SourceValueInfo(
SourceValueType.Indexer,
_drillIn, paramList);
_al.Add(info);
StartNewLevel();
}
void StartNewLevel()
{
_state = (_index < _n) ? State.DrillIn : State.Done;
_drillIn = DrillIn.Never;
}
State _state;
string _path;
int _index;
int _n;
DrillIn _drillIn;
ArrayList _al = new ArrayList();
const char NullChar = Char.MinValue;
const char EscapeChar = '^';
static SourceValueInfo[] EmptyInfo = new SourceValueInfo[0];
static string SpecialChars = @"./[]";
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- WebPartTransformerAttribute.cs
- QueryAsyncResult.cs
- TransformedBitmap.cs
- ValuePatternIdentifiers.cs
- PolicyException.cs
- MulticastOption.cs
- OuterGlowBitmapEffect.cs
- LiteralDesigner.cs
- ClientScriptManager.cs
- XmlDataLoader.cs
- CompensationParticipant.cs
- FamilyTypeface.cs
- CodeAssignStatement.cs
- DelegateTypeInfo.cs
- InkCanvas.cs
- DockingAttribute.cs
- EventProvider.cs
- JulianCalendar.cs
- AnimationLayer.cs
- SessionIDManager.cs
- IPEndPoint.cs
- Group.cs
- HttpChannelHelpers.cs
- UserValidatedEventArgs.cs
- LocalizabilityAttribute.cs
- Convert.cs
- NameTable.cs
- ChangeToolStripParentVerb.cs
- RectAnimationBase.cs
- WebPartDisplayModeCollection.cs
- ParserExtension.cs
- Missing.cs
- SelectedGridItemChangedEvent.cs
- DesignerLoader.cs
- CodeSnippetCompileUnit.cs
- Pair.cs
- BypassElementCollection.cs
- HttpResponse.cs
- InternalUserCancelledException.cs
- PcmConverter.cs
- XmlnsPrefixAttribute.cs
- XmlArrayItemAttribute.cs
- SamlAssertion.cs
- DataGridViewComboBoxColumn.cs
- EnumerableCollectionView.cs
- TextEffect.cs
- mil_commands.cs
- LambdaCompiler.Statements.cs
- OutputScope.cs
- DesignerCategoryAttribute.cs
- HtmlEmptyTagControlBuilder.cs
- UnaryNode.cs
- OleDbParameterCollection.cs
- SqlRemoveConstantOrderBy.cs
- _SSPIWrapper.cs
- PrintingPermissionAttribute.cs
- Part.cs
- AccessedThroughPropertyAttribute.cs
- Win32KeyboardDevice.cs
- Accessible.cs
- DataGridDetailsPresenter.cs
- EncodingDataItem.cs
- keycontainerpermission.cs
- UIAgentRequest.cs
- PublisherIdentityPermission.cs
- HierarchicalDataSourceControl.cs
- TextBlock.cs
- SerializationException.cs
- DoubleAnimationClockResource.cs
- QueryCursorEventArgs.cs
- AbstractSvcMapFileLoader.cs
- RuntimeResourceSet.cs
- StrokeNodeEnumerator.cs
- AppDomainResourcePerfCounters.cs
- AxHost.cs
- BehaviorEditorPart.cs
- CodeTypeParameter.cs
- DecimalStorage.cs
- Triplet.cs
- FlowLayout.cs
- EntityStoreSchemaFilterEntry.cs
- WindowProviderWrapper.cs
- XmlSerializerNamespaces.cs
- MouseButtonEventArgs.cs
- HtmlInputControl.cs
- SimpleRecyclingCache.cs
- SourceLineInfo.cs
- MobileDeviceCapabilitiesSectionHandler.cs
- ElementHost.cs
- GeometryDrawing.cs
- TypeResolver.cs
- WaitForChangedResult.cs
- XPathBinder.cs
- WebPartConnectionsCloseVerb.cs
- ReflectionTypeLoadException.cs
- WebPartConnectionsCancelEventArgs.cs
- WebServiceErrorEvent.cs
- NativeMethods.cs
- SByte.cs
- XPathSelfQuery.cs