94 lines
2.4 KiB
Dart
94 lines
2.4 KiB
Dart
|
import 'dart:math';
|
||
|
|
||
|
import 'package:quiver/core.dart';
|
||
|
|
||
|
/// Represents an individual range, with an optional start index and optional end index.
|
||
|
class RangeHeaderItem implements Comparable<RangeHeaderItem> {
|
||
|
/// The index at which this chunk begins. May be `-1`.
|
||
|
final int start;
|
||
|
|
||
|
/// The index at which this chunk ends. May be `-1`.
|
||
|
final int end;
|
||
|
|
||
|
const RangeHeaderItem([this.start = -1, this.end = -1]);
|
||
|
|
||
|
/// Joins two items together into the largest possible range.
|
||
|
RangeHeaderItem consolidate(RangeHeaderItem other) {
|
||
|
if (!(other.overlaps(this))) {
|
||
|
throw ArgumentError('The two ranges do not overlap.');
|
||
|
}
|
||
|
return RangeHeaderItem(min(start, other.start), max(end, other.end));
|
||
|
}
|
||
|
|
||
|
@override
|
||
|
int get hashCode => hash2(start, end);
|
||
|
|
||
|
@override
|
||
|
bool operator ==(other) =>
|
||
|
other is RangeHeaderItem && other.start == start && other.end == end;
|
||
|
|
||
|
bool overlaps(RangeHeaderItem other) {
|
||
|
if (other.start <= start) {
|
||
|
return other.end < start;
|
||
|
} else if (other.start > start) {
|
||
|
return other.start <= end;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
@override
|
||
|
int compareTo(RangeHeaderItem other) {
|
||
|
if (other.start > start) {
|
||
|
return -1;
|
||
|
} else if (other.start == start) {
|
||
|
if (other.end == end) {
|
||
|
return 0;
|
||
|
} else if (other.end < end) {
|
||
|
return 1;
|
||
|
} else {
|
||
|
return -1;
|
||
|
}
|
||
|
} else if (other.start < start) {
|
||
|
return 1;
|
||
|
} else {
|
||
|
return -1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@override
|
||
|
String toString() {
|
||
|
if (start > -1 && end > -1) {
|
||
|
return '$start-$end';
|
||
|
} else if (start > -1) {
|
||
|
return '$start-';
|
||
|
} else {
|
||
|
return '-$end';
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// Creates a representation of this instance suitable for a `Content-Range` header.
|
||
|
///
|
||
|
/// This can only be used if the user request only one range. If not, send a
|
||
|
/// `multipart/byteranges` response.
|
||
|
///
|
||
|
/// Please adhere to the standard!!!
|
||
|
/// http://httpwg.org/specs/rfc7233.html
|
||
|
|
||
|
String toContentRange([int? totalSize]) {
|
||
|
// var maxIndex = totalSize != null ? (totalSize - 1).toString() : '*';
|
||
|
var s = start > -1 ? start : 0;
|
||
|
|
||
|
if (end == -1) {
|
||
|
if (totalSize == null) {
|
||
|
throw UnsupportedError(
|
||
|
'If the end of this range is unknown, `totalSize` must not be null.');
|
||
|
} else {
|
||
|
// if (end == totalSize - 1) {
|
||
|
return '$s-${totalSize - 1}/$totalSize';
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return '$s-$end/$totalSize';
|
||
|
}
|
||
|
}
|