context: using System;
  using System.Collections.Generic;
  using System.Text;
  using System.Xml;
  using System.IO;
  using System.Diagnostics;
  
  namespace Microsoft.Web.XmlTransform
  {
      public class XmlFileInfoDocument : XmlDocument, IDisposable
      {
          private Encoding _textEncoding = null;
          private XmlTextReader _reader = null;
          private XmlAttributePreservationProvider _preservationProvider = null;
          private bool _firstLoad = true;
          private string _fileName = null;
  
          private int _lineNumberOffset = 0;
          private int _linePositionOffset = 0;
  
          public override void Load(string filename) {
              LoadFromFileName(filename);
  
              _firstLoad = false;
          }
  
          public override void Load(XmlReader reader) {
              _reader = reader as XmlTextReader;
              if (_reader != null) {
                  _fileName = _reader.BaseURI;
              }
  
              base.Load(reader);
  
              if (_reader != null) {
                  _textEncoding = _reader.Encoding;
              }
  
              _firstLoad = false;
          }
  
          private void LoadFromFileName(string filename) {
              _fileName = filename;
  
              StreamReader reader = null;
              try {
                  if (PreserveWhitespace) {
                      _preservationProvider = new XmlAttributePreservationProvider(filename);
                  }
  
                  reader = new StreamReader(filename, true);
                  LoadFromTextReader(reader);
              }
              finally {
                  if (_preservationProvider != null)
                  {
                      _preservationProvider.Close();
                      _preservationProvider = null;
                  }
                  if (reader != null) {
                      reader.Close();
                  }
              }
          }
  
          private void LoadFromTextReader(TextReader textReader) {
              StreamReader streamReader = textReader as StreamReader;
              if (streamReader != null) {
                  FileStream fileStream = streamReader.BaseStream as FileStream;
                  if (fileStream != null) {
                      _fileName = fileStream.Name;
                  }
  
                  _textEncoding = GetEncodingFromStream(streamReader.BaseStream);
              }
  
              _reader = new XmlTextReader(_fileName, textReader);
  
              base.Load(_reader);
  
              if (_textEncoding == null) {
                  _textEncoding = _reader.Encoding;
              }
          }
  
          private Encoding GetEncodingFromStream(Stream stream) {
              Encoding encoding = null;
              if (stream.CanSeek) {
                  byte[] buffer = new byte[3];
                  stream.Read(buffer, 0, buffer.Length);
  
                  if (buffer[0] == 0xEF && buffer[1] == 0xBB && buffer[2] == 0xBF)
                      encoding = Encoding.UTF8;
                  else if (buffer[0] == 0xFE && buffer[1] == 0xFF)
                      encoding = Encoding.BigEndianUnicode;
                  else if (buffer[0] == 0xFF && buffer[1] == 0xFE)
                      encoding = Encoding.Unicode;
                  else if (buffer[0] == 0x2B && buffer[1] == 0x2F && buffer[2] == 0x76)
                      encoding = Encoding.UTF7;
  
                  // Reset the stream
                  stream.Seek(0, SeekOrigin.Begin);
              }
  
              return encoding;
          }
  
          internal XmlNode CloneNodeFromOtherDocument(XmlNode element) {
              XmlTextReader oldReader = _reader;
              string oldFileName = _fileName;
  
              XmlNode clone = null;
              try {
                  IXmlLineInfo lineInfo = element as IXmlLineInfo;
                  if (lineInfo != null) {
                      _reader = new XmlTextReader(new StringReader(element.OuterXml));
  
                      _lineNumberOffset = lineInfo.LineNumber - 1;
                      _linePositionOffset = lineInfo.LinePosition - 2;
                      _fileName = element.OwnerDocument.BaseURI;
  
                      clone = ReadNode(_reader);
                  }
                  else {
                      _fileName = null;
                      _reader = null;
  
                      clone = ReadNode(new XmlTextReader(new StringReader(element.OuterXml)));
                  }
              }
              finally {
                  _lineNumberOffset = 0;
                  _linePositionOffset = 0;
                  _fileName = oldFileName;
  
                  _reader = oldReader;
              }
  
              return clone;
          }
  
          internal bool HasErrorInfo {
              get {
                  return _reader != null;
              }
          }
  
          internal string FileName {
              get {
                  return _fileName;
              }
          }
  
          private int CurrentLineNumber {
              get {
                  return _reader != null ? _reader.LineNumber + _lineNumberOffset : 0;
              }
          }
  
          private int CurrentLinePosition {
              get {
                  return _reader != null ? _reader.LinePosition + _linePositionOffset : 0;
              }
          }
  
          private bool FirstLoad {
              get {
                  return _firstLoad;
              }
          }
  
          private XmlAttributePreservationProvider PreservationProvider {
              get {
                  return _preservationProvider;
              }
          }
  
          private Encoding TextEncoding {
              get {
                  if (_textEncoding != null) {
                      return _textEncoding;
                  }
                  else {
                      // Copied from base implementation of XmlDocument
                      if (HasChildNodes) {
                          XmlDeclaration declaration = FirstChild as XmlDeclaration;
                          if (declaration != null) {
                              string value = declaration.Encoding;
                              if (value.Length > 0) {
                                  return System.Text.Encoding.GetEncoding(value);
                              }
                          }
                      }
                  }
                  return null;
              }
          }
  
          public override void Save(string filename)
          {
              XmlWriter xmlWriter = null;
              try{
                  if (PreserveWhitespace){
                      XmlFormatter.Format(this);
                      xmlWriter = new XmlAttributePreservingWriter(filename, TextEncoding);
                  }
                  else {
                      XmlTextWriter textWriter = new XmlTextWriter(filename, TextEncoding);
                      textWriter.Formatting = Formatting.Indented;
                      xmlWriter = textWriter;
                  }
                  WriteTo(xmlWriter);
              }
              finally {
                  if (xmlWriter != null) {
                      xmlWriter.Flush();
                      xmlWriter.Close();
                  }
              }
          }
  
          public override void Save(Stream w)
          {
              XmlWriter xmlWriter = null;
              try {
                  if (PreserveWhitespace) {
                      XmlFormatter.Format(this);
                      xmlWriter = new XmlAttributePreservingWriter(w, TextEncoding);
                  }
                  else {
  
gt:                     XmlTextWriter textWriter = new XmlTextWriter(w, TextEncoding);