blob: 3fee7e42338d0a71c64de00d34a3c6399e9eeae3 [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 Jinc5b71ee2018-04-25 16:51:40 -070020#include <android-base/file.h>
Yi Jin974a9c22017-10-02 18:37:08 -070021#include <android/util/protobuf.h>
22#include <android/util/ProtoOutputStream.h>
23#include <cutils/log.h>
Yi Jin974a9c22017-10-02 18:37:08 -070024
25namespace android {
26namespace util {
27
Yi Jin42711a02017-10-11 18:20:24 -070028ProtoOutputStream::ProtoOutputStream()
Yi Jin974a9c22017-10-02 18:37:08 -070029 :mBuffer(),
Yi Jin974a9c22017-10-02 18:37:08 -070030 mCopyBegin(0),
31 mCompact(false),
32 mDepth(0),
33 mObjectId(0),
Yi Jin00a75442018-03-30 11:01:58 -070034 mExpectedObjectToken(UINT64_C(-1))
Yi Jin974a9c22017-10-02 18:37:08 -070035{
36}
37
38ProtoOutputStream::~ProtoOutputStream()
39{
40}
41
Yi Jin7f9e63b2018-02-02 16:25:11 -080042
43void
44ProtoOutputStream::clear()
45{
46 mBuffer.clear();
47 mCopyBegin = 0;
48 mCompact = false;
49 mDepth = 0;
50 mObjectId = 0;
Yi Jin00a75442018-03-30 11:01:58 -070051 mExpectedObjectToken = UINT64_C(-1);
Yi Jin7f9e63b2018-02-02 16:25:11 -080052}
53
Yi Jin974a9c22017-10-02 18:37:08 -070054bool
55ProtoOutputStream::write(uint64_t fieldId, double val)
56{
57 if (mCompact) return false;
58 const uint32_t id = (uint32_t)fieldId;
59 switch (fieldId & FIELD_TYPE_MASK) {
Yi Jin04625ad2017-10-17 18:29:33 -070060 case FIELD_TYPE_DOUBLE: writeDoubleImpl(id, (double)val); break;
61 case FIELD_TYPE_FLOAT: writeFloatImpl(id, (float)val); break;
62 case FIELD_TYPE_INT64: writeInt64Impl(id, (long long)val); break;
63 case FIELD_TYPE_UINT64: writeUint64Impl(id, (uint64_t)val); break;
64 case FIELD_TYPE_INT32: writeInt32Impl(id, (int)val); break;
65 case FIELD_TYPE_FIXED64: writeFixed64Impl(id, (uint64_t)val); break;
66 case FIELD_TYPE_FIXED32: writeFixed32Impl(id, (uint32_t)val); break;
67 case FIELD_TYPE_UINT32: writeUint32Impl(id, (uint32_t)val); break;
68 case FIELD_TYPE_SFIXED32: writeSFixed32Impl(id, (int)val); break;
69 case FIELD_TYPE_SFIXED64: writeSFixed64Impl(id, (long long)val); break;
70 case FIELD_TYPE_SINT32: writeZigzagInt32Impl(id, (int)val); break;
71 case FIELD_TYPE_SINT64: writeZigzagInt64Impl(id, (long long)val); break;
Yi Jin974a9c22017-10-02 18:37:08 -070072 default:
73 ALOGW("Field type %d is not supported when writing double val.",
74 (int)((fieldId & FIELD_TYPE_MASK) >> FIELD_TYPE_SHIFT));
75 return false;
76 }
77 return true;
78}
79
80bool
81ProtoOutputStream::write(uint64_t fieldId, float val)
82{
83 if (mCompact) return false;
84 const uint32_t id = (uint32_t)fieldId;
85 switch (fieldId & FIELD_TYPE_MASK) {
Yi Jin04625ad2017-10-17 18:29:33 -070086 case FIELD_TYPE_DOUBLE: writeDoubleImpl(id, (double)val); break;
87 case FIELD_TYPE_FLOAT: writeFloatImpl(id, (float)val); break;
88 case FIELD_TYPE_INT64: writeInt64Impl(id, (long long)val); break;
89 case FIELD_TYPE_UINT64: writeUint64Impl(id, (uint64_t)val); break;
90 case FIELD_TYPE_INT32: writeInt32Impl(id, (int)val); break;
91 case FIELD_TYPE_FIXED64: writeFixed64Impl(id, (uint64_t)val); break;
92 case FIELD_TYPE_FIXED32: writeFixed32Impl(id, (uint32_t)val); break;
93 case FIELD_TYPE_UINT32: writeUint32Impl(id, (uint32_t)val); break;
94 case FIELD_TYPE_SFIXED32: writeSFixed32Impl(id, (int)val); break;
95 case FIELD_TYPE_SFIXED64: writeSFixed64Impl(id, (long long)val); break;
96 case FIELD_TYPE_SINT32: writeZigzagInt32Impl(id, (int)val); break;
97 case FIELD_TYPE_SINT64: writeZigzagInt64Impl(id, (long long)val); break;
Yi Jin974a9c22017-10-02 18:37:08 -070098 default:
99 ALOGW("Field type %d is not supported when writing float val.",
100 (int)((fieldId & FIELD_TYPE_MASK) >> FIELD_TYPE_SHIFT));
101 return false;
102 }
103 return true;
104}
105
106bool
107ProtoOutputStream::write(uint64_t fieldId, int val)
108{
109 if (mCompact) return false;
110 const uint32_t id = (uint32_t)fieldId;
111 switch (fieldId & FIELD_TYPE_MASK) {
Yi Jin04625ad2017-10-17 18:29:33 -0700112 case FIELD_TYPE_DOUBLE: writeDoubleImpl(id, (double)val); break;
113 case FIELD_TYPE_FLOAT: writeFloatImpl(id, (float)val); break;
114 case FIELD_TYPE_INT64: writeInt64Impl(id, (long long)val); break;
115 case FIELD_TYPE_UINT64: writeUint64Impl(id, (uint64_t)val); break;
116 case FIELD_TYPE_INT32: writeInt32Impl(id, (int)val); break;
117 case FIELD_TYPE_FIXED64: writeFixed64Impl(id, (uint64_t)val); break;
118 case FIELD_TYPE_FIXED32: writeFixed32Impl(id, (uint32_t)val); break;
119 case FIELD_TYPE_UINT32: writeUint32Impl(id, (uint32_t)val); break;
120 case FIELD_TYPE_SFIXED32: writeSFixed32Impl(id, (int)val); break;
121 case FIELD_TYPE_SFIXED64: writeSFixed64Impl(id, (long long)val); break;
122 case FIELD_TYPE_SINT32: writeZigzagInt32Impl(id, (int)val); break;
123 case FIELD_TYPE_SINT64: writeZigzagInt64Impl(id, (long long)val); break;
124 case FIELD_TYPE_ENUM: writeEnumImpl(id, (int)val); break;
125 case FIELD_TYPE_BOOL: writeBoolImpl(id, val != 0); break;
Yi Jin974a9c22017-10-02 18:37:08 -0700126 default:
127 ALOGW("Field type %d is not supported when writing int val.",
128 (int)((fieldId & FIELD_TYPE_MASK) >> FIELD_TYPE_SHIFT));
129 return false;
130 }
131 return true;
132}
133
134bool
135ProtoOutputStream::write(uint64_t fieldId, long long val)
136{
137 if (mCompact) return false;
138 const uint32_t id = (uint32_t)fieldId;
139 switch (fieldId & FIELD_TYPE_MASK) {
Yi Jin04625ad2017-10-17 18:29:33 -0700140 case FIELD_TYPE_DOUBLE: writeDoubleImpl(id, (double)val); break;
141 case FIELD_TYPE_FLOAT: writeFloatImpl(id, (float)val); break;
142 case FIELD_TYPE_INT64: writeInt64Impl(id, (long long)val); break;
143 case FIELD_TYPE_UINT64: writeUint64Impl(id, (uint64_t)val); break;
144 case FIELD_TYPE_INT32: writeInt32Impl(id, (int)val); break;
145 case FIELD_TYPE_FIXED64: writeFixed64Impl(id, (uint64_t)val); break;
146 case FIELD_TYPE_FIXED32: writeFixed32Impl(id, (uint32_t)val); break;
147 case FIELD_TYPE_UINT32: writeUint32Impl(id, (uint32_t)val); break;
148 case FIELD_TYPE_SFIXED32: writeSFixed32Impl(id, (int)val); break;
149 case FIELD_TYPE_SFIXED64: writeSFixed64Impl(id, (long long)val); break;
150 case FIELD_TYPE_SINT32: writeZigzagInt32Impl(id, (int)val); break;
151 case FIELD_TYPE_SINT64: writeZigzagInt64Impl(id, (long long)val); break;
152 case FIELD_TYPE_ENUM: writeEnumImpl(id, (int)val); break;
153 case FIELD_TYPE_BOOL: writeBoolImpl(id, val != 0); break;
Yi Jin974a9c22017-10-02 18:37:08 -0700154 default:
155 ALOGW("Field type %d is not supported when writing long long val.",
156 (int)((fieldId & FIELD_TYPE_MASK) >> FIELD_TYPE_SHIFT));
157 return false;
158 }
159 return true;
160}
161
162bool
163ProtoOutputStream::write(uint64_t fieldId, bool val)
164{
165 if (mCompact) return false;
166 const uint32_t id = (uint32_t)fieldId;
167 switch (fieldId & FIELD_TYPE_MASK) {
Yi Jin04625ad2017-10-17 18:29:33 -0700168 case FIELD_TYPE_BOOL:
Yi Jin974a9c22017-10-02 18:37:08 -0700169 writeBoolImpl(id, val);
170 return true;
171 default:
172 ALOGW("Field type %d is not supported when writing bool val.",
173 (int)((fieldId & FIELD_TYPE_MASK) >> FIELD_TYPE_SHIFT));
174 return false;
175 }
176}
177
178bool
Yi Jin6cacbcb2018-03-30 14:04:52 -0700179ProtoOutputStream::write(uint64_t fieldId, std::string val)
Yi Jin974a9c22017-10-02 18:37:08 -0700180{
181 if (mCompact) return false;
182 const uint32_t id = (uint32_t)fieldId;
183 switch (fieldId & FIELD_TYPE_MASK) {
Yi Jin04625ad2017-10-17 18:29:33 -0700184 case FIELD_TYPE_STRING:
Yi Jin974a9c22017-10-02 18:37:08 -0700185 writeUtf8StringImpl(id, val.c_str(), val.size());
186 return true;
187 default:
188 ALOGW("Field type %d is not supported when writing string val.",
189 (int)((fieldId & FIELD_TYPE_MASK) >> FIELD_TYPE_SHIFT));
190 return false;
191 }
192}
193
194bool
Yi Jine0833302017-10-23 15:42:44 -0700195ProtoOutputStream::write(uint64_t fieldId, const char* val, size_t size)
Yi Jin974a9c22017-10-02 18:37:08 -0700196{
197 if (mCompact) return false;
198 const uint32_t id = (uint32_t)fieldId;
Yi Jin974a9c22017-10-02 18:37:08 -0700199 switch (fieldId & FIELD_TYPE_MASK) {
Yi Jin04625ad2017-10-17 18:29:33 -0700200 case FIELD_TYPE_STRING:
201 case FIELD_TYPE_BYTES:
Yi Jin974a9c22017-10-02 18:37:08 -0700202 writeUtf8StringImpl(id, val, size);
203 return true;
Yi Jin04625ad2017-10-17 18:29:33 -0700204 case FIELD_TYPE_MESSAGE:
Yi Jin8ad19382017-10-30 16:07:20 -0700205 // can directly write valid format of message bytes into ProtoOutputStream without calling start/end
206 writeMessageBytesImpl(id, val, size);
207 return true;
Yi Jin974a9c22017-10-02 18:37:08 -0700208 default:
209 ALOGW("Field type %d is not supported when writing char[] val.",
210 (int)((fieldId & FIELD_TYPE_MASK) >> FIELD_TYPE_SHIFT));
211 return false;
212 }
213}
214
215/**
216 * Make a token.
217 * Bits 61-63 - tag size (So we can go backwards later if the object had not data)
218 * - 3 bits, max value 7, max value needed 5
219 * Bit 60 - true if the object is repeated
220 * Bits 59-51 - depth (For error checking)
Yi Jin00a75442018-03-30 11:01:58 -0700221 * - 9 bits, max value 511, when checking, value is masked (if we really
222 * are more than 511 levels deep)
Yi Jin974a9c22017-10-02 18:37:08 -0700223 * Bits 32-50 - objectId (For error checking)
Yi Jin00a75442018-03-30 11:01:58 -0700224 * - 19 bits, max value 524,287. that's a lot of objects. IDs will wrap
Yi Jin974a9c22017-10-02 18:37:08 -0700225 * because of the overflow, and only the tokens are compared.
226 * Bits 0-31 - offset of the first size field in the buffer.
227 */
Yi Jin00a75442018-03-30 11:01:58 -0700228static uint64_t
229makeToken(uint32_t tagSize, bool repeated, uint32_t depth, uint32_t objectId, size_t sizePos) {
230 return ((UINT64_C(0x07) & (uint64_t)tagSize) << 61)
231 | (repeated ? (UINT64_C(1) << 60) : 0)
232 | (UINT64_C(0x01ff) & (uint64_t)depth) << 51
233 | (UINT64_C(0x07ffff) & (uint64_t)objectId) << 32
234 | (UINT64_C(0x0ffffffff) & (uint64_t)sizePos);
Yi Jin974a9c22017-10-02 18:37:08 -0700235}
236
237/**
238 * Get the encoded tag size from the token.
239 */
Yi Jin00a75442018-03-30 11:01:58 -0700240static uint32_t getTagSizeFromToken(uint64_t token) {
241 return 0x7 & (token >> 61);
Yi Jin974a9c22017-10-02 18:37:08 -0700242}
243
244/**
245 * Get the nesting depth of startObject calls from the token.
246 */
Yi Jin00a75442018-03-30 11:01:58 -0700247static uint32_t getDepthFromToken(uint64_t token) {
248 return 0x01ff & (token >> 51);
Yi Jin974a9c22017-10-02 18:37:08 -0700249}
250
251/**
252 * Get the location of the childRawSize (the first 32 bit size field) in this object.
253 */
Yi Jin00a75442018-03-30 11:01:58 -0700254static uint32_t getSizePosFromToken(uint64_t token) {
255 return (uint32_t)token;
Yi Jin974a9c22017-10-02 18:37:08 -0700256}
257
Yi Jin5ee07872018-03-05 18:18:27 -0800258uint64_t
Yi Jin974a9c22017-10-02 18:37:08 -0700259ProtoOutputStream::start(uint64_t fieldId)
260{
Yi Jin04625ad2017-10-17 18:29:33 -0700261 if ((fieldId & FIELD_TYPE_MASK) != FIELD_TYPE_MESSAGE) {
Yi Jin00a75442018-03-30 11:01:58 -0700262 ALOGE("Can't call start for non-message type field: 0x%" PRIx64, fieldId);
Yi Jin974a9c22017-10-02 18:37:08 -0700263 return 0;
264 }
265
266 uint32_t id = (uint32_t)fieldId;
Yi Jin295d9b12018-02-02 14:33:20 -0800267 size_t prevPos = mBuffer.wp()->pos();
Yi Jin974a9c22017-10-02 18:37:08 -0700268 mBuffer.writeHeader(id, WIRE_TYPE_LENGTH_DELIMITED);
Yi Jin974a9c22017-10-02 18:37:08 -0700269 size_t sizePos = mBuffer.wp()->pos();
270
271 mDepth++;
272 mObjectId++;
273 mBuffer.writeRawFixed64(mExpectedObjectToken); // push previous token into stack.
274
Yi Jin295d9b12018-02-02 14:33:20 -0800275 mExpectedObjectToken = makeToken(sizePos - prevPos,
Yi Jin974a9c22017-10-02 18:37:08 -0700276 (bool)(fieldId & FIELD_COUNT_REPEATED), mDepth, mObjectId, sizePos);
277 return mExpectedObjectToken;
278}
279
280void
Yi Jin5ee07872018-03-05 18:18:27 -0800281ProtoOutputStream::end(uint64_t token)
Yi Jin974a9c22017-10-02 18:37:08 -0700282{
283 if (token != mExpectedObjectToken) {
Yi Jin00a75442018-03-30 11:01:58 -0700284 ALOGE("Unexpected token: 0x%" PRIx64 ", should be 0x%" PRIx64, token, mExpectedObjectToken);
Yi Jin974a9c22017-10-02 18:37:08 -0700285 return;
286 }
287
Yi Jin00a75442018-03-30 11:01:58 -0700288 uint32_t depth = getDepthFromToken(token);
Yi Jin974a9c22017-10-02 18:37:08 -0700289 if (depth != (mDepth & 0x01ff)) {
Yi Jin00a75442018-03-30 11:01:58 -0700290 ALOGE("Unexpected depth: %" PRIu32 ", should be %" PRIu32, depth, mDepth);
Yi Jin974a9c22017-10-02 18:37:08 -0700291 return;
292 }
293 mDepth--;
294
Yi Jin00a75442018-03-30 11:01:58 -0700295 uint32_t sizePos = getSizePosFromToken(token);
Yi Jin974a9c22017-10-02 18:37:08 -0700296 // number of bytes written in this start-end session.
297 int childRawSize = mBuffer.wp()->pos() - sizePos - 8;
298
299 // retrieve the old token from stack.
300 mBuffer.ep()->rewind()->move(sizePos);
301 mExpectedObjectToken = mBuffer.readRawFixed64();
302
303 // If raw size is larger than 0, write the negative value here to indicate a compact is needed.
304 if (childRawSize > 0) {
305 mBuffer.editRawFixed32(sizePos, -childRawSize);
306 mBuffer.editRawFixed32(sizePos+4, -1);
307 } else {
308 // reset wp which erase the header tag of the message when its size is 0.
309 mBuffer.wp()->rewind()->move(sizePos - getTagSizeFromToken(token));
310 }
311}
312
Yi Jin0abdfb02017-11-16 15:32:27 -0800313size_t
314ProtoOutputStream::bytesWritten()
315{
316 return mBuffer.size();
317}
318
Yi Jin974a9c22017-10-02 18:37:08 -0700319bool
320ProtoOutputStream::compact() {
321 if (mCompact) return true;
322 if (mDepth != 0) {
Yi Jin00a75442018-03-30 11:01:58 -0700323 ALOGE("Can't compact when depth(%" PRIu32 ") is not zero. Missing calls to end.", mDepth);
Yi Jin974a9c22017-10-02 18:37:08 -0700324 return false;
325 }
326 // record the size of the original buffer.
327 size_t rawBufferSize = mBuffer.size();
328 if (rawBufferSize == 0) return true; // nothing to do if the buffer is empty;
329
330 // reset edit pointer and recursively compute encoded size of messages.
331 mBuffer.ep()->rewind();
332 if (editEncodedSize(rawBufferSize) == 0) {
333 ALOGE("Failed to editEncodedSize.");
334 return false;
335 }
336
337 // reset both edit pointer and write pointer, and compact recursively.
338 mBuffer.ep()->rewind();
339 mBuffer.wp()->rewind();
340 if (!compactSize(rawBufferSize)) {
341 ALOGE("Failed to compactSize.");
342 return false;
343 }
344 // copy the reset to the buffer.
345 if (mCopyBegin < rawBufferSize) {
346 mBuffer.copy(mCopyBegin, rawBufferSize - mCopyBegin);
347 }
348
349 // mark true means it is not legal to write to this ProtoOutputStream anymore
350 mCompact = true;
351 return true;
352}
353
354/**
355 * First compaction pass. Iterate through the data, and fill in the
356 * nested object sizes so the next pass can compact them.
357 */
358size_t
359ProtoOutputStream::editEncodedSize(size_t rawSize)
360{
361 size_t objectStart = mBuffer.ep()->pos();
362 size_t objectEnd = objectStart + rawSize;
363 size_t encodedSize = 0;
364 int childRawSize, childEncodedSize;
365 size_t childEncodedSizePos;
366
367 while (mBuffer.ep()->pos() < objectEnd) {
368 uint32_t tag = (uint32_t)mBuffer.readRawVarint();
369 encodedSize += get_varint_size(tag);
370 switch (read_wire_type(tag)) {
371 case WIRE_TYPE_VARINT:
372 do {
373 encodedSize++;
374 } while ((mBuffer.readRawByte() & 0x80) != 0);
375 break;
376 case WIRE_TYPE_FIXED64:
377 encodedSize += 8;
378 mBuffer.ep()->move(8);
379 break;
380 case WIRE_TYPE_LENGTH_DELIMITED:
381 childRawSize = (int)mBuffer.readRawFixed32();
382 childEncodedSizePos = mBuffer.ep()->pos();
383 childEncodedSize = (int)mBuffer.readRawFixed32();
384 if (childRawSize >= 0 && childRawSize == childEncodedSize) {
385 mBuffer.ep()->move(childRawSize);
386 } else if (childRawSize < 0 && childEncodedSize == -1){
387 childEncodedSize = editEncodedSize(-childRawSize);
388 mBuffer.editRawFixed32(childEncodedSizePos, childEncodedSize);
389 } else {
390 ALOGE("Bad raw or encoded values: raw=%d, encoded=%d at %zu",
391 childRawSize, childEncodedSize, childEncodedSizePos);
392 return 0;
393 }
394 encodedSize += get_varint_size(childEncodedSize) + childEncodedSize;
395 break;
396 case WIRE_TYPE_FIXED32:
397 encodedSize += 4;
398 mBuffer.ep()->move(4);
399 break;
400 default:
401 ALOGE("Unexpected wire type %d in editEncodedSize at [%zu, %zu]",
402 read_wire_type(tag), objectStart, objectEnd);
403 return 0;
404 }
405 }
406 return encodedSize;
407}
408
409/**
410 * Second compaction pass. Iterate through the data, and copy the data
411 * forward in the buffer, converting the pairs of uint32s into a single
412 * unsigned varint of the size.
413 */
414bool
415ProtoOutputStream::compactSize(size_t rawSize)
416{
417 size_t objectStart = mBuffer.ep()->pos();
418 size_t objectEnd = objectStart + rawSize;
419 int childRawSize, childEncodedSize;
420
421 while (mBuffer.ep()->pos() < objectEnd) {
422 uint32_t tag = (uint32_t)mBuffer.readRawVarint();
423 switch (read_wire_type(tag)) {
424 case WIRE_TYPE_VARINT:
425 while ((mBuffer.readRawByte() & 0x80) != 0) {}
426 break;
427 case WIRE_TYPE_FIXED64:
428 mBuffer.ep()->move(8);
429 break;
430 case WIRE_TYPE_LENGTH_DELIMITED:
431 mBuffer.copy(mCopyBegin, mBuffer.ep()->pos() - mCopyBegin);
432
433 childRawSize = (int)mBuffer.readRawFixed32();
434 childEncodedSize = (int)mBuffer.readRawFixed32();
435 mCopyBegin = mBuffer.ep()->pos();
436
437 // write encoded size to buffer.
438 mBuffer.writeRawVarint32(childEncodedSize);
439 if (childRawSize >= 0 && childRawSize == childEncodedSize) {
440 mBuffer.ep()->move(childEncodedSize);
441 } else if (childRawSize < 0){
442 if (!compactSize(-childRawSize)) return false;
443 } else {
444 ALOGE("Bad raw or encoded values: raw=%d, encoded=%d",
445 childRawSize, childEncodedSize);
446 return false;
447 }
448 break;
449 case WIRE_TYPE_FIXED32:
450 mBuffer.ep()->move(4);
451 break;
452 default:
453 ALOGE("Unexpected wire type %d in compactSize at [%zu, %zu]",
454 read_wire_type(tag), objectStart, objectEnd);
455 return false;
456 }
457 }
458 return true;
459}
460
Yi Jin42711a02017-10-11 18:20:24 -0700461size_t
462ProtoOutputStream::size()
463{
Yi Jin00a75442018-03-30 11:01:58 -0700464 if (!compact()) {
465 ALOGE("compact failed, the ProtoOutputStream data is corrupted!");
466 // TODO: handle this error
467 }
Yi Jin42711a02017-10-11 18:20:24 -0700468 return mBuffer.size();
469}
470
Yi Jin974a9c22017-10-02 18:37:08 -0700471bool
Yi Jin42711a02017-10-11 18:20:24 -0700472ProtoOutputStream::flush(int fd)
Yi Jin974a9c22017-10-02 18:37:08 -0700473{
Yi Jin42711a02017-10-11 18:20:24 -0700474 if (fd < 0) return false;
Yi Jin974a9c22017-10-02 18:37:08 -0700475 if (!compact()) return false;
476
477 EncodedBuffer::iterator it = mBuffer.begin();
478 while (it.readBuffer() != NULL) {
Yi Jinc5b71ee2018-04-25 16:51:40 -0700479 if (!android::base::WriteFully(fd, it.readBuffer(), it.currentToRead())) return false;
Yi Jin974a9c22017-10-02 18:37:08 -0700480 it.rp()->move(it.currentToRead());
481 }
482 return true;
483}
484
Yi Jin42711a02017-10-11 18:20:24 -0700485EncodedBuffer::iterator
486ProtoOutputStream::data()
487{
Yi Jin00a75442018-03-30 11:01:58 -0700488 if (!compact()) {
489 ALOGE("compact failed, the ProtoOutputStream data is corrupted!");
490 // TODO: handle this error
491 }
Yi Jin42711a02017-10-11 18:20:24 -0700492 return mBuffer.begin();
493}
494
495void
496ProtoOutputStream::writeRawVarint(uint64_t varint)
497{
498 mBuffer.writeRawVarint64(varint);
499}
500
501void
502ProtoOutputStream::writeLengthDelimitedHeader(uint32_t id, size_t size)
503{
504 mBuffer.writeHeader(id, WIRE_TYPE_LENGTH_DELIMITED);
505 // reserves 64 bits for length delimited fields, if first field is negative, compact it.
506 mBuffer.writeRawFixed32(size);
507 mBuffer.writeRawFixed32(size);
508}
509
510void
511ProtoOutputStream::writeRawByte(uint8_t byte)
512{
513 mBuffer.writeRawByte(byte);
514}
515
Yi Jin974a9c22017-10-02 18:37:08 -0700516
517// =========================================================================
518// Private functions
519
520/**
521 * bit_cast
522 */
523template <class From, class To>
524inline To bit_cast(From const &from) {
525 To to;
526 memcpy(&to, &from, sizeof(to));
527 return to;
528}
529
530inline void
531ProtoOutputStream::writeDoubleImpl(uint32_t id, double val)
532{
Yi Jin974a9c22017-10-02 18:37:08 -0700533 mBuffer.writeHeader(id, WIRE_TYPE_FIXED64);
534 mBuffer.writeRawFixed64(bit_cast<double, uint64_t>(val));
535}
536
537inline void
538ProtoOutputStream::writeFloatImpl(uint32_t id, float val)
539{
Yi Jin974a9c22017-10-02 18:37:08 -0700540 mBuffer.writeHeader(id, WIRE_TYPE_FIXED32);
541 mBuffer.writeRawFixed32(bit_cast<float, uint32_t>(val));
542}
543
544inline void
545ProtoOutputStream::writeInt64Impl(uint32_t id, long long val)
546{
Yi Jin974a9c22017-10-02 18:37:08 -0700547 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
548 mBuffer.writeRawVarint64((uint64_t)val);
549}
550
551inline void
552ProtoOutputStream::writeInt32Impl(uint32_t id, int val)
553{
Yi Jin974a9c22017-10-02 18:37:08 -0700554 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
555 mBuffer.writeRawVarint32((uint32_t)val);
556}
557
558inline void
559ProtoOutputStream::writeUint64Impl(uint32_t id, uint64_t val)
560{
Yi Jin974a9c22017-10-02 18:37:08 -0700561 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
562 mBuffer.writeRawVarint64(val);
563}
564
565inline void
566ProtoOutputStream::writeUint32Impl(uint32_t id, uint32_t val)
567{
Yi Jin974a9c22017-10-02 18:37:08 -0700568 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
569 mBuffer.writeRawVarint32(val);
570}
571
572inline void
573ProtoOutputStream::writeFixed64Impl(uint32_t id, uint64_t val)
574{
Yi Jin974a9c22017-10-02 18:37:08 -0700575 mBuffer.writeHeader(id, WIRE_TYPE_FIXED64);
576 mBuffer.writeRawFixed64(val);
577}
578
579inline void
580ProtoOutputStream::writeFixed32Impl(uint32_t id, uint32_t val)
581{
Yi Jin974a9c22017-10-02 18:37:08 -0700582 mBuffer.writeHeader(id, WIRE_TYPE_FIXED32);
583 mBuffer.writeRawFixed32(val);
584}
585
586inline void
587ProtoOutputStream::writeSFixed64Impl(uint32_t id, long long val)
588{
Yi Jin974a9c22017-10-02 18:37:08 -0700589 mBuffer.writeHeader(id, WIRE_TYPE_FIXED64);
590 mBuffer.writeRawFixed64((uint64_t)val);
591}
592
593inline void
594ProtoOutputStream::writeSFixed32Impl(uint32_t id, int val)
595{
Yi Jin974a9c22017-10-02 18:37:08 -0700596 mBuffer.writeHeader(id, WIRE_TYPE_FIXED32);
597 mBuffer.writeRawFixed32((uint32_t)val);
598}
599
600inline void
601ProtoOutputStream::writeZigzagInt64Impl(uint32_t id, long long val)
602{
Yi Jin974a9c22017-10-02 18:37:08 -0700603 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
604 mBuffer.writeRawVarint64((val << 1) ^ (val >> 63));
605}
606
607inline void
608ProtoOutputStream::writeZigzagInt32Impl(uint32_t id, int val)
609{
Yi Jin974a9c22017-10-02 18:37:08 -0700610 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
611 mBuffer.writeRawVarint32((val << 1) ^ (val >> 31));
612}
613
614inline void
615ProtoOutputStream::writeEnumImpl(uint32_t id, int val)
616{
617 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
618 mBuffer.writeRawVarint32((uint32_t) val);
619}
620
621inline void
622ProtoOutputStream::writeBoolImpl(uint32_t id, bool val)
623{
Yi Jin974a9c22017-10-02 18:37:08 -0700624 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
625 mBuffer.writeRawVarint32(val ? 1 : 0);
626}
627
628inline void
629ProtoOutputStream::writeUtf8StringImpl(uint32_t id, const char* val, size_t size)
630{
Yi Jin04625ad2017-10-17 18:29:33 -0700631 if (val == NULL) return;
Yi Jin42711a02017-10-11 18:20:24 -0700632 writeLengthDelimitedHeader(id, size);
Yi Jin974a9c22017-10-02 18:37:08 -0700633 for (size_t i=0; i<size; i++) {
634 mBuffer.writeRawByte((uint8_t)val[i]);
635 }
636}
637
Yi Jin8ad19382017-10-30 16:07:20 -0700638inline void
639ProtoOutputStream::writeMessageBytesImpl(uint32_t id, const char* val, size_t size)
640{
641 if (val == NULL) return;
642 writeLengthDelimitedHeader(id, size);
643 for (size_t i=0; i<size; i++) {
644 mBuffer.writeRawByte(val[i]);
645 }
646}
647
Yi Jin974a9c22017-10-02 18:37:08 -0700648} // util
649} // android
650