a2b11ce5b7f291a3aa8b79b64fec5f358637c3f0
[mono.git] / mcs / class / RabbitMQ.Client / src / client / content / StreamWireFormatting.cs
1 // This source code is dual-licensed under the Apache License, version
2 // 2.0, and the Mozilla Public License, version 1.1.
3 //
4 // The APL v2.0:
5 //
6 //---------------------------------------------------------------------------
7 //   Copyright (C) 2007, 2008 LShift Ltd., Cohesive Financial
8 //   Technologies LLC., and Rabbit Technologies Ltd.
9 //
10 //   Licensed under the Apache License, Version 2.0 (the "License");
11 //   you may not use this file except in compliance with the License.
12 //   You may obtain a copy of the License at
13 //
14 //       http://www.apache.org/licenses/LICENSE-2.0
15 //
16 //   Unless required by applicable law or agreed to in writing, software
17 //   distributed under the License is distributed on an "AS IS" BASIS,
18 //   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 //   See the License for the specific language governing permissions and
20 //   limitations under the License.
21 //---------------------------------------------------------------------------
22 //
23 // The MPL v1.1:
24 //
25 //---------------------------------------------------------------------------
26 //   The contents of this file are subject to the Mozilla Public License
27 //   Version 1.1 (the "License"); you may not use this file except in
28 //   compliance with the License. You may obtain a copy of the License at
29 //   http://www.rabbitmq.com/mpl.html
30 //
31 //   Software distributed under the License is distributed on an "AS IS"
32 //   basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
33 //   License for the specific language governing rights and limitations
34 //   under the License.
35 //
36 //   The Original Code is The RabbitMQ .NET Client.
37 //
38 //   The Initial Developers of the Original Code are LShift Ltd.,
39 //   Cohesive Financial Technologies LLC., and Rabbit Technologies Ltd.
40 //
41 //   Portions created by LShift Ltd., Cohesive Financial Technologies
42 //   LLC., and Rabbit Technologies Ltd. are Copyright (C) 2007, 2008
43 //   LShift Ltd., Cohesive Financial Technologies LLC., and Rabbit
44 //   Technologies Ltd.;
45 //
46 //   All Rights Reserved.
47 //
48 //   Contributor(s): ______________________________________.
49 //
50 //---------------------------------------------------------------------------
51 using System;
52 using System.Net;
53 using System.Text;
54 using System.IO;
55
56 using RabbitMQ.Client;
57 using RabbitMQ.Util;
58
59 namespace RabbitMQ.Client.Content {
60     ///<summary>Tags used in parsing and generating StreamWireFormatting message bodies.</summary>
61     public enum StreamWireFormattingTag {
62         Bool = 0x01,
63         Byte = 0x02,
64         Bytes = 0x03,
65         Int16 = 0x04,
66         Char = 0x05,
67         Int32 = 0x06,
68         Int64 = 0x07,
69         Single = 0x08,
70         Double = 0x09,
71         String = 0x0A,
72         Null = 0x0B
73     };
74
75     ///<summary>Internal support class for use in reading and writing
76     ///information binary-compatible with QPid's "StreamMessage" wire
77     ///encoding.</summary>
78     public class StreamWireFormatting {
79         public static bool ReadBool(NetworkBinaryReader reader) {
80             object value = ReadNonnullObject("bool", reader);
81             if (value is bool) {
82                 return (bool) value;
83             }
84             if (value is string) {
85                 return PrimitiveParser.ParseBool((string) value);
86             }
87             PrimitiveParser.InvalidConversion("bool", value);
88             return false;
89         }
90
91         public static int ReadInt32(NetworkBinaryReader reader) {
92             object value = ReadNonnullObject("int", reader);
93             if (value is int || value is short || value is byte) {
94                 return (int) value;
95             }
96             if (value is string) {
97                 return PrimitiveParser.ParseInt((string) value);
98             }
99             PrimitiveParser.InvalidConversion("int", value);
100             return 0;
101         }
102
103         public static short ReadInt16(NetworkBinaryReader reader) {
104             object value = ReadNonnullObject("short", reader);
105             if (value is short || value is byte) {
106                 return (short) value;
107             }
108             if (value is string) {
109                 return PrimitiveParser.ParseShort((string) value);
110             }
111             PrimitiveParser.InvalidConversion("short", value);
112             return 0;
113         }
114
115         public static byte ReadByte(NetworkBinaryReader reader) {
116             object value = ReadNonnullObject("byte", reader);
117             if (value is byte) {
118                 return (byte) value;
119             }
120             if (value is string) {
121                 return PrimitiveParser.ParseByte((string) value);
122             }
123             PrimitiveParser.InvalidConversion("byte", value);
124             return 0;
125         }
126
127         public static char ReadChar(NetworkBinaryReader reader) {
128             object value = ReadNonnullObject("char", reader);
129             if (value is char) {
130                 return (char) value;
131             }
132             PrimitiveParser.InvalidConversion("char", value);
133             return (char) 0;
134         }
135
136         public static long ReadInt64(NetworkBinaryReader reader) {
137             object value = ReadNonnullObject("long", reader);
138             if (value is long || value is int || value is short || value is byte) {
139                 return (long) value;
140             }
141             if (value is string) {
142                 return PrimitiveParser.ParseLong((string) value);
143             }
144             PrimitiveParser.InvalidConversion("long", value);
145             return 0;
146         }
147
148         public static float ReadSingle(NetworkBinaryReader reader) {
149             object value = ReadNonnullObject("float", reader);
150             if (value is float) {
151                 return (float) value;
152             }
153             if (value is string) {
154                 return PrimitiveParser.ParseFloat((string) value);
155             }
156             PrimitiveParser.InvalidConversion("float", value);
157             return 0;
158         }
159
160         public static double ReadDouble(NetworkBinaryReader reader) {
161             object value = ReadNonnullObject("double", reader);
162             if (value is double || value is float) {
163                 return (double) value;
164             }
165             if (value is string) {
166                 return PrimitiveParser.ParseDouble((string) value);
167             }
168             PrimitiveParser.InvalidConversion("double", value);
169             return 0;
170         }
171
172         public static byte[] ReadBytes(NetworkBinaryReader reader) {
173             object value = ReadObject(reader);
174             if (value == null) {
175                 return null;
176             }
177             if (value is byte[]) {
178                 return (byte[]) value;
179             }
180             PrimitiveParser.InvalidConversion("byte[]", value);
181             return null;
182         }
183
184         public static string ReadString(NetworkBinaryReader reader) {
185             object value = ReadObject(reader);
186             if (value == null) {
187                 return null;
188             }
189             if (value is byte[]) {
190                 PrimitiveParser.InvalidConversion("string", value);
191                 return null;
192             }
193             return value.ToString();
194         }
195
196         ///<exception cref="ProtocolViolationException"/>
197         public static object ReadNonnullObject(string target, NetworkBinaryReader reader) {
198             object value = ReadObject(reader);
199             if (value == null) {
200                 throw new ProtocolViolationException(string.Format("Null {0} value not permitted",
201                                                                    target));
202             }
203             return value;
204         }
205
206         ///<exception cref="EndOfStreamException"/>
207         ///<exception cref="ProtocolViolationException"/>
208         public static object ReadObject(NetworkBinaryReader reader) {
209             int typeTag = reader.ReadByte();
210             switch (typeTag) {
211               case -1:
212                   throw new EndOfStreamException("End of StreamMessage reached");
213
214               case (int) StreamWireFormattingTag.Bool: {
215                   byte value = reader.ReadByte();
216                   switch (value) {
217                     case 0x00: return false;
218                     case 0x01: return true;
219                     default: {
220                         string message =
221                             string.Format("Invalid boolean value in StreamMessage: {0}", value);
222                         throw new ProtocolViolationException(message);
223                     }
224                   }
225               }
226
227               case (int) StreamWireFormattingTag.Byte:
228                   return reader.ReadByte();
229
230               case (int) StreamWireFormattingTag.Bytes: {
231                   int length = reader.ReadInt32();
232                   if (length == -1) {
233                       return null;
234                   } else {
235                       return reader.ReadBytes(length);
236                   }
237               }
238
239               case (int) StreamWireFormattingTag.Int16:
240                   return reader.ReadInt16();
241
242               case (int) StreamWireFormattingTag.Char:
243                   return (char) reader.ReadUInt16();
244
245               case (int) StreamWireFormattingTag.Int32:
246                   return reader.ReadInt32();
247
248               case (int) StreamWireFormattingTag.Int64:
249                   return reader.ReadInt64();
250
251               case (int) StreamWireFormattingTag.Single:
252                   return reader.ReadSingle();
253
254               case (int) StreamWireFormattingTag.Double:
255                   return reader.ReadDouble();
256
257               case (int) StreamWireFormattingTag.String:
258                   return ReadUntypedString(reader);
259
260               case (int) StreamWireFormattingTag.Null:
261                   return null;
262
263               default: {
264                   string message = string.Format("Invalid type tag in StreamMessage: {0}",
265                                                  typeTag);
266                   throw new ProtocolViolationException(message);
267               }
268             }
269         }
270
271         public static string ReadUntypedString(NetworkBinaryReader reader) {
272             BinaryWriter buffer = NetworkBinaryWriter.TemporaryBinaryWriter(256);
273             while (true) {
274                 byte b = reader.ReadByte();
275                 if (b == 0) {
276                     return Encoding.UTF8.GetString(NetworkBinaryWriter.TemporaryContents(buffer));
277                 } else {
278                     buffer.Write(b);
279                 }
280             }
281         }
282
283         public static void WriteBool(NetworkBinaryWriter writer, bool value) {
284             writer.Write((byte) StreamWireFormattingTag.Bool);
285             writer.Write(value ? (byte) 0x01 : (byte) 0x00);
286         }
287
288         public static void WriteInt32(NetworkBinaryWriter writer, int value) {
289             writer.Write((byte) StreamWireFormattingTag.Int32);
290             writer.Write(value);
291         }
292
293         public static void WriteInt16(NetworkBinaryWriter writer, short value) {
294             writer.Write((byte) StreamWireFormattingTag.Int16);
295             writer.Write(value);
296         }
297
298         public static void WriteByte(NetworkBinaryWriter writer, byte value) {
299             writer.Write((byte) StreamWireFormattingTag.Byte);
300             writer.Write(value);
301         }
302
303         public static void WriteChar(NetworkBinaryWriter writer, char value) {
304             writer.Write((byte) StreamWireFormattingTag.Char);
305             writer.Write((ushort) value);
306         }
307
308         public static void WriteInt64(NetworkBinaryWriter writer, long value) {
309             writer.Write((byte) StreamWireFormattingTag.Int64);
310             writer.Write(value);
311         }
312
313         public static void WriteSingle(NetworkBinaryWriter writer, float value) {
314             writer.Write((byte) StreamWireFormattingTag.Single);
315             writer.Write(value);
316         }
317
318         public static void WriteDouble(NetworkBinaryWriter writer, double value) {
319             writer.Write((byte) StreamWireFormattingTag.Double);
320             writer.Write(value);
321         }
322
323         public static void WriteBytes(NetworkBinaryWriter writer,
324                                       byte[] value,
325                                       int offset,
326                                       int length)
327         {
328             writer.Write((byte) StreamWireFormattingTag.Bytes);
329             writer.Write(length);
330             writer.Write(value, offset, length);
331         }
332
333         public static void WriteBytes(NetworkBinaryWriter writer, byte[] value) {
334             WriteBytes(writer, value, 0, value.Length);
335         }
336
337         public static void WriteString(NetworkBinaryWriter writer, string value) {
338             writer.Write((byte) StreamWireFormattingTag.String);
339             WriteUntypedString(writer, value);
340         }
341
342         ///<exception cref="ProtocolViolationException"/>
343         public static void WriteObject(NetworkBinaryWriter writer, object value) {
344             if (value is bool) { WriteBool(writer, (bool) value); }
345             else if (value is int) { WriteInt32(writer, (int) value); }
346             else if (value is short) { WriteInt16(writer, (short) value); }
347             else if (value is byte) { WriteByte(writer, (byte) value); }
348             else if (value is char) { WriteChar(writer, (char) value); }
349             else if (value is long) { WriteInt64(writer, (long) value); }
350             else if (value is float) { WriteSingle(writer, (float) value); }
351             else if (value is double) { WriteDouble(writer, (double) value); }
352             else if (value is byte[]) { WriteBytes(writer, (byte[]) value); }
353             else if (value is BinaryTableValue) { WriteBytes(writer,
354                                                              ((BinaryTableValue) value).Bytes); }
355             else if (value is string) { WriteString(writer, (string) value); }
356             else {
357                 string message = string.Format("Invalid object in StreamMessage.WriteObject: {0}",
358                                                value);
359                 throw new ProtocolViolationException(message);
360             }
361         }
362
363         public static void WriteUntypedString(NetworkBinaryWriter writer, string value) {
364             writer.Write(Encoding.UTF8.GetBytes(value));
365             writer.Write((byte) 0);
366         }
367     }
368 }