1ffe3c632Sopenharmony_ci// Protocol Buffers - Google's data interchange format
2ffe3c632Sopenharmony_ci// Copyright 2008 Google Inc.  All rights reserved.
3ffe3c632Sopenharmony_ci// https://developers.google.com/protocol-buffers/
4ffe3c632Sopenharmony_ci//
5ffe3c632Sopenharmony_ci// Redistribution and use in source and binary forms, with or without
6ffe3c632Sopenharmony_ci// modification, are permitted provided that the following conditions are
7ffe3c632Sopenharmony_ci// met:
8ffe3c632Sopenharmony_ci//
9ffe3c632Sopenharmony_ci//     * Redistributions of source code must retain the above copyright
10ffe3c632Sopenharmony_ci// notice, this list of conditions and the following disclaimer.
11ffe3c632Sopenharmony_ci//     * Redistributions in binary form must reproduce the above
12ffe3c632Sopenharmony_ci// copyright notice, this list of conditions and the following disclaimer
13ffe3c632Sopenharmony_ci// in the documentation and/or other materials provided with the
14ffe3c632Sopenharmony_ci// distribution.
15ffe3c632Sopenharmony_ci//     * Neither the name of Google Inc. nor the names of its
16ffe3c632Sopenharmony_ci// contributors may be used to endorse or promote products derived from
17ffe3c632Sopenharmony_ci// this software without specific prior written permission.
18ffe3c632Sopenharmony_ci//
19ffe3c632Sopenharmony_ci// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20ffe3c632Sopenharmony_ci// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21ffe3c632Sopenharmony_ci// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22ffe3c632Sopenharmony_ci// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23ffe3c632Sopenharmony_ci// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24ffe3c632Sopenharmony_ci// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25ffe3c632Sopenharmony_ci// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26ffe3c632Sopenharmony_ci// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27ffe3c632Sopenharmony_ci// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28ffe3c632Sopenharmony_ci// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29ffe3c632Sopenharmony_ci// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30ffe3c632Sopenharmony_ci
31ffe3c632Sopenharmony_ci/**
32ffe3c632Sopenharmony_ci * @fileoverview BinaryEncode defines methods for encoding Javascript values
33ffe3c632Sopenharmony_ci * into arrays of bytes compatible with the Protocol Buffer wire format.
34ffe3c632Sopenharmony_ci *
35ffe3c632Sopenharmony_ci * @author aappleby@google.com (Austin Appleby)
36ffe3c632Sopenharmony_ci */
37ffe3c632Sopenharmony_ci
38ffe3c632Sopenharmony_cigoog.provide('jspb.BinaryEncoder');
39ffe3c632Sopenharmony_ci
40ffe3c632Sopenharmony_cigoog.require('goog.asserts');
41ffe3c632Sopenharmony_cigoog.require('jspb.BinaryConstants');
42ffe3c632Sopenharmony_cigoog.require('jspb.utils');
43ffe3c632Sopenharmony_ci
44ffe3c632Sopenharmony_ci
45ffe3c632Sopenharmony_ci
46ffe3c632Sopenharmony_ci/**
47ffe3c632Sopenharmony_ci * BinaryEncoder implements encoders for all the wire types specified in
48ffe3c632Sopenharmony_ci * https://developers.google.com/protocol-buffers/docs/encoding.
49ffe3c632Sopenharmony_ci *
50ffe3c632Sopenharmony_ci * @constructor
51ffe3c632Sopenharmony_ci * @struct
52ffe3c632Sopenharmony_ci */
53ffe3c632Sopenharmony_cijspb.BinaryEncoder = function() {
54ffe3c632Sopenharmony_ci  /** @private {!Array<number>} */
55ffe3c632Sopenharmony_ci  this.buffer_ = [];
56ffe3c632Sopenharmony_ci};
57ffe3c632Sopenharmony_ci
58ffe3c632Sopenharmony_ci
59ffe3c632Sopenharmony_ci/**
60ffe3c632Sopenharmony_ci * @return {number}
61ffe3c632Sopenharmony_ci */
62ffe3c632Sopenharmony_cijspb.BinaryEncoder.prototype.length = function() {
63ffe3c632Sopenharmony_ci  return this.buffer_.length;
64ffe3c632Sopenharmony_ci};
65ffe3c632Sopenharmony_ci
66ffe3c632Sopenharmony_ci
67ffe3c632Sopenharmony_ci/**
68ffe3c632Sopenharmony_ci * @return {!Array<number>}
69ffe3c632Sopenharmony_ci */
70ffe3c632Sopenharmony_cijspb.BinaryEncoder.prototype.end = function() {
71ffe3c632Sopenharmony_ci  var buffer = this.buffer_;
72ffe3c632Sopenharmony_ci  this.buffer_ = [];
73ffe3c632Sopenharmony_ci  return buffer;
74ffe3c632Sopenharmony_ci};
75ffe3c632Sopenharmony_ci
76ffe3c632Sopenharmony_ci
77ffe3c632Sopenharmony_ci/**
78ffe3c632Sopenharmony_ci * Encodes a 64-bit integer in 32:32 split representation into its wire-format
79ffe3c632Sopenharmony_ci * varint representation and stores it in the buffer.
80ffe3c632Sopenharmony_ci * @param {number} lowBits The low 32 bits of the int.
81ffe3c632Sopenharmony_ci * @param {number} highBits The high 32 bits of the int.
82ffe3c632Sopenharmony_ci */
83ffe3c632Sopenharmony_cijspb.BinaryEncoder.prototype.writeSplitVarint64 = function(lowBits, highBits) {
84ffe3c632Sopenharmony_ci  goog.asserts.assert(lowBits == Math.floor(lowBits));
85ffe3c632Sopenharmony_ci  goog.asserts.assert(highBits == Math.floor(highBits));
86ffe3c632Sopenharmony_ci  goog.asserts.assert((lowBits >= 0) &&
87ffe3c632Sopenharmony_ci                      (lowBits < jspb.BinaryConstants.TWO_TO_32));
88ffe3c632Sopenharmony_ci  goog.asserts.assert((highBits >= 0) &&
89ffe3c632Sopenharmony_ci                      (highBits < jspb.BinaryConstants.TWO_TO_32));
90ffe3c632Sopenharmony_ci
91ffe3c632Sopenharmony_ci  // Break the binary representation into chunks of 7 bits, set the 8th bit
92ffe3c632Sopenharmony_ci  // in each chunk if it's not the final chunk, and append to the result.
93ffe3c632Sopenharmony_ci  while (highBits > 0 || lowBits > 127) {
94ffe3c632Sopenharmony_ci    this.buffer_.push((lowBits & 0x7f) | 0x80);
95ffe3c632Sopenharmony_ci    lowBits = ((lowBits >>> 7) | (highBits << 25)) >>> 0;
96ffe3c632Sopenharmony_ci    highBits = highBits >>> 7;
97ffe3c632Sopenharmony_ci  }
98ffe3c632Sopenharmony_ci  this.buffer_.push(lowBits);
99ffe3c632Sopenharmony_ci};
100ffe3c632Sopenharmony_ci
101ffe3c632Sopenharmony_ci
102ffe3c632Sopenharmony_ci/**
103ffe3c632Sopenharmony_ci * Encodes a 64-bit integer in 32:32 split representation into its wire-format
104ffe3c632Sopenharmony_ci * fixed representation and stores it in the buffer.
105ffe3c632Sopenharmony_ci * @param {number} lowBits The low 32 bits of the int.
106ffe3c632Sopenharmony_ci * @param {number} highBits The high 32 bits of the int.
107ffe3c632Sopenharmony_ci */
108ffe3c632Sopenharmony_cijspb.BinaryEncoder.prototype.writeSplitFixed64 = function(lowBits, highBits) {
109ffe3c632Sopenharmony_ci  goog.asserts.assert(lowBits == Math.floor(lowBits));
110ffe3c632Sopenharmony_ci  goog.asserts.assert(highBits == Math.floor(highBits));
111ffe3c632Sopenharmony_ci  goog.asserts.assert((lowBits >= 0) &&
112ffe3c632Sopenharmony_ci                      (lowBits < jspb.BinaryConstants.TWO_TO_32));
113ffe3c632Sopenharmony_ci  goog.asserts.assert((highBits >= 0) &&
114ffe3c632Sopenharmony_ci                      (highBits < jspb.BinaryConstants.TWO_TO_32));
115ffe3c632Sopenharmony_ci  this.writeUint32(lowBits);
116ffe3c632Sopenharmony_ci  this.writeUint32(highBits);
117ffe3c632Sopenharmony_ci};
118ffe3c632Sopenharmony_ci
119ffe3c632Sopenharmony_ci
120ffe3c632Sopenharmony_ci/**
121ffe3c632Sopenharmony_ci * Encodes a 32-bit unsigned integer into its wire-format varint representation
122ffe3c632Sopenharmony_ci * and stores it in the buffer.
123ffe3c632Sopenharmony_ci * @param {number} value The integer to convert.
124ffe3c632Sopenharmony_ci */
125ffe3c632Sopenharmony_cijspb.BinaryEncoder.prototype.writeUnsignedVarint32 = function(value) {
126ffe3c632Sopenharmony_ci  goog.asserts.assert(value == Math.floor(value));
127ffe3c632Sopenharmony_ci  goog.asserts.assert((value >= 0) &&
128ffe3c632Sopenharmony_ci                      (value < jspb.BinaryConstants.TWO_TO_32));
129ffe3c632Sopenharmony_ci
130ffe3c632Sopenharmony_ci  while (value > 127) {
131ffe3c632Sopenharmony_ci    this.buffer_.push((value & 0x7f) | 0x80);
132ffe3c632Sopenharmony_ci    value = value >>> 7;
133ffe3c632Sopenharmony_ci  }
134ffe3c632Sopenharmony_ci
135ffe3c632Sopenharmony_ci  this.buffer_.push(value);
136ffe3c632Sopenharmony_ci};
137ffe3c632Sopenharmony_ci
138ffe3c632Sopenharmony_ci
139ffe3c632Sopenharmony_ci/**
140ffe3c632Sopenharmony_ci * Encodes a 32-bit signed integer into its wire-format varint representation
141ffe3c632Sopenharmony_ci * and stores it in the buffer.
142ffe3c632Sopenharmony_ci * @param {number} value The integer to convert.
143ffe3c632Sopenharmony_ci */
144ffe3c632Sopenharmony_cijspb.BinaryEncoder.prototype.writeSignedVarint32 = function(value) {
145ffe3c632Sopenharmony_ci  goog.asserts.assert(value == Math.floor(value));
146ffe3c632Sopenharmony_ci  goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_31) &&
147ffe3c632Sopenharmony_ci                      (value < jspb.BinaryConstants.TWO_TO_31));
148ffe3c632Sopenharmony_ci
149ffe3c632Sopenharmony_ci  // Use the unsigned version if the value is not negative.
150ffe3c632Sopenharmony_ci  if (value >= 0) {
151ffe3c632Sopenharmony_ci    this.writeUnsignedVarint32(value);
152ffe3c632Sopenharmony_ci    return;
153ffe3c632Sopenharmony_ci  }
154ffe3c632Sopenharmony_ci
155ffe3c632Sopenharmony_ci  // Write nine bytes with a _signed_ right shift so we preserve the sign bit.
156ffe3c632Sopenharmony_ci  for (var i = 0; i < 9; i++) {
157ffe3c632Sopenharmony_ci    this.buffer_.push((value & 0x7f) | 0x80);
158ffe3c632Sopenharmony_ci    value = value >> 7;
159ffe3c632Sopenharmony_ci  }
160ffe3c632Sopenharmony_ci
161ffe3c632Sopenharmony_ci  // The above loop writes out 63 bits, so the last byte is always the sign bit
162ffe3c632Sopenharmony_ci  // which is always set for negative numbers.
163ffe3c632Sopenharmony_ci  this.buffer_.push(1);
164ffe3c632Sopenharmony_ci};
165ffe3c632Sopenharmony_ci
166ffe3c632Sopenharmony_ci
167ffe3c632Sopenharmony_ci/**
168ffe3c632Sopenharmony_ci * Encodes a 64-bit unsigned integer into its wire-format varint representation
169ffe3c632Sopenharmony_ci * and stores it in the buffer. Integers that are not representable in 64 bits
170ffe3c632Sopenharmony_ci * will be truncated.
171ffe3c632Sopenharmony_ci * @param {number} value The integer to convert.
172ffe3c632Sopenharmony_ci */
173ffe3c632Sopenharmony_cijspb.BinaryEncoder.prototype.writeUnsignedVarint64 = function(value) {
174ffe3c632Sopenharmony_ci  goog.asserts.assert(value == Math.floor(value));
175ffe3c632Sopenharmony_ci  goog.asserts.assert((value >= 0) &&
176ffe3c632Sopenharmony_ci                      (value < jspb.BinaryConstants.TWO_TO_64));
177ffe3c632Sopenharmony_ci  jspb.utils.splitInt64(value);
178ffe3c632Sopenharmony_ci  this.writeSplitVarint64(jspb.utils.split64Low,
179ffe3c632Sopenharmony_ci                          jspb.utils.split64High);
180ffe3c632Sopenharmony_ci};
181ffe3c632Sopenharmony_ci
182ffe3c632Sopenharmony_ci
183ffe3c632Sopenharmony_ci/**
184ffe3c632Sopenharmony_ci * Encodes a 64-bit signed integer into its wire-format varint representation
185ffe3c632Sopenharmony_ci * and stores it in the buffer. Integers that are not representable in 64 bits
186ffe3c632Sopenharmony_ci * will be truncated.
187ffe3c632Sopenharmony_ci * @param {number} value The integer to convert.
188ffe3c632Sopenharmony_ci */
189ffe3c632Sopenharmony_cijspb.BinaryEncoder.prototype.writeSignedVarint64 = function(value) {
190ffe3c632Sopenharmony_ci  goog.asserts.assert(value == Math.floor(value));
191ffe3c632Sopenharmony_ci  goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_63) &&
192ffe3c632Sopenharmony_ci                      (value < jspb.BinaryConstants.TWO_TO_63));
193ffe3c632Sopenharmony_ci  jspb.utils.splitInt64(value);
194ffe3c632Sopenharmony_ci  this.writeSplitVarint64(jspb.utils.split64Low,
195ffe3c632Sopenharmony_ci                          jspb.utils.split64High);
196ffe3c632Sopenharmony_ci};
197ffe3c632Sopenharmony_ci
198ffe3c632Sopenharmony_ci
199ffe3c632Sopenharmony_ci/**
200ffe3c632Sopenharmony_ci * Encodes a JavaScript integer into its wire-format, zigzag-encoded varint
201ffe3c632Sopenharmony_ci * representation and stores it in the buffer.
202ffe3c632Sopenharmony_ci * @param {number} value The integer to convert.
203ffe3c632Sopenharmony_ci */
204ffe3c632Sopenharmony_cijspb.BinaryEncoder.prototype.writeZigzagVarint32 = function(value) {
205ffe3c632Sopenharmony_ci  goog.asserts.assert(value == Math.floor(value));
206ffe3c632Sopenharmony_ci  goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_31) &&
207ffe3c632Sopenharmony_ci                      (value < jspb.BinaryConstants.TWO_TO_31));
208ffe3c632Sopenharmony_ci  this.writeUnsignedVarint32(((value << 1) ^ (value >> 31)) >>> 0);
209ffe3c632Sopenharmony_ci};
210ffe3c632Sopenharmony_ci
211ffe3c632Sopenharmony_ci
212ffe3c632Sopenharmony_ci/**
213ffe3c632Sopenharmony_ci * Encodes a JavaScript integer into its wire-format, zigzag-encoded varint
214ffe3c632Sopenharmony_ci * representation and stores it in the buffer. Integers not representable in 64
215ffe3c632Sopenharmony_ci * bits will be truncated.
216ffe3c632Sopenharmony_ci * @param {number} value The integer to convert.
217ffe3c632Sopenharmony_ci */
218ffe3c632Sopenharmony_cijspb.BinaryEncoder.prototype.writeZigzagVarint64 = function(value) {
219ffe3c632Sopenharmony_ci  goog.asserts.assert(value == Math.floor(value));
220ffe3c632Sopenharmony_ci  goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_63) &&
221ffe3c632Sopenharmony_ci                      (value < jspb.BinaryConstants.TWO_TO_63));
222ffe3c632Sopenharmony_ci  jspb.utils.splitZigzag64(value);
223ffe3c632Sopenharmony_ci  this.writeSplitVarint64(jspb.utils.split64Low,
224ffe3c632Sopenharmony_ci                          jspb.utils.split64High);
225ffe3c632Sopenharmony_ci};
226ffe3c632Sopenharmony_ci
227ffe3c632Sopenharmony_ci
228ffe3c632Sopenharmony_ci/**
229ffe3c632Sopenharmony_ci * Encodes a JavaScript decimal string into its wire-format, zigzag-encoded
230ffe3c632Sopenharmony_ci * varint representation and stores it in the buffer. Integers not representable
231ffe3c632Sopenharmony_ci * in 64 bits will be truncated.
232ffe3c632Sopenharmony_ci * @param {string} value The integer to convert.
233ffe3c632Sopenharmony_ci */
234ffe3c632Sopenharmony_cijspb.BinaryEncoder.prototype.writeZigzagVarint64String = function(value) {
235ffe3c632Sopenharmony_ci  this.writeZigzagVarintHash64(jspb.utils.decimalStringToHash64(value));
236ffe3c632Sopenharmony_ci};
237ffe3c632Sopenharmony_ci
238ffe3c632Sopenharmony_ci
239ffe3c632Sopenharmony_ci/**
240ffe3c632Sopenharmony_ci * Writes a 64-bit hash string (8 characters @ 8 bits of data each) to the
241ffe3c632Sopenharmony_ci * buffer as a zigzag varint.
242ffe3c632Sopenharmony_ci * @param {string} hash The hash to write.
243ffe3c632Sopenharmony_ci */
244ffe3c632Sopenharmony_cijspb.BinaryEncoder.prototype.writeZigzagVarintHash64 = function(hash) {
245ffe3c632Sopenharmony_ci  var self = this;
246ffe3c632Sopenharmony_ci  jspb.utils.splitHash64(hash);
247ffe3c632Sopenharmony_ci  jspb.utils.toZigzag64(
248ffe3c632Sopenharmony_ci      jspb.utils.split64Low, jspb.utils.split64High, function(lo, hi) {
249ffe3c632Sopenharmony_ci        self.writeSplitVarint64(lo >>> 0, hi >>> 0);
250ffe3c632Sopenharmony_ci      });
251ffe3c632Sopenharmony_ci};
252ffe3c632Sopenharmony_ci
253ffe3c632Sopenharmony_ci
254ffe3c632Sopenharmony_ci/**
255ffe3c632Sopenharmony_ci * Writes an 8-bit unsigned integer to the buffer. Numbers outside the range
256ffe3c632Sopenharmony_ci * [0,2^8) will be truncated.
257ffe3c632Sopenharmony_ci * @param {number} value The value to write.
258ffe3c632Sopenharmony_ci */
259ffe3c632Sopenharmony_cijspb.BinaryEncoder.prototype.writeUint8 = function(value) {
260ffe3c632Sopenharmony_ci  goog.asserts.assert(value == Math.floor(value));
261ffe3c632Sopenharmony_ci  goog.asserts.assert((value >= 0) && (value < 256));
262ffe3c632Sopenharmony_ci  this.buffer_.push((value >>> 0) & 0xFF);
263ffe3c632Sopenharmony_ci};
264ffe3c632Sopenharmony_ci
265ffe3c632Sopenharmony_ci
266ffe3c632Sopenharmony_ci/**
267ffe3c632Sopenharmony_ci * Writes a 16-bit unsigned integer to the buffer. Numbers outside the
268ffe3c632Sopenharmony_ci * range [0,2^16) will be truncated.
269ffe3c632Sopenharmony_ci * @param {number} value The value to write.
270ffe3c632Sopenharmony_ci */
271ffe3c632Sopenharmony_cijspb.BinaryEncoder.prototype.writeUint16 = function(value) {
272ffe3c632Sopenharmony_ci  goog.asserts.assert(value == Math.floor(value));
273ffe3c632Sopenharmony_ci  goog.asserts.assert((value >= 0) && (value < 65536));
274ffe3c632Sopenharmony_ci  this.buffer_.push((value >>> 0) & 0xFF);
275ffe3c632Sopenharmony_ci  this.buffer_.push((value >>> 8) & 0xFF);
276ffe3c632Sopenharmony_ci};
277ffe3c632Sopenharmony_ci
278ffe3c632Sopenharmony_ci
279ffe3c632Sopenharmony_ci/**
280ffe3c632Sopenharmony_ci * Writes a 32-bit unsigned integer to the buffer. Numbers outside the
281ffe3c632Sopenharmony_ci * range [0,2^32) will be truncated.
282ffe3c632Sopenharmony_ci * @param {number} value The value to write.
283ffe3c632Sopenharmony_ci */
284ffe3c632Sopenharmony_cijspb.BinaryEncoder.prototype.writeUint32 = function(value) {
285ffe3c632Sopenharmony_ci  goog.asserts.assert(value == Math.floor(value));
286ffe3c632Sopenharmony_ci  goog.asserts.assert((value >= 0) &&
287ffe3c632Sopenharmony_ci                      (value < jspb.BinaryConstants.TWO_TO_32));
288ffe3c632Sopenharmony_ci  this.buffer_.push((value >>> 0) & 0xFF);
289ffe3c632Sopenharmony_ci  this.buffer_.push((value >>> 8) & 0xFF);
290ffe3c632Sopenharmony_ci  this.buffer_.push((value >>> 16) & 0xFF);
291ffe3c632Sopenharmony_ci  this.buffer_.push((value >>> 24) & 0xFF);
292ffe3c632Sopenharmony_ci};
293ffe3c632Sopenharmony_ci
294ffe3c632Sopenharmony_ci
295ffe3c632Sopenharmony_ci/**
296ffe3c632Sopenharmony_ci * Writes a 64-bit unsigned integer to the buffer. Numbers outside the
297ffe3c632Sopenharmony_ci * range [0,2^64) will be truncated.
298ffe3c632Sopenharmony_ci * @param {number} value The value to write.
299ffe3c632Sopenharmony_ci */
300ffe3c632Sopenharmony_cijspb.BinaryEncoder.prototype.writeUint64 = function(value) {
301ffe3c632Sopenharmony_ci  goog.asserts.assert(value == Math.floor(value));
302ffe3c632Sopenharmony_ci  goog.asserts.assert((value >= 0) &&
303ffe3c632Sopenharmony_ci                      (value < jspb.BinaryConstants.TWO_TO_64));
304ffe3c632Sopenharmony_ci  jspb.utils.splitUint64(value);
305ffe3c632Sopenharmony_ci  this.writeUint32(jspb.utils.split64Low);
306ffe3c632Sopenharmony_ci  this.writeUint32(jspb.utils.split64High);
307ffe3c632Sopenharmony_ci};
308ffe3c632Sopenharmony_ci
309ffe3c632Sopenharmony_ci
310ffe3c632Sopenharmony_ci/**
311ffe3c632Sopenharmony_ci * Writes an 8-bit integer to the buffer. Numbers outside the range
312ffe3c632Sopenharmony_ci * [-2^7,2^7) will be truncated.
313ffe3c632Sopenharmony_ci * @param {number} value The value to write.
314ffe3c632Sopenharmony_ci */
315ffe3c632Sopenharmony_cijspb.BinaryEncoder.prototype.writeInt8 = function(value) {
316ffe3c632Sopenharmony_ci  goog.asserts.assert(value == Math.floor(value));
317ffe3c632Sopenharmony_ci  goog.asserts.assert((value >= -128) && (value < 128));
318ffe3c632Sopenharmony_ci  this.buffer_.push((value >>> 0) & 0xFF);
319ffe3c632Sopenharmony_ci};
320ffe3c632Sopenharmony_ci
321ffe3c632Sopenharmony_ci
322ffe3c632Sopenharmony_ci/**
323ffe3c632Sopenharmony_ci * Writes a 16-bit integer to the buffer. Numbers outside the range
324ffe3c632Sopenharmony_ci * [-2^15,2^15) will be truncated.
325ffe3c632Sopenharmony_ci * @param {number} value The value to write.
326ffe3c632Sopenharmony_ci */
327ffe3c632Sopenharmony_cijspb.BinaryEncoder.prototype.writeInt16 = function(value) {
328ffe3c632Sopenharmony_ci  goog.asserts.assert(value == Math.floor(value));
329ffe3c632Sopenharmony_ci  goog.asserts.assert((value >= -32768) && (value < 32768));
330ffe3c632Sopenharmony_ci  this.buffer_.push((value >>> 0) & 0xFF);
331ffe3c632Sopenharmony_ci  this.buffer_.push((value >>> 8) & 0xFF);
332ffe3c632Sopenharmony_ci};
333ffe3c632Sopenharmony_ci
334ffe3c632Sopenharmony_ci
335ffe3c632Sopenharmony_ci/**
336ffe3c632Sopenharmony_ci * Writes a 32-bit integer to the buffer. Numbers outside the range
337ffe3c632Sopenharmony_ci * [-2^31,2^31) will be truncated.
338ffe3c632Sopenharmony_ci * @param {number} value The value to write.
339ffe3c632Sopenharmony_ci */
340ffe3c632Sopenharmony_cijspb.BinaryEncoder.prototype.writeInt32 = function(value) {
341ffe3c632Sopenharmony_ci  goog.asserts.assert(value == Math.floor(value));
342ffe3c632Sopenharmony_ci  goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_31) &&
343ffe3c632Sopenharmony_ci                      (value < jspb.BinaryConstants.TWO_TO_31));
344ffe3c632Sopenharmony_ci  this.buffer_.push((value >>> 0) & 0xFF);
345ffe3c632Sopenharmony_ci  this.buffer_.push((value >>> 8) & 0xFF);
346ffe3c632Sopenharmony_ci  this.buffer_.push((value >>> 16) & 0xFF);
347ffe3c632Sopenharmony_ci  this.buffer_.push((value >>> 24) & 0xFF);
348ffe3c632Sopenharmony_ci};
349ffe3c632Sopenharmony_ci
350ffe3c632Sopenharmony_ci
351ffe3c632Sopenharmony_ci/**
352ffe3c632Sopenharmony_ci * Writes a 64-bit integer to the buffer. Numbers outside the range
353ffe3c632Sopenharmony_ci * [-2^63,2^63) will be truncated.
354ffe3c632Sopenharmony_ci * @param {number} value The value to write.
355ffe3c632Sopenharmony_ci */
356ffe3c632Sopenharmony_cijspb.BinaryEncoder.prototype.writeInt64 = function(value) {
357ffe3c632Sopenharmony_ci  goog.asserts.assert(value == Math.floor(value));
358ffe3c632Sopenharmony_ci  goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_63) &&
359ffe3c632Sopenharmony_ci                      (value < jspb.BinaryConstants.TWO_TO_63));
360ffe3c632Sopenharmony_ci  jspb.utils.splitInt64(value);
361ffe3c632Sopenharmony_ci  this.writeSplitFixed64(jspb.utils.split64Low, jspb.utils.split64High);
362ffe3c632Sopenharmony_ci};
363ffe3c632Sopenharmony_ci
364ffe3c632Sopenharmony_ci
365ffe3c632Sopenharmony_ci/**
366ffe3c632Sopenharmony_ci * Writes a 64-bit integer decimal strings to the buffer. Numbers outside the
367ffe3c632Sopenharmony_ci * range [-2^63,2^63) will be truncated.
368ffe3c632Sopenharmony_ci * @param {string} value The value to write.
369ffe3c632Sopenharmony_ci */
370ffe3c632Sopenharmony_cijspb.BinaryEncoder.prototype.writeInt64String = function(value) {
371ffe3c632Sopenharmony_ci  goog.asserts.assert(value == Math.floor(value));
372ffe3c632Sopenharmony_ci  goog.asserts.assert((+value >= -jspb.BinaryConstants.TWO_TO_63) &&
373ffe3c632Sopenharmony_ci                      (+value < jspb.BinaryConstants.TWO_TO_63));
374ffe3c632Sopenharmony_ci  jspb.utils.splitHash64(jspb.utils.decimalStringToHash64(value));
375ffe3c632Sopenharmony_ci  this.writeSplitFixed64(jspb.utils.split64Low, jspb.utils.split64High);
376ffe3c632Sopenharmony_ci};
377ffe3c632Sopenharmony_ci
378ffe3c632Sopenharmony_ci
379ffe3c632Sopenharmony_ci/**
380ffe3c632Sopenharmony_ci * Writes a single-precision floating point value to the buffer. Numbers
381ffe3c632Sopenharmony_ci * requiring more than 32 bits of precision will be truncated.
382ffe3c632Sopenharmony_ci * @param {number} value The value to write.
383ffe3c632Sopenharmony_ci */
384ffe3c632Sopenharmony_cijspb.BinaryEncoder.prototype.writeFloat = function(value) {
385ffe3c632Sopenharmony_ci  goog.asserts.assert(
386ffe3c632Sopenharmony_ci      value === Infinity || value === -Infinity || isNaN(value) ||
387ffe3c632Sopenharmony_ci      ((value >= -jspb.BinaryConstants.FLOAT32_MAX) &&
388ffe3c632Sopenharmony_ci       (value <= jspb.BinaryConstants.FLOAT32_MAX)));
389ffe3c632Sopenharmony_ci  jspb.utils.splitFloat32(value);
390ffe3c632Sopenharmony_ci  this.writeUint32(jspb.utils.split64Low);
391ffe3c632Sopenharmony_ci};
392ffe3c632Sopenharmony_ci
393ffe3c632Sopenharmony_ci
394ffe3c632Sopenharmony_ci/**
395ffe3c632Sopenharmony_ci * Writes a double-precision floating point value to the buffer. As this is
396ffe3c632Sopenharmony_ci * the native format used by JavaScript, no precision will be lost.
397ffe3c632Sopenharmony_ci * @param {number} value The value to write.
398ffe3c632Sopenharmony_ci */
399ffe3c632Sopenharmony_cijspb.BinaryEncoder.prototype.writeDouble = function(value) {
400ffe3c632Sopenharmony_ci  goog.asserts.assert(
401ffe3c632Sopenharmony_ci      value === Infinity || value === -Infinity || isNaN(value) ||
402ffe3c632Sopenharmony_ci      ((value >= -jspb.BinaryConstants.FLOAT64_MAX) &&
403ffe3c632Sopenharmony_ci       (value <= jspb.BinaryConstants.FLOAT64_MAX)));
404ffe3c632Sopenharmony_ci  jspb.utils.splitFloat64(value);
405ffe3c632Sopenharmony_ci  this.writeUint32(jspb.utils.split64Low);
406ffe3c632Sopenharmony_ci  this.writeUint32(jspb.utils.split64High);
407ffe3c632Sopenharmony_ci};
408ffe3c632Sopenharmony_ci
409ffe3c632Sopenharmony_ci
410ffe3c632Sopenharmony_ci/**
411ffe3c632Sopenharmony_ci * Writes a boolean value to the buffer as a varint. We allow numbers as input
412ffe3c632Sopenharmony_ci * because the JSPB code generator uses 0/1 instead of true/false to save space
413ffe3c632Sopenharmony_ci * in the string representation of the proto.
414ffe3c632Sopenharmony_ci * @param {boolean|number} value The value to write.
415ffe3c632Sopenharmony_ci */
416ffe3c632Sopenharmony_cijspb.BinaryEncoder.prototype.writeBool = function(value) {
417ffe3c632Sopenharmony_ci  goog.asserts.assert(typeof value === 'boolean' || typeof value === 'number');
418ffe3c632Sopenharmony_ci  this.buffer_.push(value ? 1 : 0);
419ffe3c632Sopenharmony_ci};
420ffe3c632Sopenharmony_ci
421ffe3c632Sopenharmony_ci
422ffe3c632Sopenharmony_ci/**
423ffe3c632Sopenharmony_ci * Writes an enum value to the buffer as a varint.
424ffe3c632Sopenharmony_ci * @param {number} value The value to write.
425ffe3c632Sopenharmony_ci */
426ffe3c632Sopenharmony_cijspb.BinaryEncoder.prototype.writeEnum = function(value) {
427ffe3c632Sopenharmony_ci  goog.asserts.assert(value == Math.floor(value));
428ffe3c632Sopenharmony_ci  goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_31) &&
429ffe3c632Sopenharmony_ci                      (value < jspb.BinaryConstants.TWO_TO_31));
430ffe3c632Sopenharmony_ci  this.writeSignedVarint32(value);
431ffe3c632Sopenharmony_ci};
432ffe3c632Sopenharmony_ci
433ffe3c632Sopenharmony_ci
434ffe3c632Sopenharmony_ci/**
435ffe3c632Sopenharmony_ci * Writes an arbitrary byte array to the buffer.
436ffe3c632Sopenharmony_ci * @param {!Uint8Array} bytes The array of bytes to write.
437ffe3c632Sopenharmony_ci */
438ffe3c632Sopenharmony_cijspb.BinaryEncoder.prototype.writeBytes = function(bytes) {
439ffe3c632Sopenharmony_ci  this.buffer_.push.apply(this.buffer_, bytes);
440ffe3c632Sopenharmony_ci};
441ffe3c632Sopenharmony_ci
442ffe3c632Sopenharmony_ci
443ffe3c632Sopenharmony_ci/**
444ffe3c632Sopenharmony_ci * Writes a 64-bit hash string (8 characters @ 8 bits of data each) to the
445ffe3c632Sopenharmony_ci * buffer as a varint.
446ffe3c632Sopenharmony_ci * @param {string} hash The hash to write.
447ffe3c632Sopenharmony_ci */
448ffe3c632Sopenharmony_cijspb.BinaryEncoder.prototype.writeVarintHash64 = function(hash) {
449ffe3c632Sopenharmony_ci  jspb.utils.splitHash64(hash);
450ffe3c632Sopenharmony_ci  this.writeSplitVarint64(jspb.utils.split64Low,
451ffe3c632Sopenharmony_ci                          jspb.utils.split64High);
452ffe3c632Sopenharmony_ci};
453ffe3c632Sopenharmony_ci
454ffe3c632Sopenharmony_ci
455ffe3c632Sopenharmony_ci/**
456ffe3c632Sopenharmony_ci * Writes a 64-bit hash string (8 characters @ 8 bits of data each) to the
457ffe3c632Sopenharmony_ci * buffer as a fixed64.
458ffe3c632Sopenharmony_ci * @param {string} hash The hash to write.
459ffe3c632Sopenharmony_ci */
460ffe3c632Sopenharmony_cijspb.BinaryEncoder.prototype.writeFixedHash64 = function(hash) {
461ffe3c632Sopenharmony_ci  jspb.utils.splitHash64(hash);
462ffe3c632Sopenharmony_ci  this.writeUint32(jspb.utils.split64Low);
463ffe3c632Sopenharmony_ci  this.writeUint32(jspb.utils.split64High);
464ffe3c632Sopenharmony_ci};
465ffe3c632Sopenharmony_ci
466ffe3c632Sopenharmony_ci
467ffe3c632Sopenharmony_ci/**
468ffe3c632Sopenharmony_ci * Writes a UTF16 Javascript string to the buffer encoded as UTF8.
469ffe3c632Sopenharmony_ci * TODO(aappleby): Add support for surrogate pairs, reject unpaired surrogates.
470ffe3c632Sopenharmony_ci * @param {string} value The string to write.
471ffe3c632Sopenharmony_ci * @return {number} The number of bytes used to encode the string.
472ffe3c632Sopenharmony_ci */
473ffe3c632Sopenharmony_cijspb.BinaryEncoder.prototype.writeString = function(value) {
474ffe3c632Sopenharmony_ci  var oldLength = this.buffer_.length;
475ffe3c632Sopenharmony_ci
476ffe3c632Sopenharmony_ci  for (var i = 0; i < value.length; i++) {
477ffe3c632Sopenharmony_ci
478ffe3c632Sopenharmony_ci    var c = value.charCodeAt(i);
479ffe3c632Sopenharmony_ci
480ffe3c632Sopenharmony_ci    if (c < 128) {
481ffe3c632Sopenharmony_ci      this.buffer_.push(c);
482ffe3c632Sopenharmony_ci    } else if (c < 2048) {
483ffe3c632Sopenharmony_ci      this.buffer_.push((c >> 6) | 192);
484ffe3c632Sopenharmony_ci      this.buffer_.push((c & 63) | 128);
485ffe3c632Sopenharmony_ci    } else if (c < 65536) {
486ffe3c632Sopenharmony_ci      // Look for surrogates
487ffe3c632Sopenharmony_ci      if (c >= 0xD800 && c <= 0xDBFF && i + 1 < value.length) {
488ffe3c632Sopenharmony_ci        var second = value.charCodeAt(i + 1);
489ffe3c632Sopenharmony_ci        if (second >= 0xDC00 && second <= 0xDFFF) { // low surrogate
490ffe3c632Sopenharmony_ci          // http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
491ffe3c632Sopenharmony_ci          c = (c - 0xD800) * 0x400 + second - 0xDC00 + 0x10000;
492ffe3c632Sopenharmony_ci
493ffe3c632Sopenharmony_ci          this.buffer_.push((c >> 18) | 240);
494ffe3c632Sopenharmony_ci          this.buffer_.push(((c >> 12) & 63 ) | 128);
495ffe3c632Sopenharmony_ci          this.buffer_.push(((c >> 6) & 63) | 128);
496ffe3c632Sopenharmony_ci          this.buffer_.push((c & 63) | 128);
497ffe3c632Sopenharmony_ci          i++;
498ffe3c632Sopenharmony_ci        }
499ffe3c632Sopenharmony_ci      }
500ffe3c632Sopenharmony_ci      else {
501ffe3c632Sopenharmony_ci        this.buffer_.push((c >> 12) | 224);
502ffe3c632Sopenharmony_ci        this.buffer_.push(((c >> 6) & 63) | 128);
503ffe3c632Sopenharmony_ci        this.buffer_.push((c & 63) | 128);
504ffe3c632Sopenharmony_ci      }
505ffe3c632Sopenharmony_ci    }
506ffe3c632Sopenharmony_ci  }
507ffe3c632Sopenharmony_ci
508ffe3c632Sopenharmony_ci  var length = this.buffer_.length - oldLength;
509ffe3c632Sopenharmony_ci  return length;
510ffe3c632Sopenharmony_ci};
511