This is an automated email from the ASF dual-hosted git repository.
asf-gitbox-commits pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git
The following commit(s) were added to refs/heads/geoapi-4.0 by this push:
new 05be1817f6 Do not allow a Landsat MLT file to refer a TIFF image
outside the scene directory.
05be1817f6 is described below
commit 05be1817f64eb93d9a35f8cc7a05616c83bb4442
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Wed Sep 2 22:40:21 2026 +0900
Do not allow a Landsat MLT file to refer a TIFF image outside the scene
directory.
---
.../main/module-info.java | 2 +-
.../main/org/apache/sis/storage/landsat/Band.java | 36 ++++--
.../apache/sis/storage/landsat/LandsatStore.java | 14 ++-
.../sis/storage/landsat/LandsatStoreProvider.java | 2 +-
.../apache/sis/storage/landsat/MetadataReader.java | 6 +-
.../sis/storage/landsat/internal/Resources.java | 135 +++++++++++++++++++++
.../storage/landsat/internal/Resources.properties | 22 ++++
.../storage/landsat/internal/Resources_en.java} | 25 ++--
.../storage/landsat/internal/Resources_fr.java} | 25 ++--
.../landsat/internal/Resources_fr.properties | 27 +++++
.../storage/landsat/internal/package-info.java} | 21 ++--
.../apache/sis/storage/landsat/package-info.java | 2 +-
.../storage/landsat/LandsatStoreProviderTest.java | 76 +++++++++++-
.../sis/storage/landsat/MetadataReaderTest.java | 7 +-
.../org.apache.sis.storage/main/module-info.java | 1 +
.../main/org/apache/sis/io/stream/IOUtilities.java | 17 +++
16 files changed, 349 insertions(+), 69 deletions(-)
diff --git
a/endorsed/src/org.apache.sis.storage.earthobservation/main/module-info.java
b/endorsed/src/org.apache.sis.storage.earthobservation/main/module-info.java
index 37a0ea58ef..2d4985925f 100644
--- a/endorsed/src/org.apache.sis.storage.earthobservation/main/module-info.java
+++ b/endorsed/src/org.apache.sis.storage.earthobservation/main/module-info.java
@@ -22,7 +22,7 @@
* @author Thi Phuong Hao Nguyen (VNSC)
* @author Minh Chinh Vu (VNSC)
* @author Martin Desruisseaux (Geomatys)
- * @version 1.4
+ * @version 1.7
* @since 0.8
*/
module org.apache.sis.storage.earthobservation {
diff --git
a/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/Band.java
b/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/Band.java
index 60554ae5d5..4ca9f84e49 100644
---
a/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/Band.java
+++
b/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/Band.java
@@ -23,6 +23,7 @@ import org.opengis.util.GenericName;
import org.opengis.metadata.Metadata;
import org.opengis.metadata.identification.Identification;
import org.opengis.metadata.content.CoverageContentType;
+import org.apache.sis.io.stream.IOUtilities;
import org.apache.sis.storage.GridCoverageResource;
import org.apache.sis.storage.StorageConnector;
import org.apache.sis.storage.DataStoreException;
@@ -39,6 +40,7 @@ import org.apache.sis.metadata.iso.content.DefaultBand;
import org.apache.sis.coverage.SampleDimension;
import org.apache.sis.measure.Units;
import org.apache.sis.util.collection.Containers;
+import org.apache.sis.storage.landsat.internal.Resources;
/**
@@ -67,11 +69,11 @@ final class Band extends GridResourceWrapper implements
CoverageModifier {
LocalName identifier;
/**
- * Filename of the file to read for band data.
- * This is relative to {@link LandsatStore#directory}.
+ * Path to the file to read for getting the band data.
+ * This is resolved against {@link LandsatStore#directory}.
* Should not be modified after the end of metadata parsing.
*/
- String filename;
+ private Path storage;
/**
* Metadata about the band.
@@ -114,7 +116,7 @@ final class Band extends GridResourceWrapper implements
CoverageModifier {
*/
@Override
protected GridCoverageResource createSource() throws DataStoreException {
- final StorageConnector connector = new StorageConnector(getDataPath());
+ final var connector = new StorageConnector(storage);
connector.setOption(OptionKey.COVERAGE_MODIFIER, this);
return new GeoTiffStore(parent, parent.getProvider(), connector,
true).components().get(0);
}
@@ -223,17 +225,29 @@ final class Band extends GridResourceWrapper implements
CoverageModifier {
*/
@Override
public Optional<FileSet> getFileSet() throws DataStoreException {
- return Optional.of(new FileSet(getDataPath()));
+ return Optional.of(new FileSet(storage));
}
/**
- * Resolves path to image file.
+ * Sets the filename if it was not already set.
+ * The filename is rejected if not inside the scene directory.
*/
- private Path getDataPath() {
- if (parent.directory != null) {
- return parent.directory.resolve(filename);
- } else {
- return Path.of(filename);
+ final void setFilename(final String value) {
+ if (storage == null) {
+ final Path base = parent.directory;
+ final Path file = (base != null ? base.resolve(value) :
Path.of(value)).normalize();
+ if (base != null ? file.startsWith(base) :
IOUtilities.isRelativeInsideDirectory(file)) {
+ storage = file;
+ } else {
+
parent.warning(Resources.format(Resources.Keys.BandOutsideSceneDirectory_2,
band.title, value));
+ }
}
}
+
+ /**
+ * Returns whether the mandatory properties have been defined on this band.
+ */
+ final boolean isValid() {
+ return storage != null;
+ }
}
diff --git
a/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/LandsatStore.java
b/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/LandsatStore.java
index b2aadcec4c..a3bbe511f3 100644
---
a/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/LandsatStore.java
+++
b/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/LandsatStore.java
@@ -82,7 +82,7 @@ import org.apache.sis.util.collection.Containers;
*
* @author Thi Phuong Hao Nguyen (VNSC)
* @author Martin Desruisseaux (Geomatys)
- * @version 1.6
+ * @version 1.7
* @since 1.1
*/
public class LandsatStore extends DataStore implements Aggregate {
@@ -143,6 +143,7 @@ public class LandsatStore extends DataStore implements
Aggregate {
connector.closeAllExcept(source);
Path file = null;
if (path != null) {
+ path = path.normalize(); // Needed for
`Band.setFilename(String)`.
if (source != null) {
file = path;
path = path.getParent(); // If the source has been
opened, then the path is a file.
@@ -239,9 +240,9 @@ public class LandsatStore extends DataStore implements
Aggregate {
* The namespace of each identifier is the name of the data set
directory.
*/
resources = new Band[parser.bands.size()];
- for (final Map.Entry<BandName,Band> entry :
parser.bands.entrySet()) {
+ for (final Map.Entry<BandName, Band> entry :
parser.bands.entrySet()) {
final Band component = entry.getValue();
- if (component.filename != null) {
+ if (component.isValid()) {
component.identifier = factory.createLocalName(scope,
entry.getKey().name());
resources[count++] = component;
}
@@ -321,6 +322,13 @@ public class LandsatStore extends DataStore implements
Aggregate {
return Optional.of(new FileSet(paths));
}
+ /**
+ * Logs a warning.
+ */
+ final void warning(final String message) {
+ listeners.warning(message);
+ }
+
/**
* Closes this Landsat store and releases any underlying resources.
* This method can be invoked asynchronously for interrupting a long
reading process.
diff --git
a/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/LandsatStoreProvider.java
b/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/LandsatStoreProvider.java
index 8fa79319a9..00293599ed 100644
---
a/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/LandsatStoreProvider.java
+++
b/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/LandsatStoreProvider.java
@@ -59,7 +59,7 @@ public class LandsatStoreProvider extends DataStoreProvider {
*
* @see #getLogger()
*/
- private static final Logger LOGGER =
Logger.getLogger("org.apache.sis.storage.landsat");
+ static final Logger LOGGER =
Logger.getLogger("org.apache.sis.storage.landsat");
/**
* The parameter descriptor to be returned by {@link #getOpenParameters()}.
diff --git
a/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/MetadataReader.java
b/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/MetadataReader.java
index 348fa06f0b..11d3bfc112 100644
---
a/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/MetadataReader.java
+++
b/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/MetadataReader.java
@@ -573,7 +573,7 @@ final class MetadataReader extends MetadataBuilder {
* This parameter is only present if the band is included in the
product.
*/
case "FILE_NAME_BAND_": {
- band(key, band).ifPresent((b) -> b.filename = value);
+ band(key, band).ifPresent((b) -> b.setFilename(value));
break;
}
/*
@@ -913,7 +913,7 @@ final class MetadataReader extends MetadataBuilder {
final var content = (DefaultCoverageDescription)
Containers.peekIfSingleton(result.getContentInfo());
if (content != null) {
final var groups = new
EnumMap<BandGroupName,DefaultAttributeGroup>(BandGroupName.class);
- for (final EnumMap.Entry<BandName,Band> entry : bands.entrySet()) {
+ for (final EnumMap.Entry<BandName, Band> entry : bands.entrySet())
{
final DefaultAttributeGroup g =
groups.computeIfAbsent(entry.getKey().group, (k) -> {
var ag = new
DefaultAttributeGroup(CoverageContentType.PHYSICAL_MEASUREMENT, null);
content.getAttributeGroups().add(ag);
@@ -952,7 +952,7 @@ final class MetadataReader extends MetadataBuilder {
if (key != null) {
String file = getFilename();
if (reader instanceof LineNumberReader) {
- file = file + ":" + ((LineNumberReader)
reader).getLineNumber();
+ file = file + ':' + ((LineNumberReader)
reader).getLineNumber();
}
key = errors().getString(Errors.Keys.CanNotReadPropertyInFile_2,
toLongName(key), file);
}
diff --git
a/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/internal/Resources.java
b/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/internal/Resources.java
new file mode 100644
index 0000000000..392c0e7a29
--- /dev/null
+++
b/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/internal/Resources.java
@@ -0,0 +1,135 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.storage.landsat.internal;
+
+import java.io.InputStream;
+import java.lang.reflect.Field;
+import java.util.Locale;
+import java.util.MissingResourceException;
+import org.apache.sis.util.resources.KeyConstants;
+import org.apache.sis.util.resources.IndexedResourceBundle;
+
+
+/**
+ * Warning and error messages that are specific to the Landsat module.
+ * Resources in this file should not be used by any other module.
+ * For resources shared by many modules in the Apache <abbr>SIS</abbr> project,
+ * see the {@code org.apache.sis.util.resources} package.
+ *
+ * @author Martin Desruisseaux (IRD, Geomatys)
+ */
+public class Resources extends IndexedResourceBundle {
+ /**
+ * Resource keys. This class is used when compiling sources, but no
dependencies to
+ * {@code Keys} should appear in any resulting class files. Since the Java
compiler
+ * inlines final integer values, using long identifiers will not bloat the
constant
+ * pools of compiled classes.
+ *
+ * @author Martin Desruisseaux (IRD, Geomatys)
+ */
+ public static final class Keys extends KeyConstants {
+ /**
+ * The unique instance of key constants handler.
+ */
+ static final Keys INSTANCE = new Keys();
+
+ /**
+ * For {@link #INSTANCE} creation only.
+ */
+ private Keys() {
+ }
+
+ /**
+ * Returns the value of a field declared in this {@code Keys} class.
+ * This method is needed for encapsulation reason, because classes in
+ * other modules cannot access this class even by reflection.
+ */
+ @Override
+ protected Object getStaticValue(final Field field) throws
IllegalAccessException {
+ if (field.getDeclaringClass() == Keys.class) {
+ return field.get(null);
+ }
+ throw new IllegalAccessException();
+ }
+
+ /**
+ * File “{1}” of band “{0}” is outside the scene directory.
+ */
+ public static final short BandOutsideSceneDirectory_2 = 1;
+ }
+
+ /**
+ * Constructs a new resource bundle loading data from
+ * the resource file of the same name as this class.
+ */
+ public Resources() {
+ }
+
+ /**
+ * Opens the binary file containing the localized resources to load.
+ * This method delegates to {@link Class#getResourceAsStream(String)},
+ * but this delegation must be done from the same module as the one
+ * that provides the binary file.
+ */
+ @Override
+ protected InputStream getResourceAsStream(final String name) {
+ return getClass().getResourceAsStream(name);
+ }
+
+ /**
+ * Returns the handle for the {@code Keys} constants.
+ *
+ * @return a handler for the constants declared in the inner {@code Keys}
class.
+ */
+ @Override
+ protected KeyConstants getKeyConstants() {
+ return Keys.INSTANCE;
+ }
+
+ /**
+ * Returns resources in the given locale.
+ *
+ * @param locale the locale, or {@code null} for the default locale.
+ * @return resources in the given locale.
+ * @throws MissingResourceException if resources cannot be found.
+ */
+ public static Resources forLocale(final Locale locale) {
+ /*
+ * We cannot factorize this method into the parent class, because we
need to call
+ * `ResourceBundle.getBundle(String)` from the module that provides
the resources.
+ * We do not cache the result because `ResourceBundle` already
provides a cache.
+ */
+ return (Resources) getBundle(Resources.class.getName(),
nonNull(locale));
+ }
+
+ /**
+ * Gets a string for the given key and replaces all occurrence of "{0}"
+ * with value of {@code arg0}.
+ *
+ * @param key the key for the desired string.
+ * @param arg0 value to substitute to "{0}".
+ * @param arg1 value to substitute to "{1}".
+ * @return the formatted string for the given key.
+ * @throws MissingResourceException if no object for the given key can be
found.
+ */
+ public static String format(final short key,
+ final Object arg0,
+ final Object arg1)
+ {
+ return forLocale(null).getString(key, arg0, arg1);
+ }
+}
diff --git
a/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/internal/Resources.properties
b/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/internal/Resources.properties
new file mode 100644
index 0000000000..6bcdbc68f4
--- /dev/null
+++
b/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/internal/Resources.properties
@@ -0,0 +1,22 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+# Resources in this file are for Landsat module usage only and should not be
used by any other module.
+# For resources shared by all modules in the Apache SIS project, see
"org.apache.sis.util.resources" package.
+#
+BandOutsideSceneDirectory_2 = File \u201c{1}\u201d of band \u201c{0}\u201d is
outside the scene directory.
diff --git
a/endorsed/src/org.apache.sis.storage.earthobservation/main/module-info.java
b/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/internal/Resources_en.java
similarity index 62%
copy from
endorsed/src/org.apache.sis.storage.earthobservation/main/module-info.java
copy to
endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/internal/Resources_en.java
index 37a0ea58ef..a2d900e951 100644
--- a/endorsed/src/org.apache.sis.storage.earthobservation/main/module-info.java
+++
b/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/internal/Resources_en.java
@@ -14,22 +14,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package org.apache.sis.storage.landsat.internal;
+
/**
- * Earth observation stores.
- *
- * @author Rémi Maréchal (Geomatys)
- * @author Thi Phuong Hao Nguyen (VNSC)
- * @author Minh Chinh Vu (VNSC)
- * @author Martin Desruisseaux (Geomatys)
- * @version 1.4
- * @since 0.8
+ * Resource in English language.
*/
-module org.apache.sis.storage.earthobservation {
- requires transitive org.apache.sis.storage.geotiff;
-
- provides org.apache.sis.storage.DataStoreProvider
- with org.apache.sis.storage.landsat.LandsatStoreProvider;
-
- exports org.apache.sis.storage.landsat;
+public class Resources_en extends Resources {
+ /**
+ * Constructs a new resource bundle loading data from
+ * the resource file of the same name as this class.
+ */
+ public Resources_en() {
+ }
}
diff --git
a/endorsed/src/org.apache.sis.storage.earthobservation/main/module-info.java
b/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/internal/Resources_fr.java
similarity index 62%
copy from
endorsed/src/org.apache.sis.storage.earthobservation/main/module-info.java
copy to
endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/internal/Resources_fr.java
index 37a0ea58ef..1b0e5c6449 100644
--- a/endorsed/src/org.apache.sis.storage.earthobservation/main/module-info.java
+++
b/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/internal/Resources_fr.java
@@ -14,22 +14,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package org.apache.sis.storage.landsat.internal;
+
/**
- * Earth observation stores.
- *
- * @author Rémi Maréchal (Geomatys)
- * @author Thi Phuong Hao Nguyen (VNSC)
- * @author Minh Chinh Vu (VNSC)
- * @author Martin Desruisseaux (Geomatys)
- * @version 1.4
- * @since 0.8
+ * Messages in French language.
*/
-module org.apache.sis.storage.earthobservation {
- requires transitive org.apache.sis.storage.geotiff;
-
- provides org.apache.sis.storage.DataStoreProvider
- with org.apache.sis.storage.landsat.LandsatStoreProvider;
-
- exports org.apache.sis.storage.landsat;
+public class Resources_fr extends Resources {
+ /**
+ * Constructs a new resource bundle loading data from
+ * the resource file of the same name as this class.
+ */
+ public Resources_fr() {
+ }
}
diff --git
a/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/internal/Resources_fr.properties
b/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/internal/Resources_fr.properties
new file mode 100644
index 0000000000..ecaeed58dc
--- /dev/null
+++
b/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/internal/Resources_fr.properties
@@ -0,0 +1,27 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+# Resources in this file are for Landsat module usage only and should not be
used by any other module.
+# For resources shared by all modules in the Apache SIS project, see
"org.apache.sis.util.resources" package.
+#
+# Punctuation rules in French (source:
http://unicode.org/udhr/n/notes_fra.html)
+#
+# U+202F NARROW NO-BREAK SPACE before ; ! and ?
+# U+00A0 NO-BREAK SPACE before :
+#
+BandOutsideSceneDirectory_2 = Le fichier \u00ab\u202f{1}\u202f\u00bb de la
bande \u00ab\u202f{0}\u202f\u00bb est en dehors du dossier de la sc\u00e8ne.
diff --git
a/endorsed/src/org.apache.sis.storage.earthobservation/main/module-info.java
b/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/internal/package-info.java
similarity index 65%
copy from
endorsed/src/org.apache.sis.storage.earthobservation/main/module-info.java
copy to
endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/internal/package-info.java
index 37a0ea58ef..075ca5ba26 100644
--- a/endorsed/src/org.apache.sis.storage.earthobservation/main/module-info.java
+++
b/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/internal/package-info.java
@@ -16,20 +16,13 @@
*/
/**
- * Earth observation stores.
+ * Shared classes for the implementation of Landsat reader.
+ *
+ * <STRONG>Do not use!</STRONG>
+ *
+ * This package is for internal use by Apache <abbr>SIS</abbr> only.
+ * Classes in this package may change in incompatible ways in any future
version without notice.
*
- * @author Rémi Maréchal (Geomatys)
- * @author Thi Phuong Hao Nguyen (VNSC)
- * @author Minh Chinh Vu (VNSC)
* @author Martin Desruisseaux (Geomatys)
- * @version 1.4
- * @since 0.8
*/
-module org.apache.sis.storage.earthobservation {
- requires transitive org.apache.sis.storage.geotiff;
-
- provides org.apache.sis.storage.DataStoreProvider
- with org.apache.sis.storage.landsat.LandsatStoreProvider;
-
- exports org.apache.sis.storage.landsat;
-}
+package org.apache.sis.storage.landsat.internal;
diff --git
a/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/package-info.java
b/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/package-info.java
index 51af8892be..bed1f0742a 100644
---
a/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/package-info.java
+++
b/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/package-info.java
@@ -27,7 +27,7 @@
* @author Thi Phuong Hao Nguyen (VNSC)
* @author Minh Chinh Vu (VNSC)
* @author Martin Desruisseaux (Geomatys)
- * @version 1.6
+ * @version 1.7
* @since 1.1
*/
package org.apache.sis.storage.landsat;
diff --git
a/endorsed/src/org.apache.sis.storage.earthobservation/test/org/apache/sis/storage/landsat/LandsatStoreProviderTest.java
b/endorsed/src/org.apache.sis.storage.earthobservation/test/org/apache/sis/storage/landsat/LandsatStoreProviderTest.java
index e00d32e595..d976dfac47 100644
---
a/endorsed/src/org.apache.sis.storage.earthobservation/test/org/apache/sis/storage/landsat/LandsatStoreProviderTest.java
+++
b/endorsed/src/org.apache.sis.storage.earthobservation/test/org/apache/sis/storage/landsat/LandsatStoreProviderTest.java
@@ -16,7 +16,15 @@
*/
package org.apache.sis.storage.landsat;
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Files;
import java.nio.charset.StandardCharsets;
+import org.apache.sis.storage.Resource;
+import org.apache.sis.storage.Aggregate;
import org.apache.sis.storage.OptionKey;
import org.apache.sis.storage.ProbeResult;
import org.apache.sis.storage.StorageConnector;
@@ -24,8 +32,10 @@ import org.apache.sis.storage.DataStoreException;
// Test dependencies
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
import static org.junit.jupiter.api.Assertions.*;
-import org.apache.sis.test.TestCase;
+import static org.apache.sis.test.Assertions.assertSingleton;
+import org.apache.sis.test.TestCaseWithLogs;
/**
@@ -33,11 +43,13 @@ import org.apache.sis.test.TestCase;
*
* @author Martin Desruisseaux (Geomatys)
*/
-public final class LandsatStoreProviderTest extends TestCase {
+@SuppressWarnings("exports")
+public final class LandsatStoreProviderTest extends TestCaseWithLogs {
/**
* Creates a new test case.
*/
public LandsatStoreProviderTest() {
+ super(LandsatStoreProvider.LOGGER);
}
/**
@@ -47,9 +59,65 @@ public final class LandsatStoreProviderTest extends TestCase
{
*/
@Test
public void testProbeContentFromReader() throws DataStoreException {
- final StorageConnector connector = new
StorageConnector(MetadataReaderTest.class.getResourceAsStream("LandsatTest.txt"));
+ final var connector = new
StorageConnector(MetadataReaderTest.class.getResourceAsStream("LandsatTest.txt"));
connector.setOption(OptionKey.ENCODING, StandardCharsets.UTF_8);
- final LandsatStoreProvider provider = new LandsatStoreProvider();
+ final var provider = new LandsatStoreProvider();
assertEquals(ProbeResult.SUPPORTED, provider.probeContent(connector));
+ loggings.assertNoUnexpectedLog();
+ }
+
+ /**
+ * Creates a temporary file with one band and read it.
+ * The path of the image for the single band is returned.
+ *
+ * @param tmpDir temporary directory where to write a scene.
+ * @param sceneName name of the scene. Will be the sub-directory
filename.
+ * @param tiffFile path of the <abbr>TIFF</abbr> file.
+ * @return paths of the file as provided by the resource.
+ * @throws IOException if an error occurred while writing the temporary
file.
+ * @throws DataStoreException if an error occurred while reading the
temporary file.
+ */
+ private static Collection<Path> readSingleBand(final Path tmpDir, final
String sceneName, final String tiffFile)
+ throws IOException, DataStoreException
+ {
+ final Path sceneDir =
Files.createDirectories(tmpDir.resolve(sceneName));
+ final Path sceneFile = sceneDir.resolve(sceneName + "_MTL.txt");
+ Files.write(sceneFile, Arrays.asList(
+ "GROUP = LANDSAT_METADATA_FILE",
+ " GROUP = PRODUCT_CONTENTS",
+ " FILE_NAME_BAND_1 = \"" + tiffFile + "\"",
+ " END_GROUP = PRODUCT_CONTENTS",
+ "END_GROUP = LANDSAT_METADATA_FILE",
+ "END"));
+
+ final var paths = new ArrayList<Path>();
+ try (var store = new LandsatStore(null, new
StorageConnector(sceneDir))) {
+ for (Resource component : store.components()) {
+ Aggregate group = assertInstanceOf(Aggregate.class, component);
+ Resource band = assertSingleton(group.components());
+ paths.addAll(band.getFileSet().orElseThrow().getPaths());
+ }
+ }
+ return paths;
+ }
+
+ /**
+ * Verifies that the Landsat reader detects when a band path is outside
the scene directory.
+ *
+ * @param tmpDir temporary directory where to write a scene.
+ * @throws IOException if an error occurred while writing the temporary
file.
+ * @throws DataStoreException if an error occurred while reading the
temporary file.
+ */
+ @Test
+ public void testBandPathValidation(@TempDir final Path tmpDir)
+ throws IOException, DataStoreException
+ {
+ final Path expected = tmpDir.resolve("valid", "B1.TIFF");
+ final Path actual = assertSingleton(readSingleBand(tmpDir, "valid",
"B1.TIFF"));
+ assertEquals(expected.toAbsolutePath(), actual.toAbsolutePath());
+ loggings.assertNoUnexpectedLog();
+ assertTrue(readSingleBand(tmpDir, "invalid",
"../outside/secret.tiff").isEmpty());
+ loggings.assertNextLogContains("../outside/secret.tiff", "Coastal
Aerosol");
+ loggings.assertNoUnexpectedLog();
}
}
diff --git
a/endorsed/src/org.apache.sis.storage.earthobservation/test/org/apache/sis/storage/landsat/MetadataReaderTest.java
b/endorsed/src/org.apache.sis.storage.earthobservation/test/org/apache/sis/storage/landsat/MetadataReaderTest.java
index bc1b7c8544..795682b9f2 100644
---
a/endorsed/src/org.apache.sis.storage.earthobservation/test/org/apache/sis/storage/landsat/MetadataReaderTest.java
+++
b/endorsed/src/org.apache.sis.storage.earthobservation/test/org/apache/sis/storage/landsat/MetadataReaderTest.java
@@ -28,6 +28,7 @@ import static java.util.Map.entry;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
+import java.io.StringReader;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import org.opengis.metadata.Metadata;
@@ -45,6 +46,7 @@ import org.opengis.metadata.spatial.DimensionNameType;
import org.opengis.util.FactoryException;
import org.apache.sis.storage.AbstractResource;
import org.apache.sis.storage.DataStoreException;
+import org.apache.sis.storage.StorageConnector;
import org.apache.sis.storage.event.StoreListeners;
import org.opengis.test.dataset.ContentVerifier;
@@ -55,6 +57,7 @@ import org.opengis.test.dataset.ContentVerifier;
* @author Thi Phuong Hao Nguyen (VNSC)
* @author Martin Desruisseaux (Geomatys)
*/
+@SuppressWarnings("exports")
public final class MetadataReaderTest extends TestCase {
/**
* Helper class for verifying metadata content.
@@ -99,7 +102,9 @@ public final class MetadataReaderTest extends TestCase {
try (BufferedReader in = new BufferedReader(new InputStreamReader(
MetadataReaderTest.class.getResourceAsStream("LandsatTest.txt"), "UTF-8")))
{
- final MetadataReader reader = new MetadataReader(null,
"LandsatTest.txt", createListeners());
+ final var store = new LandsatStore(null, new StorageConnector(
+ new StringReader("GROUP = LANDSAT_METADATA_FILE\nEND")));
+ final var reader = new MetadataReader(store, "LandsatTest.txt",
createListeners());
reader.read(in);
actual = reader.getMetadata();
}
diff --git a/endorsed/src/org.apache.sis.storage/main/module-info.java
b/endorsed/src/org.apache.sis.storage/main/module-info.java
index baf79ec7e3..024b42f67a 100644
--- a/endorsed/src/org.apache.sis.storage/main/module-info.java
+++ b/endorsed/src/org.apache.sis.storage/main/module-info.java
@@ -84,6 +84,7 @@ module org.apache.sis.storage {
org.apache.sis.storage.netcdf,
org.apache.sis.storage.geoheif,
org.apache.sis.storage.geotiff,
+ org.apache.sis.storage.earthobservation,
org.apache.sis.storage.json, // In the "incubator"
sub-project.
org.apache.sis.storage.shapefile, // In the "incubator"
sub-project.
org.apache.sis.storage.geopackage, // In the "incubator"
sub-project.
diff --git
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/io/stream/IOUtilities.java
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/io/stream/IOUtilities.java
index b2d2ece27e..cbe5b8c131 100644
---
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/io/stream/IOUtilities.java
+++
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/io/stream/IOUtilities.java
@@ -559,6 +559,23 @@ check: if (stream instanceof ChannelData) {
return false;
}
+ /**
+ * Returns {@code true} if the given file is relative and does not go up
in the parent directory.
+ * Callers should invoke {@link Path#normalize()} before this method.
+ *
+ * @param path the path to test.
+ * @return whether the given path is relative and does not go up in the
parent directory.
+ */
+ public static boolean isRelativeInsideDirectory(final Path path) {
+ if (path.isAbsolute()) {
+ return false;
+ }
+ if (path.getNameCount() != 0 &&
path.getName(0).toString().startsWith(".")) {
+ return false;
+ }
+ return true;
+ }
+
/**
* Returns {@code true} if the file at the specified path is absent or an
empty file.
* If the file exists but is not a regular file, then this method returns
{@code false}.