/
decode.js
167 lines (145 loc) · 5.9 KB
/
decode.js
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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
"use strict";
module.exports = decode;
var Enum = require("./enum"),
Reader = require("./reader"),
types = require("./types"),
util = require("./util");
/**
* General purpose message decoder.
* @param {Reader|Uint8Array} readerOrBuffer Reader or buffer to decode from
* @param {number} [length] Length of the message, if known beforehand
* @returns {Message} Populated runtime message
* @this Type
* @property {GenerateDecoder} generate Generates a type specific decoder
*/
function decode(readerOrBuffer, length) {
/* eslint-disable no-invalid-this, block-scoped-var, no-redeclare */
var fields = this.getFieldsById(),
reader = readerOrBuffer instanceof Reader ? readerOrBuffer : Reader.create(readerOrBuffer),
limit = length === undefined ? reader.len : reader.pos + length,
message = new (this.getCtor())();
while (reader.pos < limit) {
var tag = reader.uint32(),
wireType = tag & 7;
// End group
if (wireType === 4)
break;
var field = fields[tag >>> 3].resolve(),
type = field.resolvedType instanceof Enum ? "uint32" : field.type;
// Known fields
if (field) {
// Map fields
if (field.map) {
var keyType = field.resolvedKeyType /* only valid is enum */ ? "uint32" : field.keyType;
reader.skip();
reader.pos++; // assumes id 1
if (message[field.name] === util.emptyObject)
message[field.name] = {};
var key = reader[keyType]();
if (typeof key === "object")
key = util.longToHash(key);
reader.pos++; // assumes id 2
message[field.name][key] = types.basic[type] === undefined
? field.resolvedType.decode(reader, reader.uint32())
: reader[type]();
// Repeated fields
} else if (field.repeated) {
var values = message[field.name] && message[field.name].length ? message[field.name] : message[field.name] = [];
// Packed
if (field.packed && types.packed[type] !== undefined && wireType === 2) {
var plimit = reader.uint32() + reader.pos;
while (reader.pos < plimit)
values.push(reader[type]());
// Non-packed
} else if (types.basic[type] === undefined)
values.push(field.resolvedType.decode(reader, field.resolvedType.group ? undefined : reader.uint32()));
else
values.push(reader[type]());
// Non-repeated
} else if (types.basic[type] === undefined)
message[field.name] = field.resolvedType.decode(reader, field.resolvedType.group ? undefined : reader.uint32());
else
message[field.name] = reader[type]();
// Unknown fields
} else
reader.skipType(wireType);
}
return message;
/* eslint-enable no-invalid-this, block-scoped-var, no-redeclare */
}
/**
* Generates a decoder specific to the specified message type.
* @typedef GenerateDecoder
* @type {function}
* @param {Type} mtype Message type
* @returns {Codegen} Codegen instance
*/
/**/
decode.generate = function generate(mtype) {
/* eslint-disable no-unexpected-multiline */
var fields = mtype.getFieldsArray();
var gen = util.codegen("r", "l")
("r instanceof Reader||(r=Reader.create(r))")
("var c=l===undefined?r.len:r.pos+l,m=new(this.getCtor())")
("while(r.pos<c){")
("var t=r.int32()");
if (mtype.group) gen
("if((t&7)===4)")
("break");
gen
("switch(t>>>3){");
for (var i = 0; i < fields.length; ++i) {
var field = fields[i].resolve(),
type = field.resolvedType instanceof Enum ? "uint32" : field.type,
prop = util.safeProp(field.name);
gen
("case %d:", field.id);
// Map fields
if (field.map) {
var keyType = field.resolvedKeyType /* only valid is enum */ ? "uint32" : field.keyType;
gen
("r.skip().pos++")
("if(m%s===util.emptyObject)", prop)
("m%s={}", prop)
("var k=r.%s()", keyType)
("if(typeof k===\"object\")")
("k=util.longToHash(k)")
("r.pos++");
if (types.basic[type] === undefined) gen
("m%s[k]=types[%d].decode(r,r.uint32())", prop, i);
else gen
("m%s[k]=r.%s()", prop, type);
// Repeated fields
} else if (field.repeated) { gen
("m%s&&m%s.length?m%s:m%s=[]", prop, prop, prop, prop);
// Packed
if (field.packed && types.packed[type] !== undefined) gen
("if((t&7)===2){")
("var e=r.uint32()+r.pos")
("while(r.pos<e)")
("m%s.push(r.%s())", prop, type)
("}else");
// Non-packed
if (types.basic[type] === undefined) gen(field.resolvedType.group
? "m%s.push(types[%d].decode(r))"
: "m%s.push(types[%d].decode(r,r.uint32()))", prop, i);
else gen
("m%s.push(r.%s())", prop, type);
// Non-repeated
} else if (types.basic[type] === undefined) gen(field.resolvedType.group
? "m%s=types[%d].decode(r)"
: "m%s=types[%d].decode(r,r.uint32())", prop, i);
else gen
("m%s=r.%s()", prop, type);
gen
("break");
// Unknown fields
} return gen
("default:")
("r.skipType(t&7)")
("break")
("}")
("}")
("return m");
/* eslint-enable no-unexpected-multiline */
};