/** * (The MIT License) * * Copyright (c) 2012-2014 TJ Holowaychuk * Copyright (c) 2015-2016 Douglas Christopher Wilson ({ index, end : range.end, start: range.start, }); /** * Map function to remove index value from ranges. * @private */ const mapWithoutIndex = (range: RangeI): { end: number; start: number } => ({ end : range.end, start: range.start, }); /** * Sort function to sort ranges by index. * @private */ const sortByRangeIndex = (a: any, b: any): number => a.index - b.index; /** * Sort function to sort ranges by start position. * @private */ const sortByRangeStart = (a: RangeI, b: RangeI): number => a.start - b.start; /** * Combine overlapping & adjacent ranges. * @private */ const combineRanges = (ranges: RangesI): RangesI => { const ordered = ranges.map(mapWithIndex).sort(sortByRangeStart); let j = 0; for (let i = 1; i < ordered.length; i++) { const range = ordered[i]; const current = ordered[j]; // Next range if (range.start > current.end + 1) { ordered[++j] = range; } else if (range.end > current.end) { // Extend range current.end = range.end; current.index = Math.min(current.index, range.index); } } // Trim ordered array ordered.length = j + 1; // Generate combined range const combined: RangesI = ordered .sort(sortByRangeIndex) .map(mapWithoutIndex) as any; // Copy ranges type combined.type = ranges.type; return combined; }; /** * Parse "Range" header `str` relative to the given file `size`. * * @public */ const rangeParser = ( size: number, str: string, combine = false, ): RangesI | RESULT => { const index = str.indexOf("="); if (index === -1) return -2; // Split the range string const arr = str.slice(index + 1).split(","); const ranges: RangesI = [] as any; // Add ranges type ranges.type = str.slice(0, index); // Parse all ranges // eslint-disable-next-line @typescript-eslint/prefer-for-of for (let i = 0; i < arr.length; i++) { const range = arr[i].split("-"); let start = parseInt(range[0]); let end = parseInt(range[1]); // -nnn if (isNaN(start)) { start = size - end; end = size - 1; // Nnn- } else if (isNaN(end)) { end = size - 1; } // Limit last-byte-pos to current length if (end > size - 1) end = size - 1; // Invalid or unsatisifiable if (isNaN(start) || isNaN(end) || start > end || start < 0) continue; // Add range ranges.push({ start, end, }); } // Unsatisifiable if (ranges.length < 1) return -1; return combine ? combineRanges(ranges) : ranges; }; export default rangeParser; export interface RangesI extends Array { type: string; } export interface RangeI { end: number; start: number; } export const enum RESULT { INVALID = -2, UNSATISIFIABLE = -1, }