#include "./uri.hpp" #include "./debug/panic.hpp" using cruft::uri; /////////////////////////////////////////////////////////////////////////////// cruft::uri::uri (const char *str): uri (std::string (str)) { ; } //----------------------------------------------------------------------------- uri::uri (cruft::view _value): uri (std::string (_value.begin (), _value.end ())) { ; } //----------------------------------------------------------------------------- uri::uri (const std::string &_value): uri (std::string (_value)) { ; } /////////////////////////////////////////////////////////////////////////////// static uint8_t hex_to_uint (char c) { if (c >= '0' && c <= '9') return c - '0'; if (c >= 'A' && c <= 'F') return c - 'A' + 10; if (c >= 'a' && c <= 'f') return c - 'a' + 10; unreachable (); } //----------------------------------------------------------------------------- std::string cruft::uri::percent_decode (view s) { if (s.size () == 0) return std::string (); // Early check for late percent-encoding so we can simplify the decode loop { auto tail = std::find (s.size () < 3 ? s.begin () : s.end () - 2, s.end (), '%'); if (tail != s.end ()) throw parse_error ("triple overlaps end"); } // Allocate and size a potentially overlong output string. This allows us // to copy directly into its buffer. We'll shorten it at the end. std::string out; out.resize (s.size ()); // Find the percent, copy until that, decode, advance, repeat. auto out_cursor = out.begin (); for (auto i = s.begin (); i < s.end (); ++i) { auto cursor = std::find (i, s.end (), '%'); if (cursor == s.end ()) { out_cursor = std::copy (i, s.end (), out_cursor); break; } out_cursor = std::copy (i, cursor, out_cursor); *out_cursor = hex_to_uint (cursor[1]) << 4 | hex_to_uint(cursor[2]); i += 3; } out.resize (out.end () - out_cursor); return out; } //----------------------------------------------------------------------------- std::ostream& cruft::operator<< (std::ostream &os, cruft::uri::component c) { switch (c) { case cruft::uri::SCHEME: return os << "SCHEME"; case cruft::uri::HIERARCHICAL: return os << "HIERARCHICAL"; case cruft::uri::AUTHORITY: return os << "AUTHORITY"; case cruft::uri::USER: return os << "USER"; case cruft::uri::HOST: return os << "HOST"; case cruft::uri::PORT: return os << "PORT"; case cruft::uri::PATH: return os << "PATH"; case cruft::uri::QUERY: return os << "QUERY"; case cruft::uri::FRAGMENT: return os << "FRAGMENT"; case cruft::uri::NUM_COMPONENTS: unreachable (); } unreachable (); } //----------------------------------------------------------------------------- std::ostream& cruft::operator<< (std::ostream &os, cruft::uri const &val) { return os << val.value (); }