2005-01-31 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mcs / class / Novell.Directory.Ldap / Novell.Directory.Ldap.Utilclass / DN.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.Utilclass.DN.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.Utilclass
35 {
36         
37         /// <summary> A DN encapsulates a Distinguished Name (an ldap name with context). A DN
38         /// does not need to be fully distinguished, or extend to the Root of a
39         /// directory.  It provides methods to get information about the DN and to
40         /// manipulate the DN.  
41         /// 
42         ///  The following are examples of valid DN:
43         /// <ul>
44         /// <li>cn=admin,ou=marketing,o=corporation</li>
45         /// <li>cn=admin,ou=marketing</li>
46         /// <li>2.5.4.3=admin,ou=marketing</li>
47         /// <li>oid.2.5.4.3=admin,ou=marketing</li>
48         /// </ul>
49         /// 
50         /// Note: Multivalued attributes are all considered to be one
51         /// component and are represented in one RDN (see RDN)
52         /// 
53         /// 
54         /// </summary>
55         /// <seealso cref="RDN">
56         /// </seealso>
57         
58         public class DN : System.Object
59         {
60                 private void  InitBlock()
61                 {
62                         rdnList = new System.Collections.ArrayList();
63                 }
64                 /// <summary> Retrieves a list of RDN Objects, or individual names of the DN</summary>
65                 /// <returns> list of RDNs
66                 /// </returns>
67                 virtual public System.Collections.ArrayList RDNs
68                 {
69                         get
70                         {
71                                 int size = rdnList.Count;
72                                 System.Collections.ArrayList v = new System.Collections.ArrayList(size);
73                                 for (int i = 0; i < size; i++)
74                                 {
75                                         v.Add(rdnList[i]);
76                                 }
77                                 return v;
78                         }
79                         
80                 }
81                 /// <summary> Returns the Parent of this DN</summary>
82                 /// <returns> Parent DN
83                 /// </returns>
84                 virtual public DN Parent
85                 {
86                         get
87                         {
88                                 DN parent = new DN();
89                                 parent.rdnList = (System.Collections.ArrayList) this.rdnList.Clone();
90                                 if (parent.rdnList.Count >= 1)
91                                         parent.rdnList.Remove(rdnList[0]); //remove first object
92                                 return parent;
93                         }
94                         
95                 }
96                 
97                 //parser state identifiers.
98                 private const int LOOK_FOR_RDN_ATTR_TYPE = 1;
99                 private const int ALPHA_ATTR_TYPE = 2;
100                 private const int OID_ATTR_TYPE = 3;
101                 private const int LOOK_FOR_RDN_VALUE = 4;
102                 private const int QUOTED_RDN_VALUE = 5;
103                 private const int HEX_RDN_VALUE = 6;
104                 private const int UNQUOTED_RDN_VALUE = 7;
105                 
106                 /* State transition table:  Parsing starts in state 1.
107                 
108                 State   COMMA   DIGIT   "Oid."  ALPHA   EQUAL   QUOTE   SHARP   HEX
109                 --------------------------------------------------------------------
110                 1       Err     3       3       2       Err     Err     Err     Err
111                 2       Err     Err     Err     2       4       Err     Err     Err
112                 3       Err     3       Err     Err     4       Err     Err     Err
113                 4       Err     7       Err     7       Err     5       6       7
114                 5       1       5       Err     5       Err     1       Err     7
115                 6       1       6       Err     Err     Err     Err     Err     6
116                 7       1       7       Err     7       Err     Err     Err     7
117                 
118                 */
119                 
120                 
121                 private System.Collections.ArrayList rdnList;
122                 
123                 public DN()
124                 {
125                         InitBlock();
126                         return ;
127                 }
128                 /// <summary> Constructs a new DN based on the specified string representation of a
129                 /// distinguished name. The syntax of the DN must conform to that specified
130                 /// in RFC 2253.
131                 /// 
132                 /// </summary>
133                 /// <param name="dnString">a string representation of the distinguished name
134                 /// </param>
135                 /// <exception>  IllegalArgumentException  if the the value of the dnString
136                 /// parameter does not adhere to the syntax described in
137                 /// RFC 2253
138                 /// </exception>
139                 public DN(System.String dnString)
140                 {
141                         InitBlock();
142                         /* the empty string is a valid DN */
143                         if (dnString.Length == 0)
144                                 return ;
145                         
146                         char currChar;
147                         char nextChar;
148                         int currIndex;
149                         char[] tokenBuf = new char[dnString.Length];
150                         int tokenIndex;
151                         int lastIndex;
152                         int valueStart;
153                         int state;
154                         int trailingSpaceCount = 0;
155                         System.String attrType = "";
156                         System.String attrValue = "";
157                         System.String rawValue = "";
158                         int hexDigitCount = 0;
159                         RDN currRDN = new RDN();
160                         
161                         //indicates whether an OID number has a first digit of ZERO
162                         bool firstDigitZero = false;
163                         
164                         tokenIndex = 0;
165                         currIndex = 0;
166                         valueStart = 0;
167                         state = LOOK_FOR_RDN_ATTR_TYPE;
168                         lastIndex = dnString.Length - 1;
169                         while (currIndex <= lastIndex)
170                         {
171                                 currChar = dnString[currIndex];
172                                 switch (state)
173                                 {
174                                         
175                                         case LOOK_FOR_RDN_ATTR_TYPE: 
176                                                 while (currChar == ' ' && (currIndex < lastIndex))
177                                                         currChar = dnString[++currIndex];
178                                                 if (isAlpha(currChar))
179                                                 {
180                                                         if (dnString.Substring(currIndex).StartsWith("oid.") || dnString.Substring(currIndex).StartsWith("OID."))
181                                                         {
182                                                                 //form is "oid.###.##.###... or OID.###.##.###...
183                                                                 currIndex += 4; //skip oid. prefix and get to actual oid
184                                                                 if (currIndex > lastIndex)
185                                                                         throw new System.ArgumentException(dnString);
186                                                                 currChar = dnString[currIndex];
187                                                                 if (isDigit(currChar))
188                                                                 {
189                                                                         tokenBuf[tokenIndex++] = currChar;
190                                                                         state = OID_ATTR_TYPE;
191                                                                 }
192                                                                 else
193                                                                         throw new System.ArgumentException(dnString);
194                                                         }
195                                                         else
196                                                         {
197                                                                 tokenBuf[tokenIndex++] = currChar;
198                                                                 state = ALPHA_ATTR_TYPE;
199                                                         }
200                                                 }
201                                                 else if (isDigit(currChar))
202                                                 {
203                                                         --currIndex;
204                                                         state = OID_ATTR_TYPE;
205                                                 }
206                                                 else if (!(System.Char.GetUnicodeCategory(currChar) == System.Globalization.UnicodeCategory.SpaceSeparator))
207                                                         throw new System.ArgumentException(dnString);
208                                                 break;
209                                         
210                                         
211                                         case ALPHA_ATTR_TYPE: 
212                                                 if (isAlpha(currChar) || isDigit(currChar) || (currChar == '-'))
213                                                         tokenBuf[tokenIndex++] = currChar;
214                                                 else
215                                                 {
216                                                         //skip any spaces
217                                                         while ((currChar == ' ') && (currIndex < lastIndex))
218                                                                 currChar = dnString[++currIndex];
219                                                         if (currChar == '=')
220                                                         {
221                                                                 attrType = new System.String(tokenBuf, 0, tokenIndex);
222                                                                 tokenIndex = 0;
223                                                                 state = LOOK_FOR_RDN_VALUE;
224                                                         }
225                                                         else
226                                                                 throw new System.ArgumentException(dnString);
227                                                 }
228                                                 break;
229                                         
230                                         
231                                         case OID_ATTR_TYPE: 
232                                                 if (!isDigit(currChar))
233                                                         throw new System.ArgumentException(dnString);
234                                                 firstDigitZero = (currChar == '0')?true:false;
235                                                 tokenBuf[tokenIndex++] = currChar;
236                                                 currChar = dnString[++currIndex];
237                                                 
238                                                 if ((isDigit(currChar) && firstDigitZero) || (currChar == '.' && firstDigitZero))
239                                                 {
240                                                         throw new System.ArgumentException(dnString);
241                                                 }
242                                                 
243                                                 //consume all numbers.
244                                                 while (isDigit(currChar) && (currIndex < lastIndex))
245                                                 {
246                                                         tokenBuf[tokenIndex++] = currChar;
247                                                         currChar = dnString[++currIndex];
248                                                 }
249                                                 if (currChar == '.')
250                                                 {
251                                                         tokenBuf[tokenIndex++] = currChar;
252                                                         //The state remains at OID_ATTR_TYPE
253                                                 }
254                                                 else
255                                                 {
256                                                         //skip any spaces
257                                                         while (currChar == ' ' && (currIndex < lastIndex))
258                                                                 currChar = dnString[++currIndex];
259                                                         if (currChar == '=')
260                                                         {
261                                                                 attrType = new System.String(tokenBuf, 0, tokenIndex);
262                                                                 tokenIndex = 0;
263                                                                 state = LOOK_FOR_RDN_VALUE;
264                                                         }
265                                                         else
266                                                                 throw new System.ArgumentException(dnString);
267                                                 }
268                                                 break;
269                                         
270                                         
271                                         case LOOK_FOR_RDN_VALUE: 
272                                                 while (currChar == ' ')
273                                                 {
274                                                         if (currIndex < lastIndex)
275                                                                 currChar = dnString[++currIndex];
276                                                         else
277                                                                 throw new System.ArgumentException(dnString);
278                                                 }
279                                                 if (currChar == '"')
280                                                 {
281                                                         state = QUOTED_RDN_VALUE;
282                                                         valueStart = currIndex;
283                                                 }
284                                                 else if (currChar == '#')
285                                                 {
286                                                         hexDigitCount = 0;
287                                                         tokenBuf[tokenIndex++] = currChar;
288                                                         valueStart = currIndex;
289                                                         state = HEX_RDN_VALUE;
290                                                 }
291                                                 else
292                                                 {
293                                                         valueStart = currIndex;
294                                                         //check this character again in the UNQUOTED_RDN_VALUE state
295                                                         currIndex--;
296                                                         state = UNQUOTED_RDN_VALUE;
297                                                 }
298                                                 break;
299                                         
300                                         
301                                         case UNQUOTED_RDN_VALUE: 
302                                                 if (currChar == '\\')
303                                                 {
304                                                         if (!(currIndex < lastIndex))
305                                                                 throw new System.ArgumentException(dnString);
306                                                         currChar = dnString[++currIndex];
307                                                         if (isHexDigit(currChar))
308                                                         {
309                                                                 if (!(currIndex < lastIndex))
310                                                                         throw new System.ArgumentException(dnString);
311                                                                 nextChar = dnString[++currIndex];
312                                                                 if (isHexDigit(nextChar))
313                                                                 {
314                                                                         tokenBuf[tokenIndex++] = hexToChar(currChar, nextChar);
315                                                                         trailingSpaceCount = 0;
316                                                                 }
317                                                                 else
318                                                                         throw new System.ArgumentException(dnString);
319                                                         }
320                                                         else if (needsEscape(currChar) || currChar == '#' || currChar == '=' || currChar == ' ')
321                                                         {
322                                                                 tokenBuf[tokenIndex++] = currChar;
323                                                                 trailingSpaceCount = 0;
324                                                         }
325                                                         else
326                                                                 throw new System.ArgumentException(dnString);
327                                                 }
328                                                 else if (currChar == ' ')
329                                                 {
330                                                         trailingSpaceCount++;
331                                                         tokenBuf[tokenIndex++] = currChar;
332                                                 }
333                                                 else if ((currChar == ',') || (currChar == ';') || (currChar == '+'))
334                                                 {
335                                                         attrValue = new System.String(tokenBuf, 0, tokenIndex - trailingSpaceCount);
336                                                         rawValue = dnString.Substring(valueStart, (currIndex - trailingSpaceCount) - (valueStart));
337                                                         
338                                                         currRDN.add(attrType, attrValue, rawValue);
339                                                         if (currChar != '+')
340                                                         {
341                                                                 rdnList.Add(currRDN);
342                                                                 currRDN = new RDN();
343                                                         }
344                                                         
345                                                         trailingSpaceCount = 0;
346                                                         tokenIndex = 0;
347                                                         state = LOOK_FOR_RDN_ATTR_TYPE;
348                                                 }
349                                                 else if (needsEscape(currChar))
350                                                 {
351                                                         throw new System.ArgumentException(dnString);
352                                                 }
353                                                 else
354                                                 {
355                                                         trailingSpaceCount = 0;
356                                                         tokenBuf[tokenIndex++] = currChar;
357                                                 }
358                                                 break; //end UNQUOTED RDN VALUE
359                                         
360                                         
361                                         case QUOTED_RDN_VALUE: 
362                                                 if (currChar == '"')
363                                                 {
364                                                         rawValue = dnString.Substring(valueStart, (currIndex + 1) - (valueStart));
365                                                         if (currIndex < lastIndex)
366                                                                 currChar = dnString[++currIndex];
367                                                         //skip any spaces
368                                                         while ((currChar == ' ') && (currIndex < lastIndex))
369                                                                 currChar = dnString[++currIndex];
370                                                         if ((currChar == ',') || (currChar == ';') || (currChar == '+') || (currIndex == lastIndex))
371                                                         {
372                                                                 attrValue = new System.String(tokenBuf, 0, tokenIndex);
373                                                                 
374                                                                 currRDN.add(attrType, attrValue, rawValue);
375                                                                 if (currChar != '+')
376                                                                 {
377                                                                         rdnList.Add(currRDN);
378                                                                         currRDN = new RDN();
379                                                                 }
380                                                                 trailingSpaceCount = 0;
381                                                                 tokenIndex = 0;
382                                                                 state = LOOK_FOR_RDN_ATTR_TYPE;
383                                                         }
384                                                         else
385                                                                 throw new System.ArgumentException(dnString);
386                                                 }
387                                                 else if (currChar == '\\')
388                                                 {
389                                                         currChar = dnString[++currIndex];
390                                                         if (isHexDigit(currChar))
391                                                         {
392                                                                 nextChar = dnString[++currIndex];
393                                                                 if (isHexDigit(nextChar))
394                                                                 {
395                                                                         tokenBuf[tokenIndex++] = hexToChar(currChar, nextChar);
396                                                                         trailingSpaceCount = 0;
397                                                                 }
398                                                                 else
399                                                                         throw new System.ArgumentException(dnString);
400                                                         }
401                                                         else if (needsEscape(currChar) || currChar == '#' || currChar == '=' || currChar == ' ')
402                                                         {
403                                                                 tokenBuf[tokenIndex++] = currChar;
404                                                                 trailingSpaceCount = 0;
405                                                         }
406                                                         else
407                                                                 throw new System.ArgumentException(dnString);
408                                                 }
409                                                 else
410                                                         tokenBuf[tokenIndex++] = currChar;
411                                                 break; //end QUOTED RDN VALUE
412                                         
413                                         
414                                         case HEX_RDN_VALUE: 
415                                                 if ((!isHexDigit(currChar)) || (currIndex > lastIndex))
416                                                 {
417                                                         //check for odd number of hex digits
418                                                         if ((hexDigitCount % 2) != 0 || hexDigitCount == 0)
419                                                                 throw new System.ArgumentException(dnString);
420                                                         else
421                                                         {
422                                                                 rawValue = dnString.Substring(valueStart, (currIndex) - (valueStart));
423                                                                 //skip any spaces
424                                                                 while ((currChar == ' ') && (currIndex < lastIndex))
425                                                                         currChar = dnString[++currIndex];
426                                                                 if ((currChar == ',') || (currChar == ';') || (currChar == '+') || (currIndex == lastIndex))
427                                                                 {
428                                                                         attrValue = new System.String(tokenBuf, 0, tokenIndex);
429                                                                         
430                                                                         //added by cameron
431                                                                         currRDN.add(attrType, attrValue, rawValue);
432                                                                         if (currChar != '+')
433                                                                         {
434                                                                                 rdnList.Add(currRDN);
435                                                                                 currRDN = new RDN();
436                                                                         }
437                                                                         tokenIndex = 0;
438                                                                         state = LOOK_FOR_RDN_ATTR_TYPE;
439                                                                 }
440                                                                 else
441                                                                 {
442                                                                         throw new System.ArgumentException(dnString);
443                                                                 }
444                                                         }
445                                                 }
446                                                 else
447                                                 {
448                                                         tokenBuf[tokenIndex++] = currChar;
449                                                         hexDigitCount++;
450                                                 }
451                                                 break; //end HEX RDN VALUE
452                                         } //end switch
453                                 currIndex++;
454                         } //end while
455                         
456                         //check ending state
457                         if (state == UNQUOTED_RDN_VALUE || (state == HEX_RDN_VALUE && (hexDigitCount % 2) == 0) && hexDigitCount != 0)
458                         {
459                                 attrValue = new System.String(tokenBuf, 0, tokenIndex - trailingSpaceCount);
460                                 rawValue = dnString.Substring(valueStart, (currIndex - trailingSpaceCount) - (valueStart));
461                                 currRDN.add(attrType, attrValue, rawValue);
462                                 rdnList.Add(currRDN);
463                         }
464                         else if (state == LOOK_FOR_RDN_VALUE)
465                         {
466                                 //empty value is valid
467                                 attrValue = "";
468                                 rawValue = dnString.Substring(valueStart);
469                                 currRDN.add(attrType, attrValue, rawValue);
470                                 rdnList.Add(currRDN);
471                         }
472                         else
473                         {
474                                 throw new System.ArgumentException(dnString);
475                         }
476                 } //end DN constructor (string dn)
477                 
478                 
479                 /// <summary> Checks a character to see if it is an ascii alphabetic character in
480                 /// ranges 65-90 or 97-122.
481                 /// 
482                 /// </summary>
483                 /// <param name="ch">the character to be tested.
484                 /// </param>
485                 /// <returns>  <code>true</code> if the character is an ascii alphabetic
486                 /// character
487                 /// </returns>
488                 private bool isAlpha(char ch)
489                 {
490                         if (((ch < 91) && (ch > 64)) || ((ch < 123) && (ch > 96)))
491                         //ASCII A-Z
492                                 return true;
493                         else
494                                 return false;
495                 }
496                 
497                 
498                 /// <summary> Checks a character to see if it is an ascii digit (0-9) character in
499                 /// the ascii value range 48-57.
500                 /// 
501                 /// </summary>
502                 /// <param name="ch">the character to be tested.
503                 /// </param>
504                 /// <returns>  <code>true</code> if the character is an ascii alphabetic
505                 /// character
506                 /// </returns>
507                 private bool isDigit(char ch)
508                 {
509                         if ((ch < 58) && (ch > 47))
510                         //ASCII 0-9
511                                 return true;
512                         else
513                                 return false;
514                 }
515                 
516                 /// <summary> Checks a character to see if it is valid hex digit 0-9, a-f, or
517                 /// A-F (ASCII value ranges 48-47, 65-70, 97-102).
518                 /// 
519                 /// </summary>
520                 /// <param name="ch">the character to be tested.
521                 /// </param>
522                 /// <returns>  <code>true</code> if the character is a valid hex digit
523                 /// </returns>
524                 
525                 private static bool isHexDigit(char ch)
526                 {
527                         if (((ch < 58) && (ch > 47)) || ((ch < 71) && (ch > 64)) || ((ch < 103) && (ch > 96)))
528                         //ASCII A-F
529                                 return true;
530                         else
531                                 return false;
532                 }
533                 
534                 /// <summary> Checks a character to see if it must always be escaped in the
535                 /// string representation of a DN.  We must tests for space, sharp, and
536                 /// equals individually.
537                 /// 
538                 /// </summary>
539                 /// <param name="ch">the character to be tested.
540                 /// </param>
541                 /// <returns>  <code>true</code> if the character needs to be escaped in at
542                 /// least some instances.
543                 /// </returns>
544                 private bool needsEscape(char ch)
545                 {
546                         if ((ch == ',') || (ch == '+') || (ch == '\"') || (ch == ';') || (ch == '<') || (ch == '>') || (ch == '\\'))
547                                 return true;
548                         else
549                                 return false;
550                 }
551                 
552                 /// <summary> Converts two valid hex digit characters that form the string
553                 /// representation of an ascii character value to the actual ascii
554                 /// character.
555                 /// 
556                 /// </summary>
557                 /// <param name="hex1">the hex digit for the high order byte.
558                 /// </param>
559                 /// <param name="hex0">the hex digit for the low order byte.
560                 /// </param>
561                 /// <returns>  the character whose value is represented by the parameters.
562                 /// </returns>
563                 
564                 private static char hexToChar(char hex1, char hex0)
565                 {
566                         int result;
567                         
568                         if ((hex1 < 58) && (hex1 > 47))
569                         //ASCII 0-9
570                                 result = (hex1 - 48) * 16;
571                         else if ((hex1 < 71) && (hex1 > 64))
572                         //ASCII a-f
573                                 result = (hex1 - 55) * 16;
574                         else if ((hex1 < 103) && (hex1 > 96))
575                         //ASCII A-F
576                                 result = (hex1 - 87) * 16;
577                         else
578                                 throw new System.ArgumentException("Not hex digit");
579                         
580                         if ((hex0 < 58) && (hex0 > 47))
581                         //ASCII 0-9
582                                 result += (hex0 - 48);
583                         else if ((hex0 < 71) && (hex0 > 64))
584                         //ASCII a-f
585                                 result += (hex0 - 55);
586                         else if ((hex0 < 103) && (hex0 > 96))
587                         //ASCII A-F
588                                 result += (hex0 - 87);
589                         else
590                                 throw new System.ArgumentException("Not hex digit");
591                         
592                         return (char) result;
593                 }
594                 
595                 /// <summary> Creates and returns a string that represents this DN.  The string
596                 /// follows RFC 2253, which describes String representation of DN's and
597                 /// RDN's
598                 /// 
599                 /// </summary>
600                 /// <returns> A DN string.
601                 /// </returns>
602                 public override System.String ToString()
603                 {
604                         int length = rdnList.Count;
605                         System.String dn = "";
606                         if (length < 1)
607                                 return null;
608                         dn = rdnList[0].ToString();
609                         for (int i = 1; i < length; i++)
610                         {
611                                 dn += ("," + rdnList[i].ToString());
612                         }
613                         return dn;
614                 }
615                 
616                 
617                 /// <summary> Compares this DN to the specified DN to determine if they are equal.
618                 /// 
619                 /// </summary>
620                 /// <param name="toDN">the DN to compare to
621                 /// </param>
622                 /// <returns>  <code>true</code> if the DNs are equal; otherwise
623                 /// <code>false</code>
624                 /// </returns>
625
626                 public System.Collections.ArrayList getrdnList()
627                 {
628                         return this.rdnList;
629                 }
630                 public  override bool Equals(System.Object toDN)
631                 {
632                         return Equals((DN) toDN);
633                 }
634                 public   bool Equals(DN toDN)
635                 {
636                         System.Collections.ArrayList aList=toDN.getrdnList();
637                         int length = aList.Count;
638                         
639                         if (this.rdnList.Count != length)
640                                 return false;
641                         
642                         for (int i = 0; i < length; i++)
643                         {
644                                 if (!((RDN) rdnList[i]).equals((RDN) toDN.getrdnList()[i]))
645                                         return false;
646                         }
647                         return true;
648                 }
649                 
650                 /// <summary> return a string array of the individual RDNs contained in the DN
651                 /// 
652                 /// </summary>
653                 /// <param name="noTypes">  If true, returns only the values of the
654                 /// components, and not the names, e.g. "Babs
655                 /// Jensen", "Accounting", "Acme", "us" - instead of
656                 /// "cn=Babs Jensen", "ou=Accounting", "o=Acme", and
657                 /// "c=us".
658                 /// </param>
659                 /// <returns>  <code>String[]</code> containing the rdns in the DN with
660                 /// the leftmost rdn in the first element of the array
661                 /// 
662                 /// </returns>
663                 public virtual System.String[] explodeDN(bool noTypes)
664                 {
665                         int length = rdnList.Count;
666                         System.String[] rdns = new System.String[length];
667                         for (int i = 0; i < length; i++)
668                                 rdns[i] = ((RDN) rdnList[i]).toString(noTypes);
669                         return rdns;
670                 }
671                 
672                 /// <summary> Retrieves the count of RDNs, or individule names, in the Distinguished name</summary>
673                 /// <returns> the count of RDN
674                 /// </returns>
675                 public virtual int countRDNs()
676                 {
677                         return rdnList.Count;
678                 }
679                 
680                 /// <summary>Determines if this DN is <I>contained</I> by the DN passed in.  For
681                 /// example:  "cn=admin, ou=marketing, o=corporation" is contained by
682                 /// "o=corporation", "ou=marketing, o=corporation", and "ou=marketing"
683                 /// but <B>not</B> by "cn=admin" or "cn=admin,ou=marketing,o=corporation"
684                 /// Note: For users of Netscape's SDK this method is comparable to contains
685                 /// 
686                 /// </summary>
687                 /// <param name="containerDN">of a container
688                 /// </param>
689                 /// <returns> true if containerDN contains this DN
690                 /// </returns>
691                 public virtual bool isDescendantOf(DN containerDN)
692                 {
693                         int i = containerDN.rdnList.Count - 1; //index to an RDN of the ContainerDN
694                         int j = this.rdnList.Count - 1; //index to an RDN of the ContainedDN
695                         //Search from the end of the DN for an RDN that matches the end RDN of
696                         //containerDN.
697                         while (!((RDN) this.rdnList[j--]).equals((RDN) containerDN.rdnList[i]))
698                         {
699                                 if (j <= 0)
700                                         return false;
701                                 //if the end RDN of containerDN does not have any equal
702                                 //RDN in rdnList, then containerDN does not contain this DN
703                         }
704                         i--; //avoid a redundant compare
705                         j--;
706                         //step backwards to verify that all RDNs in containerDN exist in this DN
707                         for (; i >= 0 && j >= 0; i--, j--)
708                         {
709                                 if (!((RDN) this.rdnList[j]).equals((RDN) containerDN.rdnList[i]))
710                                         return false;
711                         }
712                         if (j == 0 && i == 0)
713                         //the DNs are identical and thus not contained
714                                 return false;
715                         
716                         return true;
717                 }
718                 
719                 /// <summary> Adds the RDN to the beginning of the current DN.</summary>
720                 /// <param name="rdn">an RDN to be added
721                 /// </param>
722                 public virtual void  addRDN(RDN rdn)
723                 {
724                         rdnList.Insert(0, rdn);
725                 }
726                 
727                 /// <summary> Adds the RDN to the beginning of the current DN.</summary>
728                 /// <param name="rdn">an RDN to be added
729                 /// </param>
730                 public virtual void  addRDNToFront(RDN rdn)
731                 {
732                         rdnList.Insert(0, rdn);
733                 }
734                 
735                 /// <summary> Adds the RDN to the end of the current DN</summary>
736                 /// <param name="rdn">an RDN to be added
737                 /// </param>
738                 public virtual void  addRDNToBack(RDN rdn)
739                 {
740                         rdnList.Add(rdn);
741                 }
742         } //end class DN
743 }