aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2022-07-07 03:11:30 +0200
committerSven Gothel <[email protected]>2022-07-07 03:11:30 +0200
commite2ad720568f730fe5ca2f1d0c9c911b339fb58b8 (patch)
treee2e8baf85c006d0b494b42554dc9b3d87a794816
parentb9d1c558884dd5f5ce23ee7d35e2f14201a2c4c2 (diff)
Fix dir_item::reduce()
- use while-loop to remove initial './' - always use spos and reset to pre-len when re-assembling pre+post - break resolve loop once on found idx == npos - limit loop to spos <= haystack.size()-pattern_size - resolve '/./': - remove dead-case '_dot == pre' as resolved upfront - resolve '/../': - test non-starting '/..' at end of pre -> no change. E.g. '../../../bbb' - case 'pre_str = direname(pre)': test '.' (first dir removed)
-rw-r--r--src/file_util.cpp106
-rw-r--r--test/java/jau/test/fs/TestFileUtils01.java38
-rw-r--r--test/test_fileutils01.cpp37
3 files changed, 133 insertions, 48 deletions
diff --git a/src/file_util.cpp b/src/file_util.cpp
index 5634683..d8ebccd 100644
--- a/src/file_util.cpp
+++ b/src/file_util.cpp
@@ -138,7 +138,7 @@ std::unique_ptr<dir_item::backed_string_view> dir_item::reduce(const std::string
}
// remove initial './'
- if( 0 == path2->view.find(_dot_slash) ) {
+ while( 0 == path2->view.find(_dot_slash) ) {
path2->view = path2->view.substr(2, path2->view.size()-2);
}
@@ -163,64 +163,78 @@ std::unique_ptr<dir_item::backed_string_view> dir_item::reduce(const std::string
}
// resolve '/./'
+ size_t spos=0;
size_t idx;
do {
- idx = path2->view.find(_slash_dot_slash);
- if( std::string_view::npos != idx ) {
- std::string_view pre = path2->view.substr(0, idx);
- if( 0 == pre.size() ) {
- // case '/./bbb' -> '/bbb'
- path2->view = path2->view.substr(idx+2);
- } else if( _dot == pre ) {
- // case '././bbb' -> 'bbb'
- path2->view = path2->view.substr(idx+3);
- } else {
- // case '/zzz/aaa/./bbb' -> '/zzz/aaa/bbb'
- const std::string post( path2->view.substr(idx+2) );
- path2->backup_and_append( pre, post );
- }
- if constexpr ( _debug ) {
- jau::fprintf_td(stderr, "X.2.2: path2: '%s'\n", path2->to_string(true).c_str());
- }
+ idx = path2->view.find(_slash_dot_slash, spos);
+ if constexpr ( _debug ) {
+ jau::fprintf_td(stderr, "X.2.1: path2: spos %zu, idx %zu, '%s'\n", spos, idx, path2->to_string(true).c_str());
+ }
+ if( std::string_view::npos == idx ) {
+ break;
+ }
+ std::string_view pre = path2->view.substr(0, idx);
+ if( 0 == pre.size() ) {
+ // case '/./bbb' -> '/bbb'
+ path2->view = path2->view.substr(idx+2);
+ spos = 0;
+ } else {
+ // case '/zzz/aaa/./bbb' -> '/zzz/aaa/bbb'
+ const std::string post( path2->view.substr(idx+2) );
+ path2->backup_and_append( pre, post );
+ spos = pre.size();
+ }
+ if constexpr ( _debug ) {
+ jau::fprintf_td(stderr, "X.2.2: path2: spos %zu, '%s'\n", spos, path2->to_string(true).c_str());
}
- } while( idx != std::string_view::npos );
+ } while( spos <= path2->view.size()-3 );
if constexpr ( _debug ) {
jau::fprintf_td(stderr, "X.2.X: path2: '%s'\n", path2->to_string(true).c_str());
}
// resolve '/../'
- size_t spos=0;
+ spos=0;
do {
idx = path2->view.find(_slash_dotdot_slash, spos);
- if( std::string_view::npos != idx ) {
- if( 0 == idx ) {
- // case '/../bbb' -> Error, End
- WARN_PRINT("dir_item::resolve: '..' resolution error: '%s' -> '%s'", std::string(path_).c_str(), path2->to_string().c_str());
- return path2;
- }
- std::string_view pre = path2->view.substr(0, idx);
- if( _dotdot == pre ) {
- // case '../../bbb' -> '../../bbb' unchanged
- spos = idx+4;
- } else if( _dot == pre ) {
- // case './../bbb' -> '../bbb'
- path2->view = path2->view.substr(idx+1);
+ if constexpr ( _debug ) {
+ jau::fprintf_td(stderr, "X.3.1: path2: spos %zu, idx %zu, '%s'\n", spos, idx, path2->to_string(true).c_str());
+ }
+ if( std::string_view::npos == idx ) {
+ break;
+ }
+ if( 0 == idx ) {
+ // case '/../bbb' -> Error, End
+ WARN_PRINT("dir_item::resolve: '..' resolution error: '%s' -> '%s'", std::string(path_).c_str(), path2->to_string().c_str());
+ return path2;
+ }
+ std::string_view pre = path2->view.substr(0, idx);
+ if( 2 == idx && _dotdot == pre ) {
+ // case '../../bbb' -> '../../bbb' unchanged
+ spos = idx+4;
+ } else if( 3 <= idx && _slash_dotdot == path2->view.substr(idx-3, 3) ) {
+ // case '../../../bbb' -> '../../../bbb' unchanged
+ spos = idx+4;
+ } else {
+ std::string pre_str = jau::fs::dirname( pre );
+ if( _slash == pre_str ) {
+ // case '/aaa/../bbb' -> '/bbb'
+ path2->view = path2->view.substr(idx+3);
+ spos = 0;
+ } else if( _dot == pre_str ) {
+ // case 'aaa/../bbb' -> 'bbb'
+ path2->view = path2->view.substr(idx+4);
+ spos = 0;
} else {
- std::string pre_str = jau::fs::dirname( pre );
- if( _slash == pre_str ) {
- // case '/aaa/../bbb' -> '/bbb'
- path2->view = path2->view.substr(idx+3);
- } else {
- // case '/zzz/aaa/../bbb' -> '/zzz/bbb'
- const std::string post( path2->view.substr(idx+3) );
- path2->backup_and_append( pre_str, post );
- }
- }
- if constexpr ( _debug ) {
- jau::fprintf_td(stderr, "X.3.2: path2: '%s'\n", path2->to_string(true).c_str());
+ // case '/zzz/aaa/../bbb' -> '/zzz/bbb'
+ const std::string post( path2->view.substr(idx+3) );
+ path2->backup_and_append( pre_str, post );
+ spos = pre_str.size();
}
}
- } while( idx != std::string_view::npos );
+ if constexpr ( _debug ) {
+ jau::fprintf_td(stderr, "X.3.2: path2: spos %zu, '%s'\n", spos, path2->to_string(true).c_str());
+ }
+ } while( spos <= path2->view.size()-4 );
if constexpr ( _debug ) {
jau::fprintf_td(stderr, "X.3.X: path2: '%s'\n", path2->to_string(true).c_str());
}
diff --git a/test/java/jau/test/fs/TestFileUtils01.java b/test/java/jau/test/fs/TestFileUtils01.java
index 78cfecf..55e0f7f 100644
--- a/test/java/jau/test/fs/TestFileUtils01.java
+++ b/test/java/jau/test/fs/TestFileUtils01.java
@@ -420,7 +420,43 @@ public class TestFileUtils01 extends FileUtilBaseTest {
PrintUtil.println(System.err, "test04_dir_item: 60 '"+path1_+" -> "+di.toString()+" -> '"+di.path()+"'\n");
Assert.assertTrue( "../../test_data".equals( di.dirname() ) );
Assert.assertTrue( "file_01_slink09R1.txt".equals( di.basename() ) );
- Assert.assertTrue( "../../test_data/file_01_slink09R1.txt".equals( di.path() ) );
+ Assert.assertTrue( path1_.equals( di.path() ) );
+ }
+
+ {
+ final String path1_ = "../../../jaulib/test_data";
+ final DirItem di = new DirItem(path1_);
+ PrintUtil.println(System.err, "test04_dir_item: 61 '"+path1_+" -> "+di.toString()+" -> '"+di.path()+"'\n");
+ Assert.assertTrue( "../../../jaulib".equals( di.dirname() ) );
+ Assert.assertTrue( "test_data".equals( di.basename() ) );
+ Assert.assertTrue( path1_.equals( di.path() ) );
+ }
+
+ {
+ final String path1_ = "../../../../jaulib/test_data";
+ final DirItem di = new DirItem(path1_);
+ PrintUtil.println(System.err, "test04_dir_item: 62 '"+path1_+" -> "+di.toString()+" -> '"+di.path()+"'\n");
+ Assert.assertTrue( "../../../../jaulib".equals( di.dirname() ) );
+ Assert.assertTrue( "test_data".equals( di.basename() ) );
+ Assert.assertTrue( path1_.equals( di.path() ) );
+ }
+
+ {
+ final String path1_ = "././././jaulib/test_data";
+ final DirItem di = new DirItem(path1_);
+ PrintUtil.println(System.err, "test04_dir_item: 63 '"+path1_+" -> "+di.toString()+" -> '"+di.path()+"'\n");
+ Assert.assertTrue( "jaulib".equals( di.dirname() ) );
+ Assert.assertTrue( "test_data".equals( di.basename() ) );
+ Assert.assertTrue( "jaulib/test_data".equals( di.path() ) );
+ }
+
+ {
+ final String path1_ = "a/././././jaulib/test_data";
+ final DirItem di = new DirItem(path1_);
+ PrintUtil.println(System.err, "test04_dir_item: 64 '"+path1_+" -> "+di.toString()+" -> '"+di.path()+"'\n");
+ Assert.assertTrue( "a/jaulib".equals( di.dirname() ) );
+ Assert.assertTrue( "test_data".equals( di.basename() ) );
+ Assert.assertTrue( "a/jaulib/test_data".equals( di.path() ) );
}
{
diff --git a/test/test_fileutils01.cpp b/test/test_fileutils01.cpp
index d10be65..54a59e8 100644
--- a/test/test_fileutils01.cpp
+++ b/test/test_fileutils01.cpp
@@ -396,7 +396,42 @@ class TestFileUtil01 : TestFileUtilBase {
INFO_STR("\n\ntest04_dir_item: 60 '"+path1_+" -> "+di.to_string()+" -> '"+di.path()+"'\n");
REQUIRE( "../../test_data" == di.dirname() );
REQUIRE( "file_01_slink09R1.txt" == di.basename() );
- REQUIRE( "../../test_data/file_01_slink09R1.txt" == di.path() );
+ REQUIRE( path1_ == di.path() );
+ }
+
+ {
+ const std::string path1_ = "../../../jaulib/test_data";
+ const jau::fs::dir_item di(path1_);
+ INFO_STR("\n\ntest04_dir_item: 61 '"+path1_+" -> "+di.to_string()+" -> '"+di.path()+"'\n");
+ REQUIRE( "../../../jaulib" == di.dirname() );
+ REQUIRE( "test_data" == di.basename() );
+ REQUIRE( path1_ == di.path() );
+ }
+
+ {
+ const std::string path1_ = "../../../../jaulib/test_data";
+ const jau::fs::dir_item di(path1_);
+ INFO_STR("\n\ntest04_dir_item: 62 '"+path1_+" -> "+di.to_string()+" -> '"+di.path()+"'\n");
+ REQUIRE( "../../../../jaulib" == di.dirname() );
+ REQUIRE( "test_data" == di.basename() );
+ REQUIRE( path1_ == di.path() );
+ }
+
+ {
+ const std::string path1_ = "././././jaulib/test_data";
+ const jau::fs::dir_item di(path1_);
+ INFO_STR("\n\ntest04_dir_item: 63 '"+path1_+" -> "+di.to_string()+" -> '"+di.path()+"'\n");
+ REQUIRE( "jaulib" == di.dirname() );
+ REQUIRE( "test_data" == di.basename() );
+ REQUIRE( "jaulib/test_data" == di.path() );
+ }
+ {
+ const std::string path1_ = "a/././././jaulib/test_data";
+ const jau::fs::dir_item di(path1_);
+ INFO_STR("\n\ntest04_dir_item: 64 '"+path1_+" -> "+di.to_string()+" -> '"+di.path()+"'\n");
+ REQUIRE( "a/jaulib" == di.dirname() );
+ REQUIRE( "test_data" == di.basename() );
+ REQUIRE( "a/jaulib/test_data" == di.path() );
}
{