Fix ber scanf/printf, fix for a reverted PR. (#52178)
authorSergey Andreenko <seandree@microsoft.com>
Sat, 8 May 2021 10:19:42 +0000 (03:19 -0700)
committerGitHub <noreply@github.com>
Sat, 8 May 2021 10:19:42 +0000 (03:19 -0700)
* Reenable the tests.

* Use __arglist for windows.
Use ber_put_*/ber_get_* for Unix

* Use nuint for Linux.

* review response

19 files changed:
src/libraries/Common/src/Interop/Linux/OpenLdap/Interop.Ber.cs
src/libraries/Common/src/Interop/Windows/Wldap32/Interop.Ber.cs
src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/BerPal.Linux.cs
src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/BerPal.Windows.cs
src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/common/BerConverter.Windows.cs
src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/common/BerConverter.cs
src/libraries/System.DirectoryServices.Protocols/tests/AsqRequestControlTests.cs
src/libraries/System.DirectoryServices.Protocols/tests/BerConversionExceptionTests.cs
src/libraries/System.DirectoryServices.Protocols/tests/BerConverterTests.cs
src/libraries/System.DirectoryServices.Protocols/tests/DirSyncRequestControlTests.cs
src/libraries/System.DirectoryServices.Protocols/tests/DirectoryControlTests.cs
src/libraries/System.DirectoryServices.Protocols/tests/DirectoryServicesProtocolsTests.cs
src/libraries/System.DirectoryServices.Protocols/tests/ExtendedDNControlTests.cs
src/libraries/System.DirectoryServices.Protocols/tests/PageResultRequestControlTests.cs
src/libraries/System.DirectoryServices.Protocols/tests/QuotaControlTests.cs
src/libraries/System.DirectoryServices.Protocols/tests/SearchOptionsControlTests.cs
src/libraries/System.DirectoryServices.Protocols/tests/SecurityDescriptorFlagControlTests.cs
src/libraries/System.DirectoryServices.Protocols/tests/VerifyNameControlTests.cs
src/libraries/System.DirectoryServices.Protocols/tests/VlvRequestControlTests.cs

index 9dc20b7..4ee4bc8 100644 (file)
@@ -4,11 +4,14 @@
 using System;
 using System.Runtime.InteropServices;
 using System.DirectoryServices.Protocols;
+using System.Diagnostics;
 
 internal static partial class Interop
 {
     internal static partial class Ldap
     {
+        public const int ber_default_successful_return_code = 0;
+
         [DllImport(Libraries.OpenLdap, EntryPoint = "ber_alloc_t", CharSet = CharSet.Ansi)]
         public static extern IntPtr ber_alloc(int option);
 
@@ -18,17 +21,97 @@ internal static partial class Interop
         [DllImport(Libraries.OpenLdap, EntryPoint = "ber_free", CharSet = CharSet.Ansi)]
         public static extern IntPtr ber_free([In] IntPtr berelement, int option);
 
-        [DllImport(Libraries.OpenLdap, EntryPoint = "ber_printf", CharSet = CharSet.Ansi)]
-        public static extern int ber_printf_emptyarg(SafeBerHandle berElement, string format);
+        public static int ber_printf_emptyarg(SafeBerHandle berElement, string format, nuint tag)
+        {
+            if (format == "{")
+            {
+                return ber_start_seq(berElement, tag);
+            }
+            else if (format == "}")
+            {
+                return ber_put_seq(berElement, tag);
+            }
+            else if (format == "[")
+            {
+                return ber_start_set(berElement, tag);
+            }
+            else if (format == "]")
+            {
+                return ber_put_set(berElement, tag);
+            }
+            else
+            {
+                Debug.Assert(format == "n");
+                return ber_put_null(berElement, tag);
+            }
+        }
+
+        [DllImport(Libraries.OpenLdap, EntryPoint = "ber_start_seq", CharSet = CharSet.Ansi)]
+        public static extern int ber_start_seq(SafeBerHandle berElement, nuint tag);
+
+        [DllImport(Libraries.OpenLdap, EntryPoint = "ber_start_set", CharSet = CharSet.Ansi)]
+        public static extern int ber_start_set(SafeBerHandle berElement, nuint tag);
+
+        [DllImport(Libraries.OpenLdap, EntryPoint = "ber_put_seq", CharSet = CharSet.Ansi)]
+        public static extern int ber_put_seq(SafeBerHandle berElement, nuint tag);
+
+        [DllImport(Libraries.OpenLdap, EntryPoint = "ber_put_set", CharSet = CharSet.Ansi)]
+        public static extern int ber_put_set(SafeBerHandle berElement, nuint tag);
+
+        [DllImport(Libraries.OpenLdap, EntryPoint = "ber_put_null", CharSet = CharSet.Ansi)]
+        public static extern int ber_put_null(SafeBerHandle berElement, nuint tag);
+
+        public static int ber_printf_int(SafeBerHandle berElement, string format, int value, nuint tag)
+        {
+            if (format == "i")
+            {
+                return ber_put_int(berElement, value, tag);
+            }
+            else if (format == "e")
+            {
+                return ber_put_enum(berElement, value, tag);
+            }
+            else
+            {
+                Debug.Assert(format == "b");
+                return ber_put_boolean(berElement, value, tag);
+            }
+        }
+
+        [DllImport(Libraries.OpenLdap, EntryPoint = "ber_put_int", CharSet = CharSet.Ansi)]
+        public static extern int ber_put_int(SafeBerHandle berElement, int value, nuint tag);
+
+        [DllImport(Libraries.OpenLdap, EntryPoint = "ber_put_enum", CharSet = CharSet.Ansi)]
+        public static extern int ber_put_enum(SafeBerHandle berElement, int value, nuint tag);
+
+        [DllImport(Libraries.OpenLdap, EntryPoint = "ber_put_boolean", CharSet = CharSet.Ansi)]
+        public static extern int ber_put_boolean(SafeBerHandle berElement, int value, nuint tag);
 
-        [DllImport(Libraries.OpenLdap, EntryPoint = "ber_printf", CharSet = CharSet.Ansi)]
-        public static extern int ber_printf_int(SafeBerHandle berElement, string format, int value);
+        public static int ber_printf_bytearray(SafeBerHandle berElement, string format, HGlobalMemHandle value, nuint length, nuint tag)
+        {
+            if (format == "o")
+            {
+                return ber_put_ostring(berElement, value, length, tag);
+            }
+            else if (format == "s")
+            {
+                return ber_put_string(berElement, value, tag);
+            }
+            else
+            {
+                Debug.Assert(format == "X");
+                return ber_put_bitstring(berElement, value, length, tag);
+            }
+        }
 
-        [DllImport(Libraries.OpenLdap, EntryPoint = "ber_printf", CharSet = CharSet.Ansi)]
-        public static extern int ber_printf_bytearray(SafeBerHandle berElement, string format, HGlobalMemHandle value, int length);
+        [DllImport(Libraries.OpenLdap, EntryPoint = "ber_put_ostring", CharSet = CharSet.Ansi)]
+        private static extern int ber_put_ostring(SafeBerHandle berElement, HGlobalMemHandle value, nuint length, nuint tag);
 
-        [DllImport(Libraries.OpenLdap, EntryPoint = "ber_printf", CharSet = CharSet.Ansi)]
-        public static extern int ber_printf_berarray(SafeBerHandle berElement, string format, IntPtr value);
+        [DllImport(Libraries.OpenLdap, EntryPoint = "ber_put_string", CharSet = CharSet.Ansi)]
+        private static extern int ber_put_string(SafeBerHandle berElement, HGlobalMemHandle value, nuint tag);
+
+        [DllImport(Libraries.OpenLdap, EntryPoint = "ber_put_bitstring", CharSet = CharSet.Ansi)]
+        private static extern int ber_put_bitstring(SafeBerHandle berElement, HGlobalMemHandle value, nuint length, nuint tag);
 
         [DllImport(Libraries.OpenLdap, EntryPoint = "ber_flatten", CharSet = CharSet.Ansi)]
         public static extern int ber_flatten(SafeBerHandle berElement, ref IntPtr value);
@@ -39,16 +122,90 @@ internal static partial class Interop
         [DllImport(Libraries.OpenLdap, EntryPoint = "ber_bvecfree", CharSet = CharSet.Ansi)]
         public static extern int ber_bvecfree(IntPtr value);
 
-        [DllImport(Libraries.OpenLdap, EntryPoint = "ber_scanf", CharSet = CharSet.Ansi)]
-        public static extern int ber_scanf(SafeBerHandle berElement, string format);
+        public static int ber_scanf_emptyarg(SafeBerHandle berElement, string format)
+        {
+            Debug.Assert(format == "{" || format == "}" || format == "[" || format == "]" || format == "n" || format == "x");
+            if (format == "{" || format == "[")
+            {
+                nuint len = 0;
+                return ber_skip_tag(berElement, ref len);
+            }
+            else if (format == "]" || format == "}")
+            {
+                return ber_default_successful_return_code;
+            }
+            else
+            {
+                Debug.Assert(format == "n" || format == "x");
+                return ber_get_null(berElement);
+            }
+        }
+
+        [DllImport(Libraries.OpenLdap, EntryPoint = "ber_skip_tag", CharSet = CharSet.Ansi)]
+        private static extern int ber_skip_tag(SafeBerHandle berElement, ref nuint len);
+
+        [DllImport(Libraries.OpenLdap, EntryPoint = "ber_get_null", CharSet = CharSet.Ansi)]
+        private static extern int ber_get_null(SafeBerHandle berElement);
+
+        public static int ber_scanf_int(SafeBerHandle berElement, string format, ref int value)
+        {
+            if (format == "i")
+            {
+                return ber_get_int(berElement, ref value);
+            }
+            else if (format == "e")
+            {
+                return ber_get_enum(berElement, ref value);
+            }
+            else
+            {
+                Debug.Assert(format == "b");
+                return ber_get_boolean(berElement, ref value);
+            }
+        }
+
+        [DllImport(Libraries.OpenLdap, EntryPoint = "ber_get_int", CharSet = CharSet.Ansi)]
+        private static extern int ber_get_int(SafeBerHandle berElement, ref int value);
+
+        [DllImport(Libraries.OpenLdap, EntryPoint = "ber_get_enum", CharSet = CharSet.Ansi)]
+        private static extern int ber_get_enum(SafeBerHandle berElement, ref int value);
+
+        [DllImport(Libraries.OpenLdap, EntryPoint = "ber_get_boolean", CharSet = CharSet.Ansi)]
+        private static extern int ber_get_boolean(SafeBerHandle berElement, ref int value);
+
+        public static int ber_scanf_bitstring(SafeBerHandle berElement, string format, ref IntPtr value, ref uint bitLength)
+        {
+            Debug.Assert(format == "B");
+            nuint bitLengthAsNuint = 0;
+            int res = ber_get_stringb(berElement, ref value, ref bitLengthAsNuint);
+            bitLength = (uint)bitLengthAsNuint;
+            return res;
+        }
+
+        [DllImport(Libraries.OpenLdap, EntryPoint = "ber_get_stringb", CharSet = CharSet.Ansi)]
+        private static extern int ber_get_stringb(SafeBerHandle berElement, ref IntPtr value, ref nuint bitLength);
+
+        public static int ber_scanf_ptr(SafeBerHandle berElement, string format, ref IntPtr value)
+        {
+            Debug.Assert(format == "O");
+            return ber_get_stringal(berElement, ref value);
+        }
 
-        [DllImport(Libraries.OpenLdap, EntryPoint = "ber_scanf", CharSet = CharSet.Ansi)]
-        public static extern int ber_scanf_int(SafeBerHandle berElement, string format, ref int value);
+        [DllImport(Libraries.OpenLdap, EntryPoint = "ber_get_stringal", CharSet = CharSet.Ansi)]
+        private static extern int ber_get_stringal(SafeBerHandle berElement, ref IntPtr value);
 
-        [DllImport(Libraries.OpenLdap, EntryPoint = "ber_scanf", CharSet = CharSet.Ansi)]
-        public static extern int ber_scanf_bitstring(SafeBerHandle berElement, string format, ref IntPtr value, ref int bitLength);
+        public static int ber_printf_berarray(SafeBerHandle berElement, string format, IntPtr value, nuint tag)
+        {
+            Debug.Assert(format == "v" || format == "V");
+            // V and v are not supported on Unix yet.
+            return -1;
+        }
 
-        [DllImport(Libraries.OpenLdap, EntryPoint = "ber_scanf", CharSet = CharSet.Ansi)]
-        public static extern int ber_scanf_ptr(SafeBerHandle berElement, string format, ref IntPtr value);
+        public static int ber_scanf_multibytearray(SafeBerHandle berElement, string format, ref IntPtr value)
+        {
+            Debug.Assert(format == "v" || format == "V");
+            // V and v are not supported on Unix yet.
+            return -1;
+        }
     }
 }
index 99fec68..0ba2c96 100644 (file)
@@ -16,16 +16,7 @@ internal static partial class Interop
         public static extern IntPtr ber_alloc(int option);
 
         [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ber_printf", CharSet = CharSet.Unicode)]
-        public static extern int ber_printf_emptyarg(SafeBerHandle berElement, string format);
-
-        [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ber_printf", CharSet = CharSet.Unicode)]
-        public static extern int ber_printf_int(SafeBerHandle berElement, string format, int value);
-
-        [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ber_printf", CharSet = CharSet.Unicode)]
-        public static extern int ber_printf_bytearray(SafeBerHandle berElement, string format, HGlobalMemHandle value, int length);
-
-        [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ber_printf", CharSet = CharSet.Unicode)]
-        public static extern int ber_printf_berarray(SafeBerHandle berElement, string format, IntPtr value);
+        public static extern int ber_printf(SafeBerHandle berElement, string format, __arglist);
 
         [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ber_flatten", CharSet = CharSet.Unicode)]
         public static extern int ber_flatten(SafeBerHandle berElement, ref IntPtr value);
@@ -34,16 +25,7 @@ internal static partial class Interop
         public static extern IntPtr ber_init(berval value);
 
         [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ber_scanf", CharSet = CharSet.Unicode)]
-        public static extern int ber_scanf(SafeBerHandle berElement, string format);
-
-        [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ber_scanf", CharSet = CharSet.Unicode)]
-        public static extern int ber_scanf_int(SafeBerHandle berElement, string format, ref int value);
-
-        [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ber_scanf", CharSet = CharSet.Unicode)]
-        public static extern int ber_scanf_ptr(SafeBerHandle berElement, string format, ref IntPtr value);
-
-        [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ber_scanf", CharSet = CharSet.Unicode)]
-        public static extern int ber_scanf_bitstring(SafeBerHandle berElement, string format, ref IntPtr value, ref int bitLength);
+        public static extern int ber_scanf(SafeBerHandle berElement, string format, __arglist);
 
         [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ber_bvfree", CharSet = CharSet.Unicode)]
         public static extern int ber_bvfree(IntPtr value);
index b8856cf..319bdba 100644 (file)
@@ -13,22 +13,31 @@ namespace System.DirectoryServices.Protocols
 
         internal static int FlattenBerElement(SafeBerHandle berElement, ref IntPtr flattenptr) => Interop.Ldap.ber_flatten(berElement, ref flattenptr);
 
-        internal static int PrintBerArray(SafeBerHandle berElement, string format, IntPtr value) => Interop.Ldap.ber_printf_berarray(berElement, format, value);
+        internal static int PrintBerArray(SafeBerHandle berElement, string format, IntPtr value, nuint tag) => Interop.Ldap.ber_printf_berarray(berElement, format, value, tag);
 
-        internal static int PrintByteArray(SafeBerHandle berElement, string format, HGlobalMemHandle value, int length) => Interop.Ldap.ber_printf_bytearray(berElement, format, value, length);
+        internal static int PrintByteArray(SafeBerHandle berElement, string format, HGlobalMemHandle value, nuint length, nuint tag) => Interop.Ldap.ber_printf_bytearray(berElement, format, value, length, tag);
 
-        internal static int PrintEmptyArgument(SafeBerHandle berElement, string format) => Interop.Ldap.ber_printf_emptyarg(berElement, format);
+        internal static int PrintEmptyArgument(SafeBerHandle berElement, string format, nuint tag) => Interop.Ldap.ber_printf_emptyarg(berElement, format, tag);
 
-        internal static int PrintInt(SafeBerHandle berElement, string format, int value) => Interop.Ldap.ber_printf_int(berElement, format, value);
+        internal static int PrintInt(SafeBerHandle berElement, string format, int value, nuint tag) => Interop.Ldap.ber_printf_int(berElement, format, value, tag);
 
-        internal static int ScanNext(SafeBerHandle berElement, string format) => Interop.Ldap.ber_scanf(berElement, format);
+        internal static int PrintTag(SafeBerHandle _1, string _2, nuint _3)
+        {
+            // Ber Linux tags are passed with the values that they affect, like `ber_printf_int(.., tag)`.
+            // So this function does nothing on Linux.
+            return Interop.Ldap.ber_default_successful_return_code;
+        }
 
-        internal static int ScanNextBitString(SafeBerHandle berElement, string format, ref IntPtr ptrResult, ref int bitLength) => Interop.Ldap.ber_scanf_bitstring(berElement, format, ref ptrResult, ref bitLength);
+        internal static int ScanNext(SafeBerHandle berElement, string format) => Interop.Ldap.ber_scanf_emptyarg(berElement, format);
+
+        internal static int ScanNextBitString(SafeBerHandle berElement, string format, ref IntPtr ptrResult, ref uint bitLength) => Interop.Ldap.ber_scanf_bitstring(berElement, format, ref ptrResult, ref bitLength);
 
         internal static int ScanNextInt(SafeBerHandle berElement, string format, ref int result) => Interop.Ldap.ber_scanf_int(berElement, format, ref result);
 
         internal static int ScanNextPtr(SafeBerHandle berElement, string format, ref IntPtr value) => Interop.Ldap.ber_scanf_ptr(berElement, format, ref value);
 
+        internal static int ScanNextMultiByteArray(SafeBerHandle berElement, string format, ref IntPtr value) => Interop.Ldap.ber_scanf_multibytearray(berElement, format, ref value);
+
         internal static bool IsBerDecodeError(int errorCode) => errorCode == -1;
     }
 }
index 202737f..586bcd7 100644 (file)
@@ -15,21 +15,25 @@ namespace System.DirectoryServices.Protocols
 
         internal static int FlattenBerElement(SafeBerHandle berElement, ref IntPtr flattenptr) => Interop.Ldap.ber_flatten(berElement, ref flattenptr);
 
-        internal static int PrintBerArray(SafeBerHandle berElement, string format, IntPtr value) => Interop.Ldap.ber_printf_berarray(berElement, format, value);
+        internal static int PrintBerArray(SafeBerHandle berElement, string format, IntPtr value, nuint _) => Interop.Ldap.ber_printf(berElement, format, __arglist(value));
 
-        internal static int PrintByteArray(SafeBerHandle berElement, string format, HGlobalMemHandle value, int length) => Interop.Ldap.ber_printf_bytearray(berElement, format, value, length);
+        internal static int PrintByteArray(SafeBerHandle berElement, string format, HGlobalMemHandle value, uint length, nuint _) => Interop.Ldap.ber_printf(berElement, format, __arglist(value, length));
 
-        internal static int PrintEmptyArgument(SafeBerHandle berElement, string format) => Interop.Ldap.ber_printf_emptyarg(berElement, format);
+        internal static int PrintEmptyArgument(SafeBerHandle berElement, string format, nuint _) => Interop.Ldap.ber_printf(berElement, format, __arglist());
 
-        internal static int PrintInt(SafeBerHandle berElement, string format, int value) => Interop.Ldap.ber_printf_int(berElement, format, value);
+        internal static int PrintInt(SafeBerHandle berElement, string format, int value, nuint _) => Interop.Ldap.ber_printf(berElement, format, __arglist(value));
 
-        internal static int ScanNext(SafeBerHandle berElement, string format) => Interop.Ldap.ber_scanf(berElement, format);
+        internal static int PrintTag(SafeBerHandle berElement, string format, nuint tag) => Interop.Ldap.ber_printf(berElement, format, __arglist((uint)tag));
 
-        internal static int ScanNextBitString(SafeBerHandle berElement, string format, ref IntPtr ptrResult, ref int bitLength) => Interop.Ldap.ber_scanf_bitstring(berElement, format, ref ptrResult, ref bitLength);
+        internal static int ScanNext(SafeBerHandle berElement, string format) => Interop.Ldap.ber_scanf(berElement, format, __arglist());
 
-        internal static int ScanNextInt(SafeBerHandle berElement, string format, ref int result) => Interop.Ldap.ber_scanf_int(berElement, format, ref result);
+        internal static int ScanNextBitString(SafeBerHandle berElement, string format, ref IntPtr ptrResult, ref uint bitLength) => Interop.Ldap.ber_scanf(berElement, format, __arglist(ref ptrResult, ref bitLength));
 
-        internal static int ScanNextPtr(SafeBerHandle berElement, string format, ref IntPtr value) => Interop.Ldap.ber_scanf_ptr(berElement, format, ref value);
+        internal static int ScanNextInt(SafeBerHandle berElement, string format, ref int result) => Interop.Ldap.ber_scanf(berElement, format, __arglist(ref result));
+
+        internal static int ScanNextPtr(SafeBerHandle berElement, string format, ref IntPtr value) => Interop.Ldap.ber_scanf(berElement, format, __arglist(ref value));
+
+        internal static int ScanNextMultiByteArray(SafeBerHandle berElement, string format, ref IntPtr value) => Interop.Ldap.ber_scanf(berElement, format, __arglist(ref value));
 
         internal static bool IsBerDecodeError(int errorCode) => errorCode != 0;
     }
index e4bd5d1..3bef316 100644 (file)
@@ -14,7 +14,7 @@ namespace System.DirectoryServices.Protocols
             int error;
             // return a bitstring and its length
             IntPtr ptrResult = IntPtr.Zero;
-            int length = 0;
+            uint length = 0;
             error = BerPal.ScanNextBitString(berElement, "B", ref ptrResult, ref length);
 
             if (!BerPal.IsBerDecodeError(error))
@@ -23,7 +23,7 @@ namespace System.DirectoryServices.Protocols
                 if (ptrResult != IntPtr.Zero)
                 {
                     byteArray = new byte[length];
-                    Marshal.Copy(ptrResult, byteArray, 0, length);
+                    Marshal.Copy(ptrResult, byteArray, 0, (int)length);
                 }
                 resultList.Add(byteArray);
             }
index 058024f..8833ae7 100644 (file)
@@ -29,15 +29,30 @@ namespace System.DirectoryServices.Protocols
 
             int valueCount = 0;
             int error = 0;
+
+            // We can't use vararg on Unix and can't do ber_printf(tag), so we use ber_put_int(val, tag)
+            // and this local keeps tag value for the next element.
+            nuint tag = 0;
+            bool tagIsSet = false;
             for (int formatCount = 0; formatCount < format.Length; formatCount++)
             {
+                if (tagIsSet)
+                {
+                    tagIsSet = false;
+                }
+                else
+                {
+                    int lberTagDefaultInt = -1;
+                    nuint lberTagDefaultNuint = (nuint)lberTagDefaultInt;
+                    tag = lberTagDefaultNuint;
+                }
                 char fmt = format[formatCount];
                 if (fmt == '{' || fmt == '}' || fmt == '[' || fmt == ']' || fmt == 'n')
                 {
                     // no argument needed
-                    error = BerPal.PrintEmptyArgument(berElement, new string(fmt, 1));
+                    error = BerPal.PrintEmptyArgument(berElement, new string(fmt, 1), tag);
                 }
-                else if (fmt == 't' || fmt == 'i' || fmt == 'e')
+                else if (fmt == 'i' || fmt == 'e')
                 {
                     if (valueCount >= value.Length)
                     {
@@ -54,7 +69,7 @@ namespace System.DirectoryServices.Protocols
                     }
 
                     // one int argument
-                    error = BerPal.PrintInt(berElement, new string(fmt, 1), (int)value[valueCount]);
+                    error = BerPal.PrintInt(berElement, new string(fmt, 1), (int)value[valueCount], tag);
 
                     // increase the value count
                     valueCount++;
@@ -76,7 +91,7 @@ namespace System.DirectoryServices.Protocols
                     }
 
                     // one int argument
-                    error = BerPal.PrintInt(berElement, new string(fmt, 1), (bool)value[valueCount] ? 1 : 0);
+                    error = BerPal.PrintInt(berElement, new string(fmt, 1), (bool)value[valueCount] ? 1 : 0, tag);
 
                     // increase the value count
                     valueCount++;
@@ -104,7 +119,7 @@ namespace System.DirectoryServices.Protocols
                     {
                         tempValue = utf8Encoder.GetBytes((string)value[valueCount]);
                     }
-                    error = EncodingByteArrayHelper(berElement, tempValue, 'o');
+                    error = EncodingByteArrayHelper(berElement, tempValue, 'o', tag);
 
                     // increase the value count
                     valueCount++;
@@ -128,7 +143,7 @@ namespace System.DirectoryServices.Protocols
                     }
 
                     byte[] tempValue = (byte[])value[valueCount];
-                    error = EncodingByteArrayHelper(berElement, tempValue, fmt);
+                    error = EncodingByteArrayHelper(berElement, tempValue, fmt, tag);
 
                     valueCount++;
                 }
@@ -164,11 +179,13 @@ namespace System.DirectoryServices.Protocols
                             {
                                 tempValues[i] = utf8Encoder.GetBytes(s);
                             }
+                            error = EncodingByteArrayHelper(berElement, tempValues[i], 'o', tag);
+                            if (error == -1)
+                            {
+                                break;
+                            }
                         }
                     }
-
-                    error = EncodingMultiByteArrayHelper(berElement, tempValues, 'V');
-
                     valueCount++;
                 }
                 else if (fmt == 'V')
@@ -191,8 +208,31 @@ namespace System.DirectoryServices.Protocols
 
                     byte[][] tempValue = (byte[][])value[valueCount];
 
-                    error = EncodingMultiByteArrayHelper(berElement, tempValue, fmt);
+                    error = EncodingMultiByteArrayHelper(berElement, tempValue, fmt, tag);
+
+                    valueCount++;
+                }
+                else if (fmt == 't')
+                {
+                    if (valueCount >= value.Length)
+                    {
+                        // we don't have enough argument for the format string
+                        Debug.WriteLine("value argument is not valid, valueCount >= value.Length\n");
+                        throw new ArgumentException(SR.BerConverterNotMatch);
+                    }
+
+                    if (!(value[valueCount] is int))
+                    {
+                        // argument is wrong
+                        Debug.WriteLine("type should be int\n");
+                        throw new ArgumentException(SR.BerConverterNotMatch);
+                    }
+                    tag = (uint)(int)value[valueCount];
+                    tagIsSet = true;
+                    // It will set the tag on Windows and only check the tag on Unix.
+                    error = BerPal.PrintTag(berElement, new string(fmt, 1), tag);
 
+                    // increase the value count
                     valueCount++;
                 }
                 else
@@ -423,7 +463,7 @@ namespace System.DirectoryServices.Protocols
             return decodeResult;
         }
 
-        private static int EncodingByteArrayHelper(SafeBerHandle berElement, byte[] tempValue, char fmt)
+        private static int EncodingByteArrayHelper(SafeBerHandle berElement, byte[] tempValue, char fmt, nuint tag)
         {
             int error = 0;
 
@@ -433,12 +473,12 @@ namespace System.DirectoryServices.Protocols
                 IntPtr tmp = Marshal.AllocHGlobal(tempValue.Length);
                 Marshal.Copy(tempValue, 0, tmp, tempValue.Length);
                 HGlobalMemHandle memHandle = new HGlobalMemHandle(tmp);
-                error = BerPal.PrintByteArray(berElement, new string(fmt, 1), memHandle, tempValue.Length);
+                error = BerPal.PrintByteArray(berElement, new string(fmt, 1), memHandle, (uint)tempValue.Length, tag);
             }
             else
             {
                 HGlobalMemHandle memHandle = new HGlobalMemHandle(HGlobalMemHandle._dummyPointer);
-                error = BerPal.PrintByteArray(berElement, new string(fmt, 1), memHandle, 0);
+                error = BerPal.PrintByteArray(berElement, new string(fmt, 1), memHandle, 0, tag);
             }
 
             return error;
@@ -479,7 +519,7 @@ namespace System.DirectoryServices.Protocols
             return byteArray;
         }
 
-        private static int EncodingMultiByteArrayHelper(SafeBerHandle berElement, byte[][] tempValue, char fmt)
+        private static int EncodingMultiByteArrayHelper(SafeBerHandle berElement, byte[][] tempValue, char fmt, nuint tag)
         {
             IntPtr berValArray = IntPtr.Zero;
             IntPtr tempPtr = IntPtr.Zero;
@@ -521,7 +561,7 @@ namespace System.DirectoryServices.Protocols
                     Marshal.WriteIntPtr(tempPtr, IntPtr.Zero);
                 }
 
-                error = BerPal.PrintBerArray(berElement, new string(fmt, 1), berValArray);
+                error = BerPal.PrintBerArray(berElement, new string(fmt, 1), berValArray, tag);
             }
             finally
             {
index 6391870..d270430 100644 (file)
@@ -8,7 +8,6 @@ using Xunit;
 namespace System.DirectoryServices.Protocols.Tests
 {
     [ConditionalClass(typeof(DirectoryServicesTestHelpers), nameof(DirectoryServicesTestHelpers.IsWindowsOrLibLdapIsInstalled))]
-    [ActiveIssue("https://github.com/dotnet/runtime/issues/49105", typeof(PlatformDetection), nameof(PlatformDetection.IsMacOsAppleSilicon))]
     public class AsqRequestControlTests
     {
         [Fact]
index 4a474ec..b0a47ba 100644 (file)
@@ -9,7 +9,6 @@ using Xunit;
 
 namespace System.DirectoryServices.Protocols.Tests
 {
-    [ActiveIssue("https://github.com/dotnet/runtime/issues/49105", typeof(PlatformDetection), nameof(PlatformDetection.IsMacOsAppleSilicon))]
     public class BerConversionExceptionTests
     {
         [Fact]
index d636a88..ba92d33 100644 (file)
@@ -9,7 +9,6 @@ using Xunit;
 namespace System.DirectoryServices.Protocols.Tests
 {
     [ConditionalClass(typeof(DirectoryServicesTestHelpers), nameof(DirectoryServicesTestHelpers.IsWindowsOrLibLdapIsInstalled))]
-    [ActiveIssue("https://github.com/dotnet/runtime/issues/49105", typeof(PlatformDetection), nameof(PlatformDetection.IsMacOsAppleSilicon))]
     public class BerConverterTests
     {
         public static IEnumerable<object[]> Encode_TestData()
@@ -30,6 +29,10 @@ namespace System.DirectoryServices.Protocols.Tests
             yield return new object[] { "[]", new object[] { "a" }, (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) ? new byte[] { 49, 132, 0, 0, 0, 0 } : new byte[] { 49, 0 } };
             yield return new object[] { "n", new object[] { "a" }, new byte[] { 5, 0 } };
 
+            yield return new object[] { "e", new object[] { 128 }, new byte[] { 10, 2, 0, 128 } };
+            yield return new object[] { "te", new object[] { 128, 0 }, new byte[] { 128, 1, 0 } };
+            yield return new object[] { "tet", new object[] { 128, 0, 133 }, new byte[] { 128, 1, 0 } };
+
             yield return new object[] { "tetie", new object[] { 128, 0, 133, 2, 3 }, new byte[] { 128, 1, 0, 133, 1, 2, 10, 1, 3 } };
             yield return new object[] { "{tetie}", new object[] { 128, 0, 133, 2, 3 }, (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) ? new byte[] { 48, 132, 0, 0, 0, 9, 128, 1, 0, 133, 1, 2, 10, 1, 3 } : new byte[] { 48, 9, 128, 1, 0, 133, 1, 2, 10, 1, 3 } };
 
@@ -37,10 +40,16 @@ namespace System.DirectoryServices.Protocols.Tests
             yield return new object[] { "{bb}", new object[] { true, false }, (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) ? new byte[] { 48, 132, 0, 0, 0, 6, 1, 1, 255, 1, 1, 0 } : new byte[] { 48, 6, 1, 1, 255, 1, 1, 0 } };
 
             yield return new object[] { "ssss", new object[] { null, "", "abc", "\0" }, new byte[] { 4, 0, 4, 0, 4, 3, 97, 98, 99, 4, 1, 0 } };
+
+            yield return new object[] { "o", new object[] { null },  new byte[] { 4, 0} };
+            yield return new object[] { "X", new object[] { new byte[] { 0, 1, 2, 255 } }, (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) ? new byte[] { 3, 4, 0, 1, 2, 255 } : new byte[] { 3, 2, 4, 0 } };
             yield return new object[] { "oXo", new object[] { null, new byte[] { 0, 1, 2, 255 }, new byte[0] }, (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) ? new byte[] { 4, 0, 3, 4, 0, 1, 2, 255, 4, 0 } : new byte[] { 4, 0, 3, 2, 4, 0, 4, 0 } };
             yield return new object[] { "vv", new object[] { null, new string[] { "abc", "", null } }, new byte[] { 4, 3, 97, 98, 99, 4, 0, 4, 0 } };
             yield return new object[] { "{vv}", new object[] { null, new string[] { "abc", "", null } }, (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) ? new byte[] { 48, 132, 0, 0, 0, 9, 4, 3, 97, 98, 99, 4, 0, 4, 0 } : new byte[] { 48, 9, 4, 3, 97, 98, 99, 4, 0, 4, 0 } };
-            yield return new object[] { "VVVV", new object[] { null, new byte[][] { new byte[] { 0, 1, 2, 3 }, null }, new byte[][] { new byte[0] }, new byte[0][] }, new byte[] { 4, 4, 0, 1, 2, 3, 4, 0, 4, 0 } };
+            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+            {
+                yield return new object[] { "VVVV", new object[] { null, new byte[][] { new byte[] { 0, 1, 2, 3 }, null }, new byte[][] { new byte[0] }, new byte[0][] }, new byte[] { 4, 4, 0, 1, 2, 3, 4, 0, 4, 0 } };
+            }
         }
 
         [Theory]
@@ -117,6 +126,7 @@ namespace System.DirectoryServices.Protocols.Tests
         {
             yield return new object[] { "{}", new byte[] { 48, 0, 0, 0, 0, 0 }, new object[0] };
             yield return new object[] { "{a}", new byte[] { 48, 132, 0, 0, 0, 5, 4, 3, 97, 98, 99 }, new object[] { "abc" } };
+            yield return new object[] { "{i}", new byte[] { 48, 132, 0, 0, 0, 3, 2, 1, 10 }, new object[] { 10 } };
             yield return new object[] { "{ie}", new byte[] { 48, 132, 0, 0, 0, 6, 1, 1, 255, 1, 1, 0 }, new object[] { -1, 0 } };
             yield return new object[] { "{bb}", new byte[] { 48, 132, 0, 0, 0, 6, 1, 1, 255, 1, 1, 0 }, new object[] { true, false } };
             yield return new object[] { "{OO}", new byte[] { 48, 132, 0, 0, 0, 6, 1, 1, 255, 1, 1, 0 }, new object[] { new byte[] { 255 }, new byte[] { 0 } } };
index 847f482..da6bcfb 100644 (file)
@@ -8,7 +8,6 @@ using Xunit;
 namespace System.DirectoryServices.Protocols.Tests
 {
     [ConditionalClass(typeof(DirectoryServicesTestHelpers), nameof(DirectoryServicesTestHelpers.IsWindowsOrLibLdapIsInstalled))]
-    [ActiveIssue("https://github.com/dotnet/runtime/issues/49105", typeof(PlatformDetection), nameof(PlatformDetection.IsMacOsAppleSilicon))]
     public class DirSyncRequestControlTests
     {
         [Fact]
index 4f79e81..32d2b36 100644 (file)
@@ -5,7 +5,6 @@ using Xunit;
 
 namespace System.DirectoryServices.Protocols.Tests
 {
-    [ActiveIssue("https://github.com/dotnet/runtime/issues/49105", typeof(PlatformDetection), nameof(PlatformDetection.IsMacOsAppleSilicon))]
     public class DirectoryControlTests
     {
         [Theory]
index 1329fa8..00d56e1 100644 (file)
@@ -10,7 +10,6 @@ using Xunit;
 
 namespace System.DirectoryServices.Protocols.Tests
 {
-    [ActiveIssue("https://github.com/dotnet/runtime/issues/49105", typeof(PlatformDetection), nameof(PlatformDetection.IsMacOsAppleSilicon))]
     public partial class DirectoryServicesProtocolsTests
     {
         internal static bool IsLdapConfigurationExist => LdapConfiguration.Configuration != null;
index a7c5715..284d916 100644 (file)
@@ -8,7 +8,6 @@ using Xunit;
 namespace System.DirectoryServices.Protocols.Tests
 {
     [ConditionalClass(typeof(DirectoryServicesTestHelpers), nameof(DirectoryServicesTestHelpers.IsWindowsOrLibLdapIsInstalled))]
-    [ActiveIssue("https://github.com/dotnet/runtime/issues/49105", typeof(PlatformDetection), nameof(PlatformDetection.IsMacOsAppleSilicon))]
     public class ExtendedDNControlTests
     {
         [Fact]
index e6f10e4..537874c 100644 (file)
@@ -8,7 +8,6 @@ using Xunit;
 namespace System.DirectoryServices.Protocols.Tests
 {
     [ConditionalClass(typeof(DirectoryServicesTestHelpers), nameof(DirectoryServicesTestHelpers.IsWindowsOrLibLdapIsInstalled))]
-    [ActiveIssue("https://github.com/dotnet/runtime/issues/49105", typeof(PlatformDetection), nameof(PlatformDetection.IsMacOsAppleSilicon))]
     public class PageResultRequestControlTests
     {
         [Fact]
index 033865e..b1ddaa9 100644 (file)
@@ -9,7 +9,6 @@ using Xunit;
 namespace System.DirectoryServices.Protocols.Tests
 {
     [ConditionalClass(typeof(DirectoryServicesTestHelpers), nameof(DirectoryServicesTestHelpers.IsWindowsOrLibLdapIsInstalled))]
-    [ActiveIssue("https://github.com/dotnet/runtime/issues/49105", typeof(PlatformDetection), nameof(PlatformDetection.IsMacOsAppleSilicon))]
     public class QuotaControlTests
     {
         [Fact]
index c173904..2a30d7d 100644 (file)
@@ -8,7 +8,6 @@ using Xunit;
 namespace System.DirectoryServices.Protocols.Tests
 {
     [ConditionalClass(typeof(DirectoryServicesTestHelpers), nameof(DirectoryServicesTestHelpers.IsWindowsOrLibLdapIsInstalled))]
-    [ActiveIssue("https://github.com/dotnet/runtime/issues/49105", typeof(PlatformDetection), nameof(PlatformDetection.IsMacOsAppleSilicon))]
     public class SearchOptionsControlTests
     {
         [Fact]
index 47ceca0..6ec7955 100644 (file)
@@ -8,7 +8,6 @@ using Xunit;
 namespace System.DirectoryServices.Protocols.Tests
 {
     [ConditionalClass(typeof(DirectoryServicesTestHelpers), nameof(DirectoryServicesTestHelpers.IsWindowsOrLibLdapIsInstalled))]
-    [ActiveIssue("https://github.com/dotnet/runtime/issues/49105", typeof(PlatformDetection), nameof(PlatformDetection.IsMacOsAppleSilicon))]
     public class SecurityDescriptorFlagControlTests
     {
         [Fact]
index c6edf34..5e7469d 100644 (file)
@@ -8,7 +8,6 @@ using Xunit;
 namespace System.DirectoryServices.Protocols.Tests
 {
     [ConditionalClass(typeof(DirectoryServicesTestHelpers), nameof(DirectoryServicesTestHelpers.IsWindowsOrLibLdapIsInstalled))]
-    [ActiveIssue("https://github.com/dotnet/runtime/issues/49105", typeof(PlatformDetection), nameof(PlatformDetection.IsMacOsAppleSilicon))]
     public class VerifyNameControlTests
     {
         [Fact]
index 4ea87e1..a259bd1 100644 (file)
@@ -8,7 +8,6 @@ using Xunit;
 namespace System.DirectoryServices.Protocols.Tests
 {
     [ConditionalClass(typeof(DirectoryServicesTestHelpers), nameof(DirectoryServicesTestHelpers.IsWindowsOrLibLdapIsInstalled))]
-    [ActiveIssue("https://github.com/dotnet/runtime/issues/49105", typeof(PlatformDetection), nameof(PlatformDetection.IsMacOsAppleSilicon))]
     public class VlvRequestControlTests
     {
         [Fact]