163 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			163 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
|  | /*! | ||
|  |  * range-parser | ||
|  |  * Copyright(c) 2012-2014 TJ Holowaychuk | ||
|  |  * Copyright(c) 2015-2016 Douglas Christopher Wilson | ||
|  |  * MIT Licensed | ||
|  |  */ | ||
|  | 
 | ||
|  | 'use strict' | ||
|  | 
 | ||
|  | /** | ||
|  |  * Module exports. | ||
|  |  * @public | ||
|  |  */ | ||
|  | 
 | ||
|  | module.exports = rangeParser | ||
|  | 
 | ||
|  | /** | ||
|  |  * Parse "Range" header `str` relative to the given file `size`. | ||
|  |  * | ||
|  |  * @param {Number} size | ||
|  |  * @param {String} str | ||
|  |  * @param {Object} [options] | ||
|  |  * @return {Array} | ||
|  |  * @public | ||
|  |  */ | ||
|  | 
 | ||
|  | function rangeParser (size, str, options) { | ||
|  |   if (typeof str !== 'string') { | ||
|  |     throw new TypeError('argument str must be a string') | ||
|  |   } | ||
|  | 
 | ||
|  |   var index = str.indexOf('=') | ||
|  | 
 | ||
|  |   if (index === -1) { | ||
|  |     return -2 | ||
|  |   } | ||
|  | 
 | ||
|  |   // split the range string
 | ||
|  |   var arr = str.slice(index + 1).split(',') | ||
|  |   var ranges = [] | ||
|  | 
 | ||
|  |   // add ranges type
 | ||
|  |   ranges.type = str.slice(0, index) | ||
|  | 
 | ||
|  |   // parse all ranges
 | ||
|  |   for (var i = 0; i < arr.length; i++) { | ||
|  |     var range = arr[i].split('-') | ||
|  |     var start = parseInt(range[0], 10) | ||
|  |     var end = parseInt(range[1], 10) | ||
|  | 
 | ||
|  |     // -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: start, | ||
|  |       end: end | ||
|  |     }) | ||
|  |   } | ||
|  | 
 | ||
|  |   if (ranges.length < 1) { | ||
|  |     // unsatisifiable
 | ||
|  |     return -1 | ||
|  |   } | ||
|  | 
 | ||
|  |   return options && options.combine | ||
|  |     ? combineRanges(ranges) | ||
|  |     : ranges | ||
|  | } | ||
|  | 
 | ||
|  | /** | ||
|  |  * Combine overlapping & adjacent ranges. | ||
|  |  * @private | ||
|  |  */ | ||
|  | 
 | ||
|  | function combineRanges (ranges) { | ||
|  |   var ordered = ranges.map(mapWithIndex).sort(sortByRangeStart) | ||
|  | 
 | ||
|  |   for (var j = 0, i = 1; i < ordered.length; i++) { | ||
|  |     var range = ordered[i] | ||
|  |     var current = ordered[j] | ||
|  | 
 | ||
|  |     if (range.start > current.end + 1) { | ||
|  |       // next range
 | ||
|  |       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
 | ||
|  |   var combined = ordered.sort(sortByRangeIndex).map(mapWithoutIndex) | ||
|  | 
 | ||
|  |   // copy ranges type
 | ||
|  |   combined.type = ranges.type | ||
|  | 
 | ||
|  |   return combined | ||
|  | } | ||
|  | 
 | ||
|  | /** | ||
|  |  * Map function to add index value to ranges. | ||
|  |  * @private | ||
|  |  */ | ||
|  | 
 | ||
|  | function mapWithIndex (range, index) { | ||
|  |   return { | ||
|  |     start: range.start, | ||
|  |     end: range.end, | ||
|  |     index: index | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | /** | ||
|  |  * Map function to remove index value from ranges. | ||
|  |  * @private | ||
|  |  */ | ||
|  | 
 | ||
|  | function mapWithoutIndex (range) { | ||
|  |   return { | ||
|  |     start: range.start, | ||
|  |     end: range.end | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | /** | ||
|  |  * Sort function to sort ranges by index. | ||
|  |  * @private | ||
|  |  */ | ||
|  | 
 | ||
|  | function sortByRangeIndex (a, b) { | ||
|  |   return a.index - b.index | ||
|  | } | ||
|  | 
 | ||
|  | /** | ||
|  |  * Sort function to sort ranges by start position. | ||
|  |  * @private | ||
|  |  */ | ||
|  | 
 | ||
|  | function sortByRangeStart (a, b) { | ||
|  |   return a.start - b.start | ||
|  | } |