git ssb

0+

cel / pull-git-remote-helper



Tree: ef07dd5bda4ebb6d6e9f63ebf742df7e23029f5f

Files: ef07dd5bda4ebb6d6e9f63ebf742df7e23029f5f / pack.js

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

Built with git-ssb-web