1 |
|
2 |
|
3 | exports.Encoder = Encoder;
|
4 |
|
5 | var BufferLite = require("./buffer-lite");
|
6 | var extencoders = require("./ext").encoders;
|
7 | var ExtBuffer = require("./ext-buffer").ExtBuffer;
|
8 |
|
9 | var BUFFER_LENGTH = 2048;
|
10 | var NO_ASSERT = true;
|
11 | var IS_BUFFER_SHIM = ("TYPED_ARRAY_SUPPORT" in Buffer);
|
12 | var NO_TYPED_ARRAY = IS_BUFFER_SHIM && !Buffer.TYPED_ARRAY_SUPPORT;
|
13 | var FUNCTION_HAS_NAME = Encoder.name;
|
14 | var IS_ARRAY = Array.isArray || isArray;
|
15 |
|
16 | function Encoder(opts) {
|
17 | if (!(this instanceof Encoder)) return new Encoder(opts);
|
18 | if (opts && opts.push) this.push = opts.push.bind(opts);
|
19 | }
|
20 |
|
21 | Encoder.prototype.encode = function(chunk, encoding, callback) {
|
22 | if (!this.buffer) this.flush();
|
23 | encode(this, chunk);
|
24 | this.flush();
|
25 | if (callback) callback();
|
26 | };
|
27 |
|
28 | Encoder.prototype.flush = function(length) {
|
29 | if (this.offset) {
|
30 | this.push(this.buffer.slice(0, this.offset));
|
31 | this.buffer = null;
|
32 | }
|
33 | if (length < BUFFER_LENGTH) length = 0;
|
34 | if (!this.buffer || length) {
|
35 | this.buffer = new Buffer(length || BUFFER_LENGTH);
|
36 | }
|
37 | this.offset = 0;
|
38 | };
|
39 |
|
40 | Encoder.prototype.write = function(buffer) {
|
41 | var end = this.offset + buffer.length;
|
42 | if (end >= BUFFER_LENGTH) {
|
43 | this.flush();
|
44 | this.push(buffer);
|
45 | } else {
|
46 | buffer.copy(this.buffer, this.offset);
|
47 | this.offset = end;
|
48 | }
|
49 | };
|
50 |
|
51 | var constant = new Array(256);
|
52 | var token = new Array(256);
|
53 | init();
|
54 |
|
55 | function init() {
|
56 |
|
57 |
|
58 |
|
59 |
|
60 |
|
61 | for (var i = 0x00; i <= 0xFF; i++) {
|
62 | token[i] = constant[i] = write0(i);
|
63 | }
|
64 |
|
65 | if (NO_TYPED_ARRAY) {
|
66 | init_compatible();
|
67 | } else {
|
68 | init_optimized();
|
69 | }
|
70 | }
|
71 |
|
72 | function init_optimized() {
|
73 |
|
74 |
|
75 |
|
76 | token[0xc4] = write1(0xc4);
|
77 | token[0xc5] = write2(0xc5);
|
78 | token[0xc6] = write4(0xc6);
|
79 |
|
80 |
|
81 |
|
82 |
|
83 | token[0xc7] = write1(0xc7);
|
84 | token[0xc8] = write2(0xc8);
|
85 | token[0xc9] = write4(0xc9);
|
86 |
|
87 |
|
88 |
|
89 | token[0xca] = writeN(0xca, 4, Buffer.prototype.writeFloatBE);
|
90 | token[0xcb] = writeN(0xcb, 8, Buffer.prototype.writeDoubleBE);
|
91 |
|
92 |
|
93 |
|
94 |
|
95 |
|
96 | token[0xcc] = write1(0xcc);
|
97 | token[0xcd] = write2(0xcd);
|
98 | token[0xce] = write4(0xce);
|
99 | token[0xcf] = writeN(0xcf, 8, BufferLite.writeUint64BE);
|
100 |
|
101 |
|
102 |
|
103 |
|
104 |
|
105 | token[0xd0] = write1(0xd0);
|
106 | token[0xd1] = write2(0xd1);
|
107 | token[0xd2] = write4(0xd2);
|
108 | token[0xd3] = writeN(0xd3, 8, BufferLite.writeUint64BE);
|
109 |
|
110 |
|
111 |
|
112 |
|
113 |
|
114 |
|
115 |
|
116 |
|
117 | token[0xd9] = write1(0xd9);
|
118 | token[0xda] = write2(0xda);
|
119 | token[0xdb] = write4(0xdb);
|
120 | token[0xdc] = write2(0xdc);
|
121 | token[0xdd] = write4(0xdd);
|
122 | token[0xde] = write2(0xde);
|
123 | token[0xdf] = write4(0xdf);
|
124 | }
|
125 |
|
126 | function init_compatible() {
|
127 | token[0xc4] = writeN(0xc4, 1, Buffer.prototype.writeUInt8);
|
128 | token[0xc5] = writeN(0xc5, 2, Buffer.prototype.writeUInt16BE);
|
129 | token[0xc6] = writeN(0xc6, 4, Buffer.prototype.writeUInt32BE);
|
130 | token[0xc7] = writeN(0xc7, 1, Buffer.prototype.writeUInt8);
|
131 | token[0xc8] = writeN(0xc8, 2, Buffer.prototype.writeUInt16BE);
|
132 | token[0xc9] = writeN(0xc9, 4, Buffer.prototype.writeUInt32BE);
|
133 | token[0xca] = writeN(0xca, 4, Buffer.prototype.writeFloatBE);
|
134 | token[0xcb] = writeN(0xcb, 8, Buffer.prototype.writeDoubleBE);
|
135 | token[0xcc] = writeN(0xcc, 1, Buffer.prototype.writeUInt8);
|
136 | token[0xcd] = writeN(0xcd, 2, Buffer.prototype.writeUInt16BE);
|
137 | token[0xce] = writeN(0xce, 4, Buffer.prototype.writeUInt32BE);
|
138 | token[0xcf] = writeN(0xcf, 8, BufferLite.writeUint64BE);
|
139 | token[0xd0] = writeN(0xd0, 1, Buffer.prototype.writeInt8);
|
140 | token[0xd1] = writeN(0xd1, 2, Buffer.prototype.writeInt16BE);
|
141 | token[0xd2] = writeN(0xd2, 4, Buffer.prototype.writeInt32BE);
|
142 | token[0xd3] = writeN(0xd3, 8, BufferLite.writeUint64BE);
|
143 | token[0xd9] = writeN(0xd9, 1, Buffer.prototype.writeUInt8);
|
144 | token[0xda] = writeN(0xda, 2, Buffer.prototype.writeUInt16BE);
|
145 | token[0xdb] = writeN(0xdb, 4, Buffer.prototype.writeUInt32BE);
|
146 | token[0xdc] = writeN(0xdc, 2, Buffer.prototype.writeUInt16BE);
|
147 | token[0xdd] = writeN(0xdd, 4, Buffer.prototype.writeUInt32BE);
|
148 | token[0xde] = writeN(0xde, 2, Buffer.prototype.writeUInt16BE);
|
149 | token[0xdf] = writeN(0xdf, 4, Buffer.prototype.writeUInt32BE);
|
150 | }
|
151 |
|
152 | function write0(type) {
|
153 | return function(encoder) {
|
154 | var end = encoder.offset + 1;
|
155 | if (end >= BUFFER_LENGTH) encoder.flush();
|
156 | encoder.buffer[encoder.offset++] = type;
|
157 | };
|
158 | }
|
159 |
|
160 | function write1(type) {
|
161 | return function(encoder, value) {
|
162 | var end = encoder.offset + 2;
|
163 | if (end >= BUFFER_LENGTH) encoder.flush();
|
164 | var buffer = encoder.buffer;
|
165 | var offset = encoder.offset;
|
166 | buffer[offset++] = type;
|
167 | buffer[offset++] = value;
|
168 | encoder.offset = offset;
|
169 | };
|
170 | }
|
171 |
|
172 | function write2(type) {
|
173 | return function(encoder, value) {
|
174 | var end = encoder.offset + 3;
|
175 | if (end >= BUFFER_LENGTH) encoder.flush();
|
176 | var buffer = encoder.buffer;
|
177 | var offset = encoder.offset;
|
178 | buffer[offset++] = type;
|
179 | buffer[offset++] = value >>> 8;
|
180 | buffer[offset++] = value;
|
181 | encoder.offset = offset;
|
182 | };
|
183 | }
|
184 |
|
185 | function write4(type) {
|
186 | return function(encoder, value) {
|
187 | var end = encoder.offset + 5;
|
188 | if (end >= BUFFER_LENGTH) encoder.flush();
|
189 | var buffer = encoder.buffer;
|
190 | var offset = encoder.offset;
|
191 | buffer[offset++] = type;
|
192 | buffer[offset++] = value >>> 24;
|
193 | buffer[offset++] = value >>> 16;
|
194 | buffer[offset++] = value >>> 8;
|
195 | buffer[offset++] = value;
|
196 | encoder.offset = offset;
|
197 | };
|
198 | }
|
199 |
|
200 | function writeN(type, len, method) {
|
201 | return function(encoder, value) {
|
202 | var end = encoder.offset + 1 + len;
|
203 | if (end >= BUFFER_LENGTH) encoder.flush();
|
204 | encoder.buffer[encoder.offset++] = type;
|
205 | method.call(encoder.buffer, value, encoder.offset, NO_ASSERT);
|
206 | encoder.offset += len;
|
207 | };
|
208 | }
|
209 |
|
210 | var types = {
|
211 | "string": string,
|
212 | "number": number,
|
213 | "object": object,
|
214 | "boolean": bool,
|
215 | "undefined": token[0xc0]
|
216 | };
|
217 |
|
218 | function encode(encoder, value) {
|
219 | var func = types[typeof value] || NA;
|
220 | func(encoder, value);
|
221 | }
|
222 |
|
223 | function NA(encoder, value) {
|
224 | throw new Error("Unknown supported type \"" + (typeof value) + "\": " + value);
|
225 | }
|
226 |
|
227 | function bool(encoder, value) {
|
228 |
|
229 |
|
230 | var type = value ? 0xc3 : 0xc2;
|
231 | token[type](encoder, value);
|
232 | }
|
233 |
|
234 | function number(encoder, value) {
|
235 | var ivalue = value | 0;
|
236 | var type;
|
237 | if (value !== ivalue) {
|
238 |
|
239 | type = 0xcb;
|
240 | token[type](encoder, value);
|
241 | return;
|
242 | } else if (-0x20 <= ivalue && ivalue <= 0x7F) {
|
243 |
|
244 |
|
245 | type = ivalue & 0xFF;
|
246 | } else if (0 <= ivalue) {
|
247 |
|
248 |
|
249 |
|
250 |
|
251 | type = (ivalue <= 0xFF) ? 0xcc : (ivalue <= 0xFFFF) ? 0xcd : 0xce;
|
252 | } else {
|
253 |
|
254 |
|
255 |
|
256 |
|
257 | type = (-0x80 <= ivalue) ? 0xd0 : (-0x8000 <= ivalue) ? 0xd1 : 0xd2;
|
258 | }
|
259 | token[type](encoder, ivalue);
|
260 | }
|
261 |
|
262 | function string(encoder, value) {
|
263 |
|
264 |
|
265 |
|
266 |
|
267 |
|
268 |
|
269 | var length = value.length;
|
270 | var maxsize = 5 + length * 3;
|
271 | if (encoder.offset + maxsize > BUFFER_LENGTH) {
|
272 | encoder.flush(maxsize);
|
273 | }
|
274 |
|
275 |
|
276 | var expected = (length < 32) ? 1 : (length <= 0xFF) ? 2 : (length <= 0xFFFF) ? 3 : 5;
|
277 |
|
278 |
|
279 | var start = encoder.offset + expected;
|
280 |
|
281 |
|
282 | length = BufferLite.writeString.call(encoder.buffer, value, start);
|
283 |
|
284 |
|
285 | var actual = (length < 32) ? 1 : (length <= 0xFF) ? 2 : (length <= 0xFFFF) ? 3 : 5;
|
286 |
|
287 |
|
288 | if (expected !== actual) {
|
289 | var targetStart = encoder.offset + actual;
|
290 | var end = start + length;
|
291 | if (IS_BUFFER_SHIM) {
|
292 | BufferLite.copy.call(encoder.buffer, encoder.buffer, targetStart, start, end);
|
293 | } else {
|
294 | encoder.buffer.copy(encoder.buffer, targetStart, start, end);
|
295 | }
|
296 | }
|
297 |
|
298 |
|
299 | var type = (actual === 1) ? (0xa0 + length) : (actual <= 3) ? 0xd7 + actual : 0xdb;
|
300 | token[type](encoder, length);
|
301 |
|
302 |
|
303 | encoder.offset += length;
|
304 | }
|
305 |
|
306 | var extmap = [];
|
307 | extmap[1] = 0xd4;
|
308 | extmap[2] = 0xd5;
|
309 | extmap[4] = 0xd6;
|
310 | extmap[8] = 0xd7;
|
311 | extmap[16] = 0xd8;
|
312 |
|
313 | function object(encoder, value) {
|
314 | var type;
|
315 | var length;
|
316 | if (value === null) {
|
317 |
|
318 | type = 0xc0;
|
319 | token[type](encoder, value);
|
320 | } else if (IS_ARRAY(value)) {
|
321 |
|
322 |
|
323 |
|
324 | length = value.length;
|
325 | type = (length < 16) ? (0x90 + length) : (length <= 0xFFFF) ? 0xdc : 0xdd;
|
326 | token[type](encoder, length);
|
327 | for (var i = 0; i < length; i++) {
|
328 | encode(encoder, value[i]);
|
329 | }
|
330 | } else if (Buffer.isBuffer(value)) {
|
331 |
|
332 |
|
333 |
|
334 | length = value.length;
|
335 | type = (length < 0xFF) ? 0xc4 : (length <= 0xFFFF) ? 0xc5 : 0xc6;
|
336 | token[type](encoder, length);
|
337 | encoder.write(value);
|
338 | } else {
|
339 | var n = value.constructor && value.constructor.name;
|
340 | if (!n && !FUNCTION_HAS_NAME && value instanceof ExtBuffer) n = "ExtBuffer";
|
341 | var e = extencoders[n];
|
342 | if (e) {
|
343 |
|
344 |
|
345 |
|
346 |
|
347 |
|
348 |
|
349 |
|
350 |
|
351 | var etype = e.type(value);
|
352 | var buf = e.encode(value);
|
353 | length = buf.length;
|
354 | type = extmap[length] || ((length < 0xFF) ? 0xc7 : (length <= 0xFFFF) ? 0xc8 : 0xc9);
|
355 | token[type](encoder, length);
|
356 | constant[etype](encoder);
|
357 | encoder.write(buf);
|
358 | return;
|
359 | }
|
360 |
|
361 |
|
362 |
|
363 |
|
364 | var keys = Object.keys(value);
|
365 | length = keys.length;
|
366 | type = (length < 16) ? (0x80 + length) : (length <= 0xFFFF) ? 0xde : 0xdf;
|
367 | token[type](encoder, length);
|
368 | keys.forEach(function(key) {
|
369 | encode(encoder, key);
|
370 | encode(encoder, value[key]);
|
371 | });
|
372 | }
|
373 | }
|
374 |
|
375 | function isArray(array) {
|
376 | return "[object Array]" === Object.prototype.toString.call(array);
|
377 | }
|