Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(75)

Unified Diff: lib/src/hex/decoder.dart

Issue 1393003003: Add a percent-encoding converter. (Closed) Base URL: git@github.com:dart-lang/convert.git@master
Patch Set: Code review changes Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « lib/convert.dart ('k') | lib/src/hex/encoder.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: lib/src/hex/decoder.dart
diff --git a/lib/src/hex/decoder.dart b/lib/src/hex/decoder.dart
index 2ba169af364e84f036bfd2668619843ae103818e..efb0b0d41b957a744607916c728a4127f58a3ad5 100644
--- a/lib/src/hex/decoder.dart
+++ b/lib/src/hex/decoder.dart
@@ -7,7 +7,7 @@ library convert.hex.decoder;
import 'dart:convert';
import 'dart:typed_data';
-import 'package:charcode/ascii.dart';
+import '../utils.dart';
/// The canonical instance of [HexDecoder].
const hexDecoder = const HexDecoder._();
@@ -53,7 +53,7 @@ class _HexDecoderSink extends StringConversionSinkBase {
RangeError.checkValidRange(start, end, string.length);
if (start == end) {
- if (isLast) close();
+ if (isLast) _close(string, end);
return;
}
@@ -66,7 +66,7 @@ class _HexDecoderSink extends StringConversionSinkBase {
} else {
var hexPairs = (end - start - 1) ~/ 2;
bytes = new Uint8List(1 + hexPairs);
- bytes[0] = _lastDigit + _digitForCodeUnit(codeUnits, start);
+ bytes[0] = _lastDigit + digitForCodeUnit(codeUnits, start);
start++;
bytesStart = 1;
}
@@ -74,15 +74,20 @@ class _HexDecoderSink extends StringConversionSinkBase {
_lastDigit = _decode(codeUnits, start, end, bytes, bytesStart);
_sink.add(bytes);
- if (isLast) close();
+ if (isLast) _close(string, end);
}
ByteConversionSink asUtf8Sink(bool allowMalformed) =>
new _HexDecoderByteSink(_sink);
- void close() {
+ void close() => _close();
+
+ /// Like [close], but includes [string] and [index] in the [FormatException]
+ /// if one is thrown.
+ void _close([String string, int index]) {
if (_lastDigit != null) {
- throw new FormatException("Invalid input length, must be even.");
+ throw new FormatException(
+ "Input ended with incomplete encoded byte.", string, index);
}
_sink.close();
@@ -109,7 +114,7 @@ class _HexDecoderByteSink extends ByteConversionSinkBase {
RangeError.checkValidRange(start, end, chunk.length);
if (start == end) {
- if (isLast) close();
+ if (isLast) _close(chunk, end);
return;
}
@@ -121,7 +126,7 @@ class _HexDecoderByteSink extends ByteConversionSinkBase {
} else {
var hexPairs = (end - start - 1) ~/ 2;
bytes = new Uint8List(1 + hexPairs);
- bytes[0] = _lastDigit + _digitForCodeUnit(chunk, start);
+ bytes[0] = _lastDigit + digitForCodeUnit(chunk, start);
start++;
bytesStart = 1;
}
@@ -129,12 +134,17 @@ class _HexDecoderByteSink extends ByteConversionSinkBase {
_lastDigit = _decode(chunk, start, end, bytes, bytesStart);
_sink.add(bytes);
- if (isLast) close();
+ if (isLast) _close(chunk, end);
}
- void close() {
+ void close() => _close();
+
+ /// Like [close], but includes [chunk] and [index] in the [FormatException]
+ /// if one is thrown.
+ void _close([List<int> chunk, int index]) {
if (_lastDigit != null) {
- throw new FormatException("Invalid input length, must be even.");
+ throw new FormatException(
+ "Input ended with incomplete encoded byte.", chunk, index);
}
_sink.close();
@@ -152,42 +162,11 @@ int _decode(List<int> codeUnits, int sourceStart, int sourceEnd,
List<int> destination, int destinationStart) {
var destinationIndex = destinationStart;
for (var i = sourceStart; i < sourceEnd - 1; i += 2) {
- var firstDigit = _digitForCodeUnit(codeUnits, i);
- var secondDigit = _digitForCodeUnit(codeUnits, i + 1);
+ var firstDigit = digitForCodeUnit(codeUnits, i);
+ var secondDigit = digitForCodeUnit(codeUnits, i + 1);
destination[destinationIndex++] = 16 * firstDigit + secondDigit;
}
if ((sourceEnd - sourceStart).isEven) return null;
- return 16 * _digitForCodeUnit(codeUnits, sourceEnd - 1);
-}
-
-/// Returns the digit (0 through 15) corresponding to the hexadecimal code unit
-/// at index [i] in [codeUnits].
-///
-/// If the given code unit isn't valid hexadecimal, throws a [FormatException].
-int _digitForCodeUnit(List<int> codeUnits, int index) {
- // If the code unit is a numeral, get its value. XOR works because 0 in ASCII
- // is `0b110000` and the other numerals come after it in ascending order and
- // take up at most four bits.
- //
- // We check for digits first because it ensures there's only a single branch
- // for 10 out of 16 of the expected cases. We don't count the `digit >= 0`
- // check because branch prediction will always work on it for valid data.
- var codeUnit = codeUnits[index];
- var digit = $0 ^ codeUnit;
- if (digit <= 9) {
- if (digit >= 0) return digit;
- } else {
- // If the code unit is an uppercase letter, convert it to lowercase. This
- // works because uppercase letters in ASCII are exactly `0b100000 = 0x20`
- // less than lowercase letters, so if we ensure that that bit is 1 we ensure
- // that the letter is lowercase.
- var letter = 0x20 | codeUnit;
- if ($a <= letter && letter <= $f) return letter - $a + 10;
- }
-
- throw new FormatException(
- "Invalid hexadecimal code unit "
- "U+${codeUnit.toRadixString(16).padLeft(4, '0')}.",
- codeUnits, index);
+ return 16 * digitForCodeUnit(codeUnits, sourceEnd - 1);
}
« no previous file with comments | « lib/convert.dart ('k') | lib/src/hex/encoder.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698