/// <summary>
        /// Constructor to initialize a object given the ValueType and a list of
        /// string, each representing one value in string form.
        /// </summary>
        /// <param name="valType">Type of the claim value</param>
        /// <param name="vals"></param>
        public ClaimValue(ClaimValueType valueType, string value)
        {
            this.valueType = valueType;

            //
            // Attempt to get the raw values so that any ill-formated value would throw an exception
            // and get rejected right away.
            //
            rawValues = GetRawValues(valueType, value, out valueCount);
        }
        public virtual int _GetUniqueIdentifier()
        {
            var hashCode = 399326290;

            hashCode = hashCode * -1521134295 + (Id?.GetHashCode() ?? 0);
            hashCode = hashCode * -1521134295 + (ClaimType?.GetHashCode() ?? 0);
            hashCode = hashCode * -1521134295 + (ClaimValue?.GetHashCode() ?? 0);
            hashCode = hashCode * -1521134295 + (ClaimValueType?.GetHashCode() ?? 0);
            hashCode = hashCode * -1521134295 + (Issuer?.GetHashCode() ?? 0);
            hashCode = hashCode * -1521134295 + (OriginalIssuer?.GetHashCode() ?? 0);
            return(hashCode);
        }
        /// <summary>
        /// Get the native (unmanaged) representation of the list of values in
        /// the Microsoft.Samples.Cbac.ClaimValue instance.
        /// </summary>
        /// <param name="valueType">Type of the value(s) in this instance</param>
        /// <param name="values">The collection of values each in string format</param>
        /// <param name="valueCount">Return the count of unique values</param>
        /// <returns>SafeHGlobalHandle that references a native (unmanaged)
        /// pointer to values that can be used in the 'Values' field of the
        /// CLAIM_SECURITY_ATTRIBUTE_V1 structure.</returns>
        static SafeHGlobalHandle GetRawValues(ClaimValueType valueType,
                                              string value,
                                              out ULONG valueCount)
        {
            const int BASE_OCTAL   = 8;
            const int BASE_DECIMAL = 10;
            const int BASE_HEX     = 16;

            const string OCTAL_REGEX = "^[+]?0[0-7]+$";
            const string HEX_REGEX   = "^[+]?0[xX][0-9a-fA-f]+$";

            var stringValues = new StringCollection();

            valueCount = 1;

            //
            // As part of formulating the values in native format, verify that
            // we do not have duplicates. AuthzModifyClaims fails with
            // ERROR_ALREADY_EXISTS when duplicate values are specified.
            //
            switch (valueType)
            {
            case ClaimValueType.Integer:
            {
                long[] values = new long[1];
                try
                {
                    int fromBase = BASE_DECIMAL;

                    if (Regex.Match(value, OCTAL_REGEX).Success)
                    {
                        fromBase = BASE_OCTAL;
                    }
                    else if (Regex.Match(value, HEX_REGEX).Success)
                    {
                        fromBase = BASE_HEX;
                    }

                    values[0] = Convert.ToInt64(value, fromBase);

                    return(SafeHGlobalHandle.AllocHGlobal(values));
                }
                catch (Exception e)
                {
                    throw new BadValueException(string.Format(CultureInfo.CurrentCulture,
                                                              "Invalid Int value - {0}",
                                                              value),
                                                e);
                }
            }

            case ClaimValueType.Boolean:
            {
                long[] values = new long[1];

                try
                {
                    string strValue = value;

                    if (string.Compare(value, "true", StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        strValue = "1";
                    }
                    else if (string.Compare(value, "false", StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        strValue = "0";
                    }

                    values[0] = Convert.ToInt64(strValue, CultureInfo.InvariantCulture);

                    return(SafeHGlobalHandle.AllocHGlobal(values));
                }
                catch (Exception e)
                {
                    throw new BadValueException(string.Format(CultureInfo.CurrentCulture,
                                                              "Invalid Boolean value - {0}",
                                                              value), e);
                }
            }

            case ClaimValueType.MultiValuedString:
            {
                char[]       bracketChars = { '[', ']' };
                const string CSV_REGEX    = @"# Parse CVS line. Capture next value in named group: 'val'
                                                   \s*                      # Ignore leading whitespace.
                                                   (?:                      # Group of value alternatives.
                                                       ""                   # Either a double quoted string,
                                                       (?<val>              # Capture contents between quotes.
                                                       [^""]*(""""[^""]*)*  # Zero or more non-quotes, allowing 
                                                       )                    # doubled "" quotes within string.
                                                       ""\s*                # Ignore whitespace following quote.
                                                   |  (?<val>[^,]+)         # Or... One or more non-commas.
                                                   )                        # End value alternatives group.
                                                   (?:,|$)                  # Match end is comma or EOS";

                if (!value.StartsWith("[", StringComparison.Ordinal) ||
                    !value.EndsWith("]", StringComparison.Ordinal))
                {
                    throw new BadValueException(string.Format(CultureInfo.CurrentCulture,
                                                              "Multi-valued String is not enclosed within square brackets: '{0}'",
                                                              value));
                }

                MatchCollection splitResult = Regex.Matches(value.Trim(bracketChars),
                                                            CSV_REGEX,
                                                            RegexOptions.Multiline
                                                            | RegexOptions.IgnorePatternWhitespace);

                if (splitResult.Count == 0)
                {
                    throw new BadValueException(string.Format(CultureInfo.CurrentCulture,
                                                              "Ill-formed Multi-valued String: '{0}'",
                                                              value));
                }
                else
                {
                    foreach (Match literal in splitResult)
                    {
                        string strVal = literal.Groups["val"].Value.Trim();
                        if (!stringValues.Contains(strVal))
                        {
                            if (!string.IsNullOrEmpty(strVal))
                            {
                                stringValues.Add(strVal);
                            }
                        }
                        else
                        {
                            Helper.ReportDuplicateValue(ClaimValueType.MultiValuedString,
                                                        literal.Groups["val"].Value);
                        }
                    }
                }

                if (stringValues.Count == 0)
                {
                    throw new BadValueException(string.Format(CultureInfo.CurrentCulture,
                                                              "No non-empty strings in : '{0}'",
                                                              value));
                }

                valueCount = (ULONG)stringValues.Count;

                goto case ClaimValueType.String;
            }

            case ClaimValueType.String:
            {
                if (stringValues.Count == 0)
                {
                    string strVal = value.Trim();

                    if (!string.IsNullOrEmpty(strVal))
                    {
                        stringValues.Add(strVal);
                    }
                }

                var strings = new List <SafeHGlobalHandle>(stringValues.Count);

                foreach (var stringValue in stringValues)
                {
                    SafeHGlobalHandle nativeString = SafeHGlobalHandle.AllocHGlobal(stringValue);

                    strings.Add(nativeString);
                }

                SafeHGlobalHandle result = SafeHGlobalHandle.AllocHGlobal(
                    strings.Select(n => n.ToIntPtr())
                    .ToArray());

                //
                // Since the native (managed) representation is an array
                // of pointers to strings, ensure that these pointers
                // are being referenced in the uber SafeHGlobalHandle
                // that represents the array of pointers.
                //
                result.AddSubReference(strings);

                valueCount = (ULONG)strings.Count;

                return(result);
            }

            default:
            {
                valueCount = 0;
                break;
            }
            }

            return(SafeHGlobalHandle.InvalidHandle);
        }