2 //------------------------------------------------------------------------------
3 // <copyright file="XmlWellFormedWriterHelpers.cs" company="Microsoft">
4 // Copyright (c) Microsoft Corporation. All rights reserved.
6 // <owner current="true" primary="true">[....]</owner>
7 //------------------------------------------------------------------------------
11 using System.Diagnostics;
12 using System.Collections.Generic;
14 namespace System.Xml {
16 internal partial class XmlWellFormedWriter : XmlWriter {
21 class NamespaceResolverProxy : IXmlNamespaceResolver {
22 XmlWellFormedWriter wfWriter;
24 internal NamespaceResolverProxy(XmlWellFormedWriter wfWriter) {
25 this.wfWriter = wfWriter;
28 IDictionary<string, string> IXmlNamespaceResolver.GetNamespacesInScope(XmlNamespaceScope scope) {
29 throw new NotImplementedException();
31 string IXmlNamespaceResolver.LookupNamespace(string prefix) {
32 return wfWriter.LookupNamespace(prefix);
35 string IXmlNamespaceResolver.LookupPrefix(string namespaceName) {
36 return wfWriter.LookupPrefix(namespaceName);
40 partial struct ElementScope {
42 internal int prevNSTop;
43 internal string prefix;
44 internal string localName;
45 internal string namespaceUri;
46 internal XmlSpace xmlSpace;
47 internal string xmlLang;
49 internal void Set(string prefix, string localName, string namespaceUri, int prevNSTop) {
50 this.prevNSTop = prevNSTop;
52 this.namespaceUri = namespaceUri;
53 this.localName = localName;
54 this.xmlSpace = (System.Xml.XmlSpace)(int)-1;
58 internal void WriteEndElement(XmlRawWriter rawWriter) {
59 rawWriter.WriteEndElement(prefix, localName, namespaceUri);
62 internal void WriteFullEndElement(XmlRawWriter rawWriter) {
63 rawWriter.WriteFullEndElement(prefix, localName, namespaceUri);
74 partial struct Namespace {
76 internal string prefix;
77 internal string namespaceUri;
78 internal NamespaceKind kind;
79 internal int prevNsIndex;
81 internal void Set(string prefix, string namespaceUri, NamespaceKind kind) {
83 this.namespaceUri = namespaceUri;
85 this.prevNsIndex = -1;
88 internal void WriteDecl(XmlWriter writer, XmlRawWriter rawWriter) {
89 Debug.Assert(kind == NamespaceKind.NeedToWrite);
90 if (null != rawWriter) {
91 rawWriter.WriteNamespaceDeclaration(prefix, namespaceUri);
94 if (prefix.Length == 0) {
95 writer.WriteStartAttribute(string.Empty, "xmlns", XmlReservedNs.NsXmlNs);
98 writer.WriteStartAttribute("xmlns", prefix, XmlReservedNs.NsXmlNs);
100 writer.WriteString(namespaceUri);
101 writer.WriteEndAttribute();
107 internal string prefix;
108 internal string namespaceUri;
109 internal string localName;
112 internal void Set(string prefix, string localName, string namespaceUri) {
113 this.prefix = prefix;
114 this.namespaceUri = namespaceUri;
115 this.localName = localName;
119 internal bool IsDuplicate(string prefix, string localName, string namespaceUri) {
120 return ((this.localName == localName)
121 && ((this.prefix == prefix) || (this.namespaceUri == namespaceUri)));
125 enum SpecialAttribute {
133 partial class AttributeValueCache {
148 internal ItemType type;
149 internal object data;
153 internal void Set(ItemType type, object data) {
160 internal char[] buffer;
164 internal BufferChunk(char[] buffer, int index, int count) {
165 this.buffer = buffer;
171 StringBuilder stringValue = new StringBuilder();
172 string singleStringValue; // special-case for a single WriteString call
177 internal string StringValue {
179 if (singleStringValue != null) {
180 return singleStringValue;
183 return stringValue.ToString();
188 internal void WriteEntityRef(string name) {
189 if (singleStringValue != null) {
195 stringValue.Append('<');
198 stringValue.Append('>');
201 stringValue.Append('"');
204 stringValue.Append('\'');
207 stringValue.Append('&');
210 stringValue.Append('&');
211 stringValue.Append(name);
212 stringValue.Append(';');
216 AddItem(ItemType.EntityRef, name);
219 internal void WriteCharEntity(char ch) {
220 if (singleStringValue != null) {
223 stringValue.Append(ch);
224 AddItem(ItemType.CharEntity, ch);
227 internal void WriteSurrogateCharEntity(char lowChar, char highChar) {
228 if (singleStringValue != null) {
231 stringValue.Append(highChar);
232 stringValue.Append(lowChar);
233 AddItem(ItemType.SurrogateCharEntity, new char[] { lowChar, highChar });
236 internal void WriteWhitespace(string ws) {
237 if (singleStringValue != null) {
240 stringValue.Append(ws);
241 AddItem(ItemType.Whitespace, ws);
244 internal void WriteString(string text) {
245 if (singleStringValue != null) {
249 // special-case for a single WriteString
250 if (lastItem == -1) {
251 singleStringValue = text;
256 stringValue.Append(text);
257 AddItem(ItemType.String, text);
260 internal void WriteChars(char[] buffer, int index, int count) {
261 if (singleStringValue != null) {
264 stringValue.Append(buffer, index, count);
265 AddItem(ItemType.StringChars, new BufferChunk(buffer, index, count));
268 internal void WriteRaw(char[] buffer, int index, int count) {
269 if (singleStringValue != null) {
272 stringValue.Append(buffer, index, count);
273 AddItem(ItemType.RawChars, new BufferChunk(buffer, index, count));
276 internal void WriteRaw(string data) {
277 if (singleStringValue != null) {
280 stringValue.Append(data);
281 AddItem(ItemType.Raw, data);
284 internal void WriteValue(string value) {
285 if (singleStringValue != null) {
288 stringValue.Append(value);
289 AddItem(ItemType.ValueString, value);
292 internal void Replay(XmlWriter writer) {
293 if (singleStringValue != null) {
294 writer.WriteString(singleStringValue);
298 BufferChunk bufChunk;
299 for (int i = firstItem; i <= lastItem; i++) {
300 Item item = items[i];
302 case ItemType.EntityRef:
303 writer.WriteEntityRef((string)item.data);
305 case ItemType.CharEntity:
306 writer.WriteCharEntity((char)item.data);
308 case ItemType.SurrogateCharEntity:
309 char[] chars = (char[])item.data;
310 writer.WriteSurrogateCharEntity(chars[0], chars[1]);
312 case ItemType.Whitespace:
313 writer.WriteWhitespace((string)item.data);
315 case ItemType.String:
316 writer.WriteString((string)item.data);
318 case ItemType.StringChars:
319 bufChunk = (BufferChunk)item.data;
320 writer.WriteChars(bufChunk.buffer, bufChunk.index, bufChunk.count);
323 writer.WriteRaw((string)item.data);
325 case ItemType.RawChars:
326 bufChunk = (BufferChunk)item.data;
327 writer.WriteChars(bufChunk.buffer, bufChunk.index, bufChunk.count);
329 case ItemType.ValueString:
330 writer.WriteValue((string)item.data);
333 Debug.Assert(false, "Unexpected ItemType value.");
339 // This method trims whitespaces from the beginnig and the end of the string and cached writer events
340 internal void Trim() {
341 // if only one string value -> trim the write spaces directly
342 if (singleStringValue != null) {
343 singleStringValue = XmlConvert.TrimString(singleStringValue);
347 // trim the string in StringBuilder
348 string valBefore = stringValue.ToString();
349 string valAfter = XmlConvert.TrimString(valBefore);
350 if (valBefore != valAfter) {
351 stringValue = new StringBuilder(valAfter);
354 // trim the beginning of the recorded writer events
355 XmlCharType xmlCharType = XmlCharType.Instance;
358 while (i == firstItem && i <= lastItem) {
359 Item item = items[i];
361 case ItemType.Whitespace:
364 case ItemType.String:
366 case ItemType.ValueString:
367 item.data = XmlConvert.TrimStringStart((string)item.data);
368 if (((string)item.data).Length == 0) {
369 // no characters left -> move the firstItem index to exclude it from the Replay
373 case ItemType.StringChars:
374 case ItemType.RawChars:
375 BufferChunk bufChunk = (BufferChunk)item.data;
376 int endIndex = bufChunk.index + bufChunk.count;
377 while (bufChunk.index < endIndex && xmlCharType.IsWhiteSpace(bufChunk.buffer[bufChunk.index])) {
381 if (bufChunk.index == endIndex) {
382 // no characters left -> move the firstItem index to exclude it from the Replay
390 // trim the end of the recorded writer events
392 while (i == lastItem && i >= firstItem) {
393 Item item = items[i];
395 case ItemType.Whitespace:
398 case ItemType.String:
400 case ItemType.ValueString:
401 item.data = XmlConvert.TrimStringEnd((string)item.data);
402 if (((string)item.data).Length == 0) {
403 // no characters left -> move the lastItem index to exclude it from the Replay
407 case ItemType.StringChars:
408 case ItemType.RawChars:
409 BufferChunk bufChunk = (BufferChunk)item.data;
410 while (bufChunk.count > 0 && xmlCharType.IsWhiteSpace(bufChunk.buffer[bufChunk.index + bufChunk.count - 1])) {
413 if (bufChunk.count == 0) {
414 // no characters left -> move the lastItem index to exclude it from the Replay
423 internal void Clear() {
424 singleStringValue = null;
427 stringValue.Length = 0;
430 private void StartComplexValue() {
431 Debug.Assert(singleStringValue != null);
432 Debug.Assert(lastItem == -1);
434 stringValue.Append( singleStringValue );
435 AddItem(ItemType.String, singleStringValue);
437 singleStringValue = null;
440 void AddItem(ItemType type, object data) {
441 int newItemIndex = lastItem + 1;
445 else if (items.Length == newItemIndex) {
446 Item[] newItems = new Item[newItemIndex * 2];
447 Array.Copy(items, newItems, newItemIndex);
450 if (items[newItemIndex] == null) {
451 items[newItemIndex] = new Item();
453 items[newItemIndex].Set(type, data);
454 lastItem = newItemIndex;