Modified Comments to Support XML Documentation
[mono.git] / mcs / class / Novell.Directory.Ldap / Novell.Directory.Ldap.Asn1 / LBEREncoder.cs
1 /******************************************************************************
2 * The MIT License
3 * Copyright (c) 2003 Novell Inc.  www.novell.com
4
5 * Permission is hereby granted, free of charge, to any person obtaining  a copy
6 * of this software and associated documentation files (the Software), to deal
7 * in the Software without restriction, including  without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
9 * copies of the Software, and to  permit persons to whom the Software is 
10 * furnished to do so, subject to the following conditions:
11
12 * The above copyright notice and this permission notice shall be included in 
13 * all copies or substantial portions of the Software.
14
15 * THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 *******************************************************************************/
23 //
24 // Novell.Directory.Ldap.Asn1.LBEREncoder.cs
25 //
26 // Author:
27 //   Sunil Kumar (Sunilk@novell.com)
28 //
29 // (C) 2003 Novell, Inc (http://www.novell.com)
30 //
31
32 using System;
33
34 namespace Novell.Directory.Ldap.Asn1
35 {
36         
37         /// <summary> This class provides LBER encoding routines for ASN.1 Types. LBER is a
38         /// subset of BER as described in the following taken from 5.1 of RFC 2251:
39         /// 
40         /// 5.1. Mapping Onto BER-based Transport Services
41         /// 
42         /// The protocol elements of Ldap are encoded for exchange using the
43         /// Basic Encoding Rules (BER) [11] of ASN.1 [3]. However, due to the
44         /// high overhead involved in using certain elements of the BER, the
45         /// following additional restrictions are placed on BER-encodings of Ldap
46         /// protocol elements:
47         /// 
48         /// <li>(1) Only the definite form of length encoding will be used.</li>
49         /// 
50         /// <li>(2) OCTET STRING values will be encoded in the primitive form only.</li>
51         /// 
52         /// <li>(3) If the value of a BOOLEAN type is true, the encoding MUST have
53         /// its contents octets set to hex "FF".</li>
54         /// 
55         /// <li>(4) If a value of a type is its default value, it MUST be absent.
56         /// Only some BOOLEAN and INTEGER types have default values in this
57         /// protocol definition.
58         /// 
59         /// These restrictions do not apply to ASN.1 types encapsulated inside of
60         /// OCTET STRING values, such as attribute values, unless otherwise
61         /// noted.</li>
62         /// 
63         /// [3] ITU-T Rec. X.680, "Abstract Syntax Notation One (ASN.1) -
64         /// Specification of Basic Notation", 1994.
65         /// 
66         /// [11] ITU-T Rec. X.690, "Specification of ASN.1 encoding rules: Basic,
67         /// Canonical, and Distinguished Encoding Rules", 1994.
68         /// 
69         /// </summary>
70         [CLSCompliantAttribute(true)]
71         public class LBEREncoder : Asn1Encoder
72         {
73                 
74                 /* Encoders for ASN.1 simple type Contents
75                 */
76                 public void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
77                 {
78                 }
79                 /// <summary> BER Encode an Asn1Boolean directly into the specified output stream.</summary>
80                 public virtual void  encode(Asn1Boolean b, System.IO.Stream out_Renamed)
81                 {
82                         /* Encode the id */
83                         encode(b.getIdentifier(), out_Renamed);
84                         
85                         /* Encode the length */
86                         out_Renamed.WriteByte((System.Byte) 0x01);
87                         
88                         /* Encode the boolean content*/
89                         out_Renamed.WriteByte((byte) (b.booleanValue()?(sbyte) SupportClass.Identity(0xff):(sbyte) 0x00));
90                         
91                         return ;
92                 }
93                 
94                 /// <summary> Encode an Asn1Numeric directly into the specified outputstream.
95                 /// 
96                 /// Use a two's complement representation in the fewest number of octets
97                 /// possible.
98                 /// 
99                 /// Can be used to encode INTEGER and ENUMERATED values.
100                 /// </summary>
101                 public void  encode(Asn1Numeric n, System.IO.Stream out_Renamed)
102                 {
103                         sbyte[] octets = new sbyte[8];
104                         sbyte len;
105                         long value_Renamed = n.longValue();
106                         long endValue = (value_Renamed < 0)?- 1:0;
107                         long endSign = endValue & 0x80;
108                         
109                         for (len = 0; len == 0 || value_Renamed != endValue || (octets[len - 1] & 0x80) != endSign; len++)
110                         {
111                                 octets[len] = (sbyte) (value_Renamed & 0xFF);
112                                 value_Renamed >>= 8;
113                         }
114                         
115                         encode(n.getIdentifier(), out_Renamed);
116                         out_Renamed.WriteByte((byte) len); // Length
117                         for (int i = len - 1; i >= 0; i--)
118                         // Content
119                                 out_Renamed.WriteByte((byte) octets[i]);
120                         return ;
121                 }
122                 
123                 /* Asn1 TYPE NOT YET SUPPORTED
124                 * Encode an Asn1Real directly to a stream.
125                 public void encode(Asn1Real r, OutputStream out)
126                 throws IOException
127                 {
128                 throw new IOException("LBEREncoder: Encode to a stream not implemented");
129                 }
130                 */
131                 
132                 /// <summary> Encode an Asn1Null directly into the specified outputstream.</summary>
133                 public void  encode(Asn1Null n, System.IO.Stream out_Renamed)
134                 {
135                         encode(n.getIdentifier(), out_Renamed);
136                         out_Renamed.WriteByte((System.Byte) 0x00); // Length (with no Content)
137                         return ;
138                 }
139                 
140                 /* Asn1 TYPE NOT YET SUPPORTED
141                 * Encode an Asn1BitString directly to a stream.
142                 public void encode(Asn1BitString bs, OutputStream out)
143                 throws IOException
144                 {
145                 throw new IOException("LBEREncoder: Encode to a stream not implemented");
146                 }
147                 */
148                 
149                 /// <summary> Encode an Asn1OctetString directly into the specified outputstream.</summary>
150                 public void  encode(Asn1OctetString os, System.IO.Stream out_Renamed)
151                 {
152                         encode(os.getIdentifier(), out_Renamed);
153                         encodeLength(os.byteValue().Length, out_Renamed);
154                         sbyte[] temp_sbyteArray;
155                         temp_sbyteArray = os.byteValue();
156                         out_Renamed.Write(SupportClass.ToByteArray(temp_sbyteArray), 0, temp_sbyteArray.Length);;;
157                         return ;
158                 }
159                 
160                 /* Asn1 TYPE NOT YET SUPPORTED
161                 * Encode an Asn1ObjectIdentifier directly to a stream.
162                 * public void encode(Asn1ObjectIdentifier oi, OutputStream out)
163                 * throws IOException
164                 * {
165                 * throw new IOException("LBEREncoder: Encode to a stream not implemented");
166                 * }
167                 */
168                 
169                 /* Asn1 TYPE NOT YET SUPPORTED
170                 * Encode an Asn1CharacterString directly to a stream.
171                 * public void encode(Asn1CharacterString cs, OutputStream out)
172                 * throws IOException
173                 * {
174                 * throw new IOException("LBEREncoder: Encode to a stream not implemented");
175                 * }
176                 */
177                 
178                 /* Encoders for ASN.1 structured types
179                 */
180                 
181                 /// <summary> Encode an Asn1Structured into the specified outputstream.  This method
182                 /// can be used to encode SET, SET_OF, SEQUENCE, SEQUENCE_OF
183                 /// </summary>
184                 public void  encode(Asn1Structured c, System.IO.Stream out_Renamed)
185                 {
186                         encode(c.getIdentifier(), out_Renamed);
187                         
188                         Asn1Object[] value_Renamed = c.toArray();
189                         
190                         System.IO.MemoryStream output = new System.IO.MemoryStream();
191                         
192                         /* Cycle through each element encoding each element */
193                         for (int i = 0; i < value_Renamed.Length; i++)
194                         {
195                                 (value_Renamed[i]).encode(this, output);
196                         }
197                         
198                         /* Encode the length */
199                         encodeLength((int)output.Length, out_Renamed);
200                         
201                         /* Add each encoded element into the output stream */
202                         sbyte[] temp_sbyteArray;
203                         temp_sbyteArray = SupportClass.ToSByteArray(output.ToArray());
204                         out_Renamed.Write(SupportClass.ToByteArray(temp_sbyteArray), 0, temp_sbyteArray.Length);;;
205                         return ;
206                 }
207                 
208                 /// <summary> Encode an Asn1Tagged directly into the specified outputstream.</summary>
209                 public void  encode(Asn1Tagged t, System.IO.Stream out_Renamed)
210                 {
211                         if (t.Explicit)
212                         {
213                                 encode(t.getIdentifier(), out_Renamed);
214                                 
215                                 /* determine the encoded length of the base type. */
216                                 System.IO.MemoryStream encodedContent = new System.IO.MemoryStream();
217                                 t.taggedValue().encode(this, encodedContent);
218                                 
219                                 encodeLength((int)encodedContent.Length, out_Renamed);
220                                 sbyte[] temp_sbyteArray;
221                                 temp_sbyteArray = SupportClass.ToSByteArray(encodedContent.ToArray());
222                                 out_Renamed.Write(SupportClass.ToByteArray(temp_sbyteArray), 0, temp_sbyteArray.Length);;;;
223                         }
224                         else
225                         {
226                                 t.taggedValue().encode(this, out_Renamed);
227                         }
228                         return ;
229                 }
230                 
231                 /* Encoders for ASN.1 useful types
232                 */
233                 /* Encoder for ASN.1 Identifier
234                 */
235                 
236                 /// <summary> Encode an Asn1Identifier directly into the specified outputstream.</summary>
237                 public void  encode(Asn1Identifier id, System.IO.Stream out_Renamed)
238                 {
239                         int c = id.Asn1Class;
240                         int t = id.Tag;
241                         sbyte ccf = (sbyte) ((c << 6) | (id.Constructed?0x20:0));
242                         
243                         if (t < 30)
244                         {
245                                 /* single octet */
246                                 out_Renamed.WriteByte((System.Byte) (ccf | t));
247                         }
248                         else
249                         {
250                                 /* multiple octet */
251                                 out_Renamed.WriteByte((System.Byte) (ccf | 0x1F));
252                                 encodeTagInteger(t, out_Renamed);
253                         }
254                         return ;
255                 }
256                 
257                 /* Private helper methods
258                 */
259                 
260                 /*
261                 *  Encodes the specified length into the the outputstream
262                 */
263                 private void  encodeLength(int length, System.IO.Stream out_Renamed)
264                 {
265                         if (length < 0x80)
266                         {
267                                 out_Renamed.WriteByte((System.Byte) length);
268                         }
269                         else
270                         {
271                                 sbyte[] octets = new sbyte[4]; // 4 bytes sufficient for 32 bit int.
272                                 sbyte n;
273                                 for (n = 0; length != 0; n++)
274                                 {
275                                         octets[n] = (sbyte) (length & 0xFF);
276                                         length >>= 8;
277                                 }
278                                 
279                                 out_Renamed.WriteByte((System.Byte) (0x80 | n));
280                                 
281                                 for (int i = n - 1; i >= 0; i--)
282                                         out_Renamed.WriteByte((byte) octets[i]);
283                         }
284                         return ;
285                 }
286                 
287                 /// <summary> Encodes the provided tag into the outputstream.</summary>
288                 private void  encodeTagInteger(int value_Renamed, System.IO.Stream out_Renamed)
289                 {
290                         sbyte[] octets = new sbyte[5];
291                         int n;
292                         for (n = 0; value_Renamed != 0; n++)
293                         {
294                                 octets[n] = (sbyte) (value_Renamed & 0x7F);
295                                 value_Renamed = value_Renamed >> 7;
296                         }
297                         for (int i = n - 1; i > 0; i--)
298                         {
299                                 out_Renamed.WriteByte((System.Byte) (octets[i] | 0x80));
300                         }
301                         out_Renamed.WriteByte((byte) octets[0]);
302                         return ;
303                 }
304         }
305 }