index.js 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. /*!
  2. * range-parser
  3. * Copyright(c) 2012-2014 TJ Holowaychuk
  4. * Copyright(c) 2015-2016 Douglas Christopher Wilson
  5. * MIT Licensed
  6. */
  7. 'use strict'
  8. /**
  9. * Module exports.
  10. * @public
  11. */
  12. module.exports = rangeParser
  13. /**
  14. * Parse "Range" header `str` relative to the given file `size`.
  15. *
  16. * @param {Number} size
  17. * @param {String} str
  18. * @param {Object} [options]
  19. * @return {Array}
  20. * @public
  21. */
  22. function rangeParser (size, str, options) {
  23. if (typeof str !== 'string') {
  24. throw new TypeError('argument str must be a string')
  25. }
  26. var index = str.indexOf('=')
  27. if (index === -1) {
  28. return -2
  29. }
  30. // split the range string
  31. var arr = str.slice(index + 1).split(',')
  32. var ranges = []
  33. // add ranges type
  34. ranges.type = str.slice(0, index)
  35. // parse all ranges
  36. for (var i = 0; i < arr.length; i++) {
  37. var indexOf = arr[i].indexOf('-')
  38. if (indexOf === -1) {
  39. return -2
  40. }
  41. var startStr = arr[i].slice(0, indexOf).trim()
  42. var endStr = arr[i].slice(indexOf + 1).trim()
  43. var start = parsePos(startStr)
  44. var end = parsePos(endStr)
  45. if (startStr.length === 0) {
  46. start = size - end
  47. end = size - 1
  48. } else if (endStr.length === 0) {
  49. end = size - 1
  50. }
  51. // limit last-byte-pos to current length
  52. if (end > size - 1) {
  53. end = size - 1
  54. }
  55. if (isNaN(start) || isNaN(end)) {
  56. return -2
  57. }
  58. // invalid or unsatisifiable
  59. if (start > end || start < 0) {
  60. continue
  61. }
  62. // add range
  63. ranges.push({
  64. start: start,
  65. end: end
  66. })
  67. }
  68. if (ranges.length < 1) {
  69. // unsatisifiable
  70. return -1
  71. }
  72. return options && options.combine
  73. ? combineRanges(ranges)
  74. : ranges
  75. }
  76. /**
  77. * Parse string to integer.
  78. * @private
  79. */
  80. function parsePos (str) {
  81. if (/^\d+$/.test(str)) return Number(str)
  82. return NaN
  83. }
  84. /**
  85. * Combine overlapping & adjacent ranges.
  86. * @private
  87. */
  88. function combineRanges (ranges) {
  89. var ordered = ranges.map(mapWithIndex).sort(sortByRangeStart)
  90. for (var j = 0, i = 1; i < ordered.length; i++) {
  91. var range = ordered[i]
  92. var current = ordered[j]
  93. if (range.start > current.end + 1) {
  94. // next range
  95. ordered[++j] = range
  96. } else if (range.end > current.end) {
  97. // extend range
  98. current.end = range.end
  99. current.index = Math.min(current.index, range.index)
  100. }
  101. }
  102. // trim ordered array
  103. ordered.length = j + 1
  104. // generate combined range
  105. var combined = ordered.sort(sortByRangeIndex).map(mapWithoutIndex)
  106. // copy ranges type
  107. combined.type = ranges.type
  108. return combined
  109. }
  110. /**
  111. * Map function to add index value to ranges.
  112. * @private
  113. */
  114. function mapWithIndex (range, index) {
  115. return {
  116. start: range.start,
  117. end: range.end,
  118. index: index
  119. }
  120. }
  121. /**
  122. * Map function to remove index value from ranges.
  123. * @private
  124. */
  125. function mapWithoutIndex (range) {
  126. return {
  127. start: range.start,
  128. end: range.end
  129. }
  130. }
  131. /**
  132. * Sort function to sort ranges by index.
  133. * @private
  134. */
  135. function sortByRangeIndex (a, b) {
  136. return a.index - b.index
  137. }
  138. /**
  139. * Sort function to sort ranges by start position.
  140. * @private
  141. */
  142. function sortByRangeStart (a, b) {
  143. return a.start - b.start
  144. }