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