content: // Protocol Buffers - Google's data interchange format
  // Copyright 2008 Google Inc.  All rights reserved.
  // https://developers.google.com/protocol-buffers/
  //
  // Redistribution and use in source and binary forms, with or without
  // modification, are permitted provided that the following conditions are
  // met:
  //
  //     * Redistributions of source code must retain the above copyright
  // notice, this list of conditions and the following disclaimer.
  //     * Redistributions in binary form must reproduce the above
  // copyright notice, this list of conditions and the following disclaimer
  // in the documentation and/or other materials provided with the
  // distribution.
  //     * Neither the name of Google Inc. nor the names of its
  // contributors may be used to endorse or promote products derived from
  // this software without specific prior written permission.
  //
  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  
  package com.google.protobuf;
  
  import static com.google.protobuf.Internal.checkNotNull;
  
  import java.io.FilterInputStream;
  import java.io.IOException;
  import java.io.InputStream;
  import java.io.OutputStream;
  import java.util.ArrayList;
  import java.util.Collection;
  import java.util.List;
  
  /**
   * A partial implementation of the {@link MessageLite} interface which implements as many methods of
   * that interface as possible in terms of other methods.
   *
   * @author kenton@google.com Kenton Varda
   */
  public abstract class AbstractMessageLite<
          MessageType extends AbstractMessageLite<MessageType, BuilderType>,
          BuilderType extends AbstractMessageLite.Builder<MessageType, BuilderType>>
      implements MessageLite {
    protected int memoizedHashCode = 0;
    @Override
    public ByteString toByteString() {
      try {
        final ByteString.CodedBuilder out = ByteString.newCodedBuilder(getSerializedSize());
        writeTo(out.getCodedOutput());
        return out.build();
      } catch (IOException e) {
        throw new RuntimeException(getSerializingExceptionMessage("ByteString"), e);
      }
    }
  
    @Override
    public byte[] toByteArray() {
      try {
        final byte[] result = new byte[getSerializedSize()];
        final CodedOutputStream output = CodedOutputStream.newInstance(result);
        writeTo(output);
        output.checkNoSpaceLeft();
        return result;
      } catch (IOException e) {
        throw new RuntimeException(getSerializingExceptionMessage("byte array"), e);
      }
    }
  
    @Override
    public void writeTo(final OutputStream output) throws IOException {
      final int bufferSize = CodedOutputStream.computePreferredBufferSize(getSerializedSize());
      final CodedOutputStream codedOutput = CodedOutputStream.newInstance(output, bufferSize);
      writeTo(codedOutput);
      codedOutput.flush();
    }
  
    @Override
    public void writeDelimitedTo(final OutputStream output) throws IOException {
      final int serialized = getSerializedSize();
      final int bufferSize =
          CodedOutputStream.computePreferredBufferSize(
              CodedOutputStream.computeRawVarint32Size(serialized) + serialized);
      final CodedOutputStream codedOutput = CodedOutputStream.newInstance(output, bufferSize);
      codedOutput.writeRawVarint32(serialized);
      writeTo(codedOutput);
      codedOutput.flush();
    }
  
    // We'd like these to be abstract but some folks are extending this class directly. They shouldn't
    // be doing that and they should feel bad.
    int getMemoizedSerializedSize() {
      throw new UnsupportedOperationException();
    }
  
    void setMemoizedSerializedSize(int size) {
      throw new UnsupportedOperationException();
    }
  
  
    @ExperimentalApi
    protected final boolean isInitializedInternal() {
      return Protobuf.getInstance().schemaFor(this).isInitialized(this);
    }
  
    @ExperimentalApi
    protected final int getSerializedSizeInternal() {
      return Protobuf.getInstance().schemaFor(this).getSerializedSize(this);
    }
  
    int getSerializedSize(Schema schema) {
      int memoizedSerializedSize = getMemoizedSerializedSize();
      if (memoizedSerializedSize == -1) {
        memoizedSerializedSize = schema.getSerializedSize(this);
        setMemoizedSerializedSize(memoizedSerializedSize);
      }
      return memoizedSerializedSize;
    }
  
    @ExperimentalApi
    protected final void writeToInternal(CodedOutputStream output) throws IOException {
      Protobuf.getInstance()
          .schemaFor(getClassInternal())
          .writeTo(this, CodedOutputStreamWriter.forCodedOutput(output));
    }
  
    @ExperimentalApi
    protected void mergeFromInternal(CodedInputStream input, ExtensionRegistryLite extensionRegistry)
        throws InvalidProtocolBufferException {
      try {
        Protobuf.getInstance()
            .schemaFor(getClassInternal())
            .mergeFrom(this, CodedInputStreamReader.forCodedInput(input), extensionRegistry);
      } catch (InvalidProtocolBufferException e) {
        throw e.setUnfinishedMessage(this);
      } catch (IOException e) {
        throw new InvalidProtocolBufferException(e).setUnfinishedMessage(this);
      }
    }
  
    @ExperimentalApi
    protected void makeImmutableInternal() {
      Protobuf.getInstance().schemaFor(getClassInternal()).makeImmutable(this);
    }
  
    @SuppressWarnings("unchecked")
    private Class<AbstractMessageLite<MessageType, BuilderType>> getClassInternal() {
      return (Class<AbstractMessageLite<MessageType, BuilderType>>) getClass();
    }
  
    /** Package private helper method for AbstractParser to create UninitializedMessageException. */
    UninitializedMessageException newUninitializedMessageException() {
      return new UninitializedMessageException(this);
    }
  
    private String getSerializingExceptionMessage(String target) {
      return "Serializing "
          + getClass().getName()
          + " to a "
          + target
          + " threw an IOException (should never happen).";
    }
  
    protected static void checkByteStringIsUtf8(ByteString byteString)
        throws IllegalArgumentException {
      if (!byteString.isValidUtf8()) {
        throw new IllegalArgumentException("Byte string is not UTF-8.");
      }
    }
  
    // For binary compatibility
    @Deprecated
    protected static <T> void addAll(final Iterable<T> values, final Collection<? super T> list) {
      Builder.addAll(values, (List) list);
    }
  
    protected static <T> void addAll(final Iterable<T> values, final List<? super T> list) {
      Builder.addAll(values, list);
    }
  
    /**
     * A partial implementation of the {@link Message.Builder} interface which implements as many
     * methods of that interface as possible in terms of other methods.
     */
    @SuppressWarnings("unchecked")
    public abstract static class Builder<
            MessageType extends AbstractMessageLite<MessageType, BuilderType>,
            BuilderType extends Builder<MessageType, BuilderType>>
        implements MessageLite.Builder {
      // The compiler produces an error if this is not declared explicitly.
      @Override
      public abstract BuilderType clone();
  
      @Override
      public BuilderType mergeFrom(final CodedInputStream input) throws IOException {
        return mergeFrom(input, ExtensionRegistryLite.getEmptyRegistry());
      }
  
      // Re-defined here for return type covariance.
      @Override
      public abstract BuilderType mergeFrom(
          final CodedInputStream input, final ExtensionRegistryLite extensionRegistry)
          throws IOException;
  
      @Override
      public BuilderType mergeFrom(final ByteString data) throws InvalidProtocolBufferException {
        try {
          final CodedInputStream input = data.newCodedInput();
          mergeFrom(input);
          input.checkLastTagWas(0);
          return (BuilderType) this;
        } catch (InvalidProtocolBufferException e) {
          throw e;
        } catch (IOException e) {
          throw new RuntimeException(getReadingExceptionMessage("ByteString"), e);
        }
      }
  
      @Override
      public BuilderType mergeFrom(
          final ByteString data, final ExtensionRegistryLite extensionRegistry)
          throws InvalidProtocolBufferException {
        try {
          final CodedInputStream input = data.newCodedInput();
          mergeFrom(input, extensionRegistry);
          input.checkLastTagWas(0);
          return (BuilderType) this;
        } catch (InvalidProtocolBufferException e) {
          throw e;
        } catch (IOException e) {
          throw new RuntimeException(getReadingExceptionMessage("ByteString"), e);
        }
      }
  
      @Override
      public BuilderType mergeFrom(final byte[] data) throws InvalidProtocolBufferException {
        return mergeFrom(data, 0, data.length);
      }
  
      @Override
      public BuilderType mergeFrom(final byte[] data, final int off, final int len)
          throws InvalidProtocolBufferException {
        try {
          final CodedInputStream input = CodedInputStream.newInstance(data, off, len);
          mergeFrom(input);
          input.checkLastTagWas(0);
          return (BuilderType) this;
        } catch (InvalidProtocolBufferException e) {
          throw e;
        } catch (IOException e) {
          throw new RuntimeException(getReadingExceptionMessage("byte array"), e);
        }
      }
  
      @Override
      public BuilderType mergeFrom(final byte[] data, final ExtensionRegistryLite extensionRegistry)
          throws InvalidProtocolBufferException {
        return mergeFrom(data, 0, data.length, extensionRegistry);
      }
  
      @Override
      public BuilderType mergeFrom(
          final byte[] data,
          final int off,
          final int len,
          final ExtensionRegistryLite extensionRegistry)
          throws InvalidProtocolBufferException {
        try {
          final CodedInputStream input = CodedInputStream.newInstance(data, off, len);
          mergeFrom(input, extensionRegistry);
          input.checkLastTagWas(0);
          return (BuilderType) this;
        } catch (InvalidProtocolBufferException e) {
          throw e;
        } catch (IOException e) {
          throw new RuntimeException(getReadingExceptionMessage("byte array"), e);
        }
      }
  
      @Override
      public BuilderType mergeFrom(final InputStream input) throws IOException {
        final CodedInputStream codedInput = CodedInputStream.newInstance(input);
        mergeFrom(codedInput);
        codedInput.checkLastTagWas(0);
        return (BuilderType) this;
      }
  
      @Override
      public BuilderType mergeFrom(
          final InputStream input, final ExtensionRegistryLite extensionRegistry) throws IOException {
        final CodedInputStream codedInput = CodedInputStream.newInstance(input);
        mergeFrom(codedInput, extensionRegistry);
        codedInput.checkLastTagWas(0);
        return (BuilderType) this;
      }
  
      /**
       * An InputStream implementations which reads from some other InputStream but is limited to a
       * particular number of bytes. Used by mergeDelimitedFrom(). This is intentionally
       * package-private so that UnknownFieldSet can share it.
       */
      static final class LimitedInputStream extends FilterInputStream {
        private int limit;
  
        LimitedInputStream(InputStream in, int limit) {
          super(in);
          this.limit = limit;
        }
  
        @Override
        public int available() throws IOException {
          return Math.min(super.available(), limit);
        }
  
        @Override
        public int read() throws IOException {
          if (limit <= 0) {
            return -1;
          }
          final int result = super.read();
          if (result >= 0) {
            --limit;
          }
          return result;
        }
  
        @Override
        public int read(final byte[] b, final int off, int len) throws IOException {
          if (limit <= 0) {
            return -1;
          }
          len = Math.min(len, limit);
          final int result = super.read(b, off, len);
          if (result >= 0) {
            limit -= result;
          }
          return result;
        }
  
        @Override
        public long skip(final long n) throws IOException {
          final long result = super.skip(Math.min(n, limit));
          if (result >= 0) {
            limit -= result;
          }
          return result;
        }
      }
  
      @Override
      public boolean mergeDelimitedFrom(
          final InputStream input, final ExtensionRegistryLite extensionRegistry) throws IOException {
        final int firstByte = input.read();
        if (firstByte == -1) {
          return false;
        }
        final int size = CodedInputStream.readRawVarint32(firstByte, input);
        final InputStream limitedInput = new LimitedInputStream(input, size);
        mergeFrom(limitedInput, extensionRegistry);
        return true;
      }
  
      @Override
      public boolean mergeDelimitedFrom(final InputStream input) throws IOException {
        return mergeDelimitedFrom(input, ExtensionRegistryLite.getEmptyRegistry());
      }
  
      @Override
      @SuppressWarnings("unchecked") // isInstance takes care of this
      public BuilderType mergeFrom(final MessageLite other) {
        if (!getDefaultInstanceForType().getClass().isInstance(other)) {
          throw new IllegalArgumentException(
              "mergeFrom(MessageLite) can only merge messages of the same type.");
        }
  
        return internalMergeFrom((MessageType) other);
      }
  
      protected abstract BuilderType internalMergeFrom(MessageType message);
  
      private String getReadingExceptionMessage(String target) {
        return "Reading "
            + getClass().getName()
            + " from a "
            + target
            + " threw an IOException (should never happen).";
      }
  
      // We check nulls as we iterate to avoid iterating over values twice.
      private static <T> void addAllCheckingNulls(Iterable<T> values, List<? super T> list) {
        if (list instanceof ArrayList && values instanceof Collection) {
          ((ArrayList<T>) list).ensureCapacity(list.size() + ((Collection<T>) values).size());
        }
        int begin = list.size();
        for (T value : values) {
          if (value == null) {
            // encountered a null value so we must undo our modifications prior to throwing
            String message = "Element at index " + (list.size() - begin) + " is null.";
            for (int i = list.size() - 1; i >= begin; i--) {
              list.remove(i);
            }
            throw new NullPointerException(message);
          }
          list.add(value);
        }
      }
  
      /** Construct an UninitializedMessageException reporting missing fields in the given message. */
      protected static UninitializedMessageException newUninitializedMessageException(
          MessageLite message) {
        return new UninitializedMessageException(message);
      }
  
      // For binary compatibility.
      @Deprecated
      protected static <T> void addAll(final Iterable<T> values, final Collection<? super T> list) {
        addAll(values, (List<T>) list);
      }
  
      /**
       * Adds the {@code values} to the {@code list}. This is a helper method used by generated code.
       * Users should ignore it.
       *
       * @throws NullPointerException if {@code values} or any of the elements of {@code values} is
       *     null.
       */
      protected static <T> void addAll(final Iterable<T> values, final List<? super T> list) {
        checkNotNull(values);
        if (values instanceof LazyStringList) {
          // For StringOrByteStringLists, check the underlying elements to avoid
          // forcing conversions of ByteStrings to Strings.
          // TODO(dweis): Could we just prohibit nulls in all protobuf lists and get rid of this? Is
          // if even possible to hit this condition as all protobuf methods check for null first,
          // right?
          List<?> lazyValues = ((LazyStringList) values).getUnderlyingElements();
          LazyStringList lazyList = (LazyStringList) list;
          int begin = list.size();
          for (Object value : lazyValues) {
            if (value == null) {
              // encountered a null value so we must undo our modifications prior to throwing
              String message = "Element at index " + (lazyList.size() - begin) + " is null.";
              for (int i = lazyList.size() - 1; i >= begin; i--) {
                lazyList.remove(i);
              }
              throw new NullPointerException(message);
            }
            if (value instanceof ByteString) {
              lazyList.add((ByteString) value);
            } else {
              lazyList.add((String) value);
            }
          }
        } else {
          if (values instanceof PrimitiveNonBoxingCollection) {
            list.addAll((Collection<T>) values);
          } else {
            addAllCheckingNulls(values, list);
          }
        }
      }
    }
  }
  