Ejemplo n.º 1
0
        private static Version?ParseVersion(ReadOnlySpan <char> input, bool throwOnFailure)
        {
            // Find the separator between major and minor.  It must exist.
            int majorEnd = input.IndexOf('.');

            if (majorEnd < 0)
            {
                if (throwOnFailure)
                {
                    throw new ArgumentException(SR.Arg_VersionString, nameof(input));
                }
                return(null);
            }

            // Find the ends of the optional minor and build portions.
            // We musn't have any separators after build.
            int buildEnd = -1;
            int minorEnd = input.Slice(majorEnd + 1).IndexOf('.');

            if (minorEnd != -1)
            {
                minorEnd += (majorEnd + 1);
                buildEnd  = input.Slice(minorEnd + 1).IndexOf('.');
                if (buildEnd != -1)
                {
                    buildEnd += (minorEnd + 1);
                    if (input.Slice(buildEnd + 1).Contains('.'))
                    {
                        if (throwOnFailure)
                        {
                            throw new ArgumentException(SR.Arg_VersionString, nameof(input));
                        }
                        return(null);
                    }
                }
            }

            int minor, build, revision;

            // Parse the major version
            if (!TryParseComponent(input.Slice(0, majorEnd), nameof(input), throwOnFailure, out int major))
            {
                return(null);
            }

            if (minorEnd != -1)
            {
                // If there's more than a major and minor, parse the minor, too.
                if (!TryParseComponent(input.Slice(majorEnd + 1, minorEnd - majorEnd - 1), nameof(input), throwOnFailure, out minor))
                {
                    return(null);
                }

                if (buildEnd != -1)
                {
                    // major.minor.build.revision
                    return
                        (TryParseComponent(input.Slice(minorEnd + 1, buildEnd - minorEnd - 1), nameof(build), throwOnFailure, out build) &&
                         TryParseComponent(input.Slice(buildEnd + 1), nameof(revision), throwOnFailure, out revision) ?
                         new Version(major, minor, build, revision) :
                         null);
                }
                else
                {
                    // major.minor.build
                    return(TryParseComponent(input.Slice(minorEnd + 1), nameof(build), throwOnFailure, out build) ?
                           new Version(major, minor, build) :
                           null);
                }
            }
            else
            {
                // major.minor
                return(TryParseComponent(input.Slice(majorEnd + 1), nameof(input), throwOnFailure, out minor) ?
                       new Version(major, minor) :
                       null);
            }
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Determines whether the beginning of the <paramref name="span"/> matches the specified <paramref name="value"/> when compared using the specified <paramref name="comparisonType"/> option.
        /// </summary>
        /// <param name="span">The source span.</param>
        /// <param name="value">The sequence to compare to the beginning of the source span.</param>
        /// <param name="comparisonType">One of the enumeration values that determines how the <paramref name="span"/> and <paramref name="value"/> are compared.</param>
        public static bool StartsWith(this ReadOnlySpan <char> span, ReadOnlySpan <char> value, StringComparison comparisonType)
        {
            string.CheckStringComparison(comparisonType);

            if (value.Length == 0)
            {
                return(true);
            }

            if (comparisonType >= StringComparison.Ordinal || GlobalizationMode.Invariant)
            {
                if (string.GetCaseCompareOfComparisonCulture(comparisonType) == CompareOptions.None)
                {
                    return(span.StartsWith(value));
                }

                return((span.Length >= value.Length) ? (CompareInfo.CompareOrdinalIgnoreCase(span.Slice(0, value.Length), value) == 0) : false);
            }

            if (span.Length == 0)
            {
                return(false);
            }

            return((comparisonType >= StringComparison.InvariantCulture) ?
                   CompareInfo.Invariant.IsPrefix(span, value, string.GetCaseCompareOfComparisonCulture(comparisonType)) :
                   CultureInfo.CurrentCulture.CompareInfo.IsPrefix(span, value, string.GetCaseCompareOfComparisonCulture(comparisonType)));
        }
Ejemplo n.º 3
0
        //
        // Parse
        //
        //  Convert this IPv6 address into a sequence of 8 16-bit numbers
        //
        // Inputs:
        //  <member>    Name
        //      The validated IPv6 address
        //
        // Outputs:
        //  <member>    numbers
        //      Array filled in with the numbers in the IPv6 groups
        //
        //  <member>    PrefixLength
        //      Set to the number after the prefix separator (/) if found
        //
        // Assumes:
        //  <Name> has been validated and contains only hex digits in groups of
        //  16-bit numbers, the characters ':' and '/', and a possible IPv4
        //  address
        //
        // Throws:
        //  Nothing
        //

        internal static void Parse(ReadOnlySpan <char> address, Span <ushort> numbers, int start, ref string?scopeId)
        {
            int  number          = 0;
            int  index           = 0;
            int  compressorIndex = -1;
            bool numberIsValid   = true;

            //This used to be a class instance member but have not been used so far
            int PrefixLength = 0;

            if (address[start] == '[')
            {
                ++start;
            }

            for (int i = start; i < address.Length && address[i] != ']';)
            {
                switch (address[i])
                {
                case '%':
                    if (numberIsValid)
                    {
                        numbers[index++] = (ushort)number;
                        numberIsValid    = false;
                    }

                    start = i;
                    for (++i; i < address.Length && address[i] != ']' && address[i] != '/'; ++i)
                    {
                    }
                    scopeId = new string(address.Slice(start, i - start));
                    // ignore prefix if any
                    for (; i < address.Length && address[i] != ']'; ++i)
                    {
                    }
                    break;

                case ':':
                    numbers[index++] = (ushort)number;
                    number           = 0;
                    ++i;
                    if (address[i] == ':')
                    {
                        compressorIndex = index;
                        ++i;
                    }
                    else if ((compressorIndex < 0) && (index < 6))
                    {
                        // no point checking for IPv4 address if we don't
                        // have a compressor or we haven't seen 6 16-bit
                        // numbers yet
                        break;
                    }

                    // check to see if the upcoming number is really an IPv4
                    // address. If it is, convert it to 2 ushort numbers
                    for (int j = i; j < address.Length &&
                         (address[j] != ']') &&
                         (address[j] != ':') &&
                         (address[j] != '%') &&
                         (address[j] != '/') &&
                         (j < i + 4); ++j)
                    {
                        if (address[j] == '.')
                        {
                            // we have an IPv4 address. Find the end of it:
                            // we know that since we have a valid IPv6
                            // address, the only things that will terminate
                            // the IPv4 address are the prefix delimiter '/'
                            // or the end-of-string (which we conveniently
                            // delimited with ']')
                            while (j < address.Length && (address[j] != ']') && (address[j] != '/') && (address[j] != '%'))
                            {
                                ++j;
                            }
                            number           = IPv4AddressHelper.ParseHostNumber(address, i, j);
                            numbers[index++] = (ushort)(number >> 16);
                            numbers[index++] = (ushort)number;
                            i = j;

                            // set this to avoid adding another number to
                            // the array if there's a prefix
                            number        = 0;
                            numberIsValid = false;
                            break;
                        }
                    }
                    break;

                case '/':
                    if (numberIsValid)
                    {
                        numbers[index++] = (ushort)number;
                        numberIsValid    = false;
                    }

                    // since we have a valid IPv6 address string, the prefix
                    // length is the last token in the string
                    for (++i; address[i] != ']'; ++i)
                    {
                        PrefixLength = PrefixLength * 10 + (address[i] - '0');
                    }
                    break;

                default:
                    number = number * 16 + Uri.FromHex(address[i++]);
                    break;
                }
            }

            // add number to the array if its not the prefix length or part of
            // an IPv4 address that's already been handled
            if (numberIsValid)
            {
                numbers[index++] = (ushort)number;
            }

            // if we had a compressor sequence ("::") then we need to expand the
            // numbers array
            if (compressorIndex > 0)
            {
                int toIndex   = NumberOfLabels - 1;
                int fromIndex = index - 1;

                // if fromIndex and toIndex are the same, it means that "zero bits" are already in the correct place
                // it happens for leading and trailing compression
                if (fromIndex != toIndex)
                {
                    for (int i = index - compressorIndex; i > 0; --i)
                    {
                        numbers[toIndex--]   = numbers[fromIndex];
                        numbers[fromIndex--] = 0;
                    }
                }
            }
        }
        public static unsafe IDictionary GetEnvironmentVariables()
        {
            // Format for GetEnvironmentStrings is:
            //     [=HiddenVar=value\0]* [Variable=value\0]* \0
            // See the description of Environment Blocks in MSDN's CreateProcess
            // page (null-terminated array of null-terminated strings). Note
            // the =HiddenVar's aren't always at the beginning.

            // Copy strings out, parsing into pairs and inserting into the table.
            // The first few environment variable entries start with an '='.
            // The current working directory of every drive (except for those drives
            // you haven't cd'ed into in your DOS window) are stored in the
            // environment block (as =C:=pwd) and the program's exit code is
            // as well (=ExitCode=00000000).

            char *stringPtr = Interop.Kernel32.GetEnvironmentStringsW();

            if (stringPtr == null)
            {
                throw new OutOfMemoryException();
            }

            try
            {
                var results = new Hashtable();

                char *currentPtr = stringPtr;
                while (true)
                {
                    ReadOnlySpan <char> variable = MemoryMarshal.CreateReadOnlySpanFromNullTerminated(currentPtr);
                    if (variable.IsEmpty)
                    {
                        break;
                    }

                    // Find the = separating the key and value. We skip entries that begin with =.  We also skip entries that don't
                    // have =, which can happen on some older OSes when the environment block gets corrupted.
                    int i = variable.IndexOf('=');
                    if (i > 0)
                    {
                        // Add the key and value.
                        string key   = new string(variable.Slice(0, i));
                        string value = new string(variable.Slice(i + 1));
                        try
                        {
                            // Add may throw if the environment block was corrupted leading to duplicate entries.
                            // We allow such throws and eat them (rather than proactively checking for duplication)
                            // to provide a non-fatal notification about the corruption.
                            results.Add(key, value);
                        }
                        catch (ArgumentException) { }
                    }

                    // Move to the end of this variable, after its terminator.
                    currentPtr += variable.Length + 1;
                }

                return(results);
            }
            finally
            {
                Interop.BOOL success = Interop.Kernel32.FreeEnvironmentStringsW(stringPtr);
                Debug.Assert(success != Interop.BOOL.FALSE);
            }
        }
 /// <summary>
 /// Removes all trailing occurrences of a specified element from the span.
 /// </summary>
 /// <param name="span">The source span from which the element is removed.</param>
 /// <param name="trimElement">The specified element to look for and remove.</param>
 public static ReadOnlySpan <T> TrimEnd <T>(this ReadOnlySpan <T> span, T trimElement) where T : IEquatable <T>
 => span.Slice(0, ClampEnd(span, 0, trimElement));
 /// <summary>
 /// Removes all leading occurrences of a specified element from the span.
 /// </summary>
 /// <param name="span">The source span from which the element is removed.</param>
 /// <param name="trimElement">The specified element to look for and remove.</param>
 public static ReadOnlySpan <T> TrimStart <T>(this ReadOnlySpan <T> span, T trimElement) where T : IEquatable <T>
 => span.Slice(ClampStart(span, trimElement));