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