**** Merged from MCS ****
[mono-project.git] / mcs / class / Novell.Directory.Ldap / Novell.Directory.Ldap / LdapAttribute.cs
blob5e560fd1ea129ea372ceaa016bf2ea1e1b0c8a0f
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:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
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 *******************************************************************************/
24 // Novell.Directory.Ldap.LdapAttribute.cs
26 // Author:
27 // Sunil Kumar (Sunilk@novell.com)
29 // (C) 2003 Novell, Inc (http://www.novell.com)
32 using System;
33 using ArrayEnumeration = Novell.Directory.Ldap.Utilclass.ArrayEnumeration;
34 using Base64 = Novell.Directory.Ldap.Utilclass.Base64;
36 namespace Novell.Directory.Ldap
38 /// <summary> The name and values of one attribute of a directory entry.
39 ///
40 /// LdapAttribute objects are used when searching for, adding,
41 /// modifying, and deleting attributes from the directory.
42 /// LdapAttributes are often used in conjunction with an
43 /// {@link LdapAttributeSet} when retrieving or adding multiple
44 /// attributes to an entry.
45 ///
46 ///
47 ///
48 /// </summary>
49 /// <seealso cref="LdapEntry">
50 /// </seealso>
51 /// <seealso cref="LdapAttributeSet">
52 /// </seealso>
53 /// <seealso cref="LdapModification">
54 /// </seealso>
56 public class LdapAttribute : System.ICloneable, System.IComparable
58 class URLData
60 private void InitBlock(LdapAttribute enclosingInstance)
62 this.enclosingInstance = enclosingInstance;
64 private LdapAttribute enclosingInstance;
65 public LdapAttribute Enclosing_Instance
67 get
69 return enclosingInstance;
73 private int length;
74 private sbyte[] data;
75 public URLData(LdapAttribute enclosingInstance, sbyte[] data, int length)
77 InitBlock(enclosingInstance);
78 this.length = length;
79 this.data = data;
80 return ;
82 public int getLength()
84 return length;
86 public sbyte[] getData()
88 return data;
91 /// <summary> Returns an enumerator for the values of the attribute in byte format.
92 ///
93 /// </summary>
94 /// <returns> The values of the attribute in byte format.
95 /// Note: All string values will be UTF-8 encoded. To decode use the
96 /// String constructor. Example: new String( byteArray, "UTF-8" );
97 /// </returns>
98 virtual public System.Collections.IEnumerator ByteValues
102 return new ArrayEnumeration(ByteValueArray);
106 /// <summary> Returns an enumerator for the string values of an attribute.
107 ///
108 /// </summary>
109 /// <returns> The string values of an attribute.
110 /// </returns>
111 virtual public System.Collections.IEnumerator StringValues
115 return new ArrayEnumeration(StringValueArray);
119 /// <summary> Returns the values of the attribute as an array of bytes.
120 ///
121 /// </summary>
122 /// <returns> The values as an array of bytes or an empty array if there are
123 /// no values.
124 /// </returns>
125 [CLSCompliantAttribute(false)]
126 virtual public sbyte[][] ByteValueArray
130 if (null == this.values)
131 return new sbyte[0][];
132 int size = this.values.Length;
133 sbyte[][] bva = new sbyte[size][];
134 // Deep copy so application cannot change values
135 for (int i = 0, u = size; i < u; i++)
137 bva[i] = new sbyte[((sbyte[]) values[i]).Length];
138 Array.Copy((System.Array) this.values[i], 0, (System.Array) bva[i], 0, bva[i].Length);
140 return bva;
144 /// <summary> Returns the values of the attribute as an array of strings.
145 ///
146 /// </summary>
147 /// <returns> The values as an array of strings or an empty array if there are
148 /// no values
149 /// </returns>
150 virtual public System.String[] StringValueArray
154 if (null == this.values)
155 return new System.String[0];
156 int size = values.Length;
157 System.String[] sva = new System.String[size];
158 for (int j = 0; j < size; j++)
162 System.Text.Encoding encoder = System.Text.Encoding.GetEncoding("utf-8");
163 char[] dchar = encoder.GetChars(SupportClass.ToByteArray((sbyte[])values[j]));
164 // char[] dchar = encoder.GetChars((byte[])values[j]);
165 sva[j] = new String(dchar);
166 // sva[j] = new String((sbyte[]) values[j], "UTF-8");
168 catch (System.IO.IOException uee)
170 // Exception should NEVER get thrown but just in case it does ...
171 throw new System.SystemException(uee.ToString());
174 return sva;
178 /// <summary> Returns the the first value of the attribute as a <code>String</code>.
179 ///
180 /// </summary>
181 /// <returns> The UTF-8 encoded<code>String</code> value of the attribute's
182 /// value. If the value wasn't a UTF-8 encoded <code>String</code>
183 /// to begin with the value of the returned <code>String</code> is
184 /// non deterministic.
185 ///
186 /// If <code>this</code> attribute has more than one value the
187 /// first value is converted to a UTF-8 encoded <code>String</code>
188 /// and returned. It should be noted, that the directory may
189 /// return attribute values in any order, so that the first
190 /// value may vary from one call to another.
191 ///
192 /// If the attribute has no values <code>null</code> is returned
193 /// </returns>
194 virtual public System.String StringValue
198 System.String rval = null;
199 if (this.values != null)
203 System.Text.Encoding encoder = System.Text.Encoding.GetEncoding("utf-8");
204 char[] dchar = encoder.GetChars(SupportClass.ToByteArray((sbyte[])this.values[0]));
205 // char[] dchar = encoder.GetChars((byte[]) this.values[0]);
206 rval = new String(dchar);
208 catch (System.IO.IOException use)
210 throw new System.SystemException(use.ToString());
213 return rval;
217 /// <summary> Returns the the first value of the attribute as a byte array.
218 ///
219 /// </summary>
220 /// <returns> The binary value of <code>this</code> attribute or
221 /// <code>null</code> if <code>this</code> attribute doesn't have a value.
222 ///
223 /// If the attribute has no values <code>null</code> is returned
224 /// </returns>
225 [CLSCompliantAttribute(false)]
226 virtual public sbyte[] ByteValue
230 sbyte[] bva = null;
231 if (this.values != null)
233 // Deep copy so app can't change the value
234 bva = new sbyte[((sbyte[]) values[0]).Length];
235 Array.Copy((System.Array) this.values[0], 0, (System.Array) bva, 0, bva.Length);
237 return bva;
241 /// <summary> Returns the language subtype of the attribute, if any.
242 ///
243 /// For example, if the attribute name is cn;lang-ja;phonetic,
244 /// this method returns the string, lang-ja.
245 ///
246 /// </summary>
247 /// <returns> The language subtype of the attribute or null if the attribute
248 /// has none.
249 /// </returns>
250 virtual public System.String LangSubtype
254 if (subTypes != null)
256 for (int i = 0; i < subTypes.Length; i++)
258 if (subTypes[i].StartsWith("lang-"))
260 return subTypes[i];
264 return null;
268 /// <summary> Returns the name of the attribute.
269 ///
270 /// </summary>
271 /// <returns> The name of the attribute.
272 /// </returns>
273 virtual public System.String Name
277 return name;
281 /// <summary> Replaces all values with the specified value. This protected method is
282 /// used by sub-classes of LdapSchemaElement because the value cannot be set
283 /// with a contructor.
284 /// </summary>
285 virtual protected internal System.String Value
289 values = null;
292 System.Text.Encoding encoder = System.Text.Encoding.GetEncoding("utf-8");
293 byte[] ibytes = encoder.GetBytes(value);
294 sbyte[] sbytes=SupportClass.ToSByteArray(ibytes);
296 this.add(sbytes);
298 catch (System.IO.IOException ue)
300 throw new System.SystemException(ue.ToString());
302 return ;
306 private System.String name; // full attribute name
307 private System.String baseName; // cn of cn;lang-ja;phonetic
308 private System.String[] subTypes = null; // lang-ja of cn;lang-ja
309 private System.Object[] values = null; // Array of byte[] attribute values
311 /// <summary> Constructs an attribute with copies of all values of the input
312 /// attribute.
313 ///
314 /// </summary>
315 /// <param name="attr"> An LdapAttribute to use as a template.
316 ///
317 /// @throws IllegalArgumentException if attr is null
318 /// </param>
319 public LdapAttribute(LdapAttribute attr)
321 if (attr == null)
323 throw new System.ArgumentException("LdapAttribute class cannot be null");
325 // Do a deep copy of the LdapAttribute template
326 this.name = attr.name;
327 this.baseName = attr.baseName;
328 if (null != attr.subTypes)
330 this.subTypes = new System.String[attr.subTypes.Length];
331 Array.Copy((System.Array) attr.subTypes, 0, (System.Array) this.subTypes, 0, this.subTypes.Length);
333 // OK to just copy attributes, as the app only sees a deep copy of them
334 if (null != attr.values)
336 this.values = new System.Object[attr.values.Length];
337 Array.Copy((System.Array) attr.values, 0, (System.Array) this.values, 0, this.values.Length);
339 return ;
342 /// <summary> Constructs an attribute with no values.
343 ///
344 /// </summary>
345 /// <param name="attrName">Name of the attribute.
346 ///
347 /// @throws IllegalArgumentException if attrName is null
348 /// </param>
349 public LdapAttribute(System.String attrName)
351 if ((System.Object) attrName == null)
353 throw new System.ArgumentException("Attribute name cannot be null");
355 this.name = attrName;
356 this.baseName = LdapAttribute.getBaseName(attrName);
357 this.subTypes = LdapAttribute.getSubtypes(attrName);
358 return ;
361 /// <summary> Constructs an attribute with a byte-formatted value.
362 ///
363 /// </summary>
364 /// <param name="attrName">Name of the attribute.
365 /// </param>
366 /// <param name="attrBytes">Value of the attribute as raw bytes.
367 ///
368 /// Note: If attrBytes represents a string it should be UTF-8 encoded.
369 ///
370 /// @throws IllegalArgumentException if attrName or attrBytes is null
371 /// </param>
372 [CLSCompliantAttribute(false)]
373 public LdapAttribute(System.String attrName, sbyte[] attrBytes):this(attrName)
375 if (attrBytes == null)
377 throw new System.ArgumentException("Attribute value cannot be null");
379 // Make our own copy of the byte array to prevent app from changing it
380 sbyte[] tmp = new sbyte[attrBytes.Length];
381 Array.Copy((System.Array) attrBytes, 0, (System.Array)tmp, 0, attrBytes.Length);
382 this.add(tmp);
383 return ;
386 /// <summary> Constructs an attribute with a single string value.
387 ///
388 /// </summary>
389 /// <param name="attrName">Name of the attribute.
390 /// </param>
391 /// <param name="attrString">Value of the attribute as a string.
392 ///
393 /// @throws IllegalArgumentException if attrName or attrString is null
394 /// </param>
395 public LdapAttribute(System.String attrName, System.String attrString):this(attrName)
397 if ((System.Object) attrString == null)
399 throw new System.ArgumentException("Attribute value cannot be null");
403 System.Text.Encoding encoder = System.Text.Encoding.GetEncoding("utf-8");
404 byte[] ibytes = encoder.GetBytes(attrString);
405 sbyte[] sbytes=SupportClass.ToSByteArray(ibytes);
407 this.add(sbytes);
409 catch (System.IO.IOException e)
411 throw new System.SystemException(e.ToString());
413 return ;
416 /// <summary> Constructs an attribute with an array of string values.
417 ///
418 /// </summary>
419 /// <param name="attrName">Name of the attribute.
420 /// </param>
421 /// <param name="attrStrings">Array of values as strings.
422 ///
423 /// @throws IllegalArgumentException if attrName, attrStrings, or a member
424 /// of attrStrings is null
425 /// </param>
426 public LdapAttribute(System.String attrName, System.String[] attrStrings):this(attrName)
428 if (attrStrings == null)
430 throw new System.ArgumentException("Attribute values array cannot be null");
432 for (int i = 0, u = attrStrings.Length; i < u; i++)
436 if ((System.Object) attrStrings[i] == null)
438 throw new System.ArgumentException("Attribute value " + "at array index " + i + " cannot be null");
440 System.Text.Encoding encoder = System.Text.Encoding.GetEncoding("utf-8");
441 byte[] ibytes = encoder.GetBytes(attrStrings[i]);
442 sbyte[] sbytes=SupportClass.ToSByteArray(ibytes);
443 this.add(sbytes);
444 // this.add(attrStrings[i].getBytes("UTF-8"));
446 catch (System.IO.IOException e)
448 throw new System.SystemException(e.ToString());
451 return ;
454 /// <summary> Returns a clone of this LdapAttribute.
455 ///
456 /// </summary>
457 /// <returns> clone of this LdapAttribute.
458 /// </returns>
459 public System.Object Clone()
463 System.Object newObj = base.MemberwiseClone();
464 if (values != null)
466 Array.Copy((System.Array) this.values, 0, (System.Array) ((LdapAttribute) newObj).values, 0, this.values.Length);
468 return newObj;
470 catch (System.Exception ce)
472 throw new System.SystemException("Internal error, cannot create clone");
476 /// <summary> Adds a string value to the attribute.
477 ///
478 /// </summary>
479 /// <param name="attrString">Value of the attribute as a String.
480 ///
481 /// @throws IllegalArgumentException if attrString is null
482 /// </param>
483 public virtual void addValue(System.String attrString)
485 if ((System.Object) attrString == null)
487 throw new System.ArgumentException("Attribute value cannot be null");
491 System.Text.Encoding encoder = System.Text.Encoding.GetEncoding("utf-8");
492 byte[] ibytes = encoder.GetBytes(attrString);
493 sbyte[] sbytes=SupportClass.ToSByteArray(ibytes);
494 this.add(sbytes);
495 // this.add(attrString.getBytes("UTF-8"));
497 catch (System.IO.IOException ue)
499 throw new System.SystemException(ue.ToString());
501 return ;
504 /// <summary> Adds a byte-formatted value to the attribute.
505 ///
506 /// </summary>
507 /// <param name="attrBytes">Value of the attribute as raw bytes.
508 ///
509 /// Note: If attrBytes represents a string it should be UTF-8 encoded.
510 ///
511 /// @throws IllegalArgumentException if attrBytes is null
512 /// </param>
513 [CLSCompliantAttribute(false)]
514 public virtual void addValue(sbyte[] attrBytes)
516 if (attrBytes == null)
518 throw new System.ArgumentException("Attribute value cannot be null");
520 this.add(attrBytes);
521 return ;
524 /// <summary> Adds a base64 encoded value to the attribute.
525 /// The value will be decoded and stored as bytes. String
526 /// data encoded as a base64 value must be UTF-8 characters.
527 ///
528 /// </summary>
529 /// <param name="attrString">The base64 value of the attribute as a String.
530 ///
531 /// @throws IllegalArgumentException if attrString is null
532 /// </param>
533 public virtual void addBase64Value(System.String attrString)
535 if ((System.Object) attrString == null)
537 throw new System.ArgumentException("Attribute value cannot be null");
540 this.add(Base64.decode(attrString));
541 return ;
544 /// <summary> Adds a base64 encoded value to the attribute.
545 /// The value will be decoded and stored as bytes. Character
546 /// data encoded as a base64 value must be UTF-8 characters.
547 ///
548 /// </summary>
549 /// <param name="attrString">The base64 value of the attribute as a StringBuffer.
550 /// </param>
551 /// <param name="start"> The start index of base64 encoded part, inclusive.
552 /// </param>
553 /// <param name="end"> The end index of base encoded part, exclusive.
554 ///
555 /// @throws IllegalArgumentException if attrString is null
556 /// </param>
557 public virtual void addBase64Value(System.Text.StringBuilder attrString, int start, int end)
559 if (attrString == null)
561 throw new System.ArgumentException("Attribute value cannot be null");
564 this.add(Base64.decode(attrString, start, end));
566 return ;
569 /// <summary> Adds a base64 encoded value to the attribute.
570 /// The value will be decoded and stored as bytes. Character
571 /// data encoded as a base64 value must be UTF-8 characters.
572 ///
573 /// </summary>
574 /// <param name="attrChars">The base64 value of the attribute as an array of
575 /// characters.
576 ///
577 /// @throws IllegalArgumentException if attrString is null
578 /// </param>
579 public virtual void addBase64Value(char[] attrChars)
581 if (attrChars == null)
583 throw new System.ArgumentException("Attribute value cannot be null");
586 this.add(Base64.decode(attrChars));
587 return ;
590 /// <summary> Adds a URL, indicating a file or other resource that contains
591 /// the value of the attribute.
592 ///
593 /// </summary>
594 /// <param name="url">String value of a URL pointing to the resource containing
595 /// the value of the attribute.
596 ///
597 /// @throws IllegalArgumentException if url is null
598 /// </param>
599 public virtual void addURLValue(System.String url)
601 if ((System.Object) url == null)
603 throw new System.ArgumentException("Attribute URL cannot be null");
605 addURLValue(new System.Uri(url));
606 return ;
609 /// <summary> Adds a URL, indicating a file or other resource that contains
610 /// the value of the attribute.
611 ///
612 /// </summary>
613 /// <param name="url">A URL class pointing to the resource containing the value
614 /// of the attribute.
615 ///
616 /// @throws IllegalArgumentException if url is null
617 /// </param>
618 public virtual void addURLValue(System.Uri url)
620 // Class to encapsulate the data bytes and the length
621 if (url == null)
623 throw new System.ArgumentException("Attribute URL cannot be null");
627 // Get InputStream from the URL
628 System.IO.Stream in_Renamed = System.Net.WebRequest.Create(url).GetResponse().GetResponseStream();
629 // Read the bytes into buffers and store the them in an arraylist
630 System.Collections.ArrayList bufs = new System.Collections.ArrayList();
631 sbyte[] buf = new sbyte[4096];
632 int len, totalLength = 0;
633 while ((len = SupportClass.ReadInput(in_Renamed, ref buf, 0, 4096)) != - 1)
635 bufs.Add(new URLData(this, buf, len));
636 buf = new sbyte[4096];
637 totalLength += len;
640 * Now that the length is known, allocate an array to hold all
641 * the bytes of data and copy the data to that array, store
642 * it in this LdapAttribute
644 sbyte[] data = new sbyte[totalLength];
645 int offset = 0; //
646 for (int i = 0; i < bufs.Count; i++)
648 URLData b = (URLData) bufs[i];
649 len = b.getLength();
650 Array.Copy((System.Array) b.getData(), 0, (System.Array) data, offset, len);
651 offset += len;
653 this.add(data);
655 catch (System.IO.IOException ue)
657 throw new System.SystemException(ue.ToString());
659 return ;
662 /// <summary> Returns the base name of the attribute.
663 ///
664 /// For example, if the attribute name is cn;lang-ja;phonetic,
665 /// this method returns cn.
666 ///
667 /// </summary>
668 /// <returns> The base name of the attribute.
669 /// </returns>
670 public virtual System.String getBaseName()
672 return baseName;
675 /// <summary> Returns the base name of the specified attribute name.
676 ///
677 /// For example, if the attribute name is cn;lang-ja;phonetic,
678 /// this method returns cn.
679 ///
680 /// </summary>
681 /// <param name="attrName">Name of the attribute from which to extract the
682 /// base name.
683 ///
684 /// </param>
685 /// <returns> The base name of the attribute.
686 ///
687 /// @throws IllegalArgumentException if attrName is null
688 /// </returns>
689 public static System.String getBaseName(System.String attrName)
691 if ((System.Object) attrName == null)
693 throw new System.ArgumentException("Attribute name cannot be null");
695 int idx = attrName.IndexOf((System.Char) ';');
696 if (- 1 == idx)
698 return attrName;
700 return attrName.Substring(0, (idx) - (0));
703 /// <summary> Extracts the subtypes from the attribute name.
704 ///
705 /// For example, if the attribute name is cn;lang-ja;phonetic,
706 /// this method returns an array containing lang-ja and phonetic.
707 ///
708 /// </summary>
709 /// <returns> An array subtypes or null if the attribute has none.
710 /// </returns>
711 public virtual System.String[] getSubtypes()
713 return subTypes;
716 /// <summary> Extracts the subtypes from the specified attribute name.
717 ///
718 /// For example, if the attribute name is cn;lang-ja;phonetic,
719 /// this method returns an array containing lang-ja and phonetic.
720 ///
721 /// </summary>
722 /// <param name="attrName"> Name of the attribute from which to extract
723 /// the subtypes.
724 ///
725 /// </param>
726 /// <returns> An array subtypes or null if the attribute has none.
727 ///
728 /// @throws IllegalArgumentException if attrName is null
729 /// </returns>
730 public static System.String[] getSubtypes(System.String attrName)
732 if ((System.Object) attrName == null)
734 throw new System.ArgumentException("Attribute name cannot be null");
736 SupportClass.Tokenizer st = new SupportClass.Tokenizer(attrName, ";");
737 System.String[] subTypes = null;
738 int cnt = st.Count;
739 if (cnt > 0)
741 st.NextToken(); // skip over basename
742 subTypes = new System.String[cnt - 1];
743 int i = 0;
744 while (st.HasMoreTokens())
746 subTypes[i++] = st.NextToken();
749 return subTypes;
752 /// <summary> Reports if the attribute name contains the specified subtype.
753 ///
754 /// For example, if you check for the subtype lang-en and the
755 /// attribute name is cn;lang-en, this method returns true.
756 ///
757 /// </summary>
758 /// <param name="subtype"> The single subtype to check for.
759 ///
760 /// </param>
761 /// <returns> True, if the attribute has the specified subtype;
762 /// false, if it doesn't.
763 ///
764 /// @throws IllegalArgumentException if subtype is null
765 /// </returns>
766 public virtual bool hasSubtype(System.String subtype)
768 if ((System.Object) subtype == null)
770 throw new System.ArgumentException("subtype cannot be null");
772 if (null != this.subTypes)
774 for (int i = 0; i < subTypes.Length; i++)
776 if (subTypes[i].ToUpper().Equals(subtype.ToUpper()))
777 return true;
780 return false;
783 /// <summary> Reports if the attribute name contains all the specified subtypes.
784 ///
785 /// For example, if you check for the subtypes lang-en and phonetic
786 /// and if the attribute name is cn;lang-en;phonetic, this method
787 /// returns true. If the attribute name is cn;phonetic or cn;lang-en,
788 /// this method returns false.
789 ///
790 /// </summary>
791 /// <param name="subtypes"> An array of subtypes to check for.
792 ///
793 /// </param>
794 /// <returns> True, if the attribute has all the specified subtypes;
795 /// false, if it doesn't have all the subtypes.
796 ///
797 /// @throws IllegalArgumentException if subtypes is null or if array member
798 /// is null.
799 /// </returns>
800 public virtual bool hasSubtypes(System.String[] subtypes)
802 if (subtypes == null)
804 throw new System.ArgumentException("subtypes cannot be null");
806 for (int i = 0; i < subtypes.Length; i++)
808 for (int j = 0; j < subTypes.Length; j++)
810 if ((System.Object) subTypes[j] == null)
812 throw new System.ArgumentException("subtype " + "at array index " + i + " cannot be null");
814 if (subTypes[j].ToUpper().Equals(subtypes[i].ToUpper()))
816 goto gotSubType;
819 return false;
820 gotSubType: ;
822 return true;
825 /// <summary> Removes a string value from the attribute.
826 ///
827 /// </summary>
828 /// <param name="attrString"> Value of the attribute as a string.
829 ///
830 /// Note: Removing a value which is not present in the attribute has
831 /// no effect.
832 ///
833 /// @throws IllegalArgumentException if attrString is null
834 /// </param>
835 public virtual void removeValue(System.String attrString)
837 if (null == (System.Object) attrString)
839 throw new System.ArgumentException("Attribute value cannot be null");
843 System.Text.Encoding encoder = System.Text.Encoding.GetEncoding("utf-8");
844 byte[] ibytes = encoder.GetBytes(attrString);
845 sbyte[] sbytes=SupportClass.ToSByteArray(ibytes);
846 this.removeValue(sbytes);
847 // this.removeValue(attrString.getBytes("UTF-8"));
849 catch (System.IO.IOException uee)
851 // This should NEVER happen but just in case ...
852 throw new System.SystemException(uee.ToString());
854 return ;
857 /// <summary> Removes a byte-formatted value from the attribute.
858 ///
859 /// </summary>
860 /// <param name="attrBytes"> Value of the attribute as raw bytes.
861 /// Note: If attrBytes represents a string it should be UTF-8 encoded.
862 /// Example: <code>String.getBytes("UTF-8");</code>
863 ///
864 /// Note: Removing a value which is not present in the attribute has
865 /// no effect.
866 ///
867 /// @throws IllegalArgumentException if attrBytes is null
868 /// </param>
869 [CLSCompliantAttribute(false)]
870 public virtual void removeValue(sbyte[] attrBytes)
872 if (null == attrBytes)
874 throw new System.ArgumentException("Attribute value cannot be null");
876 for (int i = 0; i < this.values.Length; i++)
878 if (equals(attrBytes, (sbyte[]) this.values[i]))
880 if (0 == i && 1 == this.values.Length)
882 // Optimize if first element of a single valued attr
883 this.values = null;
884 return ;
886 if (this.values.Length == 1)
888 this.values = null;
890 else
892 int moved = this.values.Length - i - 1;
893 System.Object[] tmp = new System.Object[this.values.Length - 1];
894 if (i != 0)
896 Array.Copy((System.Array) values, 0, (System.Array) tmp, 0, i);
898 if (moved != 0)
900 Array.Copy((System.Array) values, i + 1, (System.Array) tmp, i, moved);
902 this.values = tmp;
903 tmp = null;
905 break;
908 return ;
911 /// <summary> Returns the number of values in the attribute.
912 ///
913 /// </summary>
914 /// <returns> The number of values in the attribute.
915 /// </returns>
916 public virtual int size()
918 return null == this.values?0:this.values.Length;
921 /// <summary> Compares this object with the specified object for order.
922 ///
923 /// Ordering is determined by comparing attribute names (see
924 /// {@link #getName() }) using the method compareTo() of the String class.
925 ///
926 ///
927 /// </summary>
928 /// <param name="attribute"> The LdapAttribute to be compared to this object.
929 ///
930 /// </param>
931 /// <returns> Returns a negative integer, zero, or a positive
932 /// integer as this object is less than, equal to, or greater than the
933 /// specified object.
934 /// </returns>
935 public virtual int CompareTo(System.Object attribute)
938 return name.CompareTo(((LdapAttribute) attribute).name);
941 /// <summary> Adds an object to <code>this</code> object's list of attribute values
942 ///
943 /// </summary>
944 /// <param name="bytes"> Ultimately all of this attribute's values are treated
945 /// as binary data so we simplify the process by requiring
946 /// that all data added to our list is in binary form.
947 ///
948 /// Note: If attrBytes represents a string it should be UTF-8 encoded.
949 /// </param>
950 private void add(sbyte[] bytes)
952 if (null == this.values)
954 this.values = new System.Object[]{bytes};
956 else
958 // Duplicate attribute values not allowed
959 for (int i = 0; i < this.values.Length; i++)
961 if (equals(bytes, (sbyte[]) this.values[i]))
963 return ; // Duplicate, don't add
966 System.Object[] tmp = new System.Object[this.values.Length + 1];
967 Array.Copy((System.Array) this.values, 0, (System.Array) tmp, 0, this.values.Length);
968 tmp[this.values.Length] = bytes;
969 this.values = tmp;
970 tmp = null;
972 return ;
975 /// <summary> Returns true if the two specified arrays of bytes are equal to each
976 /// another. Matches the logic of Arrays.equals which is not available
977 /// in jdk 1.1.x.
978 ///
979 /// </summary>
980 /// <param name="e1">the first array to be tested
981 /// </param>
982 /// <param name="e2">the second array to be tested
983 /// </param>
984 /// <returns> true if the two arrays are equal
985 /// </returns>
986 private bool equals(sbyte[] e1, sbyte[] e2)
988 // If same object, they compare true
989 if (e1 == e2)
990 return true;
992 // If either but not both are null, they compare false
993 if (e1 == null || e2 == null)
994 return false;
996 // If arrays have different length, they compare false
997 int length = e1.Length;
998 if (e2.Length != length)
999 return false;
1001 // If any of the bytes are different, they compare false
1002 for (int i = 0; i < length; i++)
1004 if (e1[i] != e2[i])
1005 return false;
1008 return true;
1011 /// <summary> Returns a string representation of this LdapAttribute
1012 ///
1013 /// </summary>
1014 /// <returns> a string representation of this LdapAttribute
1015 /// </returns>
1016 public override System.String ToString()
1018 System.Text.StringBuilder result = new System.Text.StringBuilder("LdapAttribute: ");
1021 result.Append("{type='" + name + "'");
1022 if (values != null)
1024 result.Append(", ");
1025 if (values.Length == 1)
1027 result.Append("value='");
1029 else
1031 result.Append("values='");
1033 for (int i = 0; i < values.Length; i++)
1035 if (i != 0)
1037 result.Append("','");
1039 if (((sbyte[]) values[i]).Length == 0)
1041 continue;
1043 System.Text.Encoding encoder = System.Text.Encoding.GetEncoding("utf-8");
1044 // char[] dchar = encoder.GetChars((byte[]) values[i]);
1045 char[] dchar = encoder.GetChars(SupportClass.ToByteArray((sbyte[])values[i]));
1046 System.String sval = new String(dchar);
1048 // System.String sval = new String((sbyte[]) values[i], "UTF-8");
1049 if (sval.Length == 0)
1051 // didn't decode well, must be binary
1052 result.Append("<binary value, length:" + sval.Length);
1053 continue;
1055 result.Append(sval);
1057 result.Append("'");
1059 result.Append("}");
1061 catch (System.Exception e)
1063 throw new System.SystemException(e.ToString());
1065 return result.ToString();