git ssb

0+

cel / pull-git-remote-helper



Tree: f60f57ddecf31964b98f5147c7ee02faa6c871fc

Files: f60f57ddecf31964b98f5147c7ee02faa6c871fc / pack.js

4653 bytesRaw
1var buffered = require('pull-buffered')
2var pull = require('pull-stream')
3var toPull = require('stream-to-pull-stream')
4var Inflate = require('pako/lib/inflate').Inflate
5var createHash = require('./util').createHash
6
7exports.decode = decodePack
8
9var objectTypes = [
10 'none', 'commit', 'tree', 'blob',
11 'tag', 'unused', 'ofs-delta', 'ref-delta'
12]
13
14function error(cb) {
15 return function (err) {
16 cb(err || true)
17 }
18}
19
20function inflateBytes(read) {
21 var inflate = new Inflate()
22 var ended, dataOut
23
24 inflate.onData = function (data) {
25 dataOut = new Buffer(data)
26 // console.error('inflated data', data.length)
27 }
28
29 inflate.onEnd = function (status) {
30 ended = (status === 0) ? true : new Error(inflate.msg)
31 // console.error('inflated end', status, ended)
32 }
33
34 return function (abort, cb) {
35 if (ended) return cb(ended)
36 read(abort, function next(end, data) {
37 if (end === true) {
38 end = null
39 data = []
40 }
41 if (ended = end) return cb(end)
42 if (data.length > 1) return cb(new Error('got more than one byte'))
43 dataOut = null
44 inflate.push(data, end === true)
45 if (dataOut)
46 cb(null, dataOut)
47 else if (ended)
48 cb(ended)
49 else
50 read(null, next)
51 })
52 }
53}
54
55function decodePack(onEnd, read) {
56 if (read === undefined)
57 return decodePack.bind(this, onEnd)
58
59 var ended
60 var numObjects = -1
61 var checksum = createHash('sha1')
62 var b = buffered(read)
63 // TODO: optimize to pass through buffers to checksum
64 var readByte = checksum(b.chunks(1))
65 var readWord = checksum(b.chunks(4))
66 var readChecksum = b.chunks(20)
67 var expectChecksum = true
68 var opts = {
69 verbosity: 2
70 }
71
72 function readHeader(cb) {
73 readWord(null, function (end, header) {
74 if (ended = end) return cb(end)
75 if (!header.equals(header, new Buffer('PACK')))
76 read(new Error('Invalid packfile header'), error(cb))
77 else
78 readVersion(cb)
79 })
80 }
81
82 function readVersion(cb) {
83 readWord(null, function (end, word) {
84 if (ended = end) return cb(end)
85 var version = word.readUInt32BE()
86 if (version < 2 || version > 3)
87 read(new Error('Invalid packfile version ' + version), error(cb))
88 else
89 readNumObjects(cb)
90 })
91 }
92
93 function readNumObjects(cb) {
94 readWord(null, function (end, word) {
95 if (ended = end) return cb(end)
96 numObjects = word.readUInt32BE()
97 if (opts.verbosity >= 1)
98 console.error(numObjects + ' objects')
99 readObject(null, cb)
100 })
101 }
102
103 function readVarInt(cb) {
104 var type, value, shift
105 // https://codewords.recurse.com/images/three/varint.svg
106 readByte(null, function (end, buf) {
107 if (ended = end) return cb(end)
108 var firstByte = buf[0]
109 type = objectTypes[(firstByte >> 4) & 7]
110 value = firstByte & 15
111 // console.error('byte1', firstByte, firstByte.toString(2), value, value.toString(2))
112 shift = 4
113 checkByte(firstByte)
114 })
115
116 function checkByte(byte) {
117 if (byte & 0x80)
118 readByte(null, gotByte)
119 else
120 cb(null, type, value)
121 }
122
123 function gotByte(end, buf) {
124 if (ended = end) return cb(end)
125 var byte = buf[0]
126 value += (byte & 0x7f) << shift
127 shift += 7
128 // console.error('byte', byte, byte.toString(2), value, value.toString(2))
129 checkByte(byte)
130 }
131 }
132
133 function getObject(cb) {
134 readVarInt(function (end, type, length) {
135 if (opts.verbosity >= 2)
136 console.error('read var int', end, type, length)
137 numObjects--
138 if (end === true && expectChecksum)
139 onEnd(new Error('Missing checksum'))
140 if (ended = end) return cb(end)
141 // TODO: verify that the inflated data is the correct length
142 cb(null, type, length, inflateBytes(readByte))
143 })
144 }
145
146 function readTrailer(cb) {
147 // read the checksum before it updates to include the trailer
148 var expected = checksum.digest()
149 readChecksum(null, function (end, value) {
150 cb(true)
151 if (end === true && expectChecksum)
152 onEnd(new Error('Missing checksum'))
153 if (!value.equals(expected)) {
154 onEnd(new Error('Checksum mismatch: ' +
155 expected.hexSlice() + ' != ' + value.hexSlice()))
156 } else {
157 if (opts.verbosity >= 2)
158 console.error('checksum ok', expected.hexSlice())
159 onEnd(null)
160 }
161 })
162 }
163
164 function readObject(abort, cb) {
165 if (ended) cb(ended)
166 else if (abort) read(abort)
167 else if (numObjects < 0) readHeader(cb)
168 else if (numObjects > 0) getObject(cb)
169 else if (expectChecksum) readTrailer(cb)
170 }
171
172 return readObject
173}
174

Built with git-ssb-web