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#include <google/protobuf/util/field_mask_util.h>
32
33#include <google/protobuf/stubs/strutil.h>
34#include <google/protobuf/stubs/map_util.h>
35
36namespace google {
37namespace protobuf {
38namespace util {
39
40using google::protobuf::FieldMask;
41
42string FieldMaskUtil::ToString(const FieldMask& mask) {
43  return Join(mask.paths(), ",");
44}
45
46void FieldMaskUtil::FromString(StringPiece str, FieldMask* out) {
47  out->Clear();
48  vector<string> paths = Split(str, ",");
49  for (int i = 0; i < paths.size(); ++i) {
50    if (paths[i].empty()) continue;
51    out->add_paths(paths[i]);
52  }
53}
54
55bool FieldMaskUtil::SnakeCaseToCamelCase(StringPiece input, string* output) {
56  output->clear();
57  bool after_underscore = false;
58  for (int i = 0; i < input.size(); ++i) {
59    if (input[i] >= 'A' && input[i] <= 'Z') {
60      // The field name must not contain uppercase letters.
61      return false;
62    }
63    if (after_underscore) {
64      if (input[i] >= 'a' && input[i] <= 'z') {
65        output->push_back(input[i] + 'A' - 'a');
66        after_underscore = false;
67      } else {
68        // The character after a "_" must be a lowercase letter.
69        return false;
70      }
71    } else if (input[i] == '_') {
72      after_underscore = true;
73    } else {
74      output->push_back(input[i]);
75    }
76  }
77  if (after_underscore) {
78    // Trailing "_".
79    return false;
80  }
81  return true;
82}
83
84bool FieldMaskUtil::CamelCaseToSnakeCase(StringPiece input, string* output) {
85  output->clear();
86  for (int i = 0; i < input.size(); ++i) {
87    if (input[i] == '_') {
88      // The field name must not contain "_"s.
89      return false;
90    }
91    if (input[i] >= 'A' && input[i] <= 'Z') {
92      output->push_back('_');
93      output->push_back(input[i] + 'a' - 'A');
94    } else {
95      output->push_back(input[i]);
96    }
97  }
98  return true;
99}
100
101bool FieldMaskUtil::ToJsonString(const FieldMask& mask, string* out) {
102  out->clear();
103  for (int i = 0; i < mask.paths_size(); ++i) {
104    const string& path = mask.paths(i);
105    string camelcase_path;
106    if (!SnakeCaseToCamelCase(path, &camelcase_path)) {
107      return false;
108    }
109    if (i > 0) {
110      out->push_back(',');
111    }
112    out->append(camelcase_path);
113  }
114  return true;
115}
116
117bool FieldMaskUtil::FromJsonString(StringPiece str, FieldMask* out) {
118  out->Clear();
119  vector<string> paths = Split(str, ",");
120  for (int i = 0; i < paths.size(); ++i) {
121    if (paths[i].empty()) continue;
122    string snakecase_path;
123    if (!CamelCaseToSnakeCase(paths[i], &snakecase_path)) {
124      return false;
125    }
126    out->add_paths(snakecase_path);
127  }
128  return true;
129}
130
131bool FieldMaskUtil::InternalIsValidPath(const Descriptor* descriptor,
132                                        StringPiece path) {
133  vector<string> parts = Split(path, ".");
134  for (int i = 0; i < parts.size(); ++i) {
135    const string& field_name = parts[i];
136    if (descriptor == NULL) {
137      return false;
138    }
139    const FieldDescriptor* field = descriptor->FindFieldByName(field_name);
140    if (field == NULL) {
141      return false;
142    }
143    if (!field->is_repeated() &&
144        field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
145      descriptor = field->message_type();
146    } else {
147      descriptor = NULL;
148    }
149  }
150  return true;
151}
152
153void FieldMaskUtil::InternalGetFieldMaskForAllFields(
154    const Descriptor* descriptor, FieldMask* out) {
155  for (int i = 0; i < descriptor->field_count(); ++i) {
156    out->add_paths(descriptor->field(i)->name());
157  }
158}
159
160namespace {
161// A FieldMaskTree represents a FieldMask in a tree structure. For example,
162// given a FieldMask "foo.bar,foo.baz,bar.baz", the FieldMaskTree will be:
163//
164//   [root] -+- foo -+- bar
165//           |       |
166//           |       +- baz
167//           |
168//           +- bar --- baz
169//
170// In the tree, each leaf node represents a field path.
171class FieldMaskTree {
172 public:
173  FieldMaskTree();
174  ~FieldMaskTree();
175
176  void MergeFromFieldMask(const FieldMask& mask);
177  void MergeToFieldMask(FieldMask* mask);
178
179  // Add a field path into the tree. In a FieldMask, each field path matches
180  // the specified field and also all its sub-fields. If the field path to
181  // add is a sub-path of an existing field path in the tree (i.e., a leaf
182  // node), it means the tree already matches the given path so nothing will
183  // be added to the tree. If the path matches an existing non-leaf node in the
184  // tree, that non-leaf node will be turned into a leaf node with all its
185  // children removed because the path matches all the node's children.
186  void AddPath(const string& path);
187
188  // Calculate the intersection part of a field path with this tree and add
189  // the intersection field path into out.
190  void IntersectPath(const string& path, FieldMaskTree* out);
191
192  // Merge all fields specified by this tree from one message to another.
193  void MergeMessage(const Message& source,
194                    const FieldMaskUtil::MergeOptions& options,
195                    Message* destination) {
196    // Do nothing if the tree is empty.
197    if (root_.children.empty()) {
198      return;
199    }
200    MergeMessage(&root_, source, options, destination);
201  }
202
203 private:
204  struct Node {
205    Node() {}
206
207    ~Node() { ClearChildren(); }
208
209    void ClearChildren() {
210      for (map<string, Node*>::iterator it = children.begin();
211           it != children.end(); ++it) {
212        delete it->second;
213      }
214      children.clear();
215    }
216
217    map<string, Node*> children;
218
219   private:
220    GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Node);
221  };
222
223  // Merge a sub-tree to mask. This method adds the field paths represented
224  // by all leaf nodes descended from "node" to mask.
225  void MergeToFieldMask(const string& prefix, const Node* node, FieldMask* out);
226
227  // Merge all leaf nodes of a sub-tree to another tree.
228  void MergeLeafNodesToTree(const string& prefix, const Node* node,
229                            FieldMaskTree* out);
230
231  // Merge all fields specified by a sub-tree from one message to another.
232  void MergeMessage(const Node* node, const Message& source,
233                    const FieldMaskUtil::MergeOptions& options,
234                    Message* destination);
235
236  Node root_;
237
238  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldMaskTree);
239};
240
241FieldMaskTree::FieldMaskTree() {}
242
243FieldMaskTree::~FieldMaskTree() {}
244
245void FieldMaskTree::MergeFromFieldMask(const FieldMask& mask) {
246  for (int i = 0; i < mask.paths_size(); ++i) {
247    AddPath(mask.paths(i));
248  }
249}
250
251void FieldMaskTree::MergeToFieldMask(FieldMask* mask) {
252  MergeToFieldMask("", &root_, mask);
253}
254
255void FieldMaskTree::MergeToFieldMask(const string& prefix, const Node* node,
256                                     FieldMask* out) {
257  if (node->children.empty()) {
258    if (prefix.empty()) {
259      // This is the root node.
260      return;
261    }
262    out->add_paths(prefix);
263    return;
264  }
265  for (map<string, Node*>::const_iterator it = node->children.begin();
266       it != node->children.end(); ++it) {
267    string current_path = prefix.empty() ? it->first : prefix + "." + it->first;
268    MergeToFieldMask(current_path, it->second, out);
269  }
270}
271
272void FieldMaskTree::AddPath(const string& path) {
273  vector<string> parts = Split(path, ".");
274  if (parts.empty()) {
275    return;
276  }
277  bool new_branch = false;
278  Node* node = &root_;
279  for (int i = 0; i < parts.size(); ++i) {
280    if (!new_branch && node != &root_ && node->children.empty()) {
281      // Path matches an existing leaf node. This means the path is already
282      // coverred by this tree (for example, adding "foo.bar.baz" to a tree
283      // which already contains "foo.bar").
284      return;
285    }
286    const string& node_name = parts[i];
287    Node*& child = node->children[node_name];
288    if (child == NULL) {
289      new_branch = true;
290      child = new Node();
291    }
292    node = child;
293  }
294  if (!node->children.empty()) {
295    node->ClearChildren();
296  }
297}
298
299void FieldMaskTree::IntersectPath(const string& path, FieldMaskTree* out) {
300  vector<string> parts = Split(path, ".");
301  if (parts.empty()) {
302    return;
303  }
304  const Node* node = &root_;
305  for (int i = 0; i < parts.size(); ++i) {
306    if (node->children.empty()) {
307      if (node != &root_) {
308        out->AddPath(path);
309      }
310      return;
311    }
312    const string& node_name = parts[i];
313    const Node* result = FindPtrOrNull(node->children, node_name);
314    if (result == NULL) {
315      // No intersection found.
316      return;
317    }
318    node = result;
319  }
320  // Now we found a matching node with the given path. Add all leaf nodes
321  // to out.
322  MergeLeafNodesToTree(path, node, out);
323}
324
325void FieldMaskTree::MergeLeafNodesToTree(const string& prefix, const Node* node,
326                                         FieldMaskTree* out) {
327  if (node->children.empty()) {
328    out->AddPath(prefix);
329  }
330  for (map<string, Node*>::const_iterator it = node->children.begin();
331       it != node->children.end(); ++it) {
332    string current_path = prefix.empty() ? it->first : prefix + "." + it->first;
333    MergeLeafNodesToTree(current_path, it->second, out);
334  }
335}
336
337void FieldMaskTree::MergeMessage(const Node* node, const Message& source,
338                                 const FieldMaskUtil::MergeOptions& options,
339                                 Message* destination) {
340  GOOGLE_DCHECK(!node->children.empty());
341  const Reflection* source_reflection = source.GetReflection();
342  const Reflection* destination_reflection = destination->GetReflection();
343  const Descriptor* descriptor = source.GetDescriptor();
344  for (map<string, Node*>::const_iterator it = node->children.begin();
345       it != node->children.end(); ++it) {
346    const string& field_name = it->first;
347    const Node* child = it->second;
348    const FieldDescriptor* field = descriptor->FindFieldByName(field_name);
349    if (field == NULL) {
350      GOOGLE_LOG(ERROR) << "Cannot find field \"" << field_name << "\" in message "
351                 << descriptor->full_name();
352      continue;
353    }
354    if (!child->children.empty()) {
355      // Sub-paths are only allowed for singular message fields.
356      if (field->is_repeated() ||
357          field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
358        GOOGLE_LOG(ERROR) << "Field \"" << field_name << "\" in message "
359                   << descriptor->full_name()
360                   << " is not a singular message field and cannot "
361                   << "have sub-fields.";
362        continue;
363      }
364      MergeMessage(child, source_reflection->GetMessage(source, field), options,
365                   destination_reflection->MutableMessage(destination, field));
366      continue;
367    }
368    if (!field->is_repeated()) {
369      switch (field->cpp_type()) {
370#define COPY_VALUE(TYPE, Name)                                            \
371  case FieldDescriptor::CPPTYPE_##TYPE: {                                 \
372    destination_reflection->Set##Name(                                    \
373        destination, field, source_reflection->Get##Name(source, field)); \
374    break;                                                                \
375  }
376        COPY_VALUE(BOOL, Bool)
377        COPY_VALUE(INT32, Int32)
378        COPY_VALUE(INT64, Int64)
379        COPY_VALUE(UINT32, UInt32)
380        COPY_VALUE(UINT64, UInt64)
381        COPY_VALUE(FLOAT, Float)
382        COPY_VALUE(DOUBLE, Double)
383        COPY_VALUE(ENUM, Enum)
384        COPY_VALUE(STRING, String)
385#undef COPY_VALUE
386        case FieldDescriptor::CPPTYPE_MESSAGE: {
387          if (options.replace_message_fields()) {
388            destination_reflection->ClearField(destination, field);
389          }
390          if (source_reflection->HasField(source, field)) {
391            destination_reflection->MutableMessage(destination, field)
392                ->MergeFrom(source_reflection->GetMessage(source, field));
393          }
394          break;
395        }
396      }
397    } else {
398      if (options.replace_repeated_fields()) {
399        destination_reflection->ClearField(destination, field);
400      }
401      switch (field->cpp_type()) {
402#define COPY_REPEATED_VALUE(TYPE, Name)                            \
403  case FieldDescriptor::CPPTYPE_##TYPE: {                          \
404    int size = source_reflection->FieldSize(source, field);        \
405    for (int i = 0; i < size; ++i) {                               \
406      destination_reflection->Add##Name(                           \
407          destination, field,                                      \
408          source_reflection->GetRepeated##Name(source, field, i)); \
409    }                                                              \
410    break;                                                         \
411  }
412        COPY_REPEATED_VALUE(BOOL, Bool)
413        COPY_REPEATED_VALUE(INT32, Int32)
414        COPY_REPEATED_VALUE(INT64, Int64)
415        COPY_REPEATED_VALUE(UINT32, UInt32)
416        COPY_REPEATED_VALUE(UINT64, UInt64)
417        COPY_REPEATED_VALUE(FLOAT, Float)
418        COPY_REPEATED_VALUE(DOUBLE, Double)
419        COPY_REPEATED_VALUE(ENUM, Enum)
420        COPY_REPEATED_VALUE(STRING, String)
421#undef COPY_REPEATED_VALUE
422        case FieldDescriptor::CPPTYPE_MESSAGE: {
423          int size = source_reflection->FieldSize(source, field);
424          for (int i = 0; i < size; ++i) {
425            destination_reflection->AddMessage(destination, field)
426                ->MergeFrom(
427                    source_reflection->GetRepeatedMessage(source, field, i));
428          }
429          break;
430        }
431      }
432    }
433  }
434}
435
436}  // namespace
437
438void FieldMaskUtil::ToCanonicalForm(const FieldMask& mask, FieldMask* out) {
439  FieldMaskTree tree;
440  tree.MergeFromFieldMask(mask);
441  out->Clear();
442  tree.MergeToFieldMask(out);
443}
444
445void FieldMaskUtil::Union(const FieldMask& mask1, const FieldMask& mask2,
446                          FieldMask* out) {
447  FieldMaskTree tree;
448  tree.MergeFromFieldMask(mask1);
449  tree.MergeFromFieldMask(mask2);
450  out->Clear();
451  tree.MergeToFieldMask(out);
452}
453
454void FieldMaskUtil::Intersect(const FieldMask& mask1, const FieldMask& mask2,
455                              FieldMask* out) {
456  FieldMaskTree tree, intersection;
457  tree.MergeFromFieldMask(mask1);
458  for (int i = 0; i < mask2.paths_size(); ++i) {
459    tree.IntersectPath(mask2.paths(i), &intersection);
460  }
461  out->Clear();
462  intersection.MergeToFieldMask(out);
463}
464
465bool FieldMaskUtil::IsPathInFieldMask(StringPiece path, const FieldMask& mask) {
466  for (int i = 0; i < mask.paths_size(); ++i) {
467    const string& mask_path = mask.paths(i);
468    if (path == mask_path) {
469      return true;
470    } else if (mask_path.length() < path.length()) {
471      // Also check whether mask.paths(i) is a prefix of path.
472      if (path.substr(0, mask_path.length() + 1).compare(mask_path + ".") ==
473          0) {
474        return true;
475      }
476    }
477  }
478  return false;
479}
480
481void FieldMaskUtil::MergeMessageTo(const Message& source, const FieldMask& mask,
482                                   const MergeOptions& options,
483                                   Message* destination) {
484  GOOGLE_CHECK(source.GetDescriptor() == destination->GetDescriptor());
485  // Build a FieldMaskTree and walk through the tree to merge all specified
486  // fields.
487  FieldMaskTree tree;
488  tree.MergeFromFieldMask(mask);
489  tree.MergeMessage(source, options, destination);
490}
491
492}  // namespace util
493}  // namespace protobuf
494}  // namespace google
495