Example #1
0
 public static string Get_Location(DataConsumer <char> Stream)
 {
     return(Stream.AsMemory().Slice((int)Stream.LongPosition, 32).ToString());
 }
Example #2
0
        public static bool Parse_FloatingPoint(DataConsumer <char> Stream, out double outValue)
        {/* Docs: https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#rules-for-parsing-floating-point-number-values */
            if (Stream is null)
            {
                throw new ArgumentNullException(nameof(Stream));
            }
            Contract.EndContractBlock();

            double value    = 1;
            double divisor  = 1;
            double exponent = 1;

            /* Skip ASCII whitespace */
            Stream.Consume_While(Is_Ascii_Whitespace);

            if (Stream.Next == EOF)
            {
                throw new DomSyntaxError();
            }

            switch (Stream.Next)
            {
            case CHAR_HYPHEN_MINUS:
            {
                value = divisor = -1;
                Stream.Consume();
            }
            break;

            case CHAR_PLUS_SIGN:
            {
                Stream.Consume();
            }
            break;
            }

            if (Stream.Next == EOF)
            {
                throw new DomSyntaxError();
            }

            /* 9) If the character indicated by position is a U+002E FULL STOP (.),
             * and that is not the last character in input,
             * and the character after the character indicated by position is an ASCII digit,
             * then set value to zero and jump to the step labeled fraction. */
            if (Stream.Next == CHAR_FULL_STOP && Stream.NextNext != EOF && Is_Ascii_Digit(Stream.NextNext))
            {
                value = 0;
            }
            else if (!Is_Ascii_Digit(Stream.Next))
            {
                outValue = double.NaN;
                return(false);
            }
            else
            {
                /* 11) Collect a sequence of code points that are ASCII digits from input given position, and interpret the resulting sequence as a base-ten integer. Multiply value by that integer. */
                Stream.Consume_While(Is_Ascii_Digit, out ReadOnlySpan <char> outDigits);
                value *= Digits_To_Base10(outDigits);//double.Parse(outDigits.ToString(), CultureInfo.InvariantCulture);
            }

            /* 12) If position is past the end of input, jump to the step labeled conversion. */
            if (Stream.Next != EOF)
            {
                /* 13) Fraction: If the character indicated by position is a U+002E FULL STOP (.), run these substeps: */
                if (Stream.Next == CHAR_FULL_STOP)
                {
                    Stream.Consume();
                    /* 2) If position is past the end of input, or if the character indicated by position is not an ASCII digit, U+0065 LATIN SMALL LETTER E (e), or U+0045 LATIN CAPITAL LETTER E (E), then jump to the step labeled conversion. */
                    if (Stream.Next != EOF && (Is_Ascii_Digit(Stream.Next) || Stream.Next == CHAR_E_LOWER || Stream.Next == CHAR_E_UPPER))
                    {
                        /* 3) If the character indicated by position is a U+0065 LATIN SMALL LETTER E character (e) or a U+0045 LATIN CAPITAL LETTER E character (E), skip the remainder of these substeps. */
                        if (Is_Ascii_Digit(Stream.Next))
                        {
                            while (Is_Ascii_Digit(Stream.Next))
                            {
                                /* 4) Fraction loop: Multiply divisor by ten. */
                                divisor *= 10;
                                /* 5) Add the value of the character indicated by position, interpreted as a base-ten digit (0..9) and divided by divisor, to value. */
                                double n = Ascii_Digit_To_Value(Stream.Next) / divisor;
                                value += n;
                                /* 6) Advance position to the next character. */
                                Stream.Consume();
                                /* 7) If position is past the end of input, then jump to the step labeled conversion. */

                                if (Stream.Next == EOF)
                                {
                                    break;
                                }
                            }
                        }
                    }
                }

                /* 14) If the character indicated by position is U+0065 (e) or a U+0045 (E), then: */
                if (Stream.Next == CHAR_E_LOWER || Stream.Next == CHAR_E_UPPER)
                {
                    Stream.Consume();
                    /* 2) If position is past the end of input, then jump to the step labeled conversion. */
                    /* 3) If the character indicated by position is a U+002D HYPHEN-MINUS character (-): */
                    if (Stream.Next == CHAR_HYPHEN_MINUS)
                    {
                        exponent = -1;
                        Stream.Consume();
                    }
                    else if (Stream.Next == CHAR_PLUS_SIGN)
                    {
                        Stream.Consume();
                    }

                    /* 4) If the character indicated by position is not an ASCII digit, then jump to the step labeled conversion. */
                    if (Is_Ascii_Digit(Stream.Next))
                    {
                        /* 5) Collect a sequence of code points that are ASCII digits from input given position, and interpret the resulting sequence as a base-ten integer. Multiply exponent by that integer. */
                        Stream.Consume_While(Is_Ascii_Digit, out ReadOnlySpan <char> outDigits);
                        exponent *= Digits_To_Base10(outDigits);//double.Parse(outDigits.ToString(), CultureInfo.InvariantCulture);
                        /* 6) Multiply value by ten raised to the exponentth power. */
                        value *= Math.Pow(10, exponent);
                    }
                }
            }

            /* 15) Conversion: Let S be the set of finite IEEE 754 double-precision floating-point values except −0, but with two special values added: 2^1024 and −2^1024. */

            /* 16) Let rounded-value be the number in S that is closest to value,
             * selecting the number with an even significand if there are two equally close values.
             * (The two special values 2^1024 and −2^1024 are considered to have even significands for this purpose.) */
            var roundedValue = value;

            if (roundedValue == -0D)
            {
                roundedValue = -roundedValue;
            }

            /* 17) If rounded-value is 2^1024 or −2^1024, return an error. */
            if (roundedValue == double.MinValue || roundedValue == double.MaxValue)
            {
                outValue = double.NaN;
                return(false);
            }
            /* 18) Return rounded-value. */
            outValue = roundedValue;
            return(true);
        }
Example #3
0
        public static byte[] Percent_Decode(ReadOnlyMemory <byte> input)
        {/* Docs: https://url.spec.whatwg.org/#percent-decode */
            DataConsumer <byte> Stream = new DataConsumer <byte>(input, byte.MinValue);
            /* Create a list of memory chunks that make up the final string */
            ulong newLength  = 0;
            ulong?chunkStart = null;
            ulong chunkCount = 0;
            var   chunks     = new LinkedList <Tuple <ReadOnlyMemory <byte>, byte?> >();

            while (!Stream.atEnd)
            {
                EFilterResult filterResult = EFilterResult.FILTER_ACCEPT;
                byte?         bytePoint    = null;

                if (Stream.Next == CHAR_PERCENT && Is_Ascii_Hex_Digit((char)Stream.NextNext) && Is_Ascii_Hex_Digit((char)Stream.NextNextNext))
                {
                    filterResult = EFilterResult.FILTER_SKIP;
                    uint low  = (uint)Ascii_Hex_To_Value((char)Stream.NextNext);
                    uint high = (uint)Ascii_Hex_To_Value((char)Stream.NextNextNext);
                    bytePoint = (byte)(low | (high >> 4));
                    Stream.Consume(2);
                    break;
                }

                /* When filter result:
                 * ACCEPT: Char should be included in chunk
                 * SKIP: Char should not be included in chunk, if at chunk-start shift chunk-start past char, otherwise end chunk
                 * REJECT: Char should not be included in chunk, current chunk ends
                 */
                bool end_chunk = false;
                switch (filterResult)
                {
                case EFilterResult.FILTER_ACCEPT:    // Char should be included in the chunk
                {
                    if (!chunkStart.HasValue)
                    {
                        chunkStart = Stream.LongPosition;                              /* Start new chunk (if one isnt started yet) */
                    }
                }
                break;

                case EFilterResult.FILTER_REJECT:    // Char should not be included in chunk, current chunk ends
                {
                    end_chunk = true;
                }
                break;

                case EFilterResult.FILTER_SKIP:    // Char should not be included in chunk, if at chunk-start shift chunk-start past char, otherwise end chunk
                {
                    if (!chunkStart.HasValue)
                    {
                        chunkStart = Stream.LongPosition + 1;        /* At chunk-start */
                    }
                    else
                    {
                        end_chunk = true;
                    }
                }
                break;
                }

                if (end_chunk || Stream.Remaining <= 1)
                {
                    if (!chunkStart.HasValue)
                    {
                        chunkStart = Stream.LongPosition;
                    }

                    /* Push new chunk to our list */
                    var chunkSize = Stream.LongPosition - chunkStart.Value;
                    var Mem       = Stream.AsMemory().Slice((int)chunkStart.Value, (int)chunkSize);
                    var chunk     = new Tuple <ReadOnlyMemory <byte>, byte?>(Mem, bytePoint);
                    chunks.AddLast(chunk);

                    chunkCount++;
                    chunkStart = null;
                    newLength += chunkSize;
                    /* If we actually decoded a byte then account for it in the newLength */
                    if (filterResult != EFilterResult.FILTER_ACCEPT)
                    {
                        newLength++;
                    }
                }

                Stream.Consume();
            }

            /* Compile the string */
            var           dataPtr = new byte[newLength];
            Memory <byte> data    = new Memory <byte>(dataPtr);

            ulong index = 0;

            foreach (var tpl in chunks)
            {
                var chunk = tpl.Item1;
                /* Copy chunk data */
                chunk.CopyTo(data.Slice((int)index));
                index += (ulong)chunk.Length;

                if (tpl.Item2.HasValue)
                {
                    data.Span[(int)index] = tpl.Item2.Value;
                    index++;
                }
            }

            return(dataPtr);
        }