1// Protocol Buffers - Google's data interchange format 2// Copyright 2013 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 31package com.google.protobuf.nano; 32 33import java.io.IOException; 34 35/** 36 * Base class of those Protocol Buffer messages that need to store unknown fields, 37 * such as extensions. 38 */ 39public 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 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 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 */ 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 */ 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 */ 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 */ 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 164 public M clone() throws CloneNotSupportedException { 165 M cloned = (M) super.clone(); 166 InternalNano.cloneUnknownFieldData(this, cloned); 167 return cloned; 168 } 169} 170