temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 1 | // Protocol Buffers - Google's data interchange format |
kenton@google.com | 24bf56f | 2008-09-24 20:31:01 +0000 | [diff] [blame] | 2 | // Copyright 2008 Google Inc. All rights reserved. |
Feng Xiao | e428862 | 2014-10-01 16:26:23 -0700 | [diff] [blame] | 3 | // https://developers.google.com/protocol-buffers/ |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 4 | // |
kenton@google.com | 24bf56f | 2008-09-24 20:31:01 +0000 | [diff] [blame] | 5 | // Redistribution and use in source and binary forms, with or without |
| 6 | // modification, are permitted provided that the following conditions are |
| 7 | // met: |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 8 | // |
kenton@google.com | 24bf56f | 2008-09-24 20:31:01 +0000 | [diff] [blame] | 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. |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 18 | // |
kenton@google.com | 24bf56f | 2008-09-24 20:31:01 +0000 | [diff] [blame] | 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. |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 30 | |
| 31 | // Author: kenton@google.com (Kenton Varda) |
| 32 | // Based on original Protocol Buffers design by |
| 33 | // Sanjay Ghemawat, Jeff Dean, and others. |
| 34 | |
| 35 | #include <stack> |
| 36 | #include <string> |
| 37 | #include <vector> |
| 38 | |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 39 | #include <google/protobuf/wire_format.h> |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 40 | |
| 41 | #include <google/protobuf/stubs/common.h> |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 42 | #include <google/protobuf/stubs/stringprintf.h> |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 43 | #include <google/protobuf/descriptor.h> |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 44 | #include <google/protobuf/wire_format_lite_inl.h> |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 45 | #include <google/protobuf/descriptor.pb.h> |
| 46 | #include <google/protobuf/io/coded_stream.h> |
| 47 | #include <google/protobuf/io/zero_copy_stream.h> |
| 48 | #include <google/protobuf/io/zero_copy_stream_impl.h> |
| 49 | #include <google/protobuf/unknown_field_set.h> |
| 50 | |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 51 | |
xiaofeng@google.com | b55a20f | 2012-09-22 02:40:50 +0000 | [diff] [blame] | 52 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 53 | namespace google { |
| 54 | namespace protobuf { |
| 55 | namespace internal { |
| 56 | |
| 57 | namespace { |
| 58 | |
| 59 | // This function turns out to be convenient when using some macros later. |
| 60 | inline int GetEnumNumber(const EnumValueDescriptor* descriptor) { |
| 61 | return descriptor->number(); |
| 62 | } |
| 63 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 64 | } // anonymous namespace |
| 65 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 66 | // =================================================================== |
| 67 | |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 68 | bool UnknownFieldSetFieldSkipper::SkipField( |
| 69 | io::CodedInputStream* input, uint32 tag) { |
| 70 | return WireFormat::SkipField(input, tag, unknown_fields_); |
| 71 | } |
| 72 | |
| 73 | bool UnknownFieldSetFieldSkipper::SkipMessage(io::CodedInputStream* input) { |
| 74 | return WireFormat::SkipMessage(input, unknown_fields_); |
| 75 | } |
| 76 | |
| 77 | void UnknownFieldSetFieldSkipper::SkipUnknownEnum( |
| 78 | int field_number, int value) { |
| 79 | unknown_fields_->AddVarint(field_number, value); |
| 80 | } |
| 81 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 82 | bool WireFormat::SkipField(io::CodedInputStream* input, uint32 tag, |
| 83 | UnknownFieldSet* unknown_fields) { |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 84 | int number = WireFormatLite::GetTagFieldNumber(tag); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 85 | |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 86 | switch (WireFormatLite::GetTagWireType(tag)) { |
| 87 | case WireFormatLite::WIRETYPE_VARINT: { |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 88 | uint64 value; |
| 89 | if (!input->ReadVarint64(&value)) return false; |
kenton@google.com | d37d46d | 2009-04-25 02:53:47 +0000 | [diff] [blame] | 90 | if (unknown_fields != NULL) unknown_fields->AddVarint(number, value); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 91 | return true; |
| 92 | } |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 93 | case WireFormatLite::WIRETYPE_FIXED64: { |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 94 | uint64 value; |
| 95 | if (!input->ReadLittleEndian64(&value)) return false; |
kenton@google.com | d37d46d | 2009-04-25 02:53:47 +0000 | [diff] [blame] | 96 | if (unknown_fields != NULL) unknown_fields->AddFixed64(number, value); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 97 | return true; |
| 98 | } |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 99 | case WireFormatLite::WIRETYPE_LENGTH_DELIMITED: { |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 100 | uint32 length; |
| 101 | if (!input->ReadVarint32(&length)) return false; |
kenton@google.com | d37d46d | 2009-04-25 02:53:47 +0000 | [diff] [blame] | 102 | if (unknown_fields == NULL) { |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 103 | if (!input->Skip(length)) return false; |
| 104 | } else { |
kenton@google.com | d37d46d | 2009-04-25 02:53:47 +0000 | [diff] [blame] | 105 | if (!input->ReadString(unknown_fields->AddLengthDelimited(number), |
| 106 | length)) { |
temporal | 779f61c | 2008-08-13 03:15:00 +0000 | [diff] [blame] | 107 | return false; |
| 108 | } |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 109 | } |
| 110 | return true; |
| 111 | } |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 112 | case WireFormatLite::WIRETYPE_START_GROUP: { |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 113 | if (!input->IncrementRecursionDepth()) return false; |
kenton@google.com | d37d46d | 2009-04-25 02:53:47 +0000 | [diff] [blame] | 114 | if (!SkipMessage(input, (unknown_fields == NULL) ? |
| 115 | NULL : unknown_fields->AddGroup(number))) { |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 116 | return false; |
| 117 | } |
| 118 | input->DecrementRecursionDepth(); |
| 119 | // Check that the ending tag matched the starting tag. |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 120 | if (!input->LastTagWas(WireFormatLite::MakeTag( |
| 121 | WireFormatLite::GetTagFieldNumber(tag), |
| 122 | WireFormatLite::WIRETYPE_END_GROUP))) { |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 123 | return false; |
| 124 | } |
| 125 | return true; |
| 126 | } |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 127 | case WireFormatLite::WIRETYPE_END_GROUP: { |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 128 | return false; |
| 129 | } |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 130 | case WireFormatLite::WIRETYPE_FIXED32: { |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 131 | uint32 value; |
| 132 | if (!input->ReadLittleEndian32(&value)) return false; |
kenton@google.com | d37d46d | 2009-04-25 02:53:47 +0000 | [diff] [blame] | 133 | if (unknown_fields != NULL) unknown_fields->AddFixed32(number, value); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 134 | return true; |
| 135 | } |
| 136 | default: { |
| 137 | return false; |
| 138 | } |
| 139 | } |
| 140 | } |
| 141 | |
| 142 | bool WireFormat::SkipMessage(io::CodedInputStream* input, |
| 143 | UnknownFieldSet* unknown_fields) { |
Jisi Liu | 885b612 | 2015-02-28 14:51:22 -0800 | [diff] [blame^] | 144 | while (true) { |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 145 | uint32 tag = input->ReadTag(); |
| 146 | if (tag == 0) { |
| 147 | // End of input. This is a valid place to end, so return true. |
| 148 | return true; |
| 149 | } |
| 150 | |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 151 | WireFormatLite::WireType wire_type = WireFormatLite::GetTagWireType(tag); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 152 | |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 153 | if (wire_type == WireFormatLite::WIRETYPE_END_GROUP) { |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 154 | // Must be the end of the message. |
| 155 | return true; |
| 156 | } |
| 157 | |
| 158 | if (!SkipField(input, tag, unknown_fields)) return false; |
| 159 | } |
| 160 | } |
| 161 | |
Jisi Liu | 885b612 | 2015-02-28 14:51:22 -0800 | [diff] [blame^] | 162 | bool WireFormat::ReadPackedEnumPreserveUnknowns(io::CodedInputStream* input, |
| 163 | uint32 field_number, |
| 164 | bool (*is_valid)(int), |
| 165 | UnknownFieldSet* unknown_fields, |
| 166 | RepeatedField<int>* values) { |
| 167 | uint32 length; |
| 168 | if (!input->ReadVarint32(&length)) return false; |
| 169 | io::CodedInputStream::Limit limit = input->PushLimit(length); |
| 170 | while (input->BytesUntilLimit() > 0) { |
| 171 | int value; |
| 172 | if (!google::protobuf::internal::WireFormatLite::ReadPrimitive< |
| 173 | int, WireFormatLite::TYPE_ENUM>(input, &value)) { |
| 174 | return false; |
| 175 | } |
| 176 | if (is_valid == NULL || is_valid(value)) { |
| 177 | values->Add(value); |
| 178 | } else { |
| 179 | unknown_fields->AddVarint(field_number, value); |
| 180 | } |
| 181 | } |
| 182 | input->PopLimit(limit); |
| 183 | return true; |
| 184 | } |
| 185 | |
| 186 | |
kenton@google.com | d37d46d | 2009-04-25 02:53:47 +0000 | [diff] [blame] | 187 | void WireFormat::SerializeUnknownFields(const UnknownFieldSet& unknown_fields, |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 188 | io::CodedOutputStream* output) { |
| 189 | for (int i = 0; i < unknown_fields.field_count(); i++) { |
| 190 | const UnknownField& field = unknown_fields.field(i); |
kenton@google.com | d37d46d | 2009-04-25 02:53:47 +0000 | [diff] [blame] | 191 | switch (field.type()) { |
| 192 | case UnknownField::TYPE_VARINT: |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 193 | output->WriteVarint32(WireFormatLite::MakeTag(field.number(), |
| 194 | WireFormatLite::WIRETYPE_VARINT)); |
kenton@google.com | d37d46d | 2009-04-25 02:53:47 +0000 | [diff] [blame] | 195 | output->WriteVarint64(field.varint()); |
| 196 | break; |
| 197 | case UnknownField::TYPE_FIXED32: |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 198 | output->WriteVarint32(WireFormatLite::MakeTag(field.number(), |
| 199 | WireFormatLite::WIRETYPE_FIXED32)); |
kenton@google.com | d37d46d | 2009-04-25 02:53:47 +0000 | [diff] [blame] | 200 | output->WriteLittleEndian32(field.fixed32()); |
| 201 | break; |
| 202 | case UnknownField::TYPE_FIXED64: |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 203 | output->WriteVarint32(WireFormatLite::MakeTag(field.number(), |
| 204 | WireFormatLite::WIRETYPE_FIXED64)); |
kenton@google.com | d37d46d | 2009-04-25 02:53:47 +0000 | [diff] [blame] | 205 | output->WriteLittleEndian64(field.fixed64()); |
| 206 | break; |
| 207 | case UnknownField::TYPE_LENGTH_DELIMITED: |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 208 | output->WriteVarint32(WireFormatLite::MakeTag(field.number(), |
| 209 | WireFormatLite::WIRETYPE_LENGTH_DELIMITED)); |
kenton@google.com | d37d46d | 2009-04-25 02:53:47 +0000 | [diff] [blame] | 210 | output->WriteVarint32(field.length_delimited().size()); |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 211 | output->WriteRawMaybeAliased(field.length_delimited().data(), |
| 212 | field.length_delimited().size()); |
kenton@google.com | d37d46d | 2009-04-25 02:53:47 +0000 | [diff] [blame] | 213 | break; |
| 214 | case UnknownField::TYPE_GROUP: |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 215 | output->WriteVarint32(WireFormatLite::MakeTag(field.number(), |
| 216 | WireFormatLite::WIRETYPE_START_GROUP)); |
kenton@google.com | d37d46d | 2009-04-25 02:53:47 +0000 | [diff] [blame] | 217 | SerializeUnknownFields(field.group(), output); |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 218 | output->WriteVarint32(WireFormatLite::MakeTag(field.number(), |
| 219 | WireFormatLite::WIRETYPE_END_GROUP)); |
kenton@google.com | d37d46d | 2009-04-25 02:53:47 +0000 | [diff] [blame] | 220 | break; |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 221 | } |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 222 | } |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 223 | } |
| 224 | |
kenton@google.com | d37d46d | 2009-04-25 02:53:47 +0000 | [diff] [blame] | 225 | uint8* WireFormat::SerializeUnknownFieldsToArray( |
| 226 | const UnknownFieldSet& unknown_fields, |
| 227 | uint8* target) { |
| 228 | for (int i = 0; i < unknown_fields.field_count(); i++) { |
| 229 | const UnknownField& field = unknown_fields.field(i); |
| 230 | |
| 231 | switch (field.type()) { |
| 232 | case UnknownField::TYPE_VARINT: |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 233 | target = WireFormatLite::WriteInt64ToArray( |
| 234 | field.number(), field.varint(), target); |
kenton@google.com | d37d46d | 2009-04-25 02:53:47 +0000 | [diff] [blame] | 235 | break; |
| 236 | case UnknownField::TYPE_FIXED32: |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 237 | target = WireFormatLite::WriteFixed32ToArray( |
| 238 | field.number(), field.fixed32(), target); |
kenton@google.com | d37d46d | 2009-04-25 02:53:47 +0000 | [diff] [blame] | 239 | break; |
| 240 | case UnknownField::TYPE_FIXED64: |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 241 | target = WireFormatLite::WriteFixed64ToArray( |
| 242 | field.number(), field.fixed64(), target); |
kenton@google.com | d37d46d | 2009-04-25 02:53:47 +0000 | [diff] [blame] | 243 | break; |
| 244 | case UnknownField::TYPE_LENGTH_DELIMITED: |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 245 | target = WireFormatLite::WriteBytesToArray( |
| 246 | field.number(), field.length_delimited(), target); |
kenton@google.com | d37d46d | 2009-04-25 02:53:47 +0000 | [diff] [blame] | 247 | break; |
| 248 | case UnknownField::TYPE_GROUP: |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 249 | target = WireFormatLite::WriteTagToArray( |
| 250 | field.number(), WireFormatLite::WIRETYPE_START_GROUP, target); |
kenton@google.com | d37d46d | 2009-04-25 02:53:47 +0000 | [diff] [blame] | 251 | target = SerializeUnknownFieldsToArray(field.group(), target); |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 252 | target = WireFormatLite::WriteTagToArray( |
| 253 | field.number(), WireFormatLite::WIRETYPE_END_GROUP, target); |
kenton@google.com | d37d46d | 2009-04-25 02:53:47 +0000 | [diff] [blame] | 254 | break; |
| 255 | } |
| 256 | } |
| 257 | return target; |
| 258 | } |
| 259 | |
| 260 | void WireFormat::SerializeUnknownMessageSetItems( |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 261 | const UnknownFieldSet& unknown_fields, |
| 262 | io::CodedOutputStream* output) { |
| 263 | for (int i = 0; i < unknown_fields.field_count(); i++) { |
| 264 | const UnknownField& field = unknown_fields.field(i); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 265 | // The only unknown fields that are allowed to exist in a MessageSet are |
| 266 | // messages, which are length-delimited. |
kenton@google.com | d37d46d | 2009-04-25 02:53:47 +0000 | [diff] [blame] | 267 | if (field.type() == UnknownField::TYPE_LENGTH_DELIMITED) { |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 268 | // Start group. |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 269 | output->WriteVarint32(WireFormatLite::kMessageSetItemStartTag); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 270 | |
| 271 | // Write type ID. |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 272 | output->WriteVarint32(WireFormatLite::kMessageSetTypeIdTag); |
kenton@google.com | d37d46d | 2009-04-25 02:53:47 +0000 | [diff] [blame] | 273 | output->WriteVarint32(field.number()); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 274 | |
| 275 | // Write message. |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 276 | output->WriteVarint32(WireFormatLite::kMessageSetMessageTag); |
xiaofeng@google.com | b55a20f | 2012-09-22 02:40:50 +0000 | [diff] [blame] | 277 | field.SerializeLengthDelimitedNoTag(output); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 278 | |
| 279 | // End group. |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 280 | output->WriteVarint32(WireFormatLite::kMessageSetItemEndTag); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 281 | } |
kenton@google.com | d37d46d | 2009-04-25 02:53:47 +0000 | [diff] [blame] | 282 | } |
| 283 | } |
| 284 | |
| 285 | uint8* WireFormat::SerializeUnknownMessageSetItemsToArray( |
| 286 | const UnknownFieldSet& unknown_fields, |
| 287 | uint8* target) { |
| 288 | for (int i = 0; i < unknown_fields.field_count(); i++) { |
| 289 | const UnknownField& field = unknown_fields.field(i); |
| 290 | |
| 291 | // The only unknown fields that are allowed to exist in a MessageSet are |
| 292 | // messages, which are length-delimited. |
| 293 | if (field.type() == UnknownField::TYPE_LENGTH_DELIMITED) { |
kenton@google.com | d37d46d | 2009-04-25 02:53:47 +0000 | [diff] [blame] | 294 | // Start group. |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 295 | target = io::CodedOutputStream::WriteTagToArray( |
| 296 | WireFormatLite::kMessageSetItemStartTag, target); |
kenton@google.com | d37d46d | 2009-04-25 02:53:47 +0000 | [diff] [blame] | 297 | |
| 298 | // Write type ID. |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 299 | target = io::CodedOutputStream::WriteTagToArray( |
| 300 | WireFormatLite::kMessageSetTypeIdTag, target); |
| 301 | target = io::CodedOutputStream::WriteVarint32ToArray( |
| 302 | field.number(), target); |
kenton@google.com | d37d46d | 2009-04-25 02:53:47 +0000 | [diff] [blame] | 303 | |
| 304 | // Write message. |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 305 | target = io::CodedOutputStream::WriteTagToArray( |
| 306 | WireFormatLite::kMessageSetMessageTag, target); |
xiaofeng@google.com | b55a20f | 2012-09-22 02:40:50 +0000 | [diff] [blame] | 307 | target = field.SerializeLengthDelimitedNoTagToArray(target); |
kenton@google.com | d37d46d | 2009-04-25 02:53:47 +0000 | [diff] [blame] | 308 | |
| 309 | // End group. |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 310 | target = io::CodedOutputStream::WriteTagToArray( |
| 311 | WireFormatLite::kMessageSetItemEndTag, target); |
kenton@google.com | d37d46d | 2009-04-25 02:53:47 +0000 | [diff] [blame] | 312 | } |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 313 | } |
| 314 | |
kenton@google.com | d37d46d | 2009-04-25 02:53:47 +0000 | [diff] [blame] | 315 | return target; |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 316 | } |
| 317 | |
| 318 | int WireFormat::ComputeUnknownFieldsSize( |
| 319 | const UnknownFieldSet& unknown_fields) { |
| 320 | int size = 0; |
| 321 | for (int i = 0; i < unknown_fields.field_count(); i++) { |
| 322 | const UnknownField& field = unknown_fields.field(i); |
| 323 | |
kenton@google.com | d37d46d | 2009-04-25 02:53:47 +0000 | [diff] [blame] | 324 | switch (field.type()) { |
| 325 | case UnknownField::TYPE_VARINT: |
| 326 | size += io::CodedOutputStream::VarintSize32( |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 327 | WireFormatLite::MakeTag(field.number(), |
| 328 | WireFormatLite::WIRETYPE_VARINT)); |
kenton@google.com | d37d46d | 2009-04-25 02:53:47 +0000 | [diff] [blame] | 329 | size += io::CodedOutputStream::VarintSize64(field.varint()); |
| 330 | break; |
| 331 | case UnknownField::TYPE_FIXED32: |
| 332 | size += io::CodedOutputStream::VarintSize32( |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 333 | WireFormatLite::MakeTag(field.number(), |
| 334 | WireFormatLite::WIRETYPE_FIXED32)); |
kenton@google.com | d37d46d | 2009-04-25 02:53:47 +0000 | [diff] [blame] | 335 | size += sizeof(int32); |
| 336 | break; |
| 337 | case UnknownField::TYPE_FIXED64: |
| 338 | size += io::CodedOutputStream::VarintSize32( |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 339 | WireFormatLite::MakeTag(field.number(), |
| 340 | WireFormatLite::WIRETYPE_FIXED64)); |
kenton@google.com | d37d46d | 2009-04-25 02:53:47 +0000 | [diff] [blame] | 341 | size += sizeof(int64); |
| 342 | break; |
| 343 | case UnknownField::TYPE_LENGTH_DELIMITED: |
| 344 | size += io::CodedOutputStream::VarintSize32( |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 345 | WireFormatLite::MakeTag(field.number(), |
| 346 | WireFormatLite::WIRETYPE_LENGTH_DELIMITED)); |
kenton@google.com | d37d46d | 2009-04-25 02:53:47 +0000 | [diff] [blame] | 347 | size += io::CodedOutputStream::VarintSize32( |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 348 | field.length_delimited().size()); |
kenton@google.com | d37d46d | 2009-04-25 02:53:47 +0000 | [diff] [blame] | 349 | size += field.length_delimited().size(); |
| 350 | break; |
| 351 | case UnknownField::TYPE_GROUP: |
| 352 | size += io::CodedOutputStream::VarintSize32( |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 353 | WireFormatLite::MakeTag(field.number(), |
| 354 | WireFormatLite::WIRETYPE_START_GROUP)); |
kenton@google.com | d37d46d | 2009-04-25 02:53:47 +0000 | [diff] [blame] | 355 | size += ComputeUnknownFieldsSize(field.group()); |
| 356 | size += io::CodedOutputStream::VarintSize32( |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 357 | WireFormatLite::MakeTag(field.number(), |
| 358 | WireFormatLite::WIRETYPE_END_GROUP)); |
kenton@google.com | d37d46d | 2009-04-25 02:53:47 +0000 | [diff] [blame] | 359 | break; |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 360 | } |
| 361 | } |
| 362 | |
| 363 | return size; |
| 364 | } |
| 365 | |
| 366 | int WireFormat::ComputeUnknownMessageSetItemsSize( |
| 367 | const UnknownFieldSet& unknown_fields) { |
| 368 | int size = 0; |
| 369 | for (int i = 0; i < unknown_fields.field_count(); i++) { |
| 370 | const UnknownField& field = unknown_fields.field(i); |
| 371 | |
| 372 | // The only unknown fields that are allowed to exist in a MessageSet are |
| 373 | // messages, which are length-delimited. |
kenton@google.com | d37d46d | 2009-04-25 02:53:47 +0000 | [diff] [blame] | 374 | if (field.type() == UnknownField::TYPE_LENGTH_DELIMITED) { |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 375 | size += WireFormatLite::kMessageSetItemTagsSize; |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 376 | size += io::CodedOutputStream::VarintSize32(field.number()); |
xiaofeng@google.com | b55a20f | 2012-09-22 02:40:50 +0000 | [diff] [blame] | 377 | |
| 378 | int field_size = field.GetLengthDelimitedSize(); |
| 379 | size += io::CodedOutputStream::VarintSize32(field_size); |
| 380 | size += field_size; |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 381 | } |
| 382 | } |
| 383 | |
| 384 | return size; |
| 385 | } |
| 386 | |
| 387 | // =================================================================== |
| 388 | |
temporal | 779f61c | 2008-08-13 03:15:00 +0000 | [diff] [blame] | 389 | bool WireFormat::ParseAndMergePartial(io::CodedInputStream* input, |
| 390 | Message* message) { |
| 391 | const Descriptor* descriptor = message->GetDescriptor(); |
| 392 | const Reflection* message_reflection = message->GetReflection(); |
| 393 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 394 | while(true) { |
| 395 | uint32 tag = input->ReadTag(); |
| 396 | if (tag == 0) { |
| 397 | // End of input. This is a valid place to end, so return true. |
| 398 | return true; |
| 399 | } |
| 400 | |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 401 | if (WireFormatLite::GetTagWireType(tag) == |
| 402 | WireFormatLite::WIRETYPE_END_GROUP) { |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 403 | // Must be the end of the message. |
| 404 | return true; |
| 405 | } |
| 406 | |
| 407 | const FieldDescriptor* field = NULL; |
| 408 | |
| 409 | if (descriptor != NULL) { |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 410 | int field_number = WireFormatLite::GetTagFieldNumber(tag); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 411 | field = descriptor->FindFieldByNumber(field_number); |
| 412 | |
| 413 | // If that failed, check if the field is an extension. |
| 414 | if (field == NULL && descriptor->IsExtensionNumber(field_number)) { |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 415 | if (input->GetExtensionPool() == NULL) { |
| 416 | field = message_reflection->FindKnownExtensionByNumber(field_number); |
| 417 | } else { |
| 418 | field = input->GetExtensionPool() |
| 419 | ->FindExtensionByNumber(descriptor, field_number); |
| 420 | } |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 421 | } |
| 422 | |
| 423 | // If that failed, but we're a MessageSet, and this is the tag for a |
| 424 | // MessageSet item, then parse that. |
| 425 | if (field == NULL && |
| 426 | descriptor->options().message_set_wire_format() && |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 427 | tag == WireFormatLite::kMessageSetItemStartTag) { |
temporal | 779f61c | 2008-08-13 03:15:00 +0000 | [diff] [blame] | 428 | if (!ParseAndMergeMessageSetItem(input, message)) { |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 429 | return false; |
| 430 | } |
| 431 | continue; // Skip ParseAndMergeField(); already taken care of. |
| 432 | } |
| 433 | } |
| 434 | |
temporal | 779f61c | 2008-08-13 03:15:00 +0000 | [diff] [blame] | 435 | if (!ParseAndMergeField(tag, field, message, input)) { |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 436 | return false; |
| 437 | } |
| 438 | } |
| 439 | } |
| 440 | |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 441 | bool WireFormat::SkipMessageSetField(io::CodedInputStream* input, |
| 442 | uint32 field_number, |
| 443 | UnknownFieldSet* unknown_fields) { |
| 444 | uint32 length; |
| 445 | if (!input->ReadVarint32(&length)) return false; |
| 446 | return input->ReadString( |
| 447 | unknown_fields->AddLengthDelimited(field_number), length); |
| 448 | } |
| 449 | |
| 450 | bool WireFormat::ParseAndMergeMessageSetField(uint32 field_number, |
| 451 | const FieldDescriptor* field, |
| 452 | Message* message, |
| 453 | io::CodedInputStream* input) { |
| 454 | const Reflection* message_reflection = message->GetReflection(); |
| 455 | if (field == NULL) { |
| 456 | // We store unknown MessageSet extensions as groups. |
| 457 | return SkipMessageSetField( |
| 458 | input, field_number, message_reflection->MutableUnknownFields(message)); |
| 459 | } else if (field->is_repeated() || |
| 460 | field->type() != FieldDescriptor::TYPE_MESSAGE) { |
| 461 | // This shouldn't happen as we only allow optional message extensions to |
| 462 | // MessageSet. |
| 463 | GOOGLE_LOG(ERROR) << "Extensions of MessageSets must be optional messages."; |
| 464 | return false; |
| 465 | } else { |
| 466 | Message* sub_message = message_reflection->MutableMessage( |
| 467 | message, field, input->GetExtensionFactory()); |
| 468 | return WireFormatLite::ReadMessage(input, sub_message); |
| 469 | } |
| 470 | } |
| 471 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 472 | bool WireFormat::ParseAndMergeField( |
| 473 | uint32 tag, |
| 474 | const FieldDescriptor* field, // May be NULL for unknown |
temporal | 779f61c | 2008-08-13 03:15:00 +0000 | [diff] [blame] | 475 | Message* message, |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 476 | io::CodedInputStream* input) { |
temporal | 779f61c | 2008-08-13 03:15:00 +0000 | [diff] [blame] | 477 | const Reflection* message_reflection = message->GetReflection(); |
| 478 | |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 479 | enum { UNKNOWN, NORMAL_FORMAT, PACKED_FORMAT } value_format; |
| 480 | |
| 481 | if (field == NULL) { |
| 482 | value_format = UNKNOWN; |
| 483 | } else if (WireFormatLite::GetTagWireType(tag) == |
| 484 | WireTypeForFieldType(field->type())) { |
| 485 | value_format = NORMAL_FORMAT; |
| 486 | } else if (field->is_packable() && |
| 487 | WireFormatLite::GetTagWireType(tag) == |
| 488 | WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { |
| 489 | value_format = PACKED_FORMAT; |
| 490 | } else { |
| 491 | // We don't recognize this field. Either the field number is unknown |
| 492 | // or the wire type doesn't match. Put it in our unknown field set. |
| 493 | value_format = UNKNOWN; |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 494 | } |
| 495 | |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 496 | if (value_format == UNKNOWN) { |
| 497 | return SkipField(input, tag, |
| 498 | message_reflection->MutableUnknownFields(message)); |
| 499 | } else if (value_format == PACKED_FORMAT) { |
kenton@google.com | 2d6daa7 | 2009-01-22 01:27:00 +0000 | [diff] [blame] | 500 | uint32 length; |
| 501 | if (!input->ReadVarint32(&length)) return false; |
| 502 | io::CodedInputStream::Limit limit = input->PushLimit(length); |
| 503 | |
| 504 | switch (field->type()) { |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 505 | #define HANDLE_PACKED_TYPE(TYPE, CPPTYPE, CPPTYPE_METHOD) \ |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 506 | case FieldDescriptor::TYPE_##TYPE: { \ |
| 507 | while (input->BytesUntilLimit() > 0) { \ |
| 508 | CPPTYPE value; \ |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 509 | if (!WireFormatLite::ReadPrimitive< \ |
| 510 | CPPTYPE, WireFormatLite::TYPE_##TYPE>(input, &value)) \ |
| 511 | return false; \ |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 512 | message_reflection->Add##CPPTYPE_METHOD(message, field, value); \ |
| 513 | } \ |
| 514 | break; \ |
kenton@google.com | 2d6daa7 | 2009-01-22 01:27:00 +0000 | [diff] [blame] | 515 | } |
| 516 | |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 517 | HANDLE_PACKED_TYPE( INT32, int32, Int32) |
| 518 | HANDLE_PACKED_TYPE( INT64, int64, Int64) |
| 519 | HANDLE_PACKED_TYPE(SINT32, int32, Int32) |
| 520 | HANDLE_PACKED_TYPE(SINT64, int64, Int64) |
| 521 | HANDLE_PACKED_TYPE(UINT32, uint32, UInt32) |
| 522 | HANDLE_PACKED_TYPE(UINT64, uint64, UInt64) |
kenton@google.com | 2d6daa7 | 2009-01-22 01:27:00 +0000 | [diff] [blame] | 523 | |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 524 | HANDLE_PACKED_TYPE( FIXED32, uint32, UInt32) |
| 525 | HANDLE_PACKED_TYPE( FIXED64, uint64, UInt64) |
| 526 | HANDLE_PACKED_TYPE(SFIXED32, int32, Int32) |
| 527 | HANDLE_PACKED_TYPE(SFIXED64, int64, Int64) |
kenton@google.com | 2d6daa7 | 2009-01-22 01:27:00 +0000 | [diff] [blame] | 528 | |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 529 | HANDLE_PACKED_TYPE(FLOAT , float , Float ) |
| 530 | HANDLE_PACKED_TYPE(DOUBLE, double, Double) |
kenton@google.com | 2d6daa7 | 2009-01-22 01:27:00 +0000 | [diff] [blame] | 531 | |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 532 | HANDLE_PACKED_TYPE(BOOL, bool, Bool) |
kenton@google.com | 2d6daa7 | 2009-01-22 01:27:00 +0000 | [diff] [blame] | 533 | #undef HANDLE_PACKED_TYPE |
| 534 | |
| 535 | case FieldDescriptor::TYPE_ENUM: { |
| 536 | while (input->BytesUntilLimit() > 0) { |
| 537 | int value; |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 538 | if (!WireFormatLite::ReadPrimitive<int, WireFormatLite::TYPE_ENUM>( |
| 539 | input, &value)) return false; |
Feng Xiao | 6ef984a | 2014-11-10 17:34:54 -0800 | [diff] [blame] | 540 | if (message->GetDescriptor()->file()->syntax() == |
| 541 | FileDescriptor::SYNTAX_PROTO3) { |
| 542 | message_reflection->AddEnumValue(message, field, value); |
| 543 | } else { |
| 544 | const EnumValueDescriptor* enum_value = |
| 545 | field->enum_type()->FindValueByNumber(value); |
| 546 | if (enum_value != NULL) { |
| 547 | message_reflection->AddEnum(message, field, enum_value); |
Jisi Liu | 885b612 | 2015-02-28 14:51:22 -0800 | [diff] [blame^] | 548 | } else { |
| 549 | // The enum value is not one of the known values. Add it to the |
| 550 | // UnknownFieldSet. |
| 551 | int64 sign_extended_value = static_cast<int64>(value); |
| 552 | message_reflection->MutableUnknownFields(message) |
| 553 | ->AddVarint( |
| 554 | WireFormatLite::GetTagFieldNumber(tag), |
| 555 | sign_extended_value); |
Feng Xiao | 6ef984a | 2014-11-10 17:34:54 -0800 | [diff] [blame] | 556 | } |
kenton@google.com | 2d6daa7 | 2009-01-22 01:27:00 +0000 | [diff] [blame] | 557 | } |
| 558 | } |
| 559 | |
| 560 | break; |
| 561 | } |
| 562 | |
| 563 | case FieldDescriptor::TYPE_STRING: |
| 564 | case FieldDescriptor::TYPE_GROUP: |
| 565 | case FieldDescriptor::TYPE_MESSAGE: |
| 566 | case FieldDescriptor::TYPE_BYTES: |
| 567 | // Can't have packed fields of these types: these should be caught by |
| 568 | // the protocol compiler. |
| 569 | return false; |
| 570 | break; |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 571 | } |
| 572 | |
kenton@google.com | 2d6daa7 | 2009-01-22 01:27:00 +0000 | [diff] [blame] | 573 | input->PopLimit(limit); |
| 574 | } else { |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 575 | // Non-packed value (value_format == NORMAL_FORMAT) |
kenton@google.com | 2d6daa7 | 2009-01-22 01:27:00 +0000 | [diff] [blame] | 576 | switch (field->type()) { |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 577 | #define HANDLE_TYPE(TYPE, CPPTYPE, CPPTYPE_METHOD) \ |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 578 | case FieldDescriptor::TYPE_##TYPE: { \ |
| 579 | CPPTYPE value; \ |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 580 | if (!WireFormatLite::ReadPrimitive< \ |
| 581 | CPPTYPE, WireFormatLite::TYPE_##TYPE>(input, &value)) \ |
| 582 | return false; \ |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 583 | if (field->is_repeated()) { \ |
| 584 | message_reflection->Add##CPPTYPE_METHOD(message, field, value); \ |
| 585 | } else { \ |
| 586 | message_reflection->Set##CPPTYPE_METHOD(message, field, value); \ |
| 587 | } \ |
| 588 | break; \ |
kenton@google.com | 2d6daa7 | 2009-01-22 01:27:00 +0000 | [diff] [blame] | 589 | } |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 590 | |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 591 | HANDLE_TYPE( INT32, int32, Int32) |
| 592 | HANDLE_TYPE( INT64, int64, Int64) |
| 593 | HANDLE_TYPE(SINT32, int32, Int32) |
| 594 | HANDLE_TYPE(SINT64, int64, Int64) |
| 595 | HANDLE_TYPE(UINT32, uint32, UInt32) |
| 596 | HANDLE_TYPE(UINT64, uint64, UInt64) |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 597 | |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 598 | HANDLE_TYPE( FIXED32, uint32, UInt32) |
| 599 | HANDLE_TYPE( FIXED64, uint64, UInt64) |
| 600 | HANDLE_TYPE(SFIXED32, int32, Int32) |
| 601 | HANDLE_TYPE(SFIXED64, int64, Int64) |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 602 | |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 603 | HANDLE_TYPE(FLOAT , float , Float ) |
| 604 | HANDLE_TYPE(DOUBLE, double, Double) |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 605 | |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 606 | HANDLE_TYPE(BOOL, bool, Bool) |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 607 | #undef HANDLE_TYPE |
| 608 | |
kenton@google.com | 2d6daa7 | 2009-01-22 01:27:00 +0000 | [diff] [blame] | 609 | case FieldDescriptor::TYPE_ENUM: { |
| 610 | int value; |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 611 | if (!WireFormatLite::ReadPrimitive<int, WireFormatLite::TYPE_ENUM>( |
| 612 | input, &value)) return false; |
Feng Xiao | 6ef984a | 2014-11-10 17:34:54 -0800 | [diff] [blame] | 613 | if (message->GetDescriptor()->file()->syntax() == |
| 614 | FileDescriptor::SYNTAX_PROTO3) { |
kenton@google.com | 2d6daa7 | 2009-01-22 01:27:00 +0000 | [diff] [blame] | 615 | if (field->is_repeated()) { |
Feng Xiao | 6ef984a | 2014-11-10 17:34:54 -0800 | [diff] [blame] | 616 | message_reflection->AddEnumValue(message, field, value); |
kenton@google.com | 2d6daa7 | 2009-01-22 01:27:00 +0000 | [diff] [blame] | 617 | } else { |
Feng Xiao | 6ef984a | 2014-11-10 17:34:54 -0800 | [diff] [blame] | 618 | message_reflection->SetEnumValue(message, field, value); |
kenton@google.com | 2d6daa7 | 2009-01-22 01:27:00 +0000 | [diff] [blame] | 619 | } |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 620 | } else { |
Feng Xiao | 6ef984a | 2014-11-10 17:34:54 -0800 | [diff] [blame] | 621 | const EnumValueDescriptor* enum_value = |
| 622 | field->enum_type()->FindValueByNumber(value); |
| 623 | if (enum_value != NULL) { |
| 624 | if (field->is_repeated()) { |
| 625 | message_reflection->AddEnum(message, field, enum_value); |
| 626 | } else { |
| 627 | message_reflection->SetEnum(message, field, enum_value); |
| 628 | } |
| 629 | } else { |
| 630 | // The enum value is not one of the known values. Add it to the |
| 631 | // UnknownFieldSet. |
| 632 | int64 sign_extended_value = static_cast<int64>(value); |
| 633 | message_reflection->MutableUnknownFields(message) |
| 634 | ->AddVarint( |
| 635 | WireFormatLite::GetTagFieldNumber(tag), |
| 636 | sign_extended_value); |
| 637 | } |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 638 | } |
kenton@google.com | 2d6daa7 | 2009-01-22 01:27:00 +0000 | [diff] [blame] | 639 | break; |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 640 | } |
| 641 | |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 642 | // Handle strings separately so that we can optimize the ctype=CORD case. |
| 643 | case FieldDescriptor::TYPE_STRING: { |
| 644 | string value; |
| 645 | if (!WireFormatLite::ReadString(input, &value)) return false; |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 646 | VerifyUTF8StringNamedField(value.data(), value.length(), PARSE, |
| 647 | field->name().c_str()); |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 648 | if (field->is_repeated()) { |
| 649 | message_reflection->AddString(message, field, value); |
| 650 | } else { |
| 651 | message_reflection->SetString(message, field, value); |
| 652 | } |
| 653 | break; |
| 654 | } |
| 655 | |
| 656 | case FieldDescriptor::TYPE_BYTES: { |
| 657 | string value; |
| 658 | if (!WireFormatLite::ReadBytes(input, &value)) return false; |
| 659 | if (field->is_repeated()) { |
| 660 | message_reflection->AddString(message, field, value); |
| 661 | } else { |
| 662 | message_reflection->SetString(message, field, value); |
| 663 | } |
| 664 | break; |
| 665 | } |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 666 | |
kenton@google.com | 2d6daa7 | 2009-01-22 01:27:00 +0000 | [diff] [blame] | 667 | case FieldDescriptor::TYPE_GROUP: { |
| 668 | Message* sub_message; |
| 669 | if (field->is_repeated()) { |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 670 | sub_message = message_reflection->AddMessage( |
| 671 | message, field, input->GetExtensionFactory()); |
kenton@google.com | 2d6daa7 | 2009-01-22 01:27:00 +0000 | [diff] [blame] | 672 | } else { |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 673 | sub_message = message_reflection->MutableMessage( |
| 674 | message, field, input->GetExtensionFactory()); |
kenton@google.com | 2d6daa7 | 2009-01-22 01:27:00 +0000 | [diff] [blame] | 675 | } |
| 676 | |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 677 | if (!WireFormatLite::ReadGroup(WireFormatLite::GetTagFieldNumber(tag), |
| 678 | input, sub_message)) |
kenton@google.com | 2d6daa7 | 2009-01-22 01:27:00 +0000 | [diff] [blame] | 679 | return false; |
| 680 | break; |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 681 | } |
| 682 | |
kenton@google.com | 2d6daa7 | 2009-01-22 01:27:00 +0000 | [diff] [blame] | 683 | case FieldDescriptor::TYPE_MESSAGE: { |
| 684 | Message* sub_message; |
| 685 | if (field->is_repeated()) { |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 686 | sub_message = message_reflection->AddMessage( |
| 687 | message, field, input->GetExtensionFactory()); |
kenton@google.com | 2d6daa7 | 2009-01-22 01:27:00 +0000 | [diff] [blame] | 688 | } else { |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 689 | sub_message = message_reflection->MutableMessage( |
| 690 | message, field, input->GetExtensionFactory()); |
kenton@google.com | 2d6daa7 | 2009-01-22 01:27:00 +0000 | [diff] [blame] | 691 | } |
| 692 | |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 693 | if (!WireFormatLite::ReadMessage(input, sub_message)) return false; |
kenton@google.com | 2d6daa7 | 2009-01-22 01:27:00 +0000 | [diff] [blame] | 694 | break; |
| 695 | } |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 696 | } |
| 697 | } |
| 698 | |
| 699 | return true; |
| 700 | } |
| 701 | |
| 702 | bool WireFormat::ParseAndMergeMessageSetItem( |
| 703 | io::CodedInputStream* input, |
temporal | 779f61c | 2008-08-13 03:15:00 +0000 | [diff] [blame] | 704 | Message* message) { |
| 705 | const Reflection* message_reflection = message->GetReflection(); |
| 706 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 707 | // This method parses a group which should contain two fields: |
| 708 | // required int32 type_id = 2; |
| 709 | // required data message = 3; |
| 710 | |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 711 | uint32 last_type_id = 0; |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 712 | |
| 713 | // Once we see a type_id, we'll look up the FieldDescriptor for the |
| 714 | // extension. |
| 715 | const FieldDescriptor* field = NULL; |
| 716 | |
| 717 | // If we see message data before the type_id, we'll append it to this so |
xiaofeng@google.com | b55a20f | 2012-09-22 02:40:50 +0000 | [diff] [blame] | 718 | // we can parse it later. |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 719 | string message_data; |
| 720 | |
| 721 | while (true) { |
| 722 | uint32 tag = input->ReadTag(); |
| 723 | if (tag == 0) return false; |
| 724 | |
| 725 | switch (tag) { |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 726 | case WireFormatLite::kMessageSetTypeIdTag: { |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 727 | uint32 type_id; |
| 728 | if (!input->ReadVarint32(&type_id)) return false; |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 729 | last_type_id = type_id; |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 730 | field = message_reflection->FindKnownExtensionByNumber(type_id); |
| 731 | |
| 732 | if (!message_data.empty()) { |
| 733 | // We saw some message data before the type_id. Have to parse it |
| 734 | // now. |
| 735 | io::ArrayInputStream raw_input(message_data.data(), |
| 736 | message_data.size()); |
| 737 | io::CodedInputStream sub_input(&raw_input); |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 738 | if (!ParseAndMergeMessageSetField(last_type_id, field, message, |
| 739 | &sub_input)) { |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 740 | return false; |
| 741 | } |
| 742 | message_data.clear(); |
| 743 | } |
| 744 | |
| 745 | break; |
| 746 | } |
| 747 | |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 748 | case WireFormatLite::kMessageSetMessageTag: { |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 749 | if (last_type_id == 0) { |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 750 | // We haven't seen a type_id yet. Append this data to message_data. |
| 751 | string temp; |
| 752 | uint32 length; |
| 753 | if (!input->ReadVarint32(&length)) return false; |
| 754 | if (!input->ReadString(&temp, length)) return false; |
xiaofeng@google.com | b55a20f | 2012-09-22 02:40:50 +0000 | [diff] [blame] | 755 | io::StringOutputStream output_stream(&message_data); |
| 756 | io::CodedOutputStream coded_output(&output_stream); |
| 757 | coded_output.WriteVarint32(length); |
| 758 | coded_output.WriteString(temp); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 759 | } else { |
| 760 | // Already saw type_id, so we can parse this directly. |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 761 | if (!ParseAndMergeMessageSetField(last_type_id, field, message, |
| 762 | input)) { |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 763 | return false; |
| 764 | } |
| 765 | } |
| 766 | |
| 767 | break; |
| 768 | } |
| 769 | |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 770 | case WireFormatLite::kMessageSetItemEndTag: { |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 771 | return true; |
| 772 | } |
| 773 | |
| 774 | default: { |
| 775 | if (!SkipField(input, tag, NULL)) return false; |
| 776 | } |
| 777 | } |
| 778 | } |
| 779 | } |
| 780 | |
| 781 | // =================================================================== |
| 782 | |
kenton@google.com | d37d46d | 2009-04-25 02:53:47 +0000 | [diff] [blame] | 783 | void WireFormat::SerializeWithCachedSizes( |
temporal | 779f61c | 2008-08-13 03:15:00 +0000 | [diff] [blame] | 784 | const Message& message, |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 785 | int size, io::CodedOutputStream* output) { |
temporal | 779f61c | 2008-08-13 03:15:00 +0000 | [diff] [blame] | 786 | const Descriptor* descriptor = message.GetDescriptor(); |
| 787 | const Reflection* message_reflection = message.GetReflection(); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 788 | int expected_endpoint = output->ByteCount() + size; |
| 789 | |
| 790 | vector<const FieldDescriptor*> fields; |
temporal | 779f61c | 2008-08-13 03:15:00 +0000 | [diff] [blame] | 791 | message_reflection->ListFields(message, &fields); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 792 | for (int i = 0; i < fields.size(); i++) { |
kenton@google.com | d37d46d | 2009-04-25 02:53:47 +0000 | [diff] [blame] | 793 | SerializeFieldWithCachedSizes(fields[i], message, output); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 794 | } |
| 795 | |
| 796 | if (descriptor->options().message_set_wire_format()) { |
kenton@google.com | d37d46d | 2009-04-25 02:53:47 +0000 | [diff] [blame] | 797 | SerializeUnknownMessageSetItems( |
| 798 | message_reflection->GetUnknownFields(message), output); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 799 | } else { |
kenton@google.com | d37d46d | 2009-04-25 02:53:47 +0000 | [diff] [blame] | 800 | SerializeUnknownFields( |
| 801 | message_reflection->GetUnknownFields(message), output); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 802 | } |
| 803 | |
| 804 | GOOGLE_CHECK_EQ(output->ByteCount(), expected_endpoint) |
| 805 | << ": Protocol message serialized to a size different from what was " |
| 806 | "originally expected. Perhaps it was modified by another thread " |
| 807 | "during serialization?"; |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 808 | } |
| 809 | |
kenton@google.com | d37d46d | 2009-04-25 02:53:47 +0000 | [diff] [blame] | 810 | void WireFormat::SerializeFieldWithCachedSizes( |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 811 | const FieldDescriptor* field, |
temporal | 779f61c | 2008-08-13 03:15:00 +0000 | [diff] [blame] | 812 | const Message& message, |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 813 | io::CodedOutputStream* output) { |
temporal | 779f61c | 2008-08-13 03:15:00 +0000 | [diff] [blame] | 814 | const Reflection* message_reflection = message.GetReflection(); |
| 815 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 816 | if (field->is_extension() && |
| 817 | field->containing_type()->options().message_set_wire_format() && |
| 818 | field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && |
| 819 | !field->is_repeated()) { |
kenton@google.com | d37d46d | 2009-04-25 02:53:47 +0000 | [diff] [blame] | 820 | SerializeMessageSetItemWithCachedSizes(field, message, output); |
| 821 | return; |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 822 | } |
| 823 | |
| 824 | int count = 0; |
| 825 | |
| 826 | if (field->is_repeated()) { |
temporal | 779f61c | 2008-08-13 03:15:00 +0000 | [diff] [blame] | 827 | count = message_reflection->FieldSize(message, field); |
| 828 | } else if (message_reflection->HasField(message, field)) { |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 829 | count = 1; |
| 830 | } |
| 831 | |
kenton@google.com | 2d6daa7 | 2009-01-22 01:27:00 +0000 | [diff] [blame] | 832 | const bool is_packed = field->options().packed(); |
| 833 | if (is_packed && count > 0) { |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 834 | WireFormatLite::WriteTag(field->number(), |
| 835 | WireFormatLite::WIRETYPE_LENGTH_DELIMITED, output); |
kenton@google.com | 2d6daa7 | 2009-01-22 01:27:00 +0000 | [diff] [blame] | 836 | const int data_size = FieldDataOnlyByteSize(field, message); |
kenton@google.com | d37d46d | 2009-04-25 02:53:47 +0000 | [diff] [blame] | 837 | output->WriteVarint32(data_size); |
kenton@google.com | 2d6daa7 | 2009-01-22 01:27:00 +0000 | [diff] [blame] | 838 | } |
| 839 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 840 | for (int j = 0; j < count; j++) { |
| 841 | switch (field->type()) { |
kenton@google.com | 2d6daa7 | 2009-01-22 01:27:00 +0000 | [diff] [blame] | 842 | #define HANDLE_PRIMITIVE_TYPE(TYPE, CPPTYPE, TYPE_METHOD, CPPTYPE_METHOD) \ |
| 843 | case FieldDescriptor::TYPE_##TYPE: { \ |
| 844 | const CPPTYPE value = field->is_repeated() ? \ |
| 845 | message_reflection->GetRepeated##CPPTYPE_METHOD( \ |
| 846 | message, field, j) : \ |
| 847 | message_reflection->Get##CPPTYPE_METHOD( \ |
| 848 | message, field); \ |
| 849 | if (is_packed) { \ |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 850 | WireFormatLite::Write##TYPE_METHOD##NoTag(value, output); \ |
kenton@google.com | 2d6daa7 | 2009-01-22 01:27:00 +0000 | [diff] [blame] | 851 | } else { \ |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 852 | WireFormatLite::Write##TYPE_METHOD(field->number(), value, output); \ |
kenton@google.com | 2d6daa7 | 2009-01-22 01:27:00 +0000 | [diff] [blame] | 853 | } \ |
| 854 | break; \ |
| 855 | } |
| 856 | |
| 857 | HANDLE_PRIMITIVE_TYPE( INT32, int32, Int32, Int32) |
| 858 | HANDLE_PRIMITIVE_TYPE( INT64, int64, Int64, Int64) |
| 859 | HANDLE_PRIMITIVE_TYPE(SINT32, int32, SInt32, Int32) |
| 860 | HANDLE_PRIMITIVE_TYPE(SINT64, int64, SInt64, Int64) |
| 861 | HANDLE_PRIMITIVE_TYPE(UINT32, uint32, UInt32, UInt32) |
| 862 | HANDLE_PRIMITIVE_TYPE(UINT64, uint64, UInt64, UInt64) |
| 863 | |
| 864 | HANDLE_PRIMITIVE_TYPE( FIXED32, uint32, Fixed32, UInt32) |
| 865 | HANDLE_PRIMITIVE_TYPE( FIXED64, uint64, Fixed64, UInt64) |
| 866 | HANDLE_PRIMITIVE_TYPE(SFIXED32, int32, SFixed32, Int32) |
| 867 | HANDLE_PRIMITIVE_TYPE(SFIXED64, int64, SFixed64, Int64) |
| 868 | |
| 869 | HANDLE_PRIMITIVE_TYPE(FLOAT , float , Float , Float ) |
| 870 | HANDLE_PRIMITIVE_TYPE(DOUBLE, double, Double, Double) |
| 871 | |
| 872 | HANDLE_PRIMITIVE_TYPE(BOOL, bool, Bool, Bool) |
| 873 | #undef HANDLE_PRIMITIVE_TYPE |
| 874 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 875 | #define HANDLE_TYPE(TYPE, TYPE_METHOD, CPPTYPE_METHOD) \ |
| 876 | case FieldDescriptor::TYPE_##TYPE: \ |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 877 | WireFormatLite::Write##TYPE_METHOD( \ |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 878 | field->number(), \ |
| 879 | field->is_repeated() ? \ |
temporal | 779f61c | 2008-08-13 03:15:00 +0000 | [diff] [blame] | 880 | message_reflection->GetRepeated##CPPTYPE_METHOD( \ |
| 881 | message, field, j) : \ |
| 882 | message_reflection->Get##CPPTYPE_METHOD(message, field), \ |
kenton@google.com | d37d46d | 2009-04-25 02:53:47 +0000 | [diff] [blame] | 883 | output); \ |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 884 | break; |
| 885 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 886 | HANDLE_TYPE(GROUP , Group , Message) |
| 887 | HANDLE_TYPE(MESSAGE, Message, Message) |
| 888 | #undef HANDLE_TYPE |
| 889 | |
| 890 | case FieldDescriptor::TYPE_ENUM: { |
| 891 | const EnumValueDescriptor* value = field->is_repeated() ? |
temporal | 779f61c | 2008-08-13 03:15:00 +0000 | [diff] [blame] | 892 | message_reflection->GetRepeatedEnum(message, field, j) : |
| 893 | message_reflection->GetEnum(message, field); |
kenton@google.com | 2d6daa7 | 2009-01-22 01:27:00 +0000 | [diff] [blame] | 894 | if (is_packed) { |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 895 | WireFormatLite::WriteEnumNoTag(value->number(), output); |
kenton@google.com | 2d6daa7 | 2009-01-22 01:27:00 +0000 | [diff] [blame] | 896 | } else { |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 897 | WireFormatLite::WriteEnum(field->number(), value->number(), output); |
kenton@google.com | 2d6daa7 | 2009-01-22 01:27:00 +0000 | [diff] [blame] | 898 | } |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 899 | break; |
| 900 | } |
| 901 | |
| 902 | // Handle strings separately so that we can get string references |
| 903 | // instead of copying. |
kenton@google.com | 26bd9ee | 2008-11-21 00:06:27 +0000 | [diff] [blame] | 904 | case FieldDescriptor::TYPE_STRING: { |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 905 | string scratch; |
| 906 | const string& value = field->is_repeated() ? |
| 907 | message_reflection->GetRepeatedStringReference( |
| 908 | message, field, j, &scratch) : |
| 909 | message_reflection->GetStringReference(message, field, &scratch); |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 910 | VerifyUTF8StringNamedField(value.data(), value.length(), SERIALIZE, |
| 911 | field->name().c_str()); |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 912 | WireFormatLite::WriteString(field->number(), value, output); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 913 | break; |
| 914 | } |
kenton@google.com | 26bd9ee | 2008-11-21 00:06:27 +0000 | [diff] [blame] | 915 | |
| 916 | case FieldDescriptor::TYPE_BYTES: { |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 917 | string scratch; |
| 918 | const string& value = field->is_repeated() ? |
| 919 | message_reflection->GetRepeatedStringReference( |
| 920 | message, field, j, &scratch) : |
| 921 | message_reflection->GetStringReference(message, field, &scratch); |
| 922 | WireFormatLite::WriteBytes(field->number(), value, output); |
kenton@google.com | 26bd9ee | 2008-11-21 00:06:27 +0000 | [diff] [blame] | 923 | break; |
| 924 | } |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 925 | } |
| 926 | } |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 927 | } |
| 928 | |
kenton@google.com | d37d46d | 2009-04-25 02:53:47 +0000 | [diff] [blame] | 929 | void WireFormat::SerializeMessageSetItemWithCachedSizes( |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 930 | const FieldDescriptor* field, |
temporal | 779f61c | 2008-08-13 03:15:00 +0000 | [diff] [blame] | 931 | const Message& message, |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 932 | io::CodedOutputStream* output) { |
temporal | 779f61c | 2008-08-13 03:15:00 +0000 | [diff] [blame] | 933 | const Reflection* message_reflection = message.GetReflection(); |
| 934 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 935 | // Start group. |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 936 | output->WriteVarint32(WireFormatLite::kMessageSetItemStartTag); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 937 | |
| 938 | // Write type ID. |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 939 | output->WriteVarint32(WireFormatLite::kMessageSetTypeIdTag); |
kenton@google.com | d37d46d | 2009-04-25 02:53:47 +0000 | [diff] [blame] | 940 | output->WriteVarint32(field->number()); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 941 | |
| 942 | // Write message. |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 943 | output->WriteVarint32(WireFormatLite::kMessageSetMessageTag); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 944 | |
temporal | 779f61c | 2008-08-13 03:15:00 +0000 | [diff] [blame] | 945 | const Message& sub_message = message_reflection->GetMessage(message, field); |
kenton@google.com | d37d46d | 2009-04-25 02:53:47 +0000 | [diff] [blame] | 946 | output->WriteVarint32(sub_message.GetCachedSize()); |
| 947 | sub_message.SerializeWithCachedSizes(output); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 948 | |
| 949 | // End group. |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 950 | output->WriteVarint32(WireFormatLite::kMessageSetItemEndTag); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 951 | } |
| 952 | |
| 953 | // =================================================================== |
| 954 | |
temporal | 779f61c | 2008-08-13 03:15:00 +0000 | [diff] [blame] | 955 | int WireFormat::ByteSize(const Message& message) { |
| 956 | const Descriptor* descriptor = message.GetDescriptor(); |
| 957 | const Reflection* message_reflection = message.GetReflection(); |
| 958 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 959 | int our_size = 0; |
| 960 | |
| 961 | vector<const FieldDescriptor*> fields; |
temporal | 779f61c | 2008-08-13 03:15:00 +0000 | [diff] [blame] | 962 | message_reflection->ListFields(message, &fields); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 963 | for (int i = 0; i < fields.size(); i++) { |
temporal | 779f61c | 2008-08-13 03:15:00 +0000 | [diff] [blame] | 964 | our_size += FieldByteSize(fields[i], message); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 965 | } |
| 966 | |
| 967 | if (descriptor->options().message_set_wire_format()) { |
| 968 | our_size += ComputeUnknownMessageSetItemsSize( |
temporal | 779f61c | 2008-08-13 03:15:00 +0000 | [diff] [blame] | 969 | message_reflection->GetUnknownFields(message)); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 970 | } else { |
| 971 | our_size += ComputeUnknownFieldsSize( |
temporal | 779f61c | 2008-08-13 03:15:00 +0000 | [diff] [blame] | 972 | message_reflection->GetUnknownFields(message)); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 973 | } |
| 974 | |
| 975 | return our_size; |
| 976 | } |
| 977 | |
| 978 | int WireFormat::FieldByteSize( |
| 979 | const FieldDescriptor* field, |
temporal | 779f61c | 2008-08-13 03:15:00 +0000 | [diff] [blame] | 980 | const Message& message) { |
| 981 | const Reflection* message_reflection = message.GetReflection(); |
| 982 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 983 | if (field->is_extension() && |
| 984 | field->containing_type()->options().message_set_wire_format() && |
| 985 | field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && |
| 986 | !field->is_repeated()) { |
temporal | 779f61c | 2008-08-13 03:15:00 +0000 | [diff] [blame] | 987 | return MessageSetItemByteSize(field, message); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 988 | } |
| 989 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 990 | int count = 0; |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 991 | if (field->is_repeated()) { |
temporal | 779f61c | 2008-08-13 03:15:00 +0000 | [diff] [blame] | 992 | count = message_reflection->FieldSize(message, field); |
| 993 | } else if (message_reflection->HasField(message, field)) { |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 994 | count = 1; |
| 995 | } |
| 996 | |
kenton@google.com | 2d6daa7 | 2009-01-22 01:27:00 +0000 | [diff] [blame] | 997 | const int data_size = FieldDataOnlyByteSize(field, message); |
| 998 | int our_size = data_size; |
| 999 | if (field->options().packed()) { |
| 1000 | if (data_size > 0) { |
| 1001 | // Packed fields get serialized like a string, not their native type. |
| 1002 | // Technically this doesn't really matter; the size only changes if it's |
| 1003 | // a GROUP |
| 1004 | our_size += TagSize(field->number(), FieldDescriptor::TYPE_STRING); |
| 1005 | our_size += io::CodedOutputStream::VarintSize32(data_size); |
| 1006 | } |
| 1007 | } else { |
| 1008 | our_size += count * TagSize(field->number(), field->type()); |
| 1009 | } |
| 1010 | return our_size; |
| 1011 | } |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 1012 | |
kenton@google.com | 2d6daa7 | 2009-01-22 01:27:00 +0000 | [diff] [blame] | 1013 | int WireFormat::FieldDataOnlyByteSize( |
| 1014 | const FieldDescriptor* field, |
| 1015 | const Message& message) { |
| 1016 | const Reflection* message_reflection = message.GetReflection(); |
| 1017 | |
| 1018 | int count = 0; |
| 1019 | if (field->is_repeated()) { |
| 1020 | count = message_reflection->FieldSize(message, field); |
| 1021 | } else if (message_reflection->HasField(message, field)) { |
| 1022 | count = 1; |
| 1023 | } |
| 1024 | |
| 1025 | int data_size = 0; |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 1026 | switch (field->type()) { |
| 1027 | #define HANDLE_TYPE(TYPE, TYPE_METHOD, CPPTYPE_METHOD) \ |
| 1028 | case FieldDescriptor::TYPE_##TYPE: \ |
| 1029 | if (field->is_repeated()) { \ |
| 1030 | for (int j = 0; j < count; j++) { \ |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 1031 | data_size += WireFormatLite::TYPE_METHOD##Size( \ |
temporal | 779f61c | 2008-08-13 03:15:00 +0000 | [diff] [blame] | 1032 | message_reflection->GetRepeated##CPPTYPE_METHOD( \ |
| 1033 | message, field, j)); \ |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 1034 | } \ |
| 1035 | } else { \ |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 1036 | data_size += WireFormatLite::TYPE_METHOD##Size( \ |
temporal | 779f61c | 2008-08-13 03:15:00 +0000 | [diff] [blame] | 1037 | message_reflection->Get##CPPTYPE_METHOD(message, field)); \ |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 1038 | } \ |
| 1039 | break; |
| 1040 | |
| 1041 | #define HANDLE_FIXED_TYPE(TYPE, TYPE_METHOD) \ |
| 1042 | case FieldDescriptor::TYPE_##TYPE: \ |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 1043 | data_size += count * WireFormatLite::k##TYPE_METHOD##Size; \ |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 1044 | break; |
| 1045 | |
| 1046 | HANDLE_TYPE( INT32, Int32, Int32) |
| 1047 | HANDLE_TYPE( INT64, Int64, Int64) |
| 1048 | HANDLE_TYPE(SINT32, SInt32, Int32) |
| 1049 | HANDLE_TYPE(SINT64, SInt64, Int64) |
| 1050 | HANDLE_TYPE(UINT32, UInt32, UInt32) |
| 1051 | HANDLE_TYPE(UINT64, UInt64, UInt64) |
| 1052 | |
| 1053 | HANDLE_FIXED_TYPE( FIXED32, Fixed32) |
| 1054 | HANDLE_FIXED_TYPE( FIXED64, Fixed64) |
| 1055 | HANDLE_FIXED_TYPE(SFIXED32, SFixed32) |
| 1056 | HANDLE_FIXED_TYPE(SFIXED64, SFixed64) |
| 1057 | |
| 1058 | HANDLE_FIXED_TYPE(FLOAT , Float ) |
| 1059 | HANDLE_FIXED_TYPE(DOUBLE, Double) |
| 1060 | |
| 1061 | HANDLE_FIXED_TYPE(BOOL, Bool) |
| 1062 | |
| 1063 | HANDLE_TYPE(GROUP , Group , Message) |
| 1064 | HANDLE_TYPE(MESSAGE, Message, Message) |
| 1065 | #undef HANDLE_TYPE |
| 1066 | #undef HANDLE_FIXED_TYPE |
| 1067 | |
| 1068 | case FieldDescriptor::TYPE_ENUM: { |
| 1069 | if (field->is_repeated()) { |
| 1070 | for (int j = 0; j < count; j++) { |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 1071 | data_size += WireFormatLite::EnumSize( |
temporal | 779f61c | 2008-08-13 03:15:00 +0000 | [diff] [blame] | 1072 | message_reflection->GetRepeatedEnum(message, field, j)->number()); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 1073 | } |
| 1074 | } else { |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 1075 | data_size += WireFormatLite::EnumSize( |
temporal | 779f61c | 2008-08-13 03:15:00 +0000 | [diff] [blame] | 1076 | message_reflection->GetEnum(message, field)->number()); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 1077 | } |
| 1078 | break; |
| 1079 | } |
| 1080 | |
| 1081 | // Handle strings separately so that we can get string references |
| 1082 | // instead of copying. |
| 1083 | case FieldDescriptor::TYPE_STRING: |
| 1084 | case FieldDescriptor::TYPE_BYTES: { |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 1085 | for (int j = 0; j < count; j++) { |
| 1086 | string scratch; |
| 1087 | const string& value = field->is_repeated() ? |
| 1088 | message_reflection->GetRepeatedStringReference( |
| 1089 | message, field, j, &scratch) : |
| 1090 | message_reflection->GetStringReference(message, field, &scratch); |
| 1091 | data_size += WireFormatLite::StringSize(value); |
| 1092 | } |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 1093 | break; |
| 1094 | } |
| 1095 | } |
kenton@google.com | 2d6daa7 | 2009-01-22 01:27:00 +0000 | [diff] [blame] | 1096 | return data_size; |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 1097 | } |
| 1098 | |
| 1099 | int WireFormat::MessageSetItemByteSize( |
| 1100 | const FieldDescriptor* field, |
temporal | 779f61c | 2008-08-13 03:15:00 +0000 | [diff] [blame] | 1101 | const Message& message) { |
| 1102 | const Reflection* message_reflection = message.GetReflection(); |
| 1103 | |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 1104 | int our_size = WireFormatLite::kMessageSetItemTagsSize; |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 1105 | |
| 1106 | // type_id |
| 1107 | our_size += io::CodedOutputStream::VarintSize32(field->number()); |
| 1108 | |
| 1109 | // message |
temporal | 779f61c | 2008-08-13 03:15:00 +0000 | [diff] [blame] | 1110 | const Message& sub_message = message_reflection->GetMessage(message, field); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 1111 | int message_size = sub_message.ByteSize(); |
| 1112 | |
| 1113 | our_size += io::CodedOutputStream::VarintSize32(message_size); |
| 1114 | our_size += message_size; |
| 1115 | |
| 1116 | return our_size; |
| 1117 | } |
| 1118 | |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 1119 | void WireFormat::VerifyUTF8StringFallback(const char* data, |
| 1120 | int size, |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 1121 | Operation op, |
| 1122 | const char* field_name) { |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 1123 | if (!IsStructurallyValidUTF8(data, size)) { |
| 1124 | const char* operation_str = NULL; |
| 1125 | switch (op) { |
| 1126 | case PARSE: |
| 1127 | operation_str = "parsing"; |
| 1128 | break; |
| 1129 | case SERIALIZE: |
| 1130 | operation_str = "serializing"; |
| 1131 | break; |
| 1132 | // no default case: have the compiler warn if a case is not covered. |
| 1133 | } |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 1134 | string quoted_field_name = ""; |
| 1135 | if (field_name != NULL) { |
| 1136 | quoted_field_name = StringPrintf(" '%s'", field_name); |
| 1137 | } |
| 1138 | // no space below to avoid double space when the field name is missing. |
| 1139 | GOOGLE_LOG(ERROR) << "String field" << quoted_field_name << " contains invalid " |
| 1140 | << "UTF-8 data when " << operation_str << " a protocol " |
| 1141 | << "buffer. Use the 'bytes' type if you intend to send raw " |
| 1142 | << "bytes. "; |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 1143 | } |
| 1144 | } |
| 1145 | |
| 1146 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 1147 | } // namespace internal |
| 1148 | } // namespace protobuf |
| 1149 | } // namespace google |