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