1 // Protocol Buffers - Google's data interchange format 2 // Copyright 2013 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.nano; 32 33 import java.io.IOException; 34 35 /** 36 * Base class of those Protocol Buffer messages that need to store unknown fields, 37 * such as extensions. 38 */ 39 public abstract class ExtendableMessageNano<M extends ExtendableMessageNano<M>> 40 extends MessageNano { 41 /** 42 * A container for fields unknown to the message, including extensions. Extension fields can 43 * can be accessed through the {@link #getExtension} and {@link #setExtension} methods. 44 */ 45 protected FieldArray unknownFieldData; 46 47 @Override computeSerializedSize()48 protected int computeSerializedSize() { 49 int size = 0; 50 if (unknownFieldData != null) { 51 for (int i = 0; i < unknownFieldData.size(); i++) { 52 FieldData field = unknownFieldData.dataAt(i); 53 size += field.computeSerializedSize(); 54 } 55 } 56 return size; 57 } 58 59 @Override writeTo(CodedOutputByteBufferNano output)60 public void writeTo(CodedOutputByteBufferNano output) throws IOException { 61 if (unknownFieldData == null) { 62 return; 63 } 64 for (int i = 0; i < unknownFieldData.size(); i++) { 65 FieldData field = unknownFieldData.dataAt(i); 66 field.writeTo(output); 67 } 68 } 69 70 /** 71 * Checks if there is a value stored for the specified extension in this 72 * message. 73 */ hasExtension(Extension<M, ?> extension)74 public final boolean hasExtension(Extension<M, ?> extension) { 75 if (unknownFieldData == null) { 76 return false; 77 } 78 FieldData field = unknownFieldData.get(WireFormatNano.getTagFieldNumber(extension.tag)); 79 return field != null; 80 } 81 82 /** 83 * Gets the value stored in the specified extension of this message. 84 */ getExtension(Extension<M, T> extension)85 public final <T> T getExtension(Extension<M, T> extension) { 86 if (unknownFieldData == null) { 87 return null; 88 } 89 FieldData field = unknownFieldData.get(WireFormatNano.getTagFieldNumber(extension.tag)); 90 return field == null ? null : field.getValue(extension); 91 } 92 93 /** 94 * Sets the value of the specified extension of this message. 95 */ setExtension(Extension<M, T> extension, T value)96 public final <T> M setExtension(Extension<M, T> extension, T value) { 97 int fieldNumber = WireFormatNano.getTagFieldNumber(extension.tag); 98 if (value == null) { 99 if (unknownFieldData != null) { 100 unknownFieldData.remove(fieldNumber); 101 if (unknownFieldData.isEmpty()) { 102 unknownFieldData = null; 103 } 104 } 105 } else { 106 FieldData field = null; 107 if (unknownFieldData == null) { 108 unknownFieldData = new FieldArray(); 109 } else { 110 field = unknownFieldData.get(fieldNumber); 111 } 112 if (field == null) { 113 unknownFieldData.put(fieldNumber, new FieldData(extension, value)); 114 } else { 115 field.setValue(extension, value); 116 } 117 } 118 119 @SuppressWarnings("unchecked") // Generated code should guarantee type safety 120 M typedThis = (M) this; 121 return typedThis; 122 } 123 124 /** 125 * Stores the binary data of an unknown field. 126 * 127 * <p>Generated messages will call this for unknown fields if the store_unknown_fields 128 * option is on. 129 * 130 * <p>Note that the tag might be a end-group tag (rather than the start of an unknown field) in 131 * which case we do not want to add an unknown field entry. 132 * 133 * @param input the input buffer. 134 * @param tag the tag of the field. 135 136 * @return {@literal true} unless the tag is an end-group tag. 137 */ storeUnknownField(CodedInputByteBufferNano input, int tag)138 protected final boolean storeUnknownField(CodedInputByteBufferNano input, int tag) 139 throws IOException { 140 int startPos = input.getPosition(); 141 if (!input.skipField(tag)) { 142 return false; // This wasn't an unknown field, it's an end-group tag. 143 } 144 int fieldNumber = WireFormatNano.getTagFieldNumber(tag); 145 int endPos = input.getPosition(); 146 byte[] bytes = input.getData(startPos, endPos - startPos); 147 UnknownFieldData unknownField = new UnknownFieldData(tag, bytes); 148 149 FieldData field = null; 150 if (unknownFieldData == null) { 151 unknownFieldData = new FieldArray(); 152 } else { 153 field = unknownFieldData.get(fieldNumber); 154 } 155 if (field == null) { 156 field = new FieldData(); 157 unknownFieldData.put(fieldNumber, field); 158 } 159 field.addUnknownField(unknownField); 160 return true; 161 } 162 163 @Override clone()164 public M clone() throws CloneNotSupportedException { 165 M cloned = (M) super.clone(); 166 InternalNano.cloneUnknownFieldData(this, cloned); 167 return cloned; 168 } 169 } 170