xref: /aosp_15_r20/external/cronet/third_party/protobuf/src/google/protobuf/util/field_mask_util.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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 <cstdint>
34 
35 #include <google/protobuf/stubs/strutil.h>
36 #include <google/protobuf/message.h>
37 #include <google/protobuf/stubs/map_util.h>
38 
39 // Must be included last.
40 #include <google/protobuf/port_def.inc>
41 
42 namespace google {
43 namespace protobuf {
44 namespace util {
45 
46 using google::protobuf::FieldMask;
47 
ToString(const FieldMask & mask)48 std::string FieldMaskUtil::ToString(const FieldMask& mask) {
49   return Join(mask.paths(), ",");
50 }
51 
FromString(StringPiece str,FieldMask * out)52 void FieldMaskUtil::FromString(StringPiece str, FieldMask* out) {
53   out->Clear();
54   std::vector<std::string> paths = Split(str, ",");
55   for (const std::string& path : paths) {
56     if (path.empty()) continue;
57     out->add_paths(path);
58   }
59 }
60 
SnakeCaseToCamelCase(StringPiece input,std::string * output)61 bool FieldMaskUtil::SnakeCaseToCamelCase(StringPiece input,
62                                          std::string* output) {
63   output->clear();
64   bool after_underscore = false;
65   for (char input_char : input) {
66     if (input_char >= 'A' && input_char <= 'Z') {
67       // The field name must not contain uppercase letters.
68       return false;
69     }
70     if (after_underscore) {
71       if (input_char >= 'a' && input_char <= 'z') {
72         output->push_back(input_char + 'A' - 'a');
73         after_underscore = false;
74       } else {
75         // The character after a "_" must be a lowercase letter.
76         return false;
77       }
78     } else if (input_char == '_') {
79       after_underscore = true;
80     } else {
81       output->push_back(input_char);
82     }
83   }
84   if (after_underscore) {
85     // Trailing "_".
86     return false;
87   }
88   return true;
89 }
90 
CamelCaseToSnakeCase(StringPiece input,std::string * output)91 bool FieldMaskUtil::CamelCaseToSnakeCase(StringPiece input,
92                                          std::string* output) {
93   output->clear();
94   for (const char c : input) {
95     if (c == '_') {
96       // The field name must not contain "_"s.
97       return false;
98     }
99     if (c >= 'A' && c <= 'Z') {
100       output->push_back('_');
101       output->push_back(c + 'a' - 'A');
102     } else {
103       output->push_back(c);
104     }
105   }
106   return true;
107 }
108 
ToJsonString(const FieldMask & mask,std::string * out)109 bool FieldMaskUtil::ToJsonString(const FieldMask& mask, std::string* out) {
110   out->clear();
111   for (int i = 0; i < mask.paths_size(); ++i) {
112     const std::string& path = mask.paths(i);
113     std::string camelcase_path;
114     if (!SnakeCaseToCamelCase(path, &camelcase_path)) {
115       return false;
116     }
117     if (i > 0) {
118       out->push_back(',');
119     }
120     out->append(camelcase_path);
121   }
122   return true;
123 }
124 
FromJsonString(StringPiece str,FieldMask * out)125 bool FieldMaskUtil::FromJsonString(StringPiece str, FieldMask* out) {
126   out->Clear();
127   std::vector<std::string> paths = Split(str, ",");
128   for (const std::string& path : paths) {
129     if (path.empty()) continue;
130     std::string snakecase_path;
131     if (!CamelCaseToSnakeCase(path, &snakecase_path)) {
132       return false;
133     }
134     out->add_paths(snakecase_path);
135   }
136   return true;
137 }
138 
GetFieldDescriptors(const Descriptor * descriptor,StringPiece path,std::vector<const FieldDescriptor * > * field_descriptors)139 bool FieldMaskUtil::GetFieldDescriptors(
140     const Descriptor* descriptor, StringPiece path,
141     std::vector<const FieldDescriptor*>* field_descriptors) {
142   if (field_descriptors != nullptr) {
143     field_descriptors->clear();
144   }
145   std::vector<std::string> parts = Split(path, ".");
146   for (const std::string& field_name : parts) {
147     if (descriptor == nullptr) {
148       return false;
149     }
150     const FieldDescriptor* field = descriptor->FindFieldByName(field_name);
151     if (field == nullptr) {
152       return false;
153     }
154     if (field_descriptors != nullptr) {
155       field_descriptors->push_back(field);
156     }
157     if (!field->is_repeated() &&
158         field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
159       descriptor = field->message_type();
160     } else {
161       descriptor = nullptr;
162     }
163   }
164   return true;
165 }
166 
GetFieldMaskForAllFields(const Descriptor * descriptor,FieldMask * out)167 void FieldMaskUtil::GetFieldMaskForAllFields(const Descriptor* descriptor,
168                                              FieldMask* out) {
169   for (int i = 0; i < descriptor->field_count(); ++i) {
170     out->add_paths(descriptor->field(i)->name());
171   }
172 }
173 
174 namespace {
175 // A FieldMaskTree represents a FieldMask in a tree structure. For example,
176 // given a FieldMask "foo.bar,foo.baz,bar.baz", the FieldMaskTree will be:
177 //
178 //   [root] -+- foo -+- bar
179 //           |       |
180 //           |       +- baz
181 //           |
182 //           +- bar --- baz
183 //
184 // In the tree, each leaf node represents a field path.
185 class FieldMaskTree {
186  public:
187   FieldMaskTree();
188   ~FieldMaskTree();
189 
190   void MergeFromFieldMask(const FieldMask& mask);
191   void MergeToFieldMask(FieldMask* mask);
192 
193   // Add a field path into the tree. In a FieldMask, each field path matches
194   // the specified field and also all its sub-fields. If the field path to
195   // add is a sub-path of an existing field path in the tree (i.e., a leaf
196   // node), it means the tree already matches the given path so nothing will
197   // be added to the tree. If the path matches an existing non-leaf node in the
198   // tree, that non-leaf node will be turned into a leaf node with all its
199   // children removed because the path matches all the node's children.
200   void AddPath(const std::string& path);
201 
202   // Remove a path from the tree.
203   // If the path is a sub-path of an existing field path in the tree, it means
204   // we need remove the existing field path and add all sub-paths except
205   // specified path. If the path matches an existing node in the tree, this node
206   // will be moved.
207   void RemovePath(const std::string& path, const Descriptor* descriptor);
208 
209   // Calculate the intersection part of a field path with this tree and add
210   // the intersection field path into out.
211   void IntersectPath(const std::string& path, FieldMaskTree* out);
212 
213   // Merge all fields specified by this tree from one message to another.
MergeMessage(const Message & source,const FieldMaskUtil::MergeOptions & options,Message * destination)214   void MergeMessage(const Message& source,
215                     const FieldMaskUtil::MergeOptions& options,
216                     Message* destination) {
217     // Do nothing if the tree is empty.
218     if (root_.children.empty()) {
219       return;
220     }
221     MergeMessage(&root_, source, options, destination);
222   }
223 
224   // Add required field path of the message to this tree based on current tree
225   // structure. If a message is present in the tree, add the path of its
226   // required field to the tree. This is to make sure that after trimming a
227   // message with required fields are set, check IsInitialized() will not fail.
AddRequiredFieldPath(const Descriptor * descriptor)228   void AddRequiredFieldPath(const Descriptor* descriptor) {
229     // Do nothing if the tree is empty.
230     if (root_.children.empty()) {
231       return;
232     }
233     AddRequiredFieldPath(&root_, descriptor);
234   }
235 
236   // Trims all fields not specified by this tree from the given message.
237   // Returns true if the message is modified.
TrimMessage(Message * message)238   bool TrimMessage(Message* message) {
239     // Do nothing if the tree is empty.
240     if (root_.children.empty()) {
241       return false;
242     }
243     return TrimMessage(&root_, message);
244   }
245 
246  private:
247   struct Node {
Nodegoogle::protobuf::util::__anon498faa0a0111::FieldMaskTree::Node248     Node() {}
249 
~Nodegoogle::protobuf::util::__anon498faa0a0111::FieldMaskTree::Node250     ~Node() { ClearChildren(); }
251 
ClearChildrengoogle::protobuf::util::__anon498faa0a0111::FieldMaskTree::Node252     void ClearChildren() {
253       for (std::map<std::string, Node*>::iterator it = children.begin();
254            it != children.end(); ++it) {
255         delete it->second;
256       }
257       children.clear();
258     }
259 
260     std::map<std::string, Node*> children;
261 
262    private:
263     GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Node);
264   };
265 
266   // Merge a sub-tree to mask. This method adds the field paths represented
267   // by all leaf nodes descended from "node" to mask.
268   void MergeToFieldMask(const std::string& prefix, const Node* node,
269                         FieldMask* out);
270 
271   // Merge all leaf nodes of a sub-tree to another tree.
272   void MergeLeafNodesToTree(const std::string& prefix, const Node* node,
273                             FieldMaskTree* out);
274 
275   // Merge all fields specified by a sub-tree from one message to another.
276   void MergeMessage(const Node* node, const Message& source,
277                     const FieldMaskUtil::MergeOptions& options,
278                     Message* destination);
279 
280   // Add required field path of the message to this tree based on current tree
281   // structure. If a message is present in the tree, add the path of its
282   // required field to the tree. This is to make sure that after trimming a
283   // message with required fields are set, check IsInitialized() will not fail.
284   void AddRequiredFieldPath(Node* node, const Descriptor* descriptor);
285 
286   // Trims all fields not specified by this sub-tree from the given message.
287   // Returns true if the message is actually modified
288   bool TrimMessage(const Node* node, Message* message);
289 
290   Node root_;
291 
292   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldMaskTree);
293 };
294 
FieldMaskTree()295 FieldMaskTree::FieldMaskTree() {}
296 
~FieldMaskTree()297 FieldMaskTree::~FieldMaskTree() {}
298 
MergeFromFieldMask(const FieldMask & mask)299 void FieldMaskTree::MergeFromFieldMask(const FieldMask& mask) {
300   for (int i = 0; i < mask.paths_size(); ++i) {
301     AddPath(mask.paths(i));
302   }
303 }
304 
MergeToFieldMask(FieldMask * mask)305 void FieldMaskTree::MergeToFieldMask(FieldMask* mask) {
306   MergeToFieldMask("", &root_, mask);
307 }
308 
MergeToFieldMask(const std::string & prefix,const Node * node,FieldMask * out)309 void FieldMaskTree::MergeToFieldMask(const std::string& prefix,
310                                      const Node* node, FieldMask* out) {
311   if (node->children.empty()) {
312     if (prefix.empty()) {
313       // This is the root node.
314       return;
315     }
316     out->add_paths(prefix);
317     return;
318   }
319   for (std::map<std::string, Node*>::const_iterator it = node->children.begin();
320        it != node->children.end(); ++it) {
321     std::string current_path =
322         prefix.empty() ? it->first : prefix + "." + it->first;
323     MergeToFieldMask(current_path, it->second, out);
324   }
325 }
326 
AddPath(const std::string & path)327 void FieldMaskTree::AddPath(const std::string& path) {
328   std::vector<std::string> parts = Split(path, ".");
329   if (parts.empty()) {
330     return;
331   }
332   bool new_branch = false;
333   Node* node = &root_;
334   for (const std::string& node_name : parts) {
335     if (!new_branch && node != &root_ && node->children.empty()) {
336       // Path matches an existing leaf node. This means the path is already
337       // covered by this tree (for example, adding "foo.bar.baz" to a tree
338       // which already contains "foo.bar").
339       return;
340     }
341     Node*& child = node->children[node_name];
342     if (child == nullptr) {
343       new_branch = true;
344       child = new Node();
345     }
346     node = child;
347   }
348   if (!node->children.empty()) {
349     node->ClearChildren();
350   }
351 }
352 
RemovePath(const std::string & path,const Descriptor * descriptor)353 void FieldMaskTree::RemovePath(const std::string& path,
354                                const Descriptor* descriptor) {
355   if (root_.children.empty()) {
356     // Nothing to be removed from an empty tree. We shortcut it here so an empty
357     // tree won't be interpreted as a field mask containing all fields by the
358     // code below.
359     return;
360   }
361   std::vector<std::string> parts = Split(path, ".");
362   if (parts.empty()) {
363     return;
364   }
365   std::vector<Node*> nodes(parts.size());
366   Node* node = &root_;
367   const Descriptor* current_descriptor = descriptor;
368   Node* new_branch_node = nullptr;
369   for (int i = 0; i < parts.size(); ++i) {
370     nodes[i] = node;
371     const FieldDescriptor* field_descriptor =
372         current_descriptor->FindFieldByName(parts[i]);
373     if (field_descriptor == nullptr ||
374         (field_descriptor->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE &&
375          i != parts.size() - 1)) {
376       // Invalid path.
377       if (new_branch_node != nullptr) {
378         // If add any new nodes, cleanup.
379         new_branch_node->ClearChildren();
380       }
381       return;
382     }
383 
384     if (node->children.empty()) {
385       if (new_branch_node == nullptr) {
386         new_branch_node = node;
387       }
388       for (int j = 0; j < current_descriptor->field_count(); ++j) {
389         node->children[current_descriptor->field(j)->name()] = new Node();
390       }
391     }
392     if (ContainsKey(node->children, parts[i])) {
393       node = node->children[parts[i]];
394       if (field_descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
395         current_descriptor = field_descriptor->message_type();
396       }
397     } else {
398       // Path does not exist.
399       return;
400     }
401   }
402   // Remove path.
403   for (int i = parts.size() - 1; i >= 0; i--) {
404     delete nodes[i]->children[parts[i]];
405     nodes[i]->children.erase(parts[i]);
406     if (!nodes[i]->children.empty()) {
407       break;
408     }
409   }
410 }
411 
IntersectPath(const std::string & path,FieldMaskTree * out)412 void FieldMaskTree::IntersectPath(const std::string& path, FieldMaskTree* out) {
413   std::vector<std::string> parts = Split(path, ".");
414   if (parts.empty()) {
415     return;
416   }
417   const Node* node = &root_;
418   for (const std::string& node_name : parts) {
419     if (node->children.empty()) {
420       if (node != &root_) {
421         out->AddPath(path);
422       }
423       return;
424     }
425     const Node* result = FindPtrOrNull(node->children, node_name);
426     if (result == nullptr) {
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 == nullptr) {
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_t 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_t 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, implicitly 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