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