Added ifdef for TARGET_JVM.
[mono.git] / mcs / class / Novell.Directory.Ldap / Novell.Directory.Ldap.Asn1 / LBERDecoder.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.LBERDecoder.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 decoding 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 #if !TARGET_JVM 
71         [CLSCompliantAttribute(true)]
72 #endif
73         public class LBERDecoder : Asn1Decoder
74         {
75                 public LBERDecoder()
76                 {
77                         InitBlock();
78                 }
79                 public void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
80                 {
81                 }
82
83                 private void  InitBlock()
84                 {
85                         asn1ID = new Asn1Identifier();
86                         asn1Len = new Asn1Length();
87                 }
88                 //used to speed up decode, so it doesn't need to recreate an identifier every time
89                 //instead just reset is called CANNOT be static for multiple connections
90                 private Asn1Identifier asn1ID;
91                 private Asn1Length asn1Len;
92                 
93                 
94                 /* Generic decode routines
95                 */
96                 
97                 /// <summary> Decode an LBER encoded value into an Asn1Type from a byte array.</summary>
98                 [CLSCompliantAttribute(false)]
99                 public virtual Asn1Object decode(sbyte[] value_Renamed)
100                 {
101                         Asn1Object asn1 = null;
102                         
103                         System.IO.MemoryStream in_Renamed = new System.IO.MemoryStream(SupportClass.ToByteArray(value_Renamed));
104                         try
105                         {
106                                 asn1 = decode(in_Renamed);
107                         }
108                         catch (System.IO.IOException ioe)
109                         {
110                         }
111                         return asn1;
112                 }
113                 
114                 /// <summary> Decode an LBER encoded value into an Asn1Type from an InputStream.</summary>
115                 public virtual Asn1Object decode(System.IO.Stream in_Renamed)
116                 {
117                         int[] len = new int[1];
118                         return decode(in_Renamed, len);
119                 }
120                 
121                 /// <summary> Decode an LBER encoded value into an Asn1Object from an InputStream.
122                 /// 
123                 ///  This method also returns the total length of this encoded
124                 /// Asn1Object (length of type + length of length + length of content)
125                 /// in the parameter len. This information is helpful when decoding
126                 /// structured types.
127                 /// </summary>
128                 public virtual Asn1Object decode(System.IO.Stream in_Renamed, int[] len)
129                 {
130                         asn1ID.reset(in_Renamed);
131                         asn1Len.reset(in_Renamed);
132                         
133                         int length = asn1Len.Length;
134                         len[0] = asn1ID.EncodedLength + asn1Len.EncodedLength + length;
135                         
136                         if (asn1ID.Universal)
137                         {
138                                 switch (asn1ID.Tag)
139                                 {
140                                         
141                                         case Asn1Sequence.TAG: 
142                                                 return new Asn1Sequence(this, in_Renamed, length);
143                                         
144                                         case Asn1Set.TAG: 
145                                                 return new Asn1Set(this, in_Renamed, length);
146                                         
147                                         case Asn1Boolean.TAG: 
148                                                 return new Asn1Boolean(this, in_Renamed, length);
149                                         
150                                         case Asn1Integer.TAG: 
151                                                 return new Asn1Integer(this, in_Renamed, length);
152                                         
153                                         case Asn1OctetString.TAG: 
154                                                 return new Asn1OctetString(this, in_Renamed, length);
155                                         
156                                         case Asn1Enumerated.TAG: 
157                                                 return new Asn1Enumerated(this, in_Renamed, length);
158                                         
159                                         case Asn1Null.TAG: 
160                                                 return new Asn1Null(); // has no content to decode.
161                                                 /* Asn1 TYPE NOT YET SUPPORTED
162                                                 case Asn1BitString.TAG:
163                                                 return new Asn1BitString(this, in, length);
164                                                 case Asn1ObjectIdentifier.TAG:
165                                                 return new Asn1ObjectIdentifier(this, in, length);
166                                                 case Asn1Real.TAG:
167                                                 return new Asn1Real(this, in, length);
168                                                 case Asn1NumericString.TAG:
169                                                 return new Asn1NumericString(this, in, length);
170                                                 case Asn1PrintableString.TAG:
171                                                 return new Asn1PrintableString(this, in, length);
172                                                 case Asn1TeletexString.TAG:
173                                                 return new Asn1TeletexString(this, in, length);
174                                                 case Asn1VideotexString.TAG:
175                                                 return new Asn1VideotexString(this, in, length);
176                                                 case Asn1IA5String.TAG:
177                                                 return new Asn1IA5String(this, in, length);
178                                                 case Asn1GraphicString.TAG:
179                                                 return new Asn1GraphicString(this, in, length);
180                                                 case Asn1VisibleString.TAG:
181                                                 return new Asn1VisibleString(this, in, length);
182                                                 case Asn1GeneralString.TAG:
183                                                 return new Asn1GeneralString(this, in, length);
184                                                 */
185                                         
186                                         
187                                         default: 
188                                                 throw new System.IO.EndOfStreamException("Unknown tag"); // !!! need a better exception
189                                         
190                                 }
191                         }
192                         else
193                         {
194                                 // APPLICATION or CONTEXT-SPECIFIC tag
195                                 return new Asn1Tagged(this, in_Renamed, length, (Asn1Identifier) asn1ID.Clone());
196                         }
197                 }
198                 
199                 /* Decoders for ASN.1 simple type Contents
200                 */
201                 
202                 /// <summary> Decode a boolean directly from a stream.</summary>
203                 public System.Object decodeBoolean(System.IO.Stream in_Renamed, int len)
204                 {
205                         sbyte[] lber = new sbyte[len];
206                         
207                         int i = SupportClass.ReadInput(in_Renamed, ref lber, 0, lber.Length);
208                         
209                         if (i != len)
210                                 throw new System.IO.EndOfStreamException("LBER: BOOLEAN: decode error: EOF");
211                         
212                         return (lber[0] == 0x00)?false:true;
213                 }
214                 
215                 /// <summary> Decode a Numeric type directly from a stream. Decodes INTEGER
216                 /// and ENUMERATED types.
217                 /// </summary>
218                 public System.Object decodeNumeric(System.IO.Stream in_Renamed, int len)
219                 {
220                         long l = 0;
221                         int r = in_Renamed.ReadByte();
222                         
223                         if (r < 0)
224                                 throw new System.IO.EndOfStreamException("LBER: NUMERIC: decode error: EOF");
225                         
226                         if ((r & 0x80) != 0)
227                         {
228                                 // check for negative number
229                                 l = - 1;
230                         }
231                         
232                         l = (l << 8) | r;
233                         
234                         for (int i = 1; i < len; i++)
235                         {
236                                 r = in_Renamed.ReadByte();
237                                 if (r < 0)
238                                         throw new System.IO.EndOfStreamException("LBER: NUMERIC: decode error: EOF");
239                                 l = (l << 8) | r;
240                         }
241                         return (System.Int64) l;
242                 }
243                 
244                 /// <summary> Decode an OctetString directly from a stream.</summary>
245                 public System.Object decodeOctetString(System.IO.Stream in_Renamed, int len)
246                 {
247                         sbyte[] octets = new sbyte[len];
248                         int totalLen = 0;
249                         
250                         while (totalLen < len)
251                         {
252                                 // Make sure we have read all the data
253                                 int inLen = SupportClass.ReadInput(in_Renamed, ref octets, totalLen, len - totalLen);
254                                 totalLen += inLen;
255                         }
256                         
257                         return octets;
258                 }
259                 
260                 /// <summary> Decode a CharacterString directly from a stream.</summary>
261                 public System.Object decodeCharacterString(System.IO.Stream in_Renamed, int len)
262                 {
263                         sbyte[] octets = new sbyte[len];
264                         
265                         for (int i = 0; i < len; i++)
266                         {
267                                 int ret = in_Renamed.ReadByte(); // blocks
268                                 if (ret == - 1)
269                                         throw new System.IO.EndOfStreamException("LBER: CHARACTER STRING: decode error: EOF");
270                                 octets[i] = (sbyte) ret;
271                         }
272                         System.Text.Encoding encoder = System.Text.Encoding.GetEncoding("utf-8"); 
273                         char[] dchar = encoder.GetChars(SupportClass.ToByteArray(octets));
274                         string rval = new String(dchar);
275                         
276                         return rval;//new String( "UTF8");
277                 }
278         }
279 }