You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					163 lines
				
				2.8 KiB
			
		
		
			
		
	
	
					163 lines
				
				2.8 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								/*!
							 | 
						||
| 
								 | 
							
								 * 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
							 | 
						||
| 
								 | 
							
								}
							 |