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