2541 lines
91 KiB
Java
2541 lines
91 KiB
Java
![]() |
/*
|
||
|
* Copyright (C) 2012 The Android Open Source Project
|
||
|
*
|
||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
* you may not use this file except in compliance with the License.
|
||
|
* You may obtain a copy of the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
* See the License for the specific language governing permissions and
|
||
|
* limitations under the License.
|
||
|
*/
|
||
|
|
||
|
package android.util.proto;
|
||
|
|
||
|
import android.annotation.NonNull;
|
||
|
import android.annotation.Nullable;
|
||
|
import android.util.Log;
|
||
|
|
||
|
import java.io.FileDescriptor;
|
||
|
import java.io.FileOutputStream;
|
||
|
import java.io.IOException;
|
||
|
import java.io.OutputStream;
|
||
|
import java.io.UnsupportedEncodingException;
|
||
|
|
||
|
/**
|
||
|
* Class to write to a protobuf stream.
|
||
|
*
|
||
|
* <p>
|
||
|
* This API is not as convenient or type safe as the standard protobuf
|
||
|
* classes. If possible, the best recommended library is to use protobuf lite.
|
||
|
* However, in environments (such as the Android platform itself), a
|
||
|
* more memory efficient version is necessary.
|
||
|
*
|
||
|
* <p>Each write method takes an ID code from the protoc generated classes
|
||
|
* and the value to write. To make a nested object, call {@link #start(long)}
|
||
|
* and then {@link #end(long)} when you are done.
|
||
|
*
|
||
|
* <p>The ID codes have type information embedded into them, so if you call
|
||
|
* the incorrect function you will get an {@link IllegalArgumentException}.
|
||
|
*
|
||
|
* <p>To retrieve the encoded protobuf stream, call {@link #getBytes()}.
|
||
|
*
|
||
|
* stream as the top-level objects are finished.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
/* IMPLEMENTATION NOTES
|
||
|
*
|
||
|
* Because protobuf has inner values, and they are length prefixed, and
|
||
|
* those sizes themselves are stored with a variable length encoding, it
|
||
|
* is impossible to know how big an object will be in a single pass.
|
||
|
*
|
||
|
* The traditional way is to copy the in-memory representation of an object
|
||
|
* into the generated proto Message objects, do a traversal of those to
|
||
|
* cache the size, and then write the size-prefixed buffers.
|
||
|
*
|
||
|
* We are trying to avoid too much generated code here, but this class still
|
||
|
* needs to have API. We can't have the multiple passes be done by the
|
||
|
* calling code. In addition, we want to avoid the memory high water mark
|
||
|
* of duplicating all of the values into the traditional in-memory Message
|
||
|
* objects. We need to find another way.
|
||
|
*
|
||
|
* So what we do here is to let the calling code write the data into a
|
||
|
* byte[] (actually a collection of them wrapped in the EncodedBuffer class),
|
||
|
* but not do the varint encoding of the sub-message sizes. Then, we do a
|
||
|
* recursive traversal of the buffer itself, calculating the sizes (which are
|
||
|
* then knowable, although still not the actual sizes in the buffer because of
|
||
|
* possible further nesting). Then we do a third pass, compacting the
|
||
|
* buffer and varint encoding the sizes.
|
||
|
*
|
||
|
* This gets us a relatively small number of fixed-size allocations,
|
||
|
* which is less likely to cause memory fragmentation or churn the GC, and
|
||
|
* the same number of data copies as we would have gotten with setting it
|
||
|
* field-by-field in generated code, and no code bloat from generated code.
|
||
|
* The final data copy is also done with System.arraycopy, which will be
|
||
|
* more efficient, in general, than doing the individual fields twice (as in
|
||
|
* the traditional way).
|
||
|
*
|
||
|
* To accomplish the multiple passes, whenever we write a
|
||
|
* WIRE_TYPE_LENGTH_DELIMITED field, we write the size occupied in our
|
||
|
* buffer as a fixed 32 bit int (called childRawSize), not a variable length
|
||
|
* one. We reserve another 32 bit slot for the computed size (called
|
||
|
* childEncodedSize). If we know the size up front, as we do for strings
|
||
|
* and byte[], then we also put that into childEncodedSize, if we don't, we
|
||
|
* write the negative of childRawSize, as a sentinel that we need to
|
||
|
* compute it during the second pass and recursively compact it during the
|
||
|
* third pass.
|
||
|
*
|
||
|
* Unsigned size varints can be up to five bytes long, but we reserve eight
|
||
|
* bytes for overhead, so we know that when we compact the buffer, there
|
||
|
* will always be space for the encoded varint.
|
||
|
*
|
||
|
* When we can figure out the size ahead of time, we do, in order
|
||
|
* to save overhead with recalculating it, and with the later arraycopy.
|
||
|
*
|
||
|
* During the period between when the caller has called #start, but
|
||
|
* not yet called #end, we maintain a linked list of the tokens
|
||
|
* returned by #start, stored in those 8 bytes of size storage space.
|
||
|
* We use that linked list of tokens to ensure that the caller has
|
||
|
* correctly matched pairs of #start and #end calls, and issue
|
||
|
* errors if they are not matched.
|
||
|
*/
|
||
|
@android.ravenwood.annotation.RavenwoodKeepWholeClass
|
||
|
public final class ProtoOutputStream extends ProtoStream {
|
||
|
/**
|
||
|
* @hide
|
||
|
*/
|
||
|
public static final String TAG = "ProtoOutputStream";
|
||
|
|
||
|
/**
|
||
|
* Our buffer.
|
||
|
*/
|
||
|
private EncodedBuffer mBuffer;
|
||
|
|
||
|
/**
|
||
|
* Our stream. If there is one.
|
||
|
*/
|
||
|
private OutputStream mStream;
|
||
|
|
||
|
/**
|
||
|
* Current nesting depth of startObject calls.
|
||
|
*/
|
||
|
private int mDepth;
|
||
|
|
||
|
/**
|
||
|
* An ID given to objects and returned in the token from startObject
|
||
|
* and stored in the buffer until endObject is called, where the two
|
||
|
* are checked.
|
||
|
*
|
||
|
* <p>Starts at -1 and becomes more negative, so the values
|
||
|
* aren't likely to alias with the size it will be overwritten with,
|
||
|
* which tend to be small, and we will be more likely to catch when
|
||
|
* the caller of endObject uses a stale token that they didn't intend
|
||
|
* to (e.g. copy and paste error).
|
||
|
*/
|
||
|
private int mNextObjectId = -1;
|
||
|
|
||
|
/**
|
||
|
* The object token we are expecting in endObject.
|
||
|
*
|
||
|
* <p>If another call to startObject happens, this is written to that location, which gives
|
||
|
* us a stack, stored in the space for the as-yet unused size fields.
|
||
|
*/
|
||
|
private long mExpectedObjectToken;
|
||
|
|
||
|
/**
|
||
|
* Index in mBuffer that we should start copying from on the next
|
||
|
* pass of compaction.
|
||
|
*/
|
||
|
private int mCopyBegin;
|
||
|
|
||
|
/**
|
||
|
* Whether we've already compacted
|
||
|
*/
|
||
|
private boolean mCompacted;
|
||
|
|
||
|
/**
|
||
|
* Construct a {@link ProtoOutputStream} with the default chunk size.
|
||
|
*
|
||
|
* <p>This is for an in-memory proto. The caller should use {@link #getBytes()} for the result.
|
||
|
*/
|
||
|
public ProtoOutputStream() {
|
||
|
this(0);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Construct a {@link ProtoOutputStream with the given chunk size.
|
||
|
*
|
||
|
* <p>This is for an in-memory proto. The caller should use {@link #getBytes()} for the result.
|
||
|
*/
|
||
|
public ProtoOutputStream(int chunkSize) {
|
||
|
mBuffer = new EncodedBuffer(chunkSize);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Construct a {@link ProtoOutputStream} that sits on top of an {@link OutputStream}.
|
||
|
*
|
||
|
* <p>The {@link #flush()} method must be called when done writing
|
||
|
* to flush any remaining data, although data *may* be written at intermediate
|
||
|
* points within the writing as well.
|
||
|
*/
|
||
|
public ProtoOutputStream(@NonNull OutputStream stream) {
|
||
|
this();
|
||
|
mStream = stream;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Construct a {@link ProtoOutputStream} that sits on top of a {@link FileDescriptor}.
|
||
|
*
|
||
|
* <p>The {@link #flush()} method must be called when done writing
|
||
|
* to flush any remaining data, although data *may* be written at intermediate
|
||
|
* points within the writing as well.
|
||
|
*
|
||
|
* @hide
|
||
|
*/
|
||
|
public ProtoOutputStream(@NonNull FileDescriptor fd) {
|
||
|
this(new FileOutputStream(fd));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the total size of the data that has been written, after full
|
||
|
* protobuf encoding has occurred.
|
||
|
*
|
||
|
* @return the uncompressed buffer size
|
||
|
*/
|
||
|
public int getRawSize() {
|
||
|
if (mCompacted) {
|
||
|
return getBytes().length;
|
||
|
} else {
|
||
|
return mBuffer.getSize();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Write a value for the given fieldId.
|
||
|
*
|
||
|
* <p>Will automatically convert for the following field types, and
|
||
|
* throw an exception for others: double, float, int32, int64, uint32, uint64,
|
||
|
* sint32, sint64, fixed32, fixed64, sfixed32, sfixed64, bool, enum.
|
||
|
*
|
||
|
* @param fieldId The field identifier constant from the generated class.
|
||
|
* @param val The value.
|
||
|
*/
|
||
|
public void write(long fieldId, double val) {
|
||
|
assertNotCompacted();
|
||
|
final int id = (int)fieldId;
|
||
|
|
||
|
switch ((int)((fieldId & (FIELD_TYPE_MASK | FIELD_COUNT_MASK)) >> FIELD_TYPE_SHIFT)) {
|
||
|
// double
|
||
|
case (int)((FIELD_TYPE_DOUBLE | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
|
||
|
writeDoubleImpl(id, (double)val);
|
||
|
break;
|
||
|
case (int)((FIELD_TYPE_DOUBLE | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
|
||
|
case (int)((FIELD_TYPE_DOUBLE | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
|
||
|
writeRepeatedDoubleImpl(id, (double)val);
|
||
|
break;
|
||
|
// float
|
||
|
case (int)((FIELD_TYPE_FLOAT | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
|
||
|
writeFloatImpl(id, (float)val);
|
||
|
break;
|
||
|
case (int)((FIELD_TYPE_FLOAT | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
|
||
|
case (int)((FIELD_TYPE_FLOAT | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
|
||
|
writeRepeatedFloatImpl(id, (float)val);
|
||
|
break;
|
||
|
// int32
|
||
|
case (int)((FIELD_TYPE_INT32 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
|
||
|
writeInt32Impl(id, (int)val);
|
||
|
break;
|
||
|
case (int)((FIELD_TYPE_INT32 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
|
||
|
case (int)((FIELD_TYPE_INT32 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
|
||
|
writeRepeatedInt32Impl(id, (int)val);
|
||
|
break;
|
||
|
// int64
|
||
|
case (int)((FIELD_TYPE_INT64 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
|
||
|
writeInt64Impl(id, (long)val);
|
||
|
break;
|
||
|
case (int)((FIELD_TYPE_INT64 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
|
||
|
case (int)((FIELD_TYPE_INT64 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
|
||
|
writeRepeatedInt64Impl(id, (long)val);
|
||
|
break;
|
||
|
// uint32
|
||
|
case (int)((FIELD_TYPE_UINT32 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
|
||
|
writeUInt32Impl(id, (int)val);
|
||
|
break;
|
||
|
case (int)((FIELD_TYPE_UINT32 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
|
||
|
case (int)((FIELD_TYPE_UINT32 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
|
||
|
writeRepeatedUInt32Impl(id, (int)val);
|
||
|
break;
|
||
|
// uint64
|
||
|
case (int)((FIELD_TYPE_UINT64 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
|
||
|
writeUInt64Impl(id, (long)val);
|
||
|
break;
|
||
|
case (int)((FIELD_TYPE_UINT64 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
|
||
|
case (int)((FIELD_TYPE_UINT64 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
|
||
|
writeRepeatedUInt64Impl(id, (long)val);
|
||
|
break;
|
||
|
// sint32
|
||
|
case (int)((FIELD_TYPE_SINT32 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
|
||
|
writeSInt32Impl(id, (int)val);
|
||
|
break;
|
||
|
case (int)((FIELD_TYPE_SINT32 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
|
||
|
case (int)((FIELD_TYPE_SINT32 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
|
||
|
writeRepeatedSInt32Impl(id, (int)val);
|
||
|
break;
|
||
|
// sint64
|
||
|
case (int)((FIELD_TYPE_SINT64 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
|
||
|
writeSInt64Impl(id, (long)val);
|
||
|
break;
|
||
|
case (int)((FIELD_TYPE_SINT64 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
|
||
|
case (int)((FIELD_TYPE_SINT64 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
|
||
|
writeRepeatedSInt64Impl(id, (long)val);
|
||
|
break;
|
||
|
// fixed32
|
||
|
case (int)((FIELD_TYPE_FIXED32 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
|
||
|
writeFixed32Impl(id, (int)val);
|
||
|
break;
|
||
|
case (int)((FIELD_TYPE_FIXED32 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
|
||
|
case (int)((FIELD_TYPE_FIXED32 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
|
||
|
writeRepeatedFixed32Impl(id, (int)val);
|
||
|
break;
|
||
|
// fixed64
|
||
|
case (int)((FIELD_TYPE_FIXED64 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
|
||
|
writeFixed64Impl(id, (long)val);
|
||
|
break;
|
||
|
case (int)((FIELD_TYPE_FIXED64 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
|
||
|
case (int)((FIELD_TYPE_FIXED64 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
|
||
|
writeRepeatedFixed64Impl(id, (long)val);
|
||
|
break;
|
||
|
// sfixed32
|
||
|
case (int)((FIELD_TYPE_SFIXED32 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
|
||
|
writeSFixed32Impl(id, (int)val);
|
||
|
break;
|
||
|
case (int)((FIELD_TYPE_SFIXED32 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
|
||
|
case (int)((FIELD_TYPE_SFIXED32 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
|
||
|
writeRepeatedSFixed32Impl(id, (int)val);
|
||
|
break;
|
||
|
// sfixed64
|
||
|
case (int)((FIELD_TYPE_SFIXED64 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
|
||
|
writeSFixed64Impl(id, (long)val);
|
||
|
break;
|
||
|
case (int)((FIELD_TYPE_SFIXED64 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
|
||
|
case (int)((FIELD_TYPE_SFIXED64 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
|
||
|
writeRepeatedSFixed64Impl(id, (long)val);
|
||
|
break;
|
||
|
// bool
|
||
|
case (int)((FIELD_TYPE_BOOL | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
|
||
|
writeBoolImpl(id, val != 0);
|
||
|
break;
|
||
|
case (int)((FIELD_TYPE_BOOL | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
|
||
|
case (int)((FIELD_TYPE_BOOL | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
|
||
|
writeRepeatedBoolImpl(id, val != 0);
|
||
|
break;
|
||
|
// enum
|
||
|
case (int)((FIELD_TYPE_ENUM | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
|
||
|
writeEnumImpl(id, (int)val);
|
||
|
break;
|
||
|
case (int)((FIELD_TYPE_ENUM | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
|
||
|
case (int)((FIELD_TYPE_ENUM | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
|
||
|
writeRepeatedEnumImpl(id, (int)val);
|
||
|
break;
|
||
|
// string, bytes, object not allowed here.
|
||
|
default: {
|
||
|
throw new IllegalArgumentException("Attempt to call write(long, double) with "
|
||
|
+ getFieldIdString(fieldId));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Write a value for the given fieldId.
|
||
|
*
|
||
|
* <p>Will automatically convert for the following field types, and
|
||
|
* throw an exception for others: double, float, int32, int64, uint32, uint64,
|
||
|
* sint32, sint64, fixed32, fixed64, sfixed32, sfixed64, bool, enum.
|
||
|
*
|
||
|
* @param fieldId The field identifier constant from the generated class.
|
||
|
* @param val The value.
|
||
|
*/
|
||
|
public void write(long fieldId, float val) {
|
||
|
assertNotCompacted();
|
||
|
final int id = (int)fieldId;
|
||
|
|
||
|
switch ((int)((fieldId & (FIELD_TYPE_MASK | FIELD_COUNT_MASK)) >> FIELD_TYPE_SHIFT)) {
|
||
|
// double
|
||
|
case (int)((FIELD_TYPE_DOUBLE | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
|
||
|
writeDoubleImpl(id, (double)val);
|
||
|
break;
|
||
|
case (int)((FIELD_TYPE_DOUBLE | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
|
||
|
case (int)((FIELD_TYPE_DOUBLE | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
|
||
|
writeRepeatedDoubleImpl(id, (double)val);
|
||
|
break;
|
||
|
// float
|
||
|
case (int)((FIELD_TYPE_FLOAT | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
|
||
|
writeFloatImpl(id, (float)val);
|
||
|
break;
|
||
|
case (int)((FIELD_TYPE_FLOAT | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
|
||
|
case (int)((FIELD_TYPE_FLOAT | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
|
||
|
writeRepeatedFloatImpl(id, (float)val);
|
||
|
break;
|
||
|
// int32
|
||
|
case (int)((FIELD_TYPE_INT32 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
|
||
|
writeInt32Impl(id, (int)val);
|
||
|
break;
|
||
|
case (int)((FIELD_TYPE_INT32 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
|
||
|
case (int)((FIELD_TYPE_INT32 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
|
||
|
writeRepeatedInt32Impl(id, (int)val);
|
||
|
break;
|
||
|
// int64
|
||
|
case (int)((FIELD_TYPE_INT64 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
|
||
|
writeInt64Impl(id, (long)val);
|
||
|
break;
|
||
|
case (int)((FIELD_TYPE_INT64 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
|
||
|
case (int)((FIELD_TYPE_INT64 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
|
||
|
writeRepeatedInt64Impl(id, (long)val);
|
||
|
break;
|
||
|
// uint32
|
||
|
case (int)((FIELD_TYPE_UINT32 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
|
||
|
writeUInt32Impl(id, (int)val);
|
||
|
break;
|
||
|
case (int)((FIELD_TYPE_UINT32 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
|
||
|
case (int)((FIELD_TYPE_UINT32 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
|
||
|
writeRepeatedUInt32Impl(id, (int)val);
|
||
|
break;
|
||
|
// uint64
|
||
|
case (int)((FIELD_TYPE_UINT64 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
|
||
|
writeUInt64Impl(id, (long)val);
|
||
|
break;
|
||
|
case (int)((FIELD_TYPE_UINT64 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
|
||
|
case (int)((FIELD_TYPE_UINT64 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
|
||
|
writeRepeatedUInt64Impl(id, (long)val);
|
||
|
break;
|
||
|
// sint32
|
||
|
case (int)((FIELD_TYPE_SINT32 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
|
||
|
writeSInt32Impl(id, (int)val);
|
||
|
break;
|
||
|
case (int)((FIELD_TYPE_SINT32 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
|
||
|
case (int)((FIELD_TYPE_SINT32 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
|
||
|
writeRepeatedSInt32Impl(id, (int)val);
|
||
|
break;
|
||
|
// sint64
|
||
|
case (int)((FIELD_TYPE_SINT64 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
|
||
|
writeSInt64Impl(id, (long)val);
|
||
|
break;
|
||
|
case (int)((FIELD_TYPE_SINT64 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
|
||
|
case (int)((FIELD_TYPE_SINT64 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
|
||
|
writeRepeatedSInt64Impl(id, (long)val);
|
||
|
break;
|
||
|
// fixed32
|
||
|
case (int)((FIELD_TYPE_FIXED32 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
|
||
|
writeFixed32Impl(id, (int)val);
|
||
|
break;
|
||
|
case (int)((FIELD_TYPE_FIXED32 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
|
||
|
case (int)((FIELD_TYPE_FIXED32 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
|
||
|
writeRepeatedFixed32Impl(id, (int)val);
|
||
|
break;
|
||
|
// fixed64
|
||
|
case (int)((FIELD_TYPE_FIXED64 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
|
||
|
writeFixed64Impl(id, (long)val);
|
||
|
break;
|
||
|
case (int)((FIELD_TYPE_FIXED64 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
|
||
|
case (int)((FIELD_TYPE_FIXED64 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
|
||
|
writeRepeatedFixed64Impl(id, (long)val);
|
||
|
break;
|
||
|
// sfixed32
|
||
|
case (int)((FIELD_TYPE_SFIXED32 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
|
||
|
writeSFixed32Impl(id, (int)val);
|
||
|
break;
|
||
|
case (int)((FIELD_TYPE_SFIXED32 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
|
||
|
case (int)((FIELD_TYPE_SFIXED32 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
|
||
|
writeRepeatedSFixed32Impl(id, (int)val);
|
||
|
break;
|
||
|
// sfixed64
|
||
|
case (int)((FIELD_TYPE_SFIXED64 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
|
||
|
writeSFixed64Impl(id, (long)val);
|
||
|
break;
|
||
|
case (int)((FIELD_TYPE_SFIXED64 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
|
||
|
case (int)((FIELD_TYPE_SFIXED64 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
|
||
|
writeRepeatedSFixed64Impl(id, (long)val);
|
||
|
break;
|
||
|
// bool
|
||
|
case (int)((FIELD_TYPE_BOOL | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
|
||
|
writeBoolImpl(id, val != 0);
|
||
|
break;
|
||
|
case (int)((FIELD_TYPE_BOOL | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
|
||
|
case (int)((FIELD_TYPE_BOOL | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
|
||
|
writeRepeatedBoolImpl(id, val != 0);
|
||
|
break;
|
||
|
// enum
|
||
|
case (int)((FIELD_TYPE_ENUM | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
|
||
|
writeEnumImpl(id, (int)val);
|
||
|
break;
|
||
|
case (int)((FIELD_TYPE_ENUM | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
|
||
|
case (int)((FIELD_TYPE_ENUM | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
|
||
|
writeRepeatedEnumImpl(id, (int)val);
|
||
|
break;
|
||
|
// string, bytes, object not allowed here.
|
||
|
default: {
|
||
|
throw new IllegalArgumentException("Attempt to call write(long, float) with "
|
||
|
+ getFieldIdString(fieldId));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Write a value for the given fieldId.
|
||
|
*
|
||
|
* <p>Will automatically convert for the following field types, and
|
||
|
* throw an exception for others: double, float, int32, int64, uint32, uint64,
|
||
|
* sint32, sint64, fixed32, fixed64, sfixed32, sfixed64, bool, enum.
|
||
|
*
|
||
|
* @param fieldId The field identifier constant from the generated class.
|
||
|
* @param val The value.
|
||
|
*/
|
||
|
public void write(long fieldId, int val) {
|
||
|
assertNotCompacted();
|
||
|
final int id = (int)fieldId;
|
||
|
|
||
|
switch ((int)((fieldId & (FIELD_TYPE_MASK | FIELD_COUNT_MASK)) >> FIELD_TYPE_SHIFT)) {
|
||
|
// double
|
||
|
case (int)((FIELD_TYPE_DOUBLE | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
|
||
|
writeDoubleImpl(id, (double)val);
|
||
|
break;
|
||
|
case (int)((FIELD_TYPE_DOUBLE | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
|
||
|
case (int)((FIELD_TYPE_DOUBLE | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
|
||
|
writeRepeatedDoubleImpl(id, (double)val);
|
||
|
break;
|
||
|
// float
|
||
|
case (int)((FIELD_TYPE_FLOAT | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
|
||
|
writeFloatImpl(id, (float)val);
|
||
|
break;
|
||
|
case (int)((FIELD_TYPE_FLOAT | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
|
||
|
case (int)((FIELD_TYPE_FLOAT | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
|
||
|
writeRepeatedFloatImpl(id, (float)val);
|
||
|
break;
|
||
|
// int32
|
||
|
case (int)((FIELD_TYPE_INT32 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
|
||
|
writeInt32Impl(id, (int)val);
|
||
|
break;
|
||
|
case (int)((FIELD_TYPE_INT32 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
|
||
|
case (int)((FIELD_TYPE_INT32 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
|
||
|
writeRepeatedInt32Impl(id, (int)val);
|
||
|
break;
|
||
|
// int64
|
||
|
case (int)((FIELD_TYPE_INT64 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
|
||
|
writeInt64Impl(id, (long)val);
|
||
|
break;
|
||
|
case (int)((FIELD_TYPE_INT64 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
|
||
|
case (int)((FIELD_TYPE_INT64 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
|
||
|
writeRepeatedInt64Impl(id, (long)val);
|
||
|
break;
|
||
|
// uint32
|
||
|
case (int)((FIELD_TYPE_UINT32 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
|
||
|
writeUInt32Impl(id, (int)val);
|
||
|
break;
|
||
|
case (int)((FIELD_TYPE_UINT32 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
|
||
|
case (int)((FIELD_TYPE_UINT32 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
|
||
|
writeRepeatedUInt32Impl(id, (int)val);
|
||
|
break;
|
||
|
// uint64
|
||
|
case (int)((FIELD_TYPE_UINT64 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
|
||
|
writeUInt64Impl(id, (long)val);
|
||
|
break;
|
||
|
case (int)((FIELD_TYPE_UINT64 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
|
||
|
case (int)((FIELD_TYPE_UINT64 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
|
||
|
writeRepeatedUInt64Impl(id, (long)val);
|
||
|
break;
|
||
|
// sint32
|
||
|
case (int)((FIELD_TYPE_SINT32 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
|
||
|
writeSInt32Impl(id, (int)val);
|
||
|
break;
|
||
|
case (int)((FIELD_TYPE_SINT32 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
|
||
|
case (int)((FIELD_TYPE_SINT32 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
|
||
|
writeRepeatedSInt32Impl(id, (int)val);
|
||
|
break;
|
||
|
// sint64
|
||
|
case (int)((FIELD_TYPE_SINT64 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
|
||
|
writeSInt64Impl(id, (long)val);
|
||
|
break;
|
||
|
case (int)((FIELD_TYPE_SINT64 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
|
||
|
case (int)((FIELD_TYPE_SINT64 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
|
||
|
writeRepeatedSInt64Impl(id, (long)val);
|
||
|
break;
|
||
|
// fixed32
|
||
|
case (int)((FIELD_TYPE_FIXED32 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
|
||
|
writeFixed32Impl(id, (int)val);
|
||
|
break;
|
||
|
case (int)((FIELD_TYPE_FIXED32 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
|
||
|
case (int)((FIELD_TYPE_FIXED32 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
|
||
|
writeRepeatedFixed32Impl(id, (int)val);
|
||
|
break;
|
||
|
// fixed64
|
||
|
case (int)((FIELD_TYPE_FIXED64 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
|
||
|
writeFixed64Impl(id, (long)val);
|
||
|
break;
|
||
|
case (int)((FIELD_TYPE_FIXED64 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
|
||
|
case (int)((FIELD_TYPE_FIXED64 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
|
||
|
writeRepeatedFixed64Impl(id, (long)val);
|
||
|
break;
|
||
|
// sfixed32
|
||
|
case (int)((FIELD_TYPE_SFIXED32 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
|
||
|
writeSFixed32Impl(id, (int)val);
|
||
|
break;
|
||
|
case (int)((FIELD_TYPE_SFIXED32 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
|
||
|
case (int)((FIELD_TYPE_SFIXED32 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
|
||
|
writeRepeatedSFixed32Impl(id, (int)val);
|
||
|
break;
|
||
|
// sfixed64
|
||
|
case (int)((FIELD_TYPE_SFIXED64 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
|
||
|
writeSFixed64Impl(id, (long)val);
|
||
|
break;
|
||
|
case (int)((FIELD_TYPE_SFIXED64 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
|
||
|
case (int)((FIELD_TYPE_SFIXED64 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
|
||
|
writeRepeatedSFixed64Impl(id, (long)val);
|
||
|
break;
|
||
|
// bool
|
||
|
case (int)((FIELD_TYPE_BOOL | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
|
||
|
writeBoolImpl(id, val != 0);
|
||
|
break;
|
||
|
case (int)((FIELD_TYPE_BOOL | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
|
||
|
case (int)((FIELD_TYPE_BOOL | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
|
||
|
writeRepeatedBoolImpl(id, val != 0);
|
||
|
break;
|
||
|
// enum
|
||
|
case (int)((FIELD_TYPE_ENUM | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
|
||
|
writeEnumImpl(id, (int)val);
|
||
|
break;
|
||
|
case (int)((FIELD_TYPE_ENUM | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
|
||
|
case (int)((FIELD_TYPE_ENUM | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
|
||
|
writeRepeatedEnumImpl(id, (int)val);
|
||
|
break;
|
||
|
// string, bytes, object not allowed here.
|
||
|
default: {
|
||
|
throw new IllegalArgumentException("Attempt to call write(long, int) with "
|
||
|
+ getFieldIdString(fieldId));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Write a value for the given fieldId.
|
||
|
*
|
||
|
* <p>Will automatically convert for the following field types, and
|
||
|
* throw an exception for others: double, float, int32, int64, uint32, uint64,
|
||
|
* sint32, sint64, fixed32, fixed64, sfixed32, sfixed64, bool, enum.
|
||
|
*
|
||
|
* @param fieldId The field identifier constant from the generated class.
|
||
|
* @param val The value.
|
||
|
*/
|
||
|
public void write(long fieldId, long val) {
|
||
|
assertNotCompacted();
|
||
|
final int id = (int)fieldId;
|
||
|
|
||
|
switch ((int)((fieldId & (FIELD_TYPE_MASK | FIELD_COUNT_MASK)) >> FIELD_TYPE_SHIFT)) {
|
||
|
// double
|
||
|
case (int)((FIELD_TYPE_DOUBLE | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
|
||
|
writeDoubleImpl(id, (double)val);
|
||
|
break;
|
||
|
case (int)((FIELD_TYPE_DOUBLE | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
|
||
|
case (int)((FIELD_TYPE_DOUBLE | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
|
||
|
writeRepeatedDoubleImpl(id, (double)val);
|
||
|
break;
|
||
|
// float
|
||
|
case (int)((FIELD_TYPE_FLOAT | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
|
||
|
writeFloatImpl(id, (float)val);
|
||
|
break;
|
||
|
case (int)((FIELD_TYPE_FLOAT | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
|
||
|
case (int)((FIELD_TYPE_FLOAT | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
|
||
|
writeRepeatedFloatImpl(id, (float)val);
|
||
|
break;
|
||
|
// int32
|
||
|
case (int)((FIELD_TYPE_INT32 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
|
||
|
writeInt32Impl(id, (int)val);
|
||
|
break;
|
||
|
case (int)((FIELD_TYPE_INT32 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
|
||
|
case (int)((FIELD_TYPE_INT32 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
|
||
|
writeRepeatedInt32Impl(id, (int)val);
|
||
|
break;
|
||
|
// int64
|
||
|
case (int)((FIELD_TYPE_INT64 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
|
||
|
writeInt64Impl(id, (long)val);
|
||
|
break;
|
||
|
case (int)((FIELD_TYPE_INT64 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
|
||
|
case (int)((FIELD_TYPE_INT64 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
|
||
|
writeRepeatedInt64Impl(id, (long)val);
|
||
|
break;
|
||
|
// uint32
|
||
|
case (int)((FIELD_TYPE_UINT32 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
|
||
|
writeUInt32Impl(id, (int)val);
|
||
|
break;
|
||
|
case (int)((FIELD_TYPE_UINT32 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
|
||
|
case (int)((FIELD_TYPE_UINT32 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
|
||
|
writeRepeatedUInt32Impl(id, (int)val);
|
||
|
break;
|
||
|
// uint64
|
||
|
case (int)((FIELD_TYPE_UINT64 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
|
||
|
writeUInt64Impl(id, (long)val);
|
||
|
break;
|
||
|
case (int)((FIELD_TYPE_UINT64 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
|
||
|
case (int)((FIELD_TYPE_UINT64 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
|
||
|
writeRepeatedUInt64Impl(id, (long)val);
|
||
|
break;
|
||
|
// sint32
|
||
|
case (int)((FIELD_TYPE_SINT32 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
|
||
|
writeSInt32Impl(id, (int)val);
|
||
|
break;
|
||
|
case (int)((FIELD_TYPE_SINT32 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
|
||
|
case (int)((FIELD_TYPE_SINT32 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
|
||
|
writeRepeatedSInt32Impl(id, (int)val);
|
||
|
break;
|
||
|
// sint64
|
||
|
case (int)((FIELD_TYPE_SINT64 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
|
||
|
writeSInt64Impl(id, (long)val);
|
||
|
break;
|
||
|
case (int)((FIELD_TYPE_SINT64 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
|
||
|
case (int)((FIELD_TYPE_SINT64 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
|
||
|
writeRepeatedSInt64Impl(id, (long)val);
|
||
|
break;
|
||
|
// fixed32
|
||
|
case (int)((FIELD_TYPE_FIXED32 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
|
||
|
writeFixed32Impl(id, (int)val);
|
||
|
break;
|
||
|
case (int)((FIELD_TYPE_FIXED32 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
|
||
|
case (int)((FIELD_TYPE_FIXED32 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
|
||
|
writeRepeatedFixed32Impl(id, (int)val);
|
||
|
break;
|
||
|
// fixed64
|
||
|
case (int)((FIELD_TYPE_FIXED64 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
|
||
|
writeFixed64Impl(id, (long)val);
|
||
|
break;
|
||
|
case (int)((FIELD_TYPE_FIXED64 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
|
||
|
case (int)((FIELD_TYPE_FIXED64 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
|
||
|
writeRepeatedFixed64Impl(id, (long)val);
|
||
|
break;
|
||
|
// sfixed32
|
||
|
case (int)((FIELD_TYPE_SFIXED32 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
|
||
|
writeSFixed32Impl(id, (int)val);
|
||
|
break;
|
||
|
case (int)((FIELD_TYPE_SFIXED32 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
|
||
|
case (int)((FIELD_TYPE_SFIXED32 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
|
||
|
writeRepeatedSFixed32Impl(id, (int)val);
|
||
|
break;
|
||
|
// sfixed64
|
||
|
case (int)((FIELD_TYPE_SFIXED64 | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
|
||
|
writeSFixed64Impl(id, (long)val);
|
||
|
break;
|
||
|
case (int)((FIELD_TYPE_SFIXED64 | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
|
||
|
case (int)((FIELD_TYPE_SFIXED64 | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
|
||
|
writeRepeatedSFixed64Impl(id, (long)val);
|
||
|
break;
|
||
|
// bool
|
||
|
case (int)((FIELD_TYPE_BOOL | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
|
||
|
writeBoolImpl(id, val != 0);
|
||
|
break;
|
||
|
case (int)((FIELD_TYPE_BOOL | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
|
||
|
case (int)((FIELD_TYPE_BOOL | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
|
||
|
writeRepeatedBoolImpl(id, val != 0);
|
||
|
break;
|
||
|
// enum
|
||
|
case (int)((FIELD_TYPE_ENUM | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
|
||
|
writeEnumImpl(id, (int)val);
|
||
|
break;
|
||
|
case (int)((FIELD_TYPE_ENUM | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
|
||
|
case (int)((FIELD_TYPE_ENUM | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
|
||
|
writeRepeatedEnumImpl(id, (int)val);
|
||
|
break;
|
||
|
// string, bytes, object not allowed here.
|
||
|
default: {
|
||
|
throw new IllegalArgumentException("Attempt to call write(long, long) with "
|
||
|
+ getFieldIdString(fieldId));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Write a boolean value for the given fieldId.
|
||
|
*
|
||
|
* <p>If the field is not a bool field, an {@link IllegalStateException} will be thrown.
|
||
|
*
|
||
|
* @param fieldId The field identifier constant from the generated class.
|
||
|
* @param val The value.
|
||
|
*/
|
||
|
public void write(long fieldId, boolean val) {
|
||
|
assertNotCompacted();
|
||
|
final int id = (int)fieldId;
|
||
|
|
||
|
switch ((int)((fieldId & (FIELD_TYPE_MASK | FIELD_COUNT_MASK)) >> FIELD_TYPE_SHIFT)) {
|
||
|
// bool
|
||
|
case (int)((FIELD_TYPE_BOOL | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
|
||
|
writeBoolImpl(id, val);
|
||
|
break;
|
||
|
case (int)((FIELD_TYPE_BOOL | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
|
||
|
case (int)((FIELD_TYPE_BOOL | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
|
||
|
writeRepeatedBoolImpl(id, val);
|
||
|
break;
|
||
|
// nothing else allowed
|
||
|
default: {
|
||
|
throw new IllegalArgumentException("Attempt to call write(long, boolean) with "
|
||
|
+ getFieldIdString(fieldId));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Write a string value for the given fieldId.
|
||
|
*
|
||
|
* <p>If the field is not a string field, an exception will be thrown.
|
||
|
*
|
||
|
* @param fieldId The field identifier constant from the generated class.
|
||
|
* @param val The value.
|
||
|
*/
|
||
|
public void write(long fieldId, @Nullable String val) {
|
||
|
assertNotCompacted();
|
||
|
final int id = (int)fieldId;
|
||
|
|
||
|
switch ((int)((fieldId & (FIELD_TYPE_MASK | FIELD_COUNT_MASK)) >> FIELD_TYPE_SHIFT)) {
|
||
|
// string
|
||
|
case (int)((FIELD_TYPE_STRING | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
|
||
|
writeStringImpl(id, val);
|
||
|
break;
|
||
|
case (int)((FIELD_TYPE_STRING | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
|
||
|
case (int)((FIELD_TYPE_STRING | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
|
||
|
writeRepeatedStringImpl(id, val);
|
||
|
break;
|
||
|
// nothing else allowed
|
||
|
default: {
|
||
|
throw new IllegalArgumentException("Attempt to call write(long, String) with "
|
||
|
+ getFieldIdString(fieldId));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Write a byte[] value for the given fieldId.
|
||
|
*
|
||
|
* <p>If the field is not a bytes or object field, an exception will be thrown.
|
||
|
*
|
||
|
* @param fieldId The field identifier constant from the generated class.
|
||
|
* @param val The value.
|
||
|
*/
|
||
|
public void write(long fieldId, @Nullable byte[] val) {
|
||
|
assertNotCompacted();
|
||
|
final int id = (int)fieldId;
|
||
|
|
||
|
switch ((int) ((fieldId & (FIELD_TYPE_MASK | FIELD_COUNT_MASK)) >> FIELD_TYPE_SHIFT)) {
|
||
|
// bytes
|
||
|
case (int) ((FIELD_TYPE_BYTES | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
|
||
|
writeBytesImpl(id, val);
|
||
|
break;
|
||
|
case (int) ((FIELD_TYPE_BYTES | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
|
||
|
case (int) ((FIELD_TYPE_BYTES | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
|
||
|
writeRepeatedBytesImpl(id, val);
|
||
|
break;
|
||
|
// Object
|
||
|
case (int) ((FIELD_TYPE_MESSAGE | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
|
||
|
writeObjectImpl(id, val);
|
||
|
break;
|
||
|
case (int) ((FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
|
||
|
case (int) ((FIELD_TYPE_MESSAGE | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
|
||
|
writeRepeatedObjectImpl(id, val);
|
||
|
break;
|
||
|
// nothing else allowed
|
||
|
default: {
|
||
|
throw new IllegalArgumentException("Attempt to call write(long, byte[]) with "
|
||
|
+ getFieldIdString(fieldId));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Start a sub object.
|
||
|
*
|
||
|
* @param fieldId The field identifier constant from the generated class.
|
||
|
* @return The token to call {@link #end(long)} with.
|
||
|
*/
|
||
|
public long start(long fieldId) {
|
||
|
assertNotCompacted();
|
||
|
final int id = (int)fieldId;
|
||
|
|
||
|
if ((fieldId & FIELD_TYPE_MASK) == FIELD_TYPE_MESSAGE) {
|
||
|
final long count = fieldId & FIELD_COUNT_MASK;
|
||
|
if (count == FIELD_COUNT_SINGLE) {
|
||
|
return startObjectImpl(id, false);
|
||
|
} else if (count == FIELD_COUNT_REPEATED || count == FIELD_COUNT_PACKED) {
|
||
|
return startObjectImpl(id, true);
|
||
|
}
|
||
|
}
|
||
|
throw new IllegalArgumentException("Attempt to call start(long) with "
|
||
|
+ getFieldIdString(fieldId));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* End the object started by start() that returned token.
|
||
|
*
|
||
|
* @param token The token returned from {@link #start(long)}
|
||
|
*/
|
||
|
public void end(long token) {
|
||
|
endObjectImpl(token, getRepeatedFromToken(token));
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// proto3 type: double
|
||
|
// java type: double
|
||
|
// encoding: fixed64
|
||
|
// wire type: WIRE_TYPE_FIXED64
|
||
|
//
|
||
|
|
||
|
/**
|
||
|
* Write a single proto "double" type field value.
|
||
|
*
|
||
|
* @deprecated Use {@link #write(long, double)} instead.
|
||
|
* @hide
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public void writeDouble(long fieldId, double val) {
|
||
|
assertNotCompacted();
|
||
|
final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_DOUBLE);
|
||
|
|
||
|
writeDoubleImpl(id, val);
|
||
|
}
|
||
|
|
||
|
private void writeDoubleImpl(int id, double val) {
|
||
|
if (val != 0) {
|
||
|
writeTag(id, WIRE_TYPE_FIXED64);
|
||
|
mBuffer.writeRawFixed64(Double.doubleToLongBits(val));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Write a single repeated proto "double" type field value.
|
||
|
*
|
||
|
* @deprecated Use {@link #write(long, double)} instead.
|
||
|
* @hide
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public void writeRepeatedDouble(long fieldId, double val) {
|
||
|
assertNotCompacted();
|
||
|
final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_DOUBLE);
|
||
|
|
||
|
writeRepeatedDoubleImpl(id, val);
|
||
|
}
|
||
|
|
||
|
private void writeRepeatedDoubleImpl(int id, double val) {
|
||
|
writeTag(id, WIRE_TYPE_FIXED64);
|
||
|
mBuffer.writeRawFixed64(Double.doubleToLongBits(val));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Write a list of packed proto "double" type field values.
|
||
|
*
|
||
|
* @deprecated Use {@link #write(long, double)} instead.
|
||
|
* @hide
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public void writePackedDouble(long fieldId, @Nullable double[] val) {
|
||
|
assertNotCompacted();
|
||
|
final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_DOUBLE);
|
||
|
|
||
|
final int N = val != null ? val.length : 0;
|
||
|
if (N > 0) {
|
||
|
writeKnownLengthHeader(id, N * 8);
|
||
|
for (int i=0; i<N; i++) {
|
||
|
mBuffer.writeRawFixed64(Double.doubleToLongBits(val[i]));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// proto3 type: float
|
||
|
// java type: float
|
||
|
// encoding: fixed32
|
||
|
// wire type: WIRE_TYPE_FIXED32
|
||
|
//
|
||
|
|
||
|
/**
|
||
|
* Write a single proto "float" type field value.
|
||
|
*
|
||
|
* @deprecated Use {@link #write(long, float)} instead.
|
||
|
* @hide
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public void writeFloat(long fieldId, float val) {
|
||
|
assertNotCompacted();
|
||
|
final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_FLOAT);
|
||
|
|
||
|
writeFloatImpl(id, val);
|
||
|
}
|
||
|
|
||
|
private void writeFloatImpl(int id, float val) {
|
||
|
if (val != 0) {
|
||
|
writeTag(id, WIRE_TYPE_FIXED32);
|
||
|
mBuffer.writeRawFixed32(Float.floatToIntBits(val));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Write a single repeated proto "float" type field value.
|
||
|
*
|
||
|
* @deprecated Use {@link #write(long, float)} instead.
|
||
|
* @hide
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public void writeRepeatedFloat(long fieldId, float val) {
|
||
|
assertNotCompacted();
|
||
|
final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_FLOAT);
|
||
|
|
||
|
writeRepeatedFloatImpl(id, val);
|
||
|
}
|
||
|
|
||
|
private void writeRepeatedFloatImpl(int id, float val) {
|
||
|
writeTag(id, WIRE_TYPE_FIXED32);
|
||
|
mBuffer.writeRawFixed32(Float.floatToIntBits(val));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Write a list of packed proto "float" type field value.
|
||
|
*
|
||
|
* @deprecated Use {@link #write(long, float)} instead.
|
||
|
* @hide
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public void writePackedFloat(long fieldId, @Nullable float[] val) {
|
||
|
assertNotCompacted();
|
||
|
final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_FLOAT);
|
||
|
|
||
|
final int N = val != null ? val.length : 0;
|
||
|
if (N > 0) {
|
||
|
writeKnownLengthHeader(id, N * 4);
|
||
|
for (int i=0; i<N; i++) {
|
||
|
mBuffer.writeRawFixed32(Float.floatToIntBits(val[i]));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// proto3 type: int32
|
||
|
// java type: int
|
||
|
// signed/unsigned: signed
|
||
|
// encoding: varint
|
||
|
// wire type: WIRE_TYPE_VARINT
|
||
|
//
|
||
|
|
||
|
/**
|
||
|
* Writes a java int as an usigned varint.
|
||
|
*
|
||
|
* <p>The unadorned int32 type in protobuf is unfortunate because it
|
||
|
* is stored in memory as a signed value, but encodes as unsigned
|
||
|
* varints, which are formally always longs. So here, we encode
|
||
|
* negative values as 64 bits, which will get the sign-extension,
|
||
|
* and positive values as 32 bits, which saves a marginal amount
|
||
|
* of work in that it processes ints instead of longs.
|
||
|
*/
|
||
|
private void writeUnsignedVarintFromSignedInt(int val) {
|
||
|
if (val >= 0) {
|
||
|
mBuffer.writeRawVarint32(val);
|
||
|
} else {
|
||
|
mBuffer.writeRawVarint64(val);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Write a single proto "int32" type field value.
|
||
|
*
|
||
|
* <p>Note that these are stored in memory as signed values and written as unsigned
|
||
|
* varints, which if negative, are 10 bytes long. If you know the data is likely
|
||
|
* to be negative, use "sint32".
|
||
|
*
|
||
|
* @deprecated Use {@link #write(long, int)} instead.
|
||
|
* @hide
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public void writeInt32(long fieldId, int val) {
|
||
|
assertNotCompacted();
|
||
|
final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_INT32);
|
||
|
|
||
|
writeInt32Impl(id, val);
|
||
|
}
|
||
|
|
||
|
private void writeInt32Impl(int id, int val) {
|
||
|
if (val != 0) {
|
||
|
writeTag(id, WIRE_TYPE_VARINT);
|
||
|
writeUnsignedVarintFromSignedInt(val);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Write a single repeated proto "int32" type field value.
|
||
|
*
|
||
|
* <p>Note that these are stored in memory as signed values and written as unsigned
|
||
|
* varints, which if negative, are 10 bytes long. If you know the data is likely
|
||
|
* to be negative, use "sint32".
|
||
|
*
|
||
|
* @deprecated Use {@link #write(long, int)} instead.
|
||
|
* @hide
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public void writeRepeatedInt32(long fieldId, int val) {
|
||
|
assertNotCompacted();
|
||
|
final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_INT32);
|
||
|
|
||
|
writeRepeatedInt32Impl(id, val);
|
||
|
}
|
||
|
|
||
|
private void writeRepeatedInt32Impl(int id, int val) {
|
||
|
writeTag(id, WIRE_TYPE_VARINT);
|
||
|
writeUnsignedVarintFromSignedInt(val);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Write a list of packed proto "int32" type field value.
|
||
|
*
|
||
|
* <p>Note that these are stored in memory as signed values and written as unsigned
|
||
|
* varints, which if negative, are 10 bytes long. If you know the data is likely
|
||
|
* to be negative, use "sint32".
|
||
|
*
|
||
|
* @deprecated Use {@link #write(long, int)} instead.
|
||
|
* @hide
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public void writePackedInt32(long fieldId, @Nullable int[] val) {
|
||
|
assertNotCompacted();
|
||
|
final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_INT32);
|
||
|
|
||
|
final int N = val != null ? val.length : 0;
|
||
|
if (N > 0) {
|
||
|
int size = 0;
|
||
|
for (int i=0; i<N; i++) {
|
||
|
final int v = val[i];
|
||
|
size += v >= 0 ? EncodedBuffer.getRawVarint32Size(v) : 10;
|
||
|
}
|
||
|
writeKnownLengthHeader(id, size);
|
||
|
for (int i=0; i<N; i++) {
|
||
|
writeUnsignedVarintFromSignedInt(val[i]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// proto3 type: int64
|
||
|
// java type: int
|
||
|
// signed/unsigned: signed
|
||
|
// encoding: varint
|
||
|
// wire type: WIRE_TYPE_VARINT
|
||
|
//
|
||
|
|
||
|
/**
|
||
|
* Write a single proto "int64" type field value.
|
||
|
*
|
||
|
* @deprecated Use {@link #write(long, long)} instead.
|
||
|
* @hide
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public void writeInt64(long fieldId, long val) {
|
||
|
assertNotCompacted();
|
||
|
final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_INT64);
|
||
|
|
||
|
writeInt64Impl(id, val);
|
||
|
}
|
||
|
|
||
|
private void writeInt64Impl(int id, long val) {
|
||
|
if (val != 0) {
|
||
|
writeTag(id, WIRE_TYPE_VARINT);
|
||
|
mBuffer.writeRawVarint64(val);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Write a single repeated proto "int64" type field value.
|
||
|
*
|
||
|
* @deprecated Use {@link #write(long, long)} instead.
|
||
|
* @hide
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public void writeRepeatedInt64(long fieldId, long val) {
|
||
|
assertNotCompacted();
|
||
|
final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_INT64);
|
||
|
|
||
|
writeRepeatedInt64Impl(id, val);
|
||
|
}
|
||
|
|
||
|
private void writeRepeatedInt64Impl(int id, long val) {
|
||
|
writeTag(id, WIRE_TYPE_VARINT);
|
||
|
mBuffer.writeRawVarint64(val);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Write a list of packed proto "int64" type field value.
|
||
|
*
|
||
|
* @deprecated Use {@link #write(long, long)} instead.
|
||
|
* @hide
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public void writePackedInt64(long fieldId, @Nullable long[] val) {
|
||
|
assertNotCompacted();
|
||
|
final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_INT64);
|
||
|
|
||
|
final int N = val != null ? val.length : 0;
|
||
|
if (N > 0) {
|
||
|
int size = 0;
|
||
|
for (int i=0; i<N; i++) {
|
||
|
size += EncodedBuffer.getRawVarint64Size(val[i]);
|
||
|
}
|
||
|
writeKnownLengthHeader(id, size);
|
||
|
for (int i=0; i<N; i++) {
|
||
|
mBuffer.writeRawVarint64(val[i]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// proto3 type: uint32
|
||
|
// java type: int
|
||
|
// signed/unsigned: unsigned
|
||
|
// encoding: varint
|
||
|
// wire type: WIRE_TYPE_VARINT
|
||
|
//
|
||
|
|
||
|
/**
|
||
|
* Write a single proto "uint32" type field value.
|
||
|
*
|
||
|
* @deprecated Use {@link #write(long, int)} instead.
|
||
|
* @hide
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public void writeUInt32(long fieldId, int val) {
|
||
|
assertNotCompacted();
|
||
|
final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_UINT32);
|
||
|
|
||
|
writeUInt32Impl(id, val);
|
||
|
}
|
||
|
|
||
|
private void writeUInt32Impl(int id, int val) {
|
||
|
if (val != 0) {
|
||
|
writeTag(id, WIRE_TYPE_VARINT);
|
||
|
mBuffer.writeRawVarint32(val);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Write a single repeated proto "uint32" type field value.
|
||
|
*
|
||
|
* @deprecated Use {@link #write(long, int)} instead.
|
||
|
* @hide
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public void writeRepeatedUInt32(long fieldId, int val) {
|
||
|
assertNotCompacted();
|
||
|
final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_UINT32);
|
||
|
|
||
|
writeRepeatedUInt32Impl(id, val);
|
||
|
}
|
||
|
|
||
|
private void writeRepeatedUInt32Impl(int id, int val) {
|
||
|
writeTag(id, WIRE_TYPE_VARINT);
|
||
|
mBuffer.writeRawVarint32(val);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Write a list of packed proto "uint32" type field value.
|
||
|
*
|
||
|
* @deprecated Use {@link #write(long, int)} instead.
|
||
|
* @hide
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public void writePackedUInt32(long fieldId, @Nullable int[] val) {
|
||
|
assertNotCompacted();
|
||
|
final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_UINT32);
|
||
|
|
||
|
final int N = val != null ? val.length : 0;
|
||
|
if (N > 0) {
|
||
|
int size = 0;
|
||
|
for (int i=0; i<N; i++) {
|
||
|
size += EncodedBuffer.getRawVarint32Size(val[i]);
|
||
|
}
|
||
|
writeKnownLengthHeader(id, size);
|
||
|
for (int i=0; i<N; i++) {
|
||
|
mBuffer.writeRawVarint32(val[i]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// proto3 type: uint64
|
||
|
// java type: int
|
||
|
// signed/unsigned: unsigned
|
||
|
// encoding: varint
|
||
|
// wire type: WIRE_TYPE_VARINT
|
||
|
//
|
||
|
|
||
|
/**
|
||
|
* Write a single proto "uint64" type field value.
|
||
|
*
|
||
|
* @deprecated Use {@link #write(long, long)} instead.
|
||
|
* @hide
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public void writeUInt64(long fieldId, long val) {
|
||
|
assertNotCompacted();
|
||
|
final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_UINT64);
|
||
|
|
||
|
writeUInt64Impl(id, val);
|
||
|
}
|
||
|
|
||
|
private void writeUInt64Impl(int id, long val) {
|
||
|
if (val != 0) {
|
||
|
writeTag(id, WIRE_TYPE_VARINT);
|
||
|
mBuffer.writeRawVarint64(val);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Write a single proto "uint64" type field value.
|
||
|
*
|
||
|
* @deprecated Use {@link #write(long, long)} instead.
|
||
|
* @hide
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public void writeRepeatedUInt64(long fieldId, long val) {
|
||
|
assertNotCompacted();
|
||
|
final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_UINT64);
|
||
|
|
||
|
writeRepeatedUInt64Impl(id, val);
|
||
|
}
|
||
|
|
||
|
private void writeRepeatedUInt64Impl(int id, long val) {
|
||
|
writeTag(id, WIRE_TYPE_VARINT);
|
||
|
mBuffer.writeRawVarint64(val);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Write a single proto "uint64" type field value.
|
||
|
*
|
||
|
* @deprecated Use {@link #write(long, long)} instead.
|
||
|
* @hide
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public void writePackedUInt64(long fieldId, @Nullable long[] val) {
|
||
|
assertNotCompacted();
|
||
|
final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_UINT64);
|
||
|
|
||
|
final int N = val != null ? val.length : 0;
|
||
|
if (N > 0) {
|
||
|
int size = 0;
|
||
|
for (int i=0; i<N; i++) {
|
||
|
size += EncodedBuffer.getRawVarint64Size(val[i]);
|
||
|
}
|
||
|
writeKnownLengthHeader(id, size);
|
||
|
for (int i=0; i<N; i++) {
|
||
|
mBuffer.writeRawVarint64(val[i]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// proto3 type: sint32
|
||
|
// java type: int
|
||
|
// signed/unsigned: signed
|
||
|
// encoding: zig-zag
|
||
|
// wire type: WIRE_TYPE_VARINT
|
||
|
//
|
||
|
|
||
|
/**
|
||
|
* Write a single proto "sint32" type field value.
|
||
|
*
|
||
|
* @deprecated Use {@link #write(long, int)} instead.
|
||
|
* @hide
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public void writeSInt32(long fieldId, int val) {
|
||
|
assertNotCompacted();
|
||
|
final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_SINT32);
|
||
|
|
||
|
writeSInt32Impl(id, val);
|
||
|
}
|
||
|
|
||
|
private void writeSInt32Impl(int id, int val) {
|
||
|
if (val != 0) {
|
||
|
writeTag(id, WIRE_TYPE_VARINT);
|
||
|
mBuffer.writeRawZigZag32(val);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Write a single repeated proto "sint32" type field value.
|
||
|
*
|
||
|
* @deprecated Use {@link #write(long, int)} instead.
|
||
|
* @hide
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public void writeRepeatedSInt32(long fieldId, int val) {
|
||
|
assertNotCompacted();
|
||
|
final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_SINT32);
|
||
|
|
||
|
writeRepeatedSInt32Impl(id, val);
|
||
|
}
|
||
|
|
||
|
private void writeRepeatedSInt32Impl(int id, int val) {
|
||
|
writeTag(id, WIRE_TYPE_VARINT);
|
||
|
mBuffer.writeRawZigZag32(val);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Write a list of packed proto "sint32" type field value.
|
||
|
*
|
||
|
* @deprecated Use {@link #write(long, int)} instead.
|
||
|
* @hide
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public void writePackedSInt32(long fieldId, @Nullable int[] val) {
|
||
|
assertNotCompacted();
|
||
|
final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_SINT32);
|
||
|
|
||
|
final int N = val != null ? val.length : 0;
|
||
|
if (N > 0) {
|
||
|
int size = 0;
|
||
|
for (int i=0; i<N; i++) {
|
||
|
size += EncodedBuffer.getRawZigZag32Size(val[i]);
|
||
|
}
|
||
|
writeKnownLengthHeader(id, size);
|
||
|
for (int i=0; i<N; i++) {
|
||
|
mBuffer.writeRawZigZag32(val[i]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// proto3 type: sint64
|
||
|
// java type: int
|
||
|
// signed/unsigned: signed
|
||
|
// encoding: zig-zag
|
||
|
// wire type: WIRE_TYPE_VARINT
|
||
|
//
|
||
|
|
||
|
/**
|
||
|
* Write a single proto "sint64" type field value.
|
||
|
*
|
||
|
* @deprecated Use {@link #write(long, long)} instead.
|
||
|
* @hide
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public void writeSInt64(long fieldId, long val) {
|
||
|
assertNotCompacted();
|
||
|
final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_SINT64);
|
||
|
|
||
|
writeSInt64Impl(id, val);
|
||
|
}
|
||
|
|
||
|
private void writeSInt64Impl(int id, long val) {
|
||
|
if (val != 0) {
|
||
|
writeTag(id, WIRE_TYPE_VARINT);
|
||
|
mBuffer.writeRawZigZag64(val);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Write a single repeated proto "sint64" type field value.
|
||
|
*
|
||
|
* @deprecated Use {@link #write(long, long)} instead.
|
||
|
* @hide
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public void writeRepeatedSInt64(long fieldId, long val) {
|
||
|
assertNotCompacted();
|
||
|
final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_SINT64);
|
||
|
|
||
|
writeRepeatedSInt64Impl(id, val);
|
||
|
}
|
||
|
|
||
|
private void writeRepeatedSInt64Impl(int id, long val) {
|
||
|
writeTag(id, WIRE_TYPE_VARINT);
|
||
|
mBuffer.writeRawZigZag64(val);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Write a list of packed proto "sint64" type field value.
|
||
|
*
|
||
|
* @deprecated Use {@link #write(long, long)} instead.
|
||
|
* @hide
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public void writePackedSInt64(long fieldId, @Nullable long[] val) {
|
||
|
assertNotCompacted();
|
||
|
final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_SINT64);
|
||
|
|
||
|
final int N = val != null ? val.length : 0;
|
||
|
if (N > 0) {
|
||
|
int size = 0;
|
||
|
for (int i=0; i<N; i++) {
|
||
|
size += EncodedBuffer.getRawZigZag64Size(val[i]);
|
||
|
}
|
||
|
writeKnownLengthHeader(id, size);
|
||
|
for (int i=0; i<N; i++) {
|
||
|
mBuffer.writeRawZigZag64(val[i]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// proto3 type: fixed32
|
||
|
// java type: int
|
||
|
// encoding: little endian
|
||
|
// wire type: WIRE_TYPE_FIXED32
|
||
|
//
|
||
|
|
||
|
/**
|
||
|
* Write a single proto "fixed32" type field value.
|
||
|
*
|
||
|
* @deprecated Use {@link #write(long, int)} instead.
|
||
|
* @hide
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public void writeFixed32(long fieldId, int val) {
|
||
|
assertNotCompacted();
|
||
|
final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_FIXED32);
|
||
|
|
||
|
writeFixed32Impl(id, val);
|
||
|
}
|
||
|
|
||
|
private void writeFixed32Impl(int id, int val) {
|
||
|
if (val != 0) {
|
||
|
writeTag(id, WIRE_TYPE_FIXED32);
|
||
|
mBuffer.writeRawFixed32(val);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Write a single repeated proto "fixed32" type field value.
|
||
|
*
|
||
|
* @deprecated Use {@link #write(long, int)} instead.
|
||
|
* @hide
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public void writeRepeatedFixed32(long fieldId, int val) {
|
||
|
assertNotCompacted();
|
||
|
final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_FIXED32);
|
||
|
|
||
|
writeRepeatedFixed32Impl(id, val);
|
||
|
}
|
||
|
|
||
|
private void writeRepeatedFixed32Impl(int id, int val) {
|
||
|
writeTag(id, WIRE_TYPE_FIXED32);
|
||
|
mBuffer.writeRawFixed32(val);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Write a list of packed proto "fixed32" type field value.
|
||
|
*
|
||
|
* @deprecated Use {@link #write(long, int)} instead.
|
||
|
* @hide
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public void writePackedFixed32(long fieldId, @Nullable int[] val) {
|
||
|
assertNotCompacted();
|
||
|
final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_FIXED32);
|
||
|
|
||
|
final int N = val != null ? val.length : 0;
|
||
|
if (N > 0) {
|
||
|
writeKnownLengthHeader(id, N * 4);
|
||
|
for (int i=0; i<N; i++) {
|
||
|
mBuffer.writeRawFixed32(val[i]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// proto3 type: fixed64
|
||
|
// java type: long
|
||
|
// encoding: fixed64
|
||
|
// wire type: WIRE_TYPE_FIXED64
|
||
|
//
|
||
|
|
||
|
/**
|
||
|
* Write a single proto "fixed64" type field value.
|
||
|
*
|
||
|
* @deprecated Use {@link #write(long, long)} instead.
|
||
|
* @hide
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public void writeFixed64(long fieldId, long val) {
|
||
|
assertNotCompacted();
|
||
|
final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_FIXED64);
|
||
|
|
||
|
writeFixed64Impl(id, val);
|
||
|
}
|
||
|
|
||
|
private void writeFixed64Impl(int id, long val) {
|
||
|
if (val != 0) {
|
||
|
writeTag(id, WIRE_TYPE_FIXED64);
|
||
|
mBuffer.writeRawFixed64(val);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Write a single repeated proto "fixed64" type field value.
|
||
|
*
|
||
|
* @deprecated Use {@link #write(long, long)} instead.
|
||
|
* @hide
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public void writeRepeatedFixed64(long fieldId, long val) {
|
||
|
assertNotCompacted();
|
||
|
final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_FIXED64);
|
||
|
|
||
|
writeRepeatedFixed64Impl(id, val);
|
||
|
}
|
||
|
|
||
|
private void writeRepeatedFixed64Impl(int id, long val) {
|
||
|
writeTag(id, WIRE_TYPE_FIXED64);
|
||
|
mBuffer.writeRawFixed64(val);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Write a list of packed proto "fixed64" type field value.
|
||
|
*
|
||
|
* @deprecated Use {@link #write(long, long)} instead.
|
||
|
* @hide
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public void writePackedFixed64(long fieldId, @Nullable long[] val) {
|
||
|
assertNotCompacted();
|
||
|
final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_FIXED64);
|
||
|
|
||
|
final int N = val != null ? val.length : 0;
|
||
|
if (N > 0) {
|
||
|
writeKnownLengthHeader(id, N * 8);
|
||
|
for (int i=0; i<N; i++) {
|
||
|
mBuffer.writeRawFixed64(val[i]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// proto3 type: sfixed32
|
||
|
// java type: int
|
||
|
// encoding: little endian
|
||
|
// wire type: WIRE_TYPE_FIXED32
|
||
|
//
|
||
|
/**
|
||
|
* Write a single proto "sfixed32" type field value.
|
||
|
*
|
||
|
* @deprecated Use {@link #write(long, int)} instead.
|
||
|
* @hide
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public void writeSFixed32(long fieldId, int val) {
|
||
|
assertNotCompacted();
|
||
|
final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_SFIXED32);
|
||
|
|
||
|
writeSFixed32Impl(id, val);
|
||
|
}
|
||
|
|
||
|
private void writeSFixed32Impl(int id, int val) {
|
||
|
if (val != 0) {
|
||
|
writeTag(id, WIRE_TYPE_FIXED32);
|
||
|
mBuffer.writeRawFixed32(val);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Write a single repeated proto "sfixed32" type field value.
|
||
|
*
|
||
|
* @deprecated Use {@link #write(long, int)} instead.
|
||
|
* @hide
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public void writeRepeatedSFixed32(long fieldId, int val) {
|
||
|
assertNotCompacted();
|
||
|
final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_SFIXED32);
|
||
|
|
||
|
writeRepeatedSFixed32Impl(id, val);
|
||
|
}
|
||
|
|
||
|
private void writeRepeatedSFixed32Impl(int id, int val) {
|
||
|
writeTag(id, WIRE_TYPE_FIXED32);
|
||
|
mBuffer.writeRawFixed32(val);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Write a list of packed proto "sfixed32" type field value.
|
||
|
*
|
||
|
* @deprecated Use {@link #write(long, int)} instead.
|
||
|
* @hide
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public void writePackedSFixed32(long fieldId, @Nullable int[] val) {
|
||
|
assertNotCompacted();
|
||
|
final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_SFIXED32);
|
||
|
|
||
|
final int N = val != null ? val.length : 0;
|
||
|
if (N > 0) {
|
||
|
writeKnownLengthHeader(id, N * 4);
|
||
|
for (int i=0; i<N; i++) {
|
||
|
mBuffer.writeRawFixed32(val[i]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// proto3 type: sfixed64
|
||
|
// java type: long
|
||
|
// encoding: little endian
|
||
|
// wire type: WIRE_TYPE_FIXED64
|
||
|
//
|
||
|
|
||
|
/**
|
||
|
* Write a single proto "sfixed64" type field value.
|
||
|
*
|
||
|
* @deprecated Use {@link #write(long, long)} instead.
|
||
|
* @hide
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public void writeSFixed64(long fieldId, long val) {
|
||
|
assertNotCompacted();
|
||
|
final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_SFIXED64);
|
||
|
|
||
|
writeSFixed64Impl(id, val);
|
||
|
}
|
||
|
|
||
|
private void writeSFixed64Impl(int id, long val) {
|
||
|
if (val != 0) {
|
||
|
writeTag(id, WIRE_TYPE_FIXED64);
|
||
|
mBuffer.writeRawFixed64(val);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Write a single repeated proto "sfixed64" type field value.
|
||
|
*
|
||
|
* @deprecated Use {@link #write(long, long)} instead.
|
||
|
* @hide
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public void writeRepeatedSFixed64(long fieldId, long val) {
|
||
|
assertNotCompacted();
|
||
|
final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_SFIXED64);
|
||
|
|
||
|
writeRepeatedSFixed64Impl(id, val);
|
||
|
}
|
||
|
|
||
|
private void writeRepeatedSFixed64Impl(int id, long val) {
|
||
|
writeTag(id, WIRE_TYPE_FIXED64);
|
||
|
mBuffer.writeRawFixed64(val);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Write a list of packed proto "sfixed64" type field value.
|
||
|
*
|
||
|
* @deprecated Use {@link #write(long, long)} instead.
|
||
|
* @hide
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public void writePackedSFixed64(long fieldId, @Nullable long[] val) {
|
||
|
assertNotCompacted();
|
||
|
final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_SFIXED64);
|
||
|
|
||
|
final int N = val != null ? val.length : 0;
|
||
|
if (N > 0) {
|
||
|
writeKnownLengthHeader(id, N * 8);
|
||
|
for (int i=0; i<N; i++) {
|
||
|
mBuffer.writeRawFixed64(val[i]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// proto3 type: bool
|
||
|
// java type: boolean
|
||
|
// encoding: varint
|
||
|
// wire type: WIRE_TYPE_VARINT
|
||
|
//
|
||
|
|
||
|
/**
|
||
|
* Write a single proto "bool" type field value.
|
||
|
*
|
||
|
* @deprecated Use {@link #write(long, boolean)} instead.
|
||
|
* @hide
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public void writeBool(long fieldId, boolean val) {
|
||
|
assertNotCompacted();
|
||
|
final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_BOOL);
|
||
|
|
||
|
writeBoolImpl(id, val);
|
||
|
}
|
||
|
|
||
|
private void writeBoolImpl(int id, boolean val) {
|
||
|
if (val) {
|
||
|
writeTag(id, WIRE_TYPE_VARINT);
|
||
|
// 0 and 1 are the same as their varint counterparts
|
||
|
mBuffer.writeRawByte((byte)1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Write a single repeated proto "bool" type field value.
|
||
|
*
|
||
|
* @deprecated Use {@link #write(long, boolean)} instead.
|
||
|
* @hide
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public void writeRepeatedBool(long fieldId, boolean val) {
|
||
|
assertNotCompacted();
|
||
|
final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_BOOL);
|
||
|
|
||
|
writeRepeatedBoolImpl(id, val);
|
||
|
}
|
||
|
|
||
|
private void writeRepeatedBoolImpl(int id, boolean val) {
|
||
|
writeTag(id, WIRE_TYPE_VARINT);
|
||
|
mBuffer.writeRawByte((byte)(val ? 1 : 0));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Write a list of packed proto "bool" type field value.
|
||
|
*
|
||
|
* @deprecated Use {@link #write(long, boolean)} instead.
|
||
|
* @hide
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public void writePackedBool(long fieldId, @Nullable boolean[] val) {
|
||
|
assertNotCompacted();
|
||
|
final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_BOOL);
|
||
|
|
||
|
final int N = val != null ? val.length : 0;
|
||
|
if (N > 0) {
|
||
|
// Write the header
|
||
|
writeKnownLengthHeader(id, N);
|
||
|
|
||
|
// Write the data
|
||
|
for (int i=0; i<N; i++) {
|
||
|
// 0 and 1 are the same as their varint counterparts
|
||
|
mBuffer.writeRawByte((byte)(val[i] ? 1 : 0));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// proto3 type: string
|
||
|
// java type: String
|
||
|
// encoding: utf-8
|
||
|
// wire type: WIRE_TYPE_LENGTH_DELIMITED
|
||
|
//
|
||
|
|
||
|
/**
|
||
|
* Write a single proto "string" type field value.
|
||
|
*
|
||
|
* @deprecated Use {@link #write(long, String)} instead.
|
||
|
* @hide
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public void writeString(long fieldId, @Nullable String val) {
|
||
|
assertNotCompacted();
|
||
|
final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_STRING);
|
||
|
|
||
|
writeStringImpl(id, val);
|
||
|
}
|
||
|
|
||
|
private void writeStringImpl(int id, String val) {
|
||
|
if (val != null && val.length() > 0) {
|
||
|
writeUtf8String(id, val);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Write a single repeated proto "string" type field value.
|
||
|
*
|
||
|
* @deprecated Use {@link #write(long, String)} instead.
|
||
|
* @hide
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public void writeRepeatedString(long fieldId, @Nullable String val) {
|
||
|
assertNotCompacted();
|
||
|
final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_STRING);
|
||
|
|
||
|
writeRepeatedStringImpl(id, val);
|
||
|
}
|
||
|
|
||
|
private void writeRepeatedStringImpl(int id, String val) {
|
||
|
if (val == null || val.length() == 0) {
|
||
|
writeKnownLengthHeader(id, 0);
|
||
|
} else {
|
||
|
writeUtf8String(id, val);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Write a list of packed proto "string" type field value.
|
||
|
*/
|
||
|
private void writeUtf8String(int id, String val) {
|
||
|
// TODO: Is it worth converting by hand in order to not allocate?
|
||
|
try {
|
||
|
final byte[] buf = val.getBytes("UTF-8");
|
||
|
writeKnownLengthHeader(id, buf.length);
|
||
|
mBuffer.writeRawBuffer(buf);
|
||
|
} catch (UnsupportedEncodingException ex) {
|
||
|
throw new RuntimeException("not possible");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// proto3 type: bytes
|
||
|
// java type: byte[]
|
||
|
// encoding: varint
|
||
|
// wire type: WIRE_TYPE_VARINT
|
||
|
//
|
||
|
|
||
|
/**
|
||
|
* Write a single proto "bytes" type field value.
|
||
|
*
|
||
|
* @deprecated Use {@link #write(long, byte[])} instead.
|
||
|
* @hide
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public void writeBytes(long fieldId, @Nullable byte[] val) {
|
||
|
assertNotCompacted();
|
||
|
final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_BYTES);
|
||
|
|
||
|
writeBytesImpl(id, val);
|
||
|
}
|
||
|
|
||
|
private void writeBytesImpl(int id, byte[] val) {
|
||
|
if (val != null && val.length > 0) {
|
||
|
writeKnownLengthHeader(id, val.length);
|
||
|
mBuffer.writeRawBuffer(val);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Write a single repeated proto "bytes" type field value.
|
||
|
*
|
||
|
* @deprecated Use {@link #write(long, byte[])} instead.
|
||
|
* @hide
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public void writeRepeatedBytes(long fieldId, @Nullable byte[] val) {
|
||
|
assertNotCompacted();
|
||
|
final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_BYTES);
|
||
|
|
||
|
writeRepeatedBytesImpl(id, val);
|
||
|
}
|
||
|
|
||
|
private void writeRepeatedBytesImpl(int id, byte[] val) {
|
||
|
writeKnownLengthHeader(id, val == null ? 0 : val.length);
|
||
|
mBuffer.writeRawBuffer(val);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// proto3 type: enum
|
||
|
// java type: int
|
||
|
// signed/unsigned: unsigned
|
||
|
// encoding: varint
|
||
|
// wire type: WIRE_TYPE_VARINT
|
||
|
//
|
||
|
|
||
|
/**
|
||
|
* Write a single proto enum type field value.
|
||
|
*
|
||
|
* @deprecated Use {@link #write(long, int)} instead.
|
||
|
* @hide
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public void writeEnum(long fieldId, int val) {
|
||
|
assertNotCompacted();
|
||
|
final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_ENUM);
|
||
|
|
||
|
writeEnumImpl(id, val);
|
||
|
}
|
||
|
|
||
|
private void writeEnumImpl(int id, int val) {
|
||
|
if (val != 0) {
|
||
|
writeTag(id, WIRE_TYPE_VARINT);
|
||
|
writeUnsignedVarintFromSignedInt(val);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Write a single repeated proto enum type field value.
|
||
|
*
|
||
|
* @deprecated Use {@link #write(long, int)} instead.
|
||
|
* @hide
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public void writeRepeatedEnum(long fieldId, int val) {
|
||
|
assertNotCompacted();
|
||
|
final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_ENUM);
|
||
|
|
||
|
writeRepeatedEnumImpl(id, val);
|
||
|
}
|
||
|
|
||
|
private void writeRepeatedEnumImpl(int id, int val) {
|
||
|
writeTag(id, WIRE_TYPE_VARINT);
|
||
|
writeUnsignedVarintFromSignedInt(val);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Write a list of packed proto enum type field value.
|
||
|
*
|
||
|
* @deprecated Use {@link #write(long, int)} instead.
|
||
|
* @hide
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public void writePackedEnum(long fieldId, @Nullable int[] val) {
|
||
|
assertNotCompacted();
|
||
|
final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_ENUM);
|
||
|
|
||
|
final int N = val != null ? val.length : 0;
|
||
|
if (N > 0) {
|
||
|
int size = 0;
|
||
|
for (int i=0; i<N; i++) {
|
||
|
final int v = val[i];
|
||
|
size += v >= 0 ? EncodedBuffer.getRawVarint32Size(v) : 10;
|
||
|
}
|
||
|
writeKnownLengthHeader(id, size);
|
||
|
for (int i=0; i<N; i++) {
|
||
|
writeUnsignedVarintFromSignedInt(val[i]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Start a child object.
|
||
|
*
|
||
|
* Returns a token which should be passed to endObject. Calls to endObject must be
|
||
|
* nested properly.
|
||
|
*
|
||
|
* @deprecated Use {@link #start(long)} instead.
|
||
|
* @hide
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public long startObject(long fieldId) {
|
||
|
assertNotCompacted();
|
||
|
final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_MESSAGE);
|
||
|
|
||
|
return startObjectImpl(id, false);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* End a child object. Pass in the token from the correspoinding startObject call.
|
||
|
*
|
||
|
* @deprecated Use {@link #end(long)} instead.
|
||
|
* @hide
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public void endObject(long token) {
|
||
|
assertNotCompacted();
|
||
|
|
||
|
endObjectImpl(token, false);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Start a repeated child object.
|
||
|
*
|
||
|
* Returns a token which should be passed to endObject. Calls to endObject must be
|
||
|
* nested properly.
|
||
|
*
|
||
|
* @deprecated Use {@link #start(long)} instead.
|
||
|
* @hide
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public long startRepeatedObject(long fieldId) {
|
||
|
assertNotCompacted();
|
||
|
final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_MESSAGE);
|
||
|
|
||
|
return startObjectImpl(id, true);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* End a child object. Pass in the token from the correspoinding startRepeatedObject call.
|
||
|
*
|
||
|
* @deprecated Use {@link #end(long)} instead.
|
||
|
* @hide
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public void endRepeatedObject(long token) {
|
||
|
assertNotCompacted();
|
||
|
|
||
|
endObjectImpl(token, true);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Common implementation of startObject and startRepeatedObject.
|
||
|
*/
|
||
|
private long startObjectImpl(final int id, boolean repeated) {
|
||
|
writeTag(id, WIRE_TYPE_LENGTH_DELIMITED);
|
||
|
final int sizePos = mBuffer.getWritePos();
|
||
|
mDepth++;
|
||
|
mNextObjectId--;
|
||
|
|
||
|
// Write the previous token, giving us a stack of expected tokens.
|
||
|
// After endObject returns, the first fixed32 becomeschildRawSize (set in endObject)
|
||
|
// and the second one becomes childEncodedSize (set in editEncodedSize).
|
||
|
mBuffer.writeRawFixed32((int)(mExpectedObjectToken >> 32));
|
||
|
mBuffer.writeRawFixed32((int)mExpectedObjectToken);
|
||
|
|
||
|
long old = mExpectedObjectToken;
|
||
|
|
||
|
mExpectedObjectToken = makeToken(getTagSize(id), repeated, mDepth, mNextObjectId, sizePos);
|
||
|
return mExpectedObjectToken;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Common implementation of endObject and endRepeatedObject.
|
||
|
*/
|
||
|
private void endObjectImpl(long token, boolean repeated) {
|
||
|
// The upper 32 bits of the token is the depth of startObject /
|
||
|
// endObject calls. We could get aritrarily sophisticated, but
|
||
|
// that's enough to prevent the common error of missing an
|
||
|
// endObject somewhere.
|
||
|
// The lower 32 bits of the token is the offset in the buffer
|
||
|
// at which to write the size.
|
||
|
final int depth = getDepthFromToken(token);
|
||
|
final boolean expectedRepeated = getRepeatedFromToken(token);
|
||
|
final int sizePos = getOffsetFromToken(token);
|
||
|
final int childRawSize = mBuffer.getWritePos() - sizePos - 8;
|
||
|
|
||
|
if (repeated != expectedRepeated) {
|
||
|
if (repeated) {
|
||
|
throw new IllegalArgumentException("endRepeatedObject called where endObject should"
|
||
|
+ " have been");
|
||
|
} else {
|
||
|
throw new IllegalArgumentException("endObject called where endRepeatedObject should"
|
||
|
+ " have been");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Check that we're getting the token and depth that we are expecting.
|
||
|
if ((mDepth & 0x01ff) != depth || mExpectedObjectToken != token) {
|
||
|
// This text of exception is united tested. That test also implicity checks
|
||
|
// that we're tracking the objectIds and depths correctly.
|
||
|
throw new IllegalArgumentException("Mismatched startObject/endObject calls."
|
||
|
+ " Current depth " + mDepth
|
||
|
+ " token=" + token2String(token)
|
||
|
+ " expectedToken=" + token2String(mExpectedObjectToken));
|
||
|
}
|
||
|
|
||
|
// Get the next expected token that we stashed away in the buffer.
|
||
|
mExpectedObjectToken = (((long)mBuffer.getRawFixed32At(sizePos)) << 32)
|
||
|
| (0x0ffffffffL & (long)mBuffer.getRawFixed32At(sizePos+4));
|
||
|
|
||
|
mDepth--;
|
||
|
if (childRawSize > 0) {
|
||
|
mBuffer.editRawFixed32(sizePos, -childRawSize);
|
||
|
mBuffer.editRawFixed32(sizePos+4, -1);
|
||
|
} else if (repeated) {
|
||
|
mBuffer.editRawFixed32(sizePos, 0);
|
||
|
mBuffer.editRawFixed32(sizePos+4, 0);
|
||
|
} else {
|
||
|
// The object has no data. Don't include it.
|
||
|
mBuffer.rewindWriteTo(sizePos - getTagSizeFromToken(token));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Write an object that has already been flattened.
|
||
|
*
|
||
|
* @deprecated Use {@link #write(long, byte[])} instead.
|
||
|
* @hide
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public void writeObject(long fieldId, @Nullable byte[] value) {
|
||
|
assertNotCompacted();
|
||
|
final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_MESSAGE);
|
||
|
|
||
|
writeObjectImpl(id, value);
|
||
|
}
|
||
|
|
||
|
void writeObjectImpl(int id, byte[] value) {
|
||
|
if (value != null && value.length != 0) {
|
||
|
writeKnownLengthHeader(id, value.length);
|
||
|
mBuffer.writeRawBuffer(value);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Write an object that has already been flattened.
|
||
|
*
|
||
|
* @deprecated Use {@link #write(long, byte[])} instead.
|
||
|
* @hide
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public void writeRepeatedObject(long fieldId, @Nullable byte[] value) {
|
||
|
assertNotCompacted();
|
||
|
final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_MESSAGE);
|
||
|
|
||
|
writeRepeatedObjectImpl(id, value);
|
||
|
}
|
||
|
|
||
|
void writeRepeatedObjectImpl(int id, byte[] value) {
|
||
|
writeKnownLengthHeader(id, value == null ? 0 : value.length);
|
||
|
mBuffer.writeRawBuffer(value);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Tags
|
||
|
//
|
||
|
|
||
|
/**
|
||
|
* Combine a fieldId (the field keys in the proto file) and the field flags.
|
||
|
* Mostly useful for testing because the generated code contains the fieldId
|
||
|
* constants.
|
||
|
*/
|
||
|
public static long makeFieldId(int id, long fieldFlags) {
|
||
|
return fieldFlags | (((long)id) & 0x0ffffffffL);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Validates that the fieldId provided is of the type and count from expectedType.
|
||
|
*
|
||
|
* <p>The type must match exactly to pass this check.
|
||
|
*
|
||
|
* <p>The count must match according to this truth table to pass the check:
|
||
|
*
|
||
|
* expectedFlags
|
||
|
* UNKNOWN SINGLE REPEATED PACKED
|
||
|
* fieldId
|
||
|
* UNKNOWN true false false false
|
||
|
* SINGLE x true false false
|
||
|
* REPEATED x false true false
|
||
|
* PACKED x false true true
|
||
|
*
|
||
|
* @throws {@link IllegalArgumentException} if it is not.
|
||
|
*
|
||
|
* @return The raw ID of that field.
|
||
|
*/
|
||
|
public static int checkFieldId(long fieldId, long expectedFlags) {
|
||
|
final long fieldCount = fieldId & FIELD_COUNT_MASK;
|
||
|
final long fieldType = fieldId & FIELD_TYPE_MASK;
|
||
|
final long expectedCount = expectedFlags & FIELD_COUNT_MASK;
|
||
|
final long expectedType = expectedFlags & FIELD_TYPE_MASK;
|
||
|
if (((int)fieldId) == 0) {
|
||
|
throw new IllegalArgumentException("Invalid proto field " + (int)fieldId
|
||
|
+ " fieldId=" + Long.toHexString(fieldId));
|
||
|
}
|
||
|
if (fieldType != expectedType
|
||
|
|| !((fieldCount == expectedCount)
|
||
|
|| (fieldCount == FIELD_COUNT_PACKED
|
||
|
&& expectedCount == FIELD_COUNT_REPEATED))) {
|
||
|
final String countString = getFieldCountString(fieldCount);
|
||
|
final String typeString = getFieldTypeString(fieldType);
|
||
|
if (typeString != null && countString != null) {
|
||
|
final StringBuilder sb = new StringBuilder();
|
||
|
if (expectedType == FIELD_TYPE_MESSAGE) {
|
||
|
sb.append("start");
|
||
|
} else {
|
||
|
sb.append("write");
|
||
|
}
|
||
|
sb.append(getFieldCountString(expectedCount));
|
||
|
sb.append(getFieldTypeString(expectedType));
|
||
|
sb.append(" called for field ");
|
||
|
sb.append((int)fieldId);
|
||
|
sb.append(" which should be used with ");
|
||
|
if (fieldType == FIELD_TYPE_MESSAGE) {
|
||
|
sb.append("start");
|
||
|
} else {
|
||
|
sb.append("write");
|
||
|
}
|
||
|
sb.append(countString);
|
||
|
sb.append(typeString);
|
||
|
if (fieldCount == FIELD_COUNT_PACKED) {
|
||
|
sb.append(" or writeRepeated");
|
||
|
sb.append(typeString);
|
||
|
}
|
||
|
sb.append('.');
|
||
|
throw new IllegalArgumentException(sb.toString());
|
||
|
} else {
|
||
|
final StringBuilder sb = new StringBuilder();
|
||
|
if (expectedType == FIELD_TYPE_MESSAGE) {
|
||
|
sb.append("start");
|
||
|
} else {
|
||
|
sb.append("write");
|
||
|
}
|
||
|
sb.append(getFieldCountString(expectedCount));
|
||
|
sb.append(getFieldTypeString(expectedType));
|
||
|
sb.append(" called with an invalid fieldId: 0x");
|
||
|
sb.append(Long.toHexString(fieldId));
|
||
|
sb.append(". The proto field ID might be ");
|
||
|
sb.append((int)fieldId);
|
||
|
sb.append('.');
|
||
|
throw new IllegalArgumentException(sb.toString());
|
||
|
}
|
||
|
}
|
||
|
return (int)fieldId;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Return how many bytes an encoded field tag will require.
|
||
|
*/
|
||
|
private static int getTagSize(int id) {
|
||
|
return EncodedBuffer.getRawVarint32Size(id << FIELD_ID_SHIFT);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Write an individual field tag by hand.
|
||
|
*
|
||
|
* See <a href="https://developers.google.com/protocol-buffers/docs/encoding">Protobuf
|
||
|
* Encoding</a> for details on the structure of how tags and data are written.
|
||
|
*/
|
||
|
public void writeTag(int id, @WireType int wireType) {
|
||
|
mBuffer.writeRawVarint32((id << FIELD_ID_SHIFT) | wireType);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Write the header of a WIRE_TYPE_LENGTH_DELIMITED field for one where
|
||
|
* we know the size in advance and do not need to compute and compact.
|
||
|
*/
|
||
|
private void writeKnownLengthHeader(int id, int size) {
|
||
|
// Write the tag
|
||
|
writeTag(id, WIRE_TYPE_LENGTH_DELIMITED);
|
||
|
// Size will be compacted later, but we know the size, so write it,
|
||
|
// once for the rawSize and once for the encodedSize.
|
||
|
mBuffer.writeRawFixed32(size);
|
||
|
mBuffer.writeRawFixed32(size);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Getting the buffer and compaction
|
||
|
//
|
||
|
|
||
|
/**
|
||
|
* Assert that the compact call has not already occured.
|
||
|
*
|
||
|
* TODO: Will change when we add the OutputStream version of ProtoOutputStream.
|
||
|
*/
|
||
|
private void assertNotCompacted() {
|
||
|
if (mCompacted) {
|
||
|
throw new IllegalArgumentException("write called after compact");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Finish the encoding of the data, and return a byte[] with
|
||
|
* the protobuf formatted data.
|
||
|
*
|
||
|
* <p>After this call, do not call any of the write* functions. The
|
||
|
* behavior is undefined.
|
||
|
*/
|
||
|
public @NonNull byte[] getBytes() {
|
||
|
compactIfNecessary();
|
||
|
|
||
|
return mBuffer.getBytes(mBuffer.getReadableSize());
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* If the buffer hasn't already had the nested object size fields compacted
|
||
|
* and turned into an actual protobuf format, then do so.
|
||
|
*/
|
||
|
private void compactIfNecessary() {
|
||
|
if (!mCompacted) {
|
||
|
if (mDepth != 0) {
|
||
|
throw new IllegalArgumentException("Trying to compact with " + mDepth
|
||
|
+ " missing calls to endObject");
|
||
|
}
|
||
|
|
||
|
// The buffer must be compacted.
|
||
|
mBuffer.startEditing();
|
||
|
final int readableSize = mBuffer.getReadableSize();
|
||
|
|
||
|
// Cache the sizes of the objects
|
||
|
editEncodedSize(readableSize);
|
||
|
|
||
|
// Re-write the buffer with the sizes as proper varints instead
|
||
|
// of pairs of uint32s. We know this will always fit in the same
|
||
|
// buffer because the pair of uint32s is exactly 8 bytes long, and
|
||
|
// the single varint size will be no more than 5 bytes long.
|
||
|
mBuffer.rewindRead();
|
||
|
compactSizes(readableSize);
|
||
|
|
||
|
// If there is any data left over that wasn't copied yet, copy it.
|
||
|
if (mCopyBegin < readableSize) {
|
||
|
mBuffer.writeFromThisBuffer(mCopyBegin, readableSize - mCopyBegin);
|
||
|
}
|
||
|
|
||
|
// Set the new readableSize
|
||
|
mBuffer.startEditing();
|
||
|
|
||
|
// It's not valid to write to this object anymore. The write
|
||
|
// pointers are off, and then some of the data would be compacted
|
||
|
// and some not.
|
||
|
mCompacted = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* First compaction pass. Iterate through the data, and fill in the
|
||
|
* nested object sizes so the next pass can compact them.
|
||
|
*/
|
||
|
private int editEncodedSize(int rawSize) {
|
||
|
int objectStart = mBuffer.getReadPos();
|
||
|
int objectEnd = objectStart + rawSize;
|
||
|
int encodedSize = 0;
|
||
|
int tagPos;
|
||
|
|
||
|
while ((tagPos = mBuffer.getReadPos()) < objectEnd) {
|
||
|
int tag = readRawTag();
|
||
|
encodedSize += EncodedBuffer.getRawVarint32Size(tag);
|
||
|
|
||
|
final int wireType = tag & WIRE_TYPE_MASK;
|
||
|
switch (wireType) {
|
||
|
case WIRE_TYPE_VARINT:
|
||
|
encodedSize++;
|
||
|
while ((mBuffer.readRawByte() & 0x80) != 0) {
|
||
|
encodedSize++;
|
||
|
}
|
||
|
break;
|
||
|
case WIRE_TYPE_FIXED64:
|
||
|
encodedSize += 8;
|
||
|
mBuffer.skipRead(8);
|
||
|
break;
|
||
|
case WIRE_TYPE_LENGTH_DELIMITED: {
|
||
|
// This object is not of a fixed-size type. So we need to figure
|
||
|
// out how big it should be.
|
||
|
final int childRawSize = mBuffer.readRawFixed32();
|
||
|
final int childEncodedSizePos = mBuffer.getReadPos();
|
||
|
int childEncodedSize = mBuffer.readRawFixed32();
|
||
|
if (childRawSize >= 0) {
|
||
|
// We know the size, just skip ahead.
|
||
|
if (childEncodedSize != childRawSize) {
|
||
|
throw new RuntimeException("Pre-computed size where the"
|
||
|
+ " precomputed size and the raw size in the buffer"
|
||
|
+ " don't match! childRawSize=" + childRawSize
|
||
|
+ " childEncodedSize=" + childEncodedSize
|
||
|
+ " childEncodedSizePos=" + childEncodedSizePos);
|
||
|
}
|
||
|
mBuffer.skipRead(childRawSize);
|
||
|
} else {
|
||
|
// We need to compute the size. Recurse.
|
||
|
childEncodedSize = editEncodedSize(-childRawSize);
|
||
|
mBuffer.editRawFixed32(childEncodedSizePos, childEncodedSize);
|
||
|
}
|
||
|
encodedSize += EncodedBuffer.getRawVarint32Size(childEncodedSize)
|
||
|
+ childEncodedSize;
|
||
|
break;
|
||
|
}
|
||
|
case WIRE_TYPE_START_GROUP:
|
||
|
case WIRE_TYPE_END_GROUP:
|
||
|
throw new RuntimeException("groups not supported at index " + tagPos);
|
||
|
case WIRE_TYPE_FIXED32:
|
||
|
encodedSize += 4;
|
||
|
mBuffer.skipRead(4);
|
||
|
break;
|
||
|
default:
|
||
|
throw new ProtoParseException("editEncodedSize Bad tag tag=0x"
|
||
|
+ Integer.toHexString(tag) + " wireType=" + wireType
|
||
|
+ " -- " + mBuffer.getDebugString());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return encodedSize;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Second compaction pass. Iterate through the data, and copy the data
|
||
|
* forward in the buffer, converting the pairs of uint32s into a single
|
||
|
* unsigned varint of the size.
|
||
|
*/
|
||
|
private void compactSizes(int rawSize) {
|
||
|
int objectStart = mBuffer.getReadPos();
|
||
|
int objectEnd = objectStart + rawSize;
|
||
|
int tagPos;
|
||
|
while ((tagPos = mBuffer.getReadPos()) < objectEnd) {
|
||
|
int tag = readRawTag();
|
||
|
|
||
|
// For all the non-length-delimited field types, just skip over them,
|
||
|
// and we'll just System.arraycopy it later, either in the case for
|
||
|
// WIRE_TYPE_LENGTH_DELIMITED or at the top of the stack in compactIfNecessary().
|
||
|
final int wireType = tag & WIRE_TYPE_MASK;
|
||
|
switch (wireType) {
|
||
|
case WIRE_TYPE_VARINT:
|
||
|
while ((mBuffer.readRawByte() & 0x80) != 0) { }
|
||
|
break;
|
||
|
case WIRE_TYPE_FIXED64:
|
||
|
mBuffer.skipRead(8);
|
||
|
break;
|
||
|
case WIRE_TYPE_LENGTH_DELIMITED: {
|
||
|
// Copy everything up to now, including the tag for this field.
|
||
|
mBuffer.writeFromThisBuffer(mCopyBegin, mBuffer.getReadPos() - mCopyBegin);
|
||
|
// Write the new size.
|
||
|
final int childRawSize = mBuffer.readRawFixed32();
|
||
|
final int childEncodedSize = mBuffer.readRawFixed32();
|
||
|
mBuffer.writeRawVarint32(childEncodedSize);
|
||
|
// Next time, start copying from here.
|
||
|
mCopyBegin = mBuffer.getReadPos();
|
||
|
if (childRawSize >= 0) {
|
||
|
// This is raw data, not an object. Skip ahead by the size.
|
||
|
// Recurse into the child
|
||
|
mBuffer.skipRead(childEncodedSize);
|
||
|
} else {
|
||
|
compactSizes(-childRawSize);
|
||
|
}
|
||
|
break;
|
||
|
// TODO: What does regular proto do if the object would be 0 size
|
||
|
// (e.g. if it is all default values).
|
||
|
}
|
||
|
case WIRE_TYPE_START_GROUP:
|
||
|
case WIRE_TYPE_END_GROUP:
|
||
|
throw new RuntimeException("groups not supported at index " + tagPos);
|
||
|
case WIRE_TYPE_FIXED32:
|
||
|
mBuffer.skipRead(4);
|
||
|
break;
|
||
|
default:
|
||
|
throw new ProtoParseException("compactSizes Bad tag tag=0x"
|
||
|
+ Integer.toHexString(tag) + " wireType=" + wireType
|
||
|
+ " -- " + mBuffer.getDebugString());
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Write remaining data to the output stream. If there is no output stream,
|
||
|
* this function does nothing. Any currently open objects (i.e. ones that
|
||
|
* have not had {@link #end(long)} called for them will not be written). Whether this
|
||
|
* writes objects that are closed if there are remaining open objects is
|
||
|
* undefined (current implementation does not write it, future ones will).
|
||
|
* For now, can either call {@link #getBytes()} or {@link #flush()}, but not both.
|
||
|
*/
|
||
|
public void flush() {
|
||
|
if (mStream == null) {
|
||
|
return;
|
||
|
}
|
||
|
if (mDepth != 0) {
|
||
|
// TODO: The compacting code isn't ready yet to compact unless we're done.
|
||
|
// TODO: Fix that.
|
||
|
return;
|
||
|
}
|
||
|
if (mCompacted) {
|
||
|
// If we're compacted, we already wrote it finished.
|
||
|
return;
|
||
|
}
|
||
|
compactIfNecessary();
|
||
|
final byte[] data = mBuffer.getBytes(mBuffer.getReadableSize());
|
||
|
try {
|
||
|
mStream.write(data);
|
||
|
mStream.flush();
|
||
|
} catch (IOException ex) {
|
||
|
throw new RuntimeException("Error flushing proto to stream", ex);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Read a raw tag from the buffer.
|
||
|
*/
|
||
|
private int readRawTag() {
|
||
|
if (mBuffer.getReadPos() == mBuffer.getReadableSize()) {
|
||
|
return 0;
|
||
|
}
|
||
|
return (int)mBuffer.readRawUnsigned();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Dump debugging data about the buffers with the given log tag.
|
||
|
*/
|
||
|
public void dump(@NonNull String tag) {
|
||
|
Log.d(tag, mBuffer.getDebugString());
|
||
|
mBuffer.dumpBuffers(tag);
|
||
|
}
|
||
|
}
|