Skip to content

BUG: Read the extension from the final path component in get_ext#52

Open
hjmjohnson wants to merge 1 commit into
tee-ar-ex:mainfrom
hjmjohnson:fix-get-ext-path-basename
Open

BUG: Read the extension from the final path component in get_ext#52
hjmjohnson wants to merge 1 commit into
tee-ar-ex:mainfrom
hjmjohnson:fix-get-ext-path-basename

Conversation

@hjmjohnson

Copy link
Copy Markdown

get_ext() scans the entire path for ., so a dot in any parent directory is mistaken for the file extension. For a version-numbered build/output path like .../build-5.4/…/trx_test (a file with no extension), get_ext returns "4/…/trx_test", which the writer rejects with "Unsupported extension". This fixes it to read the extension from the final path component only.

Root cause
// before
const std::size_t pos = str.rfind('.');   // '.' anywhere in the path

rfind('.') on the full path finds the dot in build-5.4, not in the filename:

get_ext(".../build-5.4/out/trx_test") = "4/out/trx_test"   -> "Unsupported extension"
get_ext(".../build-main/out/trx_test") = ""                -> ok (no dot in path)

The fix restricts the search to the substring after the last / or \, then takes the part after that component's last ..

No change to dtype extraction

get_ext is also used to read the dtype from array element filenames (positions.3.float32, offsets.uint64). Those carry the dot in the basename, so the returned dtype is unchanged — the fix only differs when the basename has no dot but a parent directory does.

Testing

Adds TrxFileIo.get_ext_uses_final_path_component:

get_ext("/a/build-5.4/out/trx_test")        == ""          // the bug case
get_ext("/a/build-5.4/out/trx_test.trx")    == "trx"
get_ext("out.trx")                          == "trx"
get_ext("trx_test")                         == ""
get_ext("/a/shard.1/positions.3.float32")   == "float32"    // dtype filename, dotted parent
get_ext("offsets.uint64")                   == "uint64"
get_ext("/a/b.c/name.")                     == ""           // trailing dot

Full ctest suite passes 185/185 (the dtype callers are exercised by test_io).

Found via an ITK v5-vs-v6 downstream build testbed whose build path contained a dotted directory; the three ITKTractographyTRX tests that failed there pass with this change.

get_ext() scanned the entire path for '.' via rfind, so a dot anywhere in
a parent directory was treated as the file extension. A common trigger is
a version-numbered build/output path: for
".../build-5.4/.../trx_test" (a file with no extension) get_ext returned
"4/.../trx_test", which the writer rejects with
"Unsupported extension".

Restrict the search to the final path component (after the last '/' or
'\'), then take the substring after its last '.'. A file with no dot in
its name now correctly yields an empty extension.

This does not change the dtype-extraction callers: array element
filenames such as "positions.3.float32" and "offsets.uint64" carry the
dot in the basename, so the returned dtype is unchanged.

Adds TrxFileIo.get_ext_uses_final_path_component covering the dotted-parent
regression, no-extension, no-separator, dtype-filename, and trailing-dot
cases. Full ctest suite passes 185/185.

Found via an ITK v5-vs-v6 downstream build testbed whose build path
contained a dotted directory; the three ITKTractographyTRX tests that
failed there pass with this fix.
@hjmjohnson

Copy link
Copy Markdown
Author

@mattcieslak Some fixes exposed while trying to build TRX with both ITKv5 and ITKv6.

@hjmjohnson
hjmjohnson marked this pull request as ready for review July 17, 2026 19:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant