1// Protocol Buffers - Google's data interchange format
2// Copyright 2008 Google Inc.  All rights reserved.
3// http://code.google.com/p/protobuf/
4//
5// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are
7// met:
8//
9//     * Redistributions of source code must retain the above copyright
10// notice, this list of conditions and the following disclaimer.
11//     * Redistributions in binary form must reproduce the above
12// copyright notice, this list of conditions and the following disclaimer
13// in the documentation and/or other materials provided with the
14// distribution.
15//     * Neither the name of Google Inc. nor the names of its
16// contributors may be used to endorse or promote products derived from
17// this software without specific prior written permission.
18//
19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
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 <google/protobuf/stubs/common.h>
36#include <google/protobuf/unknown_field_set.h>
37#include <google/protobuf/stubs/stl_util-inl.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
43namespace google {
44namespace protobuf {
45
46UnknownFieldSet::UnknownFieldSet()
47  : fields_(NULL) {}
48
49UnknownFieldSet::~UnknownFieldSet() {
50  Clear();
51  delete fields_;
52}
53
54void UnknownFieldSet::ClearFallback() {
55  GOOGLE_DCHECK(fields_ != NULL);
56  for (int i = 0; i < fields_->size(); i++) {
57    (*fields_)[i].Delete();
58  }
59  fields_->clear();
60}
61
62void UnknownFieldSet::MergeFrom(const UnknownFieldSet& other) {
63  for (int i = 0; i < other.field_count(); i++) {
64    AddField(other.field(i));
65  }
66}
67
68int UnknownFieldSet::SpaceUsedExcludingSelf() const {
69  if (fields_ == NULL) return 0;
70
71  int total_size = sizeof(*fields_) + sizeof(UnknownField) * fields_->size();
72  for (int i = 0; i < fields_->size(); i++) {
73    const UnknownField& field = (*fields_)[i];
74    switch (field.type()) {
75      case UnknownField::TYPE_LENGTH_DELIMITED:
76        total_size += sizeof(*field.length_delimited_) +
77          internal::StringSpaceUsedExcludingSelf(*field.length_delimited_);
78        break;
79      case UnknownField::TYPE_GROUP:
80        total_size += field.group_->SpaceUsed();
81        break;
82      default:
83        break;
84    }
85  }
86  return total_size;
87}
88
89int UnknownFieldSet::SpaceUsed() const {
90  return sizeof(*this) + SpaceUsedExcludingSelf();
91}
92
93void UnknownFieldSet::AddVarint(int number, uint64 value) {
94  if (fields_ == NULL) fields_ = new vector<UnknownField>;
95  UnknownField field;
96  field.number_ = number;
97  field.type_ = UnknownField::TYPE_VARINT;
98  field.varint_ = value;
99  fields_->push_back(field);
100}
101
102void UnknownFieldSet::AddFixed32(int number, uint32 value) {
103  if (fields_ == NULL) fields_ = new vector<UnknownField>;
104  UnknownField field;
105  field.number_ = number;
106  field.type_ = UnknownField::TYPE_FIXED32;
107  field.fixed32_ = value;
108  fields_->push_back(field);
109}
110
111void UnknownFieldSet::AddFixed64(int number, uint64 value) {
112  if (fields_ == NULL) fields_ = new vector<UnknownField>;
113  UnknownField field;
114  field.number_ = number;
115  field.type_ = UnknownField::TYPE_FIXED64;
116  field.fixed64_ = value;
117  fields_->push_back(field);
118}
119
120string* UnknownFieldSet::AddLengthDelimited(int number) {
121  if (fields_ == NULL) fields_ = new vector<UnknownField>;
122  UnknownField field;
123  field.number_ = number;
124  field.type_ = UnknownField::TYPE_LENGTH_DELIMITED;
125  field.length_delimited_ = new string;
126  fields_->push_back(field);
127  return field.length_delimited_;
128}
129
130UnknownFieldSet* UnknownFieldSet::AddGroup(int number) {
131  if (fields_ == NULL) fields_ = new vector<UnknownField>;
132  UnknownField field;
133  field.number_ = number;
134  field.type_ = UnknownField::TYPE_GROUP;
135  field.group_ = new UnknownFieldSet;
136  fields_->push_back(field);
137  return field.group_;
138}
139
140void UnknownFieldSet::AddField(const UnknownField& field) {
141  if (fields_ == NULL) fields_ = new vector<UnknownField>;
142  fields_->push_back(field);
143  fields_->back().DeepCopy();
144}
145
146bool UnknownFieldSet::MergeFromCodedStream(io::CodedInputStream* input) {
147
148  UnknownFieldSet other;
149  if (internal::WireFormat::SkipMessage(input, &other) &&
150                                  input->ConsumedEntireMessage()) {
151    MergeFrom(other);
152    return true;
153  } else {
154    return false;
155  }
156}
157
158bool UnknownFieldSet::ParseFromCodedStream(io::CodedInputStream* input) {
159  Clear();
160  return MergeFromCodedStream(input);
161}
162
163bool UnknownFieldSet::ParseFromZeroCopyStream(io::ZeroCopyInputStream* input) {
164  io::CodedInputStream coded_input(input);
165  return ParseFromCodedStream(&coded_input) &&
166    coded_input.ConsumedEntireMessage();
167}
168
169bool UnknownFieldSet::ParseFromArray(const void* data, int size) {
170  io::ArrayInputStream input(data, size);
171  return ParseFromZeroCopyStream(&input);
172}
173
174void UnknownField::Delete() {
175  switch (type()) {
176    case UnknownField::TYPE_LENGTH_DELIMITED:
177      delete length_delimited_;
178      break;
179    case UnknownField::TYPE_GROUP:
180      delete group_;
181      break;
182    default:
183      break;
184  }
185}
186
187void UnknownField::DeepCopy() {
188  switch (type()) {
189    case UnknownField::TYPE_LENGTH_DELIMITED:
190      length_delimited_ = new string(*length_delimited_);
191      break;
192    case UnknownField::TYPE_GROUP: {
193      UnknownFieldSet* group = new UnknownFieldSet;
194      group->MergeFrom(*group_);
195      group_ = group;
196      break;
197    }
198    default:
199      break;
200  }
201}
202
203}  // namespace protobuf
204}  // namespace google
205