optional string verb = 1;
+ */
+ boolean hasVerb();
+ /**
+ * optional string verb = 1;
+ */
+ java.lang.String getVerb();
+ /**
+ * optional string verb = 1;
+ */
+ com.google.protobuf.ByteString
+ getVerbBytes();
+
+ // optional string path = 2;
+ /**
+ * optional string path = 2;
+ */
+ boolean hasPath();
+ /**
+ * optional string path = 2;
+ */
+ java.lang.String getPath();
+ /**
+ * optional string path = 2;
+ */
+ com.google.protobuf.ByteString
+ getPathBytes();
+
+ // repeated string headers = 5;
+ /**
+ * repeated string headers = 5;
+ */
+ java.util.Listrepeated string headers = 5;
+ */
+ int getHeadersCount();
+ /**
+ * repeated string headers = 5;
+ */
+ java.lang.String getHeaders(int index);
+ /**
+ * repeated string headers = 5;
+ */
+ com.google.protobuf.ByteString
+ getHeadersBytes(int index);
+
+ // optional bytes body = 3;
+ /**
+ * optional bytes body = 3;
+ */
+ boolean hasBody();
+ /**
+ * optional bytes body = 3;
+ */
+ com.google.protobuf.ByteString getBody();
+
+ // optional uint64 id = 4;
+ /**
+ * optional uint64 id = 4;
+ */
+ boolean hasId();
+ /**
+ * optional uint64 id = 4;
+ */
+ long getId();
+ }
+ /**
+ * Protobuf type {@code textsecure.WebSocketRequestMessage}
+ */
+ public static final class WebSocketRequestMessage extends
+ com.google.protobuf.GeneratedMessage
+ implements WebSocketRequestMessageOrBuilder {
+ // Use WebSocketRequestMessage.newBuilder() to construct.
+ private WebSocketRequestMessage(com.google.protobuf.GeneratedMessage.Builder> builder) {
+ super(builder);
+ this.unknownFields = builder.getUnknownFields();
+ }
+ private WebSocketRequestMessage(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }
+
+ private static final WebSocketRequestMessage defaultInstance;
+ public static WebSocketRequestMessage getDefaultInstance() {
+ return defaultInstance;
+ }
+
+ public WebSocketRequestMessage getDefaultInstanceForType() {
+ return defaultInstance;
+ }
+
+ private final com.google.protobuf.UnknownFieldSet unknownFields;
+ @java.lang.Override
+ public final com.google.protobuf.UnknownFieldSet
+ getUnknownFields() {
+ return this.unknownFields;
+ }
+ private WebSocketRequestMessage(
+ com.google.protobuf.CodedInputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ initFields();
+ int mutable_bitField0_ = 0;
+ com.google.protobuf.UnknownFieldSet.Builder unknownFields =
+ com.google.protobuf.UnknownFieldSet.newBuilder();
+ try {
+ boolean done = false;
+ while (!done) {
+ int tag = input.readTag();
+ switch (tag) {
+ case 0:
+ done = true;
+ break;
+ default: {
+ if (!parseUnknownField(input, unknownFields,
+ extensionRegistry, tag)) {
+ done = true;
+ }
+ break;
+ }
+ case 10: {
+ bitField0_ |= 0x00000001;
+ verb_ = input.readBytes();
+ break;
+ }
+ case 18: {
+ bitField0_ |= 0x00000002;
+ path_ = input.readBytes();
+ break;
+ }
+ case 26: {
+ bitField0_ |= 0x00000004;
+ body_ = input.readBytes();
+ break;
+ }
+ case 32: {
+ bitField0_ |= 0x00000008;
+ id_ = input.readUInt64();
+ break;
+ }
+ case 42: {
+ if (!((mutable_bitField0_ & 0x00000004) == 0x00000004)) {
+ headers_ = new com.google.protobuf.LazyStringArrayList();
+ mutable_bitField0_ |= 0x00000004;
+ }
+ headers_.add(input.readBytes());
+ break;
+ }
+ }
+ }
+ } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+ throw e.setUnfinishedMessage(this);
+ } catch (java.io.IOException e) {
+ throw new com.google.protobuf.InvalidProtocolBufferException(
+ e.getMessage()).setUnfinishedMessage(this);
+ } finally {
+ if (((mutable_bitField0_ & 0x00000004) == 0x00000004)) {
+ headers_ = new com.google.protobuf.UnmodifiableLazyStringList(headers_);
+ }
+ this.unknownFields = unknownFields.build();
+ makeExtensionsImmutable();
+ }
+ }
+ public static final com.google.protobuf.Descriptors.Descriptor
+ getDescriptor() {
+ return org.whispersystems.websocket.messages.protobuf.SubProtocol.internal_static_textsecure_WebSocketRequestMessage_descriptor;
+ }
+
+ protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+ internalGetFieldAccessorTable() {
+ return org.whispersystems.websocket.messages.protobuf.SubProtocol.internal_static_textsecure_WebSocketRequestMessage_fieldAccessorTable
+ .ensureFieldAccessorsInitialized(
+ org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketRequestMessage.class, org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketRequestMessage.Builder.class);
+ }
+
+ public static com.google.protobuf.Parseroptional string verb = 1;
+ */
+ public boolean hasVerb() {
+ return ((bitField0_ & 0x00000001) == 0x00000001);
+ }
+ /**
+ * optional string verb = 1;
+ */
+ public java.lang.String getVerb() {
+ java.lang.Object ref = verb_;
+ if (ref instanceof java.lang.String) {
+ return (java.lang.String) ref;
+ } else {
+ com.google.protobuf.ByteString bs =
+ (com.google.protobuf.ByteString) ref;
+ java.lang.String s = bs.toStringUtf8();
+ if (bs.isValidUtf8()) {
+ verb_ = s;
+ }
+ return s;
+ }
+ }
+ /**
+ * optional string verb = 1;
+ */
+ public com.google.protobuf.ByteString
+ getVerbBytes() {
+ java.lang.Object ref = verb_;
+ if (ref instanceof java.lang.String) {
+ com.google.protobuf.ByteString b =
+ com.google.protobuf.ByteString.copyFromUtf8(
+ (java.lang.String) ref);
+ verb_ = b;
+ return b;
+ } else {
+ return (com.google.protobuf.ByteString) ref;
+ }
+ }
+
+ // optional string path = 2;
+ public static final int PATH_FIELD_NUMBER = 2;
+ private java.lang.Object path_;
+ /**
+ * optional string path = 2;
+ */
+ public boolean hasPath() {
+ return ((bitField0_ & 0x00000002) == 0x00000002);
+ }
+ /**
+ * optional string path = 2;
+ */
+ public java.lang.String getPath() {
+ java.lang.Object ref = path_;
+ if (ref instanceof java.lang.String) {
+ return (java.lang.String) ref;
+ } else {
+ com.google.protobuf.ByteString bs =
+ (com.google.protobuf.ByteString) ref;
+ java.lang.String s = bs.toStringUtf8();
+ if (bs.isValidUtf8()) {
+ path_ = s;
+ }
+ return s;
+ }
+ }
+ /**
+ * optional string path = 2;
+ */
+ public com.google.protobuf.ByteString
+ getPathBytes() {
+ java.lang.Object ref = path_;
+ if (ref instanceof java.lang.String) {
+ com.google.protobuf.ByteString b =
+ com.google.protobuf.ByteString.copyFromUtf8(
+ (java.lang.String) ref);
+ path_ = b;
+ return b;
+ } else {
+ return (com.google.protobuf.ByteString) ref;
+ }
+ }
+
+ // repeated string headers = 5;
+ public static final int HEADERS_FIELD_NUMBER = 5;
+ private com.google.protobuf.LazyStringList headers_;
+ /**
+ * repeated string headers = 5;
+ */
+ public java.util.Listrepeated string headers = 5;
+ */
+ public int getHeadersCount() {
+ return headers_.size();
+ }
+ /**
+ * repeated string headers = 5;
+ */
+ public java.lang.String getHeaders(int index) {
+ return headers_.get(index);
+ }
+ /**
+ * repeated string headers = 5;
+ */
+ public com.google.protobuf.ByteString
+ getHeadersBytes(int index) {
+ return headers_.getByteString(index);
+ }
+
+ // optional bytes body = 3;
+ public static final int BODY_FIELD_NUMBER = 3;
+ private com.google.protobuf.ByteString body_;
+ /**
+ * optional bytes body = 3;
+ */
+ public boolean hasBody() {
+ return ((bitField0_ & 0x00000004) == 0x00000004);
+ }
+ /**
+ * optional bytes body = 3;
+ */
+ public com.google.protobuf.ByteString getBody() {
+ return body_;
+ }
+
+ // optional uint64 id = 4;
+ public static final int ID_FIELD_NUMBER = 4;
+ private long id_;
+ /**
+ * optional uint64 id = 4;
+ */
+ public boolean hasId() {
+ return ((bitField0_ & 0x00000008) == 0x00000008);
+ }
+ /**
+ * optional uint64 id = 4;
+ */
+ public long getId() {
+ return id_;
+ }
+
+ private void initFields() {
+ verb_ = "";
+ path_ = "";
+ headers_ = com.google.protobuf.LazyStringArrayList.EMPTY;
+ body_ = com.google.protobuf.ByteString.EMPTY;
+ id_ = 0L;
+ }
+ private byte memoizedIsInitialized = -1;
+ public final boolean isInitialized() {
+ byte isInitialized = memoizedIsInitialized;
+ if (isInitialized != -1) return isInitialized == 1;
+
+ memoizedIsInitialized = 1;
+ return true;
+ }
+
+ public void writeTo(com.google.protobuf.CodedOutputStream output)
+ throws java.io.IOException {
+ getSerializedSize();
+ if (((bitField0_ & 0x00000001) == 0x00000001)) {
+ output.writeBytes(1, getVerbBytes());
+ }
+ if (((bitField0_ & 0x00000002) == 0x00000002)) {
+ output.writeBytes(2, getPathBytes());
+ }
+ if (((bitField0_ & 0x00000004) == 0x00000004)) {
+ output.writeBytes(3, body_);
+ }
+ if (((bitField0_ & 0x00000008) == 0x00000008)) {
+ output.writeUInt64(4, id_);
+ }
+ for (int i = 0; i < headers_.size(); i++) {
+ output.writeBytes(5, headers_.getByteString(i));
+ }
+ getUnknownFields().writeTo(output);
+ }
+
+ private int memoizedSerializedSize = -1;
+ public int getSerializedSize() {
+ int size = memoizedSerializedSize;
+ if (size != -1) return size;
+
+ size = 0;
+ if (((bitField0_ & 0x00000001) == 0x00000001)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeBytesSize(1, getVerbBytes());
+ }
+ if (((bitField0_ & 0x00000002) == 0x00000002)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeBytesSize(2, getPathBytes());
+ }
+ if (((bitField0_ & 0x00000004) == 0x00000004)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeBytesSize(3, body_);
+ }
+ if (((bitField0_ & 0x00000008) == 0x00000008)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeUInt64Size(4, id_);
+ }
+ {
+ int dataSize = 0;
+ for (int i = 0; i < headers_.size(); i++) {
+ dataSize += com.google.protobuf.CodedOutputStream
+ .computeBytesSizeNoTag(headers_.getByteString(i));
+ }
+ size += dataSize;
+ size += 1 * getHeadersList().size();
+ }
+ size += getUnknownFields().getSerializedSize();
+ memoizedSerializedSize = size;
+ return size;
+ }
+
+ private static final long serialVersionUID = 0L;
+ @java.lang.Override
+ protected java.lang.Object writeReplace()
+ throws java.io.ObjectStreamException {
+ return super.writeReplace();
+ }
+
+ public static org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketRequestMessage parseFrom(
+ com.google.protobuf.ByteString data)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return PARSER.parseFrom(data);
+ }
+ public static org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketRequestMessage parseFrom(
+ com.google.protobuf.ByteString data,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return PARSER.parseFrom(data, extensionRegistry);
+ }
+ public static org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketRequestMessage parseFrom(byte[] data)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return PARSER.parseFrom(data);
+ }
+ public static org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketRequestMessage parseFrom(
+ byte[] data,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return PARSER.parseFrom(data, extensionRegistry);
+ }
+ public static org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketRequestMessage parseFrom(java.io.InputStream input)
+ throws java.io.IOException {
+ return PARSER.parseFrom(input);
+ }
+ public static org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketRequestMessage parseFrom(
+ java.io.InputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ return PARSER.parseFrom(input, extensionRegistry);
+ }
+ public static org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketRequestMessage parseDelimitedFrom(java.io.InputStream input)
+ throws java.io.IOException {
+ return PARSER.parseDelimitedFrom(input);
+ }
+ public static org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketRequestMessage parseDelimitedFrom(
+ java.io.InputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ return PARSER.parseDelimitedFrom(input, extensionRegistry);
+ }
+ public static org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketRequestMessage parseFrom(
+ com.google.protobuf.CodedInputStream input)
+ throws java.io.IOException {
+ return PARSER.parseFrom(input);
+ }
+ public static org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketRequestMessage parseFrom(
+ com.google.protobuf.CodedInputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ return PARSER.parseFrom(input, extensionRegistry);
+ }
+
+ public static Builder newBuilder() { return Builder.create(); }
+ public Builder newBuilderForType() { return newBuilder(); }
+ public static Builder newBuilder(org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketRequestMessage prototype) {
+ return newBuilder().mergeFrom(prototype);
+ }
+ public Builder toBuilder() { return newBuilder(this); }
+
+ @java.lang.Override
+ protected Builder newBuilderForType(
+ com.google.protobuf.GeneratedMessage.BuilderParent parent) {
+ Builder builder = new Builder(parent);
+ return builder;
+ }
+ /**
+ * Protobuf type {@code textsecure.WebSocketRequestMessage}
+ */
+ public static final class Builder extends
+ com.google.protobuf.GeneratedMessage.Builderoptional string verb = 1;
+ */
+ public boolean hasVerb() {
+ return ((bitField0_ & 0x00000001) == 0x00000001);
+ }
+ /**
+ * optional string verb = 1;
+ */
+ public java.lang.String getVerb() {
+ java.lang.Object ref = verb_;
+ if (!(ref instanceof java.lang.String)) {
+ java.lang.String s = ((com.google.protobuf.ByteString) ref)
+ .toStringUtf8();
+ verb_ = s;
+ return s;
+ } else {
+ return (java.lang.String) ref;
+ }
+ }
+ /**
+ * optional string verb = 1;
+ */
+ public com.google.protobuf.ByteString
+ getVerbBytes() {
+ java.lang.Object ref = verb_;
+ if (ref instanceof String) {
+ com.google.protobuf.ByteString b =
+ com.google.protobuf.ByteString.copyFromUtf8(
+ (java.lang.String) ref);
+ verb_ = b;
+ return b;
+ } else {
+ return (com.google.protobuf.ByteString) ref;
+ }
+ }
+ /**
+ * optional string verb = 1;
+ */
+ public Builder setVerb(
+ java.lang.String value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ bitField0_ |= 0x00000001;
+ verb_ = value;
+ onChanged();
+ return this;
+ }
+ /**
+ * optional string verb = 1;
+ */
+ public Builder clearVerb() {
+ bitField0_ = (bitField0_ & ~0x00000001);
+ verb_ = getDefaultInstance().getVerb();
+ onChanged();
+ return this;
+ }
+ /**
+ * optional string verb = 1;
+ */
+ public Builder setVerbBytes(
+ com.google.protobuf.ByteString value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ bitField0_ |= 0x00000001;
+ verb_ = value;
+ onChanged();
+ return this;
+ }
+
+ // optional string path = 2;
+ private java.lang.Object path_ = "";
+ /**
+ * optional string path = 2;
+ */
+ public boolean hasPath() {
+ return ((bitField0_ & 0x00000002) == 0x00000002);
+ }
+ /**
+ * optional string path = 2;
+ */
+ public java.lang.String getPath() {
+ java.lang.Object ref = path_;
+ if (!(ref instanceof java.lang.String)) {
+ java.lang.String s = ((com.google.protobuf.ByteString) ref)
+ .toStringUtf8();
+ path_ = s;
+ return s;
+ } else {
+ return (java.lang.String) ref;
+ }
+ }
+ /**
+ * optional string path = 2;
+ */
+ public com.google.protobuf.ByteString
+ getPathBytes() {
+ java.lang.Object ref = path_;
+ if (ref instanceof String) {
+ com.google.protobuf.ByteString b =
+ com.google.protobuf.ByteString.copyFromUtf8(
+ (java.lang.String) ref);
+ path_ = b;
+ return b;
+ } else {
+ return (com.google.protobuf.ByteString) ref;
+ }
+ }
+ /**
+ * optional string path = 2;
+ */
+ public Builder setPath(
+ java.lang.String value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ bitField0_ |= 0x00000002;
+ path_ = value;
+ onChanged();
+ return this;
+ }
+ /**
+ * optional string path = 2;
+ */
+ public Builder clearPath() {
+ bitField0_ = (bitField0_ & ~0x00000002);
+ path_ = getDefaultInstance().getPath();
+ onChanged();
+ return this;
+ }
+ /**
+ * optional string path = 2;
+ */
+ public Builder setPathBytes(
+ com.google.protobuf.ByteString value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ bitField0_ |= 0x00000002;
+ path_ = value;
+ onChanged();
+ return this;
+ }
+
+ // repeated string headers = 5;
+ private com.google.protobuf.LazyStringList headers_ = com.google.protobuf.LazyStringArrayList.EMPTY;
+ private void ensureHeadersIsMutable() {
+ if (!((bitField0_ & 0x00000004) == 0x00000004)) {
+ headers_ = new com.google.protobuf.LazyStringArrayList(headers_);
+ bitField0_ |= 0x00000004;
+ }
+ }
+ /**
+ * repeated string headers = 5;
+ */
+ public java.util.Listrepeated string headers = 5;
+ */
+ public int getHeadersCount() {
+ return headers_.size();
+ }
+ /**
+ * repeated string headers = 5;
+ */
+ public java.lang.String getHeaders(int index) {
+ return headers_.get(index);
+ }
+ /**
+ * repeated string headers = 5;
+ */
+ public com.google.protobuf.ByteString
+ getHeadersBytes(int index) {
+ return headers_.getByteString(index);
+ }
+ /**
+ * repeated string headers = 5;
+ */
+ public Builder setHeaders(
+ int index, java.lang.String value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ ensureHeadersIsMutable();
+ headers_.set(index, value);
+ onChanged();
+ return this;
+ }
+ /**
+ * repeated string headers = 5;
+ */
+ public Builder addHeaders(
+ java.lang.String value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ ensureHeadersIsMutable();
+ headers_.add(value);
+ onChanged();
+ return this;
+ }
+ /**
+ * repeated string headers = 5;
+ */
+ public Builder addAllHeaders(
+ java.lang.Iterablerepeated string headers = 5;
+ */
+ public Builder clearHeaders() {
+ headers_ = com.google.protobuf.LazyStringArrayList.EMPTY;
+ bitField0_ = (bitField0_ & ~0x00000004);
+ onChanged();
+ return this;
+ }
+ /**
+ * repeated string headers = 5;
+ */
+ public Builder addHeadersBytes(
+ com.google.protobuf.ByteString value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ ensureHeadersIsMutable();
+ headers_.add(value);
+ onChanged();
+ return this;
+ }
+
+ // optional bytes body = 3;
+ private com.google.protobuf.ByteString body_ = com.google.protobuf.ByteString.EMPTY;
+ /**
+ * optional bytes body = 3;
+ */
+ public boolean hasBody() {
+ return ((bitField0_ & 0x00000008) == 0x00000008);
+ }
+ /**
+ * optional bytes body = 3;
+ */
+ public com.google.protobuf.ByteString getBody() {
+ return body_;
+ }
+ /**
+ * optional bytes body = 3;
+ */
+ public Builder setBody(com.google.protobuf.ByteString value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ bitField0_ |= 0x00000008;
+ body_ = value;
+ onChanged();
+ return this;
+ }
+ /**
+ * optional bytes body = 3;
+ */
+ public Builder clearBody() {
+ bitField0_ = (bitField0_ & ~0x00000008);
+ body_ = getDefaultInstance().getBody();
+ onChanged();
+ return this;
+ }
+
+ // optional uint64 id = 4;
+ private long id_ ;
+ /**
+ * optional uint64 id = 4;
+ */
+ public boolean hasId() {
+ return ((bitField0_ & 0x00000010) == 0x00000010);
+ }
+ /**
+ * optional uint64 id = 4;
+ */
+ public long getId() {
+ return id_;
+ }
+ /**
+ * optional uint64 id = 4;
+ */
+ public Builder setId(long value) {
+ bitField0_ |= 0x00000010;
+ id_ = value;
+ onChanged();
+ return this;
+ }
+ /**
+ * optional uint64 id = 4;
+ */
+ public Builder clearId() {
+ bitField0_ = (bitField0_ & ~0x00000010);
+ id_ = 0L;
+ onChanged();
+ return this;
+ }
+
+ // @@protoc_insertion_point(builder_scope:textsecure.WebSocketRequestMessage)
+ }
+
+ static {
+ defaultInstance = new WebSocketRequestMessage(true);
+ defaultInstance.initFields();
+ }
+
+ // @@protoc_insertion_point(class_scope:textsecure.WebSocketRequestMessage)
+ }
+
+ public interface WebSocketResponseMessageOrBuilder
+ extends com.google.protobuf.MessageOrBuilder {
+
+ // optional uint64 id = 1;
+ /**
+ * optional uint64 id = 1;
+ */
+ boolean hasId();
+ /**
+ * optional uint64 id = 1;
+ */
+ long getId();
+
+ // optional uint32 status = 2;
+ /**
+ * optional uint32 status = 2;
+ */
+ boolean hasStatus();
+ /**
+ * optional uint32 status = 2;
+ */
+ int getStatus();
+
+ // optional string message = 3;
+ /**
+ * optional string message = 3;
+ */
+ boolean hasMessage();
+ /**
+ * optional string message = 3;
+ */
+ java.lang.String getMessage();
+ /**
+ * optional string message = 3;
+ */
+ com.google.protobuf.ByteString
+ getMessageBytes();
+
+ // repeated string headers = 5;
+ /**
+ * repeated string headers = 5;
+ */
+ java.util.Listrepeated string headers = 5;
+ */
+ int getHeadersCount();
+ /**
+ * repeated string headers = 5;
+ */
+ java.lang.String getHeaders(int index);
+ /**
+ * repeated string headers = 5;
+ */
+ com.google.protobuf.ByteString
+ getHeadersBytes(int index);
+
+ // optional bytes body = 4;
+ /**
+ * optional bytes body = 4;
+ */
+ boolean hasBody();
+ /**
+ * optional bytes body = 4;
+ */
+ com.google.protobuf.ByteString getBody();
+ }
+ /**
+ * Protobuf type {@code textsecure.WebSocketResponseMessage}
+ */
+ public static final class WebSocketResponseMessage extends
+ com.google.protobuf.GeneratedMessage
+ implements WebSocketResponseMessageOrBuilder {
+ // Use WebSocketResponseMessage.newBuilder() to construct.
+ private WebSocketResponseMessage(com.google.protobuf.GeneratedMessage.Builder> builder) {
+ super(builder);
+ this.unknownFields = builder.getUnknownFields();
+ }
+ private WebSocketResponseMessage(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }
+
+ private static final WebSocketResponseMessage defaultInstance;
+ public static WebSocketResponseMessage getDefaultInstance() {
+ return defaultInstance;
+ }
+
+ public WebSocketResponseMessage getDefaultInstanceForType() {
+ return defaultInstance;
+ }
+
+ private final com.google.protobuf.UnknownFieldSet unknownFields;
+ @java.lang.Override
+ public final com.google.protobuf.UnknownFieldSet
+ getUnknownFields() {
+ return this.unknownFields;
+ }
+ private WebSocketResponseMessage(
+ com.google.protobuf.CodedInputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ initFields();
+ int mutable_bitField0_ = 0;
+ com.google.protobuf.UnknownFieldSet.Builder unknownFields =
+ com.google.protobuf.UnknownFieldSet.newBuilder();
+ try {
+ boolean done = false;
+ while (!done) {
+ int tag = input.readTag();
+ switch (tag) {
+ case 0:
+ done = true;
+ break;
+ default: {
+ if (!parseUnknownField(input, unknownFields,
+ extensionRegistry, tag)) {
+ done = true;
+ }
+ break;
+ }
+ case 8: {
+ bitField0_ |= 0x00000001;
+ id_ = input.readUInt64();
+ break;
+ }
+ case 16: {
+ bitField0_ |= 0x00000002;
+ status_ = input.readUInt32();
+ break;
+ }
+ case 26: {
+ bitField0_ |= 0x00000004;
+ message_ = input.readBytes();
+ break;
+ }
+ case 34: {
+ bitField0_ |= 0x00000008;
+ body_ = input.readBytes();
+ break;
+ }
+ case 42: {
+ if (!((mutable_bitField0_ & 0x00000008) == 0x00000008)) {
+ headers_ = new com.google.protobuf.LazyStringArrayList();
+ mutable_bitField0_ |= 0x00000008;
+ }
+ headers_.add(input.readBytes());
+ break;
+ }
+ }
+ }
+ } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+ throw e.setUnfinishedMessage(this);
+ } catch (java.io.IOException e) {
+ throw new com.google.protobuf.InvalidProtocolBufferException(
+ e.getMessage()).setUnfinishedMessage(this);
+ } finally {
+ if (((mutable_bitField0_ & 0x00000008) == 0x00000008)) {
+ headers_ = new com.google.protobuf.UnmodifiableLazyStringList(headers_);
+ }
+ this.unknownFields = unknownFields.build();
+ makeExtensionsImmutable();
+ }
+ }
+ public static final com.google.protobuf.Descriptors.Descriptor
+ getDescriptor() {
+ return org.whispersystems.websocket.messages.protobuf.SubProtocol.internal_static_textsecure_WebSocketResponseMessage_descriptor;
+ }
+
+ protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+ internalGetFieldAccessorTable() {
+ return org.whispersystems.websocket.messages.protobuf.SubProtocol.internal_static_textsecure_WebSocketResponseMessage_fieldAccessorTable
+ .ensureFieldAccessorsInitialized(
+ org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketResponseMessage.class, org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketResponseMessage.Builder.class);
+ }
+
+ public static com.google.protobuf.Parseroptional uint64 id = 1;
+ */
+ public boolean hasId() {
+ return ((bitField0_ & 0x00000001) == 0x00000001);
+ }
+ /**
+ * optional uint64 id = 1;
+ */
+ public long getId() {
+ return id_;
+ }
+
+ // optional uint32 status = 2;
+ public static final int STATUS_FIELD_NUMBER = 2;
+ private int status_;
+ /**
+ * optional uint32 status = 2;
+ */
+ public boolean hasStatus() {
+ return ((bitField0_ & 0x00000002) == 0x00000002);
+ }
+ /**
+ * optional uint32 status = 2;
+ */
+ public int getStatus() {
+ return status_;
+ }
+
+ // optional string message = 3;
+ public static final int MESSAGE_FIELD_NUMBER = 3;
+ private java.lang.Object message_;
+ /**
+ * optional string message = 3;
+ */
+ public boolean hasMessage() {
+ return ((bitField0_ & 0x00000004) == 0x00000004);
+ }
+ /**
+ * optional string message = 3;
+ */
+ public java.lang.String getMessage() {
+ java.lang.Object ref = message_;
+ if (ref instanceof java.lang.String) {
+ return (java.lang.String) ref;
+ } else {
+ com.google.protobuf.ByteString bs =
+ (com.google.protobuf.ByteString) ref;
+ java.lang.String s = bs.toStringUtf8();
+ if (bs.isValidUtf8()) {
+ message_ = s;
+ }
+ return s;
+ }
+ }
+ /**
+ * optional string message = 3;
+ */
+ public com.google.protobuf.ByteString
+ getMessageBytes() {
+ java.lang.Object ref = message_;
+ if (ref instanceof java.lang.String) {
+ com.google.protobuf.ByteString b =
+ com.google.protobuf.ByteString.copyFromUtf8(
+ (java.lang.String) ref);
+ message_ = b;
+ return b;
+ } else {
+ return (com.google.protobuf.ByteString) ref;
+ }
+ }
+
+ // repeated string headers = 5;
+ public static final int HEADERS_FIELD_NUMBER = 5;
+ private com.google.protobuf.LazyStringList headers_;
+ /**
+ * repeated string headers = 5;
+ */
+ public java.util.Listrepeated string headers = 5;
+ */
+ public int getHeadersCount() {
+ return headers_.size();
+ }
+ /**
+ * repeated string headers = 5;
+ */
+ public java.lang.String getHeaders(int index) {
+ return headers_.get(index);
+ }
+ /**
+ * repeated string headers = 5;
+ */
+ public com.google.protobuf.ByteString
+ getHeadersBytes(int index) {
+ return headers_.getByteString(index);
+ }
+
+ // optional bytes body = 4;
+ public static final int BODY_FIELD_NUMBER = 4;
+ private com.google.protobuf.ByteString body_;
+ /**
+ * optional bytes body = 4;
+ */
+ public boolean hasBody() {
+ return ((bitField0_ & 0x00000008) == 0x00000008);
+ }
+ /**
+ * optional bytes body = 4;
+ */
+ public com.google.protobuf.ByteString getBody() {
+ return body_;
+ }
+
+ private void initFields() {
+ id_ = 0L;
+ status_ = 0;
+ message_ = "";
+ headers_ = com.google.protobuf.LazyStringArrayList.EMPTY;
+ body_ = com.google.protobuf.ByteString.EMPTY;
+ }
+ private byte memoizedIsInitialized = -1;
+ public final boolean isInitialized() {
+ byte isInitialized = memoizedIsInitialized;
+ if (isInitialized != -1) return isInitialized == 1;
+
+ memoizedIsInitialized = 1;
+ return true;
+ }
+
+ public void writeTo(com.google.protobuf.CodedOutputStream output)
+ throws java.io.IOException {
+ getSerializedSize();
+ if (((bitField0_ & 0x00000001) == 0x00000001)) {
+ output.writeUInt64(1, id_);
+ }
+ if (((bitField0_ & 0x00000002) == 0x00000002)) {
+ output.writeUInt32(2, status_);
+ }
+ if (((bitField0_ & 0x00000004) == 0x00000004)) {
+ output.writeBytes(3, getMessageBytes());
+ }
+ if (((bitField0_ & 0x00000008) == 0x00000008)) {
+ output.writeBytes(4, body_);
+ }
+ for (int i = 0; i < headers_.size(); i++) {
+ output.writeBytes(5, headers_.getByteString(i));
+ }
+ getUnknownFields().writeTo(output);
+ }
+
+ private int memoizedSerializedSize = -1;
+ public int getSerializedSize() {
+ int size = memoizedSerializedSize;
+ if (size != -1) return size;
+
+ size = 0;
+ if (((bitField0_ & 0x00000001) == 0x00000001)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeUInt64Size(1, id_);
+ }
+ if (((bitField0_ & 0x00000002) == 0x00000002)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeUInt32Size(2, status_);
+ }
+ if (((bitField0_ & 0x00000004) == 0x00000004)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeBytesSize(3, getMessageBytes());
+ }
+ if (((bitField0_ & 0x00000008) == 0x00000008)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeBytesSize(4, body_);
+ }
+ {
+ int dataSize = 0;
+ for (int i = 0; i < headers_.size(); i++) {
+ dataSize += com.google.protobuf.CodedOutputStream
+ .computeBytesSizeNoTag(headers_.getByteString(i));
+ }
+ size += dataSize;
+ size += 1 * getHeadersList().size();
+ }
+ size += getUnknownFields().getSerializedSize();
+ memoizedSerializedSize = size;
+ return size;
+ }
+
+ private static final long serialVersionUID = 0L;
+ @java.lang.Override
+ protected java.lang.Object writeReplace()
+ throws java.io.ObjectStreamException {
+ return super.writeReplace();
+ }
+
+ public static org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketResponseMessage parseFrom(
+ com.google.protobuf.ByteString data)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return PARSER.parseFrom(data);
+ }
+ public static org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketResponseMessage parseFrom(
+ com.google.protobuf.ByteString data,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return PARSER.parseFrom(data, extensionRegistry);
+ }
+ public static org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketResponseMessage parseFrom(byte[] data)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return PARSER.parseFrom(data);
+ }
+ public static org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketResponseMessage parseFrom(
+ byte[] data,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return PARSER.parseFrom(data, extensionRegistry);
+ }
+ public static org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketResponseMessage parseFrom(java.io.InputStream input)
+ throws java.io.IOException {
+ return PARSER.parseFrom(input);
+ }
+ public static org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketResponseMessage parseFrom(
+ java.io.InputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ return PARSER.parseFrom(input, extensionRegistry);
+ }
+ public static org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketResponseMessage parseDelimitedFrom(java.io.InputStream input)
+ throws java.io.IOException {
+ return PARSER.parseDelimitedFrom(input);
+ }
+ public static org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketResponseMessage parseDelimitedFrom(
+ java.io.InputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ return PARSER.parseDelimitedFrom(input, extensionRegistry);
+ }
+ public static org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketResponseMessage parseFrom(
+ com.google.protobuf.CodedInputStream input)
+ throws java.io.IOException {
+ return PARSER.parseFrom(input);
+ }
+ public static org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketResponseMessage parseFrom(
+ com.google.protobuf.CodedInputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ return PARSER.parseFrom(input, extensionRegistry);
+ }
+
+ public static Builder newBuilder() { return Builder.create(); }
+ public Builder newBuilderForType() { return newBuilder(); }
+ public static Builder newBuilder(org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketResponseMessage prototype) {
+ return newBuilder().mergeFrom(prototype);
+ }
+ public Builder toBuilder() { return newBuilder(this); }
+
+ @java.lang.Override
+ protected Builder newBuilderForType(
+ com.google.protobuf.GeneratedMessage.BuilderParent parent) {
+ Builder builder = new Builder(parent);
+ return builder;
+ }
+ /**
+ * Protobuf type {@code textsecure.WebSocketResponseMessage}
+ */
+ public static final class Builder extends
+ com.google.protobuf.GeneratedMessage.Builderoptional uint64 id = 1;
+ */
+ public boolean hasId() {
+ return ((bitField0_ & 0x00000001) == 0x00000001);
+ }
+ /**
+ * optional uint64 id = 1;
+ */
+ public long getId() {
+ return id_;
+ }
+ /**
+ * optional uint64 id = 1;
+ */
+ public Builder setId(long value) {
+ bitField0_ |= 0x00000001;
+ id_ = value;
+ onChanged();
+ return this;
+ }
+ /**
+ * optional uint64 id = 1;
+ */
+ public Builder clearId() {
+ bitField0_ = (bitField0_ & ~0x00000001);
+ id_ = 0L;
+ onChanged();
+ return this;
+ }
+
+ // optional uint32 status = 2;
+ private int status_ ;
+ /**
+ * optional uint32 status = 2;
+ */
+ public boolean hasStatus() {
+ return ((bitField0_ & 0x00000002) == 0x00000002);
+ }
+ /**
+ * optional uint32 status = 2;
+ */
+ public int getStatus() {
+ return status_;
+ }
+ /**
+ * optional uint32 status = 2;
+ */
+ public Builder setStatus(int value) {
+ bitField0_ |= 0x00000002;
+ status_ = value;
+ onChanged();
+ return this;
+ }
+ /**
+ * optional uint32 status = 2;
+ */
+ public Builder clearStatus() {
+ bitField0_ = (bitField0_ & ~0x00000002);
+ status_ = 0;
+ onChanged();
+ return this;
+ }
+
+ // optional string message = 3;
+ private java.lang.Object message_ = "";
+ /**
+ * optional string message = 3;
+ */
+ public boolean hasMessage() {
+ return ((bitField0_ & 0x00000004) == 0x00000004);
+ }
+ /**
+ * optional string message = 3;
+ */
+ public java.lang.String getMessage() {
+ java.lang.Object ref = message_;
+ if (!(ref instanceof java.lang.String)) {
+ java.lang.String s = ((com.google.protobuf.ByteString) ref)
+ .toStringUtf8();
+ message_ = s;
+ return s;
+ } else {
+ return (java.lang.String) ref;
+ }
+ }
+ /**
+ * optional string message = 3;
+ */
+ public com.google.protobuf.ByteString
+ getMessageBytes() {
+ java.lang.Object ref = message_;
+ if (ref instanceof String) {
+ com.google.protobuf.ByteString b =
+ com.google.protobuf.ByteString.copyFromUtf8(
+ (java.lang.String) ref);
+ message_ = b;
+ return b;
+ } else {
+ return (com.google.protobuf.ByteString) ref;
+ }
+ }
+ /**
+ * optional string message = 3;
+ */
+ public Builder setMessage(
+ java.lang.String value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ bitField0_ |= 0x00000004;
+ message_ = value;
+ onChanged();
+ return this;
+ }
+ /**
+ * optional string message = 3;
+ */
+ public Builder clearMessage() {
+ bitField0_ = (bitField0_ & ~0x00000004);
+ message_ = getDefaultInstance().getMessage();
+ onChanged();
+ return this;
+ }
+ /**
+ * optional string message = 3;
+ */
+ public Builder setMessageBytes(
+ com.google.protobuf.ByteString value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ bitField0_ |= 0x00000004;
+ message_ = value;
+ onChanged();
+ return this;
+ }
+
+ // repeated string headers = 5;
+ private com.google.protobuf.LazyStringList headers_ = com.google.protobuf.LazyStringArrayList.EMPTY;
+ private void ensureHeadersIsMutable() {
+ if (!((bitField0_ & 0x00000008) == 0x00000008)) {
+ headers_ = new com.google.protobuf.LazyStringArrayList(headers_);
+ bitField0_ |= 0x00000008;
+ }
+ }
+ /**
+ * repeated string headers = 5;
+ */
+ public java.util.Listrepeated string headers = 5;
+ */
+ public int getHeadersCount() {
+ return headers_.size();
+ }
+ /**
+ * repeated string headers = 5;
+ */
+ public java.lang.String getHeaders(int index) {
+ return headers_.get(index);
+ }
+ /**
+ * repeated string headers = 5;
+ */
+ public com.google.protobuf.ByteString
+ getHeadersBytes(int index) {
+ return headers_.getByteString(index);
+ }
+ /**
+ * repeated string headers = 5;
+ */
+ public Builder setHeaders(
+ int index, java.lang.String value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ ensureHeadersIsMutable();
+ headers_.set(index, value);
+ onChanged();
+ return this;
+ }
+ /**
+ * repeated string headers = 5;
+ */
+ public Builder addHeaders(
+ java.lang.String value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ ensureHeadersIsMutable();
+ headers_.add(value);
+ onChanged();
+ return this;
+ }
+ /**
+ * repeated string headers = 5;
+ */
+ public Builder addAllHeaders(
+ java.lang.Iterablerepeated string headers = 5;
+ */
+ public Builder clearHeaders() {
+ headers_ = com.google.protobuf.LazyStringArrayList.EMPTY;
+ bitField0_ = (bitField0_ & ~0x00000008);
+ onChanged();
+ return this;
+ }
+ /**
+ * repeated string headers = 5;
+ */
+ public Builder addHeadersBytes(
+ com.google.protobuf.ByteString value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ ensureHeadersIsMutable();
+ headers_.add(value);
+ onChanged();
+ return this;
+ }
+
+ // optional bytes body = 4;
+ private com.google.protobuf.ByteString body_ = com.google.protobuf.ByteString.EMPTY;
+ /**
+ * optional bytes body = 4;
+ */
+ public boolean hasBody() {
+ return ((bitField0_ & 0x00000010) == 0x00000010);
+ }
+ /**
+ * optional bytes body = 4;
+ */
+ public com.google.protobuf.ByteString getBody() {
+ return body_;
+ }
+ /**
+ * optional bytes body = 4;
+ */
+ public Builder setBody(com.google.protobuf.ByteString value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ bitField0_ |= 0x00000010;
+ body_ = value;
+ onChanged();
+ return this;
+ }
+ /**
+ * optional bytes body = 4;
+ */
+ public Builder clearBody() {
+ bitField0_ = (bitField0_ & ~0x00000010);
+ body_ = getDefaultInstance().getBody();
+ onChanged();
+ return this;
+ }
+
+ // @@protoc_insertion_point(builder_scope:textsecure.WebSocketResponseMessage)
+ }
+
+ static {
+ defaultInstance = new WebSocketResponseMessage(true);
+ defaultInstance.initFields();
+ }
+
+ // @@protoc_insertion_point(class_scope:textsecure.WebSocketResponseMessage)
+ }
+
+ public interface WebSocketMessageOrBuilder
+ extends com.google.protobuf.MessageOrBuilder {
+
+ // optional .textsecure.WebSocketMessage.Type type = 1;
+ /**
+ * optional .textsecure.WebSocketMessage.Type type = 1;
+ */
+ boolean hasType();
+ /**
+ * optional .textsecure.WebSocketMessage.Type type = 1;
+ */
+ org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketMessage.Type getType();
+
+ // optional .textsecure.WebSocketRequestMessage request = 2;
+ /**
+ * optional .textsecure.WebSocketRequestMessage request = 2;
+ */
+ boolean hasRequest();
+ /**
+ * optional .textsecure.WebSocketRequestMessage request = 2;
+ */
+ org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketRequestMessage getRequest();
+ /**
+ * optional .textsecure.WebSocketRequestMessage request = 2;
+ */
+ org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketRequestMessageOrBuilder getRequestOrBuilder();
+
+ // optional .textsecure.WebSocketResponseMessage response = 3;
+ /**
+ * optional .textsecure.WebSocketResponseMessage response = 3;
+ */
+ boolean hasResponse();
+ /**
+ * optional .textsecure.WebSocketResponseMessage response = 3;
+ */
+ org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketResponseMessage getResponse();
+ /**
+ * optional .textsecure.WebSocketResponseMessage response = 3;
+ */
+ org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketResponseMessageOrBuilder getResponseOrBuilder();
+ }
+ /**
+ * Protobuf type {@code textsecure.WebSocketMessage}
+ */
+ public static final class WebSocketMessage extends
+ com.google.protobuf.GeneratedMessage
+ implements WebSocketMessageOrBuilder {
+ // Use WebSocketMessage.newBuilder() to construct.
+ private WebSocketMessage(com.google.protobuf.GeneratedMessage.Builder> builder) {
+ super(builder);
+ this.unknownFields = builder.getUnknownFields();
+ }
+ private WebSocketMessage(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }
+
+ private static final WebSocketMessage defaultInstance;
+ public static WebSocketMessage getDefaultInstance() {
+ return defaultInstance;
+ }
+
+ public WebSocketMessage getDefaultInstanceForType() {
+ return defaultInstance;
+ }
+
+ private final com.google.protobuf.UnknownFieldSet unknownFields;
+ @java.lang.Override
+ public final com.google.protobuf.UnknownFieldSet
+ getUnknownFields() {
+ return this.unknownFields;
+ }
+ private WebSocketMessage(
+ com.google.protobuf.CodedInputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ initFields();
+ int mutable_bitField0_ = 0;
+ com.google.protobuf.UnknownFieldSet.Builder unknownFields =
+ com.google.protobuf.UnknownFieldSet.newBuilder();
+ try {
+ boolean done = false;
+ while (!done) {
+ int tag = input.readTag();
+ switch (tag) {
+ case 0:
+ done = true;
+ break;
+ default: {
+ if (!parseUnknownField(input, unknownFields,
+ extensionRegistry, tag)) {
+ done = true;
+ }
+ break;
+ }
+ case 8: {
+ int rawValue = input.readEnum();
+ org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketMessage.Type value = org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketMessage.Type.valueOf(rawValue);
+ if (value == null) {
+ unknownFields.mergeVarintField(1, rawValue);
+ } else {
+ bitField0_ |= 0x00000001;
+ type_ = value;
+ }
+ break;
+ }
+ case 18: {
+ org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketRequestMessage.Builder subBuilder = null;
+ if (((bitField0_ & 0x00000002) == 0x00000002)) {
+ subBuilder = request_.toBuilder();
+ }
+ request_ = input.readMessage(org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketRequestMessage.PARSER, extensionRegistry);
+ if (subBuilder != null) {
+ subBuilder.mergeFrom(request_);
+ request_ = subBuilder.buildPartial();
+ }
+ bitField0_ |= 0x00000002;
+ break;
+ }
+ case 26: {
+ org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketResponseMessage.Builder subBuilder = null;
+ if (((bitField0_ & 0x00000004) == 0x00000004)) {
+ subBuilder = response_.toBuilder();
+ }
+ response_ = input.readMessage(org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketResponseMessage.PARSER, extensionRegistry);
+ if (subBuilder != null) {
+ subBuilder.mergeFrom(response_);
+ response_ = subBuilder.buildPartial();
+ }
+ bitField0_ |= 0x00000004;
+ break;
+ }
+ }
+ }
+ } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+ throw e.setUnfinishedMessage(this);
+ } catch (java.io.IOException e) {
+ throw new com.google.protobuf.InvalidProtocolBufferException(
+ e.getMessage()).setUnfinishedMessage(this);
+ } finally {
+ this.unknownFields = unknownFields.build();
+ makeExtensionsImmutable();
+ }
+ }
+ public static final com.google.protobuf.Descriptors.Descriptor
+ getDescriptor() {
+ return org.whispersystems.websocket.messages.protobuf.SubProtocol.internal_static_textsecure_WebSocketMessage_descriptor;
+ }
+
+ protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+ internalGetFieldAccessorTable() {
+ return org.whispersystems.websocket.messages.protobuf.SubProtocol.internal_static_textsecure_WebSocketMessage_fieldAccessorTable
+ .ensureFieldAccessorsInitialized(
+ org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketMessage.class, org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketMessage.Builder.class);
+ }
+
+ public static com.google.protobuf.ParserUNKNOWN = 0;
+ */
+ UNKNOWN(0, 0),
+ /**
+ * REQUEST = 1;
+ */
+ REQUEST(1, 1),
+ /**
+ * RESPONSE = 2;
+ */
+ RESPONSE(2, 2),
+ ;
+
+ /**
+ * UNKNOWN = 0;
+ */
+ public static final int UNKNOWN_VALUE = 0;
+ /**
+ * REQUEST = 1;
+ */
+ public static final int REQUEST_VALUE = 1;
+ /**
+ * RESPONSE = 2;
+ */
+ public static final int RESPONSE_VALUE = 2;
+
+
+ public final int getNumber() { return value; }
+
+ public static Type valueOf(int value) {
+ switch (value) {
+ case 0: return UNKNOWN;
+ case 1: return REQUEST;
+ case 2: return RESPONSE;
+ default: return null;
+ }
+ }
+
+ public static com.google.protobuf.Internal.EnumLiteMapoptional .textsecure.WebSocketMessage.Type type = 1;
+ */
+ public boolean hasType() {
+ return ((bitField0_ & 0x00000001) == 0x00000001);
+ }
+ /**
+ * optional .textsecure.WebSocketMessage.Type type = 1;
+ */
+ public org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketMessage.Type getType() {
+ return type_;
+ }
+
+ // optional .textsecure.WebSocketRequestMessage request = 2;
+ public static final int REQUEST_FIELD_NUMBER = 2;
+ private org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketRequestMessage request_;
+ /**
+ * optional .textsecure.WebSocketRequestMessage request = 2;
+ */
+ public boolean hasRequest() {
+ return ((bitField0_ & 0x00000002) == 0x00000002);
+ }
+ /**
+ * optional .textsecure.WebSocketRequestMessage request = 2;
+ */
+ public org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketRequestMessage getRequest() {
+ return request_;
+ }
+ /**
+ * optional .textsecure.WebSocketRequestMessage request = 2;
+ */
+ public org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketRequestMessageOrBuilder getRequestOrBuilder() {
+ return request_;
+ }
+
+ // optional .textsecure.WebSocketResponseMessage response = 3;
+ public static final int RESPONSE_FIELD_NUMBER = 3;
+ private org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketResponseMessage response_;
+ /**
+ * optional .textsecure.WebSocketResponseMessage response = 3;
+ */
+ public boolean hasResponse() {
+ return ((bitField0_ & 0x00000004) == 0x00000004);
+ }
+ /**
+ * optional .textsecure.WebSocketResponseMessage response = 3;
+ */
+ public org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketResponseMessage getResponse() {
+ return response_;
+ }
+ /**
+ * optional .textsecure.WebSocketResponseMessage response = 3;
+ */
+ public org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketResponseMessageOrBuilder getResponseOrBuilder() {
+ return response_;
+ }
+
+ private void initFields() {
+ type_ = org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketMessage.Type.UNKNOWN;
+ request_ = org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketRequestMessage.getDefaultInstance();
+ response_ = org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketResponseMessage.getDefaultInstance();
+ }
+ private byte memoizedIsInitialized = -1;
+ public final boolean isInitialized() {
+ byte isInitialized = memoizedIsInitialized;
+ if (isInitialized != -1) return isInitialized == 1;
+
+ memoizedIsInitialized = 1;
+ return true;
+ }
+
+ public void writeTo(com.google.protobuf.CodedOutputStream output)
+ throws java.io.IOException {
+ getSerializedSize();
+ if (((bitField0_ & 0x00000001) == 0x00000001)) {
+ output.writeEnum(1, type_.getNumber());
+ }
+ if (((bitField0_ & 0x00000002) == 0x00000002)) {
+ output.writeMessage(2, request_);
+ }
+ if (((bitField0_ & 0x00000004) == 0x00000004)) {
+ output.writeMessage(3, response_);
+ }
+ getUnknownFields().writeTo(output);
+ }
+
+ private int memoizedSerializedSize = -1;
+ public int getSerializedSize() {
+ int size = memoizedSerializedSize;
+ if (size != -1) return size;
+
+ size = 0;
+ if (((bitField0_ & 0x00000001) == 0x00000001)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeEnumSize(1, type_.getNumber());
+ }
+ if (((bitField0_ & 0x00000002) == 0x00000002)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeMessageSize(2, request_);
+ }
+ if (((bitField0_ & 0x00000004) == 0x00000004)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeMessageSize(3, response_);
+ }
+ size += getUnknownFields().getSerializedSize();
+ memoizedSerializedSize = size;
+ return size;
+ }
+
+ private static final long serialVersionUID = 0L;
+ @java.lang.Override
+ protected java.lang.Object writeReplace()
+ throws java.io.ObjectStreamException {
+ return super.writeReplace();
+ }
+
+ public static org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketMessage parseFrom(
+ com.google.protobuf.ByteString data)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return PARSER.parseFrom(data);
+ }
+ public static org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketMessage parseFrom(
+ com.google.protobuf.ByteString data,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return PARSER.parseFrom(data, extensionRegistry);
+ }
+ public static org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketMessage parseFrom(byte[] data)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return PARSER.parseFrom(data);
+ }
+ public static org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketMessage parseFrom(
+ byte[] data,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return PARSER.parseFrom(data, extensionRegistry);
+ }
+ public static org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketMessage parseFrom(java.io.InputStream input)
+ throws java.io.IOException {
+ return PARSER.parseFrom(input);
+ }
+ public static org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketMessage parseFrom(
+ java.io.InputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ return PARSER.parseFrom(input, extensionRegistry);
+ }
+ public static org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketMessage parseDelimitedFrom(java.io.InputStream input)
+ throws java.io.IOException {
+ return PARSER.parseDelimitedFrom(input);
+ }
+ public static org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketMessage parseDelimitedFrom(
+ java.io.InputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ return PARSER.parseDelimitedFrom(input, extensionRegistry);
+ }
+ public static org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketMessage parseFrom(
+ com.google.protobuf.CodedInputStream input)
+ throws java.io.IOException {
+ return PARSER.parseFrom(input);
+ }
+ public static org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketMessage parseFrom(
+ com.google.protobuf.CodedInputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ return PARSER.parseFrom(input, extensionRegistry);
+ }
+
+ public static Builder newBuilder() { return Builder.create(); }
+ public Builder newBuilderForType() { return newBuilder(); }
+ public static Builder newBuilder(org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketMessage prototype) {
+ return newBuilder().mergeFrom(prototype);
+ }
+ public Builder toBuilder() { return newBuilder(this); }
+
+ @java.lang.Override
+ protected Builder newBuilderForType(
+ com.google.protobuf.GeneratedMessage.BuilderParent parent) {
+ Builder builder = new Builder(parent);
+ return builder;
+ }
+ /**
+ * Protobuf type {@code textsecure.WebSocketMessage}
+ */
+ public static final class Builder extends
+ com.google.protobuf.GeneratedMessage.Builderoptional .textsecure.WebSocketMessage.Type type = 1;
+ */
+ public boolean hasType() {
+ return ((bitField0_ & 0x00000001) == 0x00000001);
+ }
+ /**
+ * optional .textsecure.WebSocketMessage.Type type = 1;
+ */
+ public org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketMessage.Type getType() {
+ return type_;
+ }
+ /**
+ * optional .textsecure.WebSocketMessage.Type type = 1;
+ */
+ public Builder setType(org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketMessage.Type value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ bitField0_ |= 0x00000001;
+ type_ = value;
+ onChanged();
+ return this;
+ }
+ /**
+ * optional .textsecure.WebSocketMessage.Type type = 1;
+ */
+ public Builder clearType() {
+ bitField0_ = (bitField0_ & ~0x00000001);
+ type_ = org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketMessage.Type.UNKNOWN;
+ onChanged();
+ return this;
+ }
+
+ // optional .textsecure.WebSocketRequestMessage request = 2;
+ private org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketRequestMessage request_ = org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketRequestMessage.getDefaultInstance();
+ private com.google.protobuf.SingleFieldBuilder<
+ org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketRequestMessage, org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketRequestMessage.Builder, org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketRequestMessageOrBuilder> requestBuilder_;
+ /**
+ * optional .textsecure.WebSocketRequestMessage request = 2;
+ */
+ public boolean hasRequest() {
+ return ((bitField0_ & 0x00000002) == 0x00000002);
+ }
+ /**
+ * optional .textsecure.WebSocketRequestMessage request = 2;
+ */
+ public org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketRequestMessage getRequest() {
+ if (requestBuilder_ == null) {
+ return request_;
+ } else {
+ return requestBuilder_.getMessage();
+ }
+ }
+ /**
+ * optional .textsecure.WebSocketRequestMessage request = 2;
+ */
+ public Builder setRequest(org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketRequestMessage value) {
+ if (requestBuilder_ == null) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ request_ = value;
+ onChanged();
+ } else {
+ requestBuilder_.setMessage(value);
+ }
+ bitField0_ |= 0x00000002;
+ return this;
+ }
+ /**
+ * optional .textsecure.WebSocketRequestMessage request = 2;
+ */
+ public Builder setRequest(
+ org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketRequestMessage.Builder builderForValue) {
+ if (requestBuilder_ == null) {
+ request_ = builderForValue.build();
+ onChanged();
+ } else {
+ requestBuilder_.setMessage(builderForValue.build());
+ }
+ bitField0_ |= 0x00000002;
+ return this;
+ }
+ /**
+ * optional .textsecure.WebSocketRequestMessage request = 2;
+ */
+ public Builder mergeRequest(org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketRequestMessage value) {
+ if (requestBuilder_ == null) {
+ if (((bitField0_ & 0x00000002) == 0x00000002) &&
+ request_ != org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketRequestMessage.getDefaultInstance()) {
+ request_ =
+ org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketRequestMessage.newBuilder(request_).mergeFrom(value).buildPartial();
+ } else {
+ request_ = value;
+ }
+ onChanged();
+ } else {
+ requestBuilder_.mergeFrom(value);
+ }
+ bitField0_ |= 0x00000002;
+ return this;
+ }
+ /**
+ * optional .textsecure.WebSocketRequestMessage request = 2;
+ */
+ public Builder clearRequest() {
+ if (requestBuilder_ == null) {
+ request_ = org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketRequestMessage.getDefaultInstance();
+ onChanged();
+ } else {
+ requestBuilder_.clear();
+ }
+ bitField0_ = (bitField0_ & ~0x00000002);
+ return this;
+ }
+ /**
+ * optional .textsecure.WebSocketRequestMessage request = 2;
+ */
+ public org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketRequestMessage.Builder getRequestBuilder() {
+ bitField0_ |= 0x00000002;
+ onChanged();
+ return getRequestFieldBuilder().getBuilder();
+ }
+ /**
+ * optional .textsecure.WebSocketRequestMessage request = 2;
+ */
+ public org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketRequestMessageOrBuilder getRequestOrBuilder() {
+ if (requestBuilder_ != null) {
+ return requestBuilder_.getMessageOrBuilder();
+ } else {
+ return request_;
+ }
+ }
+ /**
+ * optional .textsecure.WebSocketRequestMessage request = 2;
+ */
+ private com.google.protobuf.SingleFieldBuilder<
+ org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketRequestMessage, org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketRequestMessage.Builder, org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketRequestMessageOrBuilder>
+ getRequestFieldBuilder() {
+ if (requestBuilder_ == null) {
+ requestBuilder_ = new com.google.protobuf.SingleFieldBuilder<
+ org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketRequestMessage, org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketRequestMessage.Builder, org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketRequestMessageOrBuilder>(
+ request_,
+ getParentForChildren(),
+ isClean());
+ request_ = null;
+ }
+ return requestBuilder_;
+ }
+
+ // optional .textsecure.WebSocketResponseMessage response = 3;
+ private org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketResponseMessage response_ = org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketResponseMessage.getDefaultInstance();
+ private com.google.protobuf.SingleFieldBuilder<
+ org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketResponseMessage, org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketResponseMessage.Builder, org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketResponseMessageOrBuilder> responseBuilder_;
+ /**
+ * optional .textsecure.WebSocketResponseMessage response = 3;
+ */
+ public boolean hasResponse() {
+ return ((bitField0_ & 0x00000004) == 0x00000004);
+ }
+ /**
+ * optional .textsecure.WebSocketResponseMessage response = 3;
+ */
+ public org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketResponseMessage getResponse() {
+ if (responseBuilder_ == null) {
+ return response_;
+ } else {
+ return responseBuilder_.getMessage();
+ }
+ }
+ /**
+ * optional .textsecure.WebSocketResponseMessage response = 3;
+ */
+ public Builder setResponse(org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketResponseMessage value) {
+ if (responseBuilder_ == null) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ response_ = value;
+ onChanged();
+ } else {
+ responseBuilder_.setMessage(value);
+ }
+ bitField0_ |= 0x00000004;
+ return this;
+ }
+ /**
+ * optional .textsecure.WebSocketResponseMessage response = 3;
+ */
+ public Builder setResponse(
+ org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketResponseMessage.Builder builderForValue) {
+ if (responseBuilder_ == null) {
+ response_ = builderForValue.build();
+ onChanged();
+ } else {
+ responseBuilder_.setMessage(builderForValue.build());
+ }
+ bitField0_ |= 0x00000004;
+ return this;
+ }
+ /**
+ * optional .textsecure.WebSocketResponseMessage response = 3;
+ */
+ public Builder mergeResponse(org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketResponseMessage value) {
+ if (responseBuilder_ == null) {
+ if (((bitField0_ & 0x00000004) == 0x00000004) &&
+ response_ != org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketResponseMessage.getDefaultInstance()) {
+ response_ =
+ org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketResponseMessage.newBuilder(response_).mergeFrom(value).buildPartial();
+ } else {
+ response_ = value;
+ }
+ onChanged();
+ } else {
+ responseBuilder_.mergeFrom(value);
+ }
+ bitField0_ |= 0x00000004;
+ return this;
+ }
+ /**
+ * optional .textsecure.WebSocketResponseMessage response = 3;
+ */
+ public Builder clearResponse() {
+ if (responseBuilder_ == null) {
+ response_ = org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketResponseMessage.getDefaultInstance();
+ onChanged();
+ } else {
+ responseBuilder_.clear();
+ }
+ bitField0_ = (bitField0_ & ~0x00000004);
+ return this;
+ }
+ /**
+ * optional .textsecure.WebSocketResponseMessage response = 3;
+ */
+ public org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketResponseMessage.Builder getResponseBuilder() {
+ bitField0_ |= 0x00000004;
+ onChanged();
+ return getResponseFieldBuilder().getBuilder();
+ }
+ /**
+ * optional .textsecure.WebSocketResponseMessage response = 3;
+ */
+ public org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketResponseMessageOrBuilder getResponseOrBuilder() {
+ if (responseBuilder_ != null) {
+ return responseBuilder_.getMessageOrBuilder();
+ } else {
+ return response_;
+ }
+ }
+ /**
+ * optional .textsecure.WebSocketResponseMessage response = 3;
+ */
+ private com.google.protobuf.SingleFieldBuilder<
+ org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketResponseMessage, org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketResponseMessage.Builder, org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketResponseMessageOrBuilder>
+ getResponseFieldBuilder() {
+ if (responseBuilder_ == null) {
+ responseBuilder_ = new com.google.protobuf.SingleFieldBuilder<
+ org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketResponseMessage, org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketResponseMessage.Builder, org.whispersystems.websocket.messages.protobuf.SubProtocol.WebSocketResponseMessageOrBuilder>(
+ response_,
+ getParentForChildren(),
+ isClean());
+ response_ = null;
+ }
+ return responseBuilder_;
+ }
+
+ // @@protoc_insertion_point(builder_scope:textsecure.WebSocketMessage)
+ }
+
+ static {
+ defaultInstance = new WebSocketMessage(true);
+ defaultInstance.initFields();
+ }
+
+ // @@protoc_insertion_point(class_scope:textsecure.WebSocketMessage)
+ }
+
+ private static com.google.protobuf.Descriptors.Descriptor
+ internal_static_textsecure_WebSocketRequestMessage_descriptor;
+ private static
+ com.google.protobuf.GeneratedMessage.FieldAccessorTable
+ internal_static_textsecure_WebSocketRequestMessage_fieldAccessorTable;
+ private static com.google.protobuf.Descriptors.Descriptor
+ internal_static_textsecure_WebSocketResponseMessage_descriptor;
+ private static
+ com.google.protobuf.GeneratedMessage.FieldAccessorTable
+ internal_static_textsecure_WebSocketResponseMessage_fieldAccessorTable;
+ private static com.google.protobuf.Descriptors.Descriptor
+ internal_static_textsecure_WebSocketMessage_descriptor;
+ private static
+ com.google.protobuf.GeneratedMessage.FieldAccessorTable
+ internal_static_textsecure_WebSocketMessage_fieldAccessorTable;
+
+ public static com.google.protobuf.Descriptors.FileDescriptor
+ getDescriptor() {
+ return descriptor;
+ }
+ private static com.google.protobuf.Descriptors.FileDescriptor
+ descriptor;
+ static {
+ java.lang.String[] descriptorData = {
+ "\n\021SubProtocol.proto\022\ntextsecure\"`\n\027WebSo" +
+ "cketRequestMessage\022\014\n\004verb\030\001 \001(\t\022\014\n\004path" +
+ "\030\002 \001(\t\022\017\n\007headers\030\005 \003(\t\022\014\n\004body\030\003 \001(\014\022\n\n" +
+ "\002id\030\004 \001(\004\"f\n\030WebSocketResponseMessage\022\n\n" +
+ "\002id\030\001 \001(\004\022\016\n\006status\030\002 \001(\r\022\017\n\007message\030\003 \001" +
+ "(\t\022\017\n\007headers\030\005 \003(\t\022\014\n\004body\030\004 \001(\014\"\341\001\n\020We" +
+ "bSocketMessage\022/\n\004type\030\001 \001(\0162!.textsecur" +
+ "e.WebSocketMessage.Type\0224\n\007request\030\002 \001(\013" +
+ "2#.textsecure.WebSocketRequestMessage\0226\n" +
+ "\010response\030\003 \001(\0132$.textsecure.WebSocketRe",
+ "sponseMessage\".\n\004Type\022\013\n\007UNKNOWN\020\000\022\013\n\007RE" +
+ "QUEST\020\001\022\014\n\010RESPONSE\020\002B0\n.org.whispersyst" +
+ "ems.websocket.messages.protobuf"
+ };
+ com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
+ new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
+ public com.google.protobuf.ExtensionRegistry assignDescriptors(
+ com.google.protobuf.Descriptors.FileDescriptor root) {
+ descriptor = root;
+ internal_static_textsecure_WebSocketRequestMessage_descriptor =
+ getDescriptor().getMessageTypes().get(0);
+ internal_static_textsecure_WebSocketRequestMessage_fieldAccessorTable = new
+ com.google.protobuf.GeneratedMessage.FieldAccessorTable(
+ internal_static_textsecure_WebSocketRequestMessage_descriptor,
+ new java.lang.String[] { "Verb", "Path", "Headers", "Body", "Id", });
+ internal_static_textsecure_WebSocketResponseMessage_descriptor =
+ getDescriptor().getMessageTypes().get(1);
+ internal_static_textsecure_WebSocketResponseMessage_fieldAccessorTable = new
+ com.google.protobuf.GeneratedMessage.FieldAccessorTable(
+ internal_static_textsecure_WebSocketResponseMessage_descriptor,
+ new java.lang.String[] { "Id", "Status", "Message", "Headers", "Body", });
+ internal_static_textsecure_WebSocketMessage_descriptor =
+ getDescriptor().getMessageTypes().get(2);
+ internal_static_textsecure_WebSocketMessage_fieldAccessorTable = new
+ com.google.protobuf.GeneratedMessage.FieldAccessorTable(
+ internal_static_textsecure_WebSocketMessage_descriptor,
+ new java.lang.String[] { "Type", "Request", "Response", });
+ return null;
+ }
+ };
+ com.google.protobuf.Descriptors.FileDescriptor
+ .internalBuildGeneratedFileFrom(descriptorData,
+ new com.google.protobuf.Descriptors.FileDescriptor[] {
+ }, assigner);
+ }
+
+ // @@protoc_insertion_point(outer_class_scope)
+}
diff --git a/websocket-resources/src/main/java/org/whispersystems/websocket/servlet/BufferingServletInputStream.java b/websocket-resources/src/main/java/org/whispersystems/websocket/servlet/BufferingServletInputStream.java
new file mode 100644
index 000000000..c35070857
--- /dev/null
+++ b/websocket-resources/src/main/java/org/whispersystems/websocket/servlet/BufferingServletInputStream.java
@@ -0,0 +1,66 @@
+/**
+ * Copyright (C) 2014 Open WhisperSystems
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see Encodes and decodes to and from Base64 notation.
+ *Homepage: http://iharder.net/base64.
+ * + *Example:
+ * + *String encoded = Base64.encode( myByteArray );
+ * byte[] myByteArray = Base64.decode( encoded );
+ *
+ * The options parameter, which appears in a few places, is used to pass + * several pieces of information to the encoder. In the "higher level" methods such as + * encodeBytes( bytes, options ) the options parameter can be used to indicate such + * things as first gzipping the bytes before encoding them, not inserting linefeeds, + * and encoding using the URL-safe and Ordered dialects.
+ * + *Note, according to RFC3548, + * Section 2.1, implementations should not add line feeds unless explicitly told + * to do so. I've got Base64 set to this behavior now, although earlier versions + * broke lines by default.
+ * + *The constants defined in Base64 can be OR-ed together to combine options, so you + * might make a call like this:
+ * + *String encoded = Base64.encodeBytes( mybytes, Base64.GZIP | Base64.DO_BREAK_LINES );
+ * to compress the data before encoding it and then making the output have newline characters.
+ *Also...
+ *String encoded = Base64.encodeBytes( crazyString.getBytes() );
+ *
+ *
+ *
+ * + * Change Log: + *
+ *+ * I am placing this code in the Public Domain. Do with it as you will. + * This software comes with no guarantees or warranties but with + * plenty of well-wishing instead! + * Please visit http://iharder.net/base64 + * periodically to check for updates or to contribute improvements. + *
+ * + * @author Robert Harder + * @author rob@iharder.net + * @version 2.3.3 + */ +public class Base64 +{ + +/* ******** P U B L I C F I E L D S ******** */ + + + /** No options specified. Value is zero. */ + public final static int NO_OPTIONS = 0; + + /** Specify encoding in first bit. Value is one. */ + public final static int ENCODE = 1; + + + /** Specify decoding in first bit. Value is zero. */ + public final static int DECODE = 0; + + + /** Specify that data should be gzip-compressed in second bit. Value is two. */ + public final static int GZIP = 2; + + /** Specify that gzipped data should not be automatically gunzipped. */ + public final static int DONT_GUNZIP = 4; + + + /** Do break lines when encoding. Value is 8. */ + public final static int DO_BREAK_LINES = 8; + + /** + * Encode using Base64-like encoding that is URL- and Filename-safe as described + * in Section 4 of RFC3548: + * http://www.faqs.org/rfcs/rfc3548.html. + * It is important to note that data encoded this way is not officially valid Base64, + * or at the very least should not be called Base64 without also specifying that is + * was encoded using the URL- and Filename-safe dialect. + */ + public final static int URL_SAFE = 16; + + + /** + * Encode using the special "ordered" dialect of Base64 described here: + * http://www.faqs.org/qa/rfcc-1940.html. + */ + public final static int ORDERED = 32; + + +/* ******** P R I V A T E F I E L D S ******** */ + + + /** Maximum line length (76) of Base64 output. */ + private final static int MAX_LINE_LENGTH = 76; + + + /** The equals sign (=) as a byte. */ + private final static byte EQUALS_SIGN = (byte)'='; + + + /** The new line character (\n) as a byte. */ + private final static byte NEW_LINE = (byte)'\n'; + + + /** Preferred encoding. */ + private final static String PREFERRED_ENCODING = "US-ASCII"; + + + private final static byte WHITE_SPACE_ENC = -5; // Indicates white space in encoding + private final static byte EQUALS_SIGN_ENC = -1; // Indicates equals sign in encoding + + +/* ******** S T A N D A R D B A S E 6 4 A L P H A B E T ******** */ + + /** The 64 valid Base64 values. */ + /* Host platform me be something funny like EBCDIC, so we hardcode these values. */ + private final static byte[] _STANDARD_ALPHABET = { + (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G', + (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N', + (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U', + (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z', + (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g', + (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n', + (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u', + (byte)'v', (byte)'w', (byte)'x', (byte)'y', (byte)'z', + (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', + (byte)'6', (byte)'7', (byte)'8', (byte)'9', (byte)'+', (byte)'/' + }; + + + /** + * Translates a Base64 value to either its 6-bit reconstruction value + * or a negative number indicating some other meaning. + **/ + private final static byte[] _STANDARD_DECODABET = { + -9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 0 - 8 + -5,-5, // Whitespace: Tab and Linefeed + -9,-9, // Decimal 11 - 12 + -5, // Whitespace: Carriage Return + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 14 - 26 + -9,-9,-9,-9,-9, // Decimal 27 - 31 + -5, // Whitespace: Space + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 33 - 42 + 62, // Plus sign at decimal 43 + -9,-9,-9, // Decimal 44 - 46 + 63, // Slash at decimal 47 + 52,53,54,55,56,57,58,59,60,61, // Numbers zero through nine + -9,-9,-9, // Decimal 58 - 60 + -1, // Equals sign at decimal 61 + -9,-9,-9, // Decimal 62 - 64 + 0,1,2,3,4,5,6,7,8,9,10,11,12,13, // Letters 'A' through 'N' + 14,15,16,17,18,19,20,21,22,23,24,25, // Letters 'O' through 'Z' + -9,-9,-9,-9,-9,-9, // Decimal 91 - 96 + 26,27,28,29,30,31,32,33,34,35,36,37,38, // Letters 'a' through 'm' + 39,40,41,42,43,44,45,46,47,48,49,50,51, // Letters 'n' through 'z' + -9,-9,-9,-9 // Decimal 123 - 126 + /*,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 127 - 139 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255 */ + }; + + +/* ******** U R L S A F E B A S E 6 4 A L P H A B E T ******** */ + + /** + * Used in the URL- and Filename-safe dialect described in Section 4 of RFC3548: + * http://www.faqs.org/rfcs/rfc3548.html. + * Notice that the last two bytes become "hyphen" and "underscore" instead of "plus" and "slash." + */ + private final static byte[] _URL_SAFE_ALPHABET = { + (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G', + (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N', + (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U', + (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z', + (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g', + (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n', + (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u', + (byte)'v', (byte)'w', (byte)'x', (byte)'y', (byte)'z', + (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', + (byte)'6', (byte)'7', (byte)'8', (byte)'9', (byte)'-', (byte)'_' + }; + + /** + * Used in decoding URL- and Filename-safe dialects of Base64. + */ + private final static byte[] _URL_SAFE_DECODABET = { + -9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 0 - 8 + -5,-5, // Whitespace: Tab and Linefeed + -9,-9, // Decimal 11 - 12 + -5, // Whitespace: Carriage Return + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 14 - 26 + -9,-9,-9,-9,-9, // Decimal 27 - 31 + -5, // Whitespace: Space + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 33 - 42 + -9, // Plus sign at decimal 43 + -9, // Decimal 44 + 62, // Minus sign at decimal 45 + -9, // Decimal 46 + -9, // Slash at decimal 47 + 52,53,54,55,56,57,58,59,60,61, // Numbers zero through nine + -9,-9,-9, // Decimal 58 - 60 + -1, // Equals sign at decimal 61 + -9,-9,-9, // Decimal 62 - 64 + 0,1,2,3,4,5,6,7,8,9,10,11,12,13, // Letters 'A' through 'N' + 14,15,16,17,18,19,20,21,22,23,24,25, // Letters 'O' through 'Z' + -9,-9,-9,-9, // Decimal 91 - 94 + 63, // Underscore at decimal 95 + -9, // Decimal 96 + 26,27,28,29,30,31,32,33,34,35,36,37,38, // Letters 'a' through 'm' + 39,40,41,42,43,44,45,46,47,48,49,50,51, // Letters 'n' through 'z' + -9,-9,-9,-9 // Decimal 123 - 126 + /*,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 127 - 139 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255 */ + }; + + + +/* ******** O R D E R E D B A S E 6 4 A L P H A B E T ******** */ + + /** + * I don't get the point of this technique, but someone requested it, + * and it is described here: + * http://www.faqs.org/qa/rfcc-1940.html. + */ + private final static byte[] _ORDERED_ALPHABET = { + (byte)'-', + (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', + (byte)'5', (byte)'6', (byte)'7', (byte)'8', (byte)'9', + (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G', + (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N', + (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U', + (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z', + (byte)'_', + (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g', + (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n', + (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u', + (byte)'v', (byte)'w', (byte)'x', (byte)'y', (byte)'z' + }; + + /** + * Used in decoding the "ordered" dialect of Base64. + */ + private final static byte[] _ORDERED_DECODABET = { + -9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 0 - 8 + -5,-5, // Whitespace: Tab and Linefeed + -9,-9, // Decimal 11 - 12 + -5, // Whitespace: Carriage Return + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 14 - 26 + -9,-9,-9,-9,-9, // Decimal 27 - 31 + -5, // Whitespace: Space + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 33 - 42 + -9, // Plus sign at decimal 43 + -9, // Decimal 44 + 0, // Minus sign at decimal 45 + -9, // Decimal 46 + -9, // Slash at decimal 47 + 1,2,3,4,5,6,7,8,9,10, // Numbers zero through nine + -9,-9,-9, // Decimal 58 - 60 + -1, // Equals sign at decimal 61 + -9,-9,-9, // Decimal 62 - 64 + 11,12,13,14,15,16,17,18,19,20,21,22,23, // Letters 'A' through 'M' + 24,25,26,27,28,29,30,31,32,33,34,35,36, // Letters 'N' through 'Z' + -9,-9,-9,-9, // Decimal 91 - 94 + 37, // Underscore at decimal 95 + -9, // Decimal 96 + 38,39,40,41,42,43,44,45,46,47,48,49,50, // Letters 'a' through 'm' + 51,52,53,54,55,56,57,58,59,60,61,62,63, // Letters 'n' through 'z' + -9,-9,-9,-9 // Decimal 123 - 126 + /*,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 127 - 139 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255 */ + }; + + +/* ******** D E T E R M I N E W H I C H A L H A B E T ******** */ + + + /** + * Returns one of the _SOMETHING_ALPHABET byte arrays depending on + * the options specified. + * It's possible, though silly, to specify ORDERED and URLSAFE + * in which case one of them will be picked, though there is + * no guarantee as to which one will be picked. + */ + private final static byte[] getAlphabet( int options ) { + if ((options & URL_SAFE) == URL_SAFE) { + return _URL_SAFE_ALPHABET; + } else if ((options & ORDERED) == ORDERED) { + return _ORDERED_ALPHABET; + } else { + return _STANDARD_ALPHABET; + } + } // end getAlphabet + + + /** + * Returns one of the _SOMETHING_DECODABET byte arrays depending on + * the options specified. + * It's possible, though silly, to specify ORDERED and URL_SAFE + * in which case one of them will be picked, though there is + * no guarantee as to which one will be picked. + */ + private final static byte[] getDecodabet( int options ) { + if( (options & URL_SAFE) == URL_SAFE) { + return _URL_SAFE_DECODABET; + } else if ((options & ORDERED) == ORDERED) { + return _ORDERED_DECODABET; + } else { + return _STANDARD_DECODABET; + } + } // end getAlphabet + + + + /** Defeats instantiation. */ + private Base64(){} + + + + public static int getEncodedLengthWithoutPadding(int unencodedLength) { + int remainderBytes = unencodedLength % 3; + int paddingBytes = 0; + + if (remainderBytes != 0) + paddingBytes = 3 - remainderBytes; + + return (((int)((unencodedLength+2)/3))*4) - paddingBytes; + } + + public static int getEncodedBytesForTarget(int targetSize) { + return ((int)(targetSize * 3)) / 4; + } + + +/* ******** E N C O D I N G M E T H O D S ******** */ + + + /** + * Encodes up to the first three bytes of array threeBytes + * and returns a four-byte array in Base64 notation. + * The actual number of significant bytes in your array is + * given by numSigBytes. + * The array threeBytes needs only be as big as + * numSigBytes. + * Code can reuse a byte array by passing a four-byte array as b4. + * + * @param b4 A reusable byte array to reduce array instantiation + * @param threeBytes the array to convert + * @param numSigBytes the number of significant bytes in your array + * @return four byte array in Base64 notation. + * @since 1.5.1 + */ + private static byte[] encode3to4( byte[] b4, byte[] threeBytes, int numSigBytes, int options ) { + encode3to4( threeBytes, 0, numSigBytes, b4, 0, options ); + return b4; + } // end encode3to4 + + + /** + *Encodes up to three bytes of the array source + * and writes the resulting four Base64 bytes to destination. + * The source and destination arrays can be manipulated + * anywhere along their length by specifying + * srcOffset and destOffset. + * This method does not check to make sure your arrays + * are large enough to accomodate srcOffset + 3 for + * the source array or destOffset + 4 for + * the destination array. + * The actual number of significant bytes in your array is + * given by numSigBytes.
+ *This is the lowest level of the encoding methods with + * all possible parameters.
+ * + * @param source the array to convert + * @param srcOffset the index where conversion begins + * @param numSigBytes the number of significant bytes in your array + * @param destination the array to hold the conversion + * @param destOffset the index where output will be put + * @return the destination array + * @since 1.3 + */ + private static byte[] encode3to4( + byte[] source, int srcOffset, int numSigBytes, + byte[] destination, int destOffset, int options ) { + + byte[] ALPHABET = getAlphabet( options ); + + // 1 2 3 + // 01234567890123456789012345678901 Bit position + // --------000000001111111122222222 Array position from threeBytes + // --------| || || || | Six bit groups to index ALPHABET + // >>18 >>12 >> 6 >> 0 Right shift necessary + // 0x3f 0x3f 0x3f Additional AND + + // Create buffer with zero-padding if there are only one or two + // significant bytes passed in the array. + // We have to shift left 24 in order to flush out the 1's that appear + // when Java treats a value as negative that is cast from a byte to an int. + int inBuff = ( numSigBytes > 0 ? ((source[ srcOffset ] << 24) >>> 8) : 0 ) + | ( numSigBytes > 1 ? ((source[ srcOffset + 1 ] << 24) >>> 16) : 0 ) + | ( numSigBytes > 2 ? ((source[ srcOffset + 2 ] << 24) >>> 24) : 0 ); + + switch( numSigBytes ) + { + case 3: + destination[ destOffset ] = ALPHABET[ (inBuff >>> 18) ]; + destination[ destOffset + 1 ] = ALPHABET[ (inBuff >>> 12) & 0x3f ]; + destination[ destOffset + 2 ] = ALPHABET[ (inBuff >>> 6) & 0x3f ]; + destination[ destOffset + 3 ] = ALPHABET[ (inBuff ) & 0x3f ]; + return destination; + + case 2: + destination[ destOffset ] = ALPHABET[ (inBuff >>> 18) ]; + destination[ destOffset + 1 ] = ALPHABET[ (inBuff >>> 12) & 0x3f ]; + destination[ destOffset + 2 ] = ALPHABET[ (inBuff >>> 6) & 0x3f ]; + destination[ destOffset + 3 ] = EQUALS_SIGN; + return destination; + + case 1: + destination[ destOffset ] = ALPHABET[ (inBuff >>> 18) ]; + destination[ destOffset + 1 ] = ALPHABET[ (inBuff >>> 12) & 0x3f ]; + destination[ destOffset + 2 ] = EQUALS_SIGN; + destination[ destOffset + 3 ] = EQUALS_SIGN; + return destination; + + default: + return destination; + } // end switch + } // end encode3to4 + + + + /** + * Performs Base64 encoding on theraw
ByteBuffer,
+ * writing it to the encoded
ByteBuffer.
+ * This is an experimental feature. Currently it does not
+ * pass along any options (such as {@link #DO_BREAK_LINES}
+ * or {@link #GZIP}.
+ *
+ * @param raw input buffer
+ * @param encoded output buffer
+ * @since 2.3
+ */
+ public static void encode( java.nio.ByteBuffer raw, java.nio.ByteBuffer encoded ){
+ byte[] raw3 = new byte[3];
+ byte[] enc4 = new byte[4];
+
+ while( raw.hasRemaining() ){
+ int rem = Math.min(3,raw.remaining());
+ raw.get(raw3,0,rem);
+ Base64.encode3to4(enc4, raw3, rem, Base64.NO_OPTIONS );
+ encoded.put(enc4);
+ } // end input remaining
+ }
+
+
+ /**
+ * Performs Base64 encoding on the raw
ByteBuffer,
+ * writing it to the encoded
CharBuffer.
+ * This is an experimental feature. Currently it does not
+ * pass along any options (such as {@link #DO_BREAK_LINES}
+ * or {@link #GZIP}.
+ *
+ * @param raw input buffer
+ * @param encoded output buffer
+ * @since 2.3
+ */
+ public static void encode( java.nio.ByteBuffer raw, java.nio.CharBuffer encoded ){
+ byte[] raw3 = new byte[3];
+ byte[] enc4 = new byte[4];
+
+ while( raw.hasRemaining() ){
+ int rem = Math.min(3,raw.remaining());
+ raw.get(raw3,0,rem);
+ Base64.encode3to4(enc4, raw3, rem, Base64.NO_OPTIONS );
+ for( int i = 0; i < 4; i++ ){
+ encoded.put( (char)(enc4[i] & 0xFF) );
+ }
+ } // end input remaining
+ }
+
+
+
+
+ /**
+ * Serializes an object and returns the Base64-encoded
+ * version of that serialized object.
+ *
+ * As of v 2.3, if the object + * cannot be serialized or there is another error, + * the method will throw an java.io.IOException. This is new to v2.3! + * In earlier versions, it just returned a null value, but + * in retrospect that's a pretty poor way to handle it.
+ * + * The object is not GZip-compressed before being encoded. + * + * @param serializableObject The object to encode + * @return The Base64-encoded object + * @throws java.io.IOException if there is an error + * @throws NullPointerException if serializedObject is null + * @since 1.4 + */ + public static String encodeObject( java.io.Serializable serializableObject ) + throws java.io.IOException { + return encodeObject( serializableObject, NO_OPTIONS ); + } // end encodeObject + + + + /** + * Serializes an object and returns the Base64-encoded + * version of that serialized object. + * + *As of v 2.3, if the object + * cannot be serialized or there is another error, + * the method will throw an java.io.IOException. This is new to v2.3! + * In earlier versions, it just returned a null value, but + * in retrospect that's a pretty poor way to handle it.
+ * + * The object is not GZip-compressed before being encoded. + *+ * Example options:
+ * GZIP: gzip-compresses object before encoding it. + * DO_BREAK_LINES: break lines at 76 characters + *+ *
+ * Example: encodeObject( myObj, Base64.GZIP )
or
+ *
+ * Example: encodeObject( myObj, Base64.GZIP | Base64.DO_BREAK_LINES )
+ *
+ * @param serializableObject The object to encode
+ * @param options Specified options
+ * @return The Base64-encoded object
+ * @see Base64#GZIP
+ * @see Base64#DO_BREAK_LINES
+ * @throws java.io.IOException if there is an error
+ * @since 2.0
+ */
+ public static String encodeObject( java.io.Serializable serializableObject, int options )
+ throws java.io.IOException {
+
+ if( serializableObject == null ){
+ throw new NullPointerException( "Cannot serialize a null object." );
+ } // end if: null
+
+ // Streams
+ java.io.ByteArrayOutputStream baos = null;
+ java.io.OutputStream b64os = null;
+ java.util.zip.GZIPOutputStream gzos = null;
+ java.io.ObjectOutputStream oos = null;
+
+
+ try {
+ // ObjectOutputStream -> (GZIP) -> Base64 -> ByteArrayOutputStream
+ baos = new java.io.ByteArrayOutputStream();
+ b64os = new Base64.OutputStream( baos, ENCODE | options );
+ if( (options & GZIP) != 0 ){
+ // Gzip
+ gzos = new java.util.zip.GZIPOutputStream(b64os);
+ oos = new java.io.ObjectOutputStream( gzos );
+ } else {
+ // Not gzipped
+ oos = new java.io.ObjectOutputStream( b64os );
+ }
+ oos.writeObject( serializableObject );
+ } // end try
+ catch( java.io.IOException e ) {
+ // Catch it and then throw it immediately so that
+ // the finally{} block is called for cleanup.
+ throw e;
+ } // end catch
+ finally {
+ try{ oos.close(); } catch( Exception e ){}
+ try{ gzos.close(); } catch( Exception e ){}
+ try{ b64os.close(); } catch( Exception e ){}
+ try{ baos.close(); } catch( Exception e ){}
+ } // end finally
+
+ // Return value according to relevant encoding.
+ try {
+ return new String( baos.toByteArray(), PREFERRED_ENCODING );
+ } // end try
+ catch (java.io.UnsupportedEncodingException uue){
+ // Fall back to some Java default
+ return new String( baos.toByteArray() );
+ } // end catch
+
+ } // end encode
+
+
+
+ /**
+ * Encodes a byte array into Base64 notation.
+ * Does not GZip-compress data.
+ *
+ * @param source The data to convert
+ * @return The data in Base64-encoded form
+ * @throws NullPointerException if source array is null
+ * @since 1.4
+ */
+ public static String encodeBytes( byte[] source ) {
+ // Since we're not going to have the GZIP encoding turned on,
+ // we're not going to have an java.io.IOException thrown, so
+ // we should not force the user to have to catch it.
+ String encoded = null;
+ try {
+ encoded = encodeBytes(source, 0, source.length, NO_OPTIONS);
+ } catch (java.io.IOException ex) {
+ assert false : ex.getMessage();
+ } // end catch
+ assert encoded != null;
+ return encoded;
+ } // end encodeBytes
+
+
+ public static String encodeBytesWithoutPadding(byte[] source, int offset, int length) {
+ String encoded = null;
+
+ try {
+ encoded = encodeBytes(source, offset, length, NO_OPTIONS);
+ } catch (java.io.IOException ex) {
+ assert false : ex.getMessage();
+ }
+
+ assert encoded != null;
+
+ if (encoded.charAt(encoded.length()-2) == '=') return encoded.substring(0, encoded.length()-2);
+ else if (encoded.charAt(encoded.length()-1) == '=') return encoded.substring(0, encoded.length()-1);
+ else return encoded;
+
+ }
+
+ public static String encodeBytesWithoutPadding(byte[] source) {
+ return encodeBytesWithoutPadding(source, 0, source.length);
+ }
+
+
+ /**
+ * Encodes a byte array into Base64 notation.
+ *
+ * Example options:
+ * GZIP: gzip-compresses object before encoding it. + * DO_BREAK_LINES: break lines at 76 characters + * Note: Technically, this makes your encoding non-compliant. + *+ *
+ * Example: encodeBytes( myData, Base64.GZIP )
or
+ *
+ * Example: encodeBytes( myData, Base64.GZIP | Base64.DO_BREAK_LINES )
+ *
+ *
+ *
As of v 2.3, if there is an error with the GZIP stream, + * the method will throw an java.io.IOException. This is new to v2.3! + * In earlier versions, it just returned a null value, but + * in retrospect that's a pretty poor way to handle it.
+ * + * + * @param source The data to convert + * @param options Specified options + * @return The Base64-encoded data as a String + * @see Base64#GZIP + * @see Base64#DO_BREAK_LINES + * @throws java.io.IOException if there is an error + * @throws NullPointerException if source array is null + * @since 2.0 + */ + public static String encodeBytes( byte[] source, int options ) throws java.io.IOException { + return encodeBytes( source, 0, source.length, options ); + } // end encodeBytes + + + /** + * Encodes a byte array into Base64 notation. + * Does not GZip-compress data. + * + *As of v 2.3, if there is an error, + * the method will throw an java.io.IOException. This is new to v2.3! + * In earlier versions, it just returned a null value, but + * in retrospect that's a pretty poor way to handle it.
+ * + * + * @param source The data to convert + * @param off Offset in array where conversion should begin + * @param len Length of data to convert + * @return The Base64-encoded data as a String + * @throws NullPointerException if source array is null + * @throws IllegalArgumentException if source array, offset, or length are invalid + * @since 1.4 + */ + public static String encodeBytes( byte[] source, int off, int len ) { + // Since we're not going to have the GZIP encoding turned on, + // we're not going to have an java.io.IOException thrown, so + // we should not force the user to have to catch it. + String encoded = null; + try { + encoded = encodeBytes( source, off, len, NO_OPTIONS ); + } catch (java.io.IOException ex) { + assert false : ex.getMessage(); + } // end catch + assert encoded != null; + return encoded; + } // end encodeBytes + + + + /** + * Encodes a byte array into Base64 notation. + *+ * Example options:
+ * GZIP: gzip-compresses object before encoding it. + * DO_BREAK_LINES: break lines at 76 characters + * Note: Technically, this makes your encoding non-compliant. + *+ *
+ * Example: encodeBytes( myData, Base64.GZIP )
or
+ *
+ * Example: encodeBytes( myData, Base64.GZIP | Base64.DO_BREAK_LINES )
+ *
+ *
+ *
As of v 2.3, if there is an error with the GZIP stream, + * the method will throw an java.io.IOException. This is new to v2.3! + * In earlier versions, it just returned a null value, but + * in retrospect that's a pretty poor way to handle it.
+ * + * + * @param source The data to convert + * @param off Offset in array where conversion should begin + * @param len Length of data to convert + * @param options Specified options + * @return The Base64-encoded data as a String + * @see Base64#GZIP + * @see Base64#DO_BREAK_LINES + * @throws java.io.IOException if there is an error + * @throws NullPointerException if source array is null + * @throws IllegalArgumentException if source array, offset, or length are invalid + * @since 2.0 + */ + public static String encodeBytes( byte[] source, int off, int len, int options ) throws java.io.IOException { + byte[] encoded = encodeBytesToBytes( source, off, len, options ); + + // Return value according to relevant encoding. + try { + return new String( encoded, PREFERRED_ENCODING ); + } // end try + catch (java.io.UnsupportedEncodingException uue) { + return new String( encoded ); + } // end catch + + } // end encodeBytes + + + + + /** + * Similar to {@link #encodeBytes(byte[])} but returns + * a byte array instead of instantiating a String. This is more efficient + * if you're working with I/O streams and have large data sets to encode. + * + * + * @param source The data to convert + * @return The Base64-encoded data as a byte[] (of ASCII characters) + * @throws NullPointerException if source array is null + * @since 2.3.1 + */ + public static byte[] encodeBytesToBytes( byte[] source ) { + byte[] encoded = null; + try { + encoded = encodeBytesToBytes( source, 0, source.length, Base64.NO_OPTIONS ); + } catch( java.io.IOException ex ) { + assert false : "IOExceptions only come from GZipping, which is turned off: " + ex.getMessage(); + } + return encoded; + } + + + /** + * Similar to {@link #encodeBytes(byte[], int, int, int)} but returns + * a byte array instead of instantiating a String. This is more efficient + * if you're working with I/O streams and have large data sets to encode. + * + * + * @param source The data to convert + * @param off Offset in array where conversion should begin + * @param len Length of data to convert + * @param options Specified options + * @return The Base64-encoded data as a String + * @see Base64#GZIP + * @see Base64#DO_BREAK_LINES + * @throws java.io.IOException if there is an error + * @throws NullPointerException if source array is null + * @throws IllegalArgumentException if source array, offset, or length are invalid + * @since 2.3.1 + */ + public static byte[] encodeBytesToBytes( byte[] source, int off, int len, int options ) throws java.io.IOException { + + if( source == null ){ + throw new NullPointerException( "Cannot serialize a null array." ); + } // end if: null + + if( off < 0 ){ + throw new IllegalArgumentException( "Cannot have negative offset: " + off ); + } // end if: off < 0 + + if( len < 0 ){ + throw new IllegalArgumentException( "Cannot have length offset: " + len ); + } // end if: len < 0 + + if( off + len > source.length ){ + throw new IllegalArgumentException( + String.format( "Cannot have offset of %d and length of %d with array of length %d", off,len,source.length)); + } // end if: off < 0 + + + + // Compress? + if( (options & GZIP) != 0 ) { + java.io.ByteArrayOutputStream baos = null; + java.util.zip.GZIPOutputStream gzos = null; + Base64.OutputStream b64os = null; + + try { + // GZip -> Base64 -> ByteArray + baos = new java.io.ByteArrayOutputStream(); + b64os = new Base64.OutputStream( baos, ENCODE | options ); + gzos = new java.util.zip.GZIPOutputStream( b64os ); + + gzos.write( source, off, len ); + gzos.close(); + } // end try + catch( java.io.IOException e ) { + // Catch it and then throw it immediately so that + // the finally{} block is called for cleanup. + throw e; + } // end catch + finally { + try{ gzos.close(); } catch( Exception e ){} + try{ b64os.close(); } catch( Exception e ){} + try{ baos.close(); } catch( Exception e ){} + } // end finally + + return baos.toByteArray(); + } // end if: compress + + // Else, don't compress. Better not to use streams at all then. + else { + boolean breakLines = (options & DO_BREAK_LINES) > 0; + + //int len43 = len * 4 / 3; + //byte[] outBuff = new byte[ ( len43 ) // Main 4:3 + // + ( (len % 3) > 0 ? 4 : 0 ) // Account for padding + // + (breakLines ? ( len43 / MAX_LINE_LENGTH ) : 0) ]; // New lines + // Try to determine more precisely how big the array needs to be. + // If we get it right, we don't have to do an array copy, and + // we save a bunch of memory. + int encLen = ( len / 3 ) * 4 + ( len % 3 > 0 ? 4 : 0 ); // Bytes needed for actual encoding + if( breakLines ){ + encLen += encLen / MAX_LINE_LENGTH; // Plus extra newline characters + } + byte[] outBuff = new byte[ encLen ]; + + + int d = 0; + int e = 0; + int len2 = len - 2; + int lineLength = 0; + for( ; d < len2; d+=3, e+=4 ) { + encode3to4( source, d+off, 3, outBuff, e, options ); + + lineLength += 4; + if( breakLines && lineLength >= MAX_LINE_LENGTH ) + { + outBuff[e+4] = NEW_LINE; + e++; + lineLength = 0; + } // end if: end of line + } // en dfor: each piece of array + + if( d < len ) { + encode3to4( source, d+off, len - d, outBuff, e, options ); + e += 4; + } // end if: some padding needed + + + // Only resize array if we didn't guess it right. + if( e < outBuff.length - 1 ){ + byte[] finalOut = new byte[e]; + System.arraycopy(outBuff,0, finalOut,0,e); + //System.err.println("Having to resize array from " + outBuff.length + " to " + e ); + return finalOut; + } else { + //System.err.println("No need to resize array."); + return outBuff; + } + + } // end else: don't compress + + } // end encodeBytesToBytes + + + + + +/* ******** D E C O D I N G M E T H O D S ******** */ + + + /** + * Decodes four bytes from array source + * and writes the resulting bytes (up to three of them) + * to destination. + * The source and destination arrays can be manipulated + * anywhere along their length by specifying + * srcOffset and destOffset. + * This method does not check to make sure your arrays + * are large enough to accomodate srcOffset + 4 for + * the source array or destOffset + 3 for + * the destination array. + * This method returns the actual number of bytes that + * were converted from the Base64 encoding. + *This is the lowest level of the decoding methods with + * all possible parameters.
+ * + * + * @param source the array to convert + * @param srcOffset the index where conversion begins + * @param destination the array to hold the conversion + * @param destOffset the index where output will be put + * @param options alphabet type is pulled from this (standard, url-safe, ordered) + * @return the number of decoded bytes converted + * @throws NullPointerException if source or destination arrays are null + * @throws IllegalArgumentException if srcOffset or destOffset are invalid + * or there is not enough room in the array. + * @since 1.3 + */ + private static int decode4to3( + byte[] source, int srcOffset, + byte[] destination, int destOffset, int options ) { + + // Lots of error checking and exception throwing + if( source == null ){ + throw new NullPointerException( "Source array was null." ); + } // end if + if( destination == null ){ + throw new NullPointerException( "Destination array was null." ); + } // end if + if( srcOffset < 0 || srcOffset + 3 >= source.length ){ + throw new IllegalArgumentException( String.format( + "Source array with length %d cannot have offset of %d and still process four bytes.", source.length, srcOffset ) ); + } // end if + if( destOffset < 0 || destOffset +2 >= destination.length ){ + throw new IllegalArgumentException( String.format( + "Destination array with length %d cannot have offset of %d and still store three bytes.", destination.length, destOffset ) ); + } // end if + + + byte[] DECODABET = getDecodabet( options ); + + // Example: Dk== + if( source[ srcOffset + 2] == EQUALS_SIGN ) { + // Two ways to do the same thing. Don't know which way I like best. + //int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 ) + // | ( ( DECODABET[ source[ srcOffset + 1] ] << 24 ) >>> 12 ); + int outBuff = ( ( DECODABET[ source[ srcOffset ] ] & 0xFF ) << 18 ) + | ( ( DECODABET[ source[ srcOffset + 1] ] & 0xFF ) << 12 ); + + destination[ destOffset ] = (byte)( outBuff >>> 16 ); + return 1; + } + + // Example: DkL= + else if( source[ srcOffset + 3 ] == EQUALS_SIGN ) { + // Two ways to do the same thing. Don't know which way I like best. + //int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 ) + // | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 ) + // | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 ); + int outBuff = ( ( DECODABET[ source[ srcOffset ] ] & 0xFF ) << 18 ) + | ( ( DECODABET[ source[ srcOffset + 1 ] ] & 0xFF ) << 12 ) + | ( ( DECODABET[ source[ srcOffset + 2 ] ] & 0xFF ) << 6 ); + + destination[ destOffset ] = (byte)( outBuff >>> 16 ); + destination[ destOffset + 1 ] = (byte)( outBuff >>> 8 ); + return 2; + } + + // Example: DkLE + else { + // Two ways to do the same thing. Don't know which way I like best. + //int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 ) + // | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 ) + // | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 ) + // | ( ( DECODABET[ source[ srcOffset + 3 ] ] << 24 ) >>> 24 ); + int outBuff = ( ( DECODABET[ source[ srcOffset ] ] & 0xFF ) << 18 ) + | ( ( DECODABET[ source[ srcOffset + 1 ] ] & 0xFF ) << 12 ) + | ( ( DECODABET[ source[ srcOffset + 2 ] ] & 0xFF ) << 6) + | ( ( DECODABET[ source[ srcOffset + 3 ] ] & 0xFF ) ); + + + destination[ destOffset ] = (byte)( outBuff >> 16 ); + destination[ destOffset + 1 ] = (byte)( outBuff >> 8 ); + destination[ destOffset + 2 ] = (byte)( outBuff ); + + return 3; + } + } // end decodeToBytes + + + + + + /** + * Low-level access to decoding ASCII characters in + * the form of a byte array. Ignores GUNZIP option, if + * it's set. This is not generally a recommended method, + * although it is used internally as part of the decoding process. + * Special case: if len = 0, an empty array is returned. Still, + * if you need more speed and reduced memory footprint (and aren't + * gzipping), consider this method. + * + * @param source The Base64 encoded data + * @return decoded data + * @since 2.3.1 + */ + public static byte[] decode( byte[] source ){ + byte[] decoded = null; + try { + decoded = decode( source, 0, source.length, Base64.NO_OPTIONS ); + } catch( java.io.IOException ex ) { + assert false : "IOExceptions only come from GZipping, which is turned off: " + ex.getMessage(); + } + return decoded; + } + + + /** + * Low-level access to decoding ASCII characters in + * the form of a byte array. Ignores GUNZIP option, if + * it's set. This is not generally a recommended method, + * although it is used internally as part of the decoding process. + * Special case: if len = 0, an empty array is returned. Still, + * if you need more speed and reduced memory footprint (and aren't + * gzipping), consider this method. + * + * @param source The Base64 encoded data + * @param off The offset of where to begin decoding + * @param len The length of characters to decode + * @param options Can specify options such as alphabet type to use + * @return decoded data + * @throws java.io.IOException If bogus characters exist in source data + * @since 1.3 + */ + public static byte[] decode( byte[] source, int off, int len, int options ) + throws java.io.IOException { + + // Lots of error checking and exception throwing + if( source == null ){ + throw new NullPointerException( "Cannot decode null source array." ); + } // end if + if( off < 0 || off + len > source.length ){ + throw new IllegalArgumentException( String.format( + "Source array with length %d cannot have offset of %d and process %d bytes.", source.length, off, len ) ); + } // end if + + if( len == 0 ){ + return new byte[0]; + }else if( len < 4 ){ + throw new IllegalArgumentException( + "Base64-encoded string must have at least four characters, but length specified was " + len ); + } // end if + + byte[] DECODABET = getDecodabet( options ); + + int len34 = len * 3 / 4; // Estimate on array size + byte[] outBuff = new byte[ len34 ]; // Upper limit on size of output + int outBuffPosn = 0; // Keep track of where we're writing + + byte[] b4 = new byte[4]; // Four byte buffer from source, eliminating white space + int b4Posn = 0; // Keep track of four byte input buffer + int i = 0; // Source array counter + byte sbiCrop = 0; // Low seven bits (ASCII) of input + byte sbiDecode = 0; // Special value from DECODABET + + for( i = off; i < off+len; i++ ) { // Loop through source + + sbiCrop = (byte)(source[i] & 0x7f); // Only the low seven bits + sbiDecode = DECODABET[ sbiCrop ]; // Special value + + // White space, Equals sign, or legit Base64 character + // Note the values such as -5 and -9 in the + // DECODABETs at the top of the file. + if( sbiDecode >= WHITE_SPACE_ENC ) { + if( sbiDecode >= EQUALS_SIGN_ENC ) { + b4[ b4Posn++ ] = sbiCrop; // Save non-whitespace + if( b4Posn > 3 ) { // Time to decode? + outBuffPosn += decode4to3( b4, 0, outBuff, outBuffPosn, options ); + b4Posn = 0; + + // If that was the equals sign, break out of 'for' loop + if( sbiCrop == EQUALS_SIGN ) { + break; + } // end if: equals sign + } // end if: quartet built + } // end if: equals sign or better + } // end if: white space, equals sign or better + else { + // There's a bad input character in the Base64 stream. + throw new java.io.IOException( String.format( + "Bad Base64 input character '%c' in array position %d", source[i], i ) ); + } // end else: + } // each input character + + byte[] out = new byte[ outBuffPosn ]; + System.arraycopy( outBuff, 0, out, 0, outBuffPosn ); + return out; + } // end decode + + + + + /** + * Decodes data from Base64 notation, automatically + * detecting gzip-compressed data and decompressing it. + * + * @param s the string to decode + * @return the decoded data + * @throws java.io.IOException If there is a problem + * @since 1.4 + */ + public static byte[] decode( String s ) throws java.io.IOException { + return decode( s, DONT_GUNZIP ); + } + + + public static byte[] decodeWithoutPadding(String source) throws java.io.IOException { + int padding = source.length() % 4; + + if (padding == 1) source = source + "="; + else if (padding == 2) source = source + "=="; + else if (padding == 3) source = source + "="; + + return decode(source); + } + + + + /** + * Decodes data from Base64 notation, automatically + * detecting gzip-compressed data and decompressing it. + * + * @param s the string to decode + * @param options encode options such as URL_SAFE + * @return the decoded data + * @throws java.io.IOException if there is an error + * @throws NullPointerException if s is null + * @since 1.4 + */ + public static byte[] decode( String s, int options ) throws java.io.IOException { + + if( s == null ){ + throw new NullPointerException( "Input string was null." ); + } // end if + + byte[] bytes; + try { + bytes = s.getBytes( PREFERRED_ENCODING ); + } // end try + catch( java.io.UnsupportedEncodingException uee ) { + bytes = s.getBytes(); + } // end catch + // + + // Decode + bytes = decode( bytes, 0, bytes.length, options ); + + // Check to see if it's gzip-compressed + // GZIP Magic Two-Byte Number: 0x8b1f (35615) + boolean dontGunzip = (options & DONT_GUNZIP) != 0; + if( (bytes != null) && (bytes.length >= 4) && (!dontGunzip) ) { + + int head = ((int)bytes[0] & 0xff) | ((bytes[1] << 8) & 0xff00); + if( java.util.zip.GZIPInputStream.GZIP_MAGIC == head ) { + java.io.ByteArrayInputStream bais = null; + java.util.zip.GZIPInputStream gzis = null; + java.io.ByteArrayOutputStream baos = null; + byte[] buffer = new byte[2048]; + int length = 0; + + try { + baos = new java.io.ByteArrayOutputStream(); + bais = new java.io.ByteArrayInputStream( bytes ); + gzis = new java.util.zip.GZIPInputStream( bais ); + + while( ( length = gzis.read( buffer ) ) >= 0 ) { + baos.write(buffer,0,length); + } // end while: reading input + + // No error? Get new bytes. + bytes = baos.toByteArray(); + + } // end try + catch( java.io.IOException e ) { + e.printStackTrace(); + // Just return originally-decoded bytes + } // end catch + finally { + try{ baos.close(); } catch( Exception e ){} + try{ gzis.close(); } catch( Exception e ){} + try{ bais.close(); } catch( Exception e ){} + } // end finally + + } // end if: gzipped + } // end if: bytes.length >= 2 + + return bytes; + } // end decode + + + + /** + * Attempts to decode Base64 data and deserialize a Java + * Object within. Returns null if there was an error. + * + * @param encodedObject The Base64 data to decode + * @return The decoded and deserialized object + * @throws NullPointerException if encodedObject is null + * @throws java.io.IOException if there is a general error + * @throws ClassNotFoundException if the decoded object is of a + * class that cannot be found by the JVM + * @since 1.5 + */ + public static Object decodeToObject( String encodedObject ) + throws java.io.IOException, ClassNotFoundException { + return decodeToObject(encodedObject,NO_OPTIONS,null); + } + + + /** + * Attempts to decode Base64 data and deserialize a Java + * Object within. Returns null if there was an error. + * If loader is not null, it will be the class loader + * used when deserializing. + * + * @param encodedObject The Base64 data to decode + * @param options Various parameters related to decoding + * @param loader Optional class loader to use in deserializing classes. + * @return The decoded and deserialized object + * @throws NullPointerException if encodedObject is null + * @throws java.io.IOException if there is a general error + * @throws ClassNotFoundException if the decoded object is of a + * class that cannot be found by the JVM + * @since 2.3.4 + */ + public static Object decodeToObject( + String encodedObject, int options, final ClassLoader loader ) + throws java.io.IOException, ClassNotFoundException { + + // Decode and gunzip if necessary + byte[] objBytes = decode( encodedObject, options ); + + java.io.ByteArrayInputStream bais = null; + java.io.ObjectInputStream ois = null; + Object obj = null; + + try { + bais = new java.io.ByteArrayInputStream( objBytes ); + + // If no custom class loader is provided, use Java's builtin OIS. + if( loader == null ){ + ois = new java.io.ObjectInputStream( bais ); + } // end if: no loader provided + + // Else make a customized object input stream that uses + // the provided class loader. + else { + ois = new java.io.ObjectInputStream(bais){ + @Override + public Class> resolveClass(java.io.ObjectStreamClass streamClass) + throws java.io.IOException, ClassNotFoundException { + Class c = Class.forName(streamClass.getName(), false, loader); + if( c == null ){ + return super.resolveClass(streamClass); + } else { + return c; // Class loader knows of this class. + } // end else: not null + } // end resolveClass + }; // end ois + } // end else: no custom class loader + + obj = ois.readObject(); + } // end try + catch( java.io.IOException e ) { + throw e; // Catch and throw in order to execute finally{} + } // end catch + catch( ClassNotFoundException e ) { + throw e; // Catch and throw in order to execute finally{} + } // end catch + finally { + try{ bais.close(); } catch( Exception e ){} + try{ ois.close(); } catch( Exception e ){} + } // end finally + + return obj; + } // end decodeObject + + + + /** + * Convenience method for encoding data to a file. + * + *As of v 2.3, if there is a error, + * the method will throw an java.io.IOException. This is new to v2.3! + * In earlier versions, it just returned false, but + * in retrospect that's a pretty poor way to handle it.
+ * + * @param dataToEncode byte array of data to encode in base64 form + * @param filename Filename for saving encoded data + * @throws java.io.IOException if there is an error + * @throws NullPointerException if dataToEncode is null + * @since 2.1 + */ + public static void encodeToFile( byte[] dataToEncode, String filename ) + throws java.io.IOException { + + if( dataToEncode == null ){ + throw new NullPointerException( "Data to encode was null." ); + } // end iff + + Base64.OutputStream bos = null; + try { + bos = new Base64.OutputStream( + new java.io.FileOutputStream( filename ), Base64.ENCODE ); + bos.write( dataToEncode ); + } // end try + catch( java.io.IOException e ) { + throw e; // Catch and throw to execute finally{} block + } // end catch: java.io.IOException + finally { + try{ bos.close(); } catch( Exception e ){} + } // end finally + + } // end encodeToFile + + + /** + * Convenience method for decoding data to a file. + * + *As of v 2.3, if there is a error, + * the method will throw an java.io.IOException. This is new to v2.3! + * In earlier versions, it just returned false, but + * in retrospect that's a pretty poor way to handle it.
+ * + * @param dataToDecode Base64-encoded data as a string + * @param filename Filename for saving decoded data + * @throws java.io.IOException if there is an error + * @since 2.1 + */ + public static void decodeToFile( String dataToDecode, String filename ) + throws java.io.IOException { + + Base64.OutputStream bos = null; + try{ + bos = new Base64.OutputStream( + new java.io.FileOutputStream( filename ), Base64.DECODE ); + bos.write( dataToDecode.getBytes( PREFERRED_ENCODING ) ); + } // end try + catch( java.io.IOException e ) { + throw e; // Catch and throw to execute finally{} block + } // end catch: java.io.IOException + finally { + try{ bos.close(); } catch( Exception e ){} + } // end finally + + } // end decodeToFile + + + + + /** + * Convenience method for reading a base64-encoded + * file and decoding it. + * + *As of v 2.3, if there is a error, + * the method will throw an java.io.IOException. This is new to v2.3! + * In earlier versions, it just returned false, but + * in retrospect that's a pretty poor way to handle it.
+ * + * @param filename Filename for reading encoded data + * @return decoded byte array + * @throws java.io.IOException if there is an error + * @since 2.1 + */ + public static byte[] decodeFromFile( String filename ) + throws java.io.IOException { + + byte[] decodedData = null; + Base64.InputStream bis = null; + try + { + // Set up some useful variables + java.io.File file = new java.io.File( filename ); + byte[] buffer = null; + int length = 0; + int numBytes = 0; + + // Check for size of file + if( file.length() > Integer.MAX_VALUE ) + { + throw new java.io.IOException( "File is too big for this convenience method (" + file.length() + " bytes)." ); + } // end if: file too big for int index + buffer = new byte[ (int)file.length() ]; + + // Open a stream + bis = new Base64.InputStream( + new java.io.BufferedInputStream( + new java.io.FileInputStream( file ) ), Base64.DECODE ); + + // Read until done + while( ( numBytes = bis.read( buffer, length, 4096 ) ) >= 0 ) { + length += numBytes; + } // end while + + // Save in a variable to return + decodedData = new byte[ length ]; + System.arraycopy( buffer, 0, decodedData, 0, length ); + + } // end try + catch( java.io.IOException e ) { + throw e; // Catch and release to execute finally{} + } // end catch: java.io.IOException + finally { + try{ bis.close(); } catch( Exception e) {} + } // end finally + + return decodedData; + } // end decodeFromFile + + + + /** + * Convenience method for reading a binary file + * and base64-encoding it. + * + *As of v 2.3, if there is a error, + * the method will throw an java.io.IOException. This is new to v2.3! + * In earlier versions, it just returned false, but + * in retrospect that's a pretty poor way to handle it.
+ * + * @param filename Filename for reading binary data + * @return base64-encoded string + * @throws java.io.IOException if there is an error + * @since 2.1 + */ + public static String encodeFromFile( String filename ) + throws java.io.IOException { + + String encodedData = null; + Base64.InputStream bis = null; + try + { + // Set up some useful variables + java.io.File file = new java.io.File( filename ); + byte[] buffer = new byte[ Math.max((int)(file.length() * 1.4),40) ]; // Need max() for math on small files (v2.2.1) + int length = 0; + int numBytes = 0; + + // Open a stream + bis = new Base64.InputStream( + new java.io.BufferedInputStream( + new java.io.FileInputStream( file ) ), Base64.ENCODE ); + + // Read until done + while( ( numBytes = bis.read( buffer, length, 4096 ) ) >= 0 ) { + length += numBytes; + } // end while + + // Save in a variable to return + encodedData = new String( buffer, 0, length, Base64.PREFERRED_ENCODING ); + + } // end try + catch( java.io.IOException e ) { + throw e; // Catch and release to execute finally{} + } // end catch: java.io.IOException + finally { + try{ bis.close(); } catch( Exception e) {} + } // end finally + + return encodedData; + } // end encodeFromFile + + /** + * Reads infile and encodes it to outfile. + * + * @param infile Input file + * @param outfile Output file + * @throws java.io.IOException if there is an error + * @since 2.2 + */ + public static void encodeFileToFile( String infile, String outfile ) + throws java.io.IOException { + + String encoded = Base64.encodeFromFile( infile ); + java.io.OutputStream out = null; + try{ + out = new java.io.BufferedOutputStream( + new java.io.FileOutputStream( outfile ) ); + out.write( encoded.getBytes("US-ASCII") ); // Strict, 7-bit output. + } // end try + catch( java.io.IOException e ) { + throw e; // Catch and release to execute finally{} + } // end catch + finally { + try { out.close(); } + catch( Exception ex ){} + } // end finally + } // end encodeFileToFile + + + /** + * Reads infile and decodes it to outfile. + * + * @param infile Input file + * @param outfile Output file + * @throws java.io.IOException if there is an error + * @since 2.2 + */ + public static void decodeFileToFile( String infile, String outfile ) + throws java.io.IOException { + + byte[] decoded = Base64.decodeFromFile( infile ); + java.io.OutputStream out = null; + try{ + out = new java.io.BufferedOutputStream( + new java.io.FileOutputStream( outfile ) ); + out.write( decoded ); + } // end try + catch( java.io.IOException e ) { + throw e; // Catch and release to execute finally{} + } // end catch + finally { + try { out.close(); } + catch( Exception ex ){} + } // end finally + } // end decodeFileToFile + + + /* ******** I N N E R C L A S S I N P U T S T R E A M ******** */ + + + + /** + * A {@link Base64.InputStream} will read data from another + * java.io.InputStream, given in the constructor, + * and encode/decode to/from Base64 notation on the fly. + * + * @see Base64 + * @since 1.3 + */ + public static class InputStream extends java.io.FilterInputStream { + + private boolean encode; // Encoding or decoding + private int position; // Current position in the buffer + private byte[] buffer; // Small buffer holding converted data + private int bufferLength; // Length of buffer (3 or 4) + private int numSigBytes; // Number of meaningful bytes in the buffer + private int lineLength; + private boolean breakLines; // Break lines at less than 80 characters + private int options; // Record options used to create the stream. + private byte[] decodabet; // Local copies to avoid extra method calls + + + /** + * Constructs a {@link Base64.InputStream} in DECODE mode. + * + * @param in the java.io.InputStream from which to read data. + * @since 1.3 + */ + public InputStream( java.io.InputStream in ) { + this( in, DECODE ); + } // end constructor + + + /** + * Constructs a {@link Base64.InputStream} in + * either ENCODE or DECODE mode. + *+ * Valid options:
+ * ENCODE or DECODE: Encode or Decode as data is read. + * DO_BREAK_LINES: break lines at 76 characters + * (only meaningful when encoding) + *+ *
+ * Example: new Base64.InputStream( in, Base64.DECODE )
+ *
+ *
+ * @param in the java.io.InputStream from which to read data.
+ * @param options Specified options
+ * @see Base64#ENCODE
+ * @see Base64#DECODE
+ * @see Base64#DO_BREAK_LINES
+ * @since 2.0
+ */
+ public InputStream( java.io.InputStream in, int options ) {
+
+ super( in );
+ this.options = options; // Record for later
+ this.breakLines = (options & DO_BREAK_LINES) > 0;
+ this.encode = (options & ENCODE) > 0;
+ this.bufferLength = encode ? 4 : 3;
+ this.buffer = new byte[ bufferLength ];
+ this.position = -1;
+ this.lineLength = 0;
+ this.decodabet = getDecodabet(options);
+ } // end constructor
+
+ /**
+ * Reads enough of the input stream to convert
+ * to/from Base64 and returns the next byte.
+ *
+ * @return next byte
+ * @since 1.3
+ */
+ @Override
+ public int read() throws java.io.IOException {
+
+ // Do we need to get data?
+ if( position < 0 ) {
+ if( encode ) {
+ byte[] b3 = new byte[3];
+ int numBinaryBytes = 0;
+ for( int i = 0; i < 3; i++ ) {
+ int b = in.read();
+
+ // If end of stream, b is -1.
+ if( b >= 0 ) {
+ b3[i] = (byte)b;
+ numBinaryBytes++;
+ } else {
+ break; // out of for loop
+ } // end else: end of stream
+
+ } // end for: each needed input byte
+
+ if( numBinaryBytes > 0 ) {
+ encode3to4( b3, 0, numBinaryBytes, buffer, 0, options );
+ position = 0;
+ numSigBytes = 4;
+ } // end if: got data
+ else {
+ return -1; // Must be end of stream
+ } // end else
+ } // end if: encoding
+
+ // Else decoding
+ else {
+ byte[] b4 = new byte[4];
+ int i = 0;
+ for( i = 0; i < 4; i++ ) {
+ // Read four "meaningful" bytes:
+ int b = 0;
+ do{ b = in.read(); }
+ while( b >= 0 && decodabet[ b & 0x7f ] <= WHITE_SPACE_ENC );
+
+ if( b < 0 ) {
+ break; // Reads a -1 if end of stream
+ } // end if: end of stream
+
+ b4[i] = (byte)b;
+ } // end for: each needed input byte
+
+ if( i == 4 ) {
+ numSigBytes = decode4to3( b4, 0, buffer, 0, options );
+ position = 0;
+ } // end if: got four characters
+ else if( i == 0 ){
+ return -1;
+ } // end else if: also padded correctly
+ else {
+ // Must have broken out from above.
+ throw new java.io.IOException( "Improperly padded Base64 input." );
+ } // end
+
+ } // end else: decode
+ } // end else: get data
+
+ // Got data?
+ if( position >= 0 ) {
+ // End of relevant data?
+ if( /*!encode &&*/ position >= numSigBytes ){
+ return -1;
+ } // end if: got data
+
+ if( encode && breakLines && lineLength >= MAX_LINE_LENGTH ) {
+ lineLength = 0;
+ return '\n';
+ } // end if
+ else {
+ lineLength++; // This isn't important when decoding
+ // but throwing an extra "if" seems
+ // just as wasteful.
+
+ int b = buffer[ position++ ];
+
+ if( position >= bufferLength ) {
+ position = -1;
+ } // end if: end
+
+ return b & 0xFF; // This is how you "cast" a byte that's
+ // intended to be unsigned.
+ } // end else
+ } // end if: position >= 0
+
+ // Else error
+ else {
+ throw new java.io.IOException( "Error in Base64 code reading stream." );
+ } // end else
+ } // end read
+
+
+ /**
+ * Calls {@link #read()} repeatedly until the end of stream
+ * is reached or len bytes are read.
+ * Returns number of bytes read into array or -1 if
+ * end of stream is encountered.
+ *
+ * @param dest array to hold values
+ * @param off offset for array
+ * @param len max number of bytes to read into array
+ * @return bytes read into array or -1 if end of stream is encountered.
+ * @since 1.3
+ */
+ @Override
+ public int read( byte[] dest, int off, int len )
+ throws java.io.IOException {
+ int i;
+ int b;
+ for( i = 0; i < len; i++ ) {
+ b = read();
+
+ if( b >= 0 ) {
+ dest[off + i] = (byte) b;
+ }
+ else if( i == 0 ) {
+ return -1;
+ }
+ else {
+ break; // Out of 'for' loop
+ } // Out of 'for' loop
+ } // end for: each byte read
+ return i;
+ } // end read
+
+ } // end inner class InputStream
+
+
+
+
+
+
+ /* ******** I N N E R C L A S S O U T P U T S T R E A M ******** */
+
+
+
+ /**
+ * A {@link Base64.OutputStream} will write data to another
+ * java.io.OutputStream, given in the constructor,
+ * and encode/decode to/from Base64 notation on the fly.
+ *
+ * @see Base64
+ * @since 1.3
+ */
+ public static class OutputStream extends java.io.FilterOutputStream {
+
+ private boolean encode;
+ private int position;
+ private byte[] buffer;
+ private int bufferLength;
+ private int lineLength;
+ private boolean breakLines;
+ private byte[] b4; // Scratch used in a few places
+ private boolean suspendEncoding;
+ private int options; // Record for later
+ private byte[] decodabet; // Local copies to avoid extra method calls
+
+ /**
+ * Constructs a {@link Base64.OutputStream} in ENCODE mode.
+ *
+ * @param out the java.io.OutputStream to which data will be written.
+ * @since 1.3
+ */
+ public OutputStream( java.io.OutputStream out ) {
+ this( out, ENCODE );
+ } // end constructor
+
+
+ /**
+ * Constructs a {@link Base64.OutputStream} in
+ * either ENCODE or DECODE mode.
+ *
+ * Valid options:
+ * ENCODE or DECODE: Encode or Decode as data is read. + * DO_BREAK_LINES: don't break lines at 76 characters + * (only meaningful when encoding) + *+ *
+ * Example: new Base64.OutputStream( out, Base64.ENCODE )
+ *
+ * @param out the java.io.OutputStream to which data will be written.
+ * @param options Specified options.
+ * @see Base64#ENCODE
+ * @see Base64#DECODE
+ * @see Base64#DO_BREAK_LINES
+ * @since 1.3
+ */
+ public OutputStream( java.io.OutputStream out, int options ) {
+ super( out );
+ this.breakLines = (options & DO_BREAK_LINES) != 0;
+ this.encode = (options & ENCODE) != 0;
+ this.bufferLength = encode ? 3 : 4;
+ this.buffer = new byte[ bufferLength ];
+ this.position = 0;
+ this.lineLength = 0;
+ this.suspendEncoding = false;
+ this.b4 = new byte[4];
+ this.options = options;
+ this.decodabet = getDecodabet(options);
+ } // end constructor
+
+
+ /**
+ * Writes the byte to the output stream after
+ * converting to/from Base64 notation.
+ * When encoding, bytes are buffered three
+ * at a time before the output stream actually
+ * gets a write() call.
+ * When decoding, bytes are buffered four
+ * at a time.
+ *
+ * @param theByte the byte to write
+ * @since 1.3
+ */
+ @Override
+ public void write(int theByte)
+ throws java.io.IOException {
+ // Encoding suspended?
+ if( suspendEncoding ) {
+ this.out.write( theByte );
+ return;
+ } // end if: supsended
+
+ // Encode?
+ if( encode ) {
+ buffer[ position++ ] = (byte)theByte;
+ if( position >= bufferLength ) { // Enough to encode.
+
+ this.out.write( encode3to4( b4, buffer, bufferLength, options ) );
+
+ lineLength += 4;
+ if( breakLines && lineLength >= MAX_LINE_LENGTH ) {
+ this.out.write( NEW_LINE );
+ lineLength = 0;
+ } // end if: end of line
+
+ position = 0;
+ } // end if: enough to output
+ } // end if: encoding
+
+ // Else, Decoding
+ else {
+ // Meaningful Base64 character?
+ if( decodabet[ theByte & 0x7f ] > WHITE_SPACE_ENC ) {
+ buffer[ position++ ] = (byte)theByte;
+ if( position >= bufferLength ) { // Enough to output.
+
+ int len = Base64.decode4to3( buffer, 0, b4, 0, options );
+ out.write( b4, 0, len );
+ position = 0;
+ } // end if: enough to output
+ } // end if: meaningful base64 character
+ else if( decodabet[ theByte & 0x7f ] != WHITE_SPACE_ENC ) {
+ throw new java.io.IOException( "Invalid character in Base64 data." );
+ } // end else: not white space either
+ } // end else: decoding
+ } // end write
+
+
+
+ /**
+ * Calls {@link #write(int)} repeatedly until len
+ * bytes are written.
+ *
+ * @param theBytes array from which to read bytes
+ * @param off offset for array
+ * @param len max number of bytes to read into array
+ * @since 1.3
+ */
+ @Override
+ public void write( byte[] theBytes, int off, int len )
+ throws java.io.IOException {
+ // Encoding suspended?
+ if( suspendEncoding ) {
+ this.out.write( theBytes, off, len );
+ return;
+ } // end if: supsended
+
+ for( int i = 0; i < len; i++ ) {
+ write( theBytes[ off + i ] );
+ } // end for: each byte written
+
+ } // end write
+
+
+
+ /**
+ * Method added by PHIL. [Thanks, PHIL. -Rob]
+ * This pads the buffer without closing the stream.
+ * @throws java.io.IOException if there's an error.
+ */
+ public void flushBase64() throws java.io.IOException {
+ if( position > 0 ) {
+ if( encode ) {
+ out.write( encode3to4( b4, buffer, position, options ) );
+ position = 0;
+ } // end if: encoding
+ else {
+ throw new java.io.IOException( "Base64 input not properly padded." );
+ } // end else: decoding
+ } // end if: buffer partially full
+
+ } // end flush
+
+
+ /**
+ * Flushes and closes (I think, in the superclass) the stream.
+ *
+ * @since 1.3
+ */
+ @Override
+ public void close() throws java.io.IOException {
+ // 1. Ensure that pending characters are written
+ flushBase64();
+
+ // 2. Actually close the stream
+ // Base class both flushes and closes.
+ super.close();
+
+ buffer = null;
+ out = null;
+ } // end close
+
+
+
+ /**
+ * Suspends encoding of the stream.
+ * May be helpful if you need to embed a piece of
+ * base64-encoded data in a stream.
+ *
+ * @throws java.io.IOException if there's an error flushing
+ * @since 1.5.1
+ */
+ public void suspendEncoding() throws java.io.IOException {
+ flushBase64();
+ this.suspendEncoding = true;
+ } // end suspendEncoding
+
+
+ /**
+ * Resumes encoding of the stream.
+ * May be helpful if you need to embed a piece of
+ * base64-encoded data in a stream.
+ *
+ * @since 1.5.1
+ */
+ public void resumeEncoding() {
+ this.suspendEncoding = false;
+ } // end resumeEncoding
+
+
+
+ } // end inner class OutputStream
+
+
+} // end class Base64
diff --git a/websocket-resources/src/test/java/org/whispersystems/websocket/LoggableRequestResponseTest.java b/websocket-resources/src/test/java/org/whispersystems/websocket/LoggableRequestResponseTest.java
new file mode 100644
index 000000000..4faa1874b
--- /dev/null
+++ b/websocket-resources/src/test/java/org/whispersystems/websocket/LoggableRequestResponseTest.java
@@ -0,0 +1,64 @@
+package org.whispersystems.websocket;
+
+import org.eclipse.jetty.server.AbstractNCSARequestLog;
+import org.eclipse.jetty.server.NCSARequestLog;
+import org.eclipse.jetty.server.RequestLog;
+import org.eclipse.jetty.util.component.AbstractLifeCycle;
+import org.eclipse.jetty.websocket.api.RemoteEndpoint;
+import org.junit.Test;
+import org.whispersystems.websocket.messages.WebSocketMessageFactory;
+import org.whispersystems.websocket.messages.WebSocketRequestMessage;
+import org.whispersystems.websocket.servlet.LoggableRequest;
+import org.whispersystems.websocket.servlet.LoggableResponse;
+import org.whispersystems.websocket.servlet.WebSocketServletRequest;
+import org.whispersystems.websocket.servlet.WebSocketServletResponse;
+import org.whispersystems.websocket.session.WebSocketSessionContext;
+
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import java.util.HashMap;
+import java.util.Optional;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class LoggableRequestResponseTest {
+
+ @Test
+ public void testLogging() {
+ NCSARequestLog requestLog = new EnabledNCSARequestLog();
+
+ WebSocketClient webSocketClient = mock(WebSocketClient.class );
+ WebSocketRequestMessage requestMessage = mock(WebSocketRequestMessage.class);
+ ServletContext servletContext = mock(ServletContext.class );
+ RemoteEndpoint remoteEndpoint = mock(RemoteEndpoint.class );
+ WebSocketMessageFactory messageFactory = mock(WebSocketMessageFactory.class);
+
+ when(requestMessage.getVerb()).thenReturn("GET");
+ when(requestMessage.getBody()).thenReturn(Optional.empty());
+ when(requestMessage.getHeaders()).thenReturn(new HashMap<>());
+ when(requestMessage.getPath()).thenReturn("/api/v1/test");
+ when(requestMessage.getRequestId()).thenReturn(1L);
+ when(requestMessage.hasRequestId()).thenReturn(true);
+
+ WebSocketSessionContext sessionContext = new WebSocketSessionContext (webSocketClient );
+ HttpServletRequest servletRequest = new WebSocketServletRequest (sessionContext, requestMessage, servletContext);
+ HttpServletResponse servletResponse = new WebSocketServletResponse(remoteEndpoint, 1, messageFactory );
+
+ LoggableRequest loggableRequest = new LoggableRequest (servletRequest );
+ LoggableResponse loggableResponse = new LoggableResponse(servletResponse);
+
+ requestLog.log(loggableRequest, loggableResponse);
+ }
+
+
+ private class EnabledNCSARequestLog extends NCSARequestLog {
+ @Override
+ public boolean isEnabled() {
+ return true;
+ }
+ }
+
+}
diff --git a/websocket-resources/src/test/java/org/whispersystems/websocket/WebSocketResourceProviderFactoryTest.java b/websocket-resources/src/test/java/org/whispersystems/websocket/WebSocketResourceProviderFactoryTest.java
new file mode 100644
index 000000000..68a995c26
--- /dev/null
+++ b/websocket-resources/src/test/java/org/whispersystems/websocket/WebSocketResourceProviderFactoryTest.java
@@ -0,0 +1,73 @@
+package org.whispersystems.websocket;
+
+
+import org.eclipse.jetty.websocket.api.Session;
+import org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest;
+import org.eclipse.jetty.websocket.servlet.ServletUpgradeResponse;
+import org.junit.Test;
+import org.whispersystems.websocket.auth.AuthenticationException;
+import org.whispersystems.websocket.auth.WebSocketAuthenticator;
+import org.whispersystems.websocket.setup.WebSocketEnvironment;
+
+import javax.servlet.ServletException;
+import java.io.IOException;
+import java.util.Optional;
+
+import io.dropwizard.jersey.setup.JerseyEnvironment;
+import static org.junit.Assert.*;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.*;
+
+public class WebSocketResourceProviderFactoryTest {
+
+ @Test
+ public void testUnauthorized() throws ServletException, AuthenticationException, IOException {
+ JerseyEnvironment jerseyEnvironment = mock(JerseyEnvironment.class );
+ WebSocketEnvironment environment = mock(WebSocketEnvironment.class );
+ WebSocketAuthenticator authenticator = mock(WebSocketAuthenticator.class);
+ ServletUpgradeRequest request = mock(ServletUpgradeRequest.class );
+ ServletUpgradeResponse response = mock(ServletUpgradeResponse.class);
+
+ when(environment.getAuthenticator()).thenReturn(authenticator);
+ when(authenticator.authenticate(eq(request))).thenReturn(new WebSocketAuthenticator.AuthenticationResult<>(Optional.empty(), true));
+ when(environment.jersey()).thenReturn(jerseyEnvironment);
+
+ WebSocketResourceProviderFactory factory = new WebSocketResourceProviderFactory(environment);
+ Object connection = factory.createWebSocket(request, response);
+
+ assertNull(connection);
+ verify(response).sendForbidden(eq("Unauthorized"));
+ verify(authenticator).authenticate(eq(request));
+ }
+
+ @Test
+ public void testValidAuthorization() throws AuthenticationException, ServletException {
+ JerseyEnvironment jerseyEnvironment = mock(JerseyEnvironment.class );
+ WebSocketEnvironment environment = mock(WebSocketEnvironment.class );
+ WebSocketAuthenticator authenticator = mock(WebSocketAuthenticator.class);
+ ServletUpgradeRequest request = mock(ServletUpgradeRequest.class );
+ ServletUpgradeResponse response = mock(ServletUpgradeResponse.class);
+ Session session = mock(Session.class );
+ Account account = new Account();
+
+ when(environment.getAuthenticator()).thenReturn(authenticator);
+ when(authenticator.authenticate(eq(request))).thenReturn(new WebSocketAuthenticator.AuthenticationResult<>(Optional.of(account), true));
+ when(environment.jersey()).thenReturn(jerseyEnvironment);
+
+ WebSocketResourceProviderFactory factory = new WebSocketResourceProviderFactory(environment);
+ Object connection = factory.createWebSocket(request, response);
+
+ assertNotNull(connection);
+ verifyNoMoreInteractions(response);
+ verify(authenticator).authenticate(eq(request));
+
+ ((WebSocketResourceProvider)connection).onWebSocketConnect(session);
+
+ assertNotNull(((WebSocketResourceProvider) connection).getContext().getAuthenticated());
+ assertEquals(((WebSocketResourceProvider)connection).getContext().getAuthenticated(), account);
+ }
+
+ private static class Account {}
+
+
+}
diff --git a/websocket-resources/src/test/java/org/whispersystems/websocket/WebSocketResourceProviderTest.java b/websocket-resources/src/test/java/org/whispersystems/websocket/WebSocketResourceProviderTest.java
new file mode 100644
index 000000000..f5745fc67
--- /dev/null
+++ b/websocket-resources/src/test/java/org/whispersystems/websocket/WebSocketResourceProviderTest.java
@@ -0,0 +1,90 @@
+package org.whispersystems.websocket;
+
+import org.eclipse.jetty.server.RequestLog;
+import org.eclipse.jetty.websocket.api.CloseStatus;
+import org.eclipse.jetty.websocket.api.RemoteEndpoint;
+import org.eclipse.jetty.websocket.api.Session;
+import org.eclipse.jetty.websocket.api.UpgradeRequest;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.whispersystems.websocket.WebSocketResourceProvider;
+import org.whispersystems.websocket.auth.AuthenticationException;
+import org.whispersystems.websocket.auth.WebSocketAuthenticator;
+import org.whispersystems.websocket.messages.protobuf.ProtobufWebSocketMessageFactory;
+import org.whispersystems.websocket.setup.WebSocketConnectListener;
+
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.LinkedList;
+import java.util.Optional;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.*;
+
+public class WebSocketResourceProviderTest {
+
+ @Test
+ public void testOnConnect() throws AuthenticationException, IOException {
+ HttpServlet contextHandler = mock(HttpServlet.class);
+ WebSocketAuthenticator