1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 using System.Collections.ObjectModel;
6 using System.Runtime.Serialization;
7 using System.Xml.Serialization;
8 using System.Collections.Generic;
9 using System.Xml;
10 using System.Xml.Schema;
11 using System.ServiceModel.Channels;
12 using System.Diagnostics;
13 using System.Diagnostics.CodeAnalysis;
14 using System.Runtime.CompilerServices;
15 
16 namespace System.ServiceModel.Syndication
17 {
CreateInlineCategoriesDelegate()18     internal delegate InlineCategoriesDocument CreateInlineCategoriesDelegate();
CreateReferencedCategoriesDelegate()19     internal delegate ReferencedCategoriesDocument CreateReferencedCategoriesDelegate();
20 
21     [XmlRoot(ElementName = App10Constants.Service, Namespace = App10Constants.Namespace)]
22     public class AtomPub10ServiceDocumentFormatter : ServiceDocumentFormatter, IXmlSerializable
23     {
24         private Type _documentType;
25         private int _maxExtensionSize;
26         private bool _preserveAttributeExtensions;
27         private bool _preserveElementExtensions;
28 
AtomPub10ServiceDocumentFormatter()29         public AtomPub10ServiceDocumentFormatter()
30             : this(typeof(ServiceDocument))
31         {
32         }
33 
AtomPub10ServiceDocumentFormatter(Type documentTypeToCreate)34         public AtomPub10ServiceDocumentFormatter(Type documentTypeToCreate)
35             : base()
36         {
37             if (documentTypeToCreate == null)
38             {
39                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("documentTypeToCreate");
40             }
41             if (!typeof(ServiceDocument).IsAssignableFrom(documentTypeToCreate))
42             {
43                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("documentTypeToCreate",
44                     SR.Format(SR.InvalidObjectTypePassed, "documentTypeToCreate", "ServiceDocument"));
45             }
46             _maxExtensionSize = int.MaxValue;
47             _preserveAttributeExtensions = true;
48             _preserveElementExtensions = true;
49             _documentType = documentTypeToCreate;
50         }
51 
AtomPub10ServiceDocumentFormatter(ServiceDocument documentToWrite)52         public AtomPub10ServiceDocumentFormatter(ServiceDocument documentToWrite)
53             : base(documentToWrite)
54         {
55             // No need to check that the parameter passed is valid - it is checked by the c'tor of the base class
56             _maxExtensionSize = int.MaxValue;
57             _preserveAttributeExtensions = true;
58             _preserveElementExtensions = true;
59             _documentType = documentToWrite.GetType();
60         }
61 
62         public override string Version
63         {
64             get { return App10Constants.Namespace; }
65         }
66 
CanRead(XmlReader reader)67         public override bool CanRead(XmlReader reader)
68         {
69             if (reader == null)
70             {
71                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader");
72             }
73             return reader.IsStartElement(App10Constants.Service, App10Constants.Namespace);
74         }
75 
76         [SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes", Justification = "The IXmlSerializable implementation is only for exposing under WCF DataContractSerializer. The funcionality is exposed to derived class through the ReadFrom\\WriteTo methods")]
IXmlSerializable.GetSchema()77         XmlSchema IXmlSerializable.GetSchema()
78         {
79             return null;
80         }
81 
82         [SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes", Justification = "The IXmlSerializable implementation is only for exposing under WCF DataContractSerializer. The funcionality is exposed to derived class through the ReadFrom\\WriteTo methods")]
IXmlSerializable.ReadXml(XmlReader reader)83         void IXmlSerializable.ReadXml(XmlReader reader)
84         {
85             if (reader == null)
86             {
87                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader");
88             }
89             TraceServiceDocumentReadBegin();
90             ReadDocument(reader);
91             TraceServiceDocumentReadEnd();
92         }
93 
94         [SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes", Justification = "The IXmlSerializable implementation is only for exposing under WCF DataContractSerializer. The funcionality is exposed to derived class through the ReadFrom\\WriteTo methods")]
IXmlSerializable.WriteXml(XmlWriter writer)95         void IXmlSerializable.WriteXml(XmlWriter writer)
96         {
97             if (writer == null)
98             {
99                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("writer");
100             }
101             if (this.Document == null)
102             {
103                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SR.DocumentFormatterDoesNotHaveDocument)));
104             }
105             TraceServiceDocumentWriteBegin();
106             WriteDocument(writer);
107             TraceServiceDocumentWriteEnd();
108         }
109 
ReadFrom(XmlReader reader)110         public override void ReadFrom(XmlReader reader)
111         {
112             if (reader == null)
113             {
114                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader");
115             }
116             reader.MoveToContent();
117             if (!CanRead(reader))
118             {
119                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.Format(SR.UnknownDocumentXml, reader.LocalName, reader.NamespaceURI)));
120             }
121             TraceServiceDocumentReadBegin();
122             ReadDocument(reader);
123             TraceServiceDocumentReadEnd();
124         }
125 
WriteTo(XmlWriter writer)126         public override void WriteTo(XmlWriter writer)
127         {
128             if (writer == null)
129             {
130                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("writer");
131             }
132             if (this.Document == null)
133             {
134                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SR.DocumentFormatterDoesNotHaveDocument)));
135             }
136             TraceServiceDocumentWriteBegin();
137             writer.WriteStartElement(App10Constants.Prefix, App10Constants.Service, App10Constants.Namespace);
138             WriteDocument(writer);
139             writer.WriteEndElement();
140             TraceServiceDocumentWriteEnd();
141         }
142 
ReadCategories(XmlReader reader, Uri baseUri, CreateInlineCategoriesDelegate inlineCategoriesFactory, CreateReferencedCategoriesDelegate referencedCategoriesFactory, string version, bool preserveElementExtensions, bool preserveAttributeExtensions, int maxExtensionSize)143         internal static CategoriesDocument ReadCategories(XmlReader reader, Uri baseUri, CreateInlineCategoriesDelegate inlineCategoriesFactory, CreateReferencedCategoriesDelegate referencedCategoriesFactory, string version, bool preserveElementExtensions, bool preserveAttributeExtensions, int maxExtensionSize)
144         {
145             string link = reader.GetAttribute(App10Constants.Href, string.Empty);
146             if (string.IsNullOrEmpty(link))
147             {
148                 InlineCategoriesDocument inlineCategories = inlineCategoriesFactory();
149                 ReadInlineCategories(reader, inlineCategories, baseUri, version, preserveElementExtensions, preserveAttributeExtensions, maxExtensionSize);
150                 return inlineCategories;
151             }
152             else
153             {
154                 ReferencedCategoriesDocument referencedCategories = referencedCategoriesFactory();
155                 ReadReferencedCategories(reader, referencedCategories, baseUri, new Uri(link, UriKind.RelativeOrAbsolute), version, preserveElementExtensions, preserveAttributeExtensions, maxExtensionSize);
156                 return referencedCategories;
157             }
158         }
159 
TraceServiceDocumentReadBegin()160         internal static void TraceServiceDocumentReadBegin()
161         {
162         }
163 
TraceServiceDocumentReadEnd()164         internal static void TraceServiceDocumentReadEnd()
165         {
166         }
167 
TraceServiceDocumentWriteBegin()168         internal static void TraceServiceDocumentWriteBegin()
169         {
170         }
171 
TraceServiceDocumentWriteEnd()172         internal static void TraceServiceDocumentWriteEnd()
173         {
174         }
175 
WriteCategoriesInnerXml(XmlWriter writer, CategoriesDocument categories, Uri baseUri, string version)176         internal static void WriteCategoriesInnerXml(XmlWriter writer, CategoriesDocument categories, Uri baseUri, string version)
177         {
178             Uri baseUriToWrite = FeedUtils.GetBaseUriToWrite(baseUri, categories.BaseUri);
179             if (baseUriToWrite != null)
180             {
181                 WriteXmlBase(writer, baseUriToWrite);
182             }
183             if (!string.IsNullOrEmpty(categories.Language))
184             {
185                 WriteXmlLang(writer, categories.Language);
186             }
187             if (categories.IsInline)
188             {
189                 WriteInlineCategoriesContent(writer, (InlineCategoriesDocument)categories, version);
190             }
191             else
192             {
193                 WriteReferencedCategoriesContent(writer, (ReferencedCategoriesDocument)categories, version);
194             }
195         }
196 
CreateDocumentInstance()197         protected override ServiceDocument CreateDocumentInstance()
198         {
199             if (_documentType == typeof(ServiceDocument))
200             {
201                 return new ServiceDocument();
202             }
203             else
204             {
205                 return (ServiceDocument)Activator.CreateInstance(_documentType);
206             }
207         }
208 
ReadInlineCategories(XmlReader reader, InlineCategoriesDocument inlineCategories, Uri baseUri, string version, bool preserveElementExtensions, bool preserveAttributeExtensions, int maxExtensionSize)209         private static void ReadInlineCategories(XmlReader reader, InlineCategoriesDocument inlineCategories, Uri baseUri, string version, bool preserveElementExtensions, bool preserveAttributeExtensions, int maxExtensionSize)
210         {
211             inlineCategories.BaseUri = baseUri;
212             if (reader.HasAttributes)
213             {
214                 while (reader.MoveToNextAttribute())
215                 {
216                     if (reader.LocalName == "base" && reader.NamespaceURI == Atom10FeedFormatter.XmlNs)
217                     {
218                         inlineCategories.BaseUri = FeedUtils.CombineXmlBase(inlineCategories.BaseUri, reader.Value);
219                     }
220                     else if (reader.LocalName == "lang" && reader.NamespaceURI == Atom10FeedFormatter.XmlNs)
221                     {
222                         inlineCategories.Language = reader.Value;
223                     }
224                     else if (reader.LocalName == App10Constants.Fixed && reader.NamespaceURI == string.Empty)
225                     {
226                         inlineCategories.IsFixed = (reader.Value == "yes");
227                     }
228                     else if (reader.LocalName == Atom10Constants.SchemeTag && reader.NamespaceURI == string.Empty)
229                     {
230                         inlineCategories.Scheme = reader.Value;
231                     }
232                     else
233                     {
234                         string ns = reader.NamespaceURI;
235                         string name = reader.LocalName;
236                         if (FeedUtils.IsXmlns(name, ns) || FeedUtils.IsXmlSchemaType(name, ns))
237                         {
238                             continue;
239                         }
240                         string val = reader.Value;
241                         if (!TryParseAttribute(name, ns, val, inlineCategories, version))
242                         {
243                             if (preserveAttributeExtensions)
244                             {
245                                 inlineCategories.AttributeExtensions.Add(new XmlQualifiedName(reader.LocalName, reader.NamespaceURI), reader.Value);
246                             }
247                             else
248                             {
249                                 SyndicationFeedFormatter.TraceSyndicationElementIgnoredOnRead(reader);
250                             }
251                         }
252                     }
253                 }
254             }
255             SyndicationFeedFormatter.MoveToStartElement(reader);
256             bool isEmptyElement = reader.IsEmptyElement;
257             reader.ReadStartElement();
258             if (!isEmptyElement)
259             {
260                 XmlBuffer buffer = null;
261                 XmlDictionaryWriter extWriter = null;
262                 try
263                 {
264                     while (reader.IsStartElement())
265                     {
266                         if (reader.IsStartElement(Atom10Constants.CategoryTag, Atom10Constants.Atom10Namespace))
267                         {
268                             SyndicationCategory category = CreateCategory(inlineCategories);
269                             Atom10FeedFormatter.ReadCategory(reader, category, version, preserveAttributeExtensions, preserveElementExtensions, maxExtensionSize);
270                             if (category.Scheme == null)
271                             {
272                                 category.Scheme = inlineCategories.Scheme;
273                             }
274                             inlineCategories.Categories.Add(category);
275                         }
276                         else if (!TryParseElement(reader, inlineCategories, version))
277                         {
278                             if (preserveElementExtensions)
279                             {
280                                 SyndicationFeedFormatter.CreateBufferIfRequiredAndWriteNode(ref buffer, ref extWriter, reader, maxExtensionSize);
281                             }
282                             else
283                             {
284                                 SyndicationFeedFormatter.TraceSyndicationElementIgnoredOnRead(reader);
285                                 reader.Skip();
286                             }
287                         }
288                     }
289                     LoadElementExtensions(buffer, extWriter, inlineCategories);
290                 }
291                 finally
292                 {
293                     if (extWriter != null)
294                     {
295                         extWriter.Close();
296                     }
297                 }
298                 reader.ReadEndElement();
299             }
300         }
301 
ReadReferencedCategories(XmlReader reader, ReferencedCategoriesDocument referencedCategories, Uri baseUri, Uri link, string version, bool preserveElementExtensions, bool preserveAttributeExtensions, int maxExtensionSize)302         private static void ReadReferencedCategories(XmlReader reader, ReferencedCategoriesDocument referencedCategories, Uri baseUri, Uri link, string version, bool preserveElementExtensions, bool preserveAttributeExtensions, int maxExtensionSize)
303         {
304             referencedCategories.BaseUri = baseUri;
305             referencedCategories.Link = link;
306             if (reader.HasAttributes)
307             {
308                 while (reader.MoveToNextAttribute())
309                 {
310                     if (reader.LocalName == "base" && reader.NamespaceURI == Atom10FeedFormatter.XmlNs)
311                     {
312                         referencedCategories.BaseUri = FeedUtils.CombineXmlBase(referencedCategories.BaseUri, reader.Value);
313                     }
314                     else if (reader.LocalName == "lang" && reader.NamespaceURI == Atom10FeedFormatter.XmlNs)
315                     {
316                         referencedCategories.Language = reader.Value;
317                     }
318                     else if (reader.LocalName == App10Constants.Href && reader.NamespaceURI == string.Empty)
319                     {
320                         continue;
321                     }
322                     else
323                     {
324                         string ns = reader.NamespaceURI;
325                         string name = reader.LocalName;
326                         if (FeedUtils.IsXmlns(name, ns) || FeedUtils.IsXmlSchemaType(name, ns))
327                         {
328                             continue;
329                         }
330                         string val = reader.Value;
331                         if (!TryParseAttribute(name, ns, val, referencedCategories, version))
332                         {
333                             if (preserveAttributeExtensions)
334                             {
335                                 referencedCategories.AttributeExtensions.Add(new XmlQualifiedName(reader.LocalName, reader.NamespaceURI), reader.Value);
336                             }
337                             else
338                             {
339                                 SyndicationFeedFormatter.TraceSyndicationElementIgnoredOnRead(reader);
340                             }
341                         }
342                     }
343                 }
344             }
345             reader.MoveToElement();
346             bool isEmptyElement = reader.IsEmptyElement;
347             reader.ReadStartElement();
348             if (!isEmptyElement)
349             {
350                 XmlBuffer buffer = null;
351                 XmlDictionaryWriter extWriter = null;
352                 try
353                 {
354                     while (reader.IsStartElement())
355                     {
356                         if (!TryParseElement(reader, referencedCategories, version))
357                         {
358                             if (preserveElementExtensions)
359                             {
360                                 SyndicationFeedFormatter.CreateBufferIfRequiredAndWriteNode(ref buffer, ref extWriter, reader, maxExtensionSize);
361                             }
362                             else
363                             {
364                                 SyndicationFeedFormatter.TraceSyndicationElementIgnoredOnRead(reader);
365                                 reader.Skip();
366                             }
367                         }
368                     }
369                     LoadElementExtensions(buffer, extWriter, referencedCategories);
370                 }
371                 finally
372                 {
373                     if (extWriter != null)
374                     {
375                         extWriter.Close();
376                     }
377                 }
378                 reader.ReadEndElement();
379             }
380         }
381 
WriteCategories(XmlWriter writer, CategoriesDocument categories, Uri baseUri, string version)382         private static void WriteCategories(XmlWriter writer, CategoriesDocument categories, Uri baseUri, string version)
383         {
384             writer.WriteStartElement(App10Constants.Prefix, App10Constants.Categories, App10Constants.Namespace);
385             WriteCategoriesInnerXml(writer, categories, baseUri, version);
386             writer.WriteEndElement();
387         }
388 
WriteInlineCategoriesContent(XmlWriter writer, InlineCategoriesDocument categories, string version)389         private static void WriteInlineCategoriesContent(XmlWriter writer, InlineCategoriesDocument categories, string version)
390         {
391             if (!string.IsNullOrEmpty(categories.Scheme))
392             {
393                 writer.WriteAttributeString(Atom10Constants.SchemeTag, categories.Scheme);
394             }
395             // by default, categories are not fixed
396             if (categories.IsFixed)
397             {
398                 writer.WriteAttributeString(App10Constants.Fixed, "yes");
399             }
400             WriteAttributeExtensions(writer, categories, version);
401             for (int i = 0; i < categories.Categories.Count; ++i)
402             {
403                 Atom10FeedFormatter.WriteCategory(writer, categories.Categories[i], version);
404             }
405             WriteElementExtensions(writer, categories, version);
406         }
407 
WriteReferencedCategoriesContent(XmlWriter writer, ReferencedCategoriesDocument categories, string version)408         private static void WriteReferencedCategoriesContent(XmlWriter writer, ReferencedCategoriesDocument categories, string version)
409         {
410             if (categories.Link != null)
411             {
412                 writer.WriteAttributeString(App10Constants.Href, FeedUtils.GetUriString(categories.Link));
413             }
414             WriteAttributeExtensions(writer, categories, version);
415             WriteElementExtensions(writer, categories, version);
416         }
417 
WriteXmlBase(XmlWriter writer, Uri baseUri)418         private static void WriteXmlBase(XmlWriter writer, Uri baseUri)
419         {
420             writer.WriteAttributeString("xml", "base", Atom10FeedFormatter.XmlNs, FeedUtils.GetUriString(baseUri));
421         }
422 
WriteXmlLang(XmlWriter writer, string lang)423         private static void WriteXmlLang(XmlWriter writer, string lang)
424         {
425             writer.WriteAttributeString("xml", "lang", Atom10FeedFormatter.XmlNs, lang);
426         }
427 
ReadCollection(XmlReader reader, Workspace workspace)428         private ResourceCollectionInfo ReadCollection(XmlReader reader, Workspace workspace)
429         {
430             ResourceCollectionInfo result = CreateCollection(workspace);
431             result.BaseUri = workspace.BaseUri;
432             if (reader.HasAttributes)
433             {
434                 while (reader.MoveToNextAttribute())
435                 {
436                     if (reader.LocalName == "base" && reader.NamespaceURI == Atom10FeedFormatter.XmlNs)
437                     {
438                         result.BaseUri = FeedUtils.CombineXmlBase(result.BaseUri, reader.Value);
439                     }
440                     else if (reader.LocalName == App10Constants.Href && reader.NamespaceURI == string.Empty)
441                     {
442                         result.Link = new Uri(reader.Value, UriKind.RelativeOrAbsolute);
443                     }
444                     else
445                     {
446                         string ns = reader.NamespaceURI;
447                         string name = reader.LocalName;
448                         if (FeedUtils.IsXmlns(name, ns) || FeedUtils.IsXmlSchemaType(name, ns))
449                         {
450                             continue;
451                         }
452                         string val = reader.Value;
453                         if (!TryParseAttribute(name, ns, val, result, this.Version))
454                         {
455                             if (_preserveAttributeExtensions)
456                             {
457                                 result.AttributeExtensions.Add(new XmlQualifiedName(reader.LocalName, reader.NamespaceURI), reader.Value);
458                             }
459                             else
460                             {
461                                 SyndicationFeedFormatter.TraceSyndicationElementIgnoredOnRead(reader);
462                             }
463                         }
464                     }
465                 }
466             }
467 
468             XmlBuffer buffer = null;
469             XmlDictionaryWriter extWriter = null;
470 
471             reader.ReadStartElement();
472             try
473             {
474                 while (reader.IsStartElement())
475                 {
476                     if (reader.IsStartElement(Atom10Constants.TitleTag, Atom10Constants.Atom10Namespace))
477                     {
478                         result.Title = Atom10FeedFormatter.ReadTextContentFrom(reader, "//app:service/app:workspace/app:collection/atom:title[@type]", _preserveAttributeExtensions);
479                     }
480                     else if (reader.IsStartElement(App10Constants.Categories, App10Constants.Namespace))
481                     {
482                         result.Categories.Add(ReadCategories(reader,
483                             result.BaseUri,
484                             delegate ()
485                             {
486                                 return CreateInlineCategories(result);
487                             },
488 
489                             delegate ()
490                             {
491                                 return CreateReferencedCategories(result);
492                             },
493                             this.Version,
494                             _preserveElementExtensions,
495                             _preserveAttributeExtensions,
496                             _maxExtensionSize));
497                     }
498                     else if (reader.IsStartElement(App10Constants.Accept, App10Constants.Namespace))
499                     {
500                         result.Accepts.Add(reader.ReadElementString());
501                     }
502                     else if (!TryParseElement(reader, result, this.Version))
503                     {
504                         if (_preserveElementExtensions)
505                         {
506                             SyndicationFeedFormatter.CreateBufferIfRequiredAndWriteNode(ref buffer, ref extWriter, reader, _maxExtensionSize);
507                         }
508                         else
509                         {
510                             SyndicationFeedFormatter.TraceSyndicationElementIgnoredOnRead(reader);
511                             reader.Skip();
512                         }
513                     }
514                 }
515                 LoadElementExtensions(buffer, extWriter, result);
516             }
517             finally
518             {
519                 if (extWriter != null)
520                 {
521                     extWriter.Close();
522                 }
523             }
524             reader.ReadEndElement();
525             return result;
526         }
527 
ReadDocument(XmlReader reader)528         private void ReadDocument(XmlReader reader)
529         {
530             ServiceDocument result = CreateDocumentInstance();
531             try
532             {
533                 SyndicationFeedFormatter.MoveToStartElement(reader);
534                 bool elementIsEmpty = reader.IsEmptyElement;
535                 if (reader.HasAttributes)
536                 {
537                     while (reader.MoveToNextAttribute())
538                     {
539                         if (reader.LocalName == "lang" && reader.NamespaceURI == Atom10FeedFormatter.XmlNs)
540                         {
541                             result.Language = reader.Value;
542                         }
543                         else if (reader.LocalName == "base" && reader.NamespaceURI == Atom10FeedFormatter.XmlNs)
544                         {
545                             result.BaseUri = new Uri(reader.Value, UriKind.RelativeOrAbsolute);
546                         }
547                         else
548                         {
549                             string ns = reader.NamespaceURI;
550                             string name = reader.LocalName;
551                             if (FeedUtils.IsXmlns(name, ns) || FeedUtils.IsXmlSchemaType(name, ns))
552                             {
553                                 continue;
554                             }
555                             string val = reader.Value;
556                             if (!TryParseAttribute(name, ns, val, result, this.Version))
557                             {
558                                 if (_preserveAttributeExtensions)
559                                 {
560                                     result.AttributeExtensions.Add(new XmlQualifiedName(reader.LocalName, reader.NamespaceURI), reader.Value);
561                                 }
562                                 else
563                                 {
564                                     SyndicationFeedFormatter.TraceSyndicationElementIgnoredOnRead(reader);
565                                 }
566                             }
567                         }
568                     }
569                 }
570                 XmlBuffer buffer = null;
571                 XmlDictionaryWriter extWriter = null;
572 
573                 reader.ReadStartElement();
574                 if (!elementIsEmpty)
575                 {
576                     try
577                     {
578                         while (reader.IsStartElement())
579                         {
580                             if (reader.IsStartElement(App10Constants.Workspace, App10Constants.Namespace))
581                             {
582                                 result.Workspaces.Add(ReadWorkspace(reader, result));
583                             }
584                             else if (!TryParseElement(reader, result, this.Version))
585                             {
586                                 if (_preserveElementExtensions)
587                                 {
588                                     SyndicationFeedFormatter.CreateBufferIfRequiredAndWriteNode(ref buffer, ref extWriter, reader, _maxExtensionSize);
589                                 }
590                                 else
591                                 {
592                                     SyndicationFeedFormatter.TraceSyndicationElementIgnoredOnRead(reader);
593                                     reader.Skip();
594                                 }
595                             }
596                         }
597                         LoadElementExtensions(buffer, extWriter, result);
598                     }
599                     finally
600                     {
601                         if (extWriter != null)
602                         {
603                             extWriter.Close();
604                         }
605                     }
606                 }
607                 reader.ReadEndElement();
608             }
609             catch (FormatException e)
610             {
611                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(FeedUtils.AddLineInfo(reader, SR.ErrorParsingDocument), e));
612             }
613             catch (ArgumentException e)
614             {
615                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(FeedUtils.AddLineInfo(reader, SR.ErrorParsingDocument), e));
616             }
617             SetDocument(result);
618         }
619 
ReadWorkspace(XmlReader reader, ServiceDocument document)620         private Workspace ReadWorkspace(XmlReader reader, ServiceDocument document)
621         {
622             Workspace result = CreateWorkspace(document);
623             result.BaseUri = document.BaseUri;
624             if (reader.HasAttributes)
625             {
626                 while (reader.MoveToNextAttribute())
627                 {
628                     if (reader.LocalName == "base" && reader.NamespaceURI == Atom10FeedFormatter.XmlNs)
629                     {
630                         result.BaseUri = FeedUtils.CombineXmlBase(result.BaseUri, reader.Value);
631                     }
632                     else
633                     {
634                         string ns = reader.NamespaceURI;
635                         string name = reader.LocalName;
636                         if (FeedUtils.IsXmlns(name, ns) || FeedUtils.IsXmlSchemaType(name, ns))
637                         {
638                             continue;
639                         }
640                         string val = reader.Value;
641                         if (!TryParseAttribute(name, ns, val, result, this.Version))
642                         {
643                             if (_preserveAttributeExtensions)
644                             {
645                                 result.AttributeExtensions.Add(new XmlQualifiedName(reader.LocalName, reader.NamespaceURI), reader.Value);
646                             }
647                             else
648                             {
649                                 SyndicationFeedFormatter.TraceSyndicationElementIgnoredOnRead(reader);
650                             }
651                         }
652                     }
653                 }
654             }
655 
656             XmlBuffer buffer = null;
657             XmlDictionaryWriter extWriter = null;
658 
659             reader.ReadStartElement();
660             try
661             {
662                 while (reader.IsStartElement())
663                 {
664                     if (reader.IsStartElement(Atom10Constants.TitleTag, Atom10Constants.Atom10Namespace))
665                     {
666                         result.Title = Atom10FeedFormatter.ReadTextContentFrom(reader, "//app:service/app:workspace/atom:title[@type]", _preserveAttributeExtensions);
667                     }
668                     else if (reader.IsStartElement(App10Constants.Collection, App10Constants.Namespace))
669                     {
670                         result.Collections.Add(ReadCollection(reader, result));
671                     }
672                     else if (!TryParseElement(reader, result, this.Version))
673                     {
674                         if (_preserveElementExtensions)
675                         {
676                             SyndicationFeedFormatter.CreateBufferIfRequiredAndWriteNode(ref buffer, ref extWriter, reader, _maxExtensionSize);
677                         }
678                         else
679                         {
680                             SyndicationFeedFormatter.TraceSyndicationElementIgnoredOnRead(reader);
681                             reader.Skip();
682                         }
683                     }
684                 }
685                 LoadElementExtensions(buffer, extWriter, result);
686             }
687             finally
688             {
689                 if (extWriter != null)
690                 {
691                     extWriter.Close();
692                 }
693             }
694             reader.ReadEndElement();
695             return result;
696         }
697 
WriteCollection(XmlWriter writer, ResourceCollectionInfo collection, Uri baseUri)698         private void WriteCollection(XmlWriter writer, ResourceCollectionInfo collection, Uri baseUri)
699         {
700             writer.WriteStartElement(App10Constants.Prefix, App10Constants.Collection, App10Constants.Namespace);
701             Uri baseUriToWrite = FeedUtils.GetBaseUriToWrite(baseUri, collection.BaseUri);
702             if (baseUriToWrite != null)
703             {
704                 baseUri = collection.BaseUri;
705                 WriteXmlBase(writer, baseUriToWrite);
706             }
707             if (collection.Link != null)
708             {
709                 writer.WriteAttributeString(App10Constants.Href, FeedUtils.GetUriString(collection.Link));
710             }
711             WriteAttributeExtensions(writer, collection, this.Version);
712             if (collection.Title != null)
713             {
714                 collection.Title.WriteTo(writer, Atom10Constants.TitleTag, Atom10Constants.Atom10Namespace);
715             }
716             for (int i = 0; i < collection.Accepts.Count; ++i)
717             {
718                 writer.WriteElementString(App10Constants.Prefix, App10Constants.Accept, App10Constants.Namespace, collection.Accepts[i]);
719             }
720             for (int i = 0; i < collection.Categories.Count; ++i)
721             {
722                 WriteCategories(writer, collection.Categories[i], baseUri, this.Version);
723             }
724             WriteElementExtensions(writer, collection, this.Version);
725             writer.WriteEndElement();
726         }
727 
WriteDocument(XmlWriter writer)728         private void WriteDocument(XmlWriter writer)
729         {
730             // declare the atom10 namespace upfront for compactness
731             writer.WriteAttributeString(Atom10Constants.Atom10Prefix, Atom10FeedFormatter.XmlNsNs, Atom10Constants.Atom10Namespace);
732             if (!string.IsNullOrEmpty(this.Document.Language))
733             {
734                 WriteXmlLang(writer, this.Document.Language);
735             }
736             Uri baseUri = this.Document.BaseUri;
737             if (baseUri != null)
738             {
739                 WriteXmlBase(writer, baseUri);
740             }
741             WriteAttributeExtensions(writer, this.Document, this.Version);
742 
743             for (int i = 0; i < this.Document.Workspaces.Count; ++i)
744             {
745                 WriteWorkspace(writer, this.Document.Workspaces[i], baseUri);
746             }
747             WriteElementExtensions(writer, this.Document, this.Version);
748         }
749 
WriteWorkspace(XmlWriter writer, Workspace workspace, Uri baseUri)750         private void WriteWorkspace(XmlWriter writer, Workspace workspace, Uri baseUri)
751         {
752             writer.WriteStartElement(App10Constants.Prefix, App10Constants.Workspace, App10Constants.Namespace);
753             Uri baseUriToWrite = FeedUtils.GetBaseUriToWrite(baseUri, workspace.BaseUri);
754             if (baseUriToWrite != null)
755             {
756                 baseUri = workspace.BaseUri;
757                 WriteXmlBase(writer, baseUriToWrite);
758             }
759             WriteAttributeExtensions(writer, workspace, this.Version);
760             if (workspace.Title != null)
761             {
762                 workspace.Title.WriteTo(writer, Atom10Constants.TitleTag, Atom10Constants.Atom10Namespace);
763             }
764             for (int i = 0; i < workspace.Collections.Count; ++i)
765             {
766                 WriteCollection(writer, workspace.Collections[i], baseUri);
767             }
768             WriteElementExtensions(writer, workspace, this.Version);
769             writer.WriteEndElement();
770         }
771     }
772 
773     [XmlRoot(ElementName = App10Constants.Service, Namespace = App10Constants.Namespace)]
774     public class AtomPub10ServiceDocumentFormatter<TServiceDocument> : AtomPub10ServiceDocumentFormatter
775         where TServiceDocument : ServiceDocument, new()
776     {
AtomPub10ServiceDocumentFormatter()777         public AtomPub10ServiceDocumentFormatter() :
778             base(typeof(TServiceDocument))
779         {
780         }
781 
AtomPub10ServiceDocumentFormatter(TServiceDocument documentToWrite)782         public AtomPub10ServiceDocumentFormatter(TServiceDocument documentToWrite)
783             : base(documentToWrite)
784         {
785         }
786 
CreateDocumentInstance()787         protected override ServiceDocument CreateDocumentInstance()
788         {
789             return new TServiceDocument();
790         }
791     }
792 }
793