in System.Xml/System/Xml/Core/XmlTextReaderImpl.cs [7930:8687]
private void ParseDtdFromParserContext() {
Debug.Assert( dtdInfo == null && fragmentParserContext != null && fragmentParserContext.HasDtdInfo );
IDtdParser dtdParser = DtdParser.Create();
// Parse DTD
dtdInfo = dtdParser.ParseFreeFloatingDtd(fragmentParserContext.BaseURI, fragmentParserContext.DocTypeName, fragmentParserContext.PublicId,
fragmentParserContext.SystemId, fragmentParserContext.InternalSubset, new DtdParserProxy( this ) );
#if SILVERLIGHT // Needed only for XmlTextReader or XmlValidatingReader
if (dtdInfo.HasDefaultAttributes || dtdInfo.HasNonCDataAttributes) {
#else
if ( ( validatingReaderCompatFlag || !v1Compat ) && ( dtdInfo.HasDefaultAttributes || dtdInfo.HasNonCDataAttributes ) ) {
#endif
addDefaultAttributesAndNormalize = true;
}
}
bool InitReadContentAsBinary() {
Debug.Assert( parsingFunction != ParsingFunction.InReadContentAsBinary );
if ( parsingFunction == ParsingFunction.InReadValueChunk ) {
throw new InvalidOperationException( Res.GetString( Res.Xml_MixingReadValueChunkWithBinary ) );
}
if ( parsingFunction == ParsingFunction.InIncrementalRead ) {
throw new InvalidOperationException( Res.GetString( Res.Xml_MixingV1StreamingWithV2Binary ) );
}
if ( !XmlReader.IsTextualNode( curNode.type ) ) {
if ( !MoveToNextContentNode( false ) ) {
return false;
}
}
SetupReadContentAsBinaryState( ParsingFunction.InReadContentAsBinary );
incReadLineInfo.Set( curNode.LineNo, curNode.LinePos );
return true;
}
bool InitReadElementContentAsBinary() {
Debug.Assert( parsingFunction != ParsingFunction.InReadElementContentAsBinary );
Debug.Assert( curNode.type == XmlNodeType.Element );
bool isEmpty = curNode.IsEmptyElement;
// move to content or off the empty element
outerReader.Read();
if ( isEmpty ) {
return false;
}
// make sure we are on a content node
if ( !MoveToNextContentNode( false ) ) {
if ( curNode.type != XmlNodeType.EndElement ) {
Throw( Res.Xml_InvalidNodeType, curNode.type.ToString() );
}
// move off end element
outerReader.Read();
return false;
}
SetupReadContentAsBinaryState( ParsingFunction.InReadElementContentAsBinary );
incReadLineInfo.Set( curNode.LineNo, curNode.LinePos );
return true;
}
bool MoveToNextContentNode( bool moveIfOnContentNode ) {
do {
switch ( curNode.type ) {
case XmlNodeType.Attribute:
return !moveIfOnContentNode;
case XmlNodeType.Text:
case XmlNodeType.Whitespace:
case XmlNodeType.SignificantWhitespace:
case XmlNodeType.CDATA:
if ( !moveIfOnContentNode ) {
return true;
}
break;
case XmlNodeType.ProcessingInstruction:
case XmlNodeType.Comment:
case XmlNodeType.EndEntity:
// skip comments, pis and end entity nodes
break;
case XmlNodeType.EntityReference:
outerReader.ResolveEntity();
break;
default:
return false;
}
moveIfOnContentNode = false;
} while ( outerReader.Read() );
return false;
}
void SetupReadContentAsBinaryState( ParsingFunction inReadBinaryFunction ) {
if ( parsingFunction == ParsingFunction.PartialTextValue ) {
incReadState = IncrementalReadState.ReadContentAsBinary_OnPartialValue;
}
else {
incReadState = IncrementalReadState.ReadContentAsBinary_OnCachedValue;
nextNextParsingFunction = nextParsingFunction;
nextParsingFunction = parsingFunction;
}
readValueOffset = 0;
parsingFunction = inReadBinaryFunction;
}
void SetupFromParserContext( XmlParserContext context, XmlReaderSettings settings ) {
Debug.Assert( context != null );
// setup nameTable
XmlNameTable nt = settings.NameTable;
nameTableFromSettings = ( nt != null );
// get name table from namespace manager in XmlParserContext, if available;
if ( context.NamespaceManager != null ) {
// must be the same as XmlReaderSettings.NameTable, or null
if ( nt != null && nt != context.NamespaceManager.NameTable ) {
throw new XmlException( Res.Xml_NametableMismatch );
}
// get the namespace manager from context
namespaceManager = context.NamespaceManager;
xmlContext.defaultNamespace = namespaceManager.LookupNamespace( string.Empty );
// get the nametable from ns manager
nt = namespaceManager.NameTable;
Debug.Assert( nt != null );
Debug.Assert( context.NameTable == null || context.NameTable == nt, "This check should have been done in XmlParserContext constructor." );
}
// get name table directly from XmlParserContext
else if ( context.NameTable != null ) {
// must be the same as XmlReaderSettings.NameTable, or null
if ( nt != null && nt != context.NameTable ) {
throw new XmlException( Res.Xml_NametableMismatch, string.Empty );
}
nt = context.NameTable;
}
// no nametable provided -> create a new one
else if ( nt == null ) {
nt = new NameTable();
Debug.Assert( nameTableFromSettings == false );
}
nameTable = nt;
// make sure we have namespace manager
if ( namespaceManager == null ) {
namespaceManager = new XmlNamespaceManager( nt );
}
// copy xml:space and xml:lang
xmlContext.xmlSpace = context.XmlSpace;
xmlContext.xmlLang = context.XmlLang;
}
//
// DtdInfo
//
#if !SILVERLIGHT
internal override IDtdInfo DtdInfo {
get {
return dtdInfo;
}
}
internal void SetDtdInfo(IDtdInfo newDtdInfo) {
Debug.Assert( dtdInfo == null );
dtdInfo = newDtdInfo;
if ( dtdInfo != null ) {
if ( ( validatingReaderCompatFlag || !v1Compat ) && ( dtdInfo.HasDefaultAttributes || dtdInfo.HasNonCDataAttributes ) ) {
addDefaultAttributesAndNormalize = true;
}
}
}
#endif
//
// Validation support
//
#if !SILVERLIGHT // no validation in Silverlight
internal IValidationEventHandling ValidationEventHandling {
set {
validationEventHandling = value;
}
}
internal OnDefaultAttributeUseDelegate OnDefaultAttributeUse {
set { onDefaultAttributeUse = value; }
}
#endif
//
// Internal properties for XmlValidatingReader
//
#if !SILVERLIGHT // Needed only for XmlValidatingReader
internal bool XmlValidatingReaderCompatibilityMode {
set {
validatingReaderCompatFlag = value;
// Fix for VSWhidbey 516556; These namespaces must be added to the nametable for back compat reasons.
if ( value ) {
nameTable.Add( XmlReservedNs.NsXs ); // Note: this is equal to XmlReservedNs.NsXsd in Everett
nameTable.Add( XmlReservedNs.NsXsi );
nameTable.Add( XmlReservedNs.NsDataType );
}
}
}
internal XmlNodeType FragmentType {
get {
return fragmentType;
}
}
internal void ChangeCurrentNodeType( XmlNodeType newNodeType ) {
Debug.Assert( curNode.type == XmlNodeType.Whitespace && newNodeType == XmlNodeType.SignificantWhitespace, "Incorrect node type change!" );
curNode.type = newNodeType;
}
internal XmlResolver GetResolver() {
if (IsResolverNull)
return null;
else
return xmlResolver;
}
internal object InternalSchemaType {
get {
return curNode.schemaType;
}
set {
curNode.schemaType = value;
}
}
internal object InternalTypedValue {
get {
return curNode.typedValue;
}
set {
curNode.typedValue = value;
}
}
internal bool StandAlone {
get {
return standalone;
}
}
internal override XmlNamespaceManager NamespaceManager {
get {
return namespaceManager;
}
}
internal bool V1Compat {
get {
return v1Compat;
}
}
#endif
internal ConformanceLevel V1ComformanceLevel {
get {
return fragmentType == XmlNodeType.Element ? ConformanceLevel.Fragment : ConformanceLevel.Document;
}
}
private bool AddDefaultAttributeDtd(IDtdDefaultAttributeInfo defAttrInfo, bool definedInDtd, NodeData[] nameSortedNodeData) {
if ( defAttrInfo.Prefix.Length > 0 ) {
attrNeedNamespaceLookup = true;
}
string localName = defAttrInfo.LocalName;
string prefix = defAttrInfo.Prefix;
// check for duplicates
if (nameSortedNodeData != null) {
if (Array.BinarySearch<object>(nameSortedNodeData, defAttrInfo, DtdDefaultAttributeInfoToNodeDataComparer.Instance) >= 0) {
return false;
}
}
else {
for (int i = index + 1; i < index + 1 + attrCount; i++) {
if ((object)nodes[i].localName == (object)localName &&
(object)nodes[i].prefix == (object)prefix) {
return false;
}
}
}
NodeData attr = AddDefaultAttributeInternal( defAttrInfo.LocalName, null, defAttrInfo.Prefix, defAttrInfo.DefaultValueExpanded,
defAttrInfo.LineNumber, defAttrInfo.LinePosition,
defAttrInfo.ValueLineNumber, defAttrInfo.ValueLinePosition, defAttrInfo.IsXmlAttribute );
Debug.Assert(attr != null);
#if !SILVERLIGHT
if (DtdValidation) {
if (onDefaultAttributeUse != null) {
onDefaultAttributeUse(defAttrInfo, this);
}
attr.typedValue = defAttrInfo.DefaultValueTyped;
}
#endif
return attr != null;
}
#if !SILVERLIGHT // Needed only for XmlValidatingReader
internal bool AddDefaultAttributeNonDtd( SchemaAttDef attrDef ) {
// atomize names - Xsd Validator does not need to have the same nametable
string localName = nameTable.Add( attrDef.Name.Name );
string prefix = nameTable.Add( attrDef.Prefix );
string ns = nameTable.Add( attrDef.Name.Namespace );
// atomize namespace - Xsd Validator does not need to have the same nametable
if ( prefix.Length == 0 && ns.Length > 0 ) {
prefix = namespaceManager.LookupPrefix( ns );
Debug.Assert( prefix != null );
if ( prefix == null ) {
prefix = string.Empty;
}
}
// find out if the attribute is already there
for (int i = index + 1; i < index + 1 + attrCount; i++) {
if ((object)nodes[i].localName == (object)localName &&
(((object)nodes[i].prefix == (object)prefix) || ((object)nodes[i].ns == (object)ns && ns != null))) {
return false;
}
}
// attribute does not exist -> we need to add it
NodeData attr = AddDefaultAttributeInternal( localName, ns, prefix, attrDef.DefaultValueExpanded,
attrDef.LineNumber, attrDef.LinePosition,
attrDef.ValueLineNumber, attrDef.ValueLinePosition, attrDef.Reserved != SchemaAttDef.Reserve.None );
Debug.Assert(attr != null);
attr.schemaType = (attrDef.SchemaType == null) ? (object)attrDef.Datatype : (object)attrDef.SchemaType;
attr.typedValue = attrDef.DefaultValueTyped;
return true;
}
#endif
private NodeData AddDefaultAttributeInternal(string localName, string ns, string prefix, string value,
int lineNo, int linePos, int valueLineNo, int valueLinePos, bool isXmlAttribute) {
// setup the attribute
NodeData attr = AddAttribute( localName, prefix, prefix.Length > 0 ? null : localName );
if ( ns != null ) {
attr.ns = ns;
}
attr.SetValue( value );
attr.IsDefaultAttribute = true;
attr.lineInfo.Set( lineNo, linePos );
attr.lineInfo2.Set( valueLineNo, valueLinePos );
// handle special attributes:
if ( attr.prefix.Length == 0 ) {
// default namespace declaration
if ( Ref.Equal( attr.localName, XmlNs ) ) {
OnDefaultNamespaceDecl( attr );
if ( !attrNeedNamespaceLookup ) {
// change element default namespace
Debug.Assert( nodes[index].type == XmlNodeType.Element );
if ( nodes[index].prefix.Length == 0 ) {
nodes[index].ns = xmlContext.defaultNamespace;
}
}
}
}
else {
// prefixed namespace declaration
if ( Ref.Equal( attr.prefix, XmlNs ) ) {
OnNamespaceDecl( attr );
if ( !attrNeedNamespaceLookup ) {
// change namespace of current element and attributes
string pref = attr.localName;
Debug.Assert( nodes[index].type == XmlNodeType.Element );
for ( int i = index; i < index + attrCount + 1; i++ ) {
if ( nodes[i].prefix.Equals( pref ) ) {
nodes[i].ns = namespaceManager.LookupNamespace( pref );
}
}
}
}
// xml: attribute
else {
if ( isXmlAttribute ) {
OnXmlReservedAttribute( attr );
}
}
}
fullAttrCleanup = true;
return attr;
}
#if !SILVERLIGHT // Needed only for XmlTextReader (when used from XmlDocument)
internal bool DisableUndeclaredEntityCheck {
set {
disableUndeclaredEntityCheck = value;
}
}
#endif
int ReadContentAsBinary( byte[] buffer, int index, int count ) {
Debug.Assert( incReadDecoder != null );
if ( incReadState == IncrementalReadState.ReadContentAsBinary_End ) {
return 0;
}
incReadDecoder.SetNextOutputBuffer( buffer, index, count );
for (;;) {
// read what is already cached in curNode
int charsRead = 0;
try {
charsRead = curNode.CopyToBinary( incReadDecoder, readValueOffset );
}
// add line info to the exception
catch ( XmlException e ) {
curNode.AdjustLineInfo( readValueOffset, ps.eolNormalized, ref incReadLineInfo );
ReThrow( e, incReadLineInfo.lineNo, incReadLineInfo.linePos );
}
readValueOffset += charsRead;
if ( incReadDecoder.IsFull ) {
return incReadDecoder.DecodedCount;
}
// if on partial value, read the rest of it
if ( incReadState == IncrementalReadState.ReadContentAsBinary_OnPartialValue ) {
curNode.SetValue( string.Empty );
// read next chunk of text
bool endOfValue = false;
int startPos = 0;
int endPos = 0;
while ( !incReadDecoder.IsFull && !endOfValue ) {
int orChars = 0;
// store current line info and parse more text
incReadLineInfo.Set( ps.LineNo, ps.LinePos );
endOfValue = ParseText( out startPos, out endPos, ref orChars );
try {
charsRead = incReadDecoder.Decode( ps.chars, startPos, endPos - startPos );
}
// add line info to the exception
catch ( XmlException e ) {
ReThrow( e, incReadLineInfo.lineNo, incReadLineInfo.linePos);
}
startPos += charsRead;
}
incReadState = endOfValue ? IncrementalReadState.ReadContentAsBinary_OnCachedValue : IncrementalReadState.ReadContentAsBinary_OnPartialValue;
readValueOffset = 0;
if ( incReadDecoder.IsFull ) {
curNode.SetValue( ps.chars, startPos, endPos - startPos );
// adjust line info for the chunk that has been already decoded
AdjustLineInfo( ps.chars, startPos - charsRead, startPos, ps.eolNormalized, ref incReadLineInfo );
curNode.SetLineInfo( incReadLineInfo.lineNo, incReadLineInfo.linePos );
return incReadDecoder.DecodedCount;
}
}
// reset to normal state so we can call Read() to move forward
ParsingFunction tmp = parsingFunction;
parsingFunction = nextParsingFunction;
nextParsingFunction = nextNextParsingFunction;
// move to next textual node in the element content; throw on sub elements
if ( !MoveToNextContentNode( true ) ) {
SetupReadContentAsBinaryState( tmp );
incReadState = IncrementalReadState.ReadContentAsBinary_End;
return incReadDecoder.DecodedCount;
}
SetupReadContentAsBinaryState( tmp );
incReadLineInfo.Set( curNode.LineNo, curNode.LinePos );
}
}
int ReadElementContentAsBinary( byte[] buffer, int index, int count ) {
if ( count == 0 ) {
return 0;
}
int decoded = ReadContentAsBinary( buffer, index, count );
if ( decoded > 0 ) {
return decoded;
}
// if 0 bytes returned check if we are on a closing EndElement, throw exception if not
if ( curNode.type != XmlNodeType.EndElement ) {
throw new XmlException( Res.Xml_InvalidNodeType, curNode.type.ToString(), this as IXmlLineInfo );
}
// reset state
parsingFunction = nextParsingFunction;
nextParsingFunction = nextNextParsingFunction;
Debug.Assert( parsingFunction != ParsingFunction.InReadElementContentAsBinary );
// move off the EndElement
outerReader.Read();
return 0;
}
void InitBase64Decoder() {
if ( base64Decoder == null ) {
base64Decoder = new Base64Decoder();
}
else {
base64Decoder.Reset();
}
incReadDecoder = base64Decoder;
}
void InitBinHexDecoder() {
if ( binHexDecoder == null ) {
binHexDecoder = new BinHexDecoder();
}
else {
binHexDecoder.Reset();
}
incReadDecoder = binHexDecoder;
}
// SxS: URIs are resolved only to be compared. No resource exposure. It's OK to suppress the SxS warning.
#if !SILVERLIGHT
[ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
[ResourceExposure(ResourceScope.None)]
#endif
bool UriEqual( Uri uri1, string uri1Str, string uri2Str, XmlResolver resolver ) {
if (resolver == null) {
return uri1Str == uri2Str;
}
if (uri1 == null){
uri1 = resolver.ResolveUri( null, uri1Str );
}
Uri uri2 = resolver.ResolveUri( null, uri2Str );
return uri1.Equals(uri2);
}
/// <summary>
/// This method should be called every time the reader is about to consume some number of
/// characters from the input. It will count it agains the security counters and
/// may throw if some of the security limits are exceeded.
/// </summary>
/// <param name="characters">Number of characters to be consumed.</param>
/// <param name="inEntityReference">true if the characters are result of entity expansion.</param>
void RegisterConsumedCharacters(long characters, bool inEntityReference) {
Debug.Assert(characters >= 0);
if (maxCharactersInDocument > 0) {
long newCharactersInDocument = charactersInDocument + characters;
if (newCharactersInDocument < charactersInDocument) {
// Integer overflow while counting
ThrowWithoutLineInfo(Res.Xml_LimitExceeded, "MaxCharactersInDocument");
}
else {
charactersInDocument = newCharactersInDocument;
}
if (charactersInDocument > maxCharactersInDocument) {
// The limit was exceeded for the total number of characters in the document
ThrowWithoutLineInfo(Res.Xml_LimitExceeded, "MaxCharactersInDocument");
}
}
if (maxCharactersFromEntities > 0 && inEntityReference) {
long newCharactersFromEntities = charactersFromEntities + characters;
if (newCharactersFromEntities < charactersFromEntities) {
// Integer overflow while counting
ThrowWithoutLineInfo(Res.Xml_LimitExceeded, "MaxCharactersFromEntities");
}
else {
charactersFromEntities = newCharactersFromEntities;
}
if ( charactersFromEntities > maxCharactersFromEntities) {
// The limit was exceeded for the number of characters from entities
ThrowWithoutLineInfo(Res.Xml_LimitExceeded, "MaxCharactersFromEntities");
}
}
}
#if SILVERLIGHT && !SILVERLIGHT_DISABLE_SECURITY
[System.Security.SecuritySafeCritical]
#endif
static internal unsafe void AdjustLineInfo(char[] chars, int startPos, int endPos, bool isNormalized, ref LineInfo lineInfo) {
Debug.Assert(startPos >= 0);
Debug.Assert(endPos < chars.Length);
Debug.Assert(startPos <= endPos);
fixed (char* pChars = &chars[startPos]) {
AdjustLineInfo(pChars, endPos - startPos, isNormalized, ref lineInfo);
}
}
#if SILVERLIGHT && !SILVERLIGHT_DISABLE_SECURITY
[System.Security.SecuritySafeCritical]
#endif
static internal unsafe void AdjustLineInfo(string str, int startPos, int endPos, bool isNormalized, ref LineInfo lineInfo) {
Debug.Assert(startPos >= 0);
Debug.Assert(endPos < str.Length);
Debug.Assert(startPos <= endPos);
fixed (char* pChars = str) {
AdjustLineInfo(pChars + startPos, endPos - startPos, isNormalized, ref lineInfo);
}
}
#if SILVERLIGHT
[System.Security.SecurityCritical]
#endif
static internal unsafe void AdjustLineInfo(char* pChars, int length, bool isNormalized, ref LineInfo lineInfo) {
int lastNewLinePos = -1;
for (int i = 0; i < length; i++) {
switch (pChars[i]) {
case '\n':
lineInfo.lineNo++;
lastNewLinePos = i;
break;
case '\r':
if (isNormalized) {
break;
}
lineInfo.lineNo++;
lastNewLinePos = i;
if (i + 1 < length && pChars[i + 1] == '\n') {
i++;
lastNewLinePos++;
}
break;
}
}
if (lastNewLinePos >= 0) {
lineInfo.linePos = length - lastNewLinePos;
}
}
// StripSpaces removes spaces at the beginning and at the end of the value and replaces sequences of spaces with a single space
internal static string StripSpaces( string value ) {
int len = value.Length;
if ( len <= 0 ) {
return string.Empty;
}
int startPos = 0;
StringBuilder norValue = null;
while ( value[startPos] == 0x20 ) {
startPos++;
if ( startPos == len ) {
return " ";
}
}
int i;
for ( i = startPos; i < len; i++ ) {
if ( value[i] == 0x20 ) {
int j = i + 1;
while ( j < len && value[j] == 0x20 ) {
j++;
}
if ( j == len ) {
if ( norValue == null ) {
return value.Substring( startPos, i - startPos );
}
else {
norValue.Append( value, startPos, i - startPos );
return norValue.ToString();
}
}
if ( j > i + 1 ) {
if ( norValue == null ) {
norValue = new StringBuilder( len );
}
norValue.Append( value, startPos, i - startPos + 1 );
startPos = j;
i = j - 1;
}
}
}
if ( norValue == null ) {
return ( startPos == 0 ) ? value : value.Substring( startPos, len - startPos );
}
else {
if ( i > startPos ) {
norValue.Append( value, startPos, i - startPos );
}
return norValue.ToString();
}
}
// StripSpaces removes spaces at the beginning and at the end of the value and replaces sequences of spaces with a single space
internal static void StripSpaces( char[] value, int index, ref int len ) {
if ( len <= 0 ) {
return;
}
int startPos = index;
int endPos = index + len;
while ( value[startPos] == 0x20 ) {
startPos++;
if ( startPos == endPos ) {
len = 1;
return;
}
}
int offset = startPos - index;
int i;
for ( i = startPos; i < endPos; i++ ) {
char ch;
if ( ( ch = value[i] ) == 0x20 ) {
int j = i + 1;
while ( j < endPos && value[j] == 0x20 ) {
j++;
}
if ( j == endPos ) {
offset += ( j - i );
break;
}
if ( j > i+1 ) {
offset += ( j - i - 1 );
i = j - 1;
}
}
value[i-offset] = ch;
}
len -= offset;
}
internal static void BlockCopyChars(char[] src, int srcOffset, char[] dst, int dstOffset, int count) {
// PERF: Buffer.BlockCopy is faster than Array.Copy
#if SILVERLIGHT
Array.Copy( src, srcOffset, dst, dstOffset, count );
#else
Buffer.BlockCopy( src, srcOffset * sizeof(char), dst, dstOffset * sizeof(char), count * sizeof(char) );
#endif
}
internal static void BlockCopy( byte[] src, int srcOffset, byte[] dst, int dstOffset, int count ) {
#if SILVERLIGHT
Array.Copy( src, srcOffset, dst, dstOffset, count );
#else
Buffer.BlockCopy(src, srcOffset, dst, dstOffset, count);
#endif
}
}