blob: 15144ac2eb28d941af7504dfb0c9ecadeaeed4f5 [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
228ProtoOutputStream::write(uint64_t fieldId, const char* val)
229{
230 if (mCompact) return false;
231 const uint32_t id = (uint32_t)fieldId;
232 int size = 0;
233 while (val[size] != '\0') size++;
234 switch (fieldId & FIELD_TYPE_MASK) {
235 case TYPE_STRING:
236 writeUtf8StringImpl(id, val, size);
237 return true;
238 default:
239 ALOGW("Field type %d is not supported when writing char[] val.",
240 (int)((fieldId & FIELD_TYPE_MASK) >> FIELD_TYPE_SHIFT));
241 return false;
242 }
243}
244
245/**
246 * Make a token.
247 * Bits 61-63 - tag size (So we can go backwards later if the object had not data)
248 * - 3 bits, max value 7, max value needed 5
249 * Bit 60 - true if the object is repeated
250 * Bits 59-51 - depth (For error checking)
251 * - 9 bits, max value 512, when checking, value is masked (if we really
252 * are more than 512 levels deep)
253 * Bits 32-50 - objectId (For error checking)
254 * - 19 bits, max value 524,288. that's a lot of objects. IDs will wrap
255 * because of the overflow, and only the tokens are compared.
256 * Bits 0-31 - offset of the first size field in the buffer.
257 */
258long long
259makeToken(int tagSize, bool repeated, int depth, int objectId, int sizePos) {
260 return ((0x07L & (long long)tagSize) << 61)
261 | (repeated ? (1LL << 60) : 0)
262 | (0x01ffL & (long long)depth) << 51
263 | (0x07ffffL & (long long)objectId) << 32
264 | (0x0ffffffffL & (long long)sizePos);
265}
266
267/**
268 * Get the encoded tag size from the token.
269 */
270static int getTagSizeFromToken(long long token) {
271 return (int)(0x7 & (token >> 61));
272}
273
274/**
275 * Get the nesting depth of startObject calls from the token.
276 */
277static int getDepthFromToken(long long token) {
278 return (int)(0x01ff & (token >> 51));
279}
280
281/**
282 * Get the location of the childRawSize (the first 32 bit size field) in this object.
283 */
284static int getSizePosFromToken(long long token) {
285 return (int)token;
286}
287
288long long
289ProtoOutputStream::start(uint64_t fieldId)
290{
291 if ((fieldId & FIELD_TYPE_MASK) != TYPE_MESSAGE) {
292 ALOGE("Can't call start for non-message type field: 0x%llx", (long long)fieldId);
293 return 0;
294 }
295
296 uint32_t id = (uint32_t)fieldId;
297 mBuffer.writeHeader(id, WIRE_TYPE_LENGTH_DELIMITED);
298
299 size_t sizePos = mBuffer.wp()->pos();
300
301 mDepth++;
302 mObjectId++;
303 mBuffer.writeRawFixed64(mExpectedObjectToken); // push previous token into stack.
304
305 mExpectedObjectToken = makeToken(get_varint_size(id),
306 (bool)(fieldId & FIELD_COUNT_REPEATED), mDepth, mObjectId, sizePos);
307 return mExpectedObjectToken;
308}
309
310void
311ProtoOutputStream::end(long long token)
312{
313 if (token != mExpectedObjectToken) {
314 ALOGE("Unexpected token: 0x%llx, should be 0x%llx", token, mExpectedObjectToken);
315 return;
316 }
317
318 int depth = getDepthFromToken(token);
319 if (depth != (mDepth & 0x01ff)) {
320 ALOGE("Unexpected depth: %d, should be %d", depth, mDepth);
321 return;
322 }
323 mDepth--;
324
325 int sizePos = getSizePosFromToken(token);
326 // number of bytes written in this start-end session.
327 int childRawSize = mBuffer.wp()->pos() - sizePos - 8;
328
329 // retrieve the old token from stack.
330 mBuffer.ep()->rewind()->move(sizePos);
331 mExpectedObjectToken = mBuffer.readRawFixed64();
332
333 // If raw size is larger than 0, write the negative value here to indicate a compact is needed.
334 if (childRawSize > 0) {
335 mBuffer.editRawFixed32(sizePos, -childRawSize);
336 mBuffer.editRawFixed32(sizePos+4, -1);
337 } else {
338 // reset wp which erase the header tag of the message when its size is 0.
339 mBuffer.wp()->rewind()->move(sizePos - getTagSizeFromToken(token));
340 }
341}
342
343bool
344ProtoOutputStream::compact() {
345 if (mCompact) return true;
346 if (mDepth != 0) {
347 ALOGE("Can't compact when depth(%d) is not zero. Missing calls to end.", mDepth);
348 return false;
349 }
350 // record the size of the original buffer.
351 size_t rawBufferSize = mBuffer.size();
352 if (rawBufferSize == 0) return true; // nothing to do if the buffer is empty;
353
354 // reset edit pointer and recursively compute encoded size of messages.
355 mBuffer.ep()->rewind();
356 if (editEncodedSize(rawBufferSize) == 0) {
357 ALOGE("Failed to editEncodedSize.");
358 return false;
359 }
360
361 // reset both edit pointer and write pointer, and compact recursively.
362 mBuffer.ep()->rewind();
363 mBuffer.wp()->rewind();
364 if (!compactSize(rawBufferSize)) {
365 ALOGE("Failed to compactSize.");
366 return false;
367 }
368 // copy the reset to the buffer.
369 if (mCopyBegin < rawBufferSize) {
370 mBuffer.copy(mCopyBegin, rawBufferSize - mCopyBegin);
371 }
372
373 // mark true means it is not legal to write to this ProtoOutputStream anymore
374 mCompact = true;
375 return true;
376}
377
378/**
379 * First compaction pass. Iterate through the data, and fill in the
380 * nested object sizes so the next pass can compact them.
381 */
382size_t
383ProtoOutputStream::editEncodedSize(size_t rawSize)
384{
385 size_t objectStart = mBuffer.ep()->pos();
386 size_t objectEnd = objectStart + rawSize;
387 size_t encodedSize = 0;
388 int childRawSize, childEncodedSize;
389 size_t childEncodedSizePos;
390
391 while (mBuffer.ep()->pos() < objectEnd) {
392 uint32_t tag = (uint32_t)mBuffer.readRawVarint();
393 encodedSize += get_varint_size(tag);
394 switch (read_wire_type(tag)) {
395 case WIRE_TYPE_VARINT:
396 do {
397 encodedSize++;
398 } while ((mBuffer.readRawByte() & 0x80) != 0);
399 break;
400 case WIRE_TYPE_FIXED64:
401 encodedSize += 8;
402 mBuffer.ep()->move(8);
403 break;
404 case WIRE_TYPE_LENGTH_DELIMITED:
405 childRawSize = (int)mBuffer.readRawFixed32();
406 childEncodedSizePos = mBuffer.ep()->pos();
407 childEncodedSize = (int)mBuffer.readRawFixed32();
408 if (childRawSize >= 0 && childRawSize == childEncodedSize) {
409 mBuffer.ep()->move(childRawSize);
410 } else if (childRawSize < 0 && childEncodedSize == -1){
411 childEncodedSize = editEncodedSize(-childRawSize);
412 mBuffer.editRawFixed32(childEncodedSizePos, childEncodedSize);
413 } else {
414 ALOGE("Bad raw or encoded values: raw=%d, encoded=%d at %zu",
415 childRawSize, childEncodedSize, childEncodedSizePos);
416 return 0;
417 }
418 encodedSize += get_varint_size(childEncodedSize) + childEncodedSize;
419 break;
420 case WIRE_TYPE_FIXED32:
421 encodedSize += 4;
422 mBuffer.ep()->move(4);
423 break;
424 default:
425 ALOGE("Unexpected wire type %d in editEncodedSize at [%zu, %zu]",
426 read_wire_type(tag), objectStart, objectEnd);
427 return 0;
428 }
429 }
430 return encodedSize;
431}
432
433/**
434 * Second compaction pass. Iterate through the data, and copy the data
435 * forward in the buffer, converting the pairs of uint32s into a single
436 * unsigned varint of the size.
437 */
438bool
439ProtoOutputStream::compactSize(size_t rawSize)
440{
441 size_t objectStart = mBuffer.ep()->pos();
442 size_t objectEnd = objectStart + rawSize;
443 int childRawSize, childEncodedSize;
444
445 while (mBuffer.ep()->pos() < objectEnd) {
446 uint32_t tag = (uint32_t)mBuffer.readRawVarint();
447 switch (read_wire_type(tag)) {
448 case WIRE_TYPE_VARINT:
449 while ((mBuffer.readRawByte() & 0x80) != 0) {}
450 break;
451 case WIRE_TYPE_FIXED64:
452 mBuffer.ep()->move(8);
453 break;
454 case WIRE_TYPE_LENGTH_DELIMITED:
455 mBuffer.copy(mCopyBegin, mBuffer.ep()->pos() - mCopyBegin);
456
457 childRawSize = (int)mBuffer.readRawFixed32();
458 childEncodedSize = (int)mBuffer.readRawFixed32();
459 mCopyBegin = mBuffer.ep()->pos();
460
461 // write encoded size to buffer.
462 mBuffer.writeRawVarint32(childEncodedSize);
463 if (childRawSize >= 0 && childRawSize == childEncodedSize) {
464 mBuffer.ep()->move(childEncodedSize);
465 } else if (childRawSize < 0){
466 if (!compactSize(-childRawSize)) return false;
467 } else {
468 ALOGE("Bad raw or encoded values: raw=%d, encoded=%d",
469 childRawSize, childEncodedSize);
470 return false;
471 }
472 break;
473 case WIRE_TYPE_FIXED32:
474 mBuffer.ep()->move(4);
475 break;
476 default:
477 ALOGE("Unexpected wire type %d in compactSize at [%zu, %zu]",
478 read_wire_type(tag), objectStart, objectEnd);
479 return false;
480 }
481 }
482 return true;
483}
484
Yi Jin42711a02017-10-11 18:20:24 -0700485size_t
486ProtoOutputStream::size()
487{
488 compact();
489 return mBuffer.size();
490}
491
Yi Jin974a9c22017-10-02 18:37:08 -0700492static bool write_all(int fd, uint8_t const* buf, size_t size)
493{
494 while (size > 0) {
495 ssize_t amt = ::write(fd, buf, size);
496 if (amt < 0) {
497 return false;
498 }
499 size -= amt;
500 buf += amt;
501 }
502 return true;
503}
504
505bool
Yi Jin42711a02017-10-11 18:20:24 -0700506ProtoOutputStream::flush(int fd)
Yi Jin974a9c22017-10-02 18:37:08 -0700507{
Yi Jin42711a02017-10-11 18:20:24 -0700508 if (fd < 0) return false;
Yi Jin974a9c22017-10-02 18:37:08 -0700509 if (!compact()) return false;
510
511 EncodedBuffer::iterator it = mBuffer.begin();
512 while (it.readBuffer() != NULL) {
Yi Jin42711a02017-10-11 18:20:24 -0700513 if (!write_all(fd, it.readBuffer(), it.currentToRead())) return false;
Yi Jin974a9c22017-10-02 18:37:08 -0700514 it.rp()->move(it.currentToRead());
515 }
516 return true;
517}
518
Yi Jin42711a02017-10-11 18:20:24 -0700519EncodedBuffer::iterator
520ProtoOutputStream::data()
521{
522 compact();
523 return mBuffer.begin();
524}
525
526void
527ProtoOutputStream::writeRawVarint(uint64_t varint)
528{
529 mBuffer.writeRawVarint64(varint);
530}
531
532void
533ProtoOutputStream::writeLengthDelimitedHeader(uint32_t id, size_t size)
534{
535 mBuffer.writeHeader(id, WIRE_TYPE_LENGTH_DELIMITED);
536 // reserves 64 bits for length delimited fields, if first field is negative, compact it.
537 mBuffer.writeRawFixed32(size);
538 mBuffer.writeRawFixed32(size);
539}
540
541void
542ProtoOutputStream::writeRawByte(uint8_t byte)
543{
544 mBuffer.writeRawByte(byte);
545}
546
Yi Jin974a9c22017-10-02 18:37:08 -0700547
548// =========================================================================
549// Private functions
550
551/**
552 * bit_cast
553 */
554template <class From, class To>
555inline To bit_cast(From const &from) {
556 To to;
557 memcpy(&to, &from, sizeof(to));
558 return to;
559}
560
561inline void
562ProtoOutputStream::writeDoubleImpl(uint32_t id, double val)
563{
564 if (val == 0.0) return;
565 mBuffer.writeHeader(id, WIRE_TYPE_FIXED64);
566 mBuffer.writeRawFixed64(bit_cast<double, uint64_t>(val));
567}
568
569inline void
570ProtoOutputStream::writeFloatImpl(uint32_t id, float val)
571{
572 if (val == 0.0) return;
573 mBuffer.writeHeader(id, WIRE_TYPE_FIXED32);
574 mBuffer.writeRawFixed32(bit_cast<float, uint32_t>(val));
575}
576
577inline void
578ProtoOutputStream::writeInt64Impl(uint32_t id, long long val)
579{
580 if (val == 0) return;
581 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
582 mBuffer.writeRawVarint64((uint64_t)val);
583}
584
585inline void
586ProtoOutputStream::writeInt32Impl(uint32_t id, int val)
587{
588 if (val == 0) return;
589 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
590 mBuffer.writeRawVarint32((uint32_t)val);
591}
592
593inline void
594ProtoOutputStream::writeUint64Impl(uint32_t id, uint64_t val)
595{
596 if (val == 0) return;
597 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
598 mBuffer.writeRawVarint64(val);
599}
600
601inline void
602ProtoOutputStream::writeUint32Impl(uint32_t id, uint32_t val)
603{
604 if (val == 0) return;
605 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
606 mBuffer.writeRawVarint32(val);
607}
608
609inline void
610ProtoOutputStream::writeFixed64Impl(uint32_t id, uint64_t val)
611{
612 if (val == 0) return;
613 mBuffer.writeHeader(id, WIRE_TYPE_FIXED64);
614 mBuffer.writeRawFixed64(val);
615}
616
617inline void
618ProtoOutputStream::writeFixed32Impl(uint32_t id, uint32_t val)
619{
620 if (val == 0) return;
621 mBuffer.writeHeader(id, WIRE_TYPE_FIXED32);
622 mBuffer.writeRawFixed32(val);
623}
624
625inline void
626ProtoOutputStream::writeSFixed64Impl(uint32_t id, long long val)
627{
628 if (val == 0) return;
629 mBuffer.writeHeader(id, WIRE_TYPE_FIXED64);
630 mBuffer.writeRawFixed64((uint64_t)val);
631}
632
633inline void
634ProtoOutputStream::writeSFixed32Impl(uint32_t id, int val)
635{
636 if (val == 0) return;
637 mBuffer.writeHeader(id, WIRE_TYPE_FIXED32);
638 mBuffer.writeRawFixed32((uint32_t)val);
639}
640
641inline void
642ProtoOutputStream::writeZigzagInt64Impl(uint32_t id, long long val)
643{
644 if (val == 0) return;
645 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
646 mBuffer.writeRawVarint64((val << 1) ^ (val >> 63));
647}
648
649inline void
650ProtoOutputStream::writeZigzagInt32Impl(uint32_t id, int val)
651{
652 if (val == 0) return;
653 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
654 mBuffer.writeRawVarint32((val << 1) ^ (val >> 31));
655}
656
657inline void
658ProtoOutputStream::writeEnumImpl(uint32_t id, int val)
659{
660 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
661 mBuffer.writeRawVarint32((uint32_t) val);
662}
663
664inline void
665ProtoOutputStream::writeBoolImpl(uint32_t id, bool val)
666{
667 if (!val) return;
668 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
669 mBuffer.writeRawVarint32(val ? 1 : 0);
670}
671
672inline void
673ProtoOutputStream::writeUtf8StringImpl(uint32_t id, const char* val, size_t size)
674{
675 if (val == NULL || size == 0) return;
Yi Jin42711a02017-10-11 18:20:24 -0700676 writeLengthDelimitedHeader(id, size);
Yi Jin974a9c22017-10-02 18:37:08 -0700677 for (size_t i=0; i<size; i++) {
678 mBuffer.writeRawByte((uint8_t)val[i]);
679 }
680}
681
682} // util
683} // android
684