XmlTextWriter2.cs 38 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436
  1. //
  2. // XmlTextWriter.cs
  3. //
  4. // Author:
  5. // Atsushi Enomoto <[email protected]>
  6. //
  7. // Copyright (C) 2006 Novell, Inc.
  8. //
  9. // Permission is hereby granted, free of charge, to any person obtaining
  10. // a copy of this software and associated documentation files (the
  11. // "Software"), to deal in the Software without restriction, including
  12. // without limitation the rights to use, copy, modify, merge, publish,
  13. // distribute, sublicense, and/or sell copies of the Software, and to
  14. // permit persons to whom the Software is furnished to do so, subject to
  15. // the following conditions:
  16. //
  17. // The above copyright notice and this permission notice shall be
  18. // included in all copies or substantial portions of the Software.
  19. //
  20. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  21. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  22. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  23. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  24. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  25. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  26. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  27. //
  28. using System;
  29. using System.Collections;
  30. using System.Globalization;
  31. using System.IO;
  32. using System.Text;
  33. using System.Xml;
  34. /*
  35. This is a fresh implementation of XmlTextWriter since Mono 1.1.14.
  36. Here are some implementation notes (mostly common to previous module):
  37. - WriteProcessingInstruction() does not reject 'X' 'M' 'L'
  38. XmlWriter violates section 2.6 of W3C XML 1.0 specification (3rd.
  39. edition) since it incorrectly allows such PI target that consists of
  40. case-insensitive sequence of 'X' - 'M' - 'L'. This is XmlWriter API
  41. design failure which does not provide perfect WriteStartDocument().
  42. - XmlTextWriter does not escape trailing ']' in internal subset.
  43. The fact is as this subsection title shows. It means, to make an
  44. XmlWriter compatible with other XmlWriters, it should always escape
  45. the trailing ']' of the input, but XmlTextWriter runs no check.
  46. - Prefix autogeneration for global attributes
  47. When an attribute has a non-empty namespace URI, the prefix must be
  48. non-empty string (since if the prefix is empty it is regarded as a
  49. local attribute). In such case, a dummy prefix must be created.
  50. Since attributes are written to TextWriter almost immediately, the
  51. same prefix might appear in the later attributes.
  52. - Namespace context
  53. Namespace handling in XmlTextWriter is pretty nasty.
  54. First of all, if WriteStartElement() takes null namespaceURI, then
  55. the element has no explicit namespace and it is treated as if
  56. Namespaces property were set as false.
  57. Namespace context is structured by some writer methods:
  58. - WriteStartElement() : If it has a non-empty argument prefix, then
  59. the new prefix is bound to the argument namespaceURI. If prefix
  60. is "" and namespaceURI is not empty, then it consists of a
  61. default namespace.
  62. - WriteStartAttribute() : there are two namespace provisions here:
  63. 1) like WriteStartElement() prefix and namespaceURI are not empty
  64. 2) prefix is "xmlns", or localName is "xmlns" and prefix is ""
  65. If prefix is "" and namespaceURI is not empty, then the prefix is
  66. "mocked up" (since an empty prefix is not possible for attributes).
  67. - WriteQualifiedName() : the argument name and namespaceURI creates
  68. a new namespace mapping. Note that default namespace (prefix "")
  69. is not constructed at the state of WriteState.Attribute.
  70. Note that WriteElementString() internally calls WriteStartElement()
  71. and WriteAttributeString() internally calls WriteStartAttribute().
  72. Sometimes those namespace outputs are in conflict. For example, if
  73. w.WriteStartElement ("p", "foo", "urn:foo");
  74. w.WriteStartAttribute ("xmlns", "p", "urn:bar");
  75. w.WriteEndElement ();
  76. urn:foo will be lost.
  77. Here are the rules:
  78. - If either prefix or localName is explicitly "xmlns" in
  79. WriteStartAttribute(), it takes the highest precedence.
  80. - For WriteStartElement(), prefix is always preserved, but
  81. namespaceURI context might not (because of the rule above).
  82. - For WriteStartAttribute(), prefix is preserved only if there is
  83. no previous mapping in the local element. If it is in conflict,
  84. a new prefix is "mocked up" like an empty prefix.
  85. - DetermineAttributePrefix(): local mapping overwrite
  86. (do not change this section title unless you also change cross
  87. references in this file.)
  88. Even if the prefix is already mapped to another namespace, it might
  89. be overridable because the conflicting mapping might reside in one
  90. of the ancestors.
  91. To check it, we once try to remove existing mapping. If it is
  92. successfully removed, then the mapping is locally added. In that
  93. case, we cannot override it, so mock another prefix up.
  94. - Attribute value preservation
  95. Since xmlns and xml:* attributes are used to determine some public
  96. behaviors such as XmlLang, XmlSpace and LookupPrefix(), it must
  97. preserve what value is being written. At the same time, users might
  98. call WriteString(), WhiteEntityRef() etc. separately, in such cases
  99. we must preserve what is output to the stream.
  100. This preservation is done using a "temporary preservation buffer",
  101. the output Flush() behavior is different from MS. In such case that
  102. XmlTextWriter uses that buffer, it won't be write anything until
  103. XmlTextWriter.WriteEndAttribute() is called. If we implement it like
  104. MS, it results in meaningless performance loss (it is not something
  105. people should expect. There is no solid behavior on when start tag
  106. closing '>' is written).
  107. */
  108. #if NET_1_1
  109. namespace System.Xml
  110. #else
  111. namespace Mono.Xml
  112. #endif
  113. {
  114. public class XmlTextWriter : XmlWriter
  115. {
  116. // Static/constant members.
  117. const string XmlNamespace = "http://www.w3.org/XML/1998/namespace";
  118. const string XmlnsNamespace = "http://www.w3.org/2000/xmlns/";
  119. static readonly Encoding unmarked_utf8encoding =
  120. new UTF8Encoding (false, false);
  121. static char [] escaped_text_chars;
  122. static char [] escaped_attr_chars;
  123. // Internal classes
  124. class XmlNodeInfo
  125. {
  126. public string Prefix;
  127. public string LocalName;
  128. public string NS;
  129. public bool HasSimple;
  130. public bool HasElements;
  131. public string XmlLang;
  132. public XmlSpace XmlSpace;
  133. }
  134. internal class StringUtil
  135. {
  136. static CultureInfo cul = CultureInfo.InvariantCulture;
  137. static CompareInfo cmp =
  138. CultureInfo.InvariantCulture.CompareInfo;
  139. public static int IndexOf (string src, string target)
  140. {
  141. return cmp.IndexOf (src, target);
  142. }
  143. public static int Compare (string s1, string s2)
  144. {
  145. return cmp.Compare (s1, s2);
  146. }
  147. public static string Format (
  148. string format, params object [] args)
  149. {
  150. return String.Format (cul, format, args);
  151. }
  152. }
  153. // Instance fields
  154. Stream base_stream;
  155. TextWriter source; // the input TextWriter to .ctor().
  156. TextWriter writer;
  157. // It is used for storing xml:space, xml:lang and xmlns values.
  158. StringWriter preserver;
  159. string preserved_name;
  160. bool is_preserved_xmlns;
  161. bool allow_doc_fragment;
  162. bool close_output_stream = true;
  163. bool ignore_encoding;
  164. bool namespaces = true;
  165. bool output_xmldecl = false;
  166. bool check_character_validity;
  167. NewLineHandling newline_handling = NewLineHandling.None;
  168. bool is_document_entity;
  169. WriteState state = WriteState.Start;
  170. XmlNodeType node_state = XmlNodeType.None;
  171. XmlNamespaceManager nsmanager;
  172. int open_count;
  173. XmlNodeInfo [] elements = new XmlNodeInfo [10];
  174. Stack new_local_namespaces = new Stack ();
  175. ArrayList explicit_nsdecls = new ArrayList ();
  176. bool indent;
  177. int indent_count = 2;
  178. char indent_char = ' ';
  179. string indent_string = " ";
  180. string newline;
  181. bool indent_attributes;
  182. char quote_char = '"';
  183. // Constructors
  184. public XmlTextWriter (string filename, Encoding encoding)
  185. : this (new FileStream (filename, FileMode.Create, FileAccess.Write, FileShare.None), encoding)
  186. {
  187. }
  188. public XmlTextWriter (Stream stream, Encoding encoding)
  189. : this (new StreamWriter (stream,
  190. encoding == null ? unmarked_utf8encoding : encoding))
  191. {
  192. ignore_encoding = (encoding == null);
  193. Initialize (writer);
  194. allow_doc_fragment = true;
  195. }
  196. public XmlTextWriter (TextWriter writer)
  197. {
  198. Initialize (writer);
  199. allow_doc_fragment = true;
  200. }
  201. #if NET_2_0
  202. XmlTextWriter (
  203. TextWriter writer, XmlWriterSettings settings)
  204. {
  205. if (settings == null)
  206. settings = new XmlWriterSettings ();
  207. Initialize (writer);
  208. close_output_stream = settings.CloseOutput;
  209. allow_doc_fragment =
  210. settings.ConformanceLevel != System.Xml.ConformanceLevel.Document;
  211. indent_string = settings.IndentChars == null ?
  212. String.Empty : settings.IndentChars;
  213. if (settings.NewLineChars != null)
  214. newline = settings.NewLineChars;
  215. indent_attributes = settings.NewLineOnAttributes;
  216. check_character_validity = settings.CheckCharacters;
  217. newline_handling = settings.NewLineHandling;
  218. if (settings.OmitXmlDeclaration)
  219. output_xmldecl = false;
  220. }
  221. #endif
  222. void Initialize (TextWriter writer)
  223. {
  224. XmlNameTable name_table = new NameTable ();
  225. this.writer = writer;
  226. if (writer is StreamWriter)
  227. base_stream = ((StreamWriter) writer).BaseStream;
  228. source = writer;
  229. nsmanager = new XmlNamespaceManager (name_table);
  230. newline = writer.NewLine;
  231. escaped_text_chars =
  232. newline_handling != NewLineHandling.None ?
  233. new char [] {'&', '<', '>', '\r', '\n'} :
  234. new char [] {'&', '<', '>'};
  235. escaped_attr_chars =
  236. new char [] {'"', '&', '<', '>', '\r', '\n'};
  237. }
  238. #if NET_2_0
  239. // 2.0 XmlWriterSettings support
  240. internal bool CheckCharacters {
  241. set { check_character_validity = value; }
  242. }
  243. internal bool CloseOutput {
  244. set { close_output_stream = value; }
  245. }
  246. // As for ConformanceLevel, MS.NET is inconsistent with
  247. // MSDN documentation. For example, even if ConformanceLevel
  248. // is set as .Auto, multiple WriteStartDocument() calls
  249. // result in an error.
  250. // ms-help://MS.NETFramework.v20.en/wd_xml/html/7db8802b-53d8-4735-a637-4d2d2158d643.htm
  251. [MonoTODO]
  252. internal ConformanceLevel ConformanceLevel {
  253. set {
  254. allow_doc_fragment = (value == System.Xml.ConformanceLevel.Fragment);
  255. }
  256. }
  257. internal string IndentChars {
  258. set { indent_string = (value == null) ? String.Empty : value; }
  259. }
  260. internal string NewLineChars {
  261. set { newline = (value == null) ? String.Empty : value; }
  262. }
  263. internal bool NewLineOnAttributes {
  264. set { indent_attributes = value; }
  265. }
  266. internal bool OmitXmlDeclaration {
  267. set { output_xmldecl = !value; }
  268. }
  269. #endif
  270. // Literal Output Control
  271. public Formatting Formatting {
  272. get { return indent ? Formatting.Indented : Formatting.None; }
  273. set {
  274. if (state != WriteState.Start)
  275. throw InvalidOperation ("Formatting must be set before it is actually used to write output.");
  276. indent = (value == Formatting.Indented);
  277. }
  278. }
  279. public int Indentation {
  280. get { return indent_count; }
  281. set {
  282. if (value < 0)
  283. throw ArgumentError ("Indentation must be non-negative integer.");
  284. indent_count = value;
  285. indent_string = value == 0 ? String.Empty :
  286. new string (indent_char, indent_count);
  287. }
  288. }
  289. public char IndentChar {
  290. get { return indent_char; }
  291. set {
  292. indent_char = value;
  293. indent_string = new string (indent_char, indent_count);
  294. }
  295. }
  296. public char QuoteChar {
  297. get { return quote_char; }
  298. set {
  299. if (state == WriteState.Attribute)
  300. throw InvalidOperation ("QuoteChar must not be changed inside attribute value.");
  301. if ((value != '\'') && (value != '\"'))
  302. throw ArgumentError ("Only ' and \" are allowed as an attribute quote character.");
  303. quote_char = value;
  304. escaped_attr_chars [0] = quote_char;
  305. }
  306. }
  307. // Context Retriever
  308. public override string XmlLang {
  309. get { return open_count == 0 ? null : elements [open_count - 1].XmlLang; }
  310. }
  311. public override XmlSpace XmlSpace {
  312. get { return open_count == 0 ? XmlSpace.None : elements [open_count - 1].XmlSpace; }
  313. }
  314. public override WriteState WriteState {
  315. get { return state; }
  316. }
  317. public override string LookupPrefix (string namespaceUri)
  318. {
  319. if (namespaceUri == null || namespaceUri == String.Empty)
  320. throw ArgumentError ("The Namespace cannot be empty.");
  321. if (namespaceUri == nsmanager.DefaultNamespace)
  322. return String.Empty;
  323. string prefix = nsmanager.LookupPrefixExclusive (
  324. namespaceUri, false);
  325. // XmlNamespaceManager has changed to return null
  326. // when NSURI not found.
  327. // (Contradiction to the ECMA documentation.)
  328. return prefix;
  329. }
  330. // Stream Control
  331. public Stream BaseStream {
  332. get { return base_stream; }
  333. }
  334. public override void Close ()
  335. {
  336. if (state == WriteState.Attribute)
  337. WriteEndAttribute ();
  338. while (open_count > 0)
  339. WriteEndElement ();
  340. if (close_output_stream)
  341. writer.Close ();
  342. else
  343. writer.Flush ();
  344. state = WriteState.Closed;
  345. }
  346. public override void Flush ()
  347. {
  348. writer.Flush ();
  349. }
  350. // Misc Control
  351. public bool Namespaces {
  352. get { return namespaces; }
  353. set {
  354. if (state != WriteState.Start)
  355. throw InvalidOperation ("This property must be set before writing output.");
  356. namespaces = value;
  357. }
  358. }
  359. // XML Declaration
  360. public override void WriteStartDocument ()
  361. {
  362. WriteStartDocumentCore (false, false);
  363. is_document_entity = true;
  364. }
  365. public override void WriteStartDocument (bool standalone)
  366. {
  367. WriteStartDocumentCore (true, standalone);
  368. is_document_entity = true;
  369. }
  370. void WriteStartDocumentCore (bool outputStd, bool standalone)
  371. {
  372. if (state != WriteState.Start)
  373. throw StateError ("XmlDeclaration");
  374. writer.Write ("<?xml version=");
  375. writer.Write (quote_char);
  376. writer.Write ("1.0");
  377. writer.Write (quote_char);
  378. if (!ignore_encoding) {
  379. writer.Write (" encoding=");
  380. writer.Write (quote_char);
  381. writer.Write (writer.Encoding.WebName);
  382. writer.Write (quote_char);
  383. }
  384. if (outputStd) {
  385. writer.Write (" standalone=");
  386. writer.Write (quote_char);
  387. writer.Write (standalone ? "yes" : "no");
  388. writer.Write (quote_char);
  389. }
  390. writer.Write ("?>");
  391. output_xmldecl = false;
  392. state = WriteState.Prolog;
  393. }
  394. public override void WriteEndDocument ()
  395. {
  396. switch (state) {
  397. #if NET_2_0
  398. case WriteState.Error:
  399. #endif
  400. case WriteState.Closed:
  401. case WriteState.Start:
  402. throw StateError ("EndDocument");
  403. }
  404. if (state == WriteState.Attribute)
  405. WriteEndAttribute ();
  406. while (open_count > 0)
  407. WriteEndElement ();
  408. state = WriteState.Start;
  409. is_document_entity = false;
  410. }
  411. // DocType Declaration
  412. public override void WriteDocType (string name,
  413. string pubid, string sysid, string subset)
  414. {
  415. if (name == null)
  416. throw ArgumentError ("name");
  417. if (!XmlChar.IsName (name))
  418. throw ArgumentError ("name");
  419. if (node_state != XmlNodeType.None)
  420. throw StateError ("DocType");
  421. node_state = XmlNodeType.DocumentType;
  422. if (output_xmldecl)
  423. OutputAutoStartDocument ();
  424. WriteIndent ();
  425. writer.Write ("<!DOCTYPE ");
  426. writer.Write (name);
  427. if (pubid != null) {
  428. writer.Write (" PUBLIC ");
  429. writer.Write (quote_char);
  430. writer.Write (pubid);
  431. writer.Write (quote_char);
  432. writer.Write (' ');
  433. writer.Write (quote_char);
  434. if (sysid != null)
  435. writer.Write (sysid);
  436. writer.Write (quote_char);
  437. }
  438. else if (sysid != null) {
  439. writer.Write (" SYSTEM ");
  440. writer.Write (quote_char);
  441. writer.Write (sysid);
  442. writer.Write (quote_char);
  443. }
  444. if (subset != null) {
  445. writer.Write ("[");
  446. // LAMESPEC: see the top of this source.
  447. writer.Write (subset);
  448. writer.Write ("]");
  449. }
  450. writer.Write ('>');
  451. state = WriteState.Prolog;
  452. }
  453. // StartElement
  454. public override void WriteStartElement (
  455. string prefix, string localName, string namespaceUri)
  456. {
  457. #if NET_2_0
  458. if (state == WriteState.Error || state == WriteState.Closed)
  459. #else
  460. if (state == WriteState.Closed)
  461. #endif
  462. throw StateError ("StartTag");
  463. node_state = XmlNodeType.Element;
  464. bool anonPrefix = (prefix == null);
  465. if (prefix == null)
  466. prefix = String.Empty;
  467. // Crazy namespace check goes here.
  468. //
  469. // 1. if Namespaces is false, then any significant
  470. // namespace indication is not allowed.
  471. // 2. if Prefix is non-empty and NamespaceURI is
  472. // empty, it is an error in 1.x, or it is reset to
  473. // an empty string in 2.0.
  474. // 3. null NamespaceURI indicates that namespace is
  475. // not considered.
  476. // 4. prefix must not be equivalent to "XML" in
  477. // case-insensitive comparison.
  478. if (!namespaces && namespaceUri != null && namespaceUri.Length > 0)
  479. throw ArgumentError ("Namespace is disabled in this XmlTextWriter.");
  480. if (!namespaces && prefix.Length > 0)
  481. throw ArgumentError ("Namespace prefix is disabled in this XmlTextWriter.");
  482. if (prefix.Length > 0 && namespaceUri == null)
  483. throw ArgumentError ("Namespace URI must not be null when prefix is not an empty string.");
  484. // Considering the fact that WriteStartAttribute()
  485. // automatically changes argument namespaceURI, this
  486. // is kind of silly implementation. See bug #77094.
  487. if (namespaces &&
  488. prefix != null && prefix.Length == 3 &&
  489. namespaceUri != XmlNamespace &&
  490. (prefix [0] == 'x' || prefix [0] == 'X') &&
  491. (prefix [1] == 'm' || prefix [1] == 'M') &&
  492. (prefix [2] == 'l' || prefix [2] == 'L'))
  493. throw new ArgumentException ("A prefix cannot be equivalent to \"xml\" in case-insensitive match.");
  494. if (output_xmldecl)
  495. OutputAutoStartDocument ();
  496. if (state == WriteState.Element)
  497. CloseStartElement ();
  498. if (open_count > 0)
  499. elements [open_count - 1].HasElements = true;
  500. nsmanager.PushScope ();
  501. if (namespaces && namespaceUri != null) {
  502. // If namespace URI is empty, then prefix must
  503. // be empty as well.
  504. if (anonPrefix && namespaceUri.Length > 0)
  505. prefix = LookupPrefix (namespaceUri);
  506. if (prefix == null || namespaceUri.Length == 0)
  507. prefix = String.Empty;
  508. }
  509. WriteIndent ();
  510. writer.Write ("<");
  511. if (prefix.Length > 0) {
  512. writer.Write (prefix);
  513. writer.Write (':');
  514. }
  515. writer.Write (localName);
  516. if (elements.Length == open_count) {
  517. XmlNodeInfo [] tmp = new XmlNodeInfo [open_count << 1];
  518. Array.Copy (elements, tmp, open_count);
  519. elements = tmp;
  520. }
  521. if (elements [open_count] == null)
  522. elements [open_count] =
  523. new XmlNodeInfo ();
  524. XmlNodeInfo info = elements [open_count];
  525. info.Prefix = prefix;
  526. info.LocalName = localName;
  527. info.NS = namespaceUri;
  528. info.HasSimple = false;
  529. info.HasElements = false;
  530. info.XmlLang = XmlLang;
  531. info.XmlSpace = XmlSpace;
  532. open_count++;
  533. if (namespaces && namespaceUri != null) {
  534. string oldns = nsmanager.LookupNamespace (prefix);
  535. if (oldns != namespaceUri) {
  536. nsmanager.AddNamespace (prefix, namespaceUri);
  537. new_local_namespaces.Push (prefix);
  538. }
  539. }
  540. state = WriteState.Element;
  541. }
  542. void CloseStartElement ()
  543. {
  544. CloseStartElementCore ();
  545. if (state == WriteState.Element)
  546. writer.Write ('>');
  547. state = WriteState.Content;
  548. }
  549. void CloseStartElementCore ()
  550. {
  551. if (state == WriteState.Attribute)
  552. WriteEndAttribute ();
  553. if (new_local_namespaces.Count == 0) {
  554. if (explicit_nsdecls.Count > 0)
  555. explicit_nsdecls.Clear ();
  556. return;
  557. }
  558. // Missing xmlns attributes are added to
  559. // explicit_nsdecls (it is cleared but this way
  560. // I save another array creation).
  561. int idx = explicit_nsdecls.Count;
  562. while (new_local_namespaces.Count > 0) {
  563. string p = (string) new_local_namespaces.Pop ();
  564. bool match = false;
  565. for (int i = 0; i < explicit_nsdecls.Count; i++) {
  566. if ((string) explicit_nsdecls [i] == p) {
  567. match = true;
  568. break;
  569. }
  570. }
  571. if (match)
  572. continue;
  573. explicit_nsdecls.Add (p);
  574. }
  575. for (int i = idx; i < explicit_nsdecls.Count; i++) {
  576. string prefix = (string) explicit_nsdecls [i];
  577. string ns = nsmanager.LookupNamespace (prefix);
  578. if (ns == null)
  579. continue; // superceded
  580. if (prefix.Length > 0) {
  581. writer.Write (" xmlns:");
  582. writer.Write (prefix);
  583. } else {
  584. writer.Write (" xmlns");
  585. }
  586. writer.Write ('=');
  587. writer.Write (quote_char);
  588. WriteEscapedString (ns, true);
  589. writer.Write (quote_char);
  590. }
  591. explicit_nsdecls.Clear ();
  592. }
  593. // EndElement
  594. public override void WriteEndElement ()
  595. {
  596. WriteEndElementCore (false);
  597. }
  598. public override void WriteFullEndElement ()
  599. {
  600. WriteEndElementCore (true);
  601. }
  602. void WriteEndElementCore (bool full)
  603. {
  604. #if NET_2_0
  605. if (state == WriteState.Error || state == WriteState.Closed)
  606. #else
  607. if (state == WriteState.Closed)
  608. #endif
  609. throw StateError ("EndElement");
  610. if (open_count == 0)
  611. throw InvalidOperation ("There is no more open element.");
  612. bool isEmpty = state != WriteState.Content;
  613. CloseStartElementCore ();
  614. nsmanager.PopScope ();
  615. bool doIndent = !elements [open_count - 1].HasSimple;
  616. if (open_count > 1)
  617. doIndent &= !elements [open_count - 2].HasSimple;
  618. XmlNodeInfo info = elements [--open_count];
  619. if (full || state == WriteState.Content) {
  620. if (state == WriteState.Element)
  621. writer.Write ('>');
  622. if (doIndent && (full || !isEmpty))
  623. DoWriteIndent ();
  624. writer.Write ("</");
  625. if (info.Prefix.Length > 0) {
  626. writer.Write (info.Prefix);
  627. writer.Write (':');
  628. }
  629. writer.Write (info.LocalName);
  630. writer.Write ('>');
  631. } else {
  632. writer.Write (" />");
  633. }
  634. state = WriteState.Content;
  635. if (open_count == 0)
  636. node_state = XmlNodeType.EndElement;
  637. }
  638. // Attribute
  639. public override void WriteStartAttribute (
  640. string prefix, string localName, string namespaceUri)
  641. {
  642. if (state != WriteState.Element && state != WriteState.Start)
  643. throw StateError ("Attribute");
  644. if ((object) prefix == null)
  645. prefix = String.Empty;
  646. // For xmlns URI, prefix is forced to be "xmlns"
  647. bool isNSDecl = false;
  648. if (namespaceUri == XmlnsNamespace) {
  649. isNSDecl = true;
  650. if (prefix.Length == 0 && localName != "xmlns")
  651. prefix = "xmlns";
  652. }
  653. else
  654. isNSDecl = (prefix == "xmlns" ||
  655. localName == "xmlns" && prefix.Length == 0);
  656. if (namespaces) {
  657. // MS implementation is pretty hacky here.
  658. // Regardless of namespace URI it is regarded
  659. // as NS URI for "xml".
  660. if (prefix == "xml")
  661. namespaceUri = XmlNamespace;
  662. // infer namespace URI.
  663. else if ((object) namespaceUri == null) {
  664. if (isNSDecl)
  665. namespaceUri = XmlnsNamespace;
  666. else
  667. namespaceUri = String.Empty;
  668. }
  669. // It is silly design - null namespace with
  670. // "xmlns" are allowed (for namespace-less
  671. // output; while there is Namespaces property)
  672. // On the other hand, namespace "" is not
  673. // allowed.
  674. if (isNSDecl && namespaceUri != XmlnsNamespace)
  675. throw ArgumentError (String.Format ("The 'xmlns' attribute is bound to the reserved namespace '{0}'", XmlnsNamespace));
  676. // If namespace URI is empty, then prefix
  677. // must be empty as well.
  678. if (prefix.Length > 0 && namespaceUri.Length == 0)
  679. throw ArgumentError ("Namespace URI must not be null when prefix is not an empty string.");
  680. // Dive into extremely complex procedure.
  681. if (!isNSDecl && namespaceUri.Length > 0)
  682. prefix = DetermineAttributePrefix (
  683. prefix, localName, namespaceUri);
  684. }
  685. if (indent_attributes)
  686. WriteIndent ();
  687. else if (state != WriteState.Start)
  688. writer.Write (' ');
  689. if (prefix.Length > 0) {
  690. writer.Write (prefix);
  691. writer.Write (':');
  692. }
  693. writer.Write (localName);
  694. writer.Write ('=');
  695. writer.Write (quote_char);
  696. if (isNSDecl || prefix == "xml") {
  697. if (preserver == null)
  698. preserver = new StringWriter ();
  699. else
  700. preserver.GetStringBuilder ().Length = 0;
  701. writer = preserver;
  702. if (!isNSDecl) {
  703. is_preserved_xmlns = false;
  704. preserved_name = localName;
  705. } else {
  706. is_preserved_xmlns = true;
  707. preserved_name = localName == "xmlns" ?
  708. String.Empty : localName;
  709. }
  710. }
  711. state = WriteState.Attribute;
  712. }
  713. // See also:
  714. // "DetermineAttributePrefix(): local mapping overwrite"
  715. string DetermineAttributePrefix (
  716. string prefix, string local, string ns)
  717. {
  718. bool mockup = false;
  719. if (prefix.Length == 0) {
  720. prefix = LookupPrefix (ns);
  721. if (prefix != null)
  722. return prefix;
  723. mockup = true;
  724. } else {
  725. prefix = nsmanager.NameTable.Add (prefix);
  726. string existing = nsmanager.LookupNamespace (prefix);
  727. if (existing == ns)
  728. return prefix;
  729. if (existing != null) {
  730. // See code comment on the head of
  731. // this source file.
  732. nsmanager.RemoveNamespace (prefix, existing);
  733. if (nsmanager.LookupNamespace (prefix) != existing) {
  734. mockup = true;
  735. nsmanager.AddNamespace (prefix, existing);
  736. }
  737. }
  738. }
  739. if (mockup)
  740. prefix = MockupPrefix (ns, true);
  741. new_local_namespaces.Push (prefix);
  742. nsmanager.AddNamespace (prefix, ns);
  743. return prefix;
  744. }
  745. string MockupPrefix (string ns, bool skipLookup)
  746. {
  747. string prefix = skipLookup ? null :
  748. LookupPrefix (ns);
  749. if (prefix != null && prefix.Length > 0)
  750. return prefix;
  751. for (int p = 1; ; p++) {
  752. prefix = StringUtil.Format ("d{0}p{1}", open_count, p);
  753. if (new_local_namespaces.Contains (prefix))
  754. continue;
  755. if (null != nsmanager.LookupNamespace (
  756. nsmanager.NameTable.Get (prefix)))
  757. continue;
  758. nsmanager.AddNamespace (prefix, ns);
  759. new_local_namespaces.Push (prefix);
  760. return prefix;
  761. }
  762. }
  763. public override void WriteEndAttribute ()
  764. {
  765. if (state != WriteState.Attribute)
  766. throw StateError ("End of attribute");
  767. if (writer == preserver) {
  768. writer = source;
  769. string value = preserver.ToString ();
  770. if (is_preserved_xmlns) {
  771. if (preserved_name.Length > 0 &&
  772. value.Length == 0)
  773. throw ArgumentError ("Non-empty prefix must be mapped to non-empty namespace URI.");
  774. string existing = nsmanager.LookupNamespace (preserved_name);
  775. explicit_nsdecls.Add (preserved_name);
  776. if (open_count > 0 &&
  777. elements [open_count - 1].NS == String.Empty &&
  778. elements [open_count - 1].Prefix == preserved_name)
  779. ; // do nothing
  780. else if (existing != value)
  781. nsmanager.AddNamespace (preserved_name, value);
  782. } else {
  783. switch (preserved_name) {
  784. case "lang":
  785. if (open_count > 0)
  786. elements [open_count - 1].XmlLang = value;
  787. break;
  788. case "space":
  789. switch (value) {
  790. case "default":
  791. if (open_count > 0)
  792. elements [open_count - 1].XmlSpace = XmlSpace.Default;
  793. break;
  794. case "preserve":
  795. if (open_count > 0)
  796. elements [open_count - 1].XmlSpace = XmlSpace.Preserve;
  797. break;
  798. default:
  799. throw ArgumentError ("Invalid value for xml:space.");
  800. }
  801. break;
  802. }
  803. }
  804. writer.Write (value);
  805. }
  806. writer.Write (quote_char);
  807. state = WriteState.Element;
  808. }
  809. // Non-Text Content
  810. public override void WriteComment (string text)
  811. {
  812. if (text == null)
  813. throw ArgumentError ("text");
  814. WriteIndent ();
  815. if (text.Length > 0 && text [text.Length - 1] == '-')
  816. throw ArgumentError ("An input string to WriteComment method must not end with '-'. Escape it with '&#2D;'.");
  817. if (StringUtil.IndexOf (text, "--") > 0)
  818. throw ArgumentError ("An XML comment cannot end with \"-\".");
  819. ShiftStateTopLevel ("Comment", false, false);
  820. writer.Write ("<!--");
  821. writer.Write (text);
  822. writer.Write ("-->");
  823. }
  824. // LAMESPEC: see comments on the top of this source.
  825. public override void WriteProcessingInstruction (string name, string text)
  826. {
  827. if (name == null)
  828. throw ArgumentError ("name");
  829. if (text == null)
  830. throw ArgumentError ("text");
  831. WriteIndent ();
  832. if (!XmlChar.IsName (name))
  833. throw ArgumentError ("A processing instruction name must be a valid XML name.");
  834. if (StringUtil.IndexOf (text, "?>") > 0)
  835. throw ArgumentError ("Processing instruction cannot contain \"?>\" as its value.");
  836. ShiftStateTopLevel ("ProcessingInstruction", false, name == "xml");
  837. writer.Write ("<?");
  838. writer.Write (name);
  839. writer.Write (' ');
  840. writer.Write (text);
  841. writer.Write ("?>");
  842. if (state == WriteState.Start)
  843. state = WriteState.Prolog;
  844. }
  845. // Text Content
  846. public override void WriteWhitespace (string text)
  847. {
  848. if (text == null)
  849. throw ArgumentError ("text");
  850. // huh? Shouldn't it accept an empty string???
  851. if (text.Length == 0 ||
  852. XmlChar.IndexOfNonWhitespace (text) >= 0)
  853. throw ArgumentError ("WriteWhitespace method accepts only whitespaces.");
  854. ShiftStateTopLevel ("Whitespace", true, false);
  855. writer.Write (text);
  856. }
  857. public override void WriteCData (string text)
  858. {
  859. if (text == null)
  860. text = String.Empty;
  861. ShiftStateContent ("Text", false);
  862. if (StringUtil.IndexOf (text, "]]>") >= 0)
  863. throw ArgumentError ("CDATA section must not contain ']]>'.");
  864. writer.Write ("<![CDATA[");
  865. WriteCheckedString (text);
  866. writer.Write ("]]>");
  867. }
  868. public override void WriteString (string text)
  869. {
  870. if (text == null || text.Length == 0)
  871. return; // do nothing, including state transition.
  872. ShiftStateContent ("Text", true);
  873. WriteEscapedString (text, state == WriteState.Attribute);
  874. }
  875. public override void WriteRaw (string raw)
  876. {
  877. if (raw == null)
  878. return; // do nothing, including state transition.
  879. //WriteIndent ();
  880. // LAMESPEC: It rejects XMLDecl while it allows
  881. // DocType which could consist of non well-formed XML.
  882. ShiftStateTopLevel ("Raw string", true, true);
  883. writer.Write (raw);
  884. }
  885. public override void WriteCharEntity (char ch)
  886. {
  887. WriteCharacterEntity (ch, '\0', false);
  888. }
  889. public override void WriteSurrogateCharEntity (char low, char high)
  890. {
  891. WriteCharacterEntity (low, high, true);
  892. }
  893. void WriteCharacterEntity (char ch, char high, bool surrogate)
  894. {
  895. if (surrogate &&
  896. ('\uD800' > high || high > '\uDC00' ||
  897. '\uDC00' > ch || ch > '\uDFFF'))
  898. throw ArgumentError (String.Format ("Invalid surrogate pair was found. Low: &#x{0:X}; High: &#x{0:X};", (int) ch, (int) high));
  899. else if (check_character_validity && XmlChar.IsInvalid (ch))
  900. throw ArgumentError (String.Format ("Invalid character &#x{0:X};", (int) ch));
  901. ShiftStateContent ("Character", true);
  902. int v = surrogate ? (high - 0xD800) * 0x400 + ch - 0xDC00 + 0x10000 : (int) ch;
  903. writer.Write ("&#x");
  904. writer.Write (v.ToString ("X", CultureInfo.InvariantCulture));
  905. writer.Write (';');
  906. }
  907. public override void WriteEntityRef (string name)
  908. {
  909. if (name == null)
  910. throw ArgumentError ("name");
  911. if (!XmlChar.IsName (name))
  912. throw ArgumentError ("Argument name must be a valid XML name.");
  913. ShiftStateContent ("Character", true);
  914. writer.Write ('&');
  915. writer.Write (name);
  916. writer.Write (';');
  917. }
  918. // Applied methods
  919. public override void WriteName (string name)
  920. {
  921. if (name == null)
  922. throw ArgumentError ("name");
  923. if (!XmlChar.IsName (name))
  924. throw ArgumentError ("Not a valid name string.");
  925. WriteString (name);
  926. }
  927. public override void WriteNmToken (string nmtoken)
  928. {
  929. if (nmtoken == null)
  930. throw ArgumentError ("nmtoken");
  931. if (!XmlChar.IsNmToken (nmtoken))
  932. throw ArgumentError ("Not a valid NMTOKEN string.");
  933. WriteString (nmtoken);
  934. }
  935. public override void WriteQualifiedName (
  936. string localName, string ns)
  937. {
  938. if (localName == null)
  939. throw ArgumentError ("localName");
  940. if (ns == null)
  941. ns = String.Empty;
  942. if (ns == XmlnsNamespace)
  943. throw ArgumentError ("Prefix 'xmlns' is reserved and cannot be overriden.");
  944. if (!XmlChar.IsNCName (localName))
  945. throw ArgumentError ("localName must be a valid NCName.");
  946. ShiftStateContent ("QName", true);
  947. string prefix =
  948. state == WriteState.Content || ns.Length > 0 ?
  949. LookupPrefix (ns) : String.Empty;
  950. if (prefix == null) {
  951. if (state == WriteState.Attribute)
  952. prefix = MockupPrefix (ns, false);
  953. else
  954. throw ArgumentError (String.Format ("Namespace '{0}' is not declared.", ns));
  955. }
  956. if (prefix != String.Empty) {
  957. writer.Write (prefix);
  958. writer.Write (":");
  959. }
  960. writer.Write (localName);
  961. }
  962. // Chunk data
  963. void CheckChunkRange (Array buffer, int index, int count)
  964. {
  965. if (buffer == null)
  966. throw new ArgumentNullException ("buffer");
  967. if (index < 0 || buffer.Length < index)
  968. throw ArgumentOutOfRangeError ("index");
  969. if (count < 0 || buffer.Length < index + count)
  970. throw ArgumentOutOfRangeError ("count");
  971. }
  972. public override void WriteBase64 (byte [] buffer, int index, int count)
  973. {
  974. CheckChunkRange (buffer, index, count);
  975. WriteString (Convert.ToBase64String (buffer, index, count));
  976. }
  977. public override void WriteBinHex (byte [] buffer, int index, int count)
  978. {
  979. CheckChunkRange (buffer, index, count);
  980. ShiftStateContent ("Text", false);
  981. XmlConvert.WriteBinHex (buffer, index, count, writer);
  982. }
  983. public override void WriteChars (char [] buffer, int index, int count)
  984. {
  985. CheckChunkRange (buffer, index, count);
  986. ShiftStateContent ("Text", true);
  987. WriteEscapedBuffer (buffer, index, count,
  988. state == WriteState.Attribute);
  989. }
  990. public override void WriteRaw (char [] buffer, int index, int count)
  991. {
  992. CheckChunkRange (buffer, index, count);
  993. ShiftStateContent ("Text", false);
  994. writer.Write (buffer, index, count);
  995. }
  996. // Utilities
  997. void WriteIndent ()
  998. {
  999. if (!indent || (open_count > 0 &&
  1000. elements [open_count - 1].HasSimple))
  1001. return;
  1002. if (state != WriteState.Start)
  1003. writer.Write (newline);
  1004. for (int i = 0; i < open_count; i++)
  1005. writer.Write (indent_string);
  1006. }
  1007. void DoWriteIndent ()
  1008. {
  1009. if (!indent)
  1010. return;
  1011. writer.Write (newline);
  1012. for (int i = 0; i < open_count; i++)
  1013. writer.Write (indent_string);
  1014. }
  1015. void OutputAutoStartDocument ()
  1016. {
  1017. if (state != WriteState.Start)
  1018. return;
  1019. WriteStartDocumentCore (false, false);
  1020. }
  1021. void ShiftStateTopLevel (string occured, bool allowAttribute, bool dontCheckXmlDecl)
  1022. {
  1023. switch (state) {
  1024. #if NET_2_0
  1025. case WriteState.Error:
  1026. #endif
  1027. case WriteState.Closed:
  1028. throw StateError (occured);
  1029. case WriteState.Start:
  1030. if (output_xmldecl && !dontCheckXmlDecl)
  1031. OutputAutoStartDocument ();
  1032. state = WriteState.Prolog;
  1033. break;
  1034. case WriteState.Attribute:
  1035. if (allowAttribute)
  1036. break;
  1037. goto case WriteState.Closed;
  1038. case WriteState.Element:
  1039. CloseStartElement ();
  1040. break;
  1041. }
  1042. if (open_count > 0 &&
  1043. state != WriteState.Attribute)
  1044. elements [open_count - 1].HasSimple = true;
  1045. }
  1046. void ShiftStateContent (string occured, bool allowAttribute)
  1047. {
  1048. switch (state) {
  1049. #if NET_2_0
  1050. case WriteState.Error:
  1051. #endif
  1052. case WriteState.Closed:
  1053. throw StateError (occured);
  1054. case WriteState.Prolog:
  1055. case WriteState.Start:
  1056. if (!allow_doc_fragment || is_document_entity)
  1057. goto case WriteState.Closed;
  1058. if (output_xmldecl)
  1059. OutputAutoStartDocument ();
  1060. state = WriteState.Content;
  1061. break;
  1062. case WriteState.Attribute:
  1063. if (allowAttribute)
  1064. break;
  1065. goto case WriteState.Closed;
  1066. case WriteState.Element:
  1067. CloseStartElement ();
  1068. break;
  1069. case WriteState.Content:
  1070. break;
  1071. }
  1072. if (open_count > 0 &&
  1073. state != WriteState.Attribute)
  1074. elements [open_count - 1].HasSimple = true;
  1075. }
  1076. void WriteEscapedString (string text, bool isAttribute)
  1077. {
  1078. char [] escaped = isAttribute ?
  1079. escaped_attr_chars : escaped_text_chars;
  1080. int idx = text.IndexOfAny (escaped);
  1081. if (idx >= 0) {
  1082. char [] arr = text.ToCharArray ();
  1083. WriteCheckedBuffer (arr, 0, idx);
  1084. WriteEscapedBuffer (
  1085. arr, idx, arr.Length - idx, isAttribute);
  1086. } else {
  1087. WriteCheckedString (text);
  1088. }
  1089. }
  1090. void WriteCheckedString (string s)
  1091. {
  1092. int i = XmlChar.IndexOfInvalid (s, true);
  1093. if (i >= 0) {
  1094. char [] arr = s.ToCharArray ();
  1095. writer.Write (arr, 0, i);
  1096. WriteCheckedBuffer (arr, i, arr.Length - i);
  1097. } else {
  1098. // no invalid character.
  1099. writer.Write (s);
  1100. }
  1101. }
  1102. void WriteCheckedBuffer (char [] text, int idx, int length)
  1103. {
  1104. int start = idx;
  1105. int end = idx + length;
  1106. while ((idx = XmlChar.IndexOfInvalid (text, start, length, true)) >= 0) {
  1107. if (check_character_validity) // actually this is one time pass.
  1108. throw ArgumentError (String.Format ("Input contains invalid character at {0} : &#x{1:X};", idx, (int) text [idx]));
  1109. if (start < idx)
  1110. writer.Write (text, start, idx - start);
  1111. writer.Write ("&#x");
  1112. writer.Write (((int) text [idx]).ToString (
  1113. "X",
  1114. CultureInfo.InvariantCulture));
  1115. writer.Write (';');
  1116. length -= idx - start + 1;
  1117. start = idx + 1;
  1118. }
  1119. if (start < end)
  1120. writer.Write (text, start, end - start);
  1121. }
  1122. void WriteEscapedBuffer (char [] text, int index, int length,
  1123. bool isAttribute)
  1124. {
  1125. int start = index;
  1126. int end = index + length;
  1127. for (int i = start; i < end; i++) {
  1128. switch (text [i]) {
  1129. default:
  1130. continue;
  1131. case '&':
  1132. case '<':
  1133. case '>':
  1134. if (start < i)
  1135. WriteCheckedBuffer (text, start, i - start);
  1136. writer.Write ('&');
  1137. switch (text [i]) {
  1138. case '&': writer.Write ("amp;"); break;
  1139. case '<': writer.Write ("lt;"); break;
  1140. case '>': writer.Write ("gt;"); break;
  1141. case '\'': writer.Write ("apos;"); break;
  1142. case '"': writer.Write ("quot;"); break;
  1143. }
  1144. break;
  1145. case '"':
  1146. case '\'':
  1147. if (isAttribute && text [i] == quote_char)
  1148. goto case '&';
  1149. continue;
  1150. case '\r':
  1151. if (i + 1 < end && text [i] == '\n')
  1152. i++; // CRLF
  1153. goto case '\n';
  1154. case '\n':
  1155. if (start < i)
  1156. WriteCheckedBuffer (text, start, i - start);
  1157. if (isAttribute) {
  1158. writer.Write (text [i] == '\r' ?
  1159. "&#xD;" : "&#xA;");
  1160. break;
  1161. }
  1162. switch (newline_handling) {
  1163. case NewLineHandling.Entitize:
  1164. writer.Write (text [i] == '\r' ?
  1165. "&#xD;" : "&#xA;");
  1166. break;
  1167. case NewLineHandling.Replace:
  1168. writer.Write (newline);
  1169. break;
  1170. default:
  1171. writer.Write (text [i]);
  1172. break;
  1173. }
  1174. break;
  1175. }
  1176. start = i + 1;
  1177. }
  1178. if (start < end)
  1179. WriteCheckedBuffer (text, start, end - start);
  1180. }
  1181. // Exceptions
  1182. Exception ArgumentOutOfRangeError (string name)
  1183. {
  1184. #if NET_2_0
  1185. state = WriteState.Error;
  1186. #endif
  1187. return new ArgumentOutOfRangeException (name);
  1188. }
  1189. Exception ArgumentError (string msg)
  1190. {
  1191. #if NET_2_0
  1192. state = WriteState.Error;
  1193. #endif
  1194. return new ArgumentException (msg);
  1195. }
  1196. Exception InvalidOperation (string msg)
  1197. {
  1198. #if NET_2_0
  1199. state = WriteState.Error;
  1200. #endif
  1201. return new InvalidOperationException (msg);
  1202. }
  1203. Exception StateError (string occured)
  1204. {
  1205. return InvalidOperation (String.Format ("This XmlWriter does not accept {0} at this state {1}.", occured, state));
  1206. }
  1207. }
  1208. }