From 8b2ecf41df43ef796d4ace1fc398c4e9e807146a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20K=C3=B6fferlein?= Date: Thu, 25 Feb 2021 21:28:48 +0100 Subject: [PATCH] Fixed issue by providing a compatibility bridge between tl::Stream (abstract paths) and tl::URI (#734) --- src/db/db/dbNetlistSpiceReader.cc | 2 +- src/img/img/imgObject.cc | 2 +- src/lay/lay/laySession.cc | 2 +- .../streamers/magic/db_plugin/dbMAGReader.cc | 2 +- src/tl/tl/tlInclude.cc | 2 +- src/tl/tl/tlStream.cc | 37 +++++++++++++------ src/tl/tl/tlStream.h | 2 + src/tl/tl/tlUri.cc | 10 +++++ src/tl/tl/tlUri.h | 13 +++++++ src/tl/unit_tests/tlUriTests.cc | 15 ++++++++ 10 files changed, 70 insertions(+), 17 deletions(-) diff --git a/src/db/db/dbNetlistSpiceReader.cc b/src/db/db/dbNetlistSpiceReader.cc index 9f42043ca..e5f1da83b 100644 --- a/src/db/db/dbNetlistSpiceReader.cc +++ b/src/db/db/dbNetlistSpiceReader.cc @@ -395,7 +395,7 @@ void NetlistSpiceReader::push_stream (const std::string &path) istream = new tl::InputStream (tl::combine_path (tl::dirname (mp_stream->source ()), path)); } } else { - istream = new tl::InputStream (current_uri.resolved (new_uri).to_string ()); + istream = new tl::InputStream (current_uri.resolved (new_uri).to_abstract_path ()); } m_streams.push_back (std::make_pair (istream, mp_stream.release ())); diff --git a/src/img/img/imgObject.cc b/src/img/img/imgObject.cc index 09f8e9c8e..f7b842263 100644 --- a/src/img/img/imgObject.cc +++ b/src/img/img/imgObject.cc @@ -1343,7 +1343,7 @@ Object::from_string (const char *str, const char *base_dir) tl::URI fp_uri (m_filename); if (base_dir && ! tl::is_absolute (fp_uri.path ())) { - m_filename = tl::URI (base_dir).resolved (fp_uri).to_string (); + m_filename = tl::URI (base_dir).resolved (fp_uri).to_abstract_path (); } read_file (); diff --git a/src/lay/lay/laySession.cc b/src/lay/lay/laySession.cc index 6aebf4b11..0cdaae8ff 100644 --- a/src/lay/lay/laySession.cc +++ b/src/lay/lay/laySession.cc @@ -145,7 +145,7 @@ Session::make_absolute (const std::string &fp) const { tl::URI fp_uri (fp); if (! m_base_dir.empty () && ! tl::is_absolute (fp_uri.path ())) { - return tl::URI (m_base_dir).resolved (fp_uri).to_string (); + return tl::URI (m_base_dir).resolved (fp_uri).to_abstract_path (); } else { return fp; } diff --git a/src/plugins/streamers/magic/db_plugin/dbMAGReader.cc b/src/plugins/streamers/magic/db_plugin/dbMAGReader.cc index fe9773fd3..71a69ae09 100644 --- a/src/plugins/streamers/magic/db_plugin/dbMAGReader.cc +++ b/src/plugins/streamers/magic/db_plugin/dbMAGReader.cc @@ -211,7 +211,7 @@ static bool find_and_normalize_file (const tl::URI &uri, std::string &path) // TODO: this is not quite efficient, but the only thing we can do for now tl::URI uri_with_ext = uri; uri_with_ext.set_path (uri_with_ext.path () + extensions[e]); - std::string us = uri_with_ext.to_string (); + std::string us = uri_with_ext.to_abstract_path (); if (tl::verbosity () >= 30) { tl::log << tl::to_string (tr ("Trying layout URI: ")) << us; diff --git a/src/tl/tl/tlInclude.cc b/src/tl/tl/tlInclude.cc index 9a946fec3..53a5a6dc1 100644 --- a/src/tl/tl/tlInclude.cc +++ b/src/tl/tl/tlInclude.cc @@ -97,7 +97,7 @@ IncludeExpander::read (const std::string &path, tl::InputStream &is, std::string include_path = tl::combine_path (tl::dirname (path), include_path); } } else { - include_path = current_uri.resolved (new_uri).to_string (); + include_path = current_uri.resolved (new_uri).to_abstract_path (); } tl::InputStream is (include_path); diff --git a/src/tl/tl/tlStream.cc b/src/tl/tl/tlStream.cc index d951c0f8a..7b1f03fc7 100644 --- a/src/tl/tl/tlStream.cc +++ b/src/tl/tl/tlStream.cc @@ -167,9 +167,10 @@ InputStream::InputStream (const std::string &abstract_path) tl::Extractor ex (abstract_path.c_str ()); -#if defined(HAVE_QT) if (ex.test (":")) { +#if defined(HAVE_QT) + QResource res (tl::to_qstring (abstract_path)); if (res.size () > 0) { @@ -189,20 +190,32 @@ InputStream::InputStream (const std::string &abstract_path) } - } else +#else + throw tl::Exception (tl::to_string (tr ("Qt not enabled - resource paths are not available"))); #endif -#if defined(HAVE_CURL) || defined(HAVE_QT) - if (ex.test ("http:") || ex.test ("https:")) { - mp_delegate = new InputHttpStream (abstract_path); - } else -#endif - if (ex.test ("pipe:")) { + + } else if (ex.test ("pipe:")) { + mp_delegate = new InputPipe (ex.get ()); - } else if (ex.test ("file:")) { - tl::URI uri (abstract_path); - mp_delegate = new InputZLibFile (uri.path ()); + } else { - mp_delegate = new InputZLibFile (abstract_path); + + tl::URI uri (abstract_path); + + if (uri.scheme () == "http" || uri.scheme () == "https") { +#if defined(HAVE_CURL) || defined(HAVE_QT) + mp_delegate = new InputHttpStream (abstract_path); +#else + throw tl::Exception (tl::to_string (tr ("HTTP support not enabled - HTTP/HTTPS paths are not available"))); +#endif + } else if (uri.scheme () == "file") { + mp_delegate = new InputZLibFile (uri.path ()); + } else if (! uri.scheme ().empty ()) { + throw tl::Exception (tl::to_string (tr ("URI scheme not supported: ")) + uri.scheme ()); + } else { + mp_delegate = new InputZLibFile (abstract_path); + } + } if (! mp_buffer) { diff --git a/src/tl/tl/tlStream.h b/src/tl/tl/tlStream.h index 31877e1f2..c355beb75 100644 --- a/src/tl/tl/tlStream.h +++ b/src/tl/tl/tlStream.h @@ -398,6 +398,8 @@ public: * * This will automatically create the appropriate delegate and * delete it later. + * + * The abstract path */ InputStream (const std::string &abstract_path); diff --git a/src/tl/tl/tlUri.cc b/src/tl/tl/tlUri.cc index a50c945ed..0c9fdf6d2 100644 --- a/src/tl/tl/tlUri.cc +++ b/src/tl/tl/tlUri.cc @@ -209,6 +209,16 @@ URI::to_string () const return res; } +std::string +URI::to_abstract_path () const +{ + if (m_scheme.empty ()) { + return path (); + } else { + return to_string (); + } +} + URI URI::resolved (const URI &other) const { diff --git a/src/tl/tl/tlUri.h b/src/tl/tl/tlUri.h index a507bf6a3..88e534894 100644 --- a/src/tl/tl/tlUri.h +++ b/src/tl/tl/tlUri.h @@ -144,6 +144,19 @@ public: */ std::string to_string () const; + /** + * @brief Turns the URI into an "abstract path" + * + * The "abstract path" is a concept provided by "tl::InputStream". + * URIs with scheme "file", "http" and "https" are equivalent to their abstract path. + * URIs without a scheme turn into system file paths. + * Other schemes are not allowed. + * + * Abstract paths are more powerful as they support pipes and Qt resource access. + * These modes are not supported by URIs. + */ + std::string to_abstract_path () const; + /** * @brief Resolves an URI relative to this one */ diff --git a/src/tl/unit_tests/tlUriTests.cc b/src/tl/unit_tests/tlUriTests.cc index 7c8712d7d..a5f7c9cbf 100644 --- a/src/tl/unit_tests/tlUriTests.cc +++ b/src/tl/unit_tests/tlUriTests.cc @@ -164,6 +164,8 @@ TEST(2) // use case taken from Magic writer: tl::URI uri ("c:\\users\\myself\\path.txt"); + EXPECT_EQ (uri.scheme (), ""); + EXPECT_EQ (uri.path (), "c:\\users\\myself\\path.txt"); std::string ext = tl::extension (uri.path ()); EXPECT_EQ (ext, "txt"); @@ -178,3 +180,16 @@ TEST(2) throw; } } + +// issue #733 +TEST(3_pathsWithPlus) +{ + EXPECT_EQ (tl::URI ("/users/a_plus_b").resolved (tl::URI ("file.txt")).to_string (), "/users/a_plus_b/file.txt"); + EXPECT_EQ (tl::URI ("/users/a+b").resolved (tl::URI ("file.txt")).to_string (), "/users/a%2Bb/file.txt"); + EXPECT_EQ (tl::URI ("/users/a+b").resolved (tl::URI ("file.txt")).to_abstract_path (), "/users/a+b/file.txt"); + EXPECT_EQ (tl::URI ("file://users/a+b").resolved (tl::URI ("file.txt")).to_string (), "file://users/a%2Bb/file.txt"); + EXPECT_EQ (tl::URI ("file://users/a+b").resolved (tl::URI ("file.txt")).to_abstract_path (), "file://users/a%2Bb/file.txt"); + // drive-letter paths + EXPECT_EQ (tl::URI ("c:/users/a+b").resolved (tl::URI ("file.txt")).to_string (), "c:/users/a%2Bb/file.txt"); + EXPECT_EQ (tl::URI ("c:/users/a+b").resolved (tl::URI ("file.txt")).to_abstract_path (), "c:/users/a+b/file.txt"); +}