blob: 1904d40ea67ac41e71c00fc7f234d0993eb6d1a4 [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
Yi Jin0abdfb02017-11-16 15:32:27 -0800298size_t
299ProtoOutputStream::bytesWritten()
300{
301 return mBuffer.size();
302}
303
Yi Jin974a9c22017-10-02 18:37:08 -0700304bool
305ProtoOutputStream::compact() {
306 if (mCompact) return true;
307 if (mDepth != 0) {
308 ALOGE("Can't compact when depth(%d) is not zero. Missing calls to end.", mDepth);
309 return false;
310 }
311 // record the size of the original buffer.
312 size_t rawBufferSize = mBuffer.size();
313 if (rawBufferSize == 0) return true; // nothing to do if the buffer is empty;
314
315 // reset edit pointer and recursively compute encoded size of messages.
316 mBuffer.ep()->rewind();
317 if (editEncodedSize(rawBufferSize) == 0) {
318 ALOGE("Failed to editEncodedSize.");
319 return false;
320 }
321
322 // reset both edit pointer and write pointer, and compact recursively.
323 mBuffer.ep()->rewind();
324 mBuffer.wp()->rewind();
325 if (!compactSize(rawBufferSize)) {
326 ALOGE("Failed to compactSize.");
327 return false;
328 }
329 // copy the reset to the buffer.
330 if (mCopyBegin < rawBufferSize) {
331 mBuffer.copy(mCopyBegin, rawBufferSize - mCopyBegin);
332 }
333
334 // mark true means it is not legal to write to this ProtoOutputStream anymore
335 mCompact = true;
336 return true;
337}
338
339/**
340 * First compaction pass. Iterate through the data, and fill in the
341 * nested object sizes so the next pass can compact them.
342 */
343size_t
344ProtoOutputStream::editEncodedSize(size_t rawSize)
345{
346 size_t objectStart = mBuffer.ep()->pos();
347 size_t objectEnd = objectStart + rawSize;
348 size_t encodedSize = 0;
349 int childRawSize, childEncodedSize;
350 size_t childEncodedSizePos;
351
352 while (mBuffer.ep()->pos() < objectEnd) {
353 uint32_t tag = (uint32_t)mBuffer.readRawVarint();
354 encodedSize += get_varint_size(tag);
355 switch (read_wire_type(tag)) {
356 case WIRE_TYPE_VARINT:
357 do {
358 encodedSize++;
359 } while ((mBuffer.readRawByte() & 0x80) != 0);
360 break;
361 case WIRE_TYPE_FIXED64:
362 encodedSize += 8;
363 mBuffer.ep()->move(8);
364 break;
365 case WIRE_TYPE_LENGTH_DELIMITED:
366 childRawSize = (int)mBuffer.readRawFixed32();
367 childEncodedSizePos = mBuffer.ep()->pos();
368 childEncodedSize = (int)mBuffer.readRawFixed32();
369 if (childRawSize >= 0 && childRawSize == childEncodedSize) {
370 mBuffer.ep()->move(childRawSize);
371 } else if (childRawSize < 0 && childEncodedSize == -1){
372 childEncodedSize = editEncodedSize(-childRawSize);
373 mBuffer.editRawFixed32(childEncodedSizePos, childEncodedSize);
374 } else {
375 ALOGE("Bad raw or encoded values: raw=%d, encoded=%d at %zu",
376 childRawSize, childEncodedSize, childEncodedSizePos);
377 return 0;
378 }
379 encodedSize += get_varint_size(childEncodedSize) + childEncodedSize;
380 break;
381 case WIRE_TYPE_FIXED32:
382 encodedSize += 4;
383 mBuffer.ep()->move(4);
384 break;
385 default:
386 ALOGE("Unexpected wire type %d in editEncodedSize at [%zu, %zu]",
387 read_wire_type(tag), objectStart, objectEnd);
388 return 0;
389 }
390 }
391 return encodedSize;
392}
393
394/**
395 * Second compaction pass. Iterate through the data, and copy the data
396 * forward in the buffer, converting the pairs of uint32s into a single
397 * unsigned varint of the size.
398 */
399bool
400ProtoOutputStream::compactSize(size_t rawSize)
401{
402 size_t objectStart = mBuffer.ep()->pos();
403 size_t objectEnd = objectStart + rawSize;
404 int childRawSize, childEncodedSize;
405
406 while (mBuffer.ep()->pos() < objectEnd) {
407 uint32_t tag = (uint32_t)mBuffer.readRawVarint();
408 switch (read_wire_type(tag)) {
409 case WIRE_TYPE_VARINT:
410 while ((mBuffer.readRawByte() & 0x80) != 0) {}
411 break;
412 case WIRE_TYPE_FIXED64:
413 mBuffer.ep()->move(8);
414 break;
415 case WIRE_TYPE_LENGTH_DELIMITED:
416 mBuffer.copy(mCopyBegin, mBuffer.ep()->pos() - mCopyBegin);
417
418 childRawSize = (int)mBuffer.readRawFixed32();
419 childEncodedSize = (int)mBuffer.readRawFixed32();
420 mCopyBegin = mBuffer.ep()->pos();
421
422 // write encoded size to buffer.
423 mBuffer.writeRawVarint32(childEncodedSize);
424 if (childRawSize >= 0 && childRawSize == childEncodedSize) {
425 mBuffer.ep()->move(childEncodedSize);
426 } else if (childRawSize < 0){
427 if (!compactSize(-childRawSize)) return false;
428 } else {
429 ALOGE("Bad raw or encoded values: raw=%d, encoded=%d",
430 childRawSize, childEncodedSize);
431 return false;
432 }
433 break;
434 case WIRE_TYPE_FIXED32:
435 mBuffer.ep()->move(4);
436 break;
437 default:
438 ALOGE("Unexpected wire type %d in compactSize at [%zu, %zu]",
439 read_wire_type(tag), objectStart, objectEnd);
440 return false;
441 }
442 }
443 return true;
444}
445
Yi Jin42711a02017-10-11 18:20:24 -0700446size_t
447ProtoOutputStream::size()
448{
449 compact();
450 return mBuffer.size();
451}
452
Yi Jin974a9c22017-10-02 18:37:08 -0700453static bool write_all(int fd, uint8_t const* buf, size_t size)
454{
455 while (size > 0) {
456 ssize_t amt = ::write(fd, buf, size);
457 if (amt < 0) {
458 return false;
459 }
460 size -= amt;
461 buf += amt;
462 }
463 return true;
464}
465
466bool
Yi Jin42711a02017-10-11 18:20:24 -0700467ProtoOutputStream::flush(int fd)
Yi Jin974a9c22017-10-02 18:37:08 -0700468{
Yi Jin42711a02017-10-11 18:20:24 -0700469 if (fd < 0) return false;
Yi Jin974a9c22017-10-02 18:37:08 -0700470 if (!compact()) return false;
471
472 EncodedBuffer::iterator it = mBuffer.begin();
473 while (it.readBuffer() != NULL) {
Yi Jin42711a02017-10-11 18:20:24 -0700474 if (!write_all(fd, it.readBuffer(), it.currentToRead())) return false;
Yi Jin974a9c22017-10-02 18:37:08 -0700475 it.rp()->move(it.currentToRead());
476 }
477 return true;
478}
479
Yi Jin42711a02017-10-11 18:20:24 -0700480EncodedBuffer::iterator
481ProtoOutputStream::data()
482{
483 compact();
484 return mBuffer.begin();
485}
486
487void
488ProtoOutputStream::writeRawVarint(uint64_t varint)
489{
490 mBuffer.writeRawVarint64(varint);
491}
492
493void
494ProtoOutputStream::writeLengthDelimitedHeader(uint32_t id, size_t size)
495{
496 mBuffer.writeHeader(id, WIRE_TYPE_LENGTH_DELIMITED);
497 // reserves 64 bits for length delimited fields, if first field is negative, compact it.
498 mBuffer.writeRawFixed32(size);
499 mBuffer.writeRawFixed32(size);
500}
501
502void
503ProtoOutputStream::writeRawByte(uint8_t byte)
504{
505 mBuffer.writeRawByte(byte);
506}
507
Yi Jin974a9c22017-10-02 18:37:08 -0700508
509// =========================================================================
510// Private functions
511
512/**
513 * bit_cast
514 */
515template <class From, class To>
516inline To bit_cast(From const &from) {
517 To to;
518 memcpy(&to, &from, sizeof(to));
519 return to;
520}
521
522inline void
523ProtoOutputStream::writeDoubleImpl(uint32_t id, double val)
524{
Yi Jin974a9c22017-10-02 18:37:08 -0700525 mBuffer.writeHeader(id, WIRE_TYPE_FIXED64);
526 mBuffer.writeRawFixed64(bit_cast<double, uint64_t>(val));
527}
528
529inline void
530ProtoOutputStream::writeFloatImpl(uint32_t id, float val)
531{
Yi Jin974a9c22017-10-02 18:37:08 -0700532 mBuffer.writeHeader(id, WIRE_TYPE_FIXED32);
533 mBuffer.writeRawFixed32(bit_cast<float, uint32_t>(val));
534}
535
536inline void
537ProtoOutputStream::writeInt64Impl(uint32_t id, long long val)
538{
Yi Jin974a9c22017-10-02 18:37:08 -0700539 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
540 mBuffer.writeRawVarint64((uint64_t)val);
541}
542
543inline void
544ProtoOutputStream::writeInt32Impl(uint32_t id, int val)
545{
Yi Jin974a9c22017-10-02 18:37:08 -0700546 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
547 mBuffer.writeRawVarint32((uint32_t)val);
548}
549
550inline void
551ProtoOutputStream::writeUint64Impl(uint32_t id, uint64_t val)
552{
Yi Jin974a9c22017-10-02 18:37:08 -0700553 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
554 mBuffer.writeRawVarint64(val);
555}
556
557inline void
558ProtoOutputStream::writeUint32Impl(uint32_t id, uint32_t val)
559{
Yi Jin974a9c22017-10-02 18:37:08 -0700560 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
561 mBuffer.writeRawVarint32(val);
562}
563
564inline void
565ProtoOutputStream::writeFixed64Impl(uint32_t id, uint64_t val)
566{
Yi Jin974a9c22017-10-02 18:37:08 -0700567 mBuffer.writeHeader(id, WIRE_TYPE_FIXED64);
568 mBuffer.writeRawFixed64(val);
569}
570
571inline void
572ProtoOutputStream::writeFixed32Impl(uint32_t id, uint32_t val)
573{
Yi Jin974a9c22017-10-02 18:37:08 -0700574 mBuffer.writeHeader(id, WIRE_TYPE_FIXED32);
575 mBuffer.writeRawFixed32(val);
576}
577
578inline void
579ProtoOutputStream::writeSFixed64Impl(uint32_t id, long long val)
580{
Yi Jin974a9c22017-10-02 18:37:08 -0700581 mBuffer.writeHeader(id, WIRE_TYPE_FIXED64);
582 mBuffer.writeRawFixed64((uint64_t)val);
583}
584
585inline void
586ProtoOutputStream::writeSFixed32Impl(uint32_t id, int val)
587{
Yi Jin974a9c22017-10-02 18:37:08 -0700588 mBuffer.writeHeader(id, WIRE_TYPE_FIXED32);
589 mBuffer.writeRawFixed32((uint32_t)val);
590}
591
592inline void
593ProtoOutputStream::writeZigzagInt64Impl(uint32_t id, long long val)
594{
Yi Jin974a9c22017-10-02 18:37:08 -0700595 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
596 mBuffer.writeRawVarint64((val << 1) ^ (val >> 63));
597}
598
599inline void
600ProtoOutputStream::writeZigzagInt32Impl(uint32_t id, int val)
601{
Yi Jin974a9c22017-10-02 18:37:08 -0700602 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
603 mBuffer.writeRawVarint32((val << 1) ^ (val >> 31));
604}
605
606inline void
607ProtoOutputStream::writeEnumImpl(uint32_t id, int val)
608{
609 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
610 mBuffer.writeRawVarint32((uint32_t) val);
611}
612
613inline void
614ProtoOutputStream::writeBoolImpl(uint32_t id, bool val)
615{
Yi Jin974a9c22017-10-02 18:37:08 -0700616 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
617 mBuffer.writeRawVarint32(val ? 1 : 0);
618}
619
620inline void
621ProtoOutputStream::writeUtf8StringImpl(uint32_t id, const char* val, size_t size)
622{
Yi Jin04625ad2017-10-17 18:29:33 -0700623 if (val == NULL) return;
Yi Jin42711a02017-10-11 18:20:24 -0700624 writeLengthDelimitedHeader(id, size);
Yi Jin974a9c22017-10-02 18:37:08 -0700625 for (size_t i=0; i<size; i++) {
626 mBuffer.writeRawByte((uint8_t)val[i]);
627 }
628}
629
Yi Jin8ad19382017-10-30 16:07:20 -0700630inline void
631ProtoOutputStream::writeMessageBytesImpl(uint32_t id, const char* val, size_t size)
632{
633 if (val == NULL) return;
634 writeLengthDelimitedHeader(id, size);
635 for (size_t i=0; i<size; i++) {
636 mBuffer.writeRawByte(val[i]);
637 }
638}
639
Yi Jin974a9c22017-10-02 18:37:08 -0700640} // util
641} // android
642