/* * Copyright (c) Facebook, Inc. and its affiliates. * * 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 #include namespace folly { // static, public Expected 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 tokens; splitTo("/", 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 const& json_pointer::tokens() const { return tokens_; } // private json_pointer::json_pointer(std::vector 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