summaryrefslogtreecommitdiff
path: root/deps/npm/node_modules/fstream/lib/file-reader.js
blob: b1f9861838ad7d064ac348b9ef7a146e638dbe18 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
// Basically just a wrapper around an fs.ReadStream

module.exports = FileReader

var fs = require("graceful-fs")
  , fstream = require("../fstream.js")
  , Reader = fstream.Reader
  , inherits = require("inherits")
  , mkdir = require("mkdirp")
  , Reader = require("./reader.js")
  , EOF = {EOF: true}
  , CLOSE = {CLOSE: true}

inherits(FileReader, Reader)

function FileReader (props) {
  // console.error("    FR create", props.path, props.size, new Error().stack)
  var me = this
  if (!(me instanceof FileReader)) throw new Error(
    "FileReader must be called as constructor.")

  // should already be established as a File type
  // XXX Todo: preserve hardlinks by tracking dev+inode+nlink,
  // with a HardLinkReader class.
  if (!((props.type === "Link" && props.Link) ||
        (props.type === "File" && props.File))) {
    throw new Error("Non-file type "+ props.type)
  }

  me._buffer = []
  me._bytesEmitted = 0
  Reader.call(me, props)
}

FileReader.prototype._getStream = function () {
  var me = this
    , stream = me._stream = fs.createReadStream(me._path, me.props)

  if (me.props.blksize) {
    stream.bufferSize = me.props.blksize
  }

  stream.on("open", me.emit.bind(me, "open"))

  stream.on("data", function (c) {
    // console.error("\t\t%d %s", c.length, me.basename)
    me._bytesEmitted += c.length
    // no point saving empty chunks
    if (!c.length) return
    else if (me._paused || me._buffer.length) {
      me._buffer.push(c)
      me._read()
    } else me.emit("data", c)
  })

  stream.on("end", function () {
    if (me._paused || me._buffer.length) {
      // console.error("FR Buffering End", me._path)
      me._buffer.push(EOF)
      me._read()
    } else {
      me.emit("end")
    }

    if (me._bytesEmitted !== me.props.size) {
      me.error("Didn't get expected byte count\n"+
               "expect: "+me.props.size + "\n" +
               "actual: "+me._bytesEmitted)
    }
  })

  stream.on("close", function () {
    if (me._paused || me._buffer.length) {
      // console.error("FR Buffering Close", me._path)
      me._buffer.push(CLOSE)
      me._read()
    } else {
      // console.error("FR close 1", me._path)
      me.emit("close")
    }
  })

  me._read()
}

FileReader.prototype._read = function () {
  var me = this
  // console.error("FR _read", me._path)
  if (me._paused) {
    // console.error("FR _read paused", me._path)
    return
  }

  if (!me._stream) {
    // console.error("FR _getStream calling", me._path)
    return me._getStream()
  }

  // clear out the buffer, if there is one.
  if (me._buffer.length) {
    // console.error("FR _read has buffer", me._buffer.length, me._path)
    var buf = me._buffer
    for (var i = 0, l = buf.length; i < l; i ++) {
      var c = buf[i]
      if (c === EOF) {
        // console.error("FR Read emitting buffered end", me._path)
        me.emit("end")
      } else if (c === CLOSE) {
        // console.error("FR Read emitting buffered close", me._path)
        me.emit("close")
      } else {
        // console.error("FR Read emitting buffered data", me._path)
        me.emit("data", c)
      }

      if (me._paused) {
        // console.error("FR Read Re-pausing at "+i, me._path)
        me._buffer = buf.slice(i)
        return
      }
    }
    me._buffer.length = 0
  }
  // console.error("FR _read done")
  // that's about all there is to it.
}

FileReader.prototype.pause = function (who) {
  var me = this
  // console.error("FR Pause", me._path)
  if (me._paused) return
  who = who || me
  me._paused = true
  if (me._stream) me._stream.pause()
  me.emit("pause", who)
}

FileReader.prototype.resume = function (who) {
  var me = this
  // console.error("FR Resume", me._path)
  if (!me._paused) return
  who = who || me
  me.emit("resume", who)
  me._paused = false
  if (me._stream) me._stream.resume()
  me._read()
}