blob: af98a111322812214210ddd8abd871063fee927f [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
Yi Jin00a75442018-03-30 11:01:58 -070018#include <inttypes.h>
19
Yi Jin974a9c22017-10-02 18:37:08 -070020#include <android/util/protobuf.h>
21#include <android/util/ProtoOutputStream.h>
22#include <cutils/log.h>
Yi Jin974a9c22017-10-02 18:37:08 -070023
24namespace android {
25namespace util {
26
Yi Jin42711a02017-10-11 18:20:24 -070027ProtoOutputStream::ProtoOutputStream()
Yi Jin974a9c22017-10-02 18:37:08 -070028 :mBuffer(),
Yi Jin974a9c22017-10-02 18:37:08 -070029 mCopyBegin(0),
30 mCompact(false),
31 mDepth(0),
32 mObjectId(0),
Yi Jin00a75442018-03-30 11:01:58 -070033 mExpectedObjectToken(UINT64_C(-1))
Yi Jin974a9c22017-10-02 18:37:08 -070034{
35}
36
37ProtoOutputStream::~ProtoOutputStream()
38{
39}
40
Yi Jin7f9e63b2018-02-02 16:25:11 -080041
42void
43ProtoOutputStream::clear()
44{
45 mBuffer.clear();
46 mCopyBegin = 0;
47 mCompact = false;
48 mDepth = 0;
49 mObjectId = 0;
Yi Jin00a75442018-03-30 11:01:58 -070050 mExpectedObjectToken = UINT64_C(-1);
Yi Jin7f9e63b2018-02-02 16:25:11 -080051}
52
Yi Jin974a9c22017-10-02 18:37:08 -070053bool
54ProtoOutputStream::write(uint64_t fieldId, double val)
55{
56 if (mCompact) return false;
57 const uint32_t id = (uint32_t)fieldId;
58 switch (fieldId & FIELD_TYPE_MASK) {
Yi Jin04625ad2017-10-17 18:29:33 -070059 case FIELD_TYPE_DOUBLE: writeDoubleImpl(id, (double)val); break;
60 case FIELD_TYPE_FLOAT: writeFloatImpl(id, (float)val); break;
61 case FIELD_TYPE_INT64: writeInt64Impl(id, (long long)val); break;
62 case FIELD_TYPE_UINT64: writeUint64Impl(id, (uint64_t)val); break;
63 case FIELD_TYPE_INT32: writeInt32Impl(id, (int)val); break;
64 case FIELD_TYPE_FIXED64: writeFixed64Impl(id, (uint64_t)val); break;
65 case FIELD_TYPE_FIXED32: writeFixed32Impl(id, (uint32_t)val); break;
66 case FIELD_TYPE_UINT32: writeUint32Impl(id, (uint32_t)val); break;
67 case FIELD_TYPE_SFIXED32: writeSFixed32Impl(id, (int)val); break;
68 case FIELD_TYPE_SFIXED64: writeSFixed64Impl(id, (long long)val); break;
69 case FIELD_TYPE_SINT32: writeZigzagInt32Impl(id, (int)val); break;
70 case FIELD_TYPE_SINT64: writeZigzagInt64Impl(id, (long long)val); break;
Yi Jin974a9c22017-10-02 18:37:08 -070071 default:
72 ALOGW("Field type %d is not supported when writing double val.",
73 (int)((fieldId & FIELD_TYPE_MASK) >> FIELD_TYPE_SHIFT));
74 return false;
75 }
76 return true;
77}
78
79bool
80ProtoOutputStream::write(uint64_t fieldId, float val)
81{
82 if (mCompact) return false;
83 const uint32_t id = (uint32_t)fieldId;
84 switch (fieldId & FIELD_TYPE_MASK) {
Yi Jin04625ad2017-10-17 18:29:33 -070085 case FIELD_TYPE_DOUBLE: writeDoubleImpl(id, (double)val); break;
86 case FIELD_TYPE_FLOAT: writeFloatImpl(id, (float)val); break;
87 case FIELD_TYPE_INT64: writeInt64Impl(id, (long long)val); break;
88 case FIELD_TYPE_UINT64: writeUint64Impl(id, (uint64_t)val); break;
89 case FIELD_TYPE_INT32: writeInt32Impl(id, (int)val); break;
90 case FIELD_TYPE_FIXED64: writeFixed64Impl(id, (uint64_t)val); break;
91 case FIELD_TYPE_FIXED32: writeFixed32Impl(id, (uint32_t)val); break;
92 case FIELD_TYPE_UINT32: writeUint32Impl(id, (uint32_t)val); break;
93 case FIELD_TYPE_SFIXED32: writeSFixed32Impl(id, (int)val); break;
94 case FIELD_TYPE_SFIXED64: writeSFixed64Impl(id, (long long)val); break;
95 case FIELD_TYPE_SINT32: writeZigzagInt32Impl(id, (int)val); break;
96 case FIELD_TYPE_SINT64: writeZigzagInt64Impl(id, (long long)val); break;
Yi Jin974a9c22017-10-02 18:37:08 -070097 default:
98 ALOGW("Field type %d is not supported when writing float val.",
99 (int)((fieldId & FIELD_TYPE_MASK) >> FIELD_TYPE_SHIFT));
100 return false;
101 }
102 return true;
103}
104
105bool
106ProtoOutputStream::write(uint64_t fieldId, int val)
107{
108 if (mCompact) return false;
109 const uint32_t id = (uint32_t)fieldId;
110 switch (fieldId & FIELD_TYPE_MASK) {
Yi Jin04625ad2017-10-17 18:29:33 -0700111 case FIELD_TYPE_DOUBLE: writeDoubleImpl(id, (double)val); break;
112 case FIELD_TYPE_FLOAT: writeFloatImpl(id, (float)val); break;
113 case FIELD_TYPE_INT64: writeInt64Impl(id, (long long)val); break;
114 case FIELD_TYPE_UINT64: writeUint64Impl(id, (uint64_t)val); break;
115 case FIELD_TYPE_INT32: writeInt32Impl(id, (int)val); break;
116 case FIELD_TYPE_FIXED64: writeFixed64Impl(id, (uint64_t)val); break;
117 case FIELD_TYPE_FIXED32: writeFixed32Impl(id, (uint32_t)val); break;
118 case FIELD_TYPE_UINT32: writeUint32Impl(id, (uint32_t)val); break;
119 case FIELD_TYPE_SFIXED32: writeSFixed32Impl(id, (int)val); break;
120 case FIELD_TYPE_SFIXED64: writeSFixed64Impl(id, (long long)val); break;
121 case FIELD_TYPE_SINT32: writeZigzagInt32Impl(id, (int)val); break;
122 case FIELD_TYPE_SINT64: writeZigzagInt64Impl(id, (long long)val); break;
123 case FIELD_TYPE_ENUM: writeEnumImpl(id, (int)val); break;
124 case FIELD_TYPE_BOOL: writeBoolImpl(id, val != 0); break;
Yi Jin974a9c22017-10-02 18:37:08 -0700125 default:
126 ALOGW("Field type %d is not supported when writing int val.",
127 (int)((fieldId & FIELD_TYPE_MASK) >> FIELD_TYPE_SHIFT));
128 return false;
129 }
130 return true;
131}
132
133bool
134ProtoOutputStream::write(uint64_t fieldId, long long val)
135{
136 if (mCompact) return false;
137 const uint32_t id = (uint32_t)fieldId;
138 switch (fieldId & FIELD_TYPE_MASK) {
Yi Jin04625ad2017-10-17 18:29:33 -0700139 case FIELD_TYPE_DOUBLE: writeDoubleImpl(id, (double)val); break;
140 case FIELD_TYPE_FLOAT: writeFloatImpl(id, (float)val); break;
141 case FIELD_TYPE_INT64: writeInt64Impl(id, (long long)val); break;
142 case FIELD_TYPE_UINT64: writeUint64Impl(id, (uint64_t)val); break;
143 case FIELD_TYPE_INT32: writeInt32Impl(id, (int)val); break;
144 case FIELD_TYPE_FIXED64: writeFixed64Impl(id, (uint64_t)val); break;
145 case FIELD_TYPE_FIXED32: writeFixed32Impl(id, (uint32_t)val); break;
146 case FIELD_TYPE_UINT32: writeUint32Impl(id, (uint32_t)val); break;
147 case FIELD_TYPE_SFIXED32: writeSFixed32Impl(id, (int)val); break;
148 case FIELD_TYPE_SFIXED64: writeSFixed64Impl(id, (long long)val); break;
149 case FIELD_TYPE_SINT32: writeZigzagInt32Impl(id, (int)val); break;
150 case FIELD_TYPE_SINT64: writeZigzagInt64Impl(id, (long long)val); break;
151 case FIELD_TYPE_ENUM: writeEnumImpl(id, (int)val); break;
152 case FIELD_TYPE_BOOL: writeBoolImpl(id, val != 0); break;
Yi Jin974a9c22017-10-02 18:37:08 -0700153 default:
154 ALOGW("Field type %d is not supported when writing long long val.",
155 (int)((fieldId & FIELD_TYPE_MASK) >> FIELD_TYPE_SHIFT));
156 return false;
157 }
158 return true;
159}
160
161bool
162ProtoOutputStream::write(uint64_t fieldId, bool val)
163{
164 if (mCompact) return false;
165 const uint32_t id = (uint32_t)fieldId;
166 switch (fieldId & FIELD_TYPE_MASK) {
Yi Jin04625ad2017-10-17 18:29:33 -0700167 case FIELD_TYPE_BOOL:
Yi Jin974a9c22017-10-02 18:37:08 -0700168 writeBoolImpl(id, val);
169 return true;
170 default:
171 ALOGW("Field type %d is not supported when writing bool val.",
172 (int)((fieldId & FIELD_TYPE_MASK) >> FIELD_TYPE_SHIFT));
173 return false;
174 }
175}
176
177bool
178ProtoOutputStream::write(uint64_t fieldId, string val)
179{
180 if (mCompact) return false;
181 const uint32_t id = (uint32_t)fieldId;
182 switch (fieldId & FIELD_TYPE_MASK) {
Yi Jin04625ad2017-10-17 18:29:33 -0700183 case FIELD_TYPE_STRING:
Yi Jin974a9c22017-10-02 18:37:08 -0700184 writeUtf8StringImpl(id, val.c_str(), val.size());
185 return true;
186 default:
187 ALOGW("Field type %d is not supported when writing string val.",
188 (int)((fieldId & FIELD_TYPE_MASK) >> FIELD_TYPE_SHIFT));
189 return false;
190 }
191}
192
193bool
Yi Jine0833302017-10-23 15:42:44 -0700194ProtoOutputStream::write(uint64_t fieldId, const char* val, size_t size)
Yi Jin974a9c22017-10-02 18:37:08 -0700195{
196 if (mCompact) return false;
197 const uint32_t id = (uint32_t)fieldId;
Yi Jin974a9c22017-10-02 18:37:08 -0700198 switch (fieldId & FIELD_TYPE_MASK) {
Yi Jin04625ad2017-10-17 18:29:33 -0700199 case FIELD_TYPE_STRING:
200 case FIELD_TYPE_BYTES:
Yi Jin974a9c22017-10-02 18:37:08 -0700201 writeUtf8StringImpl(id, val, size);
202 return true;
Yi Jin04625ad2017-10-17 18:29:33 -0700203 case FIELD_TYPE_MESSAGE:
Yi Jin8ad19382017-10-30 16:07:20 -0700204 // can directly write valid format of message bytes into ProtoOutputStream without calling start/end
205 writeMessageBytesImpl(id, val, size);
206 return true;
Yi Jin974a9c22017-10-02 18:37:08 -0700207 default:
208 ALOGW("Field type %d is not supported when writing char[] val.",
209 (int)((fieldId & FIELD_TYPE_MASK) >> FIELD_TYPE_SHIFT));
210 return false;
211 }
212}
213
214/**
215 * Make a token.
216 * Bits 61-63 - tag size (So we can go backwards later if the object had not data)
217 * - 3 bits, max value 7, max value needed 5
218 * Bit 60 - true if the object is repeated
219 * Bits 59-51 - depth (For error checking)
Yi Jin00a75442018-03-30 11:01:58 -0700220 * - 9 bits, max value 511, when checking, value is masked (if we really
221 * are more than 511 levels deep)
Yi Jin974a9c22017-10-02 18:37:08 -0700222 * Bits 32-50 - objectId (For error checking)
Yi Jin00a75442018-03-30 11:01:58 -0700223 * - 19 bits, max value 524,287. that's a lot of objects. IDs will wrap
Yi Jin974a9c22017-10-02 18:37:08 -0700224 * because of the overflow, and only the tokens are compared.
225 * Bits 0-31 - offset of the first size field in the buffer.
226 */
Yi Jin00a75442018-03-30 11:01:58 -0700227static uint64_t
228makeToken(uint32_t tagSize, bool repeated, uint32_t depth, uint32_t objectId, size_t sizePos) {
229 return ((UINT64_C(0x07) & (uint64_t)tagSize) << 61)
230 | (repeated ? (UINT64_C(1) << 60) : 0)
231 | (UINT64_C(0x01ff) & (uint64_t)depth) << 51
232 | (UINT64_C(0x07ffff) & (uint64_t)objectId) << 32
233 | (UINT64_C(0x0ffffffff) & (uint64_t)sizePos);
Yi Jin974a9c22017-10-02 18:37:08 -0700234}
235
236/**
237 * Get the encoded tag size from the token.
238 */
Yi Jin00a75442018-03-30 11:01:58 -0700239static uint32_t getTagSizeFromToken(uint64_t token) {
240 return 0x7 & (token >> 61);
Yi Jin974a9c22017-10-02 18:37:08 -0700241}
242
243/**
244 * Get the nesting depth of startObject calls from the token.
245 */
Yi Jin00a75442018-03-30 11:01:58 -0700246static uint32_t getDepthFromToken(uint64_t token) {
247 return 0x01ff & (token >> 51);
Yi Jin974a9c22017-10-02 18:37:08 -0700248}
249
250/**
251 * Get the location of the childRawSize (the first 32 bit size field) in this object.
252 */
Yi Jin00a75442018-03-30 11:01:58 -0700253static uint32_t getSizePosFromToken(uint64_t token) {
254 return (uint32_t)token;
Yi Jin974a9c22017-10-02 18:37:08 -0700255}
256
Yi Jin5ee07872018-03-05 18:18:27 -0800257uint64_t
Yi Jin974a9c22017-10-02 18:37:08 -0700258ProtoOutputStream::start(uint64_t fieldId)
259{
Yi Jin04625ad2017-10-17 18:29:33 -0700260 if ((fieldId & FIELD_TYPE_MASK) != FIELD_TYPE_MESSAGE) {
Yi Jin00a75442018-03-30 11:01:58 -0700261 ALOGE("Can't call start for non-message type field: 0x%" PRIx64, fieldId);
Yi Jin974a9c22017-10-02 18:37:08 -0700262 return 0;
263 }
264
265 uint32_t id = (uint32_t)fieldId;
Yi Jin295d9b12018-02-02 14:33:20 -0800266 size_t prevPos = mBuffer.wp()->pos();
Yi Jin974a9c22017-10-02 18:37:08 -0700267 mBuffer.writeHeader(id, WIRE_TYPE_LENGTH_DELIMITED);
Yi Jin974a9c22017-10-02 18:37:08 -0700268 size_t sizePos = mBuffer.wp()->pos();
269
270 mDepth++;
271 mObjectId++;
272 mBuffer.writeRawFixed64(mExpectedObjectToken); // push previous token into stack.
273
Yi Jin295d9b12018-02-02 14:33:20 -0800274 mExpectedObjectToken = makeToken(sizePos - prevPos,
Yi Jin974a9c22017-10-02 18:37:08 -0700275 (bool)(fieldId & FIELD_COUNT_REPEATED), mDepth, mObjectId, sizePos);
276 return mExpectedObjectToken;
277}
278
279void
Yi Jin5ee07872018-03-05 18:18:27 -0800280ProtoOutputStream::end(uint64_t token)
Yi Jin974a9c22017-10-02 18:37:08 -0700281{
282 if (token != mExpectedObjectToken) {
Yi Jin00a75442018-03-30 11:01:58 -0700283 ALOGE("Unexpected token: 0x%" PRIx64 ", should be 0x%" PRIx64, token, mExpectedObjectToken);
Yi Jin974a9c22017-10-02 18:37:08 -0700284 return;
285 }
286
Yi Jin00a75442018-03-30 11:01:58 -0700287 uint32_t depth = getDepthFromToken(token);
Yi Jin974a9c22017-10-02 18:37:08 -0700288 if (depth != (mDepth & 0x01ff)) {
Yi Jin00a75442018-03-30 11:01:58 -0700289 ALOGE("Unexpected depth: %" PRIu32 ", should be %" PRIu32, depth, mDepth);
Yi Jin974a9c22017-10-02 18:37:08 -0700290 return;
291 }
292 mDepth--;
293
Yi Jin00a75442018-03-30 11:01:58 -0700294 uint32_t sizePos = getSizePosFromToken(token);
Yi Jin974a9c22017-10-02 18:37:08 -0700295 // number of bytes written in this start-end session.
296 int childRawSize = mBuffer.wp()->pos() - sizePos - 8;
297
298 // retrieve the old token from stack.
299 mBuffer.ep()->rewind()->move(sizePos);
300 mExpectedObjectToken = mBuffer.readRawFixed64();
301
302 // If raw size is larger than 0, write the negative value here to indicate a compact is needed.
303 if (childRawSize > 0) {
304 mBuffer.editRawFixed32(sizePos, -childRawSize);
305 mBuffer.editRawFixed32(sizePos+4, -1);
306 } else {
307 // reset wp which erase the header tag of the message when its size is 0.
308 mBuffer.wp()->rewind()->move(sizePos - getTagSizeFromToken(token));
309 }
310}
311
Yi Jin0abdfb02017-11-16 15:32:27 -0800312size_t
313ProtoOutputStream::bytesWritten()
314{
315 return mBuffer.size();
316}
317
Yi Jin974a9c22017-10-02 18:37:08 -0700318bool
319ProtoOutputStream::compact() {
320 if (mCompact) return true;
321 if (mDepth != 0) {
Yi Jin00a75442018-03-30 11:01:58 -0700322 ALOGE("Can't compact when depth(%" PRIu32 ") is not zero. Missing calls to end.", mDepth);
Yi Jin974a9c22017-10-02 18:37:08 -0700323 return false;
324 }
325 // record the size of the original buffer.
326 size_t rawBufferSize = mBuffer.size();
327 if (rawBufferSize == 0) return true; // nothing to do if the buffer is empty;
328
329 // reset edit pointer and recursively compute encoded size of messages.
330 mBuffer.ep()->rewind();
331 if (editEncodedSize(rawBufferSize) == 0) {
332 ALOGE("Failed to editEncodedSize.");
333 return false;
334 }
335
336 // reset both edit pointer and write pointer, and compact recursively.
337 mBuffer.ep()->rewind();
338 mBuffer.wp()->rewind();
339 if (!compactSize(rawBufferSize)) {
340 ALOGE("Failed to compactSize.");
341 return false;
342 }
343 // copy the reset to the buffer.
344 if (mCopyBegin < rawBufferSize) {
345 mBuffer.copy(mCopyBegin, rawBufferSize - mCopyBegin);
346 }
347
348 // mark true means it is not legal to write to this ProtoOutputStream anymore
349 mCompact = true;
350 return true;
351}
352
353/**
354 * First compaction pass. Iterate through the data, and fill in the
355 * nested object sizes so the next pass can compact them.
356 */
357size_t
358ProtoOutputStream::editEncodedSize(size_t rawSize)
359{
360 size_t objectStart = mBuffer.ep()->pos();
361 size_t objectEnd = objectStart + rawSize;
362 size_t encodedSize = 0;
363 int childRawSize, childEncodedSize;
364 size_t childEncodedSizePos;
365
366 while (mBuffer.ep()->pos() < objectEnd) {
367 uint32_t tag = (uint32_t)mBuffer.readRawVarint();
368 encodedSize += get_varint_size(tag);
369 switch (read_wire_type(tag)) {
370 case WIRE_TYPE_VARINT:
371 do {
372 encodedSize++;
373 } while ((mBuffer.readRawByte() & 0x80) != 0);
374 break;
375 case WIRE_TYPE_FIXED64:
376 encodedSize += 8;
377 mBuffer.ep()->move(8);
378 break;
379 case WIRE_TYPE_LENGTH_DELIMITED:
380 childRawSize = (int)mBuffer.readRawFixed32();
381 childEncodedSizePos = mBuffer.ep()->pos();
382 childEncodedSize = (int)mBuffer.readRawFixed32();
383 if (childRawSize >= 0 && childRawSize == childEncodedSize) {
384 mBuffer.ep()->move(childRawSize);
385 } else if (childRawSize < 0 && childEncodedSize == -1){
386 childEncodedSize = editEncodedSize(-childRawSize);
387 mBuffer.editRawFixed32(childEncodedSizePos, childEncodedSize);
388 } else {
389 ALOGE("Bad raw or encoded values: raw=%d, encoded=%d at %zu",
390 childRawSize, childEncodedSize, childEncodedSizePos);
391 return 0;
392 }
393 encodedSize += get_varint_size(childEncodedSize) + childEncodedSize;
394 break;
395 case WIRE_TYPE_FIXED32:
396 encodedSize += 4;
397 mBuffer.ep()->move(4);
398 break;
399 default:
400 ALOGE("Unexpected wire type %d in editEncodedSize at [%zu, %zu]",
401 read_wire_type(tag), objectStart, objectEnd);
402 return 0;
403 }
404 }
405 return encodedSize;
406}
407
408/**
409 * Second compaction pass. Iterate through the data, and copy the data
410 * forward in the buffer, converting the pairs of uint32s into a single
411 * unsigned varint of the size.
412 */
413bool
414ProtoOutputStream::compactSize(size_t rawSize)
415{
416 size_t objectStart = mBuffer.ep()->pos();
417 size_t objectEnd = objectStart + rawSize;
418 int childRawSize, childEncodedSize;
419
420 while (mBuffer.ep()->pos() < objectEnd) {
421 uint32_t tag = (uint32_t)mBuffer.readRawVarint();
422 switch (read_wire_type(tag)) {
423 case WIRE_TYPE_VARINT:
424 while ((mBuffer.readRawByte() & 0x80) != 0) {}
425 break;
426 case WIRE_TYPE_FIXED64:
427 mBuffer.ep()->move(8);
428 break;
429 case WIRE_TYPE_LENGTH_DELIMITED:
430 mBuffer.copy(mCopyBegin, mBuffer.ep()->pos() - mCopyBegin);
431
432 childRawSize = (int)mBuffer.readRawFixed32();
433 childEncodedSize = (int)mBuffer.readRawFixed32();
434 mCopyBegin = mBuffer.ep()->pos();
435
436 // write encoded size to buffer.
437 mBuffer.writeRawVarint32(childEncodedSize);
438 if (childRawSize >= 0 && childRawSize == childEncodedSize) {
439 mBuffer.ep()->move(childEncodedSize);
440 } else if (childRawSize < 0){
441 if (!compactSize(-childRawSize)) return false;
442 } else {
443 ALOGE("Bad raw or encoded values: raw=%d, encoded=%d",
444 childRawSize, childEncodedSize);
445 return false;
446 }
447 break;
448 case WIRE_TYPE_FIXED32:
449 mBuffer.ep()->move(4);
450 break;
451 default:
452 ALOGE("Unexpected wire type %d in compactSize at [%zu, %zu]",
453 read_wire_type(tag), objectStart, objectEnd);
454 return false;
455 }
456 }
457 return true;
458}
459
Yi Jin42711a02017-10-11 18:20:24 -0700460size_t
461ProtoOutputStream::size()
462{
Yi Jin00a75442018-03-30 11:01:58 -0700463 if (!compact()) {
464 ALOGE("compact failed, the ProtoOutputStream data is corrupted!");
465 // TODO: handle this error
466 }
Yi Jin42711a02017-10-11 18:20:24 -0700467 return mBuffer.size();
468}
469
Yi Jin974a9c22017-10-02 18:37:08 -0700470static bool write_all(int fd, uint8_t const* buf, size_t size)
471{
472 while (size > 0) {
473 ssize_t amt = ::write(fd, buf, size);
474 if (amt < 0) {
475 return false;
476 }
477 size -= amt;
478 buf += amt;
479 }
480 return true;
481}
482
483bool
Yi Jin42711a02017-10-11 18:20:24 -0700484ProtoOutputStream::flush(int fd)
Yi Jin974a9c22017-10-02 18:37:08 -0700485{
Yi Jin42711a02017-10-11 18:20:24 -0700486 if (fd < 0) return false;
Yi Jin974a9c22017-10-02 18:37:08 -0700487 if (!compact()) return false;
488
489 EncodedBuffer::iterator it = mBuffer.begin();
490 while (it.readBuffer() != NULL) {
Yi Jin42711a02017-10-11 18:20:24 -0700491 if (!write_all(fd, it.readBuffer(), it.currentToRead())) return false;
Yi Jin974a9c22017-10-02 18:37:08 -0700492 it.rp()->move(it.currentToRead());
493 }
494 return true;
495}
496
Yi Jin42711a02017-10-11 18:20:24 -0700497EncodedBuffer::iterator
498ProtoOutputStream::data()
499{
Yi Jin00a75442018-03-30 11:01:58 -0700500 if (!compact()) {
501 ALOGE("compact failed, the ProtoOutputStream data is corrupted!");
502 // TODO: handle this error
503 }
Yi Jin42711a02017-10-11 18:20:24 -0700504 return mBuffer.begin();
505}
506
507void
508ProtoOutputStream::writeRawVarint(uint64_t varint)
509{
510 mBuffer.writeRawVarint64(varint);
511}
512
513void
514ProtoOutputStream::writeLengthDelimitedHeader(uint32_t id, size_t size)
515{
516 mBuffer.writeHeader(id, WIRE_TYPE_LENGTH_DELIMITED);
517 // reserves 64 bits for length delimited fields, if first field is negative, compact it.
518 mBuffer.writeRawFixed32(size);
519 mBuffer.writeRawFixed32(size);
520}
521
522void
523ProtoOutputStream::writeRawByte(uint8_t byte)
524{
525 mBuffer.writeRawByte(byte);
526}
527
Yi Jin974a9c22017-10-02 18:37:08 -0700528
529// =========================================================================
530// Private functions
531
532/**
533 * bit_cast
534 */
535template <class From, class To>
536inline To bit_cast(From const &from) {
537 To to;
538 memcpy(&to, &from, sizeof(to));
539 return to;
540}
541
542inline void
543ProtoOutputStream::writeDoubleImpl(uint32_t id, double val)
544{
Yi Jin974a9c22017-10-02 18:37:08 -0700545 mBuffer.writeHeader(id, WIRE_TYPE_FIXED64);
546 mBuffer.writeRawFixed64(bit_cast<double, uint64_t>(val));
547}
548
549inline void
550ProtoOutputStream::writeFloatImpl(uint32_t id, float val)
551{
Yi Jin974a9c22017-10-02 18:37:08 -0700552 mBuffer.writeHeader(id, WIRE_TYPE_FIXED32);
553 mBuffer.writeRawFixed32(bit_cast<float, uint32_t>(val));
554}
555
556inline void
557ProtoOutputStream::writeInt64Impl(uint32_t id, long long val)
558{
Yi Jin974a9c22017-10-02 18:37:08 -0700559 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
560 mBuffer.writeRawVarint64((uint64_t)val);
561}
562
563inline void
564ProtoOutputStream::writeInt32Impl(uint32_t id, int val)
565{
Yi Jin974a9c22017-10-02 18:37:08 -0700566 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
567 mBuffer.writeRawVarint32((uint32_t)val);
568}
569
570inline void
571ProtoOutputStream::writeUint64Impl(uint32_t id, uint64_t val)
572{
Yi Jin974a9c22017-10-02 18:37:08 -0700573 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
574 mBuffer.writeRawVarint64(val);
575}
576
577inline void
578ProtoOutputStream::writeUint32Impl(uint32_t id, uint32_t val)
579{
Yi Jin974a9c22017-10-02 18:37:08 -0700580 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
581 mBuffer.writeRawVarint32(val);
582}
583
584inline void
585ProtoOutputStream::writeFixed64Impl(uint32_t id, uint64_t val)
586{
Yi Jin974a9c22017-10-02 18:37:08 -0700587 mBuffer.writeHeader(id, WIRE_TYPE_FIXED64);
588 mBuffer.writeRawFixed64(val);
589}
590
591inline void
592ProtoOutputStream::writeFixed32Impl(uint32_t id, uint32_t val)
593{
Yi Jin974a9c22017-10-02 18:37:08 -0700594 mBuffer.writeHeader(id, WIRE_TYPE_FIXED32);
595 mBuffer.writeRawFixed32(val);
596}
597
598inline void
599ProtoOutputStream::writeSFixed64Impl(uint32_t id, long long val)
600{
Yi Jin974a9c22017-10-02 18:37:08 -0700601 mBuffer.writeHeader(id, WIRE_TYPE_FIXED64);
602 mBuffer.writeRawFixed64((uint64_t)val);
603}
604
605inline void
606ProtoOutputStream::writeSFixed32Impl(uint32_t id, int val)
607{
Yi Jin974a9c22017-10-02 18:37:08 -0700608 mBuffer.writeHeader(id, WIRE_TYPE_FIXED32);
609 mBuffer.writeRawFixed32((uint32_t)val);
610}
611
612inline void
613ProtoOutputStream::writeZigzagInt64Impl(uint32_t id, long long val)
614{
Yi Jin974a9c22017-10-02 18:37:08 -0700615 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
616 mBuffer.writeRawVarint64((val << 1) ^ (val >> 63));
617}
618
619inline void
620ProtoOutputStream::writeZigzagInt32Impl(uint32_t id, int val)
621{
Yi Jin974a9c22017-10-02 18:37:08 -0700622 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
623 mBuffer.writeRawVarint32((val << 1) ^ (val >> 31));
624}
625
626inline void
627ProtoOutputStream::writeEnumImpl(uint32_t id, int val)
628{
629 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
630 mBuffer.writeRawVarint32((uint32_t) val);
631}
632
633inline void
634ProtoOutputStream::writeBoolImpl(uint32_t id, bool val)
635{
Yi Jin974a9c22017-10-02 18:37:08 -0700636 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
637 mBuffer.writeRawVarint32(val ? 1 : 0);
638}
639
640inline void
641ProtoOutputStream::writeUtf8StringImpl(uint32_t id, const char* val, size_t size)
642{
Yi Jin04625ad2017-10-17 18:29:33 -0700643 if (val == NULL) return;
Yi Jin42711a02017-10-11 18:20:24 -0700644 writeLengthDelimitedHeader(id, size);
Yi Jin974a9c22017-10-02 18:37:08 -0700645 for (size_t i=0; i<size; i++) {
646 mBuffer.writeRawByte((uint8_t)val[i]);
647 }
648}
649
Yi Jin8ad19382017-10-30 16:07:20 -0700650inline void
651ProtoOutputStream::writeMessageBytesImpl(uint32_t id, const char* val, size_t size)
652{
653 if (val == NULL) return;
654 writeLengthDelimitedHeader(id, size);
655 for (size_t i=0; i<size; i++) {
656 mBuffer.writeRawByte(val[i]);
657 }
658}
659
Yi Jin974a9c22017-10-02 18:37:08 -0700660} // util
661} // android
662