1 // Protocol Buffers - Google's data interchange format 2 // Copyright 2008 Google Inc. All rights reserved. 3 // https://developers.google.com/protocol-buffers/ 4 // 5 // Redistribution and use in source and binary forms, with or without 6 // modification, are permitted provided that the following conditions are 7 // met: 8 // 9 // * Redistributions of source code must retain the above copyright 10 // notice, this list of conditions and the following disclaimer. 11 // * Redistributions in binary form must reproduce the above 12 // copyright notice, this list of conditions and the following disclaimer 13 // in the documentation and/or other materials provided with the 14 // distribution. 15 // * Neither the name of Google Inc. nor the names of its 16 // contributors may be used to endorse or promote products derived from 17 // this software without specific prior written permission. 18 // 19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 31 // Author: kenton (at) google.com (Kenton Varda) 32 // Based on original Protocol Buffers design by 33 // Sanjay Ghemawat, Jeff Dean, and others. 34 35 #include <google/protobuf/unknown_field_set.h> 36 37 #include <google/protobuf/stubs/common.h> 38 #include <google/protobuf/io/coded_stream.h> 39 #include <google/protobuf/io/zero_copy_stream.h> 40 #include <google/protobuf/io/zero_copy_stream_impl.h> 41 #include <google/protobuf/wire_format.h> 42 #include <google/protobuf/stubs/stl_util.h> 43 44 namespace google { 45 namespace protobuf { 46 47 UnknownFieldSet::UnknownFieldSet() 48 : fields_(NULL) {} 49 50 UnknownFieldSet::~UnknownFieldSet() { 51 Clear(); 52 delete fields_; 53 } 54 55 void UnknownFieldSet::ClearFallback() { 56 GOOGLE_DCHECK(fields_ != NULL); 57 for (int i = 0; i < fields_->size(); i++) { 58 (*fields_)[i].Delete(); 59 } 60 fields_->clear(); 61 } 62 63 void UnknownFieldSet::ClearAndFreeMemory() { 64 if (fields_ != NULL) { 65 Clear(); 66 delete fields_; 67 fields_ = NULL; 68 } 69 } 70 71 void UnknownFieldSet::MergeFrom(const UnknownFieldSet& other) { 72 for (int i = 0; i < other.field_count(); i++) { 73 AddField(other.field(i)); 74 } 75 } 76 77 int UnknownFieldSet::SpaceUsedExcludingSelf() const { 78 if (fields_ == NULL) return 0; 79 80 int total_size = sizeof(*fields_) + sizeof(UnknownField) * fields_->size(); 81 for (int i = 0; i < fields_->size(); i++) { 82 const UnknownField& field = (*fields_)[i]; 83 switch (field.type()) { 84 case UnknownField::TYPE_LENGTH_DELIMITED: 85 total_size += sizeof(*field.length_delimited_.string_value_) + 86 internal::StringSpaceUsedExcludingSelf( 87 *field.length_delimited_.string_value_); 88 break; 89 case UnknownField::TYPE_GROUP: 90 total_size += field.group_->SpaceUsed(); 91 break; 92 default: 93 break; 94 } 95 } 96 return total_size; 97 } 98 99 int UnknownFieldSet::SpaceUsed() const { 100 return sizeof(*this) + SpaceUsedExcludingSelf(); 101 } 102 103 void UnknownFieldSet::AddVarint(int number, uint64 value) { 104 if (fields_ == NULL) fields_ = new vector<UnknownField>; 105 UnknownField field; 106 field.number_ = number; 107 field.SetType(UnknownField::TYPE_VARINT); 108 field.varint_ = value; 109 fields_->push_back(field); 110 } 111 112 void UnknownFieldSet::AddFixed32(int number, uint32 value) { 113 if (fields_ == NULL) fields_ = new vector<UnknownField>; 114 UnknownField field; 115 field.number_ = number; 116 field.SetType(UnknownField::TYPE_FIXED32); 117 field.fixed32_ = value; 118 fields_->push_back(field); 119 } 120 121 void UnknownFieldSet::AddFixed64(int number, uint64 value) { 122 if (fields_ == NULL) fields_ = new vector<UnknownField>; 123 UnknownField field; 124 field.number_ = number; 125 field.SetType(UnknownField::TYPE_FIXED64); 126 field.fixed64_ = value; 127 fields_->push_back(field); 128 } 129 130 string* UnknownFieldSet::AddLengthDelimited(int number) { 131 if (fields_ == NULL) fields_ = new vector<UnknownField>; 132 UnknownField field; 133 field.number_ = number; 134 field.SetType(UnknownField::TYPE_LENGTH_DELIMITED); 135 field.length_delimited_.string_value_ = new string; 136 fields_->push_back(field); 137 return field.length_delimited_.string_value_; 138 } 139 140 141 UnknownFieldSet* UnknownFieldSet::AddGroup(int number) { 142 if (fields_ == NULL) fields_ = new vector<UnknownField>; 143 UnknownField field; 144 field.number_ = number; 145 field.SetType(UnknownField::TYPE_GROUP); 146 field.group_ = new UnknownFieldSet; 147 fields_->push_back(field); 148 return field.group_; 149 } 150 151 void UnknownFieldSet::AddField(const UnknownField& field) { 152 if (fields_ == NULL) fields_ = new vector<UnknownField>; 153 fields_->push_back(field); 154 fields_->back().DeepCopy(); 155 } 156 157 void UnknownFieldSet::DeleteSubrange(int start, int num) { 158 GOOGLE_DCHECK(fields_ != NULL); 159 // Delete the specified fields. 160 for (int i = 0; i < num; ++i) { 161 (*fields_)[i + start].Delete(); 162 } 163 // Slide down the remaining fields. 164 for (int i = start + num; i < fields_->size(); ++i) { 165 (*fields_)[i - num] = (*fields_)[i]; 166 } 167 // Pop off the # of deleted fields. 168 for (int i = 0; i < num; ++i) { 169 fields_->pop_back(); 170 } 171 } 172 173 void UnknownFieldSet::DeleteByNumber(int number) { 174 if (fields_ == NULL) return; 175 int left = 0; // The number of fields left after deletion. 176 for (int i = 0; i < fields_->size(); ++i) { 177 UnknownField* field = &(*fields_)[i]; 178 if (field->number() == number) { 179 field->Delete(); 180 } else { 181 if (i != left) { 182 (*fields_)[left] = (*fields_)[i]; 183 } 184 ++left; 185 } 186 } 187 fields_->resize(left); 188 } 189 190 bool UnknownFieldSet::MergeFromCodedStream(io::CodedInputStream* input) { 191 UnknownFieldSet other; 192 if (internal::WireFormat::SkipMessage(input, &other) && 193 input->ConsumedEntireMessage()) { 194 MergeFrom(other); 195 return true; 196 } else { 197 return false; 198 } 199 } 200 201 bool UnknownFieldSet::ParseFromCodedStream(io::CodedInputStream* input) { 202 Clear(); 203 return MergeFromCodedStream(input); 204 } 205 206 bool UnknownFieldSet::ParseFromZeroCopyStream(io::ZeroCopyInputStream* input) { 207 io::CodedInputStream coded_input(input); 208 return (ParseFromCodedStream(&coded_input) && 209 coded_input.ConsumedEntireMessage()); 210 } 211 212 bool UnknownFieldSet::ParseFromArray(const void* data, int size) { 213 io::ArrayInputStream input(data, size); 214 return ParseFromZeroCopyStream(&input); 215 } 216 217 void UnknownField::Delete() { 218 switch (type()) { 219 case UnknownField::TYPE_LENGTH_DELIMITED: 220 delete length_delimited_.string_value_; 221 break; 222 case UnknownField::TYPE_GROUP: 223 delete group_; 224 break; 225 default: 226 break; 227 } 228 } 229 230 void UnknownField::DeepCopy() { 231 switch (type()) { 232 case UnknownField::TYPE_LENGTH_DELIMITED: 233 length_delimited_.string_value_ = new string( 234 *length_delimited_.string_value_); 235 break; 236 case UnknownField::TYPE_GROUP: { 237 UnknownFieldSet* group = new UnknownFieldSet; 238 group->MergeFrom(*group_); 239 group_ = group; 240 break; 241 } 242 default: 243 break; 244 } 245 } 246 247 248 void UnknownField::SerializeLengthDelimitedNoTag( 249 io::CodedOutputStream* output) const { 250 GOOGLE_DCHECK_EQ(TYPE_LENGTH_DELIMITED, type()); 251 const string& data = *length_delimited_.string_value_; 252 output->WriteVarint32(data.size()); 253 output->WriteRawMaybeAliased(data.data(), data.size()); 254 } 255 256 uint8* UnknownField::SerializeLengthDelimitedNoTagToArray(uint8* target) const { 257 GOOGLE_DCHECK_EQ(TYPE_LENGTH_DELIMITED, type()); 258 const string& data = *length_delimited_.string_value_; 259 target = io::CodedOutputStream::WriteVarint32ToArray(data.size(), target); 260 target = io::CodedOutputStream::WriteStringToArray(data, target); 261 return target; 262 } 263 264 } // namespace protobuf 265 } // namespace google 266