Blame view

node_modules/needle/lib/decoder.js 1.52 KB
7820380e   “wangming”   1
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
  var iconv,
      inherits  = require('util').inherits,
      stream    = require('stream');
  
  var regex = /(?:charset|encoding)\s*=\s*['"]? *([\w\-]+)/i;
  
  inherits(StreamDecoder, stream.Transform);
  
  function StreamDecoder(charset) {
    if (!(this instanceof StreamDecoder))
      return new StreamDecoder(charset);
  
    stream.Transform.call(this, charset);
    this.charset = charset;
    this.parsed_chunk = false;
  }
  
  StreamDecoder.prototype._transform = function(chunk, encoding, done) {
    // try to get charset from chunk, but just once
    if (!this.parsed_chunk && (this.charset == 'utf-8' || this.charset == 'utf8')) {
      this.parsed_chunk = true;
  
      var matches = regex.exec(chunk.toString());
      if (matches) {
        var found = matches[1].toLowerCase().replace('utf8', 'utf-8'); // canonicalize;
        // set charset, but only if iconv can handle it
        if (iconv.encodingExists(found)) this.charset = found;
      }
    }
  
    if (this.charset == 'utf-8') { // no need to decode, just pass through
      this.push(chunk);
      return done();
    }
  
    // initialize stream decoder if not present
    var self = this;
    if (!this.decoder) {
      this.decoder = iconv.decodeStream(this.charset);
      this.decoder.on('data', function(decoded_chunk) {
        self.push(decoded_chunk);
      });
    };
  
    this.decoder.write(chunk);
    done();
  }
  
  module.exports = function(charset) {
    try {
      if (!iconv) iconv = require('iconv-lite');
    } catch(e) {
      /* iconv not found */
    }
  
    if (iconv)
      return new StreamDecoder(charset);
    else
      return new stream.PassThrough;
  }