blob: 015727a9a257460df7978a2737cf76cdc62854e0 [file] [log] [blame]
Yi Jin974a9c22017-10-02 18:37:08 -07001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16#define LOG_TAG "libprotoutil"
17
18#include <android/util/protobuf.h>
19#include <android/util/ProtoOutputStream.h>
20#include <cutils/log.h>
Yi Jin974a9c22017-10-02 18:37:08 -070021
22namespace android {
23namespace util {
24
Yi Jin42711a02017-10-11 18:20:24 -070025ProtoOutputStream::ProtoOutputStream()
Yi Jin974a9c22017-10-02 18:37:08 -070026 :mBuffer(),
Yi Jin974a9c22017-10-02 18:37:08 -070027 mCopyBegin(0),
28 mCompact(false),
29 mDepth(0),
30 mObjectId(0),
Yi Jin5ee07872018-03-05 18:18:27 -080031 mExpectedObjectToken(0ULL)
Yi Jin974a9c22017-10-02 18:37:08 -070032{
33}
34
35ProtoOutputStream::~ProtoOutputStream()
36{
37}
38
Yi Jin7f9e63b2018-02-02 16:25:11 -080039
40void
41ProtoOutputStream::clear()
42{
43 mBuffer.clear();
44 mCopyBegin = 0;
45 mCompact = false;
46 mDepth = 0;
47 mObjectId = 0;
Yi Jin5ee07872018-03-05 18:18:27 -080048 mExpectedObjectToken = 0ULL;
Yi Jin7f9e63b2018-02-02 16:25:11 -080049}
50
Yi Jin974a9c22017-10-02 18:37:08 -070051bool
52ProtoOutputStream::write(uint64_t fieldId, double val)
53{
54 if (mCompact) return false;
55 const uint32_t id = (uint32_t)fieldId;
56 switch (fieldId & FIELD_TYPE_MASK) {
Yi Jin04625ad2017-10-17 18:29:33 -070057 case FIELD_TYPE_DOUBLE: writeDoubleImpl(id, (double)val); break;
58 case FIELD_TYPE_FLOAT: writeFloatImpl(id, (float)val); break;
59 case FIELD_TYPE_INT64: writeInt64Impl(id, (long long)val); break;
60 case FIELD_TYPE_UINT64: writeUint64Impl(id, (uint64_t)val); break;
61 case FIELD_TYPE_INT32: writeInt32Impl(id, (int)val); break;
62 case FIELD_TYPE_FIXED64: writeFixed64Impl(id, (uint64_t)val); break;
63 case FIELD_TYPE_FIXED32: writeFixed32Impl(id, (uint32_t)val); break;
64 case FIELD_TYPE_UINT32: writeUint32Impl(id, (uint32_t)val); break;
65 case FIELD_TYPE_SFIXED32: writeSFixed32Impl(id, (int)val); break;
66 case FIELD_TYPE_SFIXED64: writeSFixed64Impl(id, (long long)val); break;
67 case FIELD_TYPE_SINT32: writeZigzagInt32Impl(id, (int)val); break;
68 case FIELD_TYPE_SINT64: writeZigzagInt64Impl(id, (long long)val); break;
Yi Jin974a9c22017-10-02 18:37:08 -070069 default:
70 ALOGW("Field type %d is not supported when writing double val.",
71 (int)((fieldId & FIELD_TYPE_MASK) >> FIELD_TYPE_SHIFT));
72 return false;
73 }
74 return true;
75}
76
77bool
78ProtoOutputStream::write(uint64_t fieldId, float val)
79{
80 if (mCompact) return false;
81 const uint32_t id = (uint32_t)fieldId;
82 switch (fieldId & FIELD_TYPE_MASK) {
Yi Jin04625ad2017-10-17 18:29:33 -070083 case FIELD_TYPE_DOUBLE: writeDoubleImpl(id, (double)val); break;
84 case FIELD_TYPE_FLOAT: writeFloatImpl(id, (float)val); break;
85 case FIELD_TYPE_INT64: writeInt64Impl(id, (long long)val); break;
86 case FIELD_TYPE_UINT64: writeUint64Impl(id, (uint64_t)val); break;
87 case FIELD_TYPE_INT32: writeInt32Impl(id, (int)val); break;
88 case FIELD_TYPE_FIXED64: writeFixed64Impl(id, (uint64_t)val); break;
89 case FIELD_TYPE_FIXED32: writeFixed32Impl(id, (uint32_t)val); break;
90 case FIELD_TYPE_UINT32: writeUint32Impl(id, (uint32_t)val); break;
91 case FIELD_TYPE_SFIXED32: writeSFixed32Impl(id, (int)val); break;
92 case FIELD_TYPE_SFIXED64: writeSFixed64Impl(id, (long long)val); break;
93 case FIELD_TYPE_SINT32: writeZigzagInt32Impl(id, (int)val); break;
94 case FIELD_TYPE_SINT64: writeZigzagInt64Impl(id, (long long)val); break;
Yi Jin974a9c22017-10-02 18:37:08 -070095 default:
96 ALOGW("Field type %d is not supported when writing float val.",
97 (int)((fieldId & FIELD_TYPE_MASK) >> FIELD_TYPE_SHIFT));
98 return false;
99 }
100 return true;
101}
102
103bool
104ProtoOutputStream::write(uint64_t fieldId, int val)
105{
106 if (mCompact) return false;
107 const uint32_t id = (uint32_t)fieldId;
108 switch (fieldId & FIELD_TYPE_MASK) {
Yi Jin04625ad2017-10-17 18:29:33 -0700109 case FIELD_TYPE_DOUBLE: writeDoubleImpl(id, (double)val); break;
110 case FIELD_TYPE_FLOAT: writeFloatImpl(id, (float)val); break;
111 case FIELD_TYPE_INT64: writeInt64Impl(id, (long long)val); break;
112 case FIELD_TYPE_UINT64: writeUint64Impl(id, (uint64_t)val); break;
113 case FIELD_TYPE_INT32: writeInt32Impl(id, (int)val); break;
114 case FIELD_TYPE_FIXED64: writeFixed64Impl(id, (uint64_t)val); break;
115 case FIELD_TYPE_FIXED32: writeFixed32Impl(id, (uint32_t)val); break;
116 case FIELD_TYPE_UINT32: writeUint32Impl(id, (uint32_t)val); break;
117 case FIELD_TYPE_SFIXED32: writeSFixed32Impl(id, (int)val); break;
118 case FIELD_TYPE_SFIXED64: writeSFixed64Impl(id, (long long)val); break;
119 case FIELD_TYPE_SINT32: writeZigzagInt32Impl(id, (int)val); break;
120 case FIELD_TYPE_SINT64: writeZigzagInt64Impl(id, (long long)val); break;
121 case FIELD_TYPE_ENUM: writeEnumImpl(id, (int)val); break;
122 case FIELD_TYPE_BOOL: writeBoolImpl(id, val != 0); break;
Yi Jin974a9c22017-10-02 18:37:08 -0700123 default:
124 ALOGW("Field type %d is not supported when writing int val.",
125 (int)((fieldId & FIELD_TYPE_MASK) >> FIELD_TYPE_SHIFT));
126 return false;
127 }
128 return true;
129}
130
131bool
132ProtoOutputStream::write(uint64_t fieldId, long long val)
133{
134 if (mCompact) return false;
135 const uint32_t id = (uint32_t)fieldId;
136 switch (fieldId & FIELD_TYPE_MASK) {
Yi Jin04625ad2017-10-17 18:29:33 -0700137 case FIELD_TYPE_DOUBLE: writeDoubleImpl(id, (double)val); break;
138 case FIELD_TYPE_FLOAT: writeFloatImpl(id, (float)val); break;
139 case FIELD_TYPE_INT64: writeInt64Impl(id, (long long)val); break;
140 case FIELD_TYPE_UINT64: writeUint64Impl(id, (uint64_t)val); break;
141 case FIELD_TYPE_INT32: writeInt32Impl(id, (int)val); break;
142 case FIELD_TYPE_FIXED64: writeFixed64Impl(id, (uint64_t)val); break;
143 case FIELD_TYPE_FIXED32: writeFixed32Impl(id, (uint32_t)val); break;
144 case FIELD_TYPE_UINT32: writeUint32Impl(id, (uint32_t)val); break;
145 case FIELD_TYPE_SFIXED32: writeSFixed32Impl(id, (int)val); break;
146 case FIELD_TYPE_SFIXED64: writeSFixed64Impl(id, (long long)val); break;
147 case FIELD_TYPE_SINT32: writeZigzagInt32Impl(id, (int)val); break;
148 case FIELD_TYPE_SINT64: writeZigzagInt64Impl(id, (long long)val); break;
149 case FIELD_TYPE_ENUM: writeEnumImpl(id, (int)val); break;
150 case FIELD_TYPE_BOOL: writeBoolImpl(id, val != 0); break;
Yi Jin974a9c22017-10-02 18:37:08 -0700151 default:
152 ALOGW("Field type %d is not supported when writing long long val.",
153 (int)((fieldId & FIELD_TYPE_MASK) >> FIELD_TYPE_SHIFT));
154 return false;
155 }
156 return true;
157}
158
159bool
160ProtoOutputStream::write(uint64_t fieldId, bool val)
161{
162 if (mCompact) return false;
163 const uint32_t id = (uint32_t)fieldId;
164 switch (fieldId & FIELD_TYPE_MASK) {
Yi Jin04625ad2017-10-17 18:29:33 -0700165 case FIELD_TYPE_BOOL:
Yi Jin974a9c22017-10-02 18:37:08 -0700166 writeBoolImpl(id, val);
167 return true;
168 default:
169 ALOGW("Field type %d is not supported when writing bool val.",
170 (int)((fieldId & FIELD_TYPE_MASK) >> FIELD_TYPE_SHIFT));
171 return false;
172 }
173}
174
175bool
Yi Jin6cacbcb2018-03-30 14:04:52 -0700176ProtoOutputStream::write(uint64_t fieldId, std::string val)
Yi Jin974a9c22017-10-02 18:37:08 -0700177{
178 if (mCompact) return false;
179 const uint32_t id = (uint32_t)fieldId;
180 switch (fieldId & FIELD_TYPE_MASK) {
Yi Jin04625ad2017-10-17 18:29:33 -0700181 case FIELD_TYPE_STRING:
Yi Jin974a9c22017-10-02 18:37:08 -0700182 writeUtf8StringImpl(id, val.c_str(), val.size());
183 return true;
184 default:
185 ALOGW("Field type %d is not supported when writing string val.",
186 (int)((fieldId & FIELD_TYPE_MASK) >> FIELD_TYPE_SHIFT));
187 return false;
188 }
189}
190
191bool
Yi Jine0833302017-10-23 15:42:44 -0700192ProtoOutputStream::write(uint64_t fieldId, const char* val, size_t size)
Yi Jin974a9c22017-10-02 18:37:08 -0700193{
194 if (mCompact) return false;
195 const uint32_t id = (uint32_t)fieldId;
Yi Jin974a9c22017-10-02 18:37:08 -0700196 switch (fieldId & FIELD_TYPE_MASK) {
Yi Jin04625ad2017-10-17 18:29:33 -0700197 case FIELD_TYPE_STRING:
198 case FIELD_TYPE_BYTES:
Yi Jin974a9c22017-10-02 18:37:08 -0700199 writeUtf8StringImpl(id, val, size);
200 return true;
Yi Jin04625ad2017-10-17 18:29:33 -0700201 case FIELD_TYPE_MESSAGE:
Yi Jin8ad19382017-10-30 16:07:20 -0700202 // can directly write valid format of message bytes into ProtoOutputStream without calling start/end
203 writeMessageBytesImpl(id, val, size);
204 return true;
Yi Jin974a9c22017-10-02 18:37:08 -0700205 default:
206 ALOGW("Field type %d is not supported when writing char[] val.",
207 (int)((fieldId & FIELD_TYPE_MASK) >> FIELD_TYPE_SHIFT));
208 return false;
209 }
210}
211
212/**
213 * Make a token.
214 * Bits 61-63 - tag size (So we can go backwards later if the object had not data)
215 * - 3 bits, max value 7, max value needed 5
216 * Bit 60 - true if the object is repeated
217 * Bits 59-51 - depth (For error checking)
218 * - 9 bits, max value 512, when checking, value is masked (if we really
219 * are more than 512 levels deep)
220 * Bits 32-50 - objectId (For error checking)
221 * - 19 bits, max value 524,288. that's a lot of objects. IDs will wrap
222 * because of the overflow, and only the tokens are compared.
223 * Bits 0-31 - offset of the first size field in the buffer.
224 */
Yi Jin5ee07872018-03-05 18:18:27 -0800225uint64_t
Yi Jin974a9c22017-10-02 18:37:08 -0700226makeToken(int tagSize, bool repeated, int depth, int objectId, int sizePos) {
Yi Jin5ee07872018-03-05 18:18:27 -0800227 return ((0x07L & (uint64_t)tagSize) << 61)
Yi Jin974a9c22017-10-02 18:37:08 -0700228 | (repeated ? (1LL << 60) : 0)
Yi Jin5ee07872018-03-05 18:18:27 -0800229 | (0x01ffL & (uint64_t)depth) << 51
230 | (0x07ffffL & (uint64_t)objectId) << 32
231 | (0x0ffffffffL & (uint64_t)sizePos);
Yi Jin974a9c22017-10-02 18:37:08 -0700232}
233
234/**
235 * Get the encoded tag size from the token.
236 */
Yi Jin5ee07872018-03-05 18:18:27 -0800237static int getTagSizeFromToken(uint64_t token) {
Yi Jin974a9c22017-10-02 18:37:08 -0700238 return (int)(0x7 & (token >> 61));
239}
240
241/**
242 * Get the nesting depth of startObject calls from the token.
243 */
Yi Jin5ee07872018-03-05 18:18:27 -0800244static int getDepthFromToken(uint64_t token) {
Yi Jin974a9c22017-10-02 18:37:08 -0700245 return (int)(0x01ff & (token >> 51));
246}
247
248/**
249 * Get the location of the childRawSize (the first 32 bit size field) in this object.
250 */
Yi Jin5ee07872018-03-05 18:18:27 -0800251static int getSizePosFromToken(uint64_t token) {
Yi Jin974a9c22017-10-02 18:37:08 -0700252 return (int)token;
253}
254
Yi Jin5ee07872018-03-05 18:18:27 -0800255uint64_t
Yi Jin974a9c22017-10-02 18:37:08 -0700256ProtoOutputStream::start(uint64_t fieldId)
257{
Yi Jin04625ad2017-10-17 18:29:33 -0700258 if ((fieldId & FIELD_TYPE_MASK) != FIELD_TYPE_MESSAGE) {
Yi Jin974a9c22017-10-02 18:37:08 -0700259 ALOGE("Can't call start for non-message type field: 0x%llx", (long long)fieldId);
260 return 0;
261 }
262
263 uint32_t id = (uint32_t)fieldId;
Yi Jin295d9b12018-02-02 14:33:20 -0800264 size_t prevPos = mBuffer.wp()->pos();
Yi Jin974a9c22017-10-02 18:37:08 -0700265 mBuffer.writeHeader(id, WIRE_TYPE_LENGTH_DELIMITED);
Yi Jin974a9c22017-10-02 18:37:08 -0700266 size_t sizePos = mBuffer.wp()->pos();
267
268 mDepth++;
269 mObjectId++;
270 mBuffer.writeRawFixed64(mExpectedObjectToken); // push previous token into stack.
271
Yi Jin295d9b12018-02-02 14:33:20 -0800272 mExpectedObjectToken = makeToken(sizePos - prevPos,
Yi Jin974a9c22017-10-02 18:37:08 -0700273 (bool)(fieldId & FIELD_COUNT_REPEATED), mDepth, mObjectId, sizePos);
274 return mExpectedObjectToken;
275}
276
277void
Yi Jin5ee07872018-03-05 18:18:27 -0800278ProtoOutputStream::end(uint64_t token)
Yi Jin974a9c22017-10-02 18:37:08 -0700279{
280 if (token != mExpectedObjectToken) {
Yi Jin5ee07872018-03-05 18:18:27 -0800281 ALOGE("Unexpected token: 0x%llx, should be 0x%llx", (long long)token, (long long)mExpectedObjectToken);
Yi Jin974a9c22017-10-02 18:37:08 -0700282 return;
283 }
284
285 int depth = getDepthFromToken(token);
286 if (depth != (mDepth & 0x01ff)) {
287 ALOGE("Unexpected depth: %d, should be %d", depth, mDepth);
288 return;
289 }
290 mDepth--;
291
292 int sizePos = getSizePosFromToken(token);
293 // number of bytes written in this start-end session.
294 int childRawSize = mBuffer.wp()->pos() - sizePos - 8;
295
296 // retrieve the old token from stack.
297 mBuffer.ep()->rewind()->move(sizePos);
298 mExpectedObjectToken = mBuffer.readRawFixed64();
299
300 // If raw size is larger than 0, write the negative value here to indicate a compact is needed.
301 if (childRawSize > 0) {
302 mBuffer.editRawFixed32(sizePos, -childRawSize);
303 mBuffer.editRawFixed32(sizePos+4, -1);
304 } else {
305 // reset wp which erase the header tag of the message when its size is 0.
306 mBuffer.wp()->rewind()->move(sizePos - getTagSizeFromToken(token));
307 }
308}
309
Yi Jin0abdfb02017-11-16 15:32:27 -0800310size_t
311ProtoOutputStream::bytesWritten()
312{
313 return mBuffer.size();
314}
315
Yi Jin974a9c22017-10-02 18:37:08 -0700316bool
317ProtoOutputStream::compact() {
318 if (mCompact) return true;
319 if (mDepth != 0) {
320 ALOGE("Can't compact when depth(%d) is not zero. Missing calls to end.", mDepth);
321 return false;
322 }
323 // record the size of the original buffer.
324 size_t rawBufferSize = mBuffer.size();
325 if (rawBufferSize == 0) return true; // nothing to do if the buffer is empty;
326
327 // reset edit pointer and recursively compute encoded size of messages.
328 mBuffer.ep()->rewind();
329 if (editEncodedSize(rawBufferSize) == 0) {
330 ALOGE("Failed to editEncodedSize.");
331 return false;
332 }
333
334 // reset both edit pointer and write pointer, and compact recursively.
335 mBuffer.ep()->rewind();
336 mBuffer.wp()->rewind();
337 if (!compactSize(rawBufferSize)) {
338 ALOGE("Failed to compactSize.");
339 return false;
340 }
341 // copy the reset to the buffer.
342 if (mCopyBegin < rawBufferSize) {
343 mBuffer.copy(mCopyBegin, rawBufferSize - mCopyBegin);
344 }
345
346 // mark true means it is not legal to write to this ProtoOutputStream anymore
347 mCompact = true;
348 return true;
349}
350
351/**
352 * First compaction pass. Iterate through the data, and fill in the
353 * nested object sizes so the next pass can compact them.
354 */
355size_t
356ProtoOutputStream::editEncodedSize(size_t rawSize)
357{
358 size_t objectStart = mBuffer.ep()->pos();
359 size_t objectEnd = objectStart + rawSize;
360 size_t encodedSize = 0;
361 int childRawSize, childEncodedSize;
362 size_t childEncodedSizePos;
363
364 while (mBuffer.ep()->pos() < objectEnd) {
365 uint32_t tag = (uint32_t)mBuffer.readRawVarint();
366 encodedSize += get_varint_size(tag);
367 switch (read_wire_type(tag)) {
368 case WIRE_TYPE_VARINT:
369 do {
370 encodedSize++;
371 } while ((mBuffer.readRawByte() & 0x80) != 0);
372 break;
373 case WIRE_TYPE_FIXED64:
374 encodedSize += 8;
375 mBuffer.ep()->move(8);
376 break;
377 case WIRE_TYPE_LENGTH_DELIMITED:
378 childRawSize = (int)mBuffer.readRawFixed32();
379 childEncodedSizePos = mBuffer.ep()->pos();
380 childEncodedSize = (int)mBuffer.readRawFixed32();
381 if (childRawSize >= 0 && childRawSize == childEncodedSize) {
382 mBuffer.ep()->move(childRawSize);
383 } else if (childRawSize < 0 && childEncodedSize == -1){
384 childEncodedSize = editEncodedSize(-childRawSize);
385 mBuffer.editRawFixed32(childEncodedSizePos, childEncodedSize);
386 } else {
387 ALOGE("Bad raw or encoded values: raw=%d, encoded=%d at %zu",
388 childRawSize, childEncodedSize, childEncodedSizePos);
389 return 0;
390 }
391 encodedSize += get_varint_size(childEncodedSize) + childEncodedSize;
392 break;
393 case WIRE_TYPE_FIXED32:
394 encodedSize += 4;
395 mBuffer.ep()->move(4);
396 break;
397 default:
398 ALOGE("Unexpected wire type %d in editEncodedSize at [%zu, %zu]",
399 read_wire_type(tag), objectStart, objectEnd);
400 return 0;
401 }
402 }
403 return encodedSize;
404}
405
406/**
407 * Second compaction pass. Iterate through the data, and copy the data
408 * forward in the buffer, converting the pairs of uint32s into a single
409 * unsigned varint of the size.
410 */
411bool
412ProtoOutputStream::compactSize(size_t rawSize)
413{
414 size_t objectStart = mBuffer.ep()->pos();
415 size_t objectEnd = objectStart + rawSize;
416 int childRawSize, childEncodedSize;
417
418 while (mBuffer.ep()->pos() < objectEnd) {
419 uint32_t tag = (uint32_t)mBuffer.readRawVarint();
420 switch (read_wire_type(tag)) {
421 case WIRE_TYPE_VARINT:
422 while ((mBuffer.readRawByte() & 0x80) != 0) {}
423 break;
424 case WIRE_TYPE_FIXED64:
425 mBuffer.ep()->move(8);
426 break;
427 case WIRE_TYPE_LENGTH_DELIMITED:
428 mBuffer.copy(mCopyBegin, mBuffer.ep()->pos() - mCopyBegin);
429
430 childRawSize = (int)mBuffer.readRawFixed32();
431 childEncodedSize = (int)mBuffer.readRawFixed32();
432 mCopyBegin = mBuffer.ep()->pos();
433
434 // write encoded size to buffer.
435 mBuffer.writeRawVarint32(childEncodedSize);
436 if (childRawSize >= 0 && childRawSize == childEncodedSize) {
437 mBuffer.ep()->move(childEncodedSize);
438 } else if (childRawSize < 0){
439 if (!compactSize(-childRawSize)) return false;
440 } else {
441 ALOGE("Bad raw or encoded values: raw=%d, encoded=%d",
442 childRawSize, childEncodedSize);
443 return false;
444 }
445 break;
446 case WIRE_TYPE_FIXED32:
447 mBuffer.ep()->move(4);
448 break;
449 default:
450 ALOGE("Unexpected wire type %d in compactSize at [%zu, %zu]",
451 read_wire_type(tag), objectStart, objectEnd);
452 return false;
453 }
454 }
455 return true;
456}
457
Yi Jin42711a02017-10-11 18:20:24 -0700458size_t
459ProtoOutputStream::size()
460{
461 compact();
462 return mBuffer.size();
463}
464
Yi Jin974a9c22017-10-02 18:37:08 -0700465static bool write_all(int fd, uint8_t const* buf, size_t size)
466{
467 while (size > 0) {
468 ssize_t amt = ::write(fd, buf, size);
469 if (amt < 0) {
470 return false;
471 }
472 size -= amt;
473 buf += amt;
474 }
475 return true;
476}
477
478bool
Yi Jin42711a02017-10-11 18:20:24 -0700479ProtoOutputStream::flush(int fd)
Yi Jin974a9c22017-10-02 18:37:08 -0700480{
Yi Jin42711a02017-10-11 18:20:24 -0700481 if (fd < 0) return false;
Yi Jin974a9c22017-10-02 18:37:08 -0700482 if (!compact()) return false;
483
484 EncodedBuffer::iterator it = mBuffer.begin();
485 while (it.readBuffer() != NULL) {
Yi Jin42711a02017-10-11 18:20:24 -0700486 if (!write_all(fd, it.readBuffer(), it.currentToRead())) return false;
Yi Jin974a9c22017-10-02 18:37:08 -0700487 it.rp()->move(it.currentToRead());
488 }
489 return true;
490}
491
Yi Jin42711a02017-10-11 18:20:24 -0700492EncodedBuffer::iterator
493ProtoOutputStream::data()
494{
495 compact();
496 return mBuffer.begin();
497}
498
499void
500ProtoOutputStream::writeRawVarint(uint64_t varint)
501{
502 mBuffer.writeRawVarint64(varint);
503}
504
505void
506ProtoOutputStream::writeLengthDelimitedHeader(uint32_t id, size_t size)
507{
508 mBuffer.writeHeader(id, WIRE_TYPE_LENGTH_DELIMITED);
509 // reserves 64 bits for length delimited fields, if first field is negative, compact it.
510 mBuffer.writeRawFixed32(size);
511 mBuffer.writeRawFixed32(size);
512}
513
514void
515ProtoOutputStream::writeRawByte(uint8_t byte)
516{
517 mBuffer.writeRawByte(byte);
518}
519
Yi Jin974a9c22017-10-02 18:37:08 -0700520
521// =========================================================================
522// Private functions
523
524/**
525 * bit_cast
526 */
527template <class From, class To>
528inline To bit_cast(From const &from) {
529 To to;
530 memcpy(&to, &from, sizeof(to));
531 return to;
532}
533
534inline void
535ProtoOutputStream::writeDoubleImpl(uint32_t id, double val)
536{
Yi Jin974a9c22017-10-02 18:37:08 -0700537 mBuffer.writeHeader(id, WIRE_TYPE_FIXED64);
538 mBuffer.writeRawFixed64(bit_cast<double, uint64_t>(val));
539}
540
541inline void
542ProtoOutputStream::writeFloatImpl(uint32_t id, float val)
543{
Yi Jin974a9c22017-10-02 18:37:08 -0700544 mBuffer.writeHeader(id, WIRE_TYPE_FIXED32);
545 mBuffer.writeRawFixed32(bit_cast<float, uint32_t>(val));
546}
547
548inline void
549ProtoOutputStream::writeInt64Impl(uint32_t id, long long val)
550{
Yi Jin974a9c22017-10-02 18:37:08 -0700551 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
552 mBuffer.writeRawVarint64((uint64_t)val);
553}
554
555inline void
556ProtoOutputStream::writeInt32Impl(uint32_t id, int val)
557{
Yi Jin974a9c22017-10-02 18:37:08 -0700558 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
559 mBuffer.writeRawVarint32((uint32_t)val);
560}
561
562inline void
563ProtoOutputStream::writeUint64Impl(uint32_t id, uint64_t val)
564{
Yi Jin974a9c22017-10-02 18:37:08 -0700565 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
566 mBuffer.writeRawVarint64(val);
567}
568
569inline void
570ProtoOutputStream::writeUint32Impl(uint32_t id, uint32_t val)
571{
Yi Jin974a9c22017-10-02 18:37:08 -0700572 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
573 mBuffer.writeRawVarint32(val);
574}
575
576inline void
577ProtoOutputStream::writeFixed64Impl(uint32_t id, uint64_t val)
578{
Yi Jin974a9c22017-10-02 18:37:08 -0700579 mBuffer.writeHeader(id, WIRE_TYPE_FIXED64);
580 mBuffer.writeRawFixed64(val);
581}
582
583inline void
584ProtoOutputStream::writeFixed32Impl(uint32_t id, uint32_t val)
585{
Yi Jin974a9c22017-10-02 18:37:08 -0700586 mBuffer.writeHeader(id, WIRE_TYPE_FIXED32);
587 mBuffer.writeRawFixed32(val);
588}
589
590inline void
591ProtoOutputStream::writeSFixed64Impl(uint32_t id, long long val)
592{
Yi Jin974a9c22017-10-02 18:37:08 -0700593 mBuffer.writeHeader(id, WIRE_TYPE_FIXED64);
594 mBuffer.writeRawFixed64((uint64_t)val);
595}
596
597inline void
598ProtoOutputStream::writeSFixed32Impl(uint32_t id, int val)
599{
Yi Jin974a9c22017-10-02 18:37:08 -0700600 mBuffer.writeHeader(id, WIRE_TYPE_FIXED32);
601 mBuffer.writeRawFixed32((uint32_t)val);
602}
603
604inline void
605ProtoOutputStream::writeZigzagInt64Impl(uint32_t id, long long val)
606{
Yi Jin974a9c22017-10-02 18:37:08 -0700607 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
608 mBuffer.writeRawVarint64((val << 1) ^ (val >> 63));
609}
610
611inline void
612ProtoOutputStream::writeZigzagInt32Impl(uint32_t id, int val)
613{
Yi Jin974a9c22017-10-02 18:37:08 -0700614 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
615 mBuffer.writeRawVarint32((val << 1) ^ (val >> 31));
616}
617
618inline void
619ProtoOutputStream::writeEnumImpl(uint32_t id, int val)
620{
621 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
622 mBuffer.writeRawVarint32((uint32_t) val);
623}
624
625inline void
626ProtoOutputStream::writeBoolImpl(uint32_t id, bool val)
627{
Yi Jin974a9c22017-10-02 18:37:08 -0700628 mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
629 mBuffer.writeRawVarint32(val ? 1 : 0);
630}
631
632inline void
633ProtoOutputStream::writeUtf8StringImpl(uint32_t id, const char* val, size_t size)
634{
Yi Jin04625ad2017-10-17 18:29:33 -0700635 if (val == NULL) return;
Yi Jin42711a02017-10-11 18:20:24 -0700636 writeLengthDelimitedHeader(id, size);
Yi Jin974a9c22017-10-02 18:37:08 -0700637 for (size_t i=0; i<size; i++) {
638 mBuffer.writeRawByte((uint8_t)val[i]);
639 }
640}
641
Yi Jin8ad19382017-10-30 16:07:20 -0700642inline void
643ProtoOutputStream::writeMessageBytesImpl(uint32_t id, const char* val, size_t size)
644{
645 if (val == NULL) return;
646 writeLengthDelimitedHeader(id, size);
647 for (size_t i=0; i<size; i++) {
648 mBuffer.writeRawByte(val[i]);
649 }
650}
651
Yi Jin974a9c22017-10-02 18:37:08 -0700652} // util
653} // android
654