1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.  All rights reserved.
3 // https://developers.google.com/protocol-buffers/
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@google.com Kenton Varda
45  */
46 public abstract class AbstractMessageLite implements MessageLite {
47   protected int memoizedHashCode = 0;
48 
toByteString()49   public ByteString toByteString() {
50     try {
51       final ByteString.CodedBuilder out =
52         ByteString.newCodedBuilder(getSerializedSize());
53       writeTo(out.getCodedOutput());
54       return out.build();
55     } catch (IOException e) {
56       throw new RuntimeException(
57         "Serializing to a ByteString threw an IOException (should " +
58         "never happen).", e);
59     }
60   }
61 
toByteArray()62   public byte[] toByteArray() {
63     try {
64       final byte[] result = new byte[getSerializedSize()];
65       final CodedOutputStream output = CodedOutputStream.newInstance(result);
66       writeTo(output);
67       output.checkNoSpaceLeft();
68       return result;
69     } catch (IOException e) {
70       throw new RuntimeException(
71         "Serializing to a byte array threw an IOException " +
72         "(should never happen).", e);
73     }
74   }
75 
writeTo(final OutputStream output)76   public void writeTo(final OutputStream output) throws IOException {
77     final int bufferSize =
78         CodedOutputStream.computePreferredBufferSize(getSerializedSize());
79     final CodedOutputStream codedOutput =
80         CodedOutputStream.newInstance(output, bufferSize);
81     writeTo(codedOutput);
82     codedOutput.flush();
83   }
84 
writeDelimitedTo(final OutputStream output)85   public void writeDelimitedTo(final OutputStream output) throws IOException {
86     final int serialized = getSerializedSize();
87     final int bufferSize = CodedOutputStream.computePreferredBufferSize(
88         CodedOutputStream.computeRawVarint32Size(serialized) + serialized);
89     final CodedOutputStream codedOutput =
90         CodedOutputStream.newInstance(output, bufferSize);
91     codedOutput.writeRawVarint32(serialized);
92     writeTo(codedOutput);
93     codedOutput.flush();
94   }
95 
96 
97   /**
98    * Package private helper method for AbstractParser to create
99    * UninitializedMessageException.
100    */
newUninitializedMessageException()101   UninitializedMessageException newUninitializedMessageException() {
102     return new UninitializedMessageException(this);
103   }
104 
checkByteStringIsUtf8(ByteString byteString)105   protected static void checkByteStringIsUtf8(ByteString byteString)
106       throws IllegalArgumentException {
107     if (!byteString.isValidUtf8()) {
108       throw new IllegalArgumentException("Byte string is not UTF-8.");
109     }
110   }
111 
112   /**
113    * A partial implementation of the {@link Message.Builder} interface which
114    * implements as many methods of that interface as possible in terms of
115    * other methods.
116    */
117   @SuppressWarnings("unchecked")
118   public static abstract class Builder<BuilderType extends Builder>
119       implements MessageLite.Builder {
120     // The compiler produces an error if this is not declared explicitly.
121     @Override
clone()122     public abstract BuilderType clone();
123 
mergeFrom(final CodedInputStream input)124     public BuilderType mergeFrom(final CodedInputStream input)
125                                  throws IOException {
126       return mergeFrom(input, ExtensionRegistryLite.getEmptyRegistry());
127     }
128 
129     // Re-defined here for return type covariance.
mergeFrom( final CodedInputStream input, final ExtensionRegistryLite extensionRegistry)130     public abstract BuilderType mergeFrom(
131         final CodedInputStream input,
132         final ExtensionRegistryLite extensionRegistry)
133         throws IOException;
134 
mergeFrom(final ByteString data)135     public BuilderType mergeFrom(final ByteString data)
136         throws InvalidProtocolBufferException {
137       try {
138         final CodedInputStream input = data.newCodedInput();
139         mergeFrom(input);
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 
mergeFrom( final ByteString data, final ExtensionRegistryLite extensionRegistry)151     public BuilderType mergeFrom(
152         final ByteString data,
153         final ExtensionRegistryLite extensionRegistry)
154         throws InvalidProtocolBufferException {
155       try {
156         final CodedInputStream input = data.newCodedInput();
157         mergeFrom(input, extensionRegistry);
158         input.checkLastTagWas(0);
159         return (BuilderType) this;
160       } catch (InvalidProtocolBufferException e) {
161         throw e;
162       } catch (IOException e) {
163         throw new RuntimeException(
164           "Reading from a ByteString threw an IOException (should " +
165           "never happen).", e);
166       }
167     }
168 
mergeFrom(final byte[] data)169     public BuilderType mergeFrom(final byte[] data)
170         throws InvalidProtocolBufferException {
171       return mergeFrom(data, 0, data.length);
172     }
173 
mergeFrom(final byte[] data, final int off, final int len)174     public BuilderType mergeFrom(final byte[] data, final int off,
175                                  final int len)
176                                  throws InvalidProtocolBufferException {
177       try {
178         final CodedInputStream input =
179             CodedInputStream.newInstance(data, off, len);
180         mergeFrom(input);
181         input.checkLastTagWas(0);
182         return (BuilderType) this;
183       } catch (InvalidProtocolBufferException e) {
184         throw e;
185       } catch (IOException e) {
186         throw new RuntimeException(
187           "Reading from a byte array threw an IOException (should " +
188           "never happen).", e);
189       }
190     }
191 
mergeFrom( final byte[] data, final ExtensionRegistryLite extensionRegistry)192     public BuilderType mergeFrom(
193         final byte[] data,
194         final ExtensionRegistryLite extensionRegistry)
195         throws InvalidProtocolBufferException {
196       return mergeFrom(data, 0, data.length, extensionRegistry);
197     }
198 
mergeFrom( final byte[] data, final int off, final int len, final ExtensionRegistryLite extensionRegistry)199     public BuilderType mergeFrom(
200         final byte[] data, final int off, final int len,
201         final ExtensionRegistryLite extensionRegistry)
202         throws InvalidProtocolBufferException {
203       try {
204         final CodedInputStream input =
205             CodedInputStream.newInstance(data, off, len);
206         mergeFrom(input, extensionRegistry);
207         input.checkLastTagWas(0);
208         return (BuilderType) this;
209       } catch (InvalidProtocolBufferException e) {
210         throw e;
211       } catch (IOException e) {
212         throw new RuntimeException(
213           "Reading from a byte array threw an IOException (should " +
214           "never happen).", e);
215       }
216     }
217 
mergeFrom(final InputStream input)218     public BuilderType mergeFrom(final InputStream input) throws IOException {
219       final CodedInputStream codedInput = CodedInputStream.newInstance(input);
220       mergeFrom(codedInput);
221       codedInput.checkLastTagWas(0);
222       return (BuilderType) this;
223     }
224 
mergeFrom( final InputStream input, final ExtensionRegistryLite extensionRegistry)225     public BuilderType mergeFrom(
226         final InputStream input,
227         final ExtensionRegistryLite extensionRegistry)
228         throws IOException {
229       final CodedInputStream codedInput = CodedInputStream.newInstance(input);
230       mergeFrom(codedInput, extensionRegistry);
231       codedInput.checkLastTagWas(0);
232       return (BuilderType) this;
233     }
234 
235     /**
236      * An InputStream implementations which reads from some other InputStream
237      * but is limited to a particular number of bytes.  Used by
238      * mergeDelimitedFrom().  This is intentionally package-private so that
239      * UnknownFieldSet can share it.
240      */
241     static final class LimitedInputStream extends FilterInputStream {
242       private int limit;
243 
LimitedInputStream(InputStream in, int limit)244       LimitedInputStream(InputStream in, int limit) {
245         super(in);
246         this.limit = limit;
247       }
248 
249       @Override
available()250       public int available() throws IOException {
251         return Math.min(super.available(), limit);
252       }
253 
254       @Override
read()255       public int read() throws IOException {
256         if (limit <= 0) {
257           return -1;
258         }
259         final int result = super.read();
260         if (result >= 0) {
261           --limit;
262         }
263         return result;
264       }
265 
266       @Override
read(final byte[] b, final int off, int len)267       public int read(final byte[] b, final int off, int len)
268                       throws IOException {
269         if (limit <= 0) {
270           return -1;
271         }
272         len = Math.min(len, limit);
273         final int result = super.read(b, off, len);
274         if (result >= 0) {
275           limit -= result;
276         }
277         return result;
278       }
279 
280       @Override
skip(final long n)281       public long skip(final long n) throws IOException {
282         final long result = super.skip(Math.min(n, limit));
283         if (result >= 0) {
284           limit -= result;
285         }
286         return result;
287       }
288     }
289 
mergeDelimitedFrom( final InputStream input, final ExtensionRegistryLite extensionRegistry)290     public boolean mergeDelimitedFrom(
291         final InputStream input,
292         final ExtensionRegistryLite extensionRegistry)
293         throws IOException {
294       final int firstByte = input.read();
295       if (firstByte == -1) {
296         return false;
297       }
298       final int size = CodedInputStream.readRawVarint32(firstByte, input);
299       final InputStream limitedInput = new LimitedInputStream(input, size);
300       mergeFrom(limitedInput, extensionRegistry);
301       return true;
302     }
303 
mergeDelimitedFrom(final InputStream input)304     public boolean mergeDelimitedFrom(final InputStream input)
305         throws IOException {
306       return mergeDelimitedFrom(input,
307           ExtensionRegistryLite.getEmptyRegistry());
308     }
309 
310     /**
311      * Construct an UninitializedMessageException reporting missing fields in
312      * the given message.
313      */
314     protected static UninitializedMessageException
newUninitializedMessageException(MessageLite message)315         newUninitializedMessageException(MessageLite message) {
316       return new UninitializedMessageException(message);
317     }
318 
319     /**
320      * Adds the {@code values} to the {@code list}.  This is a helper method
321      * used by generated code.  Users should ignore it.
322      *
323      * @throws NullPointerException if any of the elements of {@code values} is
324      * null. When that happens, some elements of {@code values} may have already
325      * been added to the result {@code list}.
326      */
addAll(final Iterable<T> values, final Collection<? super T> list)327     protected static <T> void addAll(final Iterable<T> values,
328                                      final Collection<? super T> list) {
329       if (values instanceof LazyStringList) {
330         // For StringOrByteStringLists, check the underlying elements to avoid
331         // forcing conversions of ByteStrings to Strings.
332         checkForNullValues(((LazyStringList) values).getUnderlyingElements());
333         list.addAll((Collection<T>) values);
334       } else if (values instanceof Collection) {
335         checkForNullValues(values);
336         list.addAll((Collection<T>) values);
337       } else {
338         for (final T value : values) {
339           if (value == null) {
340             throw new NullPointerException();
341           }
342           list.add(value);
343         }
344       }
345     }
346 
checkForNullValues(final Iterable<?> values)347     private static void checkForNullValues(final Iterable<?> values) {
348       for (final Object value : values) {
349         if (value == null) {
350           throw new NullPointerException();
351         }
352       }
353     }
354   }
355 }
356