2 // XmlBinaryDictionaryWriter.cs
5 // Atsushi Enomoto <atsushi@ximian.com>
7 // Copyright (C) 2005, 2007 Novell, Inc. http://www.novell.com
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 using System.Collections;
32 using System.Collections.Specialized;
33 using System.Collections.Generic;
34 using System.Globalization;
39 using BF = System.Xml.XmlBinaryFormat;
43 internal partial class XmlBinaryDictionaryWriter : XmlDictionaryWriter
45 class MyBinaryWriter : BinaryWriter
47 public MyBinaryWriter (Stream s)
52 public void WriteFlexibleInt (int value)
54 Write7BitEncodedInt (value);
59 MyBinaryWriter original, writer, buffer_writer;
60 IXmlDictionary dict_ext;
61 XmlDictionary dict_int = new XmlDictionary ();
62 XmlBinaryWriterSession session;
64 Encoding utf8Enc = new UTF8Encoding ();
65 MemoryStream buffer = new MemoryStream ();
67 const string XmlNamespace = "http://www.w3.org/XML/1998/namespace";
68 const string XmlnsNamespace = "http://www.w3.org/2000/xmlns/";
70 WriteState state = WriteState.Start;
71 bool open_start_element = false;
72 // transient current node info
73 List<KeyValuePair<string,object>> namespaces = new List<KeyValuePair<string,object>> ();
74 string xml_lang = null;
75 XmlSpace xml_space = XmlSpace.None;
78 Stack<int> ns_index_stack = new Stack<int> ();
79 Stack<string> xml_lang_stack = new Stack<string> ();
80 Stack<XmlSpace> xml_space_stack = new Stack<XmlSpace> ();
81 Stack<string> element_ns_stack = new Stack<string> ();
82 string element_ns = String.Empty;
84 string element_prefix; // only meaningful at Element state
85 // current attribute info
87 string current_attr_prefix;
88 object current_attr_name, current_attr_ns;
89 bool attr_typed_value;
90 SaveTarget save_target;
99 // XmlWriterSettings support
105 public XmlBinaryDictionaryWriter (Stream stream,
106 IXmlDictionary dictionary,
107 XmlBinaryWriterSession session, bool ownsStream)
109 if (dictionary == null)
110 dictionary = new XmlDictionary ();
112 session = new XmlBinaryWriterSession ();
114 original = new MyBinaryWriter (stream);
115 this.writer = original;
116 buffer_writer = new MyBinaryWriter (buffer);
117 this.dict_ext = dictionary;
118 this.session = session;
119 owns_stream = ownsStream;
121 AddNamespace ("xml", "http://www.w3.org/XML/1998/namespace");
122 AddNamespace ("xml", "http://www.w3.org/2000/xmlns/");
130 public override WriteState WriteState {
131 get { return state; }
134 public override string XmlLang {
135 get { return xml_lang; }
138 public override XmlSpace XmlSpace {
139 get { return xml_space; }
146 private void AddMissingElementXmlns ()
148 // push new namespaces to manager.
149 for (int i = ns_index; i < namespaces.Count; i++) {
150 var ent = namespaces [i];
151 string prefix = (string) ent.Key;
152 string ns = ent.Value as string;
153 XmlDictionaryString dns = ent.Value as XmlDictionaryString;
155 if (prefix.Length > 0) {
156 writer.Write (BF.PrefixNSString);
157 writer.Write (prefix);
160 writer.Write (BF.DefaultNSString);
163 if (prefix.Length > 0) {
164 writer.Write (BF.PrefixNSIndex);
165 writer.Write (prefix);
168 writer.Write (BF.DefaultNSIndex);
169 WriteDictionaryIndex (dns);
172 ns_index = namespaces.Count;
175 private void CheckState ()
177 if (state == WriteState.Closed) {
178 throw new InvalidOperationException ("The Writer is closed.");
182 void ProcessStateForContent ()
186 if (state == WriteState.Element)
187 CloseStartElement ();
189 ProcessPendingBuffer (false, false);
190 if (state != WriteState.Attribute)
191 writer = buffer_writer;
194 void ProcessTypedValue ()
196 ProcessStateForContent ();
197 if (state == WriteState.Attribute) {
198 if (attr_typed_value)
199 throw new InvalidOperationException (String.Format ("A typed value for the attribute '{0}' in namespace '{1}' was already written", current_attr_name, current_attr_ns));
200 attr_typed_value = true;
204 void ProcessPendingBuffer (bool last, bool endElement)
206 if (buffer.Position > 0) {
207 byte [] arr = buffer.GetBuffer ();
210 original.Write (arr, 0, (int) buffer.Position);
211 buffer.SetLength (0);
217 public override void Close ()
219 CloseOpenAttributeAndElements ();
223 else if (state != WriteState.Closed)
225 state = WriteState.Closed;
228 private void CloseOpenAttributeAndElements ()
230 CloseStartElement ();
232 while (element_count > 0)
236 private void CloseStartElement ()
238 if (!open_start_element)
241 if (state == WriteState.Attribute)
242 WriteEndAttribute ();
244 AddMissingElementXmlns ();
246 state = WriteState.Content;
247 open_start_element = false;
250 public override void Flush ()
255 public override string LookupPrefix (string ns)
257 if (ns == null || ns == String.Empty)
258 throw new ArgumentException ("The Namespace cannot be empty.");
260 var de = namespaces.LastOrDefault (i => i.Value.ToString () == ns);
261 return de.Key; // de is KeyValuePair and its default key is null.
264 public override void WriteBase64 (byte[] buffer, int index, int count)
267 throw new IndexOutOfRangeException ("Negative count");
268 ProcessStateForContent ();
271 writer.Write (BF.Bytes8);
272 writer.Write ((byte) count);
273 writer.Write (buffer, index, count);
274 } else if (count < 0x10000) {
275 writer.Write (BF.Bytes8);
276 writer.Write ((ushort) count);
277 writer.Write (buffer, index, count);
279 writer.Write (BF.Bytes32);
280 writer.Write (count);
281 writer.Write (buffer, index, count);
285 public override void WriteCData (string text)
287 if (text.IndexOf ("]]>") >= 0)
288 throw new ArgumentException ("CDATA section cannot contain text \"]]>\".");
290 ProcessStateForContent ();
292 WriteTextBinary (text);
295 public override void WriteCharEntity (char ch)
297 WriteChars (new char [] {ch}, 0, 1);
300 public override void WriteChars (char[] buffer, int index, int count)
302 ProcessStateForContent ();
304 int blen = Encoding.UTF8.GetByteCount (buffer, index, count);
307 writer.Write (BF.EmptyText);
308 else if (blen < 0x100) {
309 writer.Write (BF.Chars8);
310 writer.Write ((byte) blen);
311 writer.Write (buffer, index, count);
312 } else if (blen < 0x10000) {
313 writer.Write (BF.Chars16);
314 writer.Write ((ushort) blen);
315 writer.Write (buffer, index, count);
317 writer.Write (BF.Chars32);
319 writer.Write (buffer, index, count);
323 public override void WriteComment (string text)
325 if (text.EndsWith("-"))
326 throw new ArgumentException ("An XML comment cannot contain \"--\" inside.");
327 else if (text.IndexOf("--") > 0)
328 throw new ArgumentException ("An XML comment cannot end with \"-\".");
330 ProcessStateForContent ();
332 if (state == WriteState.Attribute)
333 throw new InvalidOperationException ("Comment node is not allowed inside an attribute");
335 writer.Write (BF.Comment);
339 public override void WriteDocType (string name, string pubid, string sysid, string subset)
341 throw new NotSupportedException ("This XmlWriter implementation does not support document type.");
344 public override void WriteEndAttribute ()
346 if (state != WriteState.Attribute)
347 throw new InvalidOperationException("Token EndAttribute in state Start would result in an invalid XML document.");
351 if (attr_value == null)
352 attr_value = String.Empty;
354 switch (save_target) {
355 case SaveTarget.XmlLang:
356 xml_lang = attr_value;
358 case SaveTarget.XmlSpace:
359 switch (attr_value) {
361 xml_space = XmlSpace.Preserve;
364 xml_space = XmlSpace.Default;
367 throw new ArgumentException (String.Format ("Invalid xml:space value: '{0}'", attr_value));
370 case SaveTarget.Namespaces:
371 if (current_attr_name.ToString ().Length > 0 && attr_value.Length == 0)
372 throw new ArgumentException ("Cannot use prefix with an empty namespace.");
374 AddNamespaceChecked (current_attr_name.ToString (), attr_value);
377 if (!attr_typed_value)
378 WriteTextBinary (attr_value);
382 if (current_attr_prefix.Length > 0 && save_target != SaveTarget.Namespaces)
383 AddNamespaceChecked (current_attr_prefix, current_attr_ns);
385 state = WriteState.Element;
386 current_attr_prefix = null;
387 current_attr_name = null;
388 current_attr_ns = null;
390 attr_typed_value = false;
393 public override void WriteEndDocument ()
395 CloseOpenAttributeAndElements ();
398 case WriteState.Start:
399 throw new InvalidOperationException ("Document has not started.");
400 case WriteState.Prolog:
401 throw new ArgumentException ("This document does not have a root element.");
404 state = WriteState.Start;
407 bool SupportsCombinedEndElementSupport (byte operation)
416 public override void WriteEndElement ()
418 if (element_count-- == 0)
419 throw new InvalidOperationException("There was no XML start tag open.");
421 if (state == WriteState.Attribute)
422 WriteEndAttribute ();
424 // Comment+EndElement does not exist
425 bool needExplicitEndElement = buffer.Position == 0 || !SupportsCombinedEndElementSupport (buffer.GetBuffer () [0]);
426 ProcessPendingBuffer (true, !needExplicitEndElement);
428 AddMissingElementXmlns ();
430 if (needExplicitEndElement)
431 writer.Write (BF.EndElement);
433 element_ns = element_ns_stack.Pop ();
434 xml_lang = xml_lang_stack.Pop ();
435 xml_space = xml_space_stack.Pop ();
436 int cur = namespaces.Count;
437 ns_index = ns_index_stack.Pop ();
438 namespaces.RemoveRange (ns_index, cur - ns_index);
439 open_start_element = false;
444 public override void WriteEntityRef (string name)
446 throw new NotSupportedException ("This XmlWriter implementation does not support entity references.");
449 public override void WriteFullEndElement ()
454 public override void WriteProcessingInstruction (string name, string text)
457 throw new ArgumentException ("Processing instructions are not supported. ('xml' is allowed for XmlDeclaration; this is because of design problem of ECMA XmlWriter)");
458 // Otherwise, silently ignored. WriteStartDocument()
459 // is still callable after this method(!)
462 public override void WriteQualifiedName (XmlDictionaryString local, XmlDictionaryString ns)
464 string prefix = namespaces.LastOrDefault (i => i.Value.ToString () == ns.ToString ()).Key;
465 bool use_dic = prefix != null;
467 prefix = LookupPrefix (ns.Value);
469 throw new ArgumentException (String.Format ("Namespace URI '{0}' is not bound to any of the prefixes", ns));
471 ProcessTypedValue ();
473 if (use_dic && prefix.Length == 1) {
474 writer.Write (BF.QNameIndex);
475 writer.Write ((byte) (prefix [0] - 'a'));
476 WriteDictionaryIndex (local);
478 // QNameIndex is not applicable.
479 WriteString (prefix);
485 public override void WriteRaw (string data)
490 public override void WriteRaw (char[] buffer, int index, int count)
492 WriteChars (buffer, index, count);
495 void CheckStateForAttribute ()
499 if (state != WriteState.Element)
500 throw new InvalidOperationException ("Token StartAttribute in state " + WriteState + " would result in an invalid XML document.");
503 string CreateNewPrefix ()
505 return CreateNewPrefix (String.Empty);
508 string CreateNewPrefix (string p)
510 for (char c = 'a'; c <= 'z'; c++)
511 if (!namespaces.Any (iter => iter.Key == p + c))
513 for (char c = 'a'; c <= 'z'; c++) {
514 var s = CreateNewPrefix (c.ToString ());
518 throw new InvalidOperationException ("too many prefix population");
521 bool CollectionContains (ICollection col, string value)
523 foreach (string v in col)
529 void ProcessStartAttributeCommon (ref string prefix, string localName, string ns, object nameObj, object nsObj)
531 // dummy prefix is created here, while the caller
532 // still uses empty string as the prefix there.
533 if (prefix.Length == 0 && ns.Length > 0) {
534 prefix = LookupPrefix (ns);
535 // Not only null but also ""; when the returned
536 // string is empty, then it still needs a dummy
537 // prefix, since default namespace does not
538 // apply to attribute
539 if (String.IsNullOrEmpty (prefix))
540 prefix = CreateNewPrefix ();
542 else if (prefix.Length > 0 && ns.Length == 0) {
545 nsObj = ns = XmlNamespace;
548 nsObj = ns = XmlnsNamespace;
551 throw new ArgumentException ("Cannot use prefix with an empty namespace.");
554 // here we omit such cases that it is used for writing
555 // namespace-less xml, unlike XmlTextWriter.
556 if (prefix == "xmlns" && ns != XmlnsNamespace)
557 throw new ArgumentException (String.Format ("The 'xmlns' attribute is bound to the reserved namespace '{0}'", XmlnsNamespace));
559 CheckStateForAttribute ();
561 state = WriteState.Attribute;
563 save_target = SaveTarget.None;
566 // MS.NET looks to allow other names than
567 // lang and space (e.g. xml:link, xml:hack).
571 save_target = SaveTarget.XmlLang;
574 save_target = SaveTarget.XmlSpace;
579 save_target = SaveTarget.Namespaces;
583 current_attr_prefix = prefix;
584 current_attr_name = nameObj;
585 current_attr_ns = nsObj;
588 public override void WriteStartAttribute (string prefix, string localName, string ns)
591 prefix = String.Empty;
594 if (localName == "xmlns" && prefix.Length == 0) {
596 localName = String.Empty;
599 ProcessStartAttributeCommon (ref prefix, localName, ns, localName, ns);
601 // for namespace nodes we don't write attribute node here.
602 if (save_target == SaveTarget.Namespaces)
605 byte op = prefix.Length == 1 && 'a' <= prefix [0] && prefix [0] <= 'z' ?
606 (byte) (prefix [0] - 'a' + BF.PrefixNAttrStringStart) :
607 prefix.Length == 0 ? BF.AttrString :
610 if (BF.PrefixNAttrStringStart <= op && op <= BF.PrefixNAttrStringEnd) {
612 writer.Write (localName);
615 if (prefix.Length > 0)
616 writer.Write (prefix);
617 writer.Write (localName);
621 public override void WriteStartDocument ()
623 WriteStartDocument (false);
626 public override void WriteStartDocument (bool standalone)
628 if (state != WriteState.Start)
629 throw new InvalidOperationException("WriteStartDocument should be the first call.");
633 // write nothing to stream.
635 state = WriteState.Prolog;
638 void PrepareStartElement ()
640 ProcessPendingBuffer (true, false);
642 CloseStartElement ();
646 element_ns_stack.Push (element_ns);
647 xml_lang_stack.Push (xml_lang);
648 xml_space_stack.Push (xml_space);
649 ns_index_stack.Push (ns_index);
652 public override void WriteStartElement (string prefix, string localName, string ns)
654 PrepareStartElement ();
656 if ((prefix != null && prefix != String.Empty) && ((ns == null) || (ns == String.Empty)))
657 throw new ArgumentException ("Cannot use a prefix with an empty namespace.");
661 if (ns == String.Empty)
662 prefix = String.Empty;
664 prefix = String.Empty;
666 byte op = prefix.Length == 1 && 'a' <= prefix [0] && prefix [0] <= 'z' ?
667 (byte) (prefix [0] - 'a' + BF.PrefixNElemStringStart) :
668 prefix.Length == 0 ? BF.ElemString :
671 if (BF.PrefixNElemStringStart <= op && op <= BF.PrefixNElemStringEnd) {
673 writer.Write (localName);
676 if (prefix.Length > 0)
677 writer.Write (prefix);
678 writer.Write (localName);
681 OpenElement (prefix, ns);
684 void OpenElement (string prefix, object nsobj)
686 string ns = nsobj.ToString ();
688 state = WriteState.Element;
689 open_start_element = true;
690 element_prefix = prefix;
692 element_ns = nsobj.ToString ();
694 if (element_ns != String.Empty && LookupPrefix (element_ns) != prefix)
695 AddNamespace (prefix, nsobj);
698 void AddNamespace (string prefix, object nsobj)
700 namespaces.Add (new KeyValuePair<string,object> (prefix, nsobj));
703 void CheckIfTextAllowed ()
706 case WriteState.Start:
707 case WriteState.Prolog:
708 throw new InvalidOperationException ("Token content in state Prolog would result in an invalid XML document.");
712 public override void WriteString (string text)
715 throw new ArgumentNullException ("text");
716 CheckIfTextAllowed ();
721 ProcessStateForContent ();
723 if (state == WriteState.Attribute)
726 WriteTextBinary (text);
729 public override void WriteString (XmlDictionaryString text)
732 throw new ArgumentNullException ("text");
733 CheckIfTextAllowed ();
736 text = XmlDictionaryString.Empty;
738 ProcessStateForContent ();
740 if (state == WriteState.Attribute)
741 attr_value += text.Value;
742 else if (text.Equals (XmlDictionary.Empty))
743 writer.Write (BF.EmptyText);
745 writer.Write (BF.TextIndex);
746 WriteDictionaryIndex (text);
750 public override void WriteSurrogateCharEntity (char lowChar, char highChar)
752 WriteChars (new char [] {highChar, lowChar}, 0, 2);
755 public override void WriteWhitespace (string ws)
757 for (int i = 0; i < ws.Length; i++) {
759 case ' ': case '\t': case '\r': case '\n':
762 throw new ArgumentException ("Invalid Whitespace");
766 ProcessStateForContent ();
768 WriteTextBinary (ws);
771 public override void WriteXmlnsAttribute (string prefix, string namespaceUri)
773 if (namespaceUri == null)
774 throw new ArgumentNullException ("namespaceUri");
776 if (String.IsNullOrEmpty (prefix))
777 prefix = CreateNewPrefix ();
779 CheckStateForAttribute ();
781 AddNamespaceChecked (prefix, namespaceUri);
783 state = WriteState.Element;
786 void AddNamespaceChecked (string prefix, object ns)
788 switch (ns.ToString ()) {
795 throw new InvalidOperationException ();
796 var o = namespaces.LastOrDefault (i => i.Key == prefix);
797 if (o.Key != null) { // i.e. exists
798 if (o.Value.ToString () != ns.ToString ()) {
799 if (namespaces.LastIndexOf (o) >= ns_index)
800 throw new ArgumentException (String.Format ("The prefix '{0}' is already mapped to another namespace URI '{1}' in this element scope and cannot be mapped to '{2}'", prefix ?? "(null)", o.Value ?? "(null)", ns.ToString ()));
802 AddNamespace (prefix, ns);
806 AddNamespace (prefix, ns);
809 #region DictionaryString
811 void WriteDictionaryIndex (XmlDictionaryString ds)
813 XmlDictionaryString ds2;
814 bool isSession = false;
816 if (ds.Dictionary != dict_ext) {
818 if (dict_int.TryLookup (ds.Value, out ds2))
820 if (!session.TryLookup (ds, out idx))
821 session.TryAdd (dict_int.Add (ds.Value), out idx);
824 writer.Write ((byte) (0x80 + ((idx % 0x80) << 1) + (isSession ? 1 : 0)));
825 writer.Write ((byte) ((byte) (idx / 0x80) << 1));
828 writer.Write ((byte) (((idx % 0x80) << 1) + (isSession ? 1 : 0)));
831 public override void WriteStartElement (string prefix, XmlDictionaryString localName, XmlDictionaryString namespaceUri)
833 PrepareStartElement ();
836 prefix = String.Empty;
838 byte op = prefix.Length == 1 && 'a' <= prefix [0] && prefix [0] <= 'z' ?
839 (byte) (prefix [0] - 'a' + BF.PrefixNElemIndexStart) :
840 prefix.Length == 0 ? BF.ElemIndex :
843 if (BF.PrefixNElemIndexStart <= op && op <= BF.PrefixNElemIndexEnd) {
845 WriteDictionaryIndex (localName);
848 if (prefix.Length > 0)
849 writer.Write (prefix);
850 WriteDictionaryIndex (localName);
853 OpenElement (prefix, namespaceUri);
856 public override void WriteStartAttribute (string prefix, XmlDictionaryString localName, XmlDictionaryString ns)
858 if (localName == null)
859 throw new ArgumentNullException ("localName");
861 prefix = String.Empty;
863 ns = XmlDictionaryString.Empty;
864 if (localName.Value == "xmlns" && prefix.Length == 0) {
866 localName = XmlDictionaryString.Empty;
869 ProcessStartAttributeCommon (ref prefix, localName.Value, ns.Value, localName, ns);
871 if (save_target == SaveTarget.Namespaces)
874 if (prefix.Length == 1 && 'a' <= prefix [0] && prefix [0] <= 'z') {
875 writer.Write ((byte) (prefix [0] - 'a' + BF.PrefixNAttrIndexStart));
876 WriteDictionaryIndex (localName);
878 byte op = ns.Value.Length == 0 ? BF.AttrIndex :BF.AttrIndexPrefix;
881 if (prefix.Length > 0)
882 writer.Write (prefix);
883 WriteDictionaryIndex (localName);
887 public override void WriteXmlnsAttribute (string prefix, XmlDictionaryString namespaceUri)
889 if (namespaceUri == null)
890 throw new ArgumentNullException ("namespaceUri");
892 if (String.IsNullOrEmpty (prefix))
893 prefix = CreateNewPrefix ();
895 CheckStateForAttribute ();
897 AddNamespaceChecked (prefix, namespaceUri);
899 state = WriteState.Element;
904 public override void WriteValue (bool value)
906 ProcessTypedValue ();
907 writer.Write ((byte) (value ? BF.BoolTrue : BF.BoolFalse));
910 public override void WriteValue (int value)
912 WriteValue ((long) value);
915 public override void WriteValue (long value)
917 ProcessTypedValue ();
920 writer.Write (BF.Zero);
922 writer.Write (BF.One);
923 else if (value < 0 || value > uint.MaxValue) {
924 writer.Write (BF.Int64);
925 for (int i = 0; i < 8; i++) {
926 writer.Write ((byte) (value & 0xFF));
929 } else if (value <= byte.MaxValue) {
930 writer.Write (BF.Int8);
931 writer.Write ((byte) value);
932 } else if (value <= short.MaxValue) {
933 writer.Write (BF.Int16);
934 writer.Write ((byte) (value & 0xFF));
935 writer.Write ((byte) (value >> 8));
936 } else if (value <= int.MaxValue) {
937 writer.Write (BF.Int32);
938 for (int i = 0; i < 4; i++) {
939 writer.Write ((byte) (value & 0xFF));
945 public override void WriteValue (float value)
947 ProcessTypedValue ();
948 writer.Write (BF.Single);
949 WriteValueContent (value);
952 void WriteValueContent (float value)
954 writer.Write (value);
957 public override void WriteValue (double value)
959 ProcessTypedValue ();
960 writer.Write (BF.Double);
961 WriteValueContent (value);
964 void WriteValueContent (double value)
966 writer.Write (value);
969 public override void WriteValue (decimal value)
971 ProcessTypedValue ();
972 writer.Write (BF.Decimal);
973 WriteValueContent (value);
976 void WriteValueContent (decimal value)
978 int [] bits = Decimal.GetBits (value);
979 // so, looks like it is saved as its internal form,
980 // not the returned order.
981 // BinaryWriter.Write(Decimal) is useless here.
982 writer.Write (bits [3]);
983 writer.Write (bits [2]);
984 writer.Write (bits [0]);
985 writer.Write (bits [1]);
988 public override void WriteValue (DateTime value)
990 ProcessTypedValue ();
991 writer.Write (BF.DateTime);
992 WriteValueContent (value);
995 void WriteValueContent (DateTime value)
997 writer.Write (value.Ticks);
1000 public override void WriteValue (Guid value)
1002 ProcessTypedValue ();
1003 writer.Write (BF.Guid);
1004 WriteValueContent (value);
1007 void WriteValueContent (Guid value)
1009 byte [] bytes = value.ToByteArray ();
1010 writer.Write (bytes, 0, bytes.Length);
1013 public override void WriteValue (UniqueId value)
1016 throw new ArgumentNullException ("value");
1019 if (value.TryGetGuid (out guid)) {
1020 // this conditional branching is required for
1021 // attr_typed_value not being true.
1022 ProcessTypedValue ();
1024 writer.Write (BF.UniqueId);
1025 byte [] bytes = guid.ToByteArray ();
1026 writer.Write (bytes, 0, bytes.Length);
1028 WriteValue (value.ToString ());
1032 public override void WriteValue (TimeSpan value)
1034 ProcessTypedValue ();
1036 writer.Write (BF.TimeSpan);
1037 WriteValueContent (value);
1040 void WriteValueContent (TimeSpan value)
1042 WriteBigEndian (value.Ticks, 8);
1046 private void WriteBigEndian (long value, int digits)
1049 for (int i = 0; i < digits; i++) {
1050 v = (v << 8) + (value & 0xFF);
1053 for (int i = 0; i < digits; i++) {
1054 writer.Write ((byte) (v & 0xFF));
1059 private void WriteTextBinary (string text)
1061 if (text.Length == 0)
1062 writer.Write (BF.EmptyText);
1064 char [] arr = text.ToCharArray ();
1065 WriteChars (arr, 0, arr.Length);
1071 #region Write typed array content
1073 // they are packed in WriteValue(), so we cannot reuse
1074 // them for array content.
1076 void WriteValueContent (bool value)
1078 writer.Write (value ? (byte) 1 : (byte) 0);
1081 void WriteValueContent (short value)
1083 writer.Write (value);
1086 void WriteValueContent (int value)
1088 writer.Write (value);
1091 void WriteValueContent (long value)
1093 writer.Write (value);