blob: fec20bf8061aed94791780ccf71285711860d8a9 [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
Colin Crossfa6bc272018-10-26 13:04:41 -0700134ProtoOutputStream::write(uint64_t fieldId, long val)
135{
136 if (mCompact) return false;
137 const uint32_t id = (uint32_t)fieldId;
138 switch (fieldId & FIELD_TYPE_MASK) {
139 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;
153 default:
154 ALOGW("Field type %d is not supported when writing long val.",
155 (int)((fieldId & FIELD_TYPE_MASK) >> FIELD_TYPE_SHIFT));
156 return false;
157 }
158 return true;
159}
160
161bool
Yi Jin974a9c22017-10-02 18:37:08 -0700162ProtoOutputStream::write(uint64_t fieldId, long long 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_DOUBLE: writeDoubleImpl(id, (double)val); break;
168 case FIELD_TYPE_FLOAT: writeFloatImpl(id, (float)val); break;
169 case FIELD_TYPE_INT64: writeInt64Impl(id, (long long)val); break;
170 case FIELD_TYPE_UINT64: writeUint64Impl(id, (uint64_t)val); break;
171 case FIELD_TYPE_INT32: writeInt32Impl(id, (int)val); break;
172 case FIELD_TYPE_FIXED64: writeFixed64Impl(id, (uint64_t)val); break;
173 case FIELD_TYPE_FIXED32: writeFixed32Impl(id, (uint32_t)val); break;
174 case FIELD_TYPE_UINT32: writeUint32Impl(id, (uint32_t)val); break;
175 case FIELD_TYPE_SFIXED32: writeSFixed32Impl(id, (int)val); break;
176 case FIELD_TYPE_SFIXED64: writeSFixed64Impl(id, (long long)val); break;
177 case FIELD_TYPE_SINT32: writeZigzagInt32Impl(id, (int)val); break;
178 case FIELD_TYPE_SINT64: writeZigzagInt64Impl(id, (long long)val); break;
179 case FIELD_TYPE_ENUM: writeEnumImpl(id, (int)val); break;
180 case FIELD_TYPE_BOOL: writeBoolImpl(id, val != 0); break;
Yi Jin974a9c22017-10-02 18:37:08 -0700181 default:
182 ALOGW("Field type %d is not supported when writing long long val.",
183 (int)((fieldId & FIELD_TYPE_MASK) >> FIELD_TYPE_SHIFT));
184 return false;
185 }
186 return true;
187}
188
189bool
190ProtoOutputStream::write(uint64_t fieldId, bool val)
191{
192 if (mCompact) return false;
193 const uint32_t id = (uint32_t)fieldId;
194 switch (fieldId & FIELD_TYPE_MASK) {
Yi Jin04625ad2017-10-17 18:29:33 -0700195 case FIELD_TYPE_BOOL:
Yi Jin974a9c22017-10-02 18:37:08 -0700196 writeBoolImpl(id, val);
197 return true;
198 default:
199 ALOGW("Field type %d is not supported when writing bool val.",
200 (int)((fieldId & FIELD_TYPE_MASK) >> FIELD_TYPE_SHIFT));
201 return false;
202 }
203}
204
205bool
Yi Jin6cacbcb2018-03-30 14:04:52 -0700206ProtoOutputStream::write(uint64_t fieldId, std::string val)
Yi Jin974a9c22017-10-02 18:37:08 -0700207{
208 if (mCompact) return false;
209 const uint32_t id = (uint32_t)fieldId;
210 switch (fieldId & FIELD_TYPE_MASK) {
Yi Jin04625ad2017-10-17 18:29:33 -0700211 case FIELD_TYPE_STRING:
Yi Jin974a9c22017-10-02 18:37:08 -0700212 writeUtf8StringImpl(id, val.c_str(), val.size());
213 return true;
214 default:
215 ALOGW("Field type %d is not supported when writing string val.",
216 (int)((fieldId & FIELD_TYPE_MASK) >> FIELD_TYPE_SHIFT));
217 return false;
218 }
219}
220
221bool
Yi Jine0833302017-10-23 15:42:44 -0700222ProtoOutputStream::write(uint64_t fieldId, const char* val, size_t size)
Yi Jin974a9c22017-10-02 18:37:08 -0700223{
224 if (mCompact) return false;
225 const uint32_t id = (uint32_t)fieldId;
Yi Jin974a9c22017-10-02 18:37:08 -0700226 switch (fieldId & FIELD_TYPE_MASK) {
Yi Jin04625ad2017-10-17 18:29:33 -0700227 case FIELD_TYPE_STRING:
228 case FIELD_TYPE_BYTES:
Yi Jin974a9c22017-10-02 18:37:08 -0700229 writeUtf8StringImpl(id, val, size);
230 return true;
Yi Jin04625ad2017-10-17 18:29:33 -0700231 case FIELD_TYPE_MESSAGE:
Yi Jin8ad19382017-10-30 16:07:20 -0700232 // can directly write valid format of message bytes into ProtoOutputStream without calling start/end
233 writeMessageBytesImpl(id, val, size);
234 return true;
Yi Jin974a9c22017-10-02 18:37:08 -0700235 default:
236 ALOGW("Field type %d is not supported when writing char[] val.",
237 (int)((fieldId & FIELD_TYPE_MASK) >> FIELD_TYPE_SHIFT));
238 return false;
239 }
240}
241
242/**
243 * Make a token.
244 * Bits 61-63 - tag size (So we can go backwards later if the object had not data)
245 * - 3 bits, max value 7, max value needed 5
246 * Bit 60 - true if the object is repeated
247 * Bits 59-51 - depth (For error checking)
Yi Jin00a75442018-03-30 11:01:58 -0700248 * - 9 bits, max value 511, when checking, value is masked (if we really
249 * are more than 511 levels deep)
Yi Jin974a9c22017-10-02 18:37:08 -0700250 * Bits 32-50 - objectId (For error checking)
Yi Jin00a75442018-03-30 11:01:58 -0700251 * - 19 bits, max value 524,287. that's a lot of objects. IDs will wrap
Yi Jin974a9c22017-10-02 18:37:08 -0700252 * because of the overflow, and only the tokens are compared.
253 * Bits 0-31 - offset of the first size field in the buffer.
254 */
Yi Jin00a75442018-03-30 11:01:58 -0700255static uint64_t
256makeToken(uint32_t tagSize, bool repeated, uint32_t depth, uint32_t objectId, size_t sizePos) {
257 return ((UINT64_C(0x07) & (uint64_t)tagSize) << 61)
258 | (repeated ? (UINT64_C(1) << 60) : 0)
259 | (UINT64_C(0x01ff) & (uint64_t)depth) << 51
260 | (UINT64_C(0x07ffff) & (uint64_t)objectId) << 32
261 | (UINT64_C(0x0ffffffff) & (uint64_t)sizePos);
Yi Jin974a9c22017-10-02 18:37:08 -0700262}
263
264/**
265 * Get the encoded tag size from the token.
266 */
Yi Jin00a75442018-03-30 11:01:58 -0700267static uint32_t getTagSizeFromToken(uint64_t token) {
268 return 0x7 & (token >> 61);
Yi Jin974a9c22017-10-02 18:37:08 -0700269}
270
271/**
272 * Get the nesting depth of startObject calls from the token.
273 */
Yi Jin00a75442018-03-30 11:01:58 -0700274static uint32_t getDepthFromToken(uint64_t token) {
275 return 0x01ff & (token >> 51);
Yi Jin974a9c22017-10-02 18:37:08 -0700276}
277
278/**
279 * Get the location of the childRawSize (the first 32 bit size field) in this object.
280 */
Yi Jin00a75442018-03-30 11:01:58 -0700281static uint32_t getSizePosFromToken(uint64_t token) {
282 return (uint32_t)token;
Yi Jin974a9c22017-10-02 18:37:08 -0700283}
284
Yi Jin5ee07872018-03-05 18:18:27 -0800285uint64_t
Yi Jin974a9c22017-10-02 18:37:08 -0700286ProtoOutputStream::start(uint64_t fieldId)
287{
Yi Jin04625ad2017-10-17 18:29:33 -0700288 if ((fieldId & FIELD_TYPE_MASK) != FIELD_TYPE_MESSAGE) {
Yi Jin00a75442018-03-30 11:01:58 -0700289 ALOGE("Can't call start for non-message type field: 0x%" PRIx64, fieldId);
Yi Jin974a9c22017-10-02 18:37:08 -0700290 return 0;
291 }
292
293 uint32_t id = (uint32_t)fieldId;
Yi Jin295d9b12018-02-02 14:33:20 -0800294 size_t prevPos = mBuffer.wp()->pos();
Yi Jin974a9c22017-10-02 18:37:08 -0700295 mBuffer.writeHeader(id, WIRE_TYPE_LENGTH_DELIMITED);
Yi Jin974a9c22017-10-02 18:37:08 -0700296 size_t sizePos = mBuffer.wp()->pos();
297
298 mDepth++;
299 mObjectId++;
300 mBuffer.writeRawFixed64(mExpectedObjectToken); // push previous token into stack.
301
Yi Jin295d9b12018-02-02 14:33:20 -0800302 mExpectedObjectToken = makeToken(sizePos - prevPos,
Yi Jin974a9c22017-10-02 18:37:08 -0700303 (bool)(fieldId & FIELD_COUNT_REPEATED), mDepth, mObjectId, sizePos);
304 return mExpectedObjectToken;
305}
306
307void
Yi Jin5ee07872018-03-05 18:18:27 -0800308ProtoOutputStream::end(uint64_t token)
Yi Jin974a9c22017-10-02 18:37:08 -0700309{
310 if (token != mExpectedObjectToken) {
Yi Jin00a75442018-03-30 11:01:58 -0700311 ALOGE("Unexpected token: 0x%" PRIx64 ", should be 0x%" PRIx64, token, mExpectedObjectToken);
Yi Jin974a9c22017-10-02 18:37:08 -0700312 return;
313 }
314
Yi Jin00a75442018-03-30 11:01:58 -0700315 uint32_t depth = getDepthFromToken(token);
Yi Jin974a9c22017-10-02 18:37:08 -0700316 if (depth != (mDepth & 0x01ff)) {
Yi Jin00a75442018-03-30 11:01:58 -0700317 ALOGE("Unexpected depth: %" PRIu32 ", should be %" PRIu32, depth, mDepth);
Yi Jin974a9c22017-10-02 18:37:08 -0700318 return;
319 }
320 mDepth--;
321
Yi Jin00a75442018-03-30 11:01:58 -0700322 uint32_t sizePos = getSizePosFromToken(token);
Yi Jin974a9c22017-10-02 18:37:08 -0700323 // number of bytes written in this start-end session.
324 int childRawSize = mBuffer.wp()->pos() - sizePos - 8;
325
326 // retrieve the old token from stack.
327 mBuffer.ep()->rewind()->move(sizePos);
328 mExpectedObjectToken = mBuffer.readRawFixed64();
329
330 // If raw size is larger than 0, write the negative value here to indicate a compact is needed.
331 if (childRawSize > 0) {
332 mBuffer.editRawFixed32(sizePos, -childRawSize);
333 mBuffer.editRawFixed32(sizePos+4, -1);
334 } else {
335 // reset wp which erase the header tag of the message when its size is 0.
336 mBuffer.wp()->rewind()->move(sizePos - getTagSizeFromToken(token));
337 }
338}
339
Yi Jin0abdfb02017-11-16 15:32:27 -0800340size_t
341ProtoOutputStream::bytesWritten()
342{
343 return mBuffer.size();
344}
345
Yi Jin974a9c22017-10-02 18:37:08 -0700346bool
347ProtoOutputStream::compact() {
348 if (mCompact) return true;
349 if (mDepth != 0) {
Yi Jin00a75442018-03-30 11:01:58 -0700350 ALOGE("Can't compact when depth(%" PRIu32 ") is not zero. Missing calls to end.", mDepth);
Yi Jin974a9c22017-10-02 18:37:08 -0700351 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{
Yi Jin00a75442018-03-30 11:01:58 -0700491 if (!compact()) {
492 ALOGE("compact failed, the ProtoOutputStream data is corrupted!");
493 // TODO: handle this error
494 }
Yi Jin42711a02017-10-11 18:20:24 -0700495 return mBuffer.size();
496}
497
Yi Jin974a9c22017-10-02 18:37:08 -0700498static bool write_all(int fd, uint8_t const* buf, size_t size)
499{
500 while (size > 0) {
501 ssize_t amt = ::write(fd, buf, size);
502 if (amt < 0) {
503 return false;
504 }
505 size -= amt;
506 buf += amt;
507 }
508 return true;
509}
510
511bool
Yi Jin42711a02017-10-11 18:20:24 -0700512ProtoOutputStream::flush(int fd)
Yi Jin974a9c22017-10-02 18:37:08 -0700513{
Yi Jin42711a02017-10-11 18:20:24 -0700514 if (fd < 0) return false;
Yi Jin974a9c22017-10-02 18:37:08 -0700515 if (!compact()) return false;
516
517 EncodedBuffer::iterator it = mBuffer.begin();
518 while (it.readBuffer() != NULL) {
Yi Jin42711a02017-10-11 18:20:24 -0700519 if (!write_all(fd, it.readBuffer(), it.currentToRead())) return false;
Yi Jin974a9c22017-10-02 18:37:08 -0700520 it.rp()->move(it.currentToRead());
521 }
522 return true;
523}
524
Yi Jin42711a02017-10-11 18:20:24 -0700525EncodedBuffer::iterator
526ProtoOutputStream::data()
527{
Yi Jin00a75442018-03-30 11:01:58 -0700528 if (!compact()) {
529 ALOGE("compact failed, the ProtoOutputStream data is corrupted!");
530 // TODO: handle this error
531 }
Yi Jin42711a02017-10-11 18:20:24 -0700532 return mBuffer.begin();
533}
534
535void
536ProtoOutputStream::writeRawVarint(uint64_t varint)
537{
538 mBuffer.writeRawVarint64(varint);
539}
540
541void
542ProtoOutputStream::writeLengthDelimitedHeader(uint32_t id, size_t size)
543{
544 mBuffer.writeHeader(id, WIRE_TYPE_LENGTH_DELIMITED);
545 // reserves 64 bits for length delimited fields, if first field is negative, compact it.
546 mBuffer.writeRawFixed32(size);
547 mBuffer.writeRawFixed32(size);
548}
549
550void
551ProtoOutputStream::writeRawByte(uint8_t byte)
552{
553 mBuffer.writeRawByte(byte);
554}
555
Yi Jin974a9c22017-10-02 18:37:08 -0700556
557// =========================================================================
558// Private functions
559
560/**
561 * bit_cast
562 */
563template <class From, class To>
564inline To bit_cast(From const &from) {
565 To to;
566 memcpy(&to, &from, sizeof(to));
567 return to;
568}
569
570inline void
571ProtoOutputStream::writeDoubleImpl(uint32_t id, double val)
572{
Yi Jin974a9c22017-10-02 18:37:08 -0700573 mBuffer.writeHeader(id, WIRE_TYPE_FIXED64);
574 mBuffer.writeRawFixed64(bit_cast<double, uint64_t>(val));
575}
576
577inline void
578ProtoOutputStream::writeFloatImpl(uint32_t id, float val)
579{
Yi Jin974a9c22017-10-02 18:37:08 -0700580 mBuffer.writeHeader(id, WIRE_TYPE_FIXED32);
581 mBuffer.writeRawFixed32(bit_cast<float, uint32_t>(val));
582}
583
584inline void
585ProtoOutputStream::writeInt64Impl(uint32_t id, long long val)
586{
Yi Jin974a9c22017-10-02 18:37:08 -0700587 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
588 mBuffer.writeRawVarint64((uint64_t)val);
589}
590
591inline void
592ProtoOutputStream::writeInt32Impl(uint32_t id, int val)
593{
Yi Jin974a9c22017-10-02 18:37:08 -0700594 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
595 mBuffer.writeRawVarint32((uint32_t)val);
596}
597
598inline void
599ProtoOutputStream::writeUint64Impl(uint32_t id, uint64_t val)
600{
Yi Jin974a9c22017-10-02 18:37:08 -0700601 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
602 mBuffer.writeRawVarint64(val);
603}
604
605inline void
606ProtoOutputStream::writeUint32Impl(uint32_t id, uint32_t val)
607{
Yi Jin974a9c22017-10-02 18:37:08 -0700608 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
609 mBuffer.writeRawVarint32(val);
610}
611
612inline void
613ProtoOutputStream::writeFixed64Impl(uint32_t id, uint64_t val)
614{
Yi Jin974a9c22017-10-02 18:37:08 -0700615 mBuffer.writeHeader(id, WIRE_TYPE_FIXED64);
616 mBuffer.writeRawFixed64(val);
617}
618
619inline void
620ProtoOutputStream::writeFixed32Impl(uint32_t id, uint32_t val)
621{
Yi Jin974a9c22017-10-02 18:37:08 -0700622 mBuffer.writeHeader(id, WIRE_TYPE_FIXED32);
623 mBuffer.writeRawFixed32(val);
624}
625
626inline void
627ProtoOutputStream::writeSFixed64Impl(uint32_t id, long long val)
628{
Yi Jin974a9c22017-10-02 18:37:08 -0700629 mBuffer.writeHeader(id, WIRE_TYPE_FIXED64);
630 mBuffer.writeRawFixed64((uint64_t)val);
631}
632
633inline void
634ProtoOutputStream::writeSFixed32Impl(uint32_t id, int val)
635{
Yi Jin974a9c22017-10-02 18:37:08 -0700636 mBuffer.writeHeader(id, WIRE_TYPE_FIXED32);
637 mBuffer.writeRawFixed32((uint32_t)val);
638}
639
640inline void
641ProtoOutputStream::writeZigzagInt64Impl(uint32_t id, long long val)
642{
Yi Jin974a9c22017-10-02 18:37:08 -0700643 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
644 mBuffer.writeRawVarint64((val << 1) ^ (val >> 63));
645}
646
647inline void
648ProtoOutputStream::writeZigzagInt32Impl(uint32_t id, int val)
649{
Yi Jin974a9c22017-10-02 18:37:08 -0700650 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
651 mBuffer.writeRawVarint32((val << 1) ^ (val >> 31));
652}
653
654inline void
655ProtoOutputStream::writeEnumImpl(uint32_t id, int val)
656{
657 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
658 mBuffer.writeRawVarint32((uint32_t) val);
659}
660
661inline void
662ProtoOutputStream::writeBoolImpl(uint32_t id, bool val)
663{
Yi Jin974a9c22017-10-02 18:37:08 -0700664 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
665 mBuffer.writeRawVarint32(val ? 1 : 0);
666}
667
668inline void
669ProtoOutputStream::writeUtf8StringImpl(uint32_t id, const char* val, size_t size)
670{
Yi Jin04625ad2017-10-17 18:29:33 -0700671 if (val == NULL) return;
Yi Jin42711a02017-10-11 18:20:24 -0700672 writeLengthDelimitedHeader(id, size);
Yi Jin974a9c22017-10-02 18:37:08 -0700673 for (size_t i=0; i<size; i++) {
674 mBuffer.writeRawByte((uint8_t)val[i]);
675 }
676}
677
Yi Jin8ad19382017-10-30 16:07:20 -0700678inline void
679ProtoOutputStream::writeMessageBytesImpl(uint32_t id, const char* val, size_t size)
680{
681 if (val == NULL) return;
682 writeLengthDelimitedHeader(id, size);
683 for (size_t i=0; i<size; i++) {
684 mBuffer.writeRawByte(val[i]);
685 }
686}
687
Yi Jin974a9c22017-10-02 18:37:08 -0700688} // util
689} // android
690