More consistent handling of special paths (like data: URLs) for technology components.

This commit is contained in:
Matthias Koefferlein 2024-11-23 19:19:23 +01:00
parent 1c23d77073
commit dc9b3bb398
12 changed files with 263 additions and 35 deletions

View File

@ -60,7 +60,7 @@ typedef l2n_std_format::keys<true> skeys;
typedef l2n_std_format::keys<false> lkeys;
LayoutToNetlistStandardReader::LayoutToNetlistStandardReader (tl::InputStream &stream)
: m_stream (stream), m_path (stream.absolute_path ()), m_dbu (0.0),
: m_stream (stream), m_path (stream.absolute_file_path ()), m_dbu (0.0),
m_progress (tl::to_string (tr ("Reading L2N database")), 1000)
{
m_progress.set_format (tl::to_string (tr ("%.0fk lines")));

View File

@ -183,7 +183,7 @@ SpiceReaderStream::line_number () const
std::string
SpiceReaderStream::source () const
{
return mp_stream->absolute_path ();
return mp_stream->absolute_file_path ();
}
bool
@ -495,7 +495,7 @@ SpiceCircuitDict::read (tl::InputStream &stream)
m_global_net_names.clear ();
m_global_nets.clear ();
m_file_id = file_id (stream.absolute_path ());
m_file_id = file_id (stream.absolute_file_path ());
while (! at_end ()) {
read_card ();

View File

@ -479,10 +479,10 @@ std::string
Technology::correct_path (const std::string &fp) const
{
std::string bp = base_path ();
if (bp.empty ()) {
if (bp.empty () || ! tl::InputStream::is_file_path (fp) || ! tl::InputStream::is_file_path (bp)) {
return fp;
} else {
return tl::relative_path (bp, fp);
return tl::relative_path (tl::InputStream::as_file_path (bp), tl::InputStream::as_file_path (fp));
}
}
@ -494,7 +494,11 @@ Technology::load (const std::string &fn)
xml_struct.parse (source, *this);
// use the tech file's path as the default base path
set_default_base_path (tl::absolute_path (fn));
if (tl::InputStream::is_file_path (fn)) {
set_default_base_path (tl::absolute_path (fn));
} else {
set_default_base_path (std::string ());
}
set_tech_file_path (fn);
}
@ -515,10 +519,10 @@ Technology::build_effective_path (const std::string &p) const
return p;
}
if (tl::is_absolute (p)) {
if (tl::InputStream::is_absolute (p)) {
return p;
} else {
return tl::combine_path (bp, p);
return tl::InputStream::combine (bp, p);
}
}

View File

@ -2981,7 +2981,7 @@ void
MainWindow::add_mru (const std::string &fn_rel, const std::string &tech)
{
std::vector <std::pair<std::string, std::string> > new_mru;
std::string fn (tl::InputStream::absolute_path (fn_rel));
std::string fn (tl::InputStream::absolute_file_path (fn_rel));
for (auto mru = m_mru.begin (); mru != m_mru.end (); ++mru) {
if (mru->first != fn /* delete non-existing files: && tl::is_readable (mru->first) */) {
@ -3025,7 +3025,7 @@ MainWindow::add_to_other_mru (const std::string &fn_rel, const std::string &cfg)
}
std::vector <std::string> new_mru;
std::string fn (tl::InputStream::absolute_path (fn_rel));
std::string fn (tl::InputStream::absolute_file_path (fn_rel));
for (auto mru = mru_ptr->begin (); mru != mru_ptr->end (); ++mru) {
if (*mru != fn /* delete non-existing files: && tl::is_readable (*mru) */) {

View File

@ -66,7 +66,7 @@ Session::fetch (const lay::MainWindow &mw)
if (lh) {
m_layouts.push_back (SessionLayoutDescriptor ());
m_layouts.back ().name = *l;
m_layouts.back ().file_path = tl::InputStream::absolute_path (lh->filename ());
m_layouts.back ().file_path = tl::InputStream::absolute_file_path (lh->filename ());
m_layouts.back ().load_options = lh->load_options ();
m_layouts.back ().save_options = lh->save_options ();
m_layouts.back ().save_options_valid = lh->save_options_valid ();
@ -89,7 +89,7 @@ Session::fetch (const lay::MainWindow &mw)
const rdb::Database *rdb = view->get_rdb (j);
if (rdb && ! rdb->filename ().empty ()) {
view_desc.rdb_filenames.push_back (tl::InputStream::absolute_path (rdb->filename ()));
view_desc.rdb_filenames.push_back (tl::InputStream::absolute_file_path (rdb->filename ()));
}
}
@ -98,7 +98,7 @@ Session::fetch (const lay::MainWindow &mw)
const db::LayoutToNetlist *l2ndb = view->get_l2ndb (j);
if (l2ndb && ! l2ndb->filename ().empty ()) {
view_desc.l2ndb_filenames.push_back (tl::InputStream::absolute_path (l2ndb->filename ()));
view_desc.l2ndb_filenames.push_back (tl::InputStream::absolute_file_path (l2ndb->filename ()));
}
}

View File

@ -1084,7 +1084,7 @@ LEFDEFReaderState::read_single_map_file (const std::string &path, std::map<std::
tl::InputStream file_stream (file);
tl::TextInputStream ts (file_stream);
tl::log << tl::to_string (tr ("Reading LEF/DEF map file")) << " " << file_stream.absolute_path ();
tl::log << tl::to_string (tr ("Reading LEF/DEF map file")) << " " << file_stream.absolute_file_path ();
// Purpose name to purpose code
std::map<std::string, LayerPurpose> purpose_translation;
@ -2011,7 +2011,7 @@ LEFDEFImporter::get_mask (long m)
void
LEFDEFImporter::read (tl::InputStream &stream, db::Layout &layout, LEFDEFReaderState &state)
{
tl::log << tl::to_string (tr ("Reading LEF/DEF file")) << " " << stream.absolute_path ();
tl::log << tl::to_string (tr ("Reading LEF/DEF file")) << " " << stream.absolute_file_path ();
m_fn = stream.filename ();

View File

@ -120,7 +120,7 @@ LEFDEFReader::read_lefdef (db::Layout &layout, const db::LoadLayoutOptions &opti
std::string base_path;
if (! effective_options.paths_relative_to_cwd ()) {
base_path = tl::dirname (m_stream.absolute_path ());
base_path = tl::dirname (m_stream.absolute_file_path ());
}
db::LEFDEFReaderState state (&effective_options, layout, base_path);
@ -179,7 +179,7 @@ LEFDEFReader::read_lefdef (db::Layout &layout, const db::LoadLayoutOptions &opti
if (effective_options.read_lef_with_def ()) {
std::string input_dir = tl::absolute_path (m_stream.absolute_path ());
std::string input_dir = tl::absolute_path (m_stream.absolute_file_path ());
if (tl::file_exists (input_dir)) {

View File

@ -1786,7 +1786,7 @@ Database::load (std::string fn)
reader.read (*this);
}
set_filename (stream.absolute_path ());
set_filename (stream.absolute_file_path ());
set_name (stream.filename ());
reset_modified ();

View File

@ -254,7 +254,6 @@ static std::vector<std::string> split_filename (const std::string &fn)
const char *cp0 = cp;
++cp;
while (*cp && *cp != '.') {
// backslash escaping (ineffective on Windows because that is a path separator)
if (*cp == '\\' && cp[1]) {
++cp;
}

View File

@ -425,32 +425,124 @@ InputStream::~InputStream ()
}
}
std::string InputStream::absolute_path (const std::string &abstract_path)
std::string InputStream::absolute_file_path (const std::string &abstract_path)
{
// TODO: align this implementation with InputStream ctor
tl::Extractor ex (abstract_path.c_str ());
#if defined(HAVE_QT)
if (ex.test (":")) {
return abstract_path;
} else
#endif
#if defined(HAVE_CURL) || defined(HAVE_QT)
if (ex.test ("http:") || ex.test ("https:")) {
return abstract_path;
} else
#endif
if (ex.test ("pipe:")) {
} else if (ex.test ("http:") || ex.test ("https:") || ex.test ("pipe:") || ex.test ("data:")) {
return abstract_path;
} else if (ex.test ("file:")) {
tl::URI uri (abstract_path);
return tl::absolute_path (uri.path ());
return tl::absolute_file_path (uri.path ());
} else {
return tl::absolute_file_path (abstract_path);
}
}
const char *
bool InputStream::is_absolute (const std::string &abstract_path)
{
// TODO: align this implementation with InputStream ctor
tl::Extractor ex (abstract_path.c_str ());
if (ex.test (":")) {
return true;
} else if (ex.test ("http:") || ex.test ("https:") || ex.test ("pipe:") || ex.test ("data:")) {
return true;
} else if (ex.test ("file:")) {
tl::URI uri (abstract_path);
return tl::is_absolute (uri.path ());
} else {
return tl::is_absolute (abstract_path);
}
}
bool InputStream::is_file_path (const std::string &abstract_path)
{
tl::Extractor ex (abstract_path.c_str ());
if (ex.test (":")) {
return false;
} else if (ex.test ("http:") || ex.test ("https:") || ex.test ("pipe:") || ex.test ("data:")) {
return false;
} else {
return true;
}
}
std::string InputStream::as_file_path (const std::string &abstract_path)
{
tl::Extractor ex (abstract_path.c_str ());
if (ex.test (":")) {
return std::string ();
} else if (ex.test ("http:") || ex.test ("https:") || ex.test ("pipe:") || ex.test ("data:")) {
return std::string ();
} else if (ex.test ("file:")) {
tl::URI uri (abstract_path);
return uri.path ();
} else {
return abstract_path;
}
}
std::string InputStream::combine (const std::string &path1, const std::string &path2)
{
if (is_absolute (path2)) {
return path2;
}
tl::Extractor ex (path1);
if (ex.test (":")) {
return path1 + "/" + path2;
} else if (ex.test ("pipe:") || ex.test ("data:")) {
// ignore un-combinable first parts
return path2;
}
tl::URI uri1 (path1);
tl::URI uri2 (path2);
if (uri1.scheme ().empty ()) {
if (uri2.scheme ().empty ()) {
return tl::combine_path (path1, path2);
} else {
return tl::combine_path (path1, uri2.path ());
}
} else {
if (uri2.scheme ().empty ()) {
uri1.set_path (uri1.path () + "/" + tl::replaced (path2, "\\", "/"));
} else {
uri1.set_path (uri1.path () + "/" + uri2.path ());
}
return uri1.to_abstract_path ();
}
}
std::string InputStream::relative_path (const std::string &path1, const std::string &path2)
{
// TODO: align this implementation with InputStream ctor
tl::Extractor ex (path2);
if (ex.test (":")) {
return path2;
} else if (ex.test ("pipe:") || ex.test ("data:")) {
return path2;
}
tl::URI uri1 (path1);
tl::URI uri2 (path2);
// NOTE: only file schemes are supported as of now
if ((uri1.scheme ().empty () || uri1.scheme () == "file") &&
(uri2.scheme ().empty () || uri2.scheme () == "file")) {
return tl::relative_path (uri1.path (), uri2.path ());
}
return path2;
}
const char *
InputStream::get (size_t n, bool bypass_inflate)
{
// if deflating, employ the deflate filter to get the data

View File

@ -531,7 +531,7 @@ public:
*
* Returns an empty string if no absolute path is available.
*/
std::string absolute_path () const
std::string absolute_file_path () const
{
return mp_delegate->absolute_path ();
}
@ -549,9 +549,34 @@ public:
void close ();
/**
* @brief Gets the absolute path for a given URL
* @brief Gets the absolute, abstract path for a given abstract path
*/
static std::string absolute_path (const std::string &path);
static std::string absolute_file_path (const std::string &apath);
/**
* @brief Gets the absolute path for a given abstract path
*/
static bool is_absolute (const std::string &apath);
/**
* @brief Gets a value indicating whether the path is a file path
*/
static bool is_file_path (const std::string &apath);
/**
* @brief Gets the file path (no scheme) if it applies to the given abstract path
*/
static std::string as_file_path (const std::string &apath);
/**
* @brief Combines two abstract paths
*/
static std::string combine (const std::string &apath1, const std::string &apath2);
/**
* @brief Returns the relative abstract path of path2 vs. path1
*/
static std::string relative_path (const std::string &apath1, const std::string &apath2);
/**
* @brief Gets the base reader (delegate)
@ -621,7 +646,7 @@ public:
virtual std::string absolute_path () const
{
return m_inflating_stream.absolute_path ();
return m_inflating_stream.absolute_file_path ();
}
virtual std::string filename () const

View File

@ -479,3 +479,111 @@ TEST(RefuseToWrite)
}
}
TEST(AbstractPathFunctions)
{
EXPECT_EQ (tl::InputStream::absolute_file_path (""), tl::absolute_file_path ("."));
EXPECT_EQ (tl::InputStream::absolute_file_path ("."), tl::absolute_file_path ("."));
EXPECT_EQ (tl::InputStream::absolute_file_path ("pipe:xyz"), "pipe:xyz");
EXPECT_EQ (tl::InputStream::absolute_file_path ("data:xyz"), "data:xyz");
EXPECT_EQ (tl::InputStream::absolute_file_path ("https:xyz"), "https:xyz");
EXPECT_EQ (tl::InputStream::absolute_file_path ("http:xyz"), "http:xyz");
EXPECT_EQ (tl::InputStream::absolute_file_path (":xyz"), ":xyz");
EXPECT_EQ (tl::InputStream::absolute_file_path ("file:xyz"), tl::absolute_file_path ("xyz"));
EXPECT_EQ (tl::InputStream::absolute_file_path ("xyz"), tl::absolute_file_path ("xyz"));
EXPECT_EQ (tl::InputStream::absolute_file_path ("xyz/uvw"), tl::absolute_file_path ("xyz/uvw"));
EXPECT_EQ (tl::InputStream::absolute_file_path ("/xyz/uvw"), "/xyz/uvw");
tl::file_utils_force_windows ();
EXPECT_EQ (tl::InputStream::absolute_file_path ("xyz\\uvw"), tl::absolute_file_path ("xyz\\uvw"));
EXPECT_EQ (tl::InputStream::absolute_file_path ("\\\\server\\xyz\\uvw"), "\\\\server\\xyz\\uvw");
EXPECT_EQ (tl::InputStream::absolute_file_path ("c:\\xyz\\uvw"), "c:\\xyz\\uvw");
tl::file_utils_force_reset ();
EXPECT_EQ (tl::InputStream::is_absolute (""), false);
EXPECT_EQ (tl::InputStream::is_absolute ("."), false);
EXPECT_EQ (tl::InputStream::is_absolute ("pipe:xyz"), true);
EXPECT_EQ (tl::InputStream::is_absolute ("data:xyz"), true);
EXPECT_EQ (tl::InputStream::is_absolute ("https:xyz"), true);
EXPECT_EQ (tl::InputStream::is_absolute ("http:xyz"), true);
EXPECT_EQ (tl::InputStream::is_absolute (":xyz"), true);
EXPECT_EQ (tl::InputStream::is_absolute ("file:xyz"), false);
EXPECT_EQ (tl::InputStream::is_absolute ("xyz"), false);
EXPECT_EQ (tl::InputStream::is_absolute ("xyz/uvw"), false);
EXPECT_EQ (tl::InputStream::is_absolute ("/xyz/uvw"), true);
tl::file_utils_force_windows ();
EXPECT_EQ (tl::InputStream::is_absolute ("xyz\\uvw"), false);
EXPECT_EQ (tl::InputStream::is_absolute ("\\\\server\\xyz\\uvw"), true);
EXPECT_EQ (tl::InputStream::is_absolute ("c:\\xyz\\uvw"), true);
tl::file_utils_force_reset ();
tl::file_utils_force_windows ();
EXPECT_EQ (tl::InputStream::combine ("a", ""), "a");
EXPECT_EQ (tl::InputStream::combine ("", "b"), "\\b");
EXPECT_EQ (tl::InputStream::combine ("a", "b"), "a\\b");
EXPECT_EQ (tl::InputStream::combine ("a", "b/c"), "a\\b/c");
EXPECT_EQ (tl::InputStream::combine ("a", "b\\c"), "a\\b\\c");
EXPECT_EQ (tl::InputStream::combine ("a", "data:abc"), "data:abc");
EXPECT_EQ (tl::InputStream::combine ("data:a", "b"), "b");
EXPECT_EQ (tl::InputStream::combine ("pipe:a", "b"), "b");
EXPECT_EQ (tl::InputStream::combine (":a", "b"), ":a/b");
EXPECT_EQ (tl::InputStream::combine ("https://a", "b"), "https://a/b");
EXPECT_EQ (tl::InputStream::combine ("https://a", "https:b"), "https:b");
EXPECT_EQ (tl::InputStream::combine ("a", "https:b"), "https:b");
EXPECT_EQ (tl::InputStream::combine ("a", "file:b"), "a\\b");
EXPECT_EQ (tl::InputStream::combine ("a", "file:\\b"), "file:\\b");
EXPECT_EQ (tl::InputStream::combine ("file:a", "file:b"), "file:a/b");
EXPECT_EQ (tl::InputStream::combine ("file:a", "file:b/c"), "file:a/b/c");
EXPECT_EQ (tl::InputStream::combine ("file:a", "b\\c"), "file:a/b/c");
tl::file_utils_force_linux ();
EXPECT_EQ (tl::InputStream::combine ("a", "b"), "a/b");
EXPECT_EQ (tl::InputStream::combine ("", "b"), "/b");
EXPECT_EQ (tl::InputStream::combine ("a", "b/c"), "a/b/c");
EXPECT_EQ (tl::InputStream::combine ("a", "data:abc"), "data:abc");
EXPECT_EQ (tl::InputStream::combine ("data:a", "b"), "b");
EXPECT_EQ (tl::InputStream::combine ("pipe:a", "b"), "b");
EXPECT_EQ (tl::InputStream::combine (":a", "b"), ":a/b");
EXPECT_EQ (tl::InputStream::combine ("https://a", "b"), "https://a/b");
EXPECT_EQ (tl::InputStream::combine ("https://a", "https:b"), "https:b");
EXPECT_EQ (tl::InputStream::combine ("a", "https:b"), "https:b");
EXPECT_EQ (tl::InputStream::combine ("a", "file:b"), "a/b");
EXPECT_EQ (tl::InputStream::combine ("a", "file:/b"), "file:/b");
EXPECT_EQ (tl::InputStream::combine ("file:a", "file:b"), "file:a/b");
EXPECT_EQ (tl::InputStream::combine ("file:a", "file:b/c"), "file:a/b/c");
EXPECT_EQ (tl::InputStream::combine ("file:a", "b/c"), "file:a/b/c");
tl::file_utils_force_reset ();
tl::file_utils_force_linux ();
EXPECT_EQ (tl::InputStream::relative_path ("", "file:/a/b/c"), "/a/b/c");
EXPECT_EQ (tl::InputStream::relative_path (".", "file:/a/b/c"), "/a/b/c");
EXPECT_EQ (tl::InputStream::relative_path ("https://x", "a/b/c"), "a/b/c");
EXPECT_EQ (tl::InputStream::relative_path ("file:/a/b", "file:/a/b/c"), "c");
EXPECT_EQ (tl::InputStream::relative_path ("/a/b", "/a/b/c"), "c");
EXPECT_EQ (tl::InputStream::relative_path ("/a/b", "/x/b/c"), "/x/b/c");
EXPECT_EQ (tl::InputStream::relative_path ("file:/a/b", "file:/a/b/c"), "c");
EXPECT_EQ (tl::InputStream::relative_path ("/a/b", "/a/b/c"), "c");
tl::file_utils_force_windows ();
EXPECT_EQ (tl::InputStream::relative_path ("/a/b", "/a/b/c"), "c");
EXPECT_EQ (tl::InputStream::relative_path ("/a/b", "\\a\\b\\c\\d"), "c\\d");
tl::file_utils_force_reset ();
EXPECT_EQ (tl::InputStream::is_file_path (""), true);
EXPECT_EQ (tl::InputStream::is_file_path (":abc"), false);
EXPECT_EQ (tl::InputStream::is_file_path ("pipe:abc"), false);
EXPECT_EQ (tl::InputStream::is_file_path ("data:abc"), false);
EXPECT_EQ (tl::InputStream::is_file_path ("http:abc"), false);
EXPECT_EQ (tl::InputStream::is_file_path ("file:abc"), true);
EXPECT_EQ (tl::InputStream::is_file_path ("a/b/c"), true);
tl::file_utils_force_windows ();
EXPECT_EQ (tl::InputStream::is_file_path ("a\\b\\c"), true);
tl::file_utils_force_reset ();
EXPECT_EQ (tl::InputStream::as_file_path (""), std::string ());
EXPECT_EQ (tl::InputStream::as_file_path (":abc"), std::string ());
EXPECT_EQ (tl::InputStream::as_file_path ("pipe:abc"), std::string ());
EXPECT_EQ (tl::InputStream::as_file_path ("data:abc"), std::string ());
EXPECT_EQ (tl::InputStream::as_file_path ("http:abc"), std::string ());
EXPECT_EQ (tl::InputStream::as_file_path ("file:abc"), "abc");
EXPECT_EQ (tl::InputStream::as_file_path ("a/b/c"), "a/b/c");
tl::file_utils_force_windows ();
EXPECT_EQ (tl::InputStream::as_file_path ("a\\b\\c"), "a\\b\\c");
tl::file_utils_force_reset ();
}