* roottypes.cs: Rename from tree.cs.
[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         public class LBEREncoder : Asn1Encoder
71         {
72                 
73                 /* Encoders for ASN.1 simple type Contents
74                 */
75                 public void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
76                 {
77                 }
78                 /// <summary> BER Encode an Asn1Boolean directly into the specified output stream.</summary>
79                 public virtual void  encode(Asn1Boolean b, System.IO.Stream out_Renamed)
80                 {
81                         /* Encode the id */
82                         encode(b.getIdentifier(), out_Renamed);
83                         
84                         /* Encode the length */
85                         out_Renamed.WriteByte((System.Byte) 0x01);
86                         
87                         /* Encode the boolean content*/
88                         out_Renamed.WriteByte((byte) (b.booleanValue()?(sbyte) SupportClass.Identity(0xff):(sbyte) 0x00));
89                         
90                         return ;
91                 }
92                 
93                 /// <summary> Encode an Asn1Numeric directly into the specified outputstream.
94                 /// 
95                 /// Use a two's complement representation in the fewest number of octets
96                 /// possible.
97                 /// 
98                 /// Can be used to encode INTEGER and ENUMERATED values.
99                 /// </summary>
100                 public void  encode(Asn1Numeric n, System.IO.Stream out_Renamed)
101                 {
102                         sbyte[] octets = new sbyte[8];
103                         sbyte len;
104                         long value_Renamed = n.longValue();
105                         long endValue = (value_Renamed < 0)?- 1:0;
106                         long endSign = endValue & 0x80;
107                         
108                         for (len = 0; len == 0 || value_Renamed != endValue || (octets[len - 1] & 0x80) != endSign; len++)
109                         {
110                                 octets[len] = (sbyte) (value_Renamed & 0xFF);
111                                 value_Renamed >>= 8;
112                         }
113                         
114                         encode(n.getIdentifier(), out_Renamed);
115                         out_Renamed.WriteByte((byte) len); // Length
116                         for (int i = len - 1; i >= 0; i--)
117                         // Content
118                                 out_Renamed.WriteByte((byte) octets[i]);
119                         return ;
120                 }
121                 
122                 /* Asn1 TYPE NOT YET SUPPORTED
123                 * Encode an Asn1Real directly to a stream.
124                 public void encode(Asn1Real r, OutputStream out)
125                 throws IOException
126                 {
127                 throw new IOException("LBEREncoder: Encode to a stream not implemented");
128                 }
129                 */
130                 
131                 /// <summary> Encode an Asn1Null directly into the specified outputstream.</summary>
132                 public void  encode(Asn1Null n, System.IO.Stream out_Renamed)
133                 {
134                         encode(n.getIdentifier(), out_Renamed);
135                         out_Renamed.WriteByte((System.Byte) 0x00); // Length (with no Content)
136                         return ;
137                 }
138                 
139                 /* Asn1 TYPE NOT YET SUPPORTED
140                 * Encode an Asn1BitString directly to a stream.
141                 public void encode(Asn1BitString bs, OutputStream out)
142                 throws IOException
143                 {
144                 throw new IOException("LBEREncoder: Encode to a stream not implemented");
145                 }
146                 */
147                 
148                 /// <summary> Encode an Asn1OctetString directly into the specified outputstream.</summary>
149                 public void  encode(Asn1OctetString os, System.IO.Stream out_Renamed)
150                 {
151                         encode(os.getIdentifier(), out_Renamed);
152                         encodeLength(os.byteValue().Length, out_Renamed);
153                         sbyte[] temp_sbyteArray;
154                         temp_sbyteArray = os.byteValue();
155                         out_Renamed.Write(SupportClass.ToByteArray(temp_sbyteArray), 0, temp_sbyteArray.Length);;;
156                         return ;
157                 }
158                 
159                 /* Asn1 TYPE NOT YET SUPPORTED
160                 * Encode an Asn1ObjectIdentifier directly to a stream.
161                 * public void encode(Asn1ObjectIdentifier oi, OutputStream out)
162                 * throws IOException
163                 * {
164                 * throw new IOException("LBEREncoder: Encode to a stream not implemented");
165                 * }
166                 */
167                 
168                 /* Asn1 TYPE NOT YET SUPPORTED
169                 * Encode an Asn1CharacterString directly to a stream.
170                 * public void encode(Asn1CharacterString cs, OutputStream out)
171                 * throws IOException
172                 * {
173                 * throw new IOException("LBEREncoder: Encode to a stream not implemented");
174                 * }
175                 */
176                 
177                 /* Encoders for ASN.1 structured types
178                 */
179                 
180                 /// <summary> Encode an Asn1Structured into the specified outputstream.  This method
181                 /// can be used to encode SET, SET_OF, SEQUENCE, SEQUENCE_OF
182                 /// </summary>
183                 public void  encode(Asn1Structured c, System.IO.Stream out_Renamed)
184                 {
185                         encode(c.getIdentifier(), out_Renamed);
186                         
187                         Asn1Object[] value_Renamed = c.toArray();
188                         
189                         System.IO.MemoryStream output = new System.IO.MemoryStream();
190                         
191                         /* Cycle through each element encoding each element */
192                         for (int i = 0; i < value_Renamed.Length; i++)
193                         {
194                                 (value_Renamed[i]).encode(this, output);
195                         }
196                         
197                         /* Encode the length */
198                         encodeLength((int)output.Length, out_Renamed);
199                         
200                         /* Add each encoded element into the output stream */
201                         sbyte[] temp_sbyteArray;
202                         temp_sbyteArray = SupportClass.ToSByteArray(output.ToArray());
203                         out_Renamed.Write(SupportClass.ToByteArray(temp_sbyteArray), 0, temp_sbyteArray.Length);;;
204                         return ;
205                 }
206                 
207                 /// <summary> Encode an Asn1Tagged directly into the specified outputstream.</summary>
208                 public void  encode(Asn1Tagged t, System.IO.Stream out_Renamed)
209                 {
210                         if (t.Explicit)
211                         {
212                                 encode(t.getIdentifier(), out_Renamed);
213                                 
214                                 /* determine the encoded length of the base type. */
215                                 System.IO.MemoryStream encodedContent = new System.IO.MemoryStream();
216                                 t.taggedValue().encode(this, encodedContent);
217                                 
218                                 encodeLength((int)encodedContent.Length, out_Renamed);
219                                 sbyte[] temp_sbyteArray;
220                                 temp_sbyteArray = SupportClass.ToSByteArray(encodedContent.ToArray());
221                                 out_Renamed.Write(SupportClass.ToByteArray(temp_sbyteArray), 0, temp_sbyteArray.Length);;;;
222                         }
223                         else
224                         {
225                                 t.taggedValue().encode(this, out_Renamed);
226                         }
227                         return ;
228                 }
229                 
230                 /* Encoders for ASN.1 useful types
231                 */
232                 /* Encoder for ASN.1 Identifier
233                 */
234                 
235                 /// <summary> Encode an Asn1Identifier directly into the specified outputstream.</summary>
236                 public void  encode(Asn1Identifier id, System.IO.Stream out_Renamed)
237                 {
238                         int c = id.Asn1Class;
239                         int t = id.Tag;
240                         sbyte ccf = (sbyte) ((c << 6) | (id.Constructed?0x20:0));
241                         
242                         if (t < 30)
243                         {
244                                 /* single octet */
245                                 out_Renamed.WriteByte((System.Byte) (ccf | t));
246                         }
247                         else
248                         {
249                                 /* multiple octet */
250                                 out_Renamed.WriteByte((System.Byte) (ccf | 0x1F));
251                                 encodeTagInteger(t, out_Renamed);
252                         }
253                         return ;
254                 }
255                 
256                 /* Private helper methods
257                 */
258                 
259                 /*
260                 *  Encodes the specified length into the the outputstream
261                 */
262                 private void  encodeLength(int length, System.IO.Stream out_Renamed)
263                 {
264                         if (length < 0x80)
265                         {
266                                 out_Renamed.WriteByte((System.Byte) length);
267                         }
268                         else
269                         {
270                                 sbyte[] octets = new sbyte[4]; // 4 bytes sufficient for 32 bit int.
271                                 sbyte n;
272                                 for (n = 0; length != 0; n++)
273                                 {
274                                         octets[n] = (sbyte) (length & 0xFF);
275                                         length >>= 8;
276                                 }
277                                 
278                                 out_Renamed.WriteByte((System.Byte) (0x80 | n));
279                                 
280                                 for (int i = n - 1; i >= 0; i--)
281                                         out_Renamed.WriteByte((byte) octets[i]);
282                         }
283                         return ;
284                 }
285                 
286                 /// <summary> Encodes the provided tag into the outputstream.</summary>
287                 private void  encodeTagInteger(int value_Renamed, System.IO.Stream out_Renamed)
288                 {
289                         sbyte[] octets = new sbyte[5];
290                         int n;
291                         for (n = 0; value_Renamed != 0; n++)
292                         {
293                                 octets[n] = (sbyte) (value_Renamed & 0x7F);
294                                 value_Renamed = value_Renamed >> 7;
295                         }
296                         for (int i = n - 1; i > 0; i--)
297                         {
298                                 out_Renamed.WriteByte((System.Byte) (octets[i] | 0x80));
299                         }
300                         out_Renamed.WriteByte((byte) octets[0]);
301                         return ;
302                 }
303         }
304 }