Index: third_party/protobuf/src/google/protobuf/util/internal/field_mask_utility.cc |
diff --git a/third_party/protobuf/src/google/protobuf/util/internal/field_mask_utility.cc b/third_party/protobuf/src/google/protobuf/util/internal/field_mask_utility.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..f0e8fc88a4f99f872cc9d2fab6f2013e3abf584e |
--- /dev/null |
+++ b/third_party/protobuf/src/google/protobuf/util/internal/field_mask_utility.cc |
@@ -0,0 +1,225 @@ |
+// Protocol Buffers - Google's data interchange format |
+// Copyright 2008 Google Inc. All rights reserved. |
+// https://developers.google.com/protocol-buffers/ |
+// |
+// Redistribution and use in source and binary forms, with or without |
+// modification, are permitted provided that the following conditions are |
+// met: |
+// |
+// * Redistributions of source code must retain the above copyright |
+// notice, this list of conditions and the following disclaimer. |
+// * Redistributions in binary form must reproduce the above |
+// copyright notice, this list of conditions and the following disclaimer |
+// in the documentation and/or other materials provided with the |
+// distribution. |
+// * Neither the name of Google Inc. nor the names of its |
+// contributors may be used to endorse or promote products derived from |
+// this software without specific prior written permission. |
+// |
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
+ |
+#include <google/protobuf/util/internal/field_mask_utility.h> |
+ |
+#include <google/protobuf/stubs/strutil.h> |
+#include <google/protobuf/stubs/status_macros.h> |
+ |
+namespace google { |
+namespace protobuf { |
+namespace util { |
+namespace converter { |
+ |
+namespace { |
+inline util::Status CallPathSink(PathSinkCallback path_sink, |
+ StringPiece arg) { |
+ return path_sink->Run(arg); |
+} |
+ |
+util::Status CreatePublicError(util::error::Code code, |
+ const string& message) { |
+ return util::Status(code, message); |
+} |
+ |
+// Appends a FieldMask path segment to a prefix. |
+string AppendPathSegmentToPrefix(StringPiece prefix, StringPiece segment) { |
+ if (prefix.empty()) { |
+ return segment.ToString(); |
+ } |
+ if (segment.empty()) { |
+ return prefix.ToString(); |
+ } |
+ // If the segment is a map key, appends it to the prefix without the ".". |
+ if (segment.starts_with("[\"")) { |
+ return StrCat(prefix, segment); |
+ } |
+ return StrCat(prefix, ".", segment); |
+} |
+ |
+} // namespace |
+ |
+string ConvertFieldMaskPath(const StringPiece path, |
+ ConverterCallback converter) { |
+ string result; |
+ result.reserve(path.size() << 1); |
+ |
+ bool is_quoted = false; |
+ bool is_escaping = false; |
+ int current_segment_start = 0; |
+ |
+ // Loops until 1 passed the end of the input to make handling the last |
+ // segment easier. |
+ for (size_t i = 0; i <= path.size(); ++i) { |
+ // Outputs quoted string as-is. |
+ if (is_quoted) { |
+ if (i == path.size()) { |
+ break; |
+ } |
+ result.push_back(path[i]); |
+ if (is_escaping) { |
+ is_escaping = false; |
+ } else if (path[i] == '\\') { |
+ is_escaping = true; |
+ } else if (path[i] == '\"') { |
+ current_segment_start = i + 1; |
+ is_quoted = false; |
+ } |
+ continue; |
+ } |
+ if (i == path.size() || path[i] == '.' || path[i] == '(' || |
+ path[i] == ')' || path[i] == '\"') { |
+ result += converter( |
+ path.substr(current_segment_start, i - current_segment_start)); |
+ if (i < path.size()) { |
+ result.push_back(path[i]); |
+ } |
+ current_segment_start = i + 1; |
+ } |
+ if (i < path.size() && path[i] == '\"') { |
+ is_quoted = true; |
+ } |
+ } |
+ return result; |
+} |
+ |
+util::Status DecodeCompactFieldMaskPaths(StringPiece paths, |
+ PathSinkCallback path_sink) { |
+ stack<string> prefix; |
+ int length = paths.length(); |
+ int previous_position = 0; |
+ bool in_map_key = false; |
+ bool is_escaping = false; |
+ // Loops until 1 passed the end of the input to make the handle of the last |
+ // segment easier. |
+ for (int i = 0; i <= length; ++i) { |
+ if (i != length) { |
+ // Skips everything in a map key until we hit the end of it, which is |
+ // marked by an un-escaped '"' immediately followed by a ']'. |
+ if (in_map_key) { |
+ if (is_escaping) { |
+ is_escaping = false; |
+ continue; |
+ } |
+ if (paths[i] == '\\') { |
+ is_escaping = true; |
+ continue; |
+ } |
+ if (paths[i] != '\"') { |
+ continue; |
+ } |
+ // Un-escaped '"' must be followed with a ']'. |
+ if (i >= length - 1 || paths[i + 1] != ']') { |
+ return util::Status( |
+ util::error::INVALID_ARGUMENT, |
+ StrCat("Invalid FieldMask '", paths, |
+ "'. Map keys should be represented as [\"some_key\"].")); |
+ } |
+ // The end of the map key ("\"]") has been found. |
+ in_map_key = false; |
+ // Skips ']'. |
+ i++; |
+ // Checks whether the key ends at the end of a path segment. |
+ if (i < length - 1 && paths[i + 1] != '.' && paths[i + 1] != ',' && |
+ paths[i + 1] != ')' && paths[i + 1] != '(') { |
+ return util::Status( |
+ util::error::INVALID_ARGUMENT, |
+ StrCat("Invalid FieldMask '", paths, |
+ "'. Map keys should be at the end of a path segment.")); |
+ } |
+ is_escaping = false; |
+ continue; |
+ } |
+ |
+ // We are not in a map key, look for the start of one. |
+ if (paths[i] == '[') { |
+ if (i >= length - 1 || paths[i + 1] != '\"') { |
+ return util::Status( |
+ util::error::INVALID_ARGUMENT, |
+ StrCat("Invalid FieldMask '", paths, |
+ "'. Map keys should be represented as [\"some_key\"].")); |
+ } |
+ // "[\"" starts a map key. |
+ in_map_key = true; |
+ i++; // Skips the '\"'. |
+ continue; |
+ } |
+ // If the current character is not a special character (',', '(' or ')'), |
+ // continue to the next. |
+ if (paths[i] != ',' && paths[i] != ')' && paths[i] != '(') { |
+ continue; |
+ } |
+ } |
+ // Gets the current segment - sub-string between previous position (after |
+ // '(', ')', ',', or the beginning of the input) and the current position. |
+ StringPiece segment = |
+ paths.substr(previous_position, i - previous_position); |
+ string current_prefix = prefix.empty() ? "" : prefix.top(); |
+ |
+ if (i < length && paths[i] == '(') { |
+ // Builds a prefix and save it into the stack. |
+ prefix.push(AppendPathSegmentToPrefix(current_prefix, segment)); |
+ } else if (!segment.empty()) { |
+ // When the current charactor is ')', ',' or the current position has |
+ // passed the end of the input, builds and outputs a new paths by |
+ // concatenating the last prefix with the current segment. |
+ RETURN_IF_ERROR(CallPathSink( |
+ path_sink, AppendPathSegmentToPrefix(current_prefix, segment))); |
+ } |
+ |
+ // Removes the last prefix after seeing a ')'. |
+ if (i < length && paths[i] == ')') { |
+ if (prefix.empty()) { |
+ return util::Status( |
+ util::error::INVALID_ARGUMENT, |
+ StrCat("Invalid FieldMask '", paths, |
+ "'. Cannot find matching '(' for all ')'.")); |
+ } |
+ prefix.pop(); |
+ } |
+ previous_position = i + 1; |
+ } |
+ if (in_map_key) { |
+ return util::Status(util::error::INVALID_ARGUMENT, |
+ StrCat("Invalid FieldMask '", paths, |
+ "'. Cannot find matching ']' for all '['.")); |
+ } |
+ if (!prefix.empty()) { |
+ return util::Status(util::error::INVALID_ARGUMENT, |
+ StrCat("Invalid FieldMask '", paths, |
+ "'. Cannot find matching ')' for all '('.")); |
+ } |
+ return util::Status::OK; |
+} |
+ |
+} // namespace converter |
+} // namespace util |
+} // namespace protobuf |
+} // namespace google |