123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113 |
- /*
- * Copyright 2011-present Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- #include <folly/json_pointer.h>
- #include <folly/String.h>
- namespace folly {
- // static, public
- Expected<json_pointer, json_pointer::parse_error> json_pointer::try_parse(
- StringPiece const str) {
- // pointer describes complete document
- if (str.empty()) {
- return json_pointer{};
- }
- if (str.at(0) != '/') {
- return makeUnexpected(parse_error::invalid_first_character);
- }
- std::vector<std::string> tokens;
- splitTo<std::string>("/", str, std::inserter(tokens, tokens.begin()));
- tokens.erase(tokens.begin());
- for (auto& token : tokens) {
- if (!unescape(token)) {
- return makeUnexpected(parse_error::invalid_escape_sequence);
- }
- }
- return json_pointer(std::move(tokens));
- }
- // static, public
- json_pointer json_pointer::parse(StringPiece const str) {
- auto res = try_parse(str);
- if (res.hasValue()) {
- return std::move(res.value());
- }
- switch (res.error()) {
- case parse_error::invalid_first_character:
- throw json_pointer::parse_exception(
- "non-empty JSON pointer string does not start with '/'");
- case parse_error::invalid_escape_sequence:
- throw json_pointer::parse_exception(
- "Invalid escape sequence in JSON pointer string");
- default:
- assume_unreachable();
- }
- }
- bool json_pointer::is_prefix_of(json_pointer const& other) const noexcept {
- auto const& other_tokens = other.tokens();
- if (tokens_.size() > other_tokens.size()) {
- return false;
- }
- auto const other_begin = other_tokens.cbegin();
- auto const other_end = other_tokens.cbegin() + tokens_.size();
- return std::equal(tokens_.cbegin(), tokens_.cend(), other_begin, other_end);
- }
- std::vector<std::string> const& json_pointer::tokens() const {
- return tokens_;
- }
- // private
- json_pointer::json_pointer(std::vector<std::string> tokens) noexcept
- : tokens_{std::move(tokens)} {}
- // private, static
- bool json_pointer::unescape(std::string& str) {
- char const* end = &str[str.size()];
- char* out = &str.front();
- char const* decode = out;
- while (decode < end) {
- if (*decode != '~') {
- *out++ = *decode++;
- continue;
- }
- if (decode + 1 == end) {
- return false;
- }
- switch (decode[1]) {
- case '1':
- *out++ = '/';
- break;
- case '0':
- *out++ = '~';
- break;
- default:
- return false;
- }
- decode += 2;
- }
- str.resize(out - &str.front());
- return true;
- }
- } // namespace folly
|