• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  private:
204   struct Node {
Nodegoogle::protobuf::util::__anonc4f239000111::FieldMaskTree::Node205     Node() {}
206 
~Nodegoogle::protobuf::util::__anonc4f239000111::FieldMaskTree::Node207     ~Node() { ClearChildren(); }
208 
ClearChildrengoogle::protobuf::util::__anonc4f239000111::FieldMaskTree::Node209     void ClearChildren() {
210       for (map<string, Node*>::iterator it = children.begin();
211            it != children.end(); ++it) {
212         delete it->second;
213       }
214       children.clear();
215     }
216 
217     map<string, Node*> children;
218 
219    private:
220     GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Node);
221   };
222 
223   // Merge a sub-tree to mask. This method adds the field paths represented
224   // by all leaf nodes descended from "node" to mask.
225   void MergeToFieldMask(const string& prefix, const Node* node, FieldMask* out);
226 
227   // Merge all leaf nodes of a sub-tree to another tree.
228   void MergeLeafNodesToTree(const string& prefix, const Node* node,
229                             FieldMaskTree* out);
230 
231   // Merge all fields specified by a sub-tree from one message to another.
232   void MergeMessage(const Node* node, const Message& source,
233                     const FieldMaskUtil::MergeOptions& options,
234                     Message* destination);
235 
236   Node root_;
237 
238   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldMaskTree);
239 };
240 
FieldMaskTree()241 FieldMaskTree::FieldMaskTree() {}
242 
~FieldMaskTree()243 FieldMaskTree::~FieldMaskTree() {}
244 
MergeFromFieldMask(const FieldMask & mask)245 void FieldMaskTree::MergeFromFieldMask(const FieldMask& mask) {
246   for (int i = 0; i < mask.paths_size(); ++i) {
247     AddPath(mask.paths(i));
248   }
249 }
250 
MergeToFieldMask(FieldMask * mask)251 void FieldMaskTree::MergeToFieldMask(FieldMask* mask) {
252   MergeToFieldMask("", &root_, mask);
253 }
254 
MergeToFieldMask(const string & prefix,const Node * node,FieldMask * out)255 void FieldMaskTree::MergeToFieldMask(const string& prefix, const Node* node,
256                                      FieldMask* out) {
257   if (node->children.empty()) {
258     if (prefix.empty()) {
259       // This is the root node.
260       return;
261     }
262     out->add_paths(prefix);
263     return;
264   }
265   for (map<string, Node*>::const_iterator it = node->children.begin();
266        it != node->children.end(); ++it) {
267     string current_path = prefix.empty() ? it->first : prefix + "." + it->first;
268     MergeToFieldMask(current_path, it->second, out);
269   }
270 }
271 
AddPath(const string & path)272 void FieldMaskTree::AddPath(const string& path) {
273   vector<string> parts = Split(path, ".");
274   if (parts.empty()) {
275     return;
276   }
277   bool new_branch = false;
278   Node* node = &root_;
279   for (int i = 0; i < parts.size(); ++i) {
280     if (!new_branch && node != &root_ && node->children.empty()) {
281       // Path matches an existing leaf node. This means the path is already
282       // coverred by this tree (for example, adding "foo.bar.baz" to a tree
283       // which already contains "foo.bar").
284       return;
285     }
286     const string& node_name = parts[i];
287     Node*& child = node->children[node_name];
288     if (child == NULL) {
289       new_branch = true;
290       child = new Node();
291     }
292     node = child;
293   }
294   if (!node->children.empty()) {
295     node->ClearChildren();
296   }
297 }
298 
IntersectPath(const string & path,FieldMaskTree * out)299 void FieldMaskTree::IntersectPath(const string& path, FieldMaskTree* out) {
300   vector<string> parts = Split(path, ".");
301   if (parts.empty()) {
302     return;
303   }
304   const Node* node = &root_;
305   for (int i = 0; i < parts.size(); ++i) {
306     if (node->children.empty()) {
307       if (node != &root_) {
308         out->AddPath(path);
309       }
310       return;
311     }
312     const string& node_name = parts[i];
313     const Node* result = FindPtrOrNull(node->children, node_name);
314     if (result == NULL) {
315       // No intersection found.
316       return;
317     }
318     node = result;
319   }
320   // Now we found a matching node with the given path. Add all leaf nodes
321   // to out.
322   MergeLeafNodesToTree(path, node, out);
323 }
324 
MergeLeafNodesToTree(const string & prefix,const Node * node,FieldMaskTree * out)325 void FieldMaskTree::MergeLeafNodesToTree(const string& prefix, const Node* node,
326                                          FieldMaskTree* out) {
327   if (node->children.empty()) {
328     out->AddPath(prefix);
329   }
330   for (map<string, Node*>::const_iterator it = node->children.begin();
331        it != node->children.end(); ++it) {
332     string current_path = prefix.empty() ? it->first : prefix + "." + it->first;
333     MergeLeafNodesToTree(current_path, it->second, out);
334   }
335 }
336 
MergeMessage(const Node * node,const Message & source,const FieldMaskUtil::MergeOptions & options,Message * destination)337 void FieldMaskTree::MergeMessage(const Node* node, const Message& source,
338                                  const FieldMaskUtil::MergeOptions& options,
339                                  Message* destination) {
340   GOOGLE_DCHECK(!node->children.empty());
341   const Reflection* source_reflection = source.GetReflection();
342   const Reflection* destination_reflection = destination->GetReflection();
343   const Descriptor* descriptor = source.GetDescriptor();
344   for (map<string, Node*>::const_iterator it = node->children.begin();
345        it != node->children.end(); ++it) {
346     const string& field_name = it->first;
347     const Node* child = it->second;
348     const FieldDescriptor* field = descriptor->FindFieldByName(field_name);
349     if (field == NULL) {
350       GOOGLE_LOG(ERROR) << "Cannot find field \"" << field_name << "\" in message "
351                  << descriptor->full_name();
352       continue;
353     }
354     if (!child->children.empty()) {
355       // Sub-paths are only allowed for singular message fields.
356       if (field->is_repeated() ||
357           field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
358         GOOGLE_LOG(ERROR) << "Field \"" << field_name << "\" in message "
359                    << descriptor->full_name()
360                    << " is not a singular message field and cannot "
361                    << "have sub-fields.";
362         continue;
363       }
364       MergeMessage(child, source_reflection->GetMessage(source, field), options,
365                    destination_reflection->MutableMessage(destination, field));
366       continue;
367     }
368     if (!field->is_repeated()) {
369       switch (field->cpp_type()) {
370 #define COPY_VALUE(TYPE, Name)                                            \
371   case FieldDescriptor::CPPTYPE_##TYPE: {                                 \
372     destination_reflection->Set##Name(                                    \
373         destination, field, source_reflection->Get##Name(source, field)); \
374     break;                                                                \
375   }
376         COPY_VALUE(BOOL, Bool)
377         COPY_VALUE(INT32, Int32)
378         COPY_VALUE(INT64, Int64)
379         COPY_VALUE(UINT32, UInt32)
380         COPY_VALUE(UINT64, UInt64)
381         COPY_VALUE(FLOAT, Float)
382         COPY_VALUE(DOUBLE, Double)
383         COPY_VALUE(ENUM, Enum)
384         COPY_VALUE(STRING, String)
385 #undef COPY_VALUE
386         case FieldDescriptor::CPPTYPE_MESSAGE: {
387           if (options.replace_message_fields()) {
388             destination_reflection->ClearField(destination, field);
389           }
390           if (source_reflection->HasField(source, field)) {
391             destination_reflection->MutableMessage(destination, field)
392                 ->MergeFrom(source_reflection->GetMessage(source, field));
393           }
394           break;
395         }
396       }
397     } else {
398       if (options.replace_repeated_fields()) {
399         destination_reflection->ClearField(destination, field);
400       }
401       switch (field->cpp_type()) {
402 #define COPY_REPEATED_VALUE(TYPE, Name)                            \
403   case FieldDescriptor::CPPTYPE_##TYPE: {                          \
404     int size = source_reflection->FieldSize(source, field);        \
405     for (int i = 0; i < size; ++i) {                               \
406       destination_reflection->Add##Name(                           \
407           destination, field,                                      \
408           source_reflection->GetRepeated##Name(source, field, i)); \
409     }                                                              \
410     break;                                                         \
411   }
412         COPY_REPEATED_VALUE(BOOL, Bool)
413         COPY_REPEATED_VALUE(INT32, Int32)
414         COPY_REPEATED_VALUE(INT64, Int64)
415         COPY_REPEATED_VALUE(UINT32, UInt32)
416         COPY_REPEATED_VALUE(UINT64, UInt64)
417         COPY_REPEATED_VALUE(FLOAT, Float)
418         COPY_REPEATED_VALUE(DOUBLE, Double)
419         COPY_REPEATED_VALUE(ENUM, Enum)
420         COPY_REPEATED_VALUE(STRING, String)
421 #undef COPY_REPEATED_VALUE
422         case FieldDescriptor::CPPTYPE_MESSAGE: {
423           int size = source_reflection->FieldSize(source, field);
424           for (int i = 0; i < size; ++i) {
425             destination_reflection->AddMessage(destination, field)
426                 ->MergeFrom(
427                     source_reflection->GetRepeatedMessage(source, field, i));
428           }
429           break;
430         }
431       }
432     }
433   }
434 }
435 
436 }  // namespace
437 
ToCanonicalForm(const FieldMask & mask,FieldMask * out)438 void FieldMaskUtil::ToCanonicalForm(const FieldMask& mask, FieldMask* out) {
439   FieldMaskTree tree;
440   tree.MergeFromFieldMask(mask);
441   out->Clear();
442   tree.MergeToFieldMask(out);
443 }
444 
Union(const FieldMask & mask1,const FieldMask & mask2,FieldMask * out)445 void FieldMaskUtil::Union(const FieldMask& mask1, const FieldMask& mask2,
446                           FieldMask* out) {
447   FieldMaskTree tree;
448   tree.MergeFromFieldMask(mask1);
449   tree.MergeFromFieldMask(mask2);
450   out->Clear();
451   tree.MergeToFieldMask(out);
452 }
453 
Intersect(const FieldMask & mask1,const FieldMask & mask2,FieldMask * out)454 void FieldMaskUtil::Intersect(const FieldMask& mask1, const FieldMask& mask2,
455                               FieldMask* out) {
456   FieldMaskTree tree, intersection;
457   tree.MergeFromFieldMask(mask1);
458   for (int i = 0; i < mask2.paths_size(); ++i) {
459     tree.IntersectPath(mask2.paths(i), &intersection);
460   }
461   out->Clear();
462   intersection.MergeToFieldMask(out);
463 }
464 
IsPathInFieldMask(StringPiece path,const FieldMask & mask)465 bool FieldMaskUtil::IsPathInFieldMask(StringPiece path, const FieldMask& mask) {
466   for (int i = 0; i < mask.paths_size(); ++i) {
467     const string& mask_path = mask.paths(i);
468     if (path == mask_path) {
469       return true;
470     } else if (mask_path.length() < path.length()) {
471       // Also check whether mask.paths(i) is a prefix of path.
472       if (path.substr(0, mask_path.length() + 1).compare(mask_path + ".") ==
473           0) {
474         return true;
475       }
476     }
477   }
478   return false;
479 }
480 
MergeMessageTo(const Message & source,const FieldMask & mask,const MergeOptions & options,Message * destination)481 void FieldMaskUtil::MergeMessageTo(const Message& source, const FieldMask& mask,
482                                    const MergeOptions& options,
483                                    Message* destination) {
484   GOOGLE_CHECK(source.GetDescriptor() == destination->GetDescriptor());
485   // Build a FieldMaskTree and walk through the tree to merge all specified
486   // fields.
487   FieldMaskTree tree;
488   tree.MergeFromFieldMask(mask);
489   tree.MergeMessage(source, options, destination);
490 }
491 
492 }  // namespace util
493 }  // namespace protobuf
494 }  // namespace google
495