2 // Copyright (C) 2010 Novell Inc. http://novell.com
4 // Permission is hereby granted, free of charge, to any person obtaining
5 // a copy of this software and associated documentation files (the
6 // "Software"), to deal in the Software without restriction, including
7 // without limitation the rights to use, copy, modify, merge, publish,
8 // distribute, sublicense, and/or sell copies of the Software, and to
9 // permit persons to whom the Software is furnished to do so, subject to
10 // the following conditions:
12 // The above copyright notice and this permission notice shall be
13 // included in all copies or substantial portions of the Software.
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 using System.Collections.Generic;
33 Unlike XmlWriter, XAML nodes are not immediately writable because object
34 output has to be delayed to be determined whether it should write
35 an attribute or an element.
37 ** NamespaceDeclarations
39 NamespaceDeclaration does not immediately participate in the state transition
40 but some write methods reject stored namespaces (e.g. WriteEndObject cannot
41 handle them). In such cases, they throw InvalidOperationException, while the
42 writer throws XamlXmlWriterException for usual state transition.
44 Though they still seems to affect some outputs. If a member with simple
45 value is written after a namespace, then it becomes an element, not attribute.
49 states are: Initial, ObjectStarted, MemberStarted, ValueWritten, MemberDone, End
51 Initial + StartObject -> ObjectStarted : push(xt)
52 ObjectStarted + StartMember -> MemberStarted : push(xm)
53 ObjectStarted + EndObject -> ObjectWritten or End : pop()
54 MemberStarted + StartObject -> ObjectStarted : push(xt)
55 MemberStarted + Value -> ValueWritten
56 MemberStarted + GetObject -> MemberDone : pop()
57 ObjectWritten + StartObject -> ObjectStarted : push(x)
58 ObjectWritten + Value -> ValueWritten : pop()
59 ObjectWritten + EndMember -> MemberDone : pop()
60 ValueWritten + StartObject -> invalid - or - ObjectStarted : push(x)
61 ValueWritten + Value -> invalid - or - ValueWritten
62 ValueWritten + EndMember -> MemberDone : pop()
63 MemberDone + EndObject -> ObjectWritten or End : pop() // xt
64 MemberDone + StartMember -> MemberStarted : push(xm)
66 (in XamlObjectWriter, Value must be followed by EndMember.)
72 internal class XamlWriterStateManager<TError,TNSError> : XamlWriterStateManager
73 where TError : Exception
74 where TNSError : Exception
76 public XamlWriterStateManager (bool isXmlWriter)
81 public override Exception CreateError (string msg)
83 return (Exception) Activator.CreateInstance (typeof (TError), new object [] {msg});
86 public override Exception CreateNamespaceError (string msg)
88 return (Exception) Activator.CreateInstance (typeof (TNSError), new object [] {msg});
92 internal enum XamlWriteState
103 internal abstract class XamlWriterStateManager
105 public XamlWriterStateManager (bool isXmlWriter)
107 allow_ns_at_value = isXmlWriter;
108 allow_object_after_value = isXmlWriter;
109 allow_parallel_values = !isXmlWriter;
110 allow_empty_member = !isXmlWriter;
114 bool allow_ns_at_value, allow_object_after_value, allow_parallel_values, allow_empty_member;
117 XamlWriteState state = XamlWriteState.Initial;
119 bool accept_multiple_values; // It is PositionalParameters-specific state.
121 public XamlWriteState State {
122 get { return state; }
125 // FIXME: actually this property is a hack. It should preserve stacked flag values for each nested member in current tree state.
126 public bool AcceptMultipleValues {
127 get { return accept_multiple_values; }
128 set { accept_multiple_values = value; }
131 public void OnClosingItem ()
133 // somewhat hacky state change to not reject StartMember->EndMember.
134 if (state == XamlWriteState.MemberStarted)
135 state = XamlWriteState.ValueWritten;
138 public void EndMember ()
140 RejectNamespaces (XamlNodeType.EndMember);
141 CheckState (XamlNodeType.EndMember);
142 state = XamlWriteState.MemberDone;
145 public void EndObject (bool hasMoreNodes)
147 RejectNamespaces (XamlNodeType.EndObject);
148 CheckState (XamlNodeType.EndObject);
149 state = hasMoreNodes ? XamlWriteState.ObjectWritten : XamlWriteState.End;
152 public void GetObject ()
154 CheckState (XamlNodeType.GetObject);
155 RejectNamespaces (XamlNodeType.GetObject);
156 state = XamlWriteState.MemberDone;
159 public void StartMember ()
161 CheckState (XamlNodeType.StartMember);
162 state = XamlWriteState.MemberStarted;
166 public void StartObject ()
168 CheckState (XamlNodeType.StartObject);
169 state = XamlWriteState.ObjectStarted;
175 CheckState (XamlNodeType.Value);
176 RejectNamespaces (XamlNodeType.Value);
177 state = XamlWriteState.ValueWritten;
180 public void Namespace ()
182 if (!allow_ns_at_value && (state == XamlWriteState.ValueWritten || state == XamlWriteState.ObjectStarted))
183 throw CreateError (String.Format ("Namespace declarations cannot be written at {0} state", state));
187 public void NamespaceCleanedUp ()
192 void CheckState (XamlNodeType next)
195 case XamlWriteState.Initial:
197 case XamlNodeType.StartObject:
201 case XamlWriteState.ObjectStarted:
203 case XamlNodeType.StartMember:
204 case XamlNodeType.EndObject:
208 case XamlWriteState.MemberStarted:
210 case XamlNodeType.StartObject:
211 case XamlNodeType.Value:
212 case XamlNodeType.GetObject:
214 case XamlNodeType.EndMember:
215 if (allow_empty_member)
220 case XamlWriteState.ObjectWritten:
222 case XamlNodeType.StartObject:
223 case XamlNodeType.Value:
224 case XamlNodeType.EndMember:
228 case XamlWriteState.ValueWritten:
230 case XamlNodeType.Value:
231 if (allow_parallel_values | accept_multiple_values)
234 case XamlNodeType.StartObject:
235 if (allow_object_after_value)
238 case XamlNodeType.EndMember:
242 case XamlWriteState.MemberDone:
244 case XamlNodeType.StartMember:
245 case XamlNodeType.EndObject:
250 throw CreateError (String.Format ("{0} is not allowed at current state {1}", next, state));
253 void RejectNamespaces (XamlNodeType next)
256 // strange, but on WriteEndMember it throws XamlXmlWriterException, while for other nodes it throws IOE.
257 string msg = String.Format ("Namespace declarations cannot be written before {0}", next);
258 if (next == XamlNodeType.EndMember)
259 throw CreateError (msg);
261 throw CreateNamespaceError (msg);
265 public abstract Exception CreateError (string msg);
266 public abstract Exception CreateNamespaceError (string msg);