Index: /trunk/src/org/openstreetmap/josm/data/validation/ValidatorCLI.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/validation/ValidatorCLI.java	(revision 19076)
+++ /trunk/src/org/openstreetmap/josm/data/validation/ValidatorCLI.java	(revision 19077)
@@ -27,5 +27,4 @@
 import java.util.stream.Collectors;
 
-import org.apache.commons.io.FilenameUtils;
 import org.openstreetmap.josm.actions.ExtensionFileFilter;
 import org.openstreetmap.josm.cli.CLIModule;
@@ -320,12 +319,33 @@
      */
     private static String getDefaultOutputName(final String inputString) {
-        final String extension = FilenameUtils.getExtension(inputString);
+        final String[] parts = getFileParts(inputString);
+        final String extension = parts[1];
         if (!Arrays.asList("zip", "bz", "xz", "geojson").contains(extension)) {
-            return FilenameUtils.getBaseName(inputString) + ".geojson";
+            return parts[0] + ".geojson";
         } else if ("geojson".equals(extension)) {
             // Account for geojson input files
-            return FilenameUtils.getBaseName(inputString) + ".validated.geojson";
-        }
-        return FilenameUtils.getBaseName(FilenameUtils.getBaseName(inputString)) + ".geojson";
+            return parts[0] + ".validated.geojson";
+        }
+        return parts[0] + ".geojson";
+    }
+
+    /**
+     * Split a string into a filename + extension. Example:
+     * "foo.bar.txt" -> ["foo.bar", "txt"]
+     * <p>
+     * Please note that future versions of Java may make this method redundant. It is not as of Java 21 (look for
+     * something like {@code Path#getExtension}, see <a href="https://bugs.openjdk.org/browse/JDK-8298318">JDK-8298318</a>.
+     * That may be in Java 22.
+     * @param inputString The string to get the filename and extension from
+     * @return The filename and the (optional) extension
+     */
+    private static String[] getFileParts(String inputString) {
+        final int split = inputString.lastIndexOf('.');
+        final int path = inputString.lastIndexOf(File.separatorChar);
+        if (split == -1 || path > split) {
+            return new String[] {inputString, ""};
+        } else {
+            return new String[]{inputString.substring(0, split), inputString.substring(split + 1)};
+        }
     }
 
Index: /trunk/src/org/openstreetmap/josm/io/OsmPbfReader.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/io/OsmPbfReader.java	(revision 19076)
+++ /trunk/src/org/openstreetmap/josm/io/OsmPbfReader.java	(revision 19077)
@@ -7,4 +7,5 @@
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.OutputStream;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -16,5 +17,4 @@
 import java.util.Set;
 
-import org.apache.commons.io.input.BoundedInputStream;
 import org.openstreetmap.josm.data.Bounds;
 import org.openstreetmap.josm.data.DataSource;
@@ -51,4 +51,69 @@
  */
 public final class OsmPbfReader extends AbstractReader {
+    /**
+     * This could be replaced by {@link org.apache.commons.io.input.BoundedInputStream} from Apache Commons IO.
+     * However, Commons IO is not <i>currently</i> (2024-05-13) a required JOSM dependency, so we should avoid using it
+     * for now. Commons IO is a <i>transitive</i> dependency, currently pulled in by {@link org.apache.commons.compress}
+     * (see {@link org.apache.commons.compress.utils.BoundedInputStream}).
+     */
+    private static final class BoundedInputStream extends InputStream {
+        private final InputStream source;
+        private long count;
+        private long mark;
+
+        BoundedInputStream(InputStream source) {
+            this.source = source;
+        }
+
+        @Override
+        public int read() throws IOException {
+            count++;
+            return this.source.read();
+        }
+
+        @Override
+        public long skip(long n) throws IOException {
+            long skipped = super.skip(n);
+            this.count += skipped;
+            return skipped;
+        }
+
+        @Override
+        public int available() throws IOException {
+            return this.source.available();
+        }
+
+        @Override
+        public void close() throws IOException {
+            this.source.close();
+        }
+
+        @Override
+        public synchronized void mark(int readlimit) {
+            this.source.mark(readlimit);
+            this.mark = this.count;
+        }
+
+        @Override
+        public synchronized void reset() throws IOException {
+            this.source.reset();
+            this.count = this.mark;
+        }
+
+        @Override
+        public boolean markSupported() {
+            return this.source.markSupported();
+        }
+
+        @Override
+        public long transferTo(OutputStream out) throws IOException {
+            return super.transferTo(out);
+        }
+
+        long getCount() {
+            return this.count;
+        }
+    }
+
     private static final long[] EMPTY_LONG = new long[0];
     /**
Index: /trunk/test/unit/org/openstreetmap/josm/data/imagery/WMTSTileSourceTest.java
===================================================================
--- /trunk/test/unit/org/openstreetmap/josm/data/imagery/WMTSTileSourceTest.java	(revision 19076)
+++ /trunk/test/unit/org/openstreetmap/josm/data/imagery/WMTSTileSourceTest.java	(revision 19077)
@@ -16,4 +16,5 @@
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
+import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.ArrayList;
@@ -22,5 +23,4 @@
 import java.util.concurrent.TimeUnit;
 
-import org.apache.commons.io.FileUtils;
 import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
@@ -488,10 +488,10 @@
     void testSupportedMimeTypesUrlEncode(String mimeType, @TempDir File temporaryDirectory)
             throws IOException, WMTSGetCapabilitiesException, ReflectiveOperationException {
-        final String data = FileUtils.readFileToString(new File(TestUtils.getTestDataRoot() +
-                "wmts/bug13975-multiple-tile-matrices-for-one-layer-projection.xml"), StandardCharsets.UTF_8)
+        final String data = Files.readString(Paths.get(TestUtils.getTestDataRoot() +
+                        "wmts", "bug13975-multiple-tile-matrices-for-one-layer-projection.xml"), StandardCharsets.UTF_8)
                 .replace("image/jpgpng", mimeType);
-        File file = new File(temporaryDirectory, "testSupportedMimeTypes.xml");
-        FileUtils.writeStringToFile(file, data, StandardCharsets.UTF_8);
-        WMTSCapabilities capabilities = WMTSTileSource.getCapabilities(file.toURI().toURL().toExternalForm(), Collections.emptyMap());
+        Path file = temporaryDirectory.toPath().resolve("testSupportedMimeTypes.xml");
+        Files.writeString(file, data, StandardCharsets.UTF_8);
+        WMTSCapabilities capabilities = WMTSTileSource.getCapabilities(file.toUri().toURL().toExternalForm(), Collections.emptyMap());
         assertEquals(2, capabilities.getLayers().size());
         Field format = WMTSTileSource.Layer.class.getDeclaredField("format");
