| Index: third_party/protobuf/src/google/protobuf/util/field_mask_util.cc
|
| diff --git a/third_party/protobuf/src/google/protobuf/util/field_mask_util.cc b/third_party/protobuf/src/google/protobuf/util/field_mask_util.cc
|
| index 29ca9c1e993c05e0b5fc137862dad2337f9e13d2..547c9fb528469d76fb2dd3db79e3e7499e1df043 100644
|
| --- a/third_party/protobuf/src/google/protobuf/util/field_mask_util.cc
|
| +++ b/third_party/protobuf/src/google/protobuf/util/field_mask_util.cc
|
| @@ -52,6 +52,82 @@ void FieldMaskUtil::FromString(StringPiece str, FieldMask* out) {
|
| }
|
| }
|
|
|
| +bool FieldMaskUtil::SnakeCaseToCamelCase(StringPiece input, string* output) {
|
| + output->clear();
|
| + bool after_underscore = false;
|
| + for (int i = 0; i < input.size(); ++i) {
|
| + if (input[i] >= 'A' && input[i] <= 'Z') {
|
| + // The field name must not contain uppercase letters.
|
| + return false;
|
| + }
|
| + if (after_underscore) {
|
| + if (input[i] >= 'a' && input[i] <= 'z') {
|
| + output->push_back(input[i] + 'A' - 'a');
|
| + after_underscore = false;
|
| + } else {
|
| + // The character after a "_" must be a lowercase letter.
|
| + return false;
|
| + }
|
| + } else if (input[i] == '_') {
|
| + after_underscore = true;
|
| + } else {
|
| + output->push_back(input[i]);
|
| + }
|
| + }
|
| + if (after_underscore) {
|
| + // Trailing "_".
|
| + return false;
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +bool FieldMaskUtil::CamelCaseToSnakeCase(StringPiece input, string* output) {
|
| + output->clear();
|
| + for (int i = 0; i < input.size(); ++i) {
|
| + if (input[i] == '_') {
|
| + // The field name must not contain "_"s.
|
| + return false;
|
| + }
|
| + if (input[i] >= 'A' && input[i] <= 'Z') {
|
| + output->push_back('_');
|
| + output->push_back(input[i] + 'a' - 'A');
|
| + } else {
|
| + output->push_back(input[i]);
|
| + }
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +bool FieldMaskUtil::ToJsonString(const FieldMask& mask, string* out) {
|
| + out->clear();
|
| + for (int i = 0; i < mask.paths_size(); ++i) {
|
| + const string& path = mask.paths(i);
|
| + string camelcase_path;
|
| + if (!SnakeCaseToCamelCase(path, &camelcase_path)) {
|
| + return false;
|
| + }
|
| + if (i > 0) {
|
| + out->push_back(',');
|
| + }
|
| + out->append(camelcase_path);
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +bool FieldMaskUtil::FromJsonString(StringPiece str, FieldMask* out) {
|
| + out->Clear();
|
| + vector<string> paths = Split(str, ",");
|
| + for (int i = 0; i < paths.size(); ++i) {
|
| + if (paths[i].empty()) continue;
|
| + string snakecase_path;
|
| + if (!CamelCaseToSnakeCase(paths[i], &snakecase_path)) {
|
| + return false;
|
| + }
|
| + out->add_paths(snakecase_path);
|
| + }
|
| + return true;
|
| +}
|
| +
|
| bool FieldMaskUtil::InternalIsValidPath(const Descriptor* descriptor,
|
| StringPiece path) {
|
| vector<string> parts = Split(path, ".");
|
| @@ -103,7 +179,7 @@ class FieldMaskTree {
|
| // Add a field path into the tree. In a FieldMask, each field path matches
|
| // the specified field and also all its sub-fields. If the field path to
|
| // add is a sub-path of an existing field path in the tree (i.e., a leaf
|
| - // node), it means the tree already matchesthe the given path so nothing will
|
| + // node), it means the tree already matches the given path so nothing will
|
| // be added to the tree. If the path matches an existing non-leaf node in the
|
| // tree, that non-leaf node will be turned into a leaf node with all its
|
| // children removed because the path matches all the node's children.
|
|
|