blob: 9d8ee729a80dcb16ef7a5e6c63ba5e1d343a7bba [file] [log] [blame]
Yi Jin974a9c22017-10-02 18:37:08 -07001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16#define LOG_TAG "libprotoutil"
17
18#include <android/util/protobuf.h>
19#include <android/util/ProtoOutputStream.h>
20#include <cutils/log.h>
Yi Jin974a9c22017-10-02 18:37:08 -070021
22namespace android {
23namespace util {
24
Yi Jin42711a02017-10-11 18:20:24 -070025ProtoOutputStream::ProtoOutputStream()
Yi Jin974a9c22017-10-02 18:37:08 -070026 :mBuffer(),
Yi Jin974a9c22017-10-02 18:37:08 -070027 mCopyBegin(0),
28 mCompact(false),
29 mDepth(0),
30 mObjectId(0),
31 mExpectedObjectToken(0LL)
32{
33}
34
35ProtoOutputStream::~ProtoOutputStream()
36{
37}
38
39bool
40ProtoOutputStream::write(uint64_t fieldId, double val)
41{
42 if (mCompact) return false;
43 const uint32_t id = (uint32_t)fieldId;
44 switch (fieldId & FIELD_TYPE_MASK) {
Yi Jin04625ad2017-10-17 18:29:33 -070045 case FIELD_TYPE_DOUBLE: writeDoubleImpl(id, (double)val); break;
46 case FIELD_TYPE_FLOAT: writeFloatImpl(id, (float)val); break;
47 case FIELD_TYPE_INT64: writeInt64Impl(id, (long long)val); break;
48 case FIELD_TYPE_UINT64: writeUint64Impl(id, (uint64_t)val); break;
49 case FIELD_TYPE_INT32: writeInt32Impl(id, (int)val); break;
50 case FIELD_TYPE_FIXED64: writeFixed64Impl(id, (uint64_t)val); break;
51 case FIELD_TYPE_FIXED32: writeFixed32Impl(id, (uint32_t)val); break;
52 case FIELD_TYPE_UINT32: writeUint32Impl(id, (uint32_t)val); break;
53 case FIELD_TYPE_SFIXED32: writeSFixed32Impl(id, (int)val); break;
54 case FIELD_TYPE_SFIXED64: writeSFixed64Impl(id, (long long)val); break;
55 case FIELD_TYPE_SINT32: writeZigzagInt32Impl(id, (int)val); break;
56 case FIELD_TYPE_SINT64: writeZigzagInt64Impl(id, (long long)val); break;
Yi Jin974a9c22017-10-02 18:37:08 -070057 default:
58 ALOGW("Field type %d is not supported when writing double val.",
59 (int)((fieldId & FIELD_TYPE_MASK) >> FIELD_TYPE_SHIFT));
60 return false;
61 }
62 return true;
63}
64
65bool
66ProtoOutputStream::write(uint64_t fieldId, float val)
67{
68 if (mCompact) return false;
69 const uint32_t id = (uint32_t)fieldId;
70 switch (fieldId & FIELD_TYPE_MASK) {
Yi Jin04625ad2017-10-17 18:29:33 -070071 case FIELD_TYPE_DOUBLE: writeDoubleImpl(id, (double)val); break;
72 case FIELD_TYPE_FLOAT: writeFloatImpl(id, (float)val); break;
73 case FIELD_TYPE_INT64: writeInt64Impl(id, (long long)val); break;
74 case FIELD_TYPE_UINT64: writeUint64Impl(id, (uint64_t)val); break;
75 case FIELD_TYPE_INT32: writeInt32Impl(id, (int)val); break;
76 case FIELD_TYPE_FIXED64: writeFixed64Impl(id, (uint64_t)val); break;
77 case FIELD_TYPE_FIXED32: writeFixed32Impl(id, (uint32_t)val); break;
78 case FIELD_TYPE_UINT32: writeUint32Impl(id, (uint32_t)val); break;
79 case FIELD_TYPE_SFIXED32: writeSFixed32Impl(id, (int)val); break;
80 case FIELD_TYPE_SFIXED64: writeSFixed64Impl(id, (long long)val); break;
81 case FIELD_TYPE_SINT32: writeZigzagInt32Impl(id, (int)val); break;
82 case FIELD_TYPE_SINT64: writeZigzagInt64Impl(id, (long long)val); break;
Yi Jin974a9c22017-10-02 18:37:08 -070083 default:
84 ALOGW("Field type %d is not supported when writing float val.",
85 (int)((fieldId & FIELD_TYPE_MASK) >> FIELD_TYPE_SHIFT));
86 return false;
87 }
88 return true;
89}
90
91bool
92ProtoOutputStream::write(uint64_t fieldId, int val)
93{
94 if (mCompact) return false;
95 const uint32_t id = (uint32_t)fieldId;
96 switch (fieldId & FIELD_TYPE_MASK) {
Yi Jin04625ad2017-10-17 18:29:33 -070097 case FIELD_TYPE_DOUBLE: writeDoubleImpl(id, (double)val); break;
98 case FIELD_TYPE_FLOAT: writeFloatImpl(id, (float)val); break;
99 case FIELD_TYPE_INT64: writeInt64Impl(id, (long long)val); break;
100 case FIELD_TYPE_UINT64: writeUint64Impl(id, (uint64_t)val); break;
101 case FIELD_TYPE_INT32: writeInt32Impl(id, (int)val); break;
102 case FIELD_TYPE_FIXED64: writeFixed64Impl(id, (uint64_t)val); break;
103 case FIELD_TYPE_FIXED32: writeFixed32Impl(id, (uint32_t)val); break;
104 case FIELD_TYPE_UINT32: writeUint32Impl(id, (uint32_t)val); break;
105 case FIELD_TYPE_SFIXED32: writeSFixed32Impl(id, (int)val); break;
106 case FIELD_TYPE_SFIXED64: writeSFixed64Impl(id, (long long)val); break;
107 case FIELD_TYPE_SINT32: writeZigzagInt32Impl(id, (int)val); break;
108 case FIELD_TYPE_SINT64: writeZigzagInt64Impl(id, (long long)val); break;
109 case FIELD_TYPE_ENUM: writeEnumImpl(id, (int)val); break;
110 case FIELD_TYPE_BOOL: writeBoolImpl(id, val != 0); break;
Yi Jin974a9c22017-10-02 18:37:08 -0700111 default:
112 ALOGW("Field type %d is not supported when writing int val.",
113 (int)((fieldId & FIELD_TYPE_MASK) >> FIELD_TYPE_SHIFT));
114 return false;
115 }
116 return true;
117}
118
119bool
120ProtoOutputStream::write(uint64_t fieldId, long long val)
121{
122 if (mCompact) return false;
123 const uint32_t id = (uint32_t)fieldId;
124 switch (fieldId & FIELD_TYPE_MASK) {
Yi Jin04625ad2017-10-17 18:29:33 -0700125 case FIELD_TYPE_DOUBLE: writeDoubleImpl(id, (double)val); break;
126 case FIELD_TYPE_FLOAT: writeFloatImpl(id, (float)val); break;
127 case FIELD_TYPE_INT64: writeInt64Impl(id, (long long)val); break;
128 case FIELD_TYPE_UINT64: writeUint64Impl(id, (uint64_t)val); break;
129 case FIELD_TYPE_INT32: writeInt32Impl(id, (int)val); break;
130 case FIELD_TYPE_FIXED64: writeFixed64Impl(id, (uint64_t)val); break;
131 case FIELD_TYPE_FIXED32: writeFixed32Impl(id, (uint32_t)val); break;
132 case FIELD_TYPE_UINT32: writeUint32Impl(id, (uint32_t)val); break;
133 case FIELD_TYPE_SFIXED32: writeSFixed32Impl(id, (int)val); break;
134 case FIELD_TYPE_SFIXED64: writeSFixed64Impl(id, (long long)val); break;
135 case FIELD_TYPE_SINT32: writeZigzagInt32Impl(id, (int)val); break;
136 case FIELD_TYPE_SINT64: writeZigzagInt64Impl(id, (long long)val); break;
137 case FIELD_TYPE_ENUM: writeEnumImpl(id, (int)val); break;
138 case FIELD_TYPE_BOOL: writeBoolImpl(id, val != 0); break;
Yi Jin974a9c22017-10-02 18:37:08 -0700139 default:
140 ALOGW("Field type %d is not supported when writing long long val.",
141 (int)((fieldId & FIELD_TYPE_MASK) >> FIELD_TYPE_SHIFT));
142 return false;
143 }
144 return true;
145}
146
147bool
148ProtoOutputStream::write(uint64_t fieldId, bool val)
149{
150 if (mCompact) return false;
151 const uint32_t id = (uint32_t)fieldId;
152 switch (fieldId & FIELD_TYPE_MASK) {
Yi Jin04625ad2017-10-17 18:29:33 -0700153 case FIELD_TYPE_BOOL:
Yi Jin974a9c22017-10-02 18:37:08 -0700154 writeBoolImpl(id, val);
155 return true;
156 default:
157 ALOGW("Field type %d is not supported when writing bool val.",
158 (int)((fieldId & FIELD_TYPE_MASK) >> FIELD_TYPE_SHIFT));
159 return false;
160 }
161}
162
163bool
164ProtoOutputStream::write(uint64_t fieldId, string val)
165{
166 if (mCompact) return false;
167 const uint32_t id = (uint32_t)fieldId;
168 switch (fieldId & FIELD_TYPE_MASK) {
Yi Jin04625ad2017-10-17 18:29:33 -0700169 case FIELD_TYPE_STRING:
Yi Jin974a9c22017-10-02 18:37:08 -0700170 writeUtf8StringImpl(id, val.c_str(), val.size());
171 return true;
172 default:
173 ALOGW("Field type %d is not supported when writing string val.",
174 (int)((fieldId & FIELD_TYPE_MASK) >> FIELD_TYPE_SHIFT));
175 return false;
176 }
177}
178
179bool
Yi Jine0833302017-10-23 15:42:44 -0700180ProtoOutputStream::write(uint64_t fieldId, const char* val, size_t size)
Yi Jin974a9c22017-10-02 18:37:08 -0700181{
182 if (mCompact) return false;
183 const uint32_t id = (uint32_t)fieldId;
Yi Jin974a9c22017-10-02 18:37:08 -0700184 switch (fieldId & FIELD_TYPE_MASK) {
Yi Jin04625ad2017-10-17 18:29:33 -0700185 case FIELD_TYPE_STRING:
186 case FIELD_TYPE_BYTES:
Yi Jin974a9c22017-10-02 18:37:08 -0700187 writeUtf8StringImpl(id, val, size);
188 return true;
Yi Jin04625ad2017-10-17 18:29:33 -0700189 case FIELD_TYPE_MESSAGE:
Yi Jin8ad19382017-10-30 16:07:20 -0700190 // can directly write valid format of message bytes into ProtoOutputStream without calling start/end
191 writeMessageBytesImpl(id, val, size);
192 return true;
Yi Jin974a9c22017-10-02 18:37:08 -0700193 default:
194 ALOGW("Field type %d is not supported when writing char[] val.",
195 (int)((fieldId & FIELD_TYPE_MASK) >> FIELD_TYPE_SHIFT));
196 return false;
197 }
198}
199
200/**
201 * Make a token.
202 * Bits 61-63 - tag size (So we can go backwards later if the object had not data)
203 * - 3 bits, max value 7, max value needed 5
204 * Bit 60 - true if the object is repeated
205 * Bits 59-51 - depth (For error checking)
206 * - 9 bits, max value 512, when checking, value is masked (if we really
207 * are more than 512 levels deep)
208 * Bits 32-50 - objectId (For error checking)
209 * - 19 bits, max value 524,288. that's a lot of objects. IDs will wrap
210 * because of the overflow, and only the tokens are compared.
211 * Bits 0-31 - offset of the first size field in the buffer.
212 */
213long long
214makeToken(int tagSize, bool repeated, int depth, int objectId, int sizePos) {
215 return ((0x07L & (long long)tagSize) << 61)
216 | (repeated ? (1LL << 60) : 0)
217 | (0x01ffL & (long long)depth) << 51
218 | (0x07ffffL & (long long)objectId) << 32
219 | (0x0ffffffffL & (long long)sizePos);
220}
221
222/**
223 * Get the encoded tag size from the token.
224 */
225static int getTagSizeFromToken(long long token) {
226 return (int)(0x7 & (token >> 61));
227}
228
229/**
230 * Get the nesting depth of startObject calls from the token.
231 */
232static int getDepthFromToken(long long token) {
233 return (int)(0x01ff & (token >> 51));
234}
235
236/**
237 * Get the location of the childRawSize (the first 32 bit size field) in this object.
238 */
239static int getSizePosFromToken(long long token) {
240 return (int)token;
241}
242
243long long
244ProtoOutputStream::start(uint64_t fieldId)
245{
Yi Jin04625ad2017-10-17 18:29:33 -0700246 if ((fieldId & FIELD_TYPE_MASK) != FIELD_TYPE_MESSAGE) {
Yi Jin974a9c22017-10-02 18:37:08 -0700247 ALOGE("Can't call start for non-message type field: 0x%llx", (long long)fieldId);
248 return 0;
249 }
250
251 uint32_t id = (uint32_t)fieldId;
252 mBuffer.writeHeader(id, WIRE_TYPE_LENGTH_DELIMITED);
253
254 size_t sizePos = mBuffer.wp()->pos();
255
256 mDepth++;
257 mObjectId++;
258 mBuffer.writeRawFixed64(mExpectedObjectToken); // push previous token into stack.
259
260 mExpectedObjectToken = makeToken(get_varint_size(id),
261 (bool)(fieldId & FIELD_COUNT_REPEATED), mDepth, mObjectId, sizePos);
262 return mExpectedObjectToken;
263}
264
265void
266ProtoOutputStream::end(long long token)
267{
268 if (token != mExpectedObjectToken) {
269 ALOGE("Unexpected token: 0x%llx, should be 0x%llx", token, mExpectedObjectToken);
270 return;
271 }
272
273 int depth = getDepthFromToken(token);
274 if (depth != (mDepth & 0x01ff)) {
275 ALOGE("Unexpected depth: %d, should be %d", depth, mDepth);
276 return;
277 }
278 mDepth--;
279
280 int sizePos = getSizePosFromToken(token);
281 // number of bytes written in this start-end session.
282 int childRawSize = mBuffer.wp()->pos() - sizePos - 8;
283
284 // retrieve the old token from stack.
285 mBuffer.ep()->rewind()->move(sizePos);
286 mExpectedObjectToken = mBuffer.readRawFixed64();
287
288 // If raw size is larger than 0, write the negative value here to indicate a compact is needed.
289 if (childRawSize > 0) {
290 mBuffer.editRawFixed32(sizePos, -childRawSize);
291 mBuffer.editRawFixed32(sizePos+4, -1);
292 } else {
293 // reset wp which erase the header tag of the message when its size is 0.
294 mBuffer.wp()->rewind()->move(sizePos - getTagSizeFromToken(token));
295 }
296}
297
298bool
299ProtoOutputStream::compact() {
300 if (mCompact) return true;
301 if (mDepth != 0) {
302 ALOGE("Can't compact when depth(%d) is not zero. Missing calls to end.", mDepth);
303 return false;
304 }
305 // record the size of the original buffer.
306 size_t rawBufferSize = mBuffer.size();
307 if (rawBufferSize == 0) return true; // nothing to do if the buffer is empty;
308
309 // reset edit pointer and recursively compute encoded size of messages.
310 mBuffer.ep()->rewind();
311 if (editEncodedSize(rawBufferSize) == 0) {
312 ALOGE("Failed to editEncodedSize.");
313 return false;
314 }
315
316 // reset both edit pointer and write pointer, and compact recursively.
317 mBuffer.ep()->rewind();
318 mBuffer.wp()->rewind();
319 if (!compactSize(rawBufferSize)) {
320 ALOGE("Failed to compactSize.");
321 return false;
322 }
323 // copy the reset to the buffer.
324 if (mCopyBegin < rawBufferSize) {
325 mBuffer.copy(mCopyBegin, rawBufferSize - mCopyBegin);
326 }
327
328 // mark true means it is not legal to write to this ProtoOutputStream anymore
329 mCompact = true;
330 return true;
331}
332
333/**
334 * First compaction pass. Iterate through the data, and fill in the
335 * nested object sizes so the next pass can compact them.
336 */
337size_t
338ProtoOutputStream::editEncodedSize(size_t rawSize)
339{
340 size_t objectStart = mBuffer.ep()->pos();
341 size_t objectEnd = objectStart + rawSize;
342 size_t encodedSize = 0;
343 int childRawSize, childEncodedSize;
344 size_t childEncodedSizePos;
345
346 while (mBuffer.ep()->pos() < objectEnd) {
347 uint32_t tag = (uint32_t)mBuffer.readRawVarint();
348 encodedSize += get_varint_size(tag);
349 switch (read_wire_type(tag)) {
350 case WIRE_TYPE_VARINT:
351 do {
352 encodedSize++;
353 } while ((mBuffer.readRawByte() & 0x80) != 0);
354 break;
355 case WIRE_TYPE_FIXED64:
356 encodedSize += 8;
357 mBuffer.ep()->move(8);
358 break;
359 case WIRE_TYPE_LENGTH_DELIMITED:
360 childRawSize = (int)mBuffer.readRawFixed32();
361 childEncodedSizePos = mBuffer.ep()->pos();
362 childEncodedSize = (int)mBuffer.readRawFixed32();
363 if (childRawSize >= 0 && childRawSize == childEncodedSize) {
364 mBuffer.ep()->move(childRawSize);
365 } else if (childRawSize < 0 && childEncodedSize == -1){
366 childEncodedSize = editEncodedSize(-childRawSize);
367 mBuffer.editRawFixed32(childEncodedSizePos, childEncodedSize);
368 } else {
369 ALOGE("Bad raw or encoded values: raw=%d, encoded=%d at %zu",
370 childRawSize, childEncodedSize, childEncodedSizePos);
371 return 0;
372 }
373 encodedSize += get_varint_size(childEncodedSize) + childEncodedSize;
374 break;
375 case WIRE_TYPE_FIXED32:
376 encodedSize += 4;
377 mBuffer.ep()->move(4);
378 break;
379 default:
380 ALOGE("Unexpected wire type %d in editEncodedSize at [%zu, %zu]",
381 read_wire_type(tag), objectStart, objectEnd);
382 return 0;
383 }
384 }
385 return encodedSize;
386}
387
388/**
389 * Second compaction pass. Iterate through the data, and copy the data
390 * forward in the buffer, converting the pairs of uint32s into a single
391 * unsigned varint of the size.
392 */
393bool
394ProtoOutputStream::compactSize(size_t rawSize)
395{
396 size_t objectStart = mBuffer.ep()->pos();
397 size_t objectEnd = objectStart + rawSize;
398 int childRawSize, childEncodedSize;
399
400 while (mBuffer.ep()->pos() < objectEnd) {
401 uint32_t tag = (uint32_t)mBuffer.readRawVarint();
402 switch (read_wire_type(tag)) {
403 case WIRE_TYPE_VARINT:
404 while ((mBuffer.readRawByte() & 0x80) != 0) {}
405 break;
406 case WIRE_TYPE_FIXED64:
407 mBuffer.ep()->move(8);
408 break;
409 case WIRE_TYPE_LENGTH_DELIMITED:
410 mBuffer.copy(mCopyBegin, mBuffer.ep()->pos() - mCopyBegin);
411
412 childRawSize = (int)mBuffer.readRawFixed32();
413 childEncodedSize = (int)mBuffer.readRawFixed32();
414 mCopyBegin = mBuffer.ep()->pos();
415
416 // write encoded size to buffer.
417 mBuffer.writeRawVarint32(childEncodedSize);
418 if (childRawSize >= 0 && childRawSize == childEncodedSize) {
419 mBuffer.ep()->move(childEncodedSize);
420 } else if (childRawSize < 0){
421 if (!compactSize(-childRawSize)) return false;
422 } else {
423 ALOGE("Bad raw or encoded values: raw=%d, encoded=%d",
424 childRawSize, childEncodedSize);
425 return false;
426 }
427 break;
428 case WIRE_TYPE_FIXED32:
429 mBuffer.ep()->move(4);
430 break;
431 default:
432 ALOGE("Unexpected wire type %d in compactSize at [%zu, %zu]",
433 read_wire_type(tag), objectStart, objectEnd);
434 return false;
435 }
436 }
437 return true;
438}
439
Yi Jin42711a02017-10-11 18:20:24 -0700440size_t
441ProtoOutputStream::size()
442{
443 compact();
444 return mBuffer.size();
445}
446
Yi Jin974a9c22017-10-02 18:37:08 -0700447static bool write_all(int fd, uint8_t const* buf, size_t size)
448{
449 while (size > 0) {
450 ssize_t amt = ::write(fd, buf, size);
451 if (amt < 0) {
452 return false;
453 }
454 size -= amt;
455 buf += amt;
456 }
457 return true;
458}
459
460bool
Yi Jin42711a02017-10-11 18:20:24 -0700461ProtoOutputStream::flush(int fd)
Yi Jin974a9c22017-10-02 18:37:08 -0700462{
Yi Jin42711a02017-10-11 18:20:24 -0700463 if (fd < 0) return false;
Yi Jin974a9c22017-10-02 18:37:08 -0700464 if (!compact()) return false;
465
466 EncodedBuffer::iterator it = mBuffer.begin();
467 while (it.readBuffer() != NULL) {
Yi Jin42711a02017-10-11 18:20:24 -0700468 if (!write_all(fd, it.readBuffer(), it.currentToRead())) return false;
Yi Jin974a9c22017-10-02 18:37:08 -0700469 it.rp()->move(it.currentToRead());
470 }
471 return true;
472}
473
Yi Jin42711a02017-10-11 18:20:24 -0700474EncodedBuffer::iterator
475ProtoOutputStream::data()
476{
477 compact();
478 return mBuffer.begin();
479}
480
481void
482ProtoOutputStream::writeRawVarint(uint64_t varint)
483{
484 mBuffer.writeRawVarint64(varint);
485}
486
487void
488ProtoOutputStream::writeLengthDelimitedHeader(uint32_t id, size_t size)
489{
490 mBuffer.writeHeader(id, WIRE_TYPE_LENGTH_DELIMITED);
491 // reserves 64 bits for length delimited fields, if first field is negative, compact it.
492 mBuffer.writeRawFixed32(size);
493 mBuffer.writeRawFixed32(size);
494}
495
496void
497ProtoOutputStream::writeRawByte(uint8_t byte)
498{
499 mBuffer.writeRawByte(byte);
500}
501
Yi Jin974a9c22017-10-02 18:37:08 -0700502
503// =========================================================================
504// Private functions
505
506/**
507 * bit_cast
508 */
509template <class From, class To>
510inline To bit_cast(From const &from) {
511 To to;
512 memcpy(&to, &from, sizeof(to));
513 return to;
514}
515
516inline void
517ProtoOutputStream::writeDoubleImpl(uint32_t id, double val)
518{
Yi Jin974a9c22017-10-02 18:37:08 -0700519 mBuffer.writeHeader(id, WIRE_TYPE_FIXED64);
520 mBuffer.writeRawFixed64(bit_cast<double, uint64_t>(val));
521}
522
523inline void
524ProtoOutputStream::writeFloatImpl(uint32_t id, float val)
525{
Yi Jin974a9c22017-10-02 18:37:08 -0700526 mBuffer.writeHeader(id, WIRE_TYPE_FIXED32);
527 mBuffer.writeRawFixed32(bit_cast<float, uint32_t>(val));
528}
529
530inline void
531ProtoOutputStream::writeInt64Impl(uint32_t id, long long val)
532{
Yi Jin974a9c22017-10-02 18:37:08 -0700533 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
534 mBuffer.writeRawVarint64((uint64_t)val);
535}
536
537inline void
538ProtoOutputStream::writeInt32Impl(uint32_t id, int val)
539{
Yi Jin974a9c22017-10-02 18:37:08 -0700540 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
541 mBuffer.writeRawVarint32((uint32_t)val);
542}
543
544inline void
545ProtoOutputStream::writeUint64Impl(uint32_t id, uint64_t val)
546{
Yi Jin974a9c22017-10-02 18:37:08 -0700547 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
548 mBuffer.writeRawVarint64(val);
549}
550
551inline void
552ProtoOutputStream::writeUint32Impl(uint32_t id, uint32_t val)
553{
Yi Jin974a9c22017-10-02 18:37:08 -0700554 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
555 mBuffer.writeRawVarint32(val);
556}
557
558inline void
559ProtoOutputStream::writeFixed64Impl(uint32_t id, uint64_t val)
560{
Yi Jin974a9c22017-10-02 18:37:08 -0700561 mBuffer.writeHeader(id, WIRE_TYPE_FIXED64);
562 mBuffer.writeRawFixed64(val);
563}
564
565inline void
566ProtoOutputStream::writeFixed32Impl(uint32_t id, uint32_t val)
567{
Yi Jin974a9c22017-10-02 18:37:08 -0700568 mBuffer.writeHeader(id, WIRE_TYPE_FIXED32);
569 mBuffer.writeRawFixed32(val);
570}
571
572inline void
573ProtoOutputStream::writeSFixed64Impl(uint32_t id, long long val)
574{
Yi Jin974a9c22017-10-02 18:37:08 -0700575 mBuffer.writeHeader(id, WIRE_TYPE_FIXED64);
576 mBuffer.writeRawFixed64((uint64_t)val);
577}
578
579inline void
580ProtoOutputStream::writeSFixed32Impl(uint32_t id, int val)
581{
Yi Jin974a9c22017-10-02 18:37:08 -0700582 mBuffer.writeHeader(id, WIRE_TYPE_FIXED32);
583 mBuffer.writeRawFixed32((uint32_t)val);
584}
585
586inline void
587ProtoOutputStream::writeZigzagInt64Impl(uint32_t id, long long val)
588{
Yi Jin974a9c22017-10-02 18:37:08 -0700589 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
590 mBuffer.writeRawVarint64((val << 1) ^ (val >> 63));
591}
592
593inline void
594ProtoOutputStream::writeZigzagInt32Impl(uint32_t id, int val)
595{
Yi Jin974a9c22017-10-02 18:37:08 -0700596 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
597 mBuffer.writeRawVarint32((val << 1) ^ (val >> 31));
598}
599
600inline void
601ProtoOutputStream::writeEnumImpl(uint32_t id, int val)
602{
603 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
604 mBuffer.writeRawVarint32((uint32_t) val);
605}
606
607inline void
608ProtoOutputStream::writeBoolImpl(uint32_t id, bool val)
609{
Yi Jin974a9c22017-10-02 18:37:08 -0700610 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
611 mBuffer.writeRawVarint32(val ? 1 : 0);
612}
613
614inline void
615ProtoOutputStream::writeUtf8StringImpl(uint32_t id, const char* val, size_t size)
616{
Yi Jin04625ad2017-10-17 18:29:33 -0700617 if (val == NULL) return;
Yi Jin42711a02017-10-11 18:20:24 -0700618 writeLengthDelimitedHeader(id, size);
Yi Jin974a9c22017-10-02 18:37:08 -0700619 for (size_t i=0; i<size; i++) {
620 mBuffer.writeRawByte((uint8_t)val[i]);
621 }
622}
623
Yi Jin8ad19382017-10-30 16:07:20 -0700624inline void
625ProtoOutputStream::writeMessageBytesImpl(uint32_t id, const char* val, size_t size)
626{
627 if (val == NULL) return;
628 writeLengthDelimitedHeader(id, size);
629 for (size_t i=0; i<size; i++) {
630 mBuffer.writeRawByte(val[i]);
631 }
632}
633
Yi Jin974a9c22017-10-02 18:37:08 -0700634} // util
635} // android
636