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