-
Notifications
You must be signed in to change notification settings - Fork 66
Expand file tree
/
Copy pathparser.coffee
More file actions
92 lines (66 loc) · 2.77 KB
/
parser.coffee
File metadata and controls
92 lines (66 loc) · 2.77 KB
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
{EventEmitter} = require 'events'
Header = require './header'
fs = require 'fs'
class Parser extends EventEmitter
constructor: (@filename, @options = {}) ->
@encoding = @options?.encoding || 'utf-8'
@encoder = @options?.encoder || @getValueString
@readStreamOptions = @options?.readStreamOptions
parse: =>
@emit 'start', @
@header = new Header @filename, @encoding
@header.parse (err) =>
@emit 'header', @header
sequenceNumber = 0
loc = 0
bufLoc = @header.start
overflow = null
@paused = false
stream = fs.createReadStream @filename, @readStreamOptions
@readBuf = =>
if @paused
@emit 'paused'
return
while buffer = stream.read()
if overflow isnt null then buffer = Buffer.concat [overflow, buffer]
while loc < (@header.start + @header.numberOfRecords * @header.recordLength) && (bufLoc + @header.recordLength) <= buffer.length
@emit 'record', @parseRecord ++sequenceNumber, buffer.slice bufLoc, bufLoc += @header.recordLength
if bufLoc < buffer.length
overflow = buffer.slice bufLoc, buffer.length
loc += bufLoc
bufLoc = 0
else
overflow = null
bufLoc -= buffer.length
loc += buffer.length
return @
stream.on 'readable',@readBuf
stream.on 'end', () =>
@emit 'end'
return @
pause: =>
@paused = true
resume: =>
@paused = false
@emit 'resuming'
do @readBuf
parseRecord: (sequenceNumber, buffer) =>
record = {
'@sequenceNumber': sequenceNumber
'@deleted': (buffer.slice 0, 1)[0] isnt 32
}
loc = 1
for field in @header.fields
do (field) =>
record[field.name] = @parseField field, buffer.slice loc, loc += field.length
return record
getValueString: (buffer, encoding) =>
return (buffer.toString encoding).trim()
parseField: (field, buffer) =>
value = @encoder buffer, @encoding
if field.type is 'N'
value = parseInt value, 10
else if field.type is 'F'
value = if value == +value and value == (value | 0) then parseInt(value, 10) else parseFloat(value, 10)
return value
module.exports = Parser