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 | |
48 | std::string FieldMaskUtil::ToString(const FieldMask& mask) { |
49 | return Join(components: mask.paths(), delim: "," ); |
50 | } |
51 | |
52 | void FieldMaskUtil::FromString(StringPiece str, FieldMask* out) { |
53 | out->Clear(); |
54 | std::vector<std::string> paths = Split(full: str, delim: "," ); |
55 | for (const std::string& path : paths) { |
56 | if (path.empty()) continue; |
57 | out->add_paths(value: path); |
58 | } |
59 | } |
60 | |
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(c: 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(c: input_char); |
82 | } |
83 | } |
84 | if (after_underscore) { |
85 | // Trailing "_". |
86 | return false; |
87 | } |
88 | return true; |
89 | } |
90 | |
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(c: '_'); |
101 | output->push_back(c: c + 'a' - 'A'); |
102 | } else { |
103 | output->push_back(c: c); |
104 | } |
105 | } |
106 | return true; |
107 | } |
108 | |
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(index: i); |
113 | std::string camelcase_path; |
114 | if (!SnakeCaseToCamelCase(input: path, output: &camelcase_path)) { |
115 | return false; |
116 | } |
117 | if (i > 0) { |
118 | out->push_back(c: ','); |
119 | } |
120 | out->append(str: camelcase_path); |
121 | } |
122 | return true; |
123 | } |
124 | |
125 | bool FieldMaskUtil::FromJsonString(StringPiece str, FieldMask* out) { |
126 | out->Clear(); |
127 | std::vector<std::string> paths = Split(full: str, delim: "," ); |
128 | for (const std::string& path : paths) { |
129 | if (path.empty()) continue; |
130 | std::string snakecase_path; |
131 | if (!CamelCaseToSnakeCase(input: path, output: &snakecase_path)) { |
132 | return false; |
133 | } |
134 | out->add_paths(value: snakecase_path); |
135 | } |
136 | return true; |
137 | } |
138 | |
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(full: path, delim: "." ); |
146 | for (const std::string& field_name : parts) { |
147 | if (descriptor == nullptr) { |
148 | return false; |
149 | } |
150 | const FieldDescriptor* field = descriptor->FindFieldByName(name: field_name); |
151 | if (field == nullptr) { |
152 | return false; |
153 | } |
154 | if (field_descriptors != nullptr) { |
155 | field_descriptors->push_back(x: 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 | |
167 | void FieldMaskUtil::GetFieldMaskForAllFields(const Descriptor* descriptor, |
168 | FieldMask* out) { |
169 | for (int i = 0; i < descriptor->field_count(); ++i) { |
170 | out->add_paths(value: descriptor->field(index: 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. |
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(node: &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. |
228 | void AddRequiredFieldPath(const Descriptor* descriptor) { |
229 | // Do nothing if the tree is empty. |
230 | if (root_.children.empty()) { |
231 | return; |
232 | } |
233 | AddRequiredFieldPath(node: &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. |
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(node: &root_, message); |
244 | } |
245 | |
246 | private: |
247 | struct Node { |
248 | Node() {} |
249 | |
250 | ~Node() { ClearChildren(); } |
251 | |
252 | 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 | |
295 | FieldMaskTree::FieldMaskTree() {} |
296 | |
297 | FieldMaskTree::~FieldMaskTree() {} |
298 | |
299 | void FieldMaskTree::MergeFromFieldMask(const FieldMask& mask) { |
300 | for (int i = 0; i < mask.paths_size(); ++i) { |
301 | AddPath(path: mask.paths(index: i)); |
302 | } |
303 | } |
304 | |
305 | void FieldMaskTree::MergeToFieldMask(FieldMask* mask) { |
306 | MergeToFieldMask(prefix: "" , node: &root_, out: mask); |
307 | } |
308 | |
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(value: 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(prefix: current_path, node: it->second, out); |
324 | } |
325 | } |
326 | |
327 | void FieldMaskTree::AddPath(const std::string& path) { |
328 | std::vector<std::string> parts = Split(full: path, delim: "." ); |
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 | |
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(full: path, delim: "." ); |
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(name: 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(index: j)->name()] = new Node(); |
390 | } |
391 | } |
392 | if (ContainsKey(collection: node->children, key: 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(x: parts[i]); |
406 | if (!nodes[i]->children.empty()) { |
407 | break; |
408 | } |
409 | } |
410 | } |
411 | |
412 | void FieldMaskTree::IntersectPath(const std::string& path, FieldMaskTree* out) { |
413 | std::vector<std::string> parts = Split(full: path, delim: "." ); |
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(collection: node->children, key: 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(prefix: path, node, out); |
435 | } |
436 | |
437 | void FieldMaskTree::MergeLeafNodesToTree(const std::string& prefix, |
438 | const Node* node, FieldMaskTree* out) { |
439 | if (node->children.empty()) { |
440 | out->AddPath(path: 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(prefix: current_path, node: it->second, out); |
447 | } |
448 | } |
449 | |
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(name: 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(node: child, source: source_reflection->GetMessage(message: source, field), options, |
478 | destination: destination_reflection->MutableMessage(message: 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(message: destination, field); |
506 | } |
507 | if (source_reflection->HasField(message: source, field)) { |
508 | destination_reflection->MutableMessage(message: destination, field) |
509 | ->MergeFrom(from: source_reflection->GetMessage(message: source, field)); |
510 | } |
511 | break; |
512 | } |
513 | } |
514 | } else { |
515 | if (options.replace_repeated_fields()) { |
516 | destination_reflection->ClearField(message: 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(message: source, field); |
541 | for (int i = 0; i < size; ++i) { |
542 | destination_reflection->AddMessage(message: destination, field) |
543 | ->MergeFrom( |
544 | from: source_reflection->GetRepeatedMessage(message: source, field, index: i)); |
545 | } |
546 | break; |
547 | } |
548 | } |
549 | } |
550 | } |
551 | } |
552 | |
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(node: child, descriptor: 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(x: 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(node: child, descriptor: field->message_type()); |
582 | } |
583 | } |
584 | } |
585 | } |
586 | } |
587 | |
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(x: field->name()); |
598 | if (it == node->children.end()) { |
599 | if (field->is_repeated()) { |
600 | if (reflection->FieldSize(message: *message, field) != 0) { |
601 | modified = true; |
602 | } |
603 | } else { |
604 | if (reflection->HasField(message: *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: *message, field)) { |
613 | bool nestedMessageChanged = |
614 | TrimMessage(node: child, message: reflection->MutableMessage(message, field)); |
615 | modified = nestedMessageChanged || modified; |
616 | } |
617 | } |
618 | } |
619 | } |
620 | return modified; |
621 | } |
622 | |
623 | } // namespace |
624 | |
625 | void FieldMaskUtil::ToCanonicalForm(const FieldMask& mask, FieldMask* out) { |
626 | FieldMaskTree tree; |
627 | tree.MergeFromFieldMask(mask); |
628 | out->Clear(); |
629 | tree.MergeToFieldMask(mask: out); |
630 | } |
631 | |
632 | void FieldMaskUtil::Union(const FieldMask& mask1, const FieldMask& mask2, |
633 | FieldMask* out) { |
634 | FieldMaskTree tree; |
635 | tree.MergeFromFieldMask(mask: mask1); |
636 | tree.MergeFromFieldMask(mask: mask2); |
637 | out->Clear(); |
638 | tree.MergeToFieldMask(mask: out); |
639 | } |
640 | |
641 | void FieldMaskUtil::Intersect(const FieldMask& mask1, const FieldMask& mask2, |
642 | FieldMask* out) { |
643 | FieldMaskTree tree, intersection; |
644 | tree.MergeFromFieldMask(mask: mask1); |
645 | for (int i = 0; i < mask2.paths_size(); ++i) { |
646 | tree.IntersectPath(path: mask2.paths(index: i), out: &intersection); |
647 | } |
648 | out->Clear(); |
649 | intersection.MergeToFieldMask(mask: out); |
650 | } |
651 | |
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(mask: mask1); |
661 | for (int i = 0; i < mask2.paths_size(); ++i) { |
662 | tree.RemovePath(path: mask2.paths(index: i), descriptor); |
663 | } |
664 | out->Clear(); |
665 | tree.MergeToFieldMask(mask: out); |
666 | } |
667 | |
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(index: 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(pos: 0, n: mask_path.length() + 1).compare(x: mask_path + "." ) == |
677 | 0) { |
678 | return true; |
679 | } |
680 | } |
681 | } |
682 | return false; |
683 | } |
684 | |
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 | |
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 | |
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 | |