17e02f374901ff471db5140f415de157ac6243050Tom Chao// Protocol Buffers - Google's data interchange format 27e02f374901ff471db5140f415de157ac6243050Tom Chao// Copyright 2013 Google Inc. All rights reserved. 37e02f374901ff471db5140f415de157ac6243050Tom Chao// http://code.google.com/p/protobuf/ 47e02f374901ff471db5140f415de157ac6243050Tom Chao// 57e02f374901ff471db5140f415de157ac6243050Tom Chao// Redistribution and use in source and binary forms, with or without 67e02f374901ff471db5140f415de157ac6243050Tom Chao// modification, are permitted provided that the following conditions are 77e02f374901ff471db5140f415de157ac6243050Tom Chao// met: 87e02f374901ff471db5140f415de157ac6243050Tom Chao// 97e02f374901ff471db5140f415de157ac6243050Tom Chao// * Redistributions of source code must retain the above copyright 107e02f374901ff471db5140f415de157ac6243050Tom Chao// notice, this list of conditions and the following disclaimer. 117e02f374901ff471db5140f415de157ac6243050Tom Chao// * Redistributions in binary form must reproduce the above 127e02f374901ff471db5140f415de157ac6243050Tom Chao// copyright notice, this list of conditions and the following disclaimer 137e02f374901ff471db5140f415de157ac6243050Tom Chao// in the documentation and/or other materials provided with the 147e02f374901ff471db5140f415de157ac6243050Tom Chao// distribution. 157e02f374901ff471db5140f415de157ac6243050Tom Chao// * Neither the name of Google Inc. nor the names of its 167e02f374901ff471db5140f415de157ac6243050Tom Chao// contributors may be used to endorse or promote products derived from 177e02f374901ff471db5140f415de157ac6243050Tom Chao// this software without specific prior written permission. 187e02f374901ff471db5140f415de157ac6243050Tom Chao// 197e02f374901ff471db5140f415de157ac6243050Tom Chao// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 207e02f374901ff471db5140f415de157ac6243050Tom Chao// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 217e02f374901ff471db5140f415de157ac6243050Tom Chao// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 227e02f374901ff471db5140f415de157ac6243050Tom Chao// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 237e02f374901ff471db5140f415de157ac6243050Tom Chao// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 247e02f374901ff471db5140f415de157ac6243050Tom Chao// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 257e02f374901ff471db5140f415de157ac6243050Tom Chao// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 267e02f374901ff471db5140f415de157ac6243050Tom Chao// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 277e02f374901ff471db5140f415de157ac6243050Tom Chao// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 287e02f374901ff471db5140f415de157ac6243050Tom Chao// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 297e02f374901ff471db5140f415de157ac6243050Tom Chao// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 307e02f374901ff471db5140f415de157ac6243050Tom Chao 317e02f374901ff471db5140f415de157ac6243050Tom Chaopackage com.google.protobuf.nano; 327e02f374901ff471db5140f415de157ac6243050Tom Chao 33382ddccb550e1c822ef26a0e65988998f7446624Max Caiimport java.io.IOException; 347e02f374901ff471db5140f415de157ac6243050Tom Chao 357e02f374901ff471db5140f415de157ac6243050Tom Chao/** 367e02f374901ff471db5140f415de157ac6243050Tom Chao * Base class of those Protocol Buffer messages that need to store unknown fields, 377e02f374901ff471db5140f415de157ac6243050Tom Chao * such as extensions. 387e02f374901ff471db5140f415de157ac6243050Tom Chao */ 39382ddccb550e1c822ef26a0e65988998f7446624Max Caipublic abstract class ExtendableMessageNano<M extends ExtendableMessageNano<M>> 40382ddccb550e1c822ef26a0e65988998f7446624Max Cai extends MessageNano { 417e02f374901ff471db5140f415de157ac6243050Tom Chao /** 427e02f374901ff471db5140f415de157ac6243050Tom Chao * A container for fields unknown to the message, including extensions. Extension fields can 43382ddccb550e1c822ef26a0e65988998f7446624Max Cai * can be accessed through the {@link #getExtension} and {@link #setExtension} methods. 447e02f374901ff471db5140f415de157ac6243050Tom Chao */ 45cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira protected FieldArray unknownFieldData; 467e02f374901ff471db5140f415de157ac6243050Tom Chao 477e02f374901ff471db5140f415de157ac6243050Tom Chao @Override 48c82101204dcde798f870d95e91f5483c3e57eb29Dave Hawkey protected int computeSerializedSize() { 49382ddccb550e1c822ef26a0e65988998f7446624Max Cai int size = 0; 50cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira if (unknownFieldData != null) { 51cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira for (int i = 0; i < unknownFieldData.size(); i++) { 52cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira FieldData field = unknownFieldData.dataAt(i); 53cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira size += field.computeSerializedSize(); 54cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira } 55382ddccb550e1c822ef26a0e65988998f7446624Max Cai } 567e02f374901ff471db5140f415de157ac6243050Tom Chao return size; 577e02f374901ff471db5140f415de157ac6243050Tom Chao } 587e02f374901ff471db5140f415de157ac6243050Tom Chao 59382ddccb550e1c822ef26a0e65988998f7446624Max Cai @Override 60382ddccb550e1c822ef26a0e65988998f7446624Max Cai public void writeTo(CodedOutputByteBufferNano output) throws IOException { 61cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira if (unknownFieldData == null) { 62cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira return; 63cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira } 64cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira for (int i = 0; i < unknownFieldData.size(); i++) { 65cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira FieldData field = unknownFieldData.dataAt(i); 66cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira field.writeTo(output); 67382ddccb550e1c822ef26a0e65988998f7446624Max Cai } 68382ddccb550e1c822ef26a0e65988998f7446624Max Cai } 69382ddccb550e1c822ef26a0e65988998f7446624Max Cai 707e02f374901ff471db5140f415de157ac6243050Tom Chao /** 717e02f374901ff471db5140f415de157ac6243050Tom Chao * Gets the value stored in the specified extension of this message. 727e02f374901ff471db5140f415de157ac6243050Tom Chao */ 73382ddccb550e1c822ef26a0e65988998f7446624Max Cai public final <T> T getExtension(Extension<M, T> extension) { 74cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira if (unknownFieldData == null) { 75cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira return null; 76cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira } 77cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira FieldData field = unknownFieldData.get(WireFormatNano.getTagFieldNumber(extension.tag)); 78cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira return field == null ? null : field.getValue(extension); 797e02f374901ff471db5140f415de157ac6243050Tom Chao } 807e02f374901ff471db5140f415de157ac6243050Tom Chao 817e02f374901ff471db5140f415de157ac6243050Tom Chao /** 827e02f374901ff471db5140f415de157ac6243050Tom Chao * Sets the value of the specified extension of this message. 837e02f374901ff471db5140f415de157ac6243050Tom Chao */ 84382ddccb550e1c822ef26a0e65988998f7446624Max Cai public final <T> M setExtension(Extension<M, T> extension, T value) { 85cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira int fieldNumber = WireFormatNano.getTagFieldNumber(extension.tag); 86cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira if (value == null) { 87cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira if (unknownFieldData != null) { 88cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira unknownFieldData.remove(fieldNumber); 89cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira if (unknownFieldData.isEmpty()) { 90cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira unknownFieldData = null; 91cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira } 92cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira } 93cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira } else { 94cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira FieldData field = null; 95cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira if (unknownFieldData == null) { 96cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira unknownFieldData = new FieldArray(); 97cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira } else { 98cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira field = unknownFieldData.get(fieldNumber); 99cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira } 100cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira if (field == null) { 101cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira unknownFieldData.put(fieldNumber, new FieldData(extension, value)); 102cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira } else { 103cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira field.setValue(extension, value); 104cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira } 105cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira } 106382ddccb550e1c822ef26a0e65988998f7446624Max Cai 107382ddccb550e1c822ef26a0e65988998f7446624Max Cai @SuppressWarnings("unchecked") // Generated code should guarantee type safety 108382ddccb550e1c822ef26a0e65988998f7446624Max Cai M typedThis = (M) this; 109382ddccb550e1c822ef26a0e65988998f7446624Max Cai return typedThis; 110382ddccb550e1c822ef26a0e65988998f7446624Max Cai } 111382ddccb550e1c822ef26a0e65988998f7446624Max Cai 112382ddccb550e1c822ef26a0e65988998f7446624Max Cai /** 113382ddccb550e1c822ef26a0e65988998f7446624Max Cai * Stores the binary data of an unknown field. 114382ddccb550e1c822ef26a0e65988998f7446624Max Cai * 115382ddccb550e1c822ef26a0e65988998f7446624Max Cai * <p>Generated messages will call this for unknown fields if the store_unknown_fields 116382ddccb550e1c822ef26a0e65988998f7446624Max Cai * option is on. 117382ddccb550e1c822ef26a0e65988998f7446624Max Cai * 118382ddccb550e1c822ef26a0e65988998f7446624Max Cai * <p>Note that the tag might be a end-group tag (rather than the start of an unknown field) in 119382ddccb550e1c822ef26a0e65988998f7446624Max Cai * which case we do not want to add an unknown field entry. 120382ddccb550e1c822ef26a0e65988998f7446624Max Cai * 121382ddccb550e1c822ef26a0e65988998f7446624Max Cai * @param input the input buffer. 122382ddccb550e1c822ef26a0e65988998f7446624Max Cai * @param tag the tag of the field. 123382ddccb550e1c822ef26a0e65988998f7446624Max Cai 124382ddccb550e1c822ef26a0e65988998f7446624Max Cai * @return {@literal true} unless the tag is an end-group tag. 125382ddccb550e1c822ef26a0e65988998f7446624Max Cai */ 126382ddccb550e1c822ef26a0e65988998f7446624Max Cai protected final boolean storeUnknownField(CodedInputByteBufferNano input, int tag) 127382ddccb550e1c822ef26a0e65988998f7446624Max Cai throws IOException { 128382ddccb550e1c822ef26a0e65988998f7446624Max Cai int startPos = input.getPosition(); 129382ddccb550e1c822ef26a0e65988998f7446624Max Cai if (!input.skipField(tag)) { 130382ddccb550e1c822ef26a0e65988998f7446624Max Cai return false; // This wasn't an unknown field, it's an end-group tag. 131382ddccb550e1c822ef26a0e65988998f7446624Max Cai } 132cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira int fieldNumber = WireFormatNano.getTagFieldNumber(tag); 133382ddccb550e1c822ef26a0e65988998f7446624Max Cai int endPos = input.getPosition(); 134382ddccb550e1c822ef26a0e65988998f7446624Max Cai byte[] bytes = input.getData(startPos, endPos - startPos); 135cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira UnknownFieldData unknownField = new UnknownFieldData(tag, bytes); 136cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira 137cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira FieldData field = null; 138cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira if (unknownFieldData == null) { 139cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira unknownFieldData = new FieldArray(); 140cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira } else { 141cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira field = unknownFieldData.get(fieldNumber); 142cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira } 143cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira if (field == null) { 144cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira field = new FieldData(); 145cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira unknownFieldData.put(fieldNumber, field); 146cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira } 147cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira field.addUnknownField(unknownField); 148382ddccb550e1c822ef26a0e65988998f7446624Max Cai return true; 1497e02f374901ff471db5140f415de157ac6243050Tom Chao } 15011f883e185a2ea6fd6d0b19520e9f0f004e90e5cMax Cai 15111f883e185a2ea6fd6d0b19520e9f0f004e90e5cMax Cai /** 15211f883e185a2ea6fd6d0b19520e9f0f004e90e5cMax Cai * Returns whether the stored unknown field data in this message is equivalent to that in the 15311f883e185a2ea6fd6d0b19520e9f0f004e90e5cMax Cai * other message. 15411f883e185a2ea6fd6d0b19520e9f0f004e90e5cMax Cai * 15511f883e185a2ea6fd6d0b19520e9f0f004e90e5cMax Cai * @param other the other message. 15611f883e185a2ea6fd6d0b19520e9f0f004e90e5cMax Cai * @return whether the two sets of unknown field data are equal. 15711f883e185a2ea6fd6d0b19520e9f0f004e90e5cMax Cai */ 15811f883e185a2ea6fd6d0b19520e9f0f004e90e5cMax Cai protected final boolean unknownFieldDataEquals(M other) { 15911f883e185a2ea6fd6d0b19520e9f0f004e90e5cMax Cai if (unknownFieldData == null || unknownFieldData.isEmpty()) { 16011f883e185a2ea6fd6d0b19520e9f0f004e90e5cMax Cai return other.unknownFieldData == null || other.unknownFieldData.isEmpty(); 16111f883e185a2ea6fd6d0b19520e9f0f004e90e5cMax Cai } else { 16211f883e185a2ea6fd6d0b19520e9f0f004e90e5cMax Cai return unknownFieldData.equals(other.unknownFieldData); 16311f883e185a2ea6fd6d0b19520e9f0f004e90e5cMax Cai } 16411f883e185a2ea6fd6d0b19520e9f0f004e90e5cMax Cai } 16511f883e185a2ea6fd6d0b19520e9f0f004e90e5cMax Cai 16611f883e185a2ea6fd6d0b19520e9f0f004e90e5cMax Cai /** 16711f883e185a2ea6fd6d0b19520e9f0f004e90e5cMax Cai * Computes the hashcode representing the unknown field data stored in this message. 16811f883e185a2ea6fd6d0b19520e9f0f004e90e5cMax Cai * 16911f883e185a2ea6fd6d0b19520e9f0f004e90e5cMax Cai * @return the hashcode for the unknown field data. 17011f883e185a2ea6fd6d0b19520e9f0f004e90e5cMax Cai */ 17111f883e185a2ea6fd6d0b19520e9f0f004e90e5cMax Cai protected final int unknownFieldDataHashCode() { 17211f883e185a2ea6fd6d0b19520e9f0f004e90e5cMax Cai return (unknownFieldData == null || unknownFieldData.isEmpty() 17311f883e185a2ea6fd6d0b19520e9f0f004e90e5cMax Cai ? 0 : unknownFieldData.hashCode()); 17411f883e185a2ea6fd6d0b19520e9f0f004e90e5cMax Cai } 175382ddccb550e1c822ef26a0e65988998f7446624Max Cai} 176