Home | History | Annotate | Download | only in protobuf
      1 // Protocol Buffers - Google's data interchange format
      2 // Copyright 2008 Google Inc.  All rights reserved.
      3 // http://code.google.com/p/protobuf/
      4 //
      5 // Redistribution and use in source and binary forms, with or without
      6 // modification, are permitted provided that the following conditions are
      7 // met:
      8 //
      9 //     * Redistributions of source code must retain the above copyright
     10 // notice, this list of conditions and the following disclaimer.
     11 //     * Redistributions in binary form must reproduce the above
     12 // copyright notice, this list of conditions and the following disclaimer
     13 // in the documentation and/or other materials provided with the
     14 // distribution.
     15 //     * Neither the name of Google Inc. nor the names of its
     16 // contributors may be used to endorse or promote products derived from
     17 // this software without specific prior written permission.
     18 //
     19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     30 
     31 package com.google.protobuf;
     32 
     33 import java.io.FilterInputStream;
     34 import java.io.InputStream;
     35 import java.io.IOException;
     36 import java.io.OutputStream;
     37 import java.util.Collection;
     38 
     39 /**
     40  * A partial implementation of the {@link MessageLite} interface which
     41  * implements as many methods of that interface as possible in terms of other
     42  * methods.
     43  *
     44  * @author kenton (at) google.com Kenton Varda
     45  */
     46 public abstract class AbstractMessageLite implements MessageLite {
     47   public ByteString toByteString() {
     48     try {
     49       final ByteString.CodedBuilder out =
     50         ByteString.newCodedBuilder(getSerializedSize());
     51       writeTo(out.getCodedOutput());
     52       return out.build();
     53     } catch (IOException e) {
     54       throw new RuntimeException(
     55         "Serializing to a ByteString threw an IOException (should " +
     56         "never happen).", e);
     57     }
     58   }
     59 
     60   public byte[] toByteArray() {
     61     try {
     62       final byte[] result = new byte[getSerializedSize()];
     63       final CodedOutputStream output = CodedOutputStream.newInstance(result);
     64       writeTo(output);
     65       output.checkNoSpaceLeft();
     66       return result;
     67     } catch (IOException e) {
     68       throw new RuntimeException(
     69         "Serializing to a byte array threw an IOException " +
     70         "(should never happen).", e);
     71     }
     72   }
     73 
     74   public void writeTo(final OutputStream output) throws IOException {
     75     final int bufferSize =
     76         CodedOutputStream.computePreferredBufferSize(getSerializedSize());
     77     final CodedOutputStream codedOutput =
     78         CodedOutputStream.newInstance(output, bufferSize);
     79     writeTo(codedOutput);
     80     codedOutput.flush();
     81   }
     82 
     83   public void writeDelimitedTo(final OutputStream output) throws IOException {
     84     final int serialized = getSerializedSize();
     85     final int bufferSize = CodedOutputStream.computePreferredBufferSize(
     86         CodedOutputStream.computeRawVarint32Size(serialized) + serialized);
     87     final CodedOutputStream codedOutput =
     88         CodedOutputStream.newInstance(output, bufferSize);
     89     codedOutput.writeRawVarint32(serialized);
     90     writeTo(codedOutput);
     91     codedOutput.flush();
     92   }
     93 
     94   /**
     95    * A partial implementation of the {@link Message.Builder} interface which
     96    * implements as many methods of that interface as possible in terms of
     97    * other methods.
     98    */
     99   @SuppressWarnings("unchecked")
    100   public static abstract class Builder<BuilderType extends Builder>
    101       implements MessageLite.Builder {
    102     // The compiler produces an error if this is not declared explicitly.
    103     @Override
    104     public abstract BuilderType clone();
    105 
    106     public BuilderType mergeFrom(final CodedInputStream input)
    107                                  throws IOException {
    108       return mergeFrom(input, ExtensionRegistryLite.getEmptyRegistry());
    109     }
    110 
    111     // Re-defined here for return type covariance.
    112     public abstract BuilderType mergeFrom(
    113         final CodedInputStream input,
    114         final ExtensionRegistryLite extensionRegistry)
    115         throws IOException;
    116 
    117     public BuilderType mergeFrom(final ByteString data)
    118         throws InvalidProtocolBufferException {
    119       try {
    120         final CodedInputStream input = data.newCodedInput();
    121         mergeFrom(input);
    122         input.checkLastTagWas(0);
    123         return (BuilderType) this;
    124       } catch (InvalidProtocolBufferException e) {
    125         throw e;
    126       } catch (IOException e) {
    127         throw new RuntimeException(
    128           "Reading from a ByteString threw an IOException (should " +
    129           "never happen).", e);
    130       }
    131     }
    132 
    133     public BuilderType mergeFrom(
    134         final ByteString data,
    135         final ExtensionRegistryLite extensionRegistry)
    136         throws InvalidProtocolBufferException {
    137       try {
    138         final CodedInputStream input = data.newCodedInput();
    139         mergeFrom(input, extensionRegistry);
    140         input.checkLastTagWas(0);
    141         return (BuilderType) this;
    142       } catch (InvalidProtocolBufferException e) {
    143         throw e;
    144       } catch (IOException e) {
    145         throw new RuntimeException(
    146           "Reading from a ByteString threw an IOException (should " +
    147           "never happen).", e);
    148       }
    149     }
    150 
    151     public BuilderType mergeFrom(final byte[] data)
    152         throws InvalidProtocolBufferException {
    153       return mergeFrom(data, 0, data.length);
    154     }
    155 
    156     public BuilderType mergeFrom(final byte[] data, final int off,
    157                                  final int len)
    158                                  throws InvalidProtocolBufferException {
    159       try {
    160         final CodedInputStream input =
    161             CodedInputStream.newInstance(data, off, len);
    162         mergeFrom(input);
    163         input.checkLastTagWas(0);
    164         return (BuilderType) this;
    165       } catch (InvalidProtocolBufferException e) {
    166         throw e;
    167       } catch (IOException e) {
    168         throw new RuntimeException(
    169           "Reading from a byte array threw an IOException (should " +
    170           "never happen).", e);
    171       }
    172     }
    173 
    174     public BuilderType mergeFrom(
    175         final byte[] data,
    176         final ExtensionRegistryLite extensionRegistry)
    177         throws InvalidProtocolBufferException {
    178       return mergeFrom(data, 0, data.length, extensionRegistry);
    179     }
    180 
    181     public BuilderType mergeFrom(
    182         final byte[] data, final int off, final int len,
    183         final ExtensionRegistryLite extensionRegistry)
    184         throws InvalidProtocolBufferException {
    185       try {
    186         final CodedInputStream input =
    187             CodedInputStream.newInstance(data, off, len);
    188         mergeFrom(input, extensionRegistry);
    189         input.checkLastTagWas(0);
    190         return (BuilderType) this;
    191       } catch (InvalidProtocolBufferException e) {
    192         throw e;
    193       } catch (IOException e) {
    194         throw new RuntimeException(
    195           "Reading from a byte array threw an IOException (should " +
    196           "never happen).", e);
    197       }
    198     }
    199 
    200     public BuilderType mergeFrom(final InputStream input) throws IOException {
    201       final CodedInputStream codedInput = CodedInputStream.newInstance(input);
    202       mergeFrom(codedInput);
    203       codedInput.checkLastTagWas(0);
    204       return (BuilderType) this;
    205     }
    206 
    207     public BuilderType mergeFrom(
    208         final InputStream input,
    209         final ExtensionRegistryLite extensionRegistry)
    210         throws IOException {
    211       final CodedInputStream codedInput = CodedInputStream.newInstance(input);
    212       mergeFrom(codedInput, extensionRegistry);
    213       codedInput.checkLastTagWas(0);
    214       return (BuilderType) this;
    215     }
    216 
    217     /**
    218      * An InputStream implementations which reads from some other InputStream
    219      * but is limited to a particular number of bytes.  Used by
    220      * mergeDelimitedFrom().  This is intentionally package-private so that
    221      * UnknownFieldSet can share it.
    222      */
    223     static final class LimitedInputStream extends FilterInputStream {
    224       private int limit;
    225 
    226       LimitedInputStream(InputStream in, int limit) {
    227         super(in);
    228         this.limit = limit;
    229       }
    230 
    231       @Override
    232       public int available() throws IOException {
    233         return Math.min(super.available(), limit);
    234       }
    235 
    236       @Override
    237       public int read() throws IOException {
    238         if (limit <= 0) {
    239           return -1;
    240         }
    241         final int result = super.read();
    242         if (result >= 0) {
    243           --limit;
    244         }
    245         return result;
    246       }
    247 
    248       @Override
    249       public int read(final byte[] b, final int off, int len)
    250                       throws IOException {
    251         if (limit <= 0) {
    252           return -1;
    253         }
    254         len = Math.min(len, limit);
    255         final int result = super.read(b, off, len);
    256         if (result >= 0) {
    257           limit -= result;
    258         }
    259         return result;
    260       }
    261 
    262       @Override
    263       public long skip(final long n) throws IOException {
    264         final long result = super.skip(Math.min(n, limit));
    265         if (result >= 0) {
    266           limit -= result;
    267         }
    268         return result;
    269       }
    270     }
    271 
    272     public boolean mergeDelimitedFrom(
    273         final InputStream input,
    274         final ExtensionRegistryLite extensionRegistry)
    275         throws IOException {
    276       final int firstByte = input.read();
    277       if (firstByte == -1) {
    278         return false;
    279       }
    280       final int size = CodedInputStream.readRawVarint32(firstByte, input);
    281       final InputStream limitedInput = new LimitedInputStream(input, size);
    282       mergeFrom(limitedInput, extensionRegistry);
    283       return true;
    284     }
    285 
    286     public boolean mergeDelimitedFrom(final InputStream input)
    287         throws IOException {
    288       return mergeDelimitedFrom(input,
    289           ExtensionRegistryLite.getEmptyRegistry());
    290     }
    291 
    292     /**
    293      * Construct an UninitializedMessageException reporting missing fields in
    294      * the given message.
    295      */
    296     protected static UninitializedMessageException
    297         newUninitializedMessageException(MessageLite message) {
    298       return new UninitializedMessageException(message);
    299     }
    300 
    301     /**
    302      * Adds the {@code values} to the {@code list}.  This is a helper method
    303      * used by generated code.  Users should ignore it.
    304      *
    305      * @throws NullPointerException if any of the elements of {@code values} is
    306      * null.
    307      */
    308     protected static <T> void addAll(final Iterable<T> values,
    309                                      final Collection<? super T> list) {
    310       for (final T value : values) {
    311         if (value == null) {
    312           throw new NullPointerException();
    313         }
    314       }
    315       if (values instanceof Collection) {
    316         @SuppressWarnings("unsafe") final
    317         Collection<T> collection = (Collection<T>) values;
    318         list.addAll(collection);
    319       } else {
    320         for (final T value : values) {
    321           list.add(value);
    322         }
    323       }
    324     }
    325   }
    326 }
    327