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 #include <google/protobuf/stubs/map_util.h>
35
36 namespace google {
37 namespace protobuf {
38 namespace util {
39
40 using google::protobuf::FieldMask;
41
ToString(const FieldMask & mask)42 string FieldMaskUtil::ToString(const FieldMask& mask) {
43 return Join(mask.paths(), ",");
44 }
45
FromString(StringPiece str,FieldMask * out)46 void FieldMaskUtil::FromString(StringPiece str, FieldMask* out) {
47 out->Clear();
48 vector<string> paths = Split(str, ",");
49 for (int i = 0; i < paths.size(); ++i) {
50 if (paths[i].empty()) continue;
51 out->add_paths(paths[i]);
52 }
53 }
54
SnakeCaseToCamelCase(StringPiece input,string * output)55 bool FieldMaskUtil::SnakeCaseToCamelCase(StringPiece input, string* output) {
56 output->clear();
57 bool after_underscore = false;
58 for (int i = 0; i < input.size(); ++i) {
59 if (input[i] >= 'A' && input[i] <= 'Z') {
60 // The field name must not contain uppercase letters.
61 return false;
62 }
63 if (after_underscore) {
64 if (input[i] >= 'a' && input[i] <= 'z') {
65 output->push_back(input[i] + 'A' - 'a');
66 after_underscore = false;
67 } else {
68 // The character after a "_" must be a lowercase letter.
69 return false;
70 }
71 } else if (input[i] == '_') {
72 after_underscore = true;
73 } else {
74 output->push_back(input[i]);
75 }
76 }
77 if (after_underscore) {
78 // Trailing "_".
79 return false;
80 }
81 return true;
82 }
83
CamelCaseToSnakeCase(StringPiece input,string * output)84 bool FieldMaskUtil::CamelCaseToSnakeCase(StringPiece input, string* output) {
85 output->clear();
86 for (int i = 0; i < input.size(); ++i) {
87 if (input[i] == '_') {
88 // The field name must not contain "_"s.
89 return false;
90 }
91 if (input[i] >= 'A' && input[i] <= 'Z') {
92 output->push_back('_');
93 output->push_back(input[i] + 'a' - 'A');
94 } else {
95 output->push_back(input[i]);
96 }
97 }
98 return true;
99 }
100
ToJsonString(const FieldMask & mask,string * out)101 bool FieldMaskUtil::ToJsonString(const FieldMask& mask, string* out) {
102 out->clear();
103 for (int i = 0; i < mask.paths_size(); ++i) {
104 const string& path = mask.paths(i);
105 string camelcase_path;
106 if (!SnakeCaseToCamelCase(path, &camelcase_path)) {
107 return false;
108 }
109 if (i > 0) {
110 out->push_back(',');
111 }
112 out->append(camelcase_path);
113 }
114 return true;
115 }
116
FromJsonString(StringPiece str,FieldMask * out)117 bool FieldMaskUtil::FromJsonString(StringPiece str, FieldMask* out) {
118 out->Clear();
119 vector<string> paths = Split(str, ",");
120 for (int i = 0; i < paths.size(); ++i) {
121 if (paths[i].empty()) continue;
122 string snakecase_path;
123 if (!CamelCaseToSnakeCase(paths[i], &snakecase_path)) {
124 return false;
125 }
126 out->add_paths(snakecase_path);
127 }
128 return true;
129 }
130
InternalIsValidPath(const Descriptor * descriptor,StringPiece path)131 bool FieldMaskUtil::InternalIsValidPath(const Descriptor* descriptor,
132 StringPiece path) {
133 vector<string> parts = Split(path, ".");
134 for (int i = 0; i < parts.size(); ++i) {
135 const string& field_name = parts[i];
136 if (descriptor == NULL) {
137 return false;
138 }
139 const FieldDescriptor* field = descriptor->FindFieldByName(field_name);
140 if (field == NULL) {
141 return false;
142 }
143 if (!field->is_repeated() &&
144 field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
145 descriptor = field->message_type();
146 } else {
147 descriptor = NULL;
148 }
149 }
150 return true;
151 }
152
InternalGetFieldMaskForAllFields(const Descriptor * descriptor,FieldMask * out)153 void FieldMaskUtil::InternalGetFieldMaskForAllFields(
154 const Descriptor* descriptor, FieldMask* out) {
155 for (int i = 0; i < descriptor->field_count(); ++i) {
156 out->add_paths(descriptor->field(i)->name());
157 }
158 }
159
160 namespace {
161 // A FieldMaskTree represents a FieldMask in a tree structure. For example,
162 // given a FieldMask "foo.bar,foo.baz,bar.baz", the FieldMaskTree will be:
163 //
164 // [root] -+- foo -+- bar
165 // | |
166 // | +- baz
167 // |
168 // +- bar --- baz
169 //
170 // In the tree, each leaf node represents a field path.
171 class FieldMaskTree {
172 public:
173 FieldMaskTree();
174 ~FieldMaskTree();
175
176 void MergeFromFieldMask(const FieldMask& mask);
177 void MergeToFieldMask(FieldMask* mask);
178
179 // Add a field path into the tree. In a FieldMask, each field path matches
180 // the specified field and also all its sub-fields. If the field path to
181 // add is a sub-path of an existing field path in the tree (i.e., a leaf
182 // node), it means the tree already matches the given path so nothing will
183 // be added to the tree. If the path matches an existing non-leaf node in the
184 // tree, that non-leaf node will be turned into a leaf node with all its
185 // children removed because the path matches all the node's children.
186 void AddPath(const string& path);
187
188 // Calculate the intersection part of a field path with this tree and add
189 // the intersection field path into out.
190 void IntersectPath(const string& path, FieldMaskTree* out);
191
192 // Merge all fields specified by this tree from one message to another.
MergeMessage(const Message & source,const FieldMaskUtil::MergeOptions & options,Message * destination)193 void MergeMessage(const Message& source,
194 const FieldMaskUtil::MergeOptions& options,
195 Message* destination) {
196 // Do nothing if the tree is empty.
197 if (root_.children.empty()) {
198 return;
199 }
200 MergeMessage(&root_, source, options, destination);
201 }
202
203 // Trims all fields not specified by this tree from the given message.
TrimMessage(Message * message)204 void TrimMessage(Message* message) {
205 // Do nothing if the tree is empty.
206 if (root_.children.empty()) {
207 return;
208 }
209 TrimMessage(&root_, message);
210 }
211
212 private:
213 struct Node {
Nodegoogle::protobuf::util::__anon405789c10111::FieldMaskTree::Node214 Node() {}
215
~Nodegoogle::protobuf::util::__anon405789c10111::FieldMaskTree::Node216 ~Node() { ClearChildren(); }
217
ClearChildrengoogle::protobuf::util::__anon405789c10111::FieldMaskTree::Node218 void ClearChildren() {
219 for (map<string, Node*>::iterator it = children.begin();
220 it != children.end(); ++it) {
221 delete it->second;
222 }
223 children.clear();
224 }
225
226 map<string, Node*> children;
227
228 private:
229 GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Node);
230 };
231
232 // Merge a sub-tree to mask. This method adds the field paths represented
233 // by all leaf nodes descended from "node" to mask.
234 void MergeToFieldMask(const string& prefix, const Node* node, FieldMask* out);
235
236 // Merge all leaf nodes of a sub-tree to another tree.
237 void MergeLeafNodesToTree(const string& prefix, const Node* node,
238 FieldMaskTree* out);
239
240 // Merge all fields specified by a sub-tree from one message to another.
241 void MergeMessage(const Node* node, const Message& source,
242 const FieldMaskUtil::MergeOptions& options,
243 Message* destination);
244
245 // Trims all fields not specified by this sub-tree from the given message.
246 void TrimMessage(const Node* node, Message* message);
247
248 Node root_;
249
250 GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldMaskTree);
251 };
252
FieldMaskTree()253 FieldMaskTree::FieldMaskTree() {}
254
~FieldMaskTree()255 FieldMaskTree::~FieldMaskTree() {}
256
MergeFromFieldMask(const FieldMask & mask)257 void FieldMaskTree::MergeFromFieldMask(const FieldMask& mask) {
258 for (int i = 0; i < mask.paths_size(); ++i) {
259 AddPath(mask.paths(i));
260 }
261 }
262
MergeToFieldMask(FieldMask * mask)263 void FieldMaskTree::MergeToFieldMask(FieldMask* mask) {
264 MergeToFieldMask("", &root_, mask);
265 }
266
MergeToFieldMask(const string & prefix,const Node * node,FieldMask * out)267 void FieldMaskTree::MergeToFieldMask(const string& prefix, const Node* node,
268 FieldMask* out) {
269 if (node->children.empty()) {
270 if (prefix.empty()) {
271 // This is the root node.
272 return;
273 }
274 out->add_paths(prefix);
275 return;
276 }
277 for (map<string, Node*>::const_iterator it = node->children.begin();
278 it != node->children.end(); ++it) {
279 string current_path = prefix.empty() ? it->first : prefix + "." + it->first;
280 MergeToFieldMask(current_path, it->second, out);
281 }
282 }
283
AddPath(const string & path)284 void FieldMaskTree::AddPath(const string& path) {
285 vector<string> parts = Split(path, ".");
286 if (parts.empty()) {
287 return;
288 }
289 bool new_branch = false;
290 Node* node = &root_;
291 for (int i = 0; i < parts.size(); ++i) {
292 if (!new_branch && node != &root_ && node->children.empty()) {
293 // Path matches an existing leaf node. This means the path is already
294 // coverred by this tree (for example, adding "foo.bar.baz" to a tree
295 // which already contains "foo.bar").
296 return;
297 }
298 const string& node_name = parts[i];
299 Node*& child = node->children[node_name];
300 if (child == NULL) {
301 new_branch = true;
302 child = new Node();
303 }
304 node = child;
305 }
306 if (!node->children.empty()) {
307 node->ClearChildren();
308 }
309 }
310
IntersectPath(const string & path,FieldMaskTree * out)311 void FieldMaskTree::IntersectPath(const string& path, FieldMaskTree* out) {
312 vector<string> parts = Split(path, ".");
313 if (parts.empty()) {
314 return;
315 }
316 const Node* node = &root_;
317 for (int i = 0; i < parts.size(); ++i) {
318 if (node->children.empty()) {
319 if (node != &root_) {
320 out->AddPath(path);
321 }
322 return;
323 }
324 const string& node_name = parts[i];
325 const Node* result = FindPtrOrNull(node->children, node_name);
326 if (result == NULL) {
327 // No intersection found.
328 return;
329 }
330 node = result;
331 }
332 // Now we found a matching node with the given path. Add all leaf nodes
333 // to out.
334 MergeLeafNodesToTree(path, node, out);
335 }
336
MergeLeafNodesToTree(const string & prefix,const Node * node,FieldMaskTree * out)337 void FieldMaskTree::MergeLeafNodesToTree(const string& prefix, const Node* node,
338 FieldMaskTree* out) {
339 if (node->children.empty()) {
340 out->AddPath(prefix);
341 }
342 for (map<string, Node*>::const_iterator it = node->children.begin();
343 it != node->children.end(); ++it) {
344 string current_path = prefix.empty() ? it->first : prefix + "." + it->first;
345 MergeLeafNodesToTree(current_path, it->second, out);
346 }
347 }
348
MergeMessage(const Node * node,const Message & source,const FieldMaskUtil::MergeOptions & options,Message * destination)349 void FieldMaskTree::MergeMessage(const Node* node, const Message& source,
350 const FieldMaskUtil::MergeOptions& options,
351 Message* destination) {
352 GOOGLE_DCHECK(!node->children.empty());
353 const Reflection* source_reflection = source.GetReflection();
354 const Reflection* destination_reflection = destination->GetReflection();
355 const Descriptor* descriptor = source.GetDescriptor();
356 for (map<string, Node*>::const_iterator it = node->children.begin();
357 it != node->children.end(); ++it) {
358 const string& field_name = it->first;
359 const Node* child = it->second;
360 const FieldDescriptor* field = descriptor->FindFieldByName(field_name);
361 if (field == NULL) {
362 GOOGLE_LOG(ERROR) << "Cannot find field \"" << field_name << "\" in message "
363 << descriptor->full_name();
364 continue;
365 }
366 if (!child->children.empty()) {
367 // Sub-paths are only allowed for singular message fields.
368 if (field->is_repeated() ||
369 field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
370 GOOGLE_LOG(ERROR) << "Field \"" << field_name << "\" in message "
371 << descriptor->full_name()
372 << " is not a singular message field and cannot "
373 << "have sub-fields.";
374 continue;
375 }
376 MergeMessage(child, source_reflection->GetMessage(source, field), options,
377 destination_reflection->MutableMessage(destination, field));
378 continue;
379 }
380 if (!field->is_repeated()) {
381 switch (field->cpp_type()) {
382 #define COPY_VALUE(TYPE, Name) \
383 case FieldDescriptor::CPPTYPE_##TYPE: { \
384 if (source_reflection->HasField(source, field)) { \
385 destination_reflection->Set##Name( \
386 destination, field, source_reflection->Get##Name(source, field)); \
387 } else { \
388 destination_reflection->ClearField(destination, field); \
389 } \
390 break; \
391 }
392 COPY_VALUE(BOOL, Bool)
393 COPY_VALUE(INT32, Int32)
394 COPY_VALUE(INT64, Int64)
395 COPY_VALUE(UINT32, UInt32)
396 COPY_VALUE(UINT64, UInt64)
397 COPY_VALUE(FLOAT, Float)
398 COPY_VALUE(DOUBLE, Double)
399 COPY_VALUE(ENUM, Enum)
400 COPY_VALUE(STRING, String)
401 #undef COPY_VALUE
402 case FieldDescriptor::CPPTYPE_MESSAGE: {
403 if (options.replace_message_fields()) {
404 destination_reflection->ClearField(destination, field);
405 }
406 if (source_reflection->HasField(source, field)) {
407 destination_reflection->MutableMessage(destination, field)
408 ->MergeFrom(source_reflection->GetMessage(source, field));
409 }
410 break;
411 }
412 }
413 } else {
414 if (options.replace_repeated_fields()) {
415 destination_reflection->ClearField(destination, field);
416 }
417 switch (field->cpp_type()) {
418 #define COPY_REPEATED_VALUE(TYPE, Name) \
419 case FieldDescriptor::CPPTYPE_##TYPE: { \
420 int size = source_reflection->FieldSize(source, field); \
421 for (int i = 0; i < size; ++i) { \
422 destination_reflection->Add##Name( \
423 destination, field, \
424 source_reflection->GetRepeated##Name(source, field, i)); \
425 } \
426 break; \
427 }
428 COPY_REPEATED_VALUE(BOOL, Bool)
429 COPY_REPEATED_VALUE(INT32, Int32)
430 COPY_REPEATED_VALUE(INT64, Int64)
431 COPY_REPEATED_VALUE(UINT32, UInt32)
432 COPY_REPEATED_VALUE(UINT64, UInt64)
433 COPY_REPEATED_VALUE(FLOAT, Float)
434 COPY_REPEATED_VALUE(DOUBLE, Double)
435 COPY_REPEATED_VALUE(ENUM, Enum)
436 COPY_REPEATED_VALUE(STRING, String)
437 #undef COPY_REPEATED_VALUE
438 case FieldDescriptor::CPPTYPE_MESSAGE: {
439 int size = source_reflection->FieldSize(source, field);
440 for (int i = 0; i < size; ++i) {
441 destination_reflection->AddMessage(destination, field)
442 ->MergeFrom(
443 source_reflection->GetRepeatedMessage(source, field, i));
444 }
445 break;
446 }
447 }
448 }
449 }
450 }
451
TrimMessage(const Node * node,Message * message)452 void FieldMaskTree::TrimMessage(const Node* node, Message* message) {
453 GOOGLE_DCHECK(!node->children.empty());
454 const Reflection* reflection = message->GetReflection();
455 const Descriptor* descriptor = message->GetDescriptor();
456 const int32 field_count = descriptor->field_count();
457 for (int index = 0; index < field_count; ++index) {
458 const FieldDescriptor* field = descriptor->field(index);
459 if (!ContainsKey(node->children, field->name())) {
460 reflection->ClearField(message, field);
461 } else {
462 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
463 Node* child = node->children.at(field->name());
464 if (!child->children.empty()) {
465 TrimMessage(child, reflection->MutableMessage(message, field));
466 }
467 }
468 }
469 }
470 }
471
472 } // namespace
473
ToCanonicalForm(const FieldMask & mask,FieldMask * out)474 void FieldMaskUtil::ToCanonicalForm(const FieldMask& mask, FieldMask* out) {
475 FieldMaskTree tree;
476 tree.MergeFromFieldMask(mask);
477 out->Clear();
478 tree.MergeToFieldMask(out);
479 }
480
Union(const FieldMask & mask1,const FieldMask & mask2,FieldMask * out)481 void FieldMaskUtil::Union(const FieldMask& mask1, const FieldMask& mask2,
482 FieldMask* out) {
483 FieldMaskTree tree;
484 tree.MergeFromFieldMask(mask1);
485 tree.MergeFromFieldMask(mask2);
486 out->Clear();
487 tree.MergeToFieldMask(out);
488 }
489
Intersect(const FieldMask & mask1,const FieldMask & mask2,FieldMask * out)490 void FieldMaskUtil::Intersect(const FieldMask& mask1, const FieldMask& mask2,
491 FieldMask* out) {
492 FieldMaskTree tree, intersection;
493 tree.MergeFromFieldMask(mask1);
494 for (int i = 0; i < mask2.paths_size(); ++i) {
495 tree.IntersectPath(mask2.paths(i), &intersection);
496 }
497 out->Clear();
498 intersection.MergeToFieldMask(out);
499 }
500
IsPathInFieldMask(StringPiece path,const FieldMask & mask)501 bool FieldMaskUtil::IsPathInFieldMask(StringPiece path, const FieldMask& mask) {
502 for (int i = 0; i < mask.paths_size(); ++i) {
503 const string& mask_path = mask.paths(i);
504 if (path == mask_path) {
505 return true;
506 } else if (mask_path.length() < path.length()) {
507 // Also check whether mask.paths(i) is a prefix of path.
508 if (path.substr(0, mask_path.length() + 1).compare(mask_path + ".") ==
509 0) {
510 return true;
511 }
512 }
513 }
514 return false;
515 }
516
MergeMessageTo(const Message & source,const FieldMask & mask,const MergeOptions & options,Message * destination)517 void FieldMaskUtil::MergeMessageTo(const Message& source, const FieldMask& mask,
518 const MergeOptions& options,
519 Message* destination) {
520 GOOGLE_CHECK(source.GetDescriptor() == destination->GetDescriptor());
521 // Build a FieldMaskTree and walk through the tree to merge all specified
522 // fields.
523 FieldMaskTree tree;
524 tree.MergeFromFieldMask(mask);
525 tree.MergeMessage(source, options, destination);
526 }
527
TrimMessage(const FieldMask & mask,Message * destination)528 void FieldMaskUtil::TrimMessage(const FieldMask& mask, Message* destination) {
529 // Build a FieldMaskTree and walk through the tree to merge all specified
530 // fields.
531 FieldMaskTree tree;
532 tree.MergeFromFieldMask(mask);
533 tree.TrimMessage(GOOGLE_CHECK_NOTNULL(destination));
534 }
535
536 } // namespace util
537 } // namespace protobuf
538 } // namespace google
539