blob: 0c62d522bd800d68e76549c0871383a596a09bd6 [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 Jinfd2a4c72018-04-26 11:49:08 -070018#include <cinttypes>
19#include <type_traits>
Yi Jin00a75442018-03-30 11:01:58 -070020
Yi Jinc5b71ee2018-04-25 16:51:40 -070021#include <android-base/file.h>
Yi Jin974a9c22017-10-02 18:37:08 -070022#include <android/util/protobuf.h>
23#include <android/util/ProtoOutputStream.h>
24#include <cutils/log.h>
Yi Jin974a9c22017-10-02 18:37:08 -070025
26namespace android {
27namespace util {
28
Yi Jin42711a02017-10-11 18:20:24 -070029ProtoOutputStream::ProtoOutputStream()
Yi Jin974a9c22017-10-02 18:37:08 -070030 :mBuffer(),
Yi Jin974a9c22017-10-02 18:37:08 -070031 mCopyBegin(0),
32 mCompact(false),
33 mDepth(0),
34 mObjectId(0),
Yi Jin00a75442018-03-30 11:01:58 -070035 mExpectedObjectToken(UINT64_C(-1))
Yi Jin974a9c22017-10-02 18:37:08 -070036{
37}
38
39ProtoOutputStream::~ProtoOutputStream()
40{
41}
42
Yi Jin7f9e63b2018-02-02 16:25:11 -080043
44void
45ProtoOutputStream::clear()
46{
47 mBuffer.clear();
48 mCopyBegin = 0;
49 mCompact = false;
50 mDepth = 0;
51 mObjectId = 0;
Yi Jin00a75442018-03-30 11:01:58 -070052 mExpectedObjectToken = UINT64_C(-1);
Yi Jin7f9e63b2018-02-02 16:25:11 -080053}
54
Yi Jinfd2a4c72018-04-26 11:49:08 -070055template<typename T>
Yi Jin974a9c22017-10-02 18:37:08 -070056bool
Yi Jinfd2a4c72018-04-26 11:49:08 -070057ProtoOutputStream::internalWrite(uint64_t fieldId, T val, const char* typeName)
Yi Jin974a9c22017-10-02 18:37:08 -070058{
59 if (mCompact) return false;
60 const uint32_t id = (uint32_t)fieldId;
61 switch (fieldId & FIELD_TYPE_MASK) {
Yi Jin04625ad2017-10-17 18:29:33 -070062 case FIELD_TYPE_DOUBLE: writeDoubleImpl(id, (double)val); break;
63 case FIELD_TYPE_FLOAT: writeFloatImpl(id, (float)val); break;
Yi Jinfd2a4c72018-04-26 11:49:08 -070064 case FIELD_TYPE_INT64: writeInt64Impl(id, (int64_t)val); break;
Yi Jin04625ad2017-10-17 18:29:33 -070065 case FIELD_TYPE_UINT64: writeUint64Impl(id, (uint64_t)val); break;
Yi Jinfd2a4c72018-04-26 11:49:08 -070066 case FIELD_TYPE_INT32: writeInt32Impl(id, (int32_t)val); break;
Yi Jin04625ad2017-10-17 18:29:33 -070067 case FIELD_TYPE_FIXED64: writeFixed64Impl(id, (uint64_t)val); break;
68 case FIELD_TYPE_FIXED32: writeFixed32Impl(id, (uint32_t)val); break;
69 case FIELD_TYPE_UINT32: writeUint32Impl(id, (uint32_t)val); break;
Yi Jinfd2a4c72018-04-26 11:49:08 -070070 case FIELD_TYPE_SFIXED32: writeSFixed32Impl(id, (int32_t)val); break;
71 case FIELD_TYPE_SFIXED64: writeSFixed64Impl(id, (int64_t)val); break;
72 case FIELD_TYPE_SINT32: writeZigzagInt32Impl(id, (int32_t)val); break;
73 case FIELD_TYPE_SINT64: writeZigzagInt64Impl(id, (int64_t)val); break;
74 case FIELD_TYPE_ENUM:
75 if (std::is_integral<T>::value) {
76 writeEnumImpl(id, (int)val);
77 } else {
78 goto unsupported;
79 }
80 break;
81 case FIELD_TYPE_BOOL:
82 if (std::is_integral<T>::value) {
83 writeBoolImpl(id, val != 0);
84 } else {
85 goto unsupported;
86 }
87 break;
Yi Jin974a9c22017-10-02 18:37:08 -070088 default:
Yi Jinfd2a4c72018-04-26 11:49:08 -070089 goto unsupported;
Yi Jin974a9c22017-10-02 18:37:08 -070090 }
91 return true;
Yi Jinfd2a4c72018-04-26 11:49:08 -070092
93unsupported:
94 ALOGW("Field type %" PRIu64 " is not supported when writing %s val.",
95 (fieldId & FIELD_TYPE_MASK) >> FIELD_TYPE_SHIFT, typeName);
96 return false;
Yi Jin974a9c22017-10-02 18:37:08 -070097}
98
99bool
Yi Jinfd2a4c72018-04-26 11:49:08 -0700100ProtoOutputStream::write(uint64_t fieldId, double val)
101{
102 return internalWrite(fieldId, val, "double");
103}
104
105
106bool
Yi Jin974a9c22017-10-02 18:37:08 -0700107ProtoOutputStream::write(uint64_t fieldId, float val)
108{
Yi Jinfd2a4c72018-04-26 11:49:08 -0700109 return internalWrite(fieldId, val, "float");
Yi Jin974a9c22017-10-02 18:37:08 -0700110}
111
112bool
113ProtoOutputStream::write(uint64_t fieldId, int val)
114{
Yi Jinfd2a4c72018-04-26 11:49:08 -0700115 return internalWrite(fieldId, val, "int");
Yi Jin974a9c22017-10-02 18:37:08 -0700116}
117
118bool
Colin Crossfa6bc272018-10-26 13:04:41 -0700119ProtoOutputStream::write(uint64_t fieldId, long val)
120{
121 if (mCompact) return false;
122 const uint32_t id = (uint32_t)fieldId;
123 switch (fieldId & FIELD_TYPE_MASK) {
124 case FIELD_TYPE_DOUBLE: writeDoubleImpl(id, (double)val); break;
125 case FIELD_TYPE_FLOAT: writeFloatImpl(id, (float)val); break;
126 case FIELD_TYPE_INT64: writeInt64Impl(id, (long long)val); break;
127 case FIELD_TYPE_UINT64: writeUint64Impl(id, (uint64_t)val); break;
128 case FIELD_TYPE_INT32: writeInt32Impl(id, (int)val); break;
129 case FIELD_TYPE_FIXED64: writeFixed64Impl(id, (uint64_t)val); break;
130 case FIELD_TYPE_FIXED32: writeFixed32Impl(id, (uint32_t)val); break;
131 case FIELD_TYPE_UINT32: writeUint32Impl(id, (uint32_t)val); break;
132 case FIELD_TYPE_SFIXED32: writeSFixed32Impl(id, (int)val); break;
133 case FIELD_TYPE_SFIXED64: writeSFixed64Impl(id, (long long)val); break;
134 case FIELD_TYPE_SINT32: writeZigzagInt32Impl(id, (int)val); break;
135 case FIELD_TYPE_SINT64: writeZigzagInt64Impl(id, (long long)val); break;
136 case FIELD_TYPE_ENUM: writeEnumImpl(id, (int)val); break;
137 case FIELD_TYPE_BOOL: writeBoolImpl(id, val != 0); break;
138 default:
139 ALOGW("Field type %d is not supported when writing long val.",
140 (int)((fieldId & FIELD_TYPE_MASK) >> FIELD_TYPE_SHIFT));
141 return false;
142 }
143 return true;
144}
145
146bool
Yi Jin974a9c22017-10-02 18:37:08 -0700147ProtoOutputStream::write(uint64_t fieldId, long long val)
148{
Yi Jinfd2a4c72018-04-26 11:49:08 -0700149 return internalWrite(fieldId, val, "long long");
Yi Jin974a9c22017-10-02 18:37:08 -0700150}
151
152bool
153ProtoOutputStream::write(uint64_t fieldId, bool val)
154{
155 if (mCompact) return false;
156 const uint32_t id = (uint32_t)fieldId;
157 switch (fieldId & FIELD_TYPE_MASK) {
Yi Jin04625ad2017-10-17 18:29:33 -0700158 case FIELD_TYPE_BOOL:
Yi Jin974a9c22017-10-02 18:37:08 -0700159 writeBoolImpl(id, val);
160 return true;
161 default:
Yi Jinfd2a4c72018-04-26 11:49:08 -0700162 ALOGW("Field type %" PRIu64 " is not supported when writing bool val.",
163 (fieldId & FIELD_TYPE_MASK) >> FIELD_TYPE_SHIFT);
Yi Jin974a9c22017-10-02 18:37:08 -0700164 return false;
165 }
166}
167
168bool
Yi Jin6cacbcb2018-03-30 14:04:52 -0700169ProtoOutputStream::write(uint64_t fieldId, std::string val)
Yi Jin974a9c22017-10-02 18:37:08 -0700170{
171 if (mCompact) return false;
172 const uint32_t id = (uint32_t)fieldId;
173 switch (fieldId & FIELD_TYPE_MASK) {
Yi Jin04625ad2017-10-17 18:29:33 -0700174 case FIELD_TYPE_STRING:
Yi Jin974a9c22017-10-02 18:37:08 -0700175 writeUtf8StringImpl(id, val.c_str(), val.size());
176 return true;
177 default:
Yi Jinfd2a4c72018-04-26 11:49:08 -0700178 ALOGW("Field type %" PRIu64 " is not supported when writing string val.",
179 (fieldId & FIELD_TYPE_MASK) >> FIELD_TYPE_SHIFT);
Yi Jin974a9c22017-10-02 18:37:08 -0700180 return false;
181 }
182}
183
184bool
Yi Jine0833302017-10-23 15:42:44 -0700185ProtoOutputStream::write(uint64_t fieldId, const char* val, size_t size)
Yi Jin974a9c22017-10-02 18:37:08 -0700186{
187 if (mCompact) return false;
188 const uint32_t id = (uint32_t)fieldId;
Yi Jin974a9c22017-10-02 18:37:08 -0700189 switch (fieldId & FIELD_TYPE_MASK) {
Yi Jin04625ad2017-10-17 18:29:33 -0700190 case FIELD_TYPE_STRING:
191 case FIELD_TYPE_BYTES:
Yi Jin974a9c22017-10-02 18:37:08 -0700192 writeUtf8StringImpl(id, val, size);
193 return true;
Yi Jin04625ad2017-10-17 18:29:33 -0700194 case FIELD_TYPE_MESSAGE:
Yi Jin8ad19382017-10-30 16:07:20 -0700195 // can directly write valid format of message bytes into ProtoOutputStream without calling start/end
196 writeMessageBytesImpl(id, val, size);
197 return true;
Yi Jin974a9c22017-10-02 18:37:08 -0700198 default:
Yi Jinfd2a4c72018-04-26 11:49:08 -0700199 ALOGW("Field type %" PRIu64 " is not supported when writing char[] val.",
200 (fieldId & FIELD_TYPE_MASK) >> FIELD_TYPE_SHIFT);
Yi Jin974a9c22017-10-02 18:37:08 -0700201 return false;
202 }
203}
204
205/**
206 * Make a token.
207 * Bits 61-63 - tag size (So we can go backwards later if the object had not data)
208 * - 3 bits, max value 7, max value needed 5
209 * Bit 60 - true if the object is repeated
210 * Bits 59-51 - depth (For error checking)
Yi Jin00a75442018-03-30 11:01:58 -0700211 * - 9 bits, max value 511, when checking, value is masked (if we really
212 * are more than 511 levels deep)
Yi Jin974a9c22017-10-02 18:37:08 -0700213 * Bits 32-50 - objectId (For error checking)
Yi Jin00a75442018-03-30 11:01:58 -0700214 * - 19 bits, max value 524,287. that's a lot of objects. IDs will wrap
Yi Jin974a9c22017-10-02 18:37:08 -0700215 * because of the overflow, and only the tokens are compared.
216 * Bits 0-31 - offset of the first size field in the buffer.
217 */
Yi Jin00a75442018-03-30 11:01:58 -0700218static uint64_t
219makeToken(uint32_t tagSize, bool repeated, uint32_t depth, uint32_t objectId, size_t sizePos) {
220 return ((UINT64_C(0x07) & (uint64_t)tagSize) << 61)
221 | (repeated ? (UINT64_C(1) << 60) : 0)
222 | (UINT64_C(0x01ff) & (uint64_t)depth) << 51
223 | (UINT64_C(0x07ffff) & (uint64_t)objectId) << 32
224 | (UINT64_C(0x0ffffffff) & (uint64_t)sizePos);
Yi Jin974a9c22017-10-02 18:37:08 -0700225}
226
227/**
228 * Get the encoded tag size from the token.
229 */
Yi Jin00a75442018-03-30 11:01:58 -0700230static uint32_t getTagSizeFromToken(uint64_t token) {
231 return 0x7 & (token >> 61);
Yi Jin974a9c22017-10-02 18:37:08 -0700232}
233
234/**
235 * Get the nesting depth of startObject calls from the token.
236 */
Yi Jin00a75442018-03-30 11:01:58 -0700237static uint32_t getDepthFromToken(uint64_t token) {
238 return 0x01ff & (token >> 51);
Yi Jin974a9c22017-10-02 18:37:08 -0700239}
240
241/**
242 * Get the location of the childRawSize (the first 32 bit size field) in this object.
243 */
Yi Jin00a75442018-03-30 11:01:58 -0700244static uint32_t getSizePosFromToken(uint64_t token) {
245 return (uint32_t)token;
Yi Jin974a9c22017-10-02 18:37:08 -0700246}
247
Yi Jin5ee07872018-03-05 18:18:27 -0800248uint64_t
Yi Jin974a9c22017-10-02 18:37:08 -0700249ProtoOutputStream::start(uint64_t fieldId)
250{
Yi Jin04625ad2017-10-17 18:29:33 -0700251 if ((fieldId & FIELD_TYPE_MASK) != FIELD_TYPE_MESSAGE) {
Yi Jin00a75442018-03-30 11:01:58 -0700252 ALOGE("Can't call start for non-message type field: 0x%" PRIx64, fieldId);
Yi Jin974a9c22017-10-02 18:37:08 -0700253 return 0;
254 }
255
256 uint32_t id = (uint32_t)fieldId;
Yi Jin295d9b12018-02-02 14:33:20 -0800257 size_t prevPos = mBuffer.wp()->pos();
Yi Jin974a9c22017-10-02 18:37:08 -0700258 mBuffer.writeHeader(id, WIRE_TYPE_LENGTH_DELIMITED);
Yi Jin974a9c22017-10-02 18:37:08 -0700259 size_t sizePos = mBuffer.wp()->pos();
260
261 mDepth++;
262 mObjectId++;
263 mBuffer.writeRawFixed64(mExpectedObjectToken); // push previous token into stack.
264
Yi Jin295d9b12018-02-02 14:33:20 -0800265 mExpectedObjectToken = makeToken(sizePos - prevPos,
Yi Jin974a9c22017-10-02 18:37:08 -0700266 (bool)(fieldId & FIELD_COUNT_REPEATED), mDepth, mObjectId, sizePos);
267 return mExpectedObjectToken;
268}
269
270void
Yi Jin5ee07872018-03-05 18:18:27 -0800271ProtoOutputStream::end(uint64_t token)
Yi Jin974a9c22017-10-02 18:37:08 -0700272{
273 if (token != mExpectedObjectToken) {
Yi Jin00a75442018-03-30 11:01:58 -0700274 ALOGE("Unexpected token: 0x%" PRIx64 ", should be 0x%" PRIx64, token, mExpectedObjectToken);
Yi Jin18678bd2018-04-27 11:51:13 -0700275 mDepth = UINT32_C(-1); // make depth invalid
Yi Jin974a9c22017-10-02 18:37:08 -0700276 return;
277 }
278
Yi Jin00a75442018-03-30 11:01:58 -0700279 uint32_t depth = getDepthFromToken(token);
Yi Jin974a9c22017-10-02 18:37:08 -0700280 if (depth != (mDepth & 0x01ff)) {
Yi Jin00a75442018-03-30 11:01:58 -0700281 ALOGE("Unexpected depth: %" PRIu32 ", should be %" PRIu32, depth, mDepth);
Yi Jin18678bd2018-04-27 11:51:13 -0700282 mDepth = UINT32_C(-1); // make depth invalid
Yi Jin974a9c22017-10-02 18:37:08 -0700283 return;
284 }
285 mDepth--;
286
Yi Jin00a75442018-03-30 11:01:58 -0700287 uint32_t sizePos = getSizePosFromToken(token);
Yi Jin974a9c22017-10-02 18:37:08 -0700288 // number of bytes written in this start-end session.
289 int childRawSize = mBuffer.wp()->pos() - sizePos - 8;
290
291 // retrieve the old token from stack.
292 mBuffer.ep()->rewind()->move(sizePos);
293 mExpectedObjectToken = mBuffer.readRawFixed64();
294
295 // If raw size is larger than 0, write the negative value here to indicate a compact is needed.
296 if (childRawSize > 0) {
297 mBuffer.editRawFixed32(sizePos, -childRawSize);
298 mBuffer.editRawFixed32(sizePos+4, -1);
299 } else {
300 // reset wp which erase the header tag of the message when its size is 0.
301 mBuffer.wp()->rewind()->move(sizePos - getTagSizeFromToken(token));
302 }
303}
304
Yi Jin0abdfb02017-11-16 15:32:27 -0800305size_t
306ProtoOutputStream::bytesWritten()
307{
308 return mBuffer.size();
309}
310
Yi Jin974a9c22017-10-02 18:37:08 -0700311bool
312ProtoOutputStream::compact() {
313 if (mCompact) return true;
314 if (mDepth != 0) {
Yi Jin18678bd2018-04-27 11:51:13 -0700315 ALOGE("Can't compact when depth(%" PRIu32 ") is not zero. Missing or extra calls to end.", mDepth);
Yi Jin974a9c22017-10-02 18:37:08 -0700316 return false;
317 }
318 // record the size of the original buffer.
319 size_t rawBufferSize = mBuffer.size();
320 if (rawBufferSize == 0) return true; // nothing to do if the buffer is empty;
321
322 // reset edit pointer and recursively compute encoded size of messages.
323 mBuffer.ep()->rewind();
324 if (editEncodedSize(rawBufferSize) == 0) {
325 ALOGE("Failed to editEncodedSize.");
326 return false;
327 }
328
329 // reset both edit pointer and write pointer, and compact recursively.
330 mBuffer.ep()->rewind();
331 mBuffer.wp()->rewind();
332 if (!compactSize(rawBufferSize)) {
333 ALOGE("Failed to compactSize.");
334 return false;
335 }
336 // copy the reset to the buffer.
337 if (mCopyBegin < rawBufferSize) {
338 mBuffer.copy(mCopyBegin, rawBufferSize - mCopyBegin);
339 }
340
341 // mark true means it is not legal to write to this ProtoOutputStream anymore
342 mCompact = true;
343 return true;
344}
345
346/**
347 * First compaction pass. Iterate through the data, and fill in the
348 * nested object sizes so the next pass can compact them.
349 */
350size_t
351ProtoOutputStream::editEncodedSize(size_t rawSize)
352{
353 size_t objectStart = mBuffer.ep()->pos();
354 size_t objectEnd = objectStart + rawSize;
355 size_t encodedSize = 0;
356 int childRawSize, childEncodedSize;
357 size_t childEncodedSizePos;
358
359 while (mBuffer.ep()->pos() < objectEnd) {
360 uint32_t tag = (uint32_t)mBuffer.readRawVarint();
361 encodedSize += get_varint_size(tag);
362 switch (read_wire_type(tag)) {
363 case WIRE_TYPE_VARINT:
364 do {
365 encodedSize++;
366 } while ((mBuffer.readRawByte() & 0x80) != 0);
367 break;
368 case WIRE_TYPE_FIXED64:
369 encodedSize += 8;
370 mBuffer.ep()->move(8);
371 break;
372 case WIRE_TYPE_LENGTH_DELIMITED:
373 childRawSize = (int)mBuffer.readRawFixed32();
374 childEncodedSizePos = mBuffer.ep()->pos();
375 childEncodedSize = (int)mBuffer.readRawFixed32();
376 if (childRawSize >= 0 && childRawSize == childEncodedSize) {
377 mBuffer.ep()->move(childRawSize);
378 } else if (childRawSize < 0 && childEncodedSize == -1){
379 childEncodedSize = editEncodedSize(-childRawSize);
380 mBuffer.editRawFixed32(childEncodedSizePos, childEncodedSize);
381 } else {
382 ALOGE("Bad raw or encoded values: raw=%d, encoded=%d at %zu",
383 childRawSize, childEncodedSize, childEncodedSizePos);
384 return 0;
385 }
386 encodedSize += get_varint_size(childEncodedSize) + childEncodedSize;
387 break;
388 case WIRE_TYPE_FIXED32:
389 encodedSize += 4;
390 mBuffer.ep()->move(4);
391 break;
392 default:
393 ALOGE("Unexpected wire type %d in editEncodedSize at [%zu, %zu]",
394 read_wire_type(tag), objectStart, objectEnd);
395 return 0;
396 }
397 }
398 return encodedSize;
399}
400
401/**
402 * Second compaction pass. Iterate through the data, and copy the data
403 * forward in the buffer, converting the pairs of uint32s into a single
404 * unsigned varint of the size.
405 */
406bool
407ProtoOutputStream::compactSize(size_t rawSize)
408{
409 size_t objectStart = mBuffer.ep()->pos();
410 size_t objectEnd = objectStart + rawSize;
411 int childRawSize, childEncodedSize;
412
413 while (mBuffer.ep()->pos() < objectEnd) {
414 uint32_t tag = (uint32_t)mBuffer.readRawVarint();
415 switch (read_wire_type(tag)) {
416 case WIRE_TYPE_VARINT:
417 while ((mBuffer.readRawByte() & 0x80) != 0) {}
418 break;
419 case WIRE_TYPE_FIXED64:
420 mBuffer.ep()->move(8);
421 break;
422 case WIRE_TYPE_LENGTH_DELIMITED:
423 mBuffer.copy(mCopyBegin, mBuffer.ep()->pos() - mCopyBegin);
424
425 childRawSize = (int)mBuffer.readRawFixed32();
426 childEncodedSize = (int)mBuffer.readRawFixed32();
427 mCopyBegin = mBuffer.ep()->pos();
428
429 // write encoded size to buffer.
430 mBuffer.writeRawVarint32(childEncodedSize);
431 if (childRawSize >= 0 && childRawSize == childEncodedSize) {
432 mBuffer.ep()->move(childEncodedSize);
433 } else if (childRawSize < 0){
434 if (!compactSize(-childRawSize)) return false;
435 } else {
436 ALOGE("Bad raw or encoded values: raw=%d, encoded=%d",
437 childRawSize, childEncodedSize);
438 return false;
439 }
440 break;
441 case WIRE_TYPE_FIXED32:
442 mBuffer.ep()->move(4);
443 break;
444 default:
445 ALOGE("Unexpected wire type %d in compactSize at [%zu, %zu]",
446 read_wire_type(tag), objectStart, objectEnd);
447 return false;
448 }
449 }
450 return true;
451}
452
Yi Jin42711a02017-10-11 18:20:24 -0700453size_t
454ProtoOutputStream::size()
455{
Yi Jin00a75442018-03-30 11:01:58 -0700456 if (!compact()) {
457 ALOGE("compact failed, the ProtoOutputStream data is corrupted!");
Yi Jin18678bd2018-04-27 11:51:13 -0700458 return 0;
Yi Jin00a75442018-03-30 11:01:58 -0700459 }
Yi Jin42711a02017-10-11 18:20:24 -0700460 return mBuffer.size();
461}
462
Yi Jin974a9c22017-10-02 18:37:08 -0700463bool
Yi Jin42711a02017-10-11 18:20:24 -0700464ProtoOutputStream::flush(int fd)
Yi Jin974a9c22017-10-02 18:37:08 -0700465{
Yi Jin42711a02017-10-11 18:20:24 -0700466 if (fd < 0) return false;
Yi Jin974a9c22017-10-02 18:37:08 -0700467 if (!compact()) return false;
468
469 EncodedBuffer::iterator it = mBuffer.begin();
470 while (it.readBuffer() != NULL) {
Yi Jinc5b71ee2018-04-25 16:51:40 -0700471 if (!android::base::WriteFully(fd, it.readBuffer(), it.currentToRead())) return false;
Yi Jin974a9c22017-10-02 18:37:08 -0700472 it.rp()->move(it.currentToRead());
473 }
474 return true;
475}
476
Yi Jin42711a02017-10-11 18:20:24 -0700477EncodedBuffer::iterator
478ProtoOutputStream::data()
479{
Yi Jin00a75442018-03-30 11:01:58 -0700480 if (!compact()) {
481 ALOGE("compact failed, the ProtoOutputStream data is corrupted!");
Yi Jin18678bd2018-04-27 11:51:13 -0700482 mBuffer.clear();
Yi Jin00a75442018-03-30 11:01:58 -0700483 }
Yi Jin42711a02017-10-11 18:20:24 -0700484 return mBuffer.begin();
485}
486
487void
488ProtoOutputStream::writeRawVarint(uint64_t varint)
489{
490 mBuffer.writeRawVarint64(varint);
491}
492
493void
494ProtoOutputStream::writeLengthDelimitedHeader(uint32_t id, size_t size)
495{
496 mBuffer.writeHeader(id, WIRE_TYPE_LENGTH_DELIMITED);
497 // reserves 64 bits for length delimited fields, if first field is negative, compact it.
498 mBuffer.writeRawFixed32(size);
499 mBuffer.writeRawFixed32(size);
500}
501
502void
503ProtoOutputStream::writeRawByte(uint8_t byte)
504{
505 mBuffer.writeRawByte(byte);
506}
507
Yi Jin974a9c22017-10-02 18:37:08 -0700508
509// =========================================================================
510// Private functions
511
512/**
513 * bit_cast
514 */
515template <class From, class To>
516inline To bit_cast(From const &from) {
517 To to;
518 memcpy(&to, &from, sizeof(to));
519 return to;
520}
521
522inline void
523ProtoOutputStream::writeDoubleImpl(uint32_t id, double val)
524{
Yi Jin974a9c22017-10-02 18:37:08 -0700525 mBuffer.writeHeader(id, WIRE_TYPE_FIXED64);
526 mBuffer.writeRawFixed64(bit_cast<double, uint64_t>(val));
527}
528
529inline void
530ProtoOutputStream::writeFloatImpl(uint32_t id, float val)
531{
Yi Jin974a9c22017-10-02 18:37:08 -0700532 mBuffer.writeHeader(id, WIRE_TYPE_FIXED32);
533 mBuffer.writeRawFixed32(bit_cast<float, uint32_t>(val));
534}
535
536inline void
Yi Jinfd2a4c72018-04-26 11:49:08 -0700537ProtoOutputStream::writeInt64Impl(uint32_t id, int64_t val)
Yi Jin974a9c22017-10-02 18:37:08 -0700538{
Yi Jin974a9c22017-10-02 18:37:08 -0700539 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
Yi Jinfd2a4c72018-04-26 11:49:08 -0700540 mBuffer.writeRawVarint64(val);
Yi Jin974a9c22017-10-02 18:37:08 -0700541}
542
543inline void
Yi Jinfd2a4c72018-04-26 11:49:08 -0700544ProtoOutputStream::writeInt32Impl(uint32_t id, int32_t val)
Yi Jin974a9c22017-10-02 18:37:08 -0700545{
Yi Jin974a9c22017-10-02 18:37:08 -0700546 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
Yi Jinfd2a4c72018-04-26 11:49:08 -0700547 mBuffer.writeRawVarint32(val);
Yi Jin974a9c22017-10-02 18:37:08 -0700548}
549
550inline void
551ProtoOutputStream::writeUint64Impl(uint32_t id, uint64_t val)
552{
Yi Jin974a9c22017-10-02 18:37:08 -0700553 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
554 mBuffer.writeRawVarint64(val);
555}
556
557inline void
558ProtoOutputStream::writeUint32Impl(uint32_t id, uint32_t val)
559{
Yi Jin974a9c22017-10-02 18:37:08 -0700560 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
561 mBuffer.writeRawVarint32(val);
562}
563
564inline void
565ProtoOutputStream::writeFixed64Impl(uint32_t id, uint64_t val)
566{
Yi Jin974a9c22017-10-02 18:37:08 -0700567 mBuffer.writeHeader(id, WIRE_TYPE_FIXED64);
568 mBuffer.writeRawFixed64(val);
569}
570
571inline void
572ProtoOutputStream::writeFixed32Impl(uint32_t id, uint32_t val)
573{
Yi Jin974a9c22017-10-02 18:37:08 -0700574 mBuffer.writeHeader(id, WIRE_TYPE_FIXED32);
575 mBuffer.writeRawFixed32(val);
576}
577
578inline void
Yi Jinfd2a4c72018-04-26 11:49:08 -0700579ProtoOutputStream::writeSFixed64Impl(uint32_t id, int64_t val)
Yi Jin974a9c22017-10-02 18:37:08 -0700580{
Yi Jin974a9c22017-10-02 18:37:08 -0700581 mBuffer.writeHeader(id, WIRE_TYPE_FIXED64);
Yi Jinfd2a4c72018-04-26 11:49:08 -0700582 mBuffer.writeRawFixed64(val);
Yi Jin974a9c22017-10-02 18:37:08 -0700583}
584
585inline void
Yi Jinfd2a4c72018-04-26 11:49:08 -0700586ProtoOutputStream::writeSFixed32Impl(uint32_t id, int32_t val)
Yi Jin974a9c22017-10-02 18:37:08 -0700587{
Yi Jin974a9c22017-10-02 18:37:08 -0700588 mBuffer.writeHeader(id, WIRE_TYPE_FIXED32);
Yi Jinfd2a4c72018-04-26 11:49:08 -0700589 mBuffer.writeRawFixed32(val);
Yi Jin974a9c22017-10-02 18:37:08 -0700590}
591
592inline void
Yi Jinfd2a4c72018-04-26 11:49:08 -0700593ProtoOutputStream::writeZigzagInt64Impl(uint32_t id, int64_t val)
Yi Jin974a9c22017-10-02 18:37:08 -0700594{
Yi Jin974a9c22017-10-02 18:37:08 -0700595 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
596 mBuffer.writeRawVarint64((val << 1) ^ (val >> 63));
597}
598
599inline void
Yi Jinfd2a4c72018-04-26 11:49:08 -0700600ProtoOutputStream::writeZigzagInt32Impl(uint32_t id, int32_t val)
Yi Jin974a9c22017-10-02 18:37:08 -0700601{
Yi Jin974a9c22017-10-02 18:37:08 -0700602 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
603 mBuffer.writeRawVarint32((val << 1) ^ (val >> 31));
604}
605
606inline void
607ProtoOutputStream::writeEnumImpl(uint32_t id, int val)
608{
609 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
610 mBuffer.writeRawVarint32((uint32_t) val);
611}
612
613inline void
614ProtoOutputStream::writeBoolImpl(uint32_t id, bool val)
615{
Yi Jin974a9c22017-10-02 18:37:08 -0700616 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
617 mBuffer.writeRawVarint32(val ? 1 : 0);
618}
619
620inline void
621ProtoOutputStream::writeUtf8StringImpl(uint32_t id, const char* val, size_t size)
622{
Yi Jin04625ad2017-10-17 18:29:33 -0700623 if (val == NULL) return;
Yi Jin42711a02017-10-11 18:20:24 -0700624 writeLengthDelimitedHeader(id, size);
Yi Jin974a9c22017-10-02 18:37:08 -0700625 for (size_t i=0; i<size; i++) {
626 mBuffer.writeRawByte((uint8_t)val[i]);
627 }
628}
629
Yi Jin8ad19382017-10-30 16:07:20 -0700630inline void
631ProtoOutputStream::writeMessageBytesImpl(uint32_t id, const char* val, size_t size)
632{
633 if (val == NULL) return;
634 writeLengthDelimitedHeader(id, size);
635 for (size_t i=0; i<size; i++) {
636 mBuffer.writeRawByte(val[i]);
637 }
638}
639
Yi Jin974a9c22017-10-02 18:37:08 -0700640} // util
641} // android
642