From fb9f736a3c6c2e1c91c69b1abc0456b54215e8ef Mon Sep 17 00:00:00 2001 From: Joe Onorato Date: Fri, 28 Oct 2016 13:07:43 -0700 Subject: ProtoOutputStream convenience methods. - Add a set of write methods to ProtoOutputStream that figure out the type. The other methods are doing all the type checking anyway, so this won't be much slower, and it's way easier to use. The expected java type casts that people would do anyway happen inside. - Add writeObject and writeRepeatedObject methods that write a pre-encoded object. - Add a constructor that takes an OutputStream, and a flush() method. Right now, all the data gets flushed at the end, but given this API it would be possible to write smaller chunks at the object boundaries and do more sophisticated buffering. Test: CTS Change-Id: Ieb852092d3d65812c81139558151de9e3f467dc8 --- api/test-current.txt | 16 + .../java/android/util/proto/ProtoOutputStream.java | 903 +++++++++++++++++++++ 2 files changed, 919 insertions(+) diff --git a/api/test-current.txt b/api/test-current.txt index 9cd08d549863..2bf6e04b312b 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -41525,11 +41525,15 @@ package android.util.proto { public final class ProtoOutputStream { ctor public ProtoOutputStream(); ctor public ProtoOutputStream(int); + ctor public ProtoOutputStream(java.io.OutputStream); + ctor public ProtoOutputStream(java.io.FileDescriptor); method public static int checkFieldId(long, long); method public static int convertObjectIdToOrdinal(int); method public void dump(java.lang.String); + method public void end(long); method public void endObject(long); method public void endRepeatedObject(long); + method public void flush(); method public byte[] getBytes(); method public static int getDepthFromToken(long); method public static int getObjectIdFromToken(long); @@ -41538,9 +41542,17 @@ package android.util.proto { method public static int getTagSizeFromToken(long); method public static long makeFieldId(int, long); method public static long makeToken(int, boolean, int, int, int); + method public long start(long); method public long startObject(long); method public long startRepeatedObject(long); method public static java.lang.String token2String(long); + method public void write(long, double); + method public void write(long, float); + method public void write(long, int); + method public void write(long, long); + method public void write(long, boolean); + method public void write(long, java.lang.String); + method public void write(long, byte[]); method public void writeBool(long, boolean); method public void writeBytes(long, byte[]); method public void writeDouble(long, double); @@ -41550,6 +41562,8 @@ package android.util.proto { method public void writeFloat(long, float); method public void writeInt32(long, int); method public void writeInt64(long, long); + method public void writeObject(long, byte[]); + method public void writeObjectImpl(int, byte[]); method public void writePackedBool(long, boolean[]); method public void writePackedDouble(long, double[]); method public void writePackedEnum(long, int[]); @@ -41573,6 +41587,8 @@ package android.util.proto { method public void writeRepeatedFloat(long, float); method public void writeRepeatedInt32(long, int); method public void writeRepeatedInt64(long, long); + method public void writeRepeatedObject(long, byte[]); + method public void writeRepeatedObjectImpl(int, byte[]); method public void writeRepeatedSFixed32(long, int); method public void writeRepeatedSFixed64(long, long); method public void writeRepeatedSInt32(long, int); diff --git a/core/java/android/util/proto/ProtoOutputStream.java b/core/java/android/util/proto/ProtoOutputStream.java index 8f99399cc155..81251fc2fd66 100644 --- a/core/java/android/util/proto/ProtoOutputStream.java +++ b/core/java/android/util/proto/ProtoOutputStream.java @@ -19,6 +19,10 @@ package android.util.proto; import android.annotation.TestApi; import android.util.Log; +import java.io.FileDescriptor; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.util.List; @@ -178,6 +182,11 @@ public final class ProtoOutputStream { */ private EncodedBuffer mBuffer; + /** + * Our stream. If there is one. + */ + private OutputStream mStream; + /** * Current nesting depth of startObject calls. */ @@ -226,6 +235,690 @@ public final class ProtoOutputStream { mBuffer = new EncodedBuffer(chunkSize); } + /** + * Construct a ProtoOutputStream that sits on top of an OutputStream. + * @more + * The {@link #flush() flush()} method must be called when done writing + * to flush any remanining data, althought data *may* be written at intermediate + * points within the writing as well. + */ + public ProtoOutputStream(OutputStream stream) { + this(); + mStream = stream; + } + + /** + * Construct a ProtoOutputStream that sits on top of a FileDescriptor. + * @more + * The {@link #flush() flush()} method must be called when done writing + * to flush any remanining data, althought data *may* be written at intermediate + * points within the writing as well. + */ + public ProtoOutputStream(FileDescriptor fd) { + this(new FileOutputStream(fd)); + } + + /** + * Write a value for the given fieldId. + * + * 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. + * + * 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. + * + * 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. + * + * 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. + * + * If the field is not a bool 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, 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. + * + * 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, 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. + * + * 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, 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_OBJECT | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT): + writeObjectImpl(id, val); + break; + case (int)((FIELD_TYPE_OBJECT | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT): + case (int)((FIELD_TYPE_OBJECT | 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. + */ + public long start(long fieldId) { + assertNotCompacted(); + final int id = (int)fieldId; + + if ((fieldId & FIELD_TYPE_MASK) == FIELD_TYPE_OBJECT) { + 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. + */ + public void end(long token) { + endObjectImpl(token, getRepeatedFromToken(token)); + } + // // proto3 type: double // java type: double @@ -240,6 +933,10 @@ public final class ProtoOutputStream { 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)); @@ -253,6 +950,10 @@ public final class ProtoOutputStream { 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)); } @@ -287,6 +988,10 @@ public final class ProtoOutputStream { 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)); @@ -300,6 +1005,10 @@ public final class ProtoOutputStream { 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)); } @@ -357,6 +1066,10 @@ public final class ProtoOutputStream { 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); @@ -374,6 +1087,10 @@ public final class ProtoOutputStream { 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); } @@ -418,6 +1135,10 @@ public final class ProtoOutputStream { 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); @@ -431,6 +1152,10 @@ public final class ProtoOutputStream { 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); } @@ -470,6 +1195,10 @@ public final class ProtoOutputStream { 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); @@ -483,6 +1212,10 @@ public final class ProtoOutputStream { 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); } @@ -522,6 +1255,10 @@ public final class ProtoOutputStream { 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); @@ -535,6 +1272,10 @@ public final class ProtoOutputStream { 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); } @@ -574,6 +1315,10 @@ public final class ProtoOutputStream { 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); @@ -587,6 +1332,10 @@ public final class ProtoOutputStream { 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); } @@ -626,6 +1375,10 @@ public final class ProtoOutputStream { 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); @@ -639,6 +1392,10 @@ public final class ProtoOutputStream { 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); } @@ -677,6 +1434,10 @@ public final class ProtoOutputStream { 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); @@ -690,6 +1451,10 @@ public final class ProtoOutputStream { 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); } @@ -724,6 +1489,10 @@ public final class ProtoOutputStream { 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); @@ -737,6 +1506,10 @@ public final class ProtoOutputStream { assertNotCompacted(); final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_FIXED64); + writeRepeatedFixed64(id, val); + } + + private void writeRepeatedFixed64Impl(int id, long val) { writeTag(id, WIRE_TYPE_FIXED64); mBuffer.writeRawFixed64(val); } @@ -770,6 +1543,10 @@ public final class ProtoOutputStream { 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); @@ -783,6 +1560,10 @@ public final class ProtoOutputStream { 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); } @@ -817,6 +1598,10 @@ public final class ProtoOutputStream { 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); @@ -830,6 +1615,10 @@ public final class ProtoOutputStream { assertNotCompacted(); final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_SFIXED64); + writeRepeatedSFixed64(id, val); + } + + private void writeRepeatedSFixed64Impl(int id, long val) { writeTag(id, WIRE_TYPE_FIXED64); mBuffer.writeRawFixed64(val); } @@ -864,6 +1653,10 @@ public final class ProtoOutputStream { 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 @@ -878,6 +1671,10 @@ public final class ProtoOutputStream { assertNotCompacted(); final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_BOOL); + writeRepeatedBool(id, val); + } + + private void writeRepeatedBoolImpl(int id, boolean val) { writeTag(id, WIRE_TYPE_VARINT); mBuffer.writeRawByte((byte)(val ? 1 : 0)); } @@ -916,6 +1713,10 @@ public final class ProtoOutputStream { 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); } @@ -928,6 +1729,10 @@ public final class ProtoOutputStream { 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 { @@ -963,6 +1768,10 @@ public final class ProtoOutputStream { 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); @@ -976,6 +1785,10 @@ public final class ProtoOutputStream { 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); } @@ -995,6 +1808,10 @@ public final class ProtoOutputStream { 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); @@ -1008,6 +1825,10 @@ public final class ProtoOutputStream { 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); } @@ -1239,6 +2060,38 @@ public final class ProtoOutputStream { } } + /** + * Write an object that has already been flattend. + */ + public void writeObject(long fieldId, byte[] value) { + assertNotCompacted(); + final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_OBJECT); + + writeObjectImpl(id, value); + } + + public 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 flattend. + */ + public void writeRepeatedObject(long fieldId, byte[] value) { + assertNotCompacted(); + final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_OBJECT); + + writeRepeatedObjectImpl(id, value); + } + + public void writeRepeatedObjectImpl(int id, byte[] value) { + writeKnownLengthHeader(id, value == null ? 0 : value.length); + mBuffer.writeRawBuffer(value); + } + // // Tags // @@ -1358,6 +2211,25 @@ public final class ProtoOutputStream { } } + /** + * Get a debug string for a fieldId. + */ + private String getFieldIdString(long fieldId) { + final long fieldCount = fieldId & FIELD_COUNT_MASK; + String countString = getFieldCountString(fieldCount); + if (countString == null) { + countString = "fieldCount=" + fieldCount; + } + + final long fieldType = fieldId & FIELD_TYPE_MASK; + String typeString = getFieldTypeString(fieldType); + if (typeString == null) { + typeString = "fieldType=" + fieldType; + } + + return fieldCount + " " + typeString + " tag=" + ((int)fieldId) + + " fieldId=0x" + Long.toHexString(fieldId); + } /** * Return how many bytes an encoded field tag will require. @@ -1579,6 +2451,37 @@ public final class ProtoOutputStream { } } + /** + * 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 endObject 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 getBytes() or 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. */ -- cgit v1.2.3-59-g8ed1b