diff options
author | Sven Gothel <[email protected]> | 2022-07-07 03:11:30 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2022-07-07 03:11:30 +0200 |
commit | e2ad720568f730fe5ca2f1d0c9c911b339fb58b8 (patch) | |
tree | e2e8baf85c006d0b494b42554dc9b3d87a794816 | |
parent | b9d1c558884dd5f5ce23ee7d35e2f14201a2c4c2 (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.cpp | 106 | ||||
-rw-r--r-- | test/java/jau/test/fs/TestFileUtils01.java | 38 | ||||
-rw-r--r-- | test/test_fileutils01.cpp | 37 |
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() ); } { |