public static string Get_Location(DataConsumer <char> Stream) { return(Stream.AsMemory().Slice((int)Stream.LongPosition, 32).ToString()); }
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); }
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); }