blob: 9dadf1c2051012bf2146cf144a100df150b11556 [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>
21#include <cstring>
22
23namespace android {
24namespace util {
25
26/**
27 * Position of the field type in a (long long) fieldId.
28 */
29const uint64_t FIELD_TYPE_SHIFT = 32;
30
31/**
32 * Mask for the field types stored in a fieldId. Leaves a whole
33 * byte for future expansion, even though there are currently only 17 types.
34 */
35const uint64_t FIELD_TYPE_MASK = 0x0ffULL << FIELD_TYPE_SHIFT;
36
37const uint64_t FIELD_TYPE_UNKNOWN = 0;
38const uint64_t TYPE_DOUBLE = 1ULL << FIELD_TYPE_SHIFT; // double, exactly eight bytes on the wire.
39const uint64_t TYPE_FLOAT = 2ULL << FIELD_TYPE_SHIFT; // float, exactly four bytes on the wire.
40const uint64_t TYPE_INT64 = 3ULL << FIELD_TYPE_SHIFT; // int64, varint on the wire. Negative numbers
41 // take 10 bytes. Use TYPE_SINT64 if negative
42 // values are likely.
43const uint64_t TYPE_UINT64 = 4ULL << FIELD_TYPE_SHIFT; // uint64, varint on the wire.
44const uint64_t TYPE_INT32 = 5ULL << FIELD_TYPE_SHIFT; // int32, varint on the wire. Negative numbers
45 // take 10 bytes. Use TYPE_SINT32 if negative
46 // values are likely.
47const uint64_t TYPE_FIXED64 = 6ULL << FIELD_TYPE_SHIFT; // uint64, exactly eight bytes on the wire.
48const uint64_t TYPE_FIXED32 = 7ULL << FIELD_TYPE_SHIFT; // uint32, exactly four bytes on the wire.
49const uint64_t TYPE_BOOL = 8ULL << FIELD_TYPE_SHIFT; // bool, varint on the wire.
50const uint64_t TYPE_STRING = 9ULL << FIELD_TYPE_SHIFT; // UTF-8 text.
51const uint64_t TYPE_GROUP = 10ULL << FIELD_TYPE_SHIFT; // Tag-delimited message. Deprecated.
52const uint64_t TYPE_MESSAGE = 11ULL << FIELD_TYPE_SHIFT; // Length-delimited message.
53
54const uint64_t TYPE_BYTES = 12ULL << FIELD_TYPE_SHIFT; // Arbitrary byte array.
55const uint64_t TYPE_UINT32 = 13ULL << FIELD_TYPE_SHIFT; // uint32, varint on the wire
56const uint64_t TYPE_ENUM = 14ULL << FIELD_TYPE_SHIFT; // Enum, varint on the wire
57const uint64_t TYPE_SFIXED32 = 15ULL << FIELD_TYPE_SHIFT; // int32, exactly four bytes on the wire
58const uint64_t TYPE_SFIXED64 = 16ULL << FIELD_TYPE_SHIFT; // int64, exactly eight bytes on the wire
59const uint64_t TYPE_SINT32 = 17ULL << FIELD_TYPE_SHIFT; // int32, ZigZag-encoded varint on the wire
60const uint64_t TYPE_SINT64 = 18ULL << FIELD_TYPE_SHIFT; // int64, ZigZag-encoded varint on the wire
61
62//
63// FieldId flags for whether the field is single, repeated or packed.
64// TODO: packed is not supported yet.
65//
66const uint64_t FIELD_COUNT_SHIFT = 40;
67const uint64_t FIELD_COUNT_MASK = 0x0fULL << FIELD_COUNT_SHIFT;
68const uint64_t FIELD_COUNT_UNKNOWN = 0;
69const uint64_t FIELD_COUNT_SINGLE = 1ULL << FIELD_COUNT_SHIFT;
70const uint64_t FIELD_COUNT_REPEATED = 2ULL << FIELD_COUNT_SHIFT;
71const uint64_t FIELD_COUNT_PACKED = 4ULL << FIELD_COUNT_SHIFT;
72
Yi Jin42711a02017-10-11 18:20:24 -070073ProtoOutputStream::ProtoOutputStream()
Yi Jin974a9c22017-10-02 18:37:08 -070074 :mBuffer(),
Yi Jin974a9c22017-10-02 18:37:08 -070075 mCopyBegin(0),
76 mCompact(false),
77 mDepth(0),
78 mObjectId(0),
79 mExpectedObjectToken(0LL)
80{
81}
82
83ProtoOutputStream::~ProtoOutputStream()
84{
85}
86
87bool
88ProtoOutputStream::write(uint64_t fieldId, double val)
89{
90 if (mCompact) return false;
91 const uint32_t id = (uint32_t)fieldId;
92 switch (fieldId & FIELD_TYPE_MASK) {
93 case TYPE_DOUBLE: writeDoubleImpl(id, (double)val); break;
94 case TYPE_FLOAT: writeFloatImpl(id, (float)val); break;
95 case TYPE_INT64: writeInt64Impl(id, (long long)val); break;
96 case TYPE_UINT64: writeUint64Impl(id, (uint64_t)val); break;
97 case TYPE_INT32: writeInt32Impl(id, (int)val); break;
98 case TYPE_FIXED64: writeFixed64Impl(id, (uint64_t)val); break;
99 case TYPE_FIXED32: writeFixed32Impl(id, (uint32_t)val); break;
100 case TYPE_UINT32: writeUint32Impl(id, (uint32_t)val); break;
101 case TYPE_SFIXED32: writeSFixed32Impl(id, (int)val); break;
102 case TYPE_SFIXED64: writeSFixed64Impl(id, (long long)val); break;
103 case TYPE_SINT32: writeZigzagInt32Impl(id, (int)val); break;
104 case TYPE_SINT64: writeZigzagInt64Impl(id, (long long)val); break;
105 default:
106 ALOGW("Field type %d is not supported when writing double val.",
107 (int)((fieldId & FIELD_TYPE_MASK) >> FIELD_TYPE_SHIFT));
108 return false;
109 }
110 return true;
111}
112
113bool
114ProtoOutputStream::write(uint64_t fieldId, float val)
115{
116 if (mCompact) return false;
117 const uint32_t id = (uint32_t)fieldId;
118 switch (fieldId & FIELD_TYPE_MASK) {
119 case TYPE_DOUBLE: writeDoubleImpl(id, (double)val); break;
120 case TYPE_FLOAT: writeFloatImpl(id, (float)val); break;
121 case TYPE_INT64: writeInt64Impl(id, (long long)val); break;
122 case TYPE_UINT64: writeUint64Impl(id, (uint64_t)val); break;
123 case TYPE_INT32: writeInt32Impl(id, (int)val); break;
124 case TYPE_FIXED64: writeFixed64Impl(id, (uint64_t)val); break;
125 case TYPE_FIXED32: writeFixed32Impl(id, (uint32_t)val); break;
126 case TYPE_UINT32: writeUint32Impl(id, (uint32_t)val); break;
127 case TYPE_SFIXED32: writeSFixed32Impl(id, (int)val); break;
128 case TYPE_SFIXED64: writeSFixed64Impl(id, (long long)val); break;
129 case TYPE_SINT32: writeZigzagInt32Impl(id, (int)val); break;
130 case TYPE_SINT64: writeZigzagInt64Impl(id, (long long)val); break;
131 default:
132 ALOGW("Field type %d is not supported when writing float val.",
133 (int)((fieldId & FIELD_TYPE_MASK) >> FIELD_TYPE_SHIFT));
134 return false;
135 }
136 return true;
137}
138
139bool
140ProtoOutputStream::write(uint64_t fieldId, int val)
141{
142 if (mCompact) return false;
143 const uint32_t id = (uint32_t)fieldId;
144 switch (fieldId & FIELD_TYPE_MASK) {
145 case TYPE_DOUBLE: writeDoubleImpl(id, (double)val); break;
146 case TYPE_FLOAT: writeFloatImpl(id, (float)val); break;
147 case TYPE_INT64: writeInt64Impl(id, (long long)val); break;
148 case TYPE_UINT64: writeUint64Impl(id, (uint64_t)val); break;
149 case TYPE_INT32: writeInt32Impl(id, (int)val); break;
150 case TYPE_FIXED64: writeFixed64Impl(id, (uint64_t)val); break;
151 case TYPE_FIXED32: writeFixed32Impl(id, (uint32_t)val); break;
152 case TYPE_UINT32: writeUint32Impl(id, (uint32_t)val); break;
153 case TYPE_SFIXED32: writeSFixed32Impl(id, (int)val); break;
154 case TYPE_SFIXED64: writeSFixed64Impl(id, (long long)val); break;
155 case TYPE_SINT32: writeZigzagInt32Impl(id, (int)val); break;
156 case TYPE_SINT64: writeZigzagInt64Impl(id, (long long)val); break;
157 case TYPE_ENUM: writeEnumImpl(id, (int)val); break;
158 case TYPE_BOOL: writeBoolImpl(id, val != 0); break;
159 default:
160 ALOGW("Field type %d is not supported when writing int val.",
161 (int)((fieldId & FIELD_TYPE_MASK) >> FIELD_TYPE_SHIFT));
162 return false;
163 }
164 return true;
165}
166
167bool
168ProtoOutputStream::write(uint64_t fieldId, long long val)
169{
170 if (mCompact) return false;
171 const uint32_t id = (uint32_t)fieldId;
172 switch (fieldId & FIELD_TYPE_MASK) {
173 case TYPE_DOUBLE: writeDoubleImpl(id, (double)val); break;
174 case TYPE_FLOAT: writeFloatImpl(id, (float)val); break;
175 case TYPE_INT64: writeInt64Impl(id, (long long)val); break;
176 case TYPE_UINT64: writeUint64Impl(id, (uint64_t)val); break;
177 case TYPE_INT32: writeInt32Impl(id, (int)val); break;
178 case TYPE_FIXED64: writeFixed64Impl(id, (uint64_t)val); break;
179 case TYPE_FIXED32: writeFixed32Impl(id, (uint32_t)val); break;
180 case TYPE_UINT32: writeUint32Impl(id, (uint32_t)val); break;
181 case TYPE_SFIXED32: writeSFixed32Impl(id, (int)val); break;
182 case TYPE_SFIXED64: writeSFixed64Impl(id, (long long)val); break;
183 case TYPE_SINT32: writeZigzagInt32Impl(id, (int)val); break;
184 case TYPE_SINT64: writeZigzagInt64Impl(id, (long long)val); break;
185 case TYPE_ENUM: writeEnumImpl(id, (int)val); break;
186 case TYPE_BOOL: writeBoolImpl(id, val != 0); break;
187 default:
188 ALOGW("Field type %d is not supported when writing long long val.",
189 (int)((fieldId & FIELD_TYPE_MASK) >> FIELD_TYPE_SHIFT));
190 return false;
191 }
192 return true;
193}
194
195bool
196ProtoOutputStream::write(uint64_t fieldId, bool val)
197{
198 if (mCompact) return false;
199 const uint32_t id = (uint32_t)fieldId;
200 switch (fieldId & FIELD_TYPE_MASK) {
201 case TYPE_BOOL:
202 writeBoolImpl(id, val);
203 return true;
204 default:
205 ALOGW("Field type %d is not supported when writing bool val.",
206 (int)((fieldId & FIELD_TYPE_MASK) >> FIELD_TYPE_SHIFT));
207 return false;
208 }
209}
210
211bool
212ProtoOutputStream::write(uint64_t fieldId, string val)
213{
214 if (mCompact) return false;
215 const uint32_t id = (uint32_t)fieldId;
216 switch (fieldId & FIELD_TYPE_MASK) {
217 case TYPE_STRING:
218 writeUtf8StringImpl(id, val.c_str(), val.size());
219 return true;
220 default:
221 ALOGW("Field type %d is not supported when writing string val.",
222 (int)((fieldId & FIELD_TYPE_MASK) >> FIELD_TYPE_SHIFT));
223 return false;
224 }
225}
226
227bool
Yi Jine0833302017-10-23 15:42:44 -0700228ProtoOutputStream::write(uint64_t fieldId, const char* val, size_t size)
Yi Jin974a9c22017-10-02 18:37:08 -0700229{
230 if (mCompact) return false;
231 const uint32_t id = (uint32_t)fieldId;
Yi Jin974a9c22017-10-02 18:37:08 -0700232 switch (fieldId & FIELD_TYPE_MASK) {
233 case TYPE_STRING:
Yi Jine0833302017-10-23 15:42:44 -0700234 case TYPE_BYTES:
Yi Jin974a9c22017-10-02 18:37:08 -0700235 writeUtf8StringImpl(id, val, size);
236 return true;
237 default:
238 ALOGW("Field type %d is not supported when writing char[] val.",
239 (int)((fieldId & FIELD_TYPE_MASK) >> FIELD_TYPE_SHIFT));
240 return false;
241 }
242}
243
244/**
245 * Make a token.
246 * Bits 61-63 - tag size (So we can go backwards later if the object had not data)
247 * - 3 bits, max value 7, max value needed 5
248 * Bit 60 - true if the object is repeated
249 * Bits 59-51 - depth (For error checking)
250 * - 9 bits, max value 512, when checking, value is masked (if we really
251 * are more than 512 levels deep)
252 * Bits 32-50 - objectId (For error checking)
253 * - 19 bits, max value 524,288. that's a lot of objects. IDs will wrap
254 * because of the overflow, and only the tokens are compared.
255 * Bits 0-31 - offset of the first size field in the buffer.
256 */
257long long
258makeToken(int tagSize, bool repeated, int depth, int objectId, int sizePos) {
259 return ((0x07L & (long long)tagSize) << 61)
260 | (repeated ? (1LL << 60) : 0)
261 | (0x01ffL & (long long)depth) << 51
262 | (0x07ffffL & (long long)objectId) << 32
263 | (0x0ffffffffL & (long long)sizePos);
264}
265
266/**
267 * Get the encoded tag size from the token.
268 */
269static int getTagSizeFromToken(long long token) {
270 return (int)(0x7 & (token >> 61));
271}
272
273/**
274 * Get the nesting depth of startObject calls from the token.
275 */
276static int getDepthFromToken(long long token) {
277 return (int)(0x01ff & (token >> 51));
278}
279
280/**
281 * Get the location of the childRawSize (the first 32 bit size field) in this object.
282 */
283static int getSizePosFromToken(long long token) {
284 return (int)token;
285}
286
287long long
288ProtoOutputStream::start(uint64_t fieldId)
289{
290 if ((fieldId & FIELD_TYPE_MASK) != TYPE_MESSAGE) {
291 ALOGE("Can't call start for non-message type field: 0x%llx", (long long)fieldId);
292 return 0;
293 }
294
295 uint32_t id = (uint32_t)fieldId;
296 mBuffer.writeHeader(id, WIRE_TYPE_LENGTH_DELIMITED);
297
298 size_t sizePos = mBuffer.wp()->pos();
299
300 mDepth++;
301 mObjectId++;
302 mBuffer.writeRawFixed64(mExpectedObjectToken); // push previous token into stack.
303
304 mExpectedObjectToken = makeToken(get_varint_size(id),
305 (bool)(fieldId & FIELD_COUNT_REPEATED), mDepth, mObjectId, sizePos);
306 return mExpectedObjectToken;
307}
308
309void
310ProtoOutputStream::end(long long token)
311{
312 if (token != mExpectedObjectToken) {
313 ALOGE("Unexpected token: 0x%llx, should be 0x%llx", token, mExpectedObjectToken);
314 return;
315 }
316
317 int depth = getDepthFromToken(token);
318 if (depth != (mDepth & 0x01ff)) {
319 ALOGE("Unexpected depth: %d, should be %d", depth, mDepth);
320 return;
321 }
322 mDepth--;
323
324 int sizePos = getSizePosFromToken(token);
325 // number of bytes written in this start-end session.
326 int childRawSize = mBuffer.wp()->pos() - sizePos - 8;
327
328 // retrieve the old token from stack.
329 mBuffer.ep()->rewind()->move(sizePos);
330 mExpectedObjectToken = mBuffer.readRawFixed64();
331
332 // If raw size is larger than 0, write the negative value here to indicate a compact is needed.
333 if (childRawSize > 0) {
334 mBuffer.editRawFixed32(sizePos, -childRawSize);
335 mBuffer.editRawFixed32(sizePos+4, -1);
336 } else {
337 // reset wp which erase the header tag of the message when its size is 0.
338 mBuffer.wp()->rewind()->move(sizePos - getTagSizeFromToken(token));
339 }
340}
341
342bool
343ProtoOutputStream::compact() {
344 if (mCompact) return true;
345 if (mDepth != 0) {
346 ALOGE("Can't compact when depth(%d) is not zero. Missing calls to end.", mDepth);
347 return false;
348 }
349 // record the size of the original buffer.
350 size_t rawBufferSize = mBuffer.size();
351 if (rawBufferSize == 0) return true; // nothing to do if the buffer is empty;
352
353 // reset edit pointer and recursively compute encoded size of messages.
354 mBuffer.ep()->rewind();
355 if (editEncodedSize(rawBufferSize) == 0) {
356 ALOGE("Failed to editEncodedSize.");
357 return false;
358 }
359
360 // reset both edit pointer and write pointer, and compact recursively.
361 mBuffer.ep()->rewind();
362 mBuffer.wp()->rewind();
363 if (!compactSize(rawBufferSize)) {
364 ALOGE("Failed to compactSize.");
365 return false;
366 }
367 // copy the reset to the buffer.
368 if (mCopyBegin < rawBufferSize) {
369 mBuffer.copy(mCopyBegin, rawBufferSize - mCopyBegin);
370 }
371
372 // mark true means it is not legal to write to this ProtoOutputStream anymore
373 mCompact = true;
374 return true;
375}
376
377/**
378 * First compaction pass. Iterate through the data, and fill in the
379 * nested object sizes so the next pass can compact them.
380 */
381size_t
382ProtoOutputStream::editEncodedSize(size_t rawSize)
383{
384 size_t objectStart = mBuffer.ep()->pos();
385 size_t objectEnd = objectStart + rawSize;
386 size_t encodedSize = 0;
387 int childRawSize, childEncodedSize;
388 size_t childEncodedSizePos;
389
390 while (mBuffer.ep()->pos() < objectEnd) {
391 uint32_t tag = (uint32_t)mBuffer.readRawVarint();
392 encodedSize += get_varint_size(tag);
393 switch (read_wire_type(tag)) {
394 case WIRE_TYPE_VARINT:
395 do {
396 encodedSize++;
397 } while ((mBuffer.readRawByte() & 0x80) != 0);
398 break;
399 case WIRE_TYPE_FIXED64:
400 encodedSize += 8;
401 mBuffer.ep()->move(8);
402 break;
403 case WIRE_TYPE_LENGTH_DELIMITED:
404 childRawSize = (int)mBuffer.readRawFixed32();
405 childEncodedSizePos = mBuffer.ep()->pos();
406 childEncodedSize = (int)mBuffer.readRawFixed32();
407 if (childRawSize >= 0 && childRawSize == childEncodedSize) {
408 mBuffer.ep()->move(childRawSize);
409 } else if (childRawSize < 0 && childEncodedSize == -1){
410 childEncodedSize = editEncodedSize(-childRawSize);
411 mBuffer.editRawFixed32(childEncodedSizePos, childEncodedSize);
412 } else {
413 ALOGE("Bad raw or encoded values: raw=%d, encoded=%d at %zu",
414 childRawSize, childEncodedSize, childEncodedSizePos);
415 return 0;
416 }
417 encodedSize += get_varint_size(childEncodedSize) + childEncodedSize;
418 break;
419 case WIRE_TYPE_FIXED32:
420 encodedSize += 4;
421 mBuffer.ep()->move(4);
422 break;
423 default:
424 ALOGE("Unexpected wire type %d in editEncodedSize at [%zu, %zu]",
425 read_wire_type(tag), objectStart, objectEnd);
426 return 0;
427 }
428 }
429 return encodedSize;
430}
431
432/**
433 * Second compaction pass. Iterate through the data, and copy the data
434 * forward in the buffer, converting the pairs of uint32s into a single
435 * unsigned varint of the size.
436 */
437bool
438ProtoOutputStream::compactSize(size_t rawSize)
439{
440 size_t objectStart = mBuffer.ep()->pos();
441 size_t objectEnd = objectStart + rawSize;
442 int childRawSize, childEncodedSize;
443
444 while (mBuffer.ep()->pos() < objectEnd) {
445 uint32_t tag = (uint32_t)mBuffer.readRawVarint();
446 switch (read_wire_type(tag)) {
447 case WIRE_TYPE_VARINT:
448 while ((mBuffer.readRawByte() & 0x80) != 0) {}
449 break;
450 case WIRE_TYPE_FIXED64:
451 mBuffer.ep()->move(8);
452 break;
453 case WIRE_TYPE_LENGTH_DELIMITED:
454 mBuffer.copy(mCopyBegin, mBuffer.ep()->pos() - mCopyBegin);
455
456 childRawSize = (int)mBuffer.readRawFixed32();
457 childEncodedSize = (int)mBuffer.readRawFixed32();
458 mCopyBegin = mBuffer.ep()->pos();
459
460 // write encoded size to buffer.
461 mBuffer.writeRawVarint32(childEncodedSize);
462 if (childRawSize >= 0 && childRawSize == childEncodedSize) {
463 mBuffer.ep()->move(childEncodedSize);
464 } else if (childRawSize < 0){
465 if (!compactSize(-childRawSize)) return false;
466 } else {
467 ALOGE("Bad raw or encoded values: raw=%d, encoded=%d",
468 childRawSize, childEncodedSize);
469 return false;
470 }
471 break;
472 case WIRE_TYPE_FIXED32:
473 mBuffer.ep()->move(4);
474 break;
475 default:
476 ALOGE("Unexpected wire type %d in compactSize at [%zu, %zu]",
477 read_wire_type(tag), objectStart, objectEnd);
478 return false;
479 }
480 }
481 return true;
482}
483
Yi Jin42711a02017-10-11 18:20:24 -0700484size_t
485ProtoOutputStream::size()
486{
487 compact();
488 return mBuffer.size();
489}
490
Yi Jin974a9c22017-10-02 18:37:08 -0700491static bool write_all(int fd, uint8_t const* buf, size_t size)
492{
493 while (size > 0) {
494 ssize_t amt = ::write(fd, buf, size);
495 if (amt < 0) {
496 return false;
497 }
498 size -= amt;
499 buf += amt;
500 }
501 return true;
502}
503
504bool
Yi Jin42711a02017-10-11 18:20:24 -0700505ProtoOutputStream::flush(int fd)
Yi Jin974a9c22017-10-02 18:37:08 -0700506{
Yi Jin42711a02017-10-11 18:20:24 -0700507 if (fd < 0) return false;
Yi Jin974a9c22017-10-02 18:37:08 -0700508 if (!compact()) return false;
509
510 EncodedBuffer::iterator it = mBuffer.begin();
511 while (it.readBuffer() != NULL) {
Yi Jin42711a02017-10-11 18:20:24 -0700512 if (!write_all(fd, it.readBuffer(), it.currentToRead())) return false;
Yi Jin974a9c22017-10-02 18:37:08 -0700513 it.rp()->move(it.currentToRead());
514 }
515 return true;
516}
517
Yi Jin42711a02017-10-11 18:20:24 -0700518EncodedBuffer::iterator
519ProtoOutputStream::data()
520{
521 compact();
522 return mBuffer.begin();
523}
524
525void
526ProtoOutputStream::writeRawVarint(uint64_t varint)
527{
528 mBuffer.writeRawVarint64(varint);
529}
530
531void
532ProtoOutputStream::writeLengthDelimitedHeader(uint32_t id, size_t size)
533{
534 mBuffer.writeHeader(id, WIRE_TYPE_LENGTH_DELIMITED);
535 // reserves 64 bits for length delimited fields, if first field is negative, compact it.
536 mBuffer.writeRawFixed32(size);
537 mBuffer.writeRawFixed32(size);
538}
539
540void
541ProtoOutputStream::writeRawByte(uint8_t byte)
542{
543 mBuffer.writeRawByte(byte);
544}
545
Yi Jin974a9c22017-10-02 18:37:08 -0700546
547// =========================================================================
548// Private functions
549
550/**
551 * bit_cast
552 */
553template <class From, class To>
554inline To bit_cast(From const &from) {
555 To to;
556 memcpy(&to, &from, sizeof(to));
557 return to;
558}
559
560inline void
561ProtoOutputStream::writeDoubleImpl(uint32_t id, double val)
562{
563 if (val == 0.0) return;
564 mBuffer.writeHeader(id, WIRE_TYPE_FIXED64);
565 mBuffer.writeRawFixed64(bit_cast<double, uint64_t>(val));
566}
567
568inline void
569ProtoOutputStream::writeFloatImpl(uint32_t id, float val)
570{
571 if (val == 0.0) return;
572 mBuffer.writeHeader(id, WIRE_TYPE_FIXED32);
573 mBuffer.writeRawFixed32(bit_cast<float, uint32_t>(val));
574}
575
576inline void
577ProtoOutputStream::writeInt64Impl(uint32_t id, long long val)
578{
579 if (val == 0) return;
580 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
581 mBuffer.writeRawVarint64((uint64_t)val);
582}
583
584inline void
585ProtoOutputStream::writeInt32Impl(uint32_t id, int val)
586{
587 if (val == 0) return;
588 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
589 mBuffer.writeRawVarint32((uint32_t)val);
590}
591
592inline void
593ProtoOutputStream::writeUint64Impl(uint32_t id, uint64_t val)
594{
595 if (val == 0) return;
596 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
597 mBuffer.writeRawVarint64(val);
598}
599
600inline void
601ProtoOutputStream::writeUint32Impl(uint32_t id, uint32_t val)
602{
603 if (val == 0) return;
604 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
605 mBuffer.writeRawVarint32(val);
606}
607
608inline void
609ProtoOutputStream::writeFixed64Impl(uint32_t id, uint64_t val)
610{
611 if (val == 0) return;
612 mBuffer.writeHeader(id, WIRE_TYPE_FIXED64);
613 mBuffer.writeRawFixed64(val);
614}
615
616inline void
617ProtoOutputStream::writeFixed32Impl(uint32_t id, uint32_t val)
618{
619 if (val == 0) return;
620 mBuffer.writeHeader(id, WIRE_TYPE_FIXED32);
621 mBuffer.writeRawFixed32(val);
622}
623
624inline void
625ProtoOutputStream::writeSFixed64Impl(uint32_t id, long long val)
626{
627 if (val == 0) return;
628 mBuffer.writeHeader(id, WIRE_TYPE_FIXED64);
629 mBuffer.writeRawFixed64((uint64_t)val);
630}
631
632inline void
633ProtoOutputStream::writeSFixed32Impl(uint32_t id, int val)
634{
635 if (val == 0) return;
636 mBuffer.writeHeader(id, WIRE_TYPE_FIXED32);
637 mBuffer.writeRawFixed32((uint32_t)val);
638}
639
640inline void
641ProtoOutputStream::writeZigzagInt64Impl(uint32_t id, long long val)
642{
643 if (val == 0) return;
644 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
645 mBuffer.writeRawVarint64((val << 1) ^ (val >> 63));
646}
647
648inline void
649ProtoOutputStream::writeZigzagInt32Impl(uint32_t id, int val)
650{
651 if (val == 0) return;
652 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
653 mBuffer.writeRawVarint32((val << 1) ^ (val >> 31));
654}
655
656inline void
657ProtoOutputStream::writeEnumImpl(uint32_t id, int val)
658{
659 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
660 mBuffer.writeRawVarint32((uint32_t) val);
661}
662
663inline void
664ProtoOutputStream::writeBoolImpl(uint32_t id, bool val)
665{
666 if (!val) return;
667 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
668 mBuffer.writeRawVarint32(val ? 1 : 0);
669}
670
671inline void
672ProtoOutputStream::writeUtf8StringImpl(uint32_t id, const char* val, size_t size)
673{
674 if (val == NULL || size == 0) return;
Yi Jin42711a02017-10-11 18:20:24 -0700675 writeLengthDelimitedHeader(id, size);
Yi Jin974a9c22017-10-02 18:37:08 -0700676 for (size_t i=0; i<size; i++) {
677 mBuffer.writeRawByte((uint8_t)val[i]);
678 }
679}
680
681} // util
682} // android
683