OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 define("codec", function() { | |
Aaron Boodman
2013/11/18 18:34:48
According to the AMD web page, it is encouraged to
abarth-chromium
2013/11/18 19:13:20
Yep.
| |
6 | |
7 // Memory ------------------------------------------------------------------- | |
8 | |
9 function store8(memory, pointer, val) { | |
10 memory[pointer] = val; | |
11 } | |
12 | |
13 function store16(memory, pointer, val) { | |
14 memory[pointer + 0] = val >> 0; | |
15 memory[pointer + 1] = val >> 8; | |
16 } | |
17 | |
18 function store32(memory, pointer, val) { | |
19 memory[pointer + 0] = val >> 0; | |
20 memory[pointer + 1] = val >> 8; | |
21 memory[pointer + 2] = val >> 16; | |
22 memory[pointer + 3] = val >> 24; | |
23 } | |
24 | |
25 function store64(memory, pointer, val) { | |
26 store32(memory, pointer, val); | |
27 var hi = (val / 0x10000) | 0; | |
Aaron Boodman
2013/11/18 18:34:48
high :)
abarth-chromium
2013/11/18 19:13:20
Fixed. :)
| |
28 store32(memory, pointer + 4, hi); | |
29 } | |
30 | |
31 function load8(memory, pointer) { | |
32 return memory[pointer]; | |
33 } | |
34 | |
35 function load16(memory, pointer) { | |
36 return (memory[pointer + 0] << 0) + | |
37 (memory[pointer + 1] << 8); | |
38 } | |
39 | |
40 function load32(memory, pointer) { | |
41 return (memory[pointer + 0] << 0) + | |
42 (memory[pointer + 1] << 8) + | |
43 (memory[pointer + 2] << 16) + | |
44 (memory[pointer + 3] << 24); | |
45 } | |
46 | |
47 function load64(memory, pointer) { | |
48 var lo = load32(memory, pointer); | |
49 var hi = load32(memory, pointer + 4); | |
50 return lo + hi * 0x10000; | |
abarth-chromium
2013/11/18 19:13:20
Fixed here too.
| |
51 } | |
52 | |
53 // Buffer ------------------------------------------------------------------- | |
54 | |
55 function Buffer(size) { | |
56 this.memory = new Uint8Array(size); | |
57 this.next = 0; | |
58 } | |
59 | |
60 Buffer.prototype.alloc = function(size) { | |
61 var pointer = this.next; | |
62 this.next += size; | |
63 if (this.next > this.memory.length) | |
64 this.grow(1.5 * (this.memory.length + size)); | |
Aaron Boodman
2013/11/18 18:34:48
Make the rounding explicit here, just so that read
abarth-chromium
2013/11/18 19:13:20
Done.
| |
65 return pointer; | |
66 }; | |
67 | |
68 Buffer.prototype.grow = function(size) { | |
69 var newMemory = new Uint8Array(size); | |
70 var oldMemory = this.memory; | |
71 for (var i = 0; i < oldMemory.length; ++i) | |
72 newMemory[i] = oldMemory[i]; | |
73 this.memory = newMemory; | |
74 }; | |
75 | |
76 // Constants ---------------------------------------------------------------- | |
77 | |
78 var kArrayHeaderSize = 8; | |
79 var kStructHeaderSize = 8; | |
80 var kMessageHeaderSize = 8; | |
81 | |
82 // Decoder ------------------------------------------------------------------ | |
83 | |
84 function Decoder(memory, handles, base) { | |
85 this.memory = memory; | |
86 this.handles = handles; | |
87 this.base = base; | |
88 this.next = base; | |
89 } | |
90 | |
91 Decoder.prototype.skip = function(offset) { | |
92 this.next += offset; | |
93 }; | |
94 | |
95 Decoder.prototype.read8 = function() { | |
96 var result = load8(this.memory, this.next); | |
97 this.next += 1; | |
98 return result; | |
99 }; | |
100 | |
101 Decoder.prototype.read32 = function() { | |
102 var result = load32(this.memory, this.next); | |
103 this.next += 4; | |
104 return result; | |
105 }; | |
106 | |
107 Decoder.prototype.read64 = function() { | |
108 var result = load64(this.memory, this.next); | |
109 this.next += 8; | |
110 return result; | |
111 }; | |
112 | |
113 Decoder.prototype.decodePointer = function() { | |
114 // TODO(abarth): To correctly decode a pointer, we need to know the real | |
115 // base address of the array buffer. | |
116 var offsetPointer = this.next; | |
117 var offset = this.read64(); | |
118 if (!offset) | |
119 return 0; | |
120 return offsetPointer + offset; | |
121 }; | |
122 | |
123 Decoder.prototype.decodeAndCreateDecoder = function() { | |
124 return new Decoder(this.memory, this.handles, this.decodePointer()); | |
125 }; | |
126 | |
127 Decoder.prototype.decodeHandle = function() { | |
128 return this.handles[this.read32()]; | |
129 }; | |
130 | |
131 Decoder.prototype.decodeString = function() { | |
132 // TODO(abarth): We should really support UTF-8. We might want to | |
133 // jump out of the VM to decode the string directly from the array | |
134 // buffer using v8::String::NewFromUtf8. | |
135 var numberOfBytes = this.read32(); | |
136 var numberOfElements = this.read32(); | |
137 var val = new Array(numberOfElements); | |
138 var memory = this.memory; | |
139 var base = this.next; | |
140 for (var i = 0; i < numberOfElements; ++i) { | |
141 val[i] = String.fromCharCode(memory[base + i] & 0x7F); | |
142 } | |
143 this.next += numberOfElements; | |
144 return val.join(''); | |
145 }; | |
146 | |
147 Decoder.prototype.decodeArray = function(cls) { | |
148 var numberOfBytes = this.read32(); | |
149 var numberOfElements = this.read32(); | |
150 var val = new Array(numberOfElements); | |
151 for (var i = 0; i < numberOfElements; ++i) { | |
152 val[i] = cls.decode(this); | |
153 } | |
154 return val; | |
155 }; | |
156 | |
157 Decoder.prototype.decodeStructPointer = function(cls) { | |
158 return cls.decode(this.decodeAndCreateDecoder()); | |
159 }; | |
160 | |
161 Decoder.prototype.decodeArrayPointer = function(cls) { | |
162 return this.decodeAndCreateDecoder().decodeArray(cls); | |
163 }; | |
164 | |
165 Decoder.prototype.decodeStringPointer = function() { | |
166 return this.decodeAndCreateDecoder().decodeString(); | |
167 }; | |
168 | |
169 // Encoder ------------------------------------------------------------------ | |
170 | |
171 function Encoder(buffer, handles, base) { | |
172 this.buffer = buffer; | |
173 this.handles = handles; | |
174 this.base = base; | |
175 this.next = base; | |
176 } | |
177 | |
178 Encoder.prototype.skip = function(offset) { | |
179 this.next += offset; | |
180 }; | |
181 | |
182 Encoder.prototype.write8 = function(val) { | |
183 store8(this.buffer.memory, this.next, val); | |
184 this.next += 1; | |
185 }; | |
186 | |
187 Encoder.prototype.write32 = function(val) { | |
188 store32(this.buffer.memory, this.next, val); | |
189 this.next += 4; | |
190 }; | |
191 | |
192 Encoder.prototype.write64 = function(val) { | |
193 store64(this.buffer.memory, this.next, val); | |
194 this.next += 8; | |
195 }; | |
196 | |
197 Encoder.prototype.encodePointer = function(pointer) { | |
198 if (!pointer) | |
199 return this.write64(0); | |
200 // TODO(abarth): To correctly encode a pointer, we need to know the real | |
201 // base address of the array buffer. | |
202 var offset = pointer - this.next; | |
203 this.write64(offset); | |
204 }; | |
205 | |
206 Encoder.prototype.createAndEncodeEncoder = function(size) { | |
207 var pointer = this.buffer.alloc(size); | |
208 this.encodePointer(pointer); | |
209 return new Encoder(this.buffer, this.handles, pointer); | |
210 }; | |
211 | |
212 Encoder.prototype.encodeHandle = function(handle) { | |
213 this.handles.push(handle); | |
214 this.write32(this.handles.length - 1); | |
215 }; | |
216 | |
217 Encoder.prototype.encodeString = function(val) { | |
218 var numberOfElements = val.length; | |
219 var numberOfBytes = kArrayHeaderSize + numberOfElements; | |
220 this.write32(numberOfBytes); | |
221 this.write32(numberOfElements); | |
222 // TODO(abarth): We should really support UTF-8. We might want to | |
223 // jump out of the VM to encode the string directly from the array | |
224 // buffer using v8::String::WriteUtf8. | |
225 var memory = this.buffer.memory; | |
226 var base = this.next; | |
227 var len = val.length; | |
228 for (var i = 0; i < len; ++i) { | |
229 memory[base + i] = val.charCodeAt(i) & 0x7F; | |
230 } | |
231 this.next += len; | |
232 }; | |
233 | |
234 Encoder.prototype.encodeArray = function(cls, val) { | |
235 var numberOfElements = val.length; | |
236 var numberOfBytes = kArrayHeaderSize + cls.encodedSize * numberOfElements; | |
237 this.write32(numberOfBytes); | |
238 this.write32(numberOfElements); | |
239 for (var i = 0; i < numberOfElements; ++i) { | |
240 cls.encode(this, val[i]); | |
241 } | |
242 }; | |
243 | |
244 Encoder.prototype.encodeStructPointer = function(cls, val) { | |
245 var encoder = this.createAndEncodeEncoder(cls.encodedSize); | |
246 cls.encode(encoder, val); | |
247 }; | |
248 | |
249 Encoder.prototype.encodeArrayPointer = function(cls, val) { | |
250 var encodedSize = kArrayHeaderSize + cls.encodedSize * val.length; | |
251 var encoder = this.createAndEncodeEncoder(encodedSize); | |
252 encoder.encodeArray(cls, val); | |
253 }; | |
254 | |
255 Encoder.prototype.encodeStringPointer = function(val) { | |
256 // TODO(abarth): This won't be right once we support UTF-8. | |
257 var encodedSize = kArrayHeaderSize + val.length; | |
258 var encoder = this.createAndEncodeEncoder(encodedSize); | |
259 encoder.encodeString(val); | |
260 }; | |
261 | |
262 // Message ------------------------------------------------------------------ | |
263 | |
264 function Message(memory, handles) { | |
265 this.memory = memory; | |
266 this.handles = handles; | |
267 } | |
268 | |
269 // MessageBuilder ----------------------------------------------------------- | |
270 | |
271 function MessageBuilder(messageName, payloadSize) { | |
272 var numberOfBytes = kMessageHeaderSize + payloadSize; | |
273 this.buffer = new Buffer(numberOfBytes); | |
274 this.handles = []; | |
275 var encoder = this.createEncoder(kMessageHeaderSize); | |
276 encoder.write32(numberOfBytes); | |
277 encoder.write32(messageName); | |
278 } | |
279 | |
280 MessageBuilder.prototype.createEncoder = function(size) { | |
281 var pointer = this.buffer.alloc(size); | |
282 return new Encoder(this.buffer, this.handles, pointer); | |
283 } | |
284 | |
285 MessageBuilder.prototype.encodeStruct = function(cls, val) { | |
286 cls.encode(this.createEncoder(cls.encodedSize), val); | |
287 }; | |
288 | |
289 MessageBuilder.prototype.finish = function() { | |
290 var message = new Message(this.buffer.memory, this.handles); | |
291 this.buffer = null; | |
292 this.handles = null; | |
293 this.encoder = null; | |
294 return message; | |
295 }; | |
296 | |
297 // MessageReader ------------------------------------------------------------ | |
298 | |
299 function MessageReader(message) { | |
300 this.decoder = new Decoder(message.memory, message.handles, 0); | |
301 this.payloadSize = this.decoder.read32() - kMessageHeaderSize; | |
302 this.messageName = this.decoder.read32(); | |
303 } | |
304 | |
305 MessageReader.prototype.decodeStruct = function(cls) { | |
306 return cls.decode(this.decoder); | |
307 }; | |
308 | |
309 // Built-in types ----------------------------------------------------------- | |
310 | |
311 function Uint8() { | |
312 } | |
313 | |
314 Uint8.encodedSize = 1; | |
315 | |
316 Uint8.decode = function(decoder) { | |
317 return decoder.read8(); | |
318 }; | |
319 | |
320 Uint8.encode = function(encoder, val) { | |
321 encoder.write8(val); | |
322 }; | |
323 | |
324 function Uint16() { | |
325 } | |
326 | |
327 Uint16.encodedSize = 2; | |
328 | |
329 Uint16.decode = function(decoder) { | |
330 return decoder.read16(); | |
331 }; | |
332 | |
333 Uint16.encode = function(encoder, val) { | |
334 encoder.write16(val); | |
335 }; | |
336 | |
337 function Uint32() { | |
338 } | |
339 | |
340 Uint32.encodedSize = 4; | |
341 | |
342 Uint32.decode = function(decoder) { | |
343 return decoder.read32(); | |
344 }; | |
345 | |
346 Uint32.encode = function(encoder, val) { | |
347 encoder.write32(val); | |
348 }; | |
349 | |
350 function Uint64() { | |
351 }; | |
352 | |
353 Uint64.encodedSize = 8; | |
354 | |
355 Uint64.decode = function(decoder) { | |
356 return decoder.read64(); | |
357 }; | |
358 | |
359 Uint64.encode = function(encoder, val) { | |
360 encoder.write64(val); | |
361 }; | |
362 | |
363 function PointerTo(cls) { | |
364 this.cls = cls; | |
365 }; | |
366 | |
367 PointerTo.prototype.encodedSize = 8; | |
368 | |
369 PointerTo.prototype.decode = function(decoder) { | |
370 return this.cls.decode(decoder.decodeAndCreateDecoder()); | |
371 }; | |
372 | |
373 PointerTo.prototype.encode = function(encoder, val) { | |
374 var objectEncoder = encoder.createAndEncodeEncoder(this.cls.encodedSize); | |
375 this.cls.encode(objectEncoder, val); | |
376 }; | |
377 | |
378 function Handle() { | |
379 } | |
380 | |
381 Handle.encodedSize = 4; | |
382 | |
383 Handle.decode = function(decoder) { | |
384 return decoder.decodeHandle(); | |
385 }; | |
386 | |
387 Handle.encode = function(encoder, val) { | |
388 encoder.encodeHandle(val); | |
389 }; | |
390 | |
391 var exports = {}; | |
392 exports.load32 = load32; | |
393 exports.MessageBuilder = MessageBuilder; | |
394 exports.MessageReader = MessageReader; | |
395 exports.kArrayHeaderSize = kArrayHeaderSize; | |
396 exports.kStructHeaderSize = kStructHeaderSize; | |
397 exports.kMessageHeaderSize = kMessageHeaderSize; | |
398 exports.Uint8 = Uint8; | |
399 exports.Uint16 = Uint16; | |
400 exports.Uint32 = Uint32; | |
401 exports.Uint64 = Uint64; | |
402 exports.PointerTo = PointerTo; | |
403 exports.Handle = Handle; | |
404 return exports; | |
405 }); | |
OLD | NEW |