• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
35 #include <google/protobuf/stubs/map_util.h>
36 
37 #include <google/protobuf/port_def.inc>
38 
39 namespace google {
40 namespace protobuf {
41 namespace util {
42 
43 using google::protobuf::FieldMask;
44 
ToString(const FieldMask & mask)45 std::string FieldMaskUtil::ToString(const FieldMask& mask) {
46   return Join(mask.paths(), ",");
47 }
48 
FromString(StringPiece str,FieldMask * out)49 void FieldMaskUtil::FromString(StringPiece str, FieldMask* out) {
50   out->Clear();
51   std::vector<std::string> paths = Split(str, ",");
52   for (int i = 0; i < paths.size(); ++i) {
53     if (paths[i].empty()) continue;
54     out->add_paths(paths[i]);
55   }
56 }
57 
SnakeCaseToCamelCase(StringPiece input,std::string * output)58 bool FieldMaskUtil::SnakeCaseToCamelCase(StringPiece input,
59                                          std::string* output) {
60   output->clear();
61   bool after_underscore = false;
62   for (int i = 0; i < input.size(); ++i) {
63     if (input[i] >= 'A' && input[i] <= 'Z') {
64       // The field name must not contain uppercase letters.
65       return false;
66     }
67     if (after_underscore) {
68       if (input[i] >= 'a' && input[i] <= 'z') {
69         output->push_back(input[i] + 'A' - 'a');
70         after_underscore = false;
71       } else {
72         // The character after a "_" must be a lowercase letter.
73         return false;
74       }
75     } else if (input[i] == '_') {
76       after_underscore = true;
77     } else {
78       output->push_back(input[i]);
79     }
80   }
81   if (after_underscore) {
82     // Trailing "_".
83     return false;
84   }
85   return true;
86 }
87 
CamelCaseToSnakeCase(StringPiece input,std::string * output)88 bool FieldMaskUtil::CamelCaseToSnakeCase(StringPiece input,
89                                          std::string* output) {
90   output->clear();
91   for (int i = 0; i < input.size(); ++i) {
92     if (input[i] == '_') {
93       // The field name must not contain "_"s.
94       return false;
95     }
96     if (input[i] >= 'A' && input[i] <= 'Z') {
97       output->push_back('_');
98       output->push_back(input[i] + 'a' - 'A');
99     } else {
100       output->push_back(input[i]);
101     }
102   }
103   return true;
104 }
105 
ToJsonString(const FieldMask & mask,std::string * out)106 bool FieldMaskUtil::ToJsonString(const FieldMask& mask, std::string* out) {
107   out->clear();
108   for (int i = 0; i < mask.paths_size(); ++i) {
109     const std::string& path = mask.paths(i);
110     std::string camelcase_path;
111     if (!SnakeCaseToCamelCase(path, &camelcase_path)) {
112       return false;
113     }
114     if (i > 0) {
115       out->push_back(',');
116     }
117     out->append(camelcase_path);
118   }
119   return true;
120 }
121 
FromJsonString(StringPiece str,FieldMask * out)122 bool FieldMaskUtil::FromJsonString(StringPiece str, FieldMask* out) {
123   out->Clear();
124   std::vector<std::string> paths = Split(str, ",");
125   for (int i = 0; i < paths.size(); ++i) {
126     if (paths[i].empty()) continue;
127     std::string snakecase_path;
128     if (!CamelCaseToSnakeCase(paths[i], &snakecase_path)) {
129       return false;
130     }
131     out->add_paths(snakecase_path);
132   }
133   return true;
134 }
135 
GetFieldDescriptors(const Descriptor * descriptor,StringPiece path,std::vector<const FieldDescriptor * > * field_descriptors)136 bool FieldMaskUtil::GetFieldDescriptors(
137     const Descriptor* descriptor, StringPiece path,
138     std::vector<const FieldDescriptor*>* field_descriptors) {
139   if (field_descriptors != nullptr) {
140     field_descriptors->clear();
141   }
142   std::vector<std::string> parts = Split(path, ".");
143   for (int i = 0; i < parts.size(); ++i) {
144     const std::string& field_name = parts[i];
145     if (descriptor == nullptr) {
146       return false;
147     }
148     const FieldDescriptor* field = descriptor->FindFieldByName(field_name);
149     if (field == nullptr) {
150       return false;
151     }
152     if (field_descriptors != nullptr) {
153       field_descriptors->push_back(field);
154     }
155     if (!field->is_repeated() &&
156         field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
157       descriptor = field->message_type();
158     } else {
159       descriptor = nullptr;
160     }
161   }
162   return true;
163 }
164 
GetFieldMaskForAllFields(const Descriptor * descriptor,FieldMask * out)165 void FieldMaskUtil::GetFieldMaskForAllFields(const Descriptor* descriptor,
166                                              FieldMask* out) {
167   for (int i = 0; i < descriptor->field_count(); ++i) {
168     out->add_paths(descriptor->field(i)->name());
169   }
170 }
171 
172 namespace {
173 // A FieldMaskTree represents a FieldMask in a tree structure. For example,
174 // given a FieldMask "foo.bar,foo.baz,bar.baz", the FieldMaskTree will be:
175 //
176 //   [root] -+- foo -+- bar
177 //           |       |
178 //           |       +- baz
179 //           |
180 //           +- bar --- baz
181 //
182 // In the tree, each leaf node represents a field path.
183 class FieldMaskTree {
184  public:
185   FieldMaskTree();
186   ~FieldMaskTree();
187 
188   void MergeFromFieldMask(const FieldMask& mask);
189   void MergeToFieldMask(FieldMask* mask);
190 
191   // Add a field path into the tree. In a FieldMask, each field path matches
192   // the specified field and also all its sub-fields. If the field path to
193   // add is a sub-path of an existing field path in the tree (i.e., a leaf
194   // node), it means the tree already matches the given path so nothing will
195   // be added to the tree. If the path matches an existing non-leaf node in the
196   // tree, that non-leaf node will be turned into a leaf node with all its
197   // children removed because the path matches all the node's children.
198   void AddPath(const std::string& path);
199 
200   // Remove a path from the tree.
201   // If the path is a sub-path of an existing field path in the tree, it means
202   // we need remove the existing fied path and add all sub-paths except
203   // specified path. If the path matches an existing node in the tree, this node
204   // will be moved.
205   void RemovePath(const std::string& path, const Descriptor* descriptor);
206 
207   // Calculate the intersection part of a field path with this tree and add
208   // the intersection field path into out.
209   void IntersectPath(const std::string& path, FieldMaskTree* out);
210 
211   // Merge all fields specified by this tree from one message to another.
MergeMessage(const Message & source,const FieldMaskUtil::MergeOptions & options,Message * destination)212   void MergeMessage(const Message& source,
213                     const FieldMaskUtil::MergeOptions& options,
214                     Message* destination) {
215     // Do nothing if the tree is empty.
216     if (root_.children.empty()) {
217       return;
218     }
219     MergeMessage(&root_, source, options, destination);
220   }
221 
222   // Add required field path of the message to this tree based on current tree
223   // structure. If a message is present in the tree, add the path of its
224   // required field to the tree. This is to make sure that after trimming a
225   // message with required fields are set, check IsInitialized() will not fail.
AddRequiredFieldPath(const Descriptor * descriptor)226   void AddRequiredFieldPath(const Descriptor* descriptor) {
227     // Do nothing if the tree is empty.
228     if (root_.children.empty()) {
229       return;
230     }
231     AddRequiredFieldPath(&root_, descriptor);
232   }
233 
234   // Trims all fields not specified by this tree from the given message.
235   // Returns true if the message is modified.
TrimMessage(Message * message)236   bool TrimMessage(Message* message) {
237     // Do nothing if the tree is empty.
238     if (root_.children.empty()) {
239       return false;
240     }
241     return TrimMessage(&root_, message);
242   }
243 
244  private:
245   struct Node {
Nodegoogle::protobuf::util::__anon464fe6e80111::FieldMaskTree::Node246     Node() {}
247 
~Nodegoogle::protobuf::util::__anon464fe6e80111::FieldMaskTree::Node248     ~Node() { ClearChildren(); }
249 
ClearChildrengoogle::protobuf::util::__anon464fe6e80111::FieldMaskTree::Node250     void ClearChildren() {
251       for (std::map<std::string, Node*>::iterator it = children.begin();
252            it != children.end(); ++it) {
253         delete it->second;
254       }
255       children.clear();
256     }
257 
258     std::map<std::string, Node*> children;
259 
260    private:
261     GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Node);
262   };
263 
264   // Merge a sub-tree to mask. This method adds the field paths represented
265   // by all leaf nodes descended from "node" to mask.
266   void MergeToFieldMask(const std::string& prefix, const Node* node,
267                         FieldMask* out);
268 
269   // Merge all leaf nodes of a sub-tree to another tree.
270   void MergeLeafNodesToTree(const std::string& prefix, const Node* node,
271                             FieldMaskTree* out);
272 
273   // Merge all fields specified by a sub-tree from one message to another.
274   void MergeMessage(const Node* node, const Message& source,
275                     const FieldMaskUtil::MergeOptions& options,
276                     Message* destination);
277 
278   // Add required field path of the message to this tree based on current tree
279   // structure. If a message is present in the tree, add the path of its
280   // required field to the tree. This is to make sure that after trimming a
281   // message with required fields are set, check IsInitialized() will not fail.
282   void AddRequiredFieldPath(Node* node, const Descriptor* descriptor);
283 
284   // Trims all fields not specified by this sub-tree from the given message.
285   // Returns true if the message is actually modified
286   bool TrimMessage(const Node* node, Message* message);
287 
288   Node root_;
289 
290   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldMaskTree);
291 };
292 
FieldMaskTree()293 FieldMaskTree::FieldMaskTree() {}
294 
~FieldMaskTree()295 FieldMaskTree::~FieldMaskTree() {}
296 
MergeFromFieldMask(const FieldMask & mask)297 void FieldMaskTree::MergeFromFieldMask(const FieldMask& mask) {
298   for (int i = 0; i < mask.paths_size(); ++i) {
299     AddPath(mask.paths(i));
300   }
301 }
302 
MergeToFieldMask(FieldMask * mask)303 void FieldMaskTree::MergeToFieldMask(FieldMask* mask) {
304   MergeToFieldMask("", &root_, mask);
305 }
306 
MergeToFieldMask(const std::string & prefix,const Node * node,FieldMask * out)307 void FieldMaskTree::MergeToFieldMask(const std::string& prefix,
308                                      const Node* node, FieldMask* out) {
309   if (node->children.empty()) {
310     if (prefix.empty()) {
311       // This is the root node.
312       return;
313     }
314     out->add_paths(prefix);
315     return;
316   }
317   for (std::map<std::string, Node*>::const_iterator it = node->children.begin();
318        it != node->children.end(); ++it) {
319     std::string current_path =
320         prefix.empty() ? it->first : prefix + "." + it->first;
321     MergeToFieldMask(current_path, it->second, out);
322   }
323 }
324 
AddPath(const std::string & path)325 void FieldMaskTree::AddPath(const std::string& path) {
326   std::vector<std::string> parts = Split(path, ".");
327   if (parts.empty()) {
328     return;
329   }
330   bool new_branch = false;
331   Node* node = &root_;
332   for (int i = 0; i < parts.size(); ++i) {
333     if (!new_branch && node != &root_ && node->children.empty()) {
334       // Path matches an existing leaf node. This means the path is already
335       // coverred by this tree (for example, adding "foo.bar.baz" to a tree
336       // which already contains "foo.bar").
337       return;
338     }
339     const std::string& node_name = parts[i];
340     Node*& child = node->children[node_name];
341     if (child == NULL) {
342       new_branch = true;
343       child = new Node();
344     }
345     node = child;
346   }
347   if (!node->children.empty()) {
348     node->ClearChildren();
349   }
350 }
351 
RemovePath(const std::string & path,const Descriptor * descriptor)352 void FieldMaskTree::RemovePath(const std::string& path,
353                                const Descriptor* descriptor) {
354   if (root_.children.empty()) {
355     // Nothing to be removed from an empty tree. We shortcut it here so an empty
356     // tree won't be interpreted as a field mask containing all fields by the
357     // code below.
358     return;
359   }
360   std::vector<std::string> parts = Split(path, ".");
361   if (parts.empty()) {
362     return;
363   }
364   std::vector<Node*> nodes(parts.size());
365   Node* node = &root_;
366   const Descriptor* current_descriptor = descriptor;
367   Node* new_branch_node = nullptr;
368   for (int i = 0; i < parts.size(); ++i) {
369     nodes[i] = node;
370     const FieldDescriptor* field_descriptor =
371         current_descriptor->FindFieldByName(parts[i]);
372     if (field_descriptor == nullptr ||
373         (field_descriptor->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE &&
374          i != parts.size() - 1)) {
375       // Invalid path.
376       if (new_branch_node != nullptr) {
377         // If add any new nodes, cleanup.
378         new_branch_node->ClearChildren();
379       }
380       return;
381     }
382 
383     if (node->children.empty()) {
384       if (new_branch_node == nullptr) {
385         new_branch_node = node;
386       }
387       for (int i = 0; i < current_descriptor->field_count(); ++i) {
388         node->children[current_descriptor->field(i)->name()] = new Node();
389       }
390     }
391     if (ContainsKey(node->children, parts[i])) {
392       node = node->children[parts[i]];
393       if (field_descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
394         current_descriptor = field_descriptor->message_type();
395       }
396     } else {
397       // Path does not exist.
398       return;
399     }
400   }
401   // Remove path.
402   for (int i = parts.size() - 1; i >= 0; i--) {
403     delete nodes[i]->children[parts[i]];
404     nodes[i]->children.erase(parts[i]);
405     if (!nodes[i]->children.empty()) {
406       break;
407     }
408   }
409 }
410 
IntersectPath(const std::string & path,FieldMaskTree * out)411 void FieldMaskTree::IntersectPath(const std::string& path, FieldMaskTree* out) {
412   std::vector<std::string> parts = Split(path, ".");
413   if (parts.empty()) {
414     return;
415   }
416   const Node* node = &root_;
417   for (int i = 0; i < parts.size(); ++i) {
418     if (node->children.empty()) {
419       if (node != &root_) {
420         out->AddPath(path);
421       }
422       return;
423     }
424     const std::string& node_name = parts[i];
425     const Node* result = FindPtrOrNull(node->children, node_name);
426     if (result == NULL) {
427       // No intersection found.
428       return;
429     }
430     node = result;
431   }
432   // Now we found a matching node with the given path. Add all leaf nodes
433   // to out.
434   MergeLeafNodesToTree(path, node, out);
435 }
436 
MergeLeafNodesToTree(const std::string & prefix,const Node * node,FieldMaskTree * out)437 void FieldMaskTree::MergeLeafNodesToTree(const std::string& prefix,
438                                          const Node* node, FieldMaskTree* out) {
439   if (node->children.empty()) {
440     out->AddPath(prefix);
441   }
442   for (std::map<std::string, Node*>::const_iterator it = node->children.begin();
443        it != node->children.end(); ++it) {
444     std::string current_path =
445         prefix.empty() ? it->first : prefix + "." + it->first;
446     MergeLeafNodesToTree(current_path, it->second, out);
447   }
448 }
449 
MergeMessage(const Node * node,const Message & source,const FieldMaskUtil::MergeOptions & options,Message * destination)450 void FieldMaskTree::MergeMessage(const Node* node, const Message& source,
451                                  const FieldMaskUtil::MergeOptions& options,
452                                  Message* destination) {
453   GOOGLE_DCHECK(!node->children.empty());
454   const Reflection* source_reflection = source.GetReflection();
455   const Reflection* destination_reflection = destination->GetReflection();
456   const Descriptor* descriptor = source.GetDescriptor();
457   for (std::map<std::string, Node*>::const_iterator it = node->children.begin();
458        it != node->children.end(); ++it) {
459     const std::string& field_name = it->first;
460     const Node* child = it->second;
461     const FieldDescriptor* field = descriptor->FindFieldByName(field_name);
462     if (field == NULL) {
463       GOOGLE_LOG(ERROR) << "Cannot find field \"" << field_name << "\" in message "
464                  << descriptor->full_name();
465       continue;
466     }
467     if (!child->children.empty()) {
468       // Sub-paths are only allowed for singular message fields.
469       if (field->is_repeated() ||
470           field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
471         GOOGLE_LOG(ERROR) << "Field \"" << field_name << "\" in message "
472                    << descriptor->full_name()
473                    << " is not a singular message field and cannot "
474                    << "have sub-fields.";
475         continue;
476       }
477       MergeMessage(child, source_reflection->GetMessage(source, field), options,
478                    destination_reflection->MutableMessage(destination, field));
479       continue;
480     }
481     if (!field->is_repeated()) {
482       switch (field->cpp_type()) {
483 #define COPY_VALUE(TYPE, Name)                                              \
484   case FieldDescriptor::CPPTYPE_##TYPE: {                                   \
485     if (source_reflection->HasField(source, field)) {                       \
486       destination_reflection->Set##Name(                                    \
487           destination, field, source_reflection->Get##Name(source, field)); \
488     } else {                                                                \
489       destination_reflection->ClearField(destination, field);               \
490     }                                                                       \
491     break;                                                                  \
492   }
493         COPY_VALUE(BOOL, Bool)
494         COPY_VALUE(INT32, Int32)
495         COPY_VALUE(INT64, Int64)
496         COPY_VALUE(UINT32, UInt32)
497         COPY_VALUE(UINT64, UInt64)
498         COPY_VALUE(FLOAT, Float)
499         COPY_VALUE(DOUBLE, Double)
500         COPY_VALUE(ENUM, Enum)
501         COPY_VALUE(STRING, String)
502 #undef COPY_VALUE
503         case FieldDescriptor::CPPTYPE_MESSAGE: {
504           if (options.replace_message_fields()) {
505             destination_reflection->ClearField(destination, field);
506           }
507           if (source_reflection->HasField(source, field)) {
508             destination_reflection->MutableMessage(destination, field)
509                 ->MergeFrom(source_reflection->GetMessage(source, field));
510           }
511           break;
512         }
513       }
514     } else {
515       if (options.replace_repeated_fields()) {
516         destination_reflection->ClearField(destination, field);
517       }
518       switch (field->cpp_type()) {
519 #define COPY_REPEATED_VALUE(TYPE, Name)                            \
520   case FieldDescriptor::CPPTYPE_##TYPE: {                          \
521     int size = source_reflection->FieldSize(source, field);        \
522     for (int i = 0; i < size; ++i) {                               \
523       destination_reflection->Add##Name(                           \
524           destination, field,                                      \
525           source_reflection->GetRepeated##Name(source, field, i)); \
526     }                                                              \
527     break;                                                         \
528   }
529         COPY_REPEATED_VALUE(BOOL, Bool)
530         COPY_REPEATED_VALUE(INT32, Int32)
531         COPY_REPEATED_VALUE(INT64, Int64)
532         COPY_REPEATED_VALUE(UINT32, UInt32)
533         COPY_REPEATED_VALUE(UINT64, UInt64)
534         COPY_REPEATED_VALUE(FLOAT, Float)
535         COPY_REPEATED_VALUE(DOUBLE, Double)
536         COPY_REPEATED_VALUE(ENUM, Enum)
537         COPY_REPEATED_VALUE(STRING, String)
538 #undef COPY_REPEATED_VALUE
539         case FieldDescriptor::CPPTYPE_MESSAGE: {
540           int size = source_reflection->FieldSize(source, field);
541           for (int i = 0; i < size; ++i) {
542             destination_reflection->AddMessage(destination, field)
543                 ->MergeFrom(
544                     source_reflection->GetRepeatedMessage(source, field, i));
545           }
546           break;
547         }
548       }
549     }
550   }
551 }
552 
AddRequiredFieldPath(Node * node,const Descriptor * descriptor)553 void FieldMaskTree::AddRequiredFieldPath(Node* node,
554                                          const Descriptor* descriptor) {
555   const int32 field_count = descriptor->field_count();
556   for (int index = 0; index < field_count; ++index) {
557     const FieldDescriptor* field = descriptor->field(index);
558     if (field->is_required()) {
559       const std::string& node_name = field->name();
560       Node*& child = node->children[node_name];
561       if (child == nullptr) {
562         // Add required field path to the tree
563         child = new Node();
564       } else if (child->children.empty()) {
565         // If the required field is in the tree and does not have any children,
566         // do nothing.
567         continue;
568       }
569       // Add required field in the children to the tree if the field is message.
570       if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
571         AddRequiredFieldPath(child, field->message_type());
572       }
573     } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
574       std::map<std::string, Node*>::const_iterator it =
575           node->children.find(field->name());
576       if (it != node->children.end()) {
577         // Add required fields in the children to the
578         // tree if the field is a message and present in the tree.
579         Node* child = it->second;
580         if (!child->children.empty()) {
581           AddRequiredFieldPath(child, field->message_type());
582         }
583       }
584     }
585   }
586 }
587 
TrimMessage(const Node * node,Message * message)588 bool FieldMaskTree::TrimMessage(const Node* node, Message* message) {
589   GOOGLE_DCHECK(!node->children.empty());
590   const Reflection* reflection = message->GetReflection();
591   const Descriptor* descriptor = message->GetDescriptor();
592   const int32 field_count = descriptor->field_count();
593   bool modified = false;
594   for (int index = 0; index < field_count; ++index) {
595     const FieldDescriptor* field = descriptor->field(index);
596     std::map<std::string, Node*>::const_iterator it =
597         node->children.find(field->name());
598     if (it == node->children.end()) {
599       if (field->is_repeated()) {
600         if (reflection->FieldSize(*message, field) != 0) {
601           modified = true;
602         }
603       } else {
604         if (reflection->HasField(*message, field)) {
605           modified = true;
606         }
607       }
608       reflection->ClearField(message, field);
609     } else {
610       if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
611         Node* child = it->second;
612         if (!child->children.empty() && reflection->HasField(*message, field)) {
613           bool nestedMessageChanged =
614               TrimMessage(child, reflection->MutableMessage(message, field));
615           modified = nestedMessageChanged || modified;
616         }
617       }
618     }
619   }
620   return modified;
621 }
622 
623 }  // namespace
624 
ToCanonicalForm(const FieldMask & mask,FieldMask * out)625 void FieldMaskUtil::ToCanonicalForm(const FieldMask& mask, FieldMask* out) {
626   FieldMaskTree tree;
627   tree.MergeFromFieldMask(mask);
628   out->Clear();
629   tree.MergeToFieldMask(out);
630 }
631 
Union(const FieldMask & mask1,const FieldMask & mask2,FieldMask * out)632 void FieldMaskUtil::Union(const FieldMask& mask1, const FieldMask& mask2,
633                           FieldMask* out) {
634   FieldMaskTree tree;
635   tree.MergeFromFieldMask(mask1);
636   tree.MergeFromFieldMask(mask2);
637   out->Clear();
638   tree.MergeToFieldMask(out);
639 }
640 
Intersect(const FieldMask & mask1,const FieldMask & mask2,FieldMask * out)641 void FieldMaskUtil::Intersect(const FieldMask& mask1, const FieldMask& mask2,
642                               FieldMask* out) {
643   FieldMaskTree tree, intersection;
644   tree.MergeFromFieldMask(mask1);
645   for (int i = 0; i < mask2.paths_size(); ++i) {
646     tree.IntersectPath(mask2.paths(i), &intersection);
647   }
648   out->Clear();
649   intersection.MergeToFieldMask(out);
650 }
651 
Subtract(const Descriptor * descriptor,const FieldMask & mask1,const FieldMask & mask2,FieldMask * out)652 void FieldMaskUtil::Subtract(const Descriptor* descriptor,
653                              const FieldMask& mask1, const FieldMask& mask2,
654                              FieldMask* out) {
655   if (mask1.paths().empty()) {
656     out->Clear();
657     return;
658   }
659   FieldMaskTree tree;
660   tree.MergeFromFieldMask(mask1);
661   for (int i = 0; i < mask2.paths_size(); ++i) {
662     tree.RemovePath(mask2.paths(i), descriptor);
663   }
664   out->Clear();
665   tree.MergeToFieldMask(out);
666 }
667 
IsPathInFieldMask(StringPiece path,const FieldMask & mask)668 bool FieldMaskUtil::IsPathInFieldMask(StringPiece path,
669                                       const FieldMask& mask) {
670   for (int i = 0; i < mask.paths_size(); ++i) {
671     const std::string& mask_path = mask.paths(i);
672     if (path == mask_path) {
673       return true;
674     } else if (mask_path.length() < path.length()) {
675       // Also check whether mask.paths(i) is a prefix of path.
676       if (path.substr(0, mask_path.length() + 1).compare(mask_path + ".") ==
677           0) {
678         return true;
679       }
680     }
681   }
682   return false;
683 }
684 
MergeMessageTo(const Message & source,const FieldMask & mask,const MergeOptions & options,Message * destination)685 void FieldMaskUtil::MergeMessageTo(const Message& source, const FieldMask& mask,
686                                    const MergeOptions& options,
687                                    Message* destination) {
688   GOOGLE_CHECK(source.GetDescriptor() == destination->GetDescriptor());
689   // Build a FieldMaskTree and walk through the tree to merge all specified
690   // fields.
691   FieldMaskTree tree;
692   tree.MergeFromFieldMask(mask);
693   tree.MergeMessage(source, options, destination);
694 }
695 
TrimMessage(const FieldMask & mask,Message * message)696 bool FieldMaskUtil::TrimMessage(const FieldMask& mask, Message* message) {
697   // Build a FieldMaskTree and walk through the tree to merge all specified
698   // fields.
699   FieldMaskTree tree;
700   tree.MergeFromFieldMask(mask);
701   return tree.TrimMessage(GOOGLE_CHECK_NOTNULL(message));
702 }
703 
TrimMessage(const FieldMask & mask,Message * message,const TrimOptions & options)704 bool FieldMaskUtil::TrimMessage(const FieldMask& mask, Message* message,
705                                 const TrimOptions& options) {
706   // Build a FieldMaskTree and walk through the tree to merge all specified
707   // fields.
708   FieldMaskTree tree;
709   tree.MergeFromFieldMask(mask);
710   // If keep_required_fields is true, implicitely add required fields of
711   // a message present in the tree to prevent from trimming.
712   if (options.keep_required_fields()) {
713     tree.AddRequiredFieldPath(GOOGLE_CHECK_NOTNULL(message->GetDescriptor()));
714   }
715   return tree.TrimMessage(GOOGLE_CHECK_NOTNULL(message));
716 }
717 
718 }  // namespace util
719 }  // namespace protobuf
720 }  // namespace google
721