Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -248,12 +248,14 @@ public static void setProperty(Object bean, String name, Object value,
Class<?> fieldType = getPropertyUtils().getPropertyType(propertyVlaue, name3);
if (fieldType != null && fieldType.isArray()) {
int length = current == null ? 0 : Array.getLength(current);
Object array = Array.newInstance(fieldType.getComponentType(), Math.max(length, index + 1));
if (length > 0) {
System.arraycopy(current, 0, array, 0, length);
if (length <= index) {
Object array = Array.newInstance(fieldType.getComponentType(), index + 1);
if (length > 0) {
System.arraycopy(current, 0, array, 0, length);
}
getPropertyUtils().setProperty(propertyVlaue, name3, array);
}
Array.set(array, index, value);
getPropertyUtils().setProperty(propertyVlaue, name3, array);
BeanUtils.setProperty(propertyVlaue, name2, value);
} else if (current instanceof List) {
List<Object> list = (List<Object>) current;
while (list.size() <= index) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;

import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream;
import org.apache.commons.compress.compressors.bzip2.BZip2CompressorOutputStream;
Expand Down Expand Up @@ -176,6 +177,9 @@ public static void decompress(File srcFile, boolean delete) throws IOException {

public static void decompress(File srcFile, File destDir) throws IOException {
File destFile = new File(destDir, FilenameUtils.getBaseName(srcFile.getName()));
if (Files.exists(destFile.toPath()) && Files.isSameFile(srcFile.toPath(), destFile.toPath())) {
throw new IOException("Decompression output must differ from compressed input: " + srcFile);
}
try(InputStream input = new FileInputStream(srcFile);
OutputStream output = new FileOutputStream(destFile);) {
BZip2Utils.decompress(input, output);
Expand Down
4 changes: 4 additions & 0 deletions hitool-core/src/main/java/hitool/core/compress/GZipUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;

import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream;
Expand Down Expand Up @@ -194,6 +195,9 @@ public static void decompress(File srcFile, boolean delete) throws IOException {

public static void decompress(File srcFile, File destDir) throws IOException {
File destFile = new File(destDir, FilenameUtils.getBaseName(srcFile.getName()));
if (Files.exists(destFile.toPath()) && Files.isSameFile(srcFile.toPath(), destFile.toPath())) {
throw new IOException("Decompression output must differ from compressed input: " + srcFile);
}
try (InputStream input = new FileInputStream(srcFile);
OutputStream output = new FileOutputStream(destFile);){
GZipUtils.decompress(input, output);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package hitool.core.beanutils;

import org.junit.Test;

import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.fail;

public class BeanPropertyIndexedConversionTest {
@Test
public void convertsFormValuesForExistingAndExpandedNumericArrays() {
Root root = new Root();
root.setChild(new Child());
root.getChild().setNumbers(new int[] {1, 4});

BeanPropertyUtils.setProperty(root, "child.numbers[0]", "2", true);
assertArrayEquals(new int[] {2, 4}, root.getChild().getNumbers());

BeanPropertyUtils.setProperty(root, "child.numbers[3]", new String[] {"7"}, true);
assertArrayEquals(new int[] {2, 4, 0, 7}, root.getChild().getNumbers());
}

@Test
public void initializesNullArraysAndPreservesStringNulls() {
Root root = new Root();
root.setChild(new Child());
BeanPropertyUtils.setProperty(root, "child.numbers[0]", "3", true);
assertArrayEquals(new int[] {3}, root.getChild().getNumbers());

BeanPropertyUtils.setProperty(root, "child.labels[1]", new String[] {"label"}, true);
assertEquals("label", root.getChild().getLabels()[1]);
assertNull(root.getChild().getLabels()[0]);
BeanPropertyUtils.setProperty(root, "child.labels[0]", null, true);
assertNull(root.getChild().getLabels()[0]);
}

@Test
public void retainsBeanUtilsConversionForMalformedAndNullNumericValues() {
Root root = new Root();
root.setChild(new Child());
root.getChild().setNumbers(new int[] {5, 9});
// BeanUtils 1.11.0 converts malformed or null primitive values to zero.
BeanPropertyUtils.setProperty(root, "child.numbers[0]", "not-a-number", true);
assertArrayEquals(new int[] {0, 9}, root.getChild().getNumbers());
BeanPropertyUtils.setProperty(root, "child.numbers[1]", null, true);
assertArrayEquals(new int[] {0, 0}, root.getChild().getNumbers());
}

@Test
public void invalidIndexDoesNotChangeExistingElements() {
Root root = new Root();
root.setChild(new Child());
root.getChild().setNumbers(new int[] {5});
try {
BeanPropertyUtils.setProperty(root, "child.numbers[invalid]", "2", true);
fail("Expected invalid indexed property to fail");
} catch (RuntimeException expected) {
assertArrayEquals(new int[] {5}, root.getChild().getNumbers());
}
}

public static class Root {
private Child child;
public Child getChild() { return child; }
public void setChild(Child child) { this.child = child; }
}

public static class Child {
private int[] numbers;
private String[] labels;
public int[] getNumbers() { return numbers; }
public void setNumbers(int[] numbers) { this.numbers = numbers; }
public String[] getLabels() { return labels; }
public void setLabels(String[] labels) { this.labels = labels; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package hitool.core.compress;

import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;

import org.junit.Test;

import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.fail;

public class CompressionSelfOverwriteTest {
@Test
public void gzipRejectsExtensionlessInputAndSameFileAlias() throws Exception {
byte[] compressed = GZipUtils.compress("payload".getBytes(StandardCharsets.UTF_8));
Path dir = Files.createTempDirectory("hitool-gzip-safety-");
try {
Path source = dir.resolve("payload");
Files.write(source, compressed);
expectIOException(() -> GZipUtils.decompress(source.toFile(), false));
assertArrayEquals(compressed, Files.readAllBytes(source));
expectIOException(() -> GZipUtils.decompress(source.toFile(), dir.toFile()));
assertArrayEquals(compressed, Files.readAllBytes(source));

Path named = dir.resolve("named.gz");
Files.write(named, compressed);
Path alias = dir.resolve("named");
Files.createSymbolicLink(alias, named.getFileName());
expectIOException(() -> GZipUtils.decompress(named.toFile(), dir.toFile()));
assertArrayEquals(compressed, Files.readAllBytes(named));
} finally {
Files.deleteIfExists(dir.resolve("named"));
Files.deleteIfExists(dir.resolve("named.gz"));
Files.deleteIfExists(dir.resolve("payload"));
Files.deleteIfExists(dir);
}
}

@Test
public void bzip2RejectsExtensionlessInputAndSameFileAlias() throws Exception {
byte[] compressed = BZip2Utils.compress("payload".getBytes(StandardCharsets.UTF_8));
Path dir = Files.createTempDirectory("hitool-bzip2-safety-");
try {
Path source = dir.resolve("payload");
Files.write(source, compressed);
expectIOException(() -> BZip2Utils.decompress(source.toFile(), false));
assertArrayEquals(compressed, Files.readAllBytes(source));
expectIOException(() -> BZip2Utils.decompress(source.toFile(), dir.toFile()));
assertArrayEquals(compressed, Files.readAllBytes(source));

Path named = dir.resolve("named.bz2");
Files.write(named, compressed);
Path alias = dir.resolve("named");
Files.createSymbolicLink(alias, named.getFileName());
expectIOException(() -> BZip2Utils.decompress(named.toFile(), dir.toFile()));
assertArrayEquals(compressed, Files.readAllBytes(named));
} finally {
Files.deleteIfExists(dir.resolve("named"));
Files.deleteIfExists(dir.resolve("named.bz2"));
Files.deleteIfExists(dir.resolve("payload"));
Files.deleteIfExists(dir);
}
}

private void expectIOException(ThrowingAction action) throws Exception {
try {
action.run();
fail("Expected IOException before opening the output file");
} catch (IOException expected) {
// The compressed source must remain intact.
}
}

private interface ThrowingAction {
void run() throws Exception;
}
}
Loading