diff --git a/fileformat/src/main/java/de/bmarwell/zchunk/fileformat/HeaderChecksumType.java b/fileformat/src/main/java/de/bmarwell/zchunk/fileformat/HeaderChecksumType.java
index e5cd704..4f11ca0 100644
--- a/fileformat/src/main/java/de/bmarwell/zchunk/fileformat/HeaderChecksumType.java
+++ b/fileformat/src/main/java/de/bmarwell/zchunk/fileformat/HeaderChecksumType.java
@@ -16,35 +16,69 @@
package de.bmarwell.zchunk.fileformat;
+import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
import java.util.StringJoiner;
+import java.util.logging.Logger;
/**
* 0 = SHA-1
* 1 = SHA-256
*/
public enum HeaderChecksumType {
- SHA1("SHA-1"),
- SHA256("SHA-256");
+ UNKNOWN("unknown", -1L, 0),
+ SHA1("SHA-1", 0L, -1),
+ SHA256("SHA-256", 1L, -1);
private final String digestAlgorithm;
private final int digestLength;
+ /**
+ * Constant and unique value as from {@code codezchunk_format.txt}.
+ */
+ private final long identifier;
- HeaderChecksumType(final String digestAlgorithm) {
+ HeaderChecksumType(final String digestAlgorithm, final long identifier, final int manualDigestLength) {
try {
this.digestAlgorithm = digestAlgorithm;
- this.digestLength = MessageDigest.getInstance(digestAlgorithm).getDigestLength();
+ if (manualDigestLength <= -1) {
+ // use default
+ this.digestLength = MessageDigest.getInstance(digestAlgorithm).getDigestLength();
+ } else {
+ this.digestLength = manualDigestLength;
+ }
+
+ this.identifier = identifier;
} catch (final NoSuchAlgorithmException algoEx) {
throw new IllegalArgumentException("Unable to create hashing algorithm: [" + digestAlgorithm + "]. Check your JVM settings.", algoEx);
}
}
+ public static HeaderChecksumType find(final BigInteger unsignedLongValue) {
+ if (unsignedLongValue.compareTo(BigInteger.valueOf(Integer.MAX_VALUE)) >= 1) {
+ final String message = String.format("Unknown Checksum type: [%s], exeeds [%d]!", unsignedLongValue.toString(), Integer.MAX_VALUE);
+ Logger.getLogger(HeaderChecksumType.class.getCanonicalName()).warning(message);
+ return UNKNOWN;
+ }
+
+ final long requestedId = unsignedLongValue.longValue();
+
+ return Arrays.stream(values())
+ .filter(algo -> algo.identifier == requestedId)
+ .findFirst()
+ .orElse(UNKNOWN);
+ }
+
public int getDigestLength() {
return this.digestLength;
}
- public MessageDigest digest() {
+ public long getIdentifier() {
+ return this.identifier;
+ }
+
+ public MessageDigest getMessageDigest() {
try {
return MessageDigest.getInstance(this.digestAlgorithm);
} catch (final NoSuchAlgorithmException algoEx) {
@@ -57,6 +91,7 @@ public String toString() {
return new StringJoiner(", ", HeaderChecksumType.class.getSimpleName() + "[", "]")
.add("digestAlgorithm=" + this.digestAlgorithm)
.add("digestLength=" + this.digestLength)
+ .add("identifier=" + this.identifier)
.add("ordinal=" + this.ordinal())
.toString();
}
diff --git a/fileformat/src/main/java/de/bmarwell/zchunk/fileformat/IndexChecksumType.java b/fileformat/src/main/java/de/bmarwell/zchunk/fileformat/IndexChecksumType.java
index 6636ae5..3f8cc32 100644
--- a/fileformat/src/main/java/de/bmarwell/zchunk/fileformat/IndexChecksumType.java
+++ b/fileformat/src/main/java/de/bmarwell/zchunk/fileformat/IndexChecksumType.java
@@ -33,16 +33,16 @@ public enum IndexChecksumType {
SHA512("SHA-512", -1),
SHA512_128("SHA-512", 16);
- private final MessageDigest digestAlgorithm;
+ private final String digestAlgorithm;
private final int length;
IndexChecksumType(final String digestAlgorithm, final int length) {
try {
- this.digestAlgorithm = MessageDigest.getInstance(digestAlgorithm);
+ this.digestAlgorithm = digestAlgorithm;
if (length != -1) {
this.length = length;
} else {
- this.length = this.digestAlgorithm.getDigestLength();
+ this.length = MessageDigest.getInstance(digestAlgorithm).getDigestLength();
}
} catch (final NoSuchAlgorithmException algoEx) {
throw new IllegalArgumentException("Unable to create hashing algorithm: [" + digestAlgorithm + "]. Check your JVM settings.", algoEx);
@@ -54,9 +54,9 @@ public int actualChecksumLength() {
}
public byte[] digest(final byte[] input) {
- final byte[] digest = this.digestAlgorithm.digest(input);
+ final byte[] digest = this.getMessageDigest().digest(input);
- if (this.length != this.digestAlgorithm.getDigestLength()) {
+ if (this.length != getMessageDigest().getDigestLength()) {
final byte[] actualDigest = new byte[this.length];
System.arraycopy(digest, 0, actualDigest, 0, this.length);
return actualDigest;
@@ -65,10 +65,18 @@ public byte[] digest(final byte[] input) {
return digest;
}
+ public MessageDigest getMessageDigest() {
+ try {
+ return MessageDigest.getInstance(this.digestAlgorithm);
+ } catch (final NoSuchAlgorithmException algoEx) {
+ throw new IllegalStateException("Unable to create message getMessageDigest instance!", algoEx);
+ }
+ }
+
@Override
public String toString() {
return new StringJoiner(", ", IndexChecksumType.class.getSimpleName() + "[", "]")
- .add("digestAlgorithm=" + this.digestAlgorithm.getAlgorithm())
+ .add("digestAlgorithm=" + this.digestAlgorithm)
.add("actualChecksumLength=" + this.length)
.add("ordinal=" + this.ordinal())
.toString();
diff --git a/fileformat/src/main/java/de/bmarwell/zchunk/fileformat/ZChunk.java b/fileformat/src/main/java/de/bmarwell/zchunk/fileformat/ZChunk.java
new file mode 100644
index 0000000..5d29d29
--- /dev/null
+++ b/fileformat/src/main/java/de/bmarwell/zchunk/fileformat/ZChunk.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2019, the zchunk-java contributors.
+ *
+ * Licensed 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 de.bmarwell.zchunk.fileformat;
+
+import de.bmarwell.zchunk.fileformat.err.InvalidFileException;
+import de.bmarwell.zchunk.fileformat.util.ChecksumUtil;
+import java.io.File;
+
+public class ZChunk {
+
+ /**
+ * Reads in a zchunk file.
+ *
+ *
The header part will stay in memory (heap).
+ * The data streams and/or chunks will be available as inputstream, but are not
+ * eagerly loaded into memory.
+ *
+ * @param input
+ * the input file.
+ * @return a {@link ZChunkFile} instance.
+ * @throws InvalidFileException
+ * if the input file is not a zchunk file.
+ * @throws NullPointerException
+ * if the input file is {@code null}.
+ */
+ public static ZChunkFile fromFile(final File input) {
+ final ZChunkHeader header = ZChunkHeaderFactory.getZChunkFileHeader(input);
+
+ return ImmutableZChunkFile.builder().header(header).build();
+ }
+
+ public static boolean validateFile(final File file) {
+ final ZChunkFile zChunkFile = fromFile(file);
+ final ZChunkHeader header = zChunkFile.getHeader();
+
+ return ChecksumUtil.isValidHeader(header)
+ && ChecksumUtil.allChunksAreValid(header, file)
+ && ChecksumUtil.isValidData(header, file);
+ }
+
+}
diff --git a/fileformat/src/main/java/de/bmarwell/zchunk/fileformat/ZChunkHeaderChunkInfo.java b/fileformat/src/main/java/de/bmarwell/zchunk/fileformat/ZChunkHeaderChunkInfo.java
index c5d28a4..f7a8426 100644
--- a/fileformat/src/main/java/de/bmarwell/zchunk/fileformat/ZChunkHeaderChunkInfo.java
+++ b/fileformat/src/main/java/de/bmarwell/zchunk/fileformat/ZChunkHeaderChunkInfo.java
@@ -18,6 +18,7 @@
import de.bmarwell.zchunk.compressedint.CompressedInt;
import de.bmarwell.zchunk.fileformat.util.ByteUtils;
+import java.util.Comparator;
import java.util.Optional;
import java.util.StringJoiner;
import org.immutables.value.Value;
@@ -38,6 +39,8 @@
@Value.Immutable
public abstract class ZChunkHeaderChunkInfo {
+ public static final Comparator INDEX_COMPARATOR = Comparator.comparing(ZChunkHeaderChunkInfo::getCurrentIndex);
+
public abstract long getCurrentIndex();
public abstract Optional getChunkStream();
diff --git a/fileformat/src/main/java/de/bmarwell/zchunk/fileformat/ZChunkHeaderFactory.java b/fileformat/src/main/java/de/bmarwell/zchunk/fileformat/ZChunkHeaderFactory.java
index 5cc936c..a9451de 100644
--- a/fileformat/src/main/java/de/bmarwell/zchunk/fileformat/ZChunkHeaderFactory.java
+++ b/fileformat/src/main/java/de/bmarwell/zchunk/fileformat/ZChunkHeaderFactory.java
@@ -17,6 +17,7 @@
package de.bmarwell.zchunk.fileformat;
import static de.bmarwell.zchunk.fileformat.ZChunkConstants.Header.MAX_LEAD_SIZE;
+import static java.util.stream.Collectors.toConcurrentMap;
import de.bmarwell.zchunk.compressedint.CompressedInt;
import de.bmarwell.zchunk.compressedint.CompressedIntFactory;
@@ -36,6 +37,7 @@
import java.math.BigInteger;
import java.nio.channels.Channels;
import java.util.Set;
+import java.util.function.Function;
import java.util.logging.Logger;
public final class ZChunkHeaderFactory {
@@ -46,29 +48,11 @@ private ZChunkHeaderFactory() {
//
}
- /**
- * Reads in a zchunk file.
- *
- * The header part will stay in memory (heap).
- * The data streams and/or chunks will be available as inputstream, but are not
- * eagerly loaded into memory.
- *
- * @param input
- * the input file.
- * @return a {@link ZChunkFile} instance.
- * @throws InvalidFileException
- * if the input file is not a zchunk file.
- * @throws NullPointerException
- * if the input file is {@code null}.
- */
- public static ZChunkFile fromFile(final File input) {
- final ZChunkHeader header = getZChunkFileHeader(input);
-
- return ImmutableZChunkFile.builder().header(header).build();
- }
-
- private static ZChunkHeader getZChunkFileHeader(final File input) {
+ public static ZChunkHeader getZChunkFileHeader(final File input) {
final ZChunkHeaderLead lead = readFileHeaderLead(input);
+ if (lead.getChecksumType() == HeaderChecksumType.UNKNOWN) {
+ throw new UnsupportedOperationException("Unknown getMessageDigest type: [" + lead.getChecksumType() + "].");
+ }
final byte[] completeHeader = readCompleteHeader(input, lead);
final ZChunkHeaderPreface preface = readHeaderPreface(completeHeader, lead);
final ZChunkHeaderIndex index = readHeaderIndex(completeHeader, lead, preface);
@@ -235,7 +219,8 @@ private static ZChunkHeaderIndex readHeaderIndex(final byte[] completeHeader, fi
.dictChecksum(parser.readDictChecksum())
.dictLength(parser.readDictLength())
.uncompressedDictLength(parser.readUncompressedDictLength())
- .addAllChunkInfo(parser.readChunkInfos())
+ .putAllChunkInfo(parser.readChunkInfos().stream()
+ .collect(toConcurrentMap(ZChunkHeaderChunkInfo::getChunkChecksum, Function.identity())))
.build();
}
diff --git a/fileformat/src/main/java/de/bmarwell/zchunk/fileformat/ZChunkHeaderIndex.java b/fileformat/src/main/java/de/bmarwell/zchunk/fileformat/ZChunkHeaderIndex.java
index 0e7fff5..1f12dd9 100644
--- a/fileformat/src/main/java/de/bmarwell/zchunk/fileformat/ZChunkHeaderIndex.java
+++ b/fileformat/src/main/java/de/bmarwell/zchunk/fileformat/ZChunkHeaderIndex.java
@@ -18,9 +18,13 @@
import de.bmarwell.zchunk.compressedint.CompressedInt;
import de.bmarwell.zchunk.fileformat.util.ByteUtils;
-import java.util.List;
+import java.util.Map;
import java.util.Optional;
+import java.util.Set;
import java.util.StringJoiner;
+import java.util.TreeSet;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
import org.immutables.value.Value;
/**
@@ -80,7 +84,17 @@ public IndexChecksumType getChunkChecksumType() {
public abstract CompressedInt getUncompressedDictLength();
- public abstract List getChunkInfo();
+ public abstract Map getChunkInfo();
+
+ @Value.Lazy
+ public Set getChunkInfoSortedByIndex() {
+ final Supplier> IndexSortedList = () -> new TreeSet<>(ZChunkHeaderChunkInfo.INDEX_COMPARATOR);
+
+ return getChunkInfo().values()
+ .stream()
+ .sorted(ZChunkHeaderChunkInfo.INDEX_COMPARATOR)
+ .collect(Collectors.toCollection(IndexSortedList));
+ }
@Override
public String toString() {
diff --git a/fileformat/src/main/java/de/bmarwell/zchunk/fileformat/ZChunkHeaderLead.java b/fileformat/src/main/java/de/bmarwell/zchunk/fileformat/ZChunkHeaderLead.java
index 96a8621..82e8898 100644
--- a/fileformat/src/main/java/de/bmarwell/zchunk/fileformat/ZChunkHeaderLead.java
+++ b/fileformat/src/main/java/de/bmarwell/zchunk/fileformat/ZChunkHeaderLead.java
@@ -41,7 +41,7 @@ public abstract class ZChunkHeaderLead {
@Value.Derived
public HeaderChecksumType getChecksumType() {
- return HeaderChecksumType.values()[getChecksumTypeInt().getIntValue()];
+ return HeaderChecksumType.find(getChecksumTypeInt().getValue());
}
/**
diff --git a/fileformat/src/main/java/de/bmarwell/zchunk/fileformat/parser/ZChunkIndexParser.java b/fileformat/src/main/java/de/bmarwell/zchunk/fileformat/parser/ZChunkIndexParser.java
index ea84f89..ccc0979 100644
--- a/fileformat/src/main/java/de/bmarwell/zchunk/fileformat/parser/ZChunkIndexParser.java
+++ b/fileformat/src/main/java/de/bmarwell/zchunk/fileformat/parser/ZChunkIndexParser.java
@@ -176,7 +176,7 @@ public CompressedInt readUncompressedDictLength() {
}
}
- public Iterable extends ZChunkHeaderChunkInfo> readChunkInfos() {
+ public List extends ZChunkHeaderChunkInfo> readChunkInfos() {
if (this.chunkStreamOffset == -1L) {
readUncompressedDictLength();
}
diff --git a/fileformat/src/main/java/de/bmarwell/zchunk/fileformat/parser/ZChunkLeadParser.java b/fileformat/src/main/java/de/bmarwell/zchunk/fileformat/parser/ZChunkLeadParser.java
index 3dfe80e..db7bbeb 100644
--- a/fileformat/src/main/java/de/bmarwell/zchunk/fileformat/parser/ZChunkLeadParser.java
+++ b/fileformat/src/main/java/de/bmarwell/zchunk/fileformat/parser/ZChunkLeadParser.java
@@ -105,7 +105,7 @@ public CompressedInt readLeadCksumType() {
final CompressedInt checksumType = CompressedIntFactory.readCompressedInt(bis);
this.headerSizeOffset = FILE_MAGIC.length + (long) checksumType.getCompressedBytes().length;
- this.checksumType = HeaderChecksumType.values()[checksumType.getIntValue()];
+ this.checksumType = HeaderChecksumType.find(checksumType.getValue());
return checksumType;
} catch (final IOException ioEx) {
diff --git a/fileformat/src/main/java/de/bmarwell/zchunk/fileformat/util/ChecksumUtil.java b/fileformat/src/main/java/de/bmarwell/zchunk/fileformat/util/ChecksumUtil.java
index c42ac63..d1a1266 100644
--- a/fileformat/src/main/java/de/bmarwell/zchunk/fileformat/util/ChecksumUtil.java
+++ b/fileformat/src/main/java/de/bmarwell/zchunk/fileformat/util/ChecksumUtil.java
@@ -20,27 +20,38 @@
import static java.util.stream.Collectors.toList;
import de.bmarwell.zchunk.fileformat.HeaderChecksumType;
+import de.bmarwell.zchunk.fileformat.PrefaceFlag;
import de.bmarwell.zchunk.fileformat.ZChunkHeader;
import de.bmarwell.zchunk.fileformat.ZChunkHeaderChunkInfo;
import de.bmarwell.zchunk.fileformat.ZChunkHeaderIndex;
import de.bmarwell.zchunk.fileformat.ZChunkHeaderLead;
import de.bmarwell.zchunk.fileformat.ZChunkHeaderPreface;
import de.bmarwell.zchunk.fileformat.ZChunkHeaderSignatures;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
import java.security.MessageDigest;
import java.util.Arrays;
+import java.util.Collection;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.logging.Level;
import java.util.logging.Logger;
public final class ChecksumUtil {
private static final Logger LOG = Logger.getLogger(ChecksumUtil.class.getCanonicalName());
+ /**
+ * Buffer size for reading files.
+ */
+ private static final int BUFFER_SIZE = 1024;
+
private ChecksumUtil() {
// util
}
- public static boolean isValid(final ZChunkHeader header) {
+ public static boolean isValidHeader(final ZChunkHeader header) {
final byte[] expectedChecksum = header.getLead().getChecksum();
final byte[] calculatedChecksum = calculateHeaderChecksum(header);
@@ -49,7 +60,7 @@ public static boolean isValid(final ZChunkHeader header) {
public static byte[] calculateHeaderChecksum(final ZChunkHeader header) {
final HeaderChecksumType digestAlgorithm = header.getLead().getChecksumType();
- final MessageDigest digest = digestAlgorithm.digest();
+ final MessageDigest digest = digestAlgorithm.getMessageDigest();
digest.update(getLeadBytes(header.getLead()));
digest.update(getPrefaceBytes(header.getPreface()));
@@ -81,7 +92,8 @@ private static byte[] getSignatureBytes(final ZChunkHeaderSignatures signatures)
}
private static byte[] getIndexBytes(final ZChunkHeaderIndex index) {
- final byte[] chunkInfos = getChunkInfoBytes(index.getChunkInfo());
+
+ final byte[] chunkInfos = getChunkInfoBytes(index.getChunkInfoSortedByIndex());
final byte[] indexBytes = concat(
index.getIndexSize().getCompressedBytes(),
@@ -97,7 +109,7 @@ private static byte[] getIndexBytes(final ZChunkHeaderIndex index) {
return indexBytes;
}
- private static byte[] getChunkInfoBytes(final List chunkInfos) {
+ private static byte[] getChunkInfoBytes(final Collection chunkInfos) {
final List collect = chunkInfos.stream()
.map(ChecksumUtil::getChunkInfoBytes)
.collect(toList());
@@ -167,4 +179,55 @@ private static byte[] concatByteArrays(final List byteList) {
}
+ public static boolean isValidData(final ZChunkHeader zChunkHeader, final File fileToCheck) {
+ if (zChunkHeader.getPreface().getPrefaceFlags().contains(PrefaceFlag.HAS_DATA_STREAMS)) {
+ throw new UnsupportedOperationException("Data streams not supported yet.");
+ }
+
+ final int totalHeaderSize = OffsetUtil.getTotalHeaderSize(zChunkHeader.getLead());
+ final HeaderChecksumType chunkChecksumType = zChunkHeader.getLead().getChecksumType();
+ final MessageDigest messageDigest = chunkChecksumType.getMessageDigest();
+
+ try (final FileInputStream fis = new FileInputStream(fileToCheck)) {
+ fis.skip(totalHeaderSize);
+ final byte[] buffer = new byte[BUFFER_SIZE];
+ int read = 0;
+ while ((read = fis.read(buffer)) == BUFFER_SIZE) {
+ messageDigest.update(buffer);
+ }
+ final byte[] lastChunk = new byte[read];
+ System.arraycopy(buffer, 0, lastChunk, 0, read);
+ messageDigest.update(lastChunk);
+
+ final byte[] expected = zChunkHeader.getPreface().getTotalDataChecksum();
+ final byte[] actual = messageDigest.digest();
+
+ return Arrays.equals(expected, actual);
+ } catch (final IOException ioEx) {
+ LOG.log(Level.SEVERE, ioEx, () -> "Unable to seek [" + totalHeaderSize + "] bytes into the file.");
+ return false;
+ }
+
+ }
+
+ public static boolean allChunksAreValid(final ZChunkHeader zChunkFile, final File file) {
+ return zChunkFile.getIndex().getChunkInfoSortedByIndex().stream()
+ .allMatch(chunk -> chunkIsValid(chunk, zChunkFile, file));
+ }
+
+ private static boolean chunkIsValid(final ZChunkHeaderChunkInfo chunk, final ZChunkHeader zChunkFile, final File file) {
+ final long chunkOffset = OffsetUtil.getChunkOffset(zChunkFile, chunk.getCurrentIndex());
+
+ try (final FileInputStream fis = new FileInputStream(file)) {
+ fis.skip(chunkOffset);
+ final byte[] chunkData = new byte[chunk.getChunkLength().getIntValue()];
+ fis.read(chunkData);
+ final byte[] digest = zChunkFile.getIndex().getChunkChecksumType().digest(chunkData);
+
+ return Arrays.equals(chunk.getChunkChecksum(), digest);
+ } catch (final IOException ioEx) {
+ LOG.log(Level.SEVERE, ioEx, () -> "Unable to seek [" + chunkOffset + "] bytes into the file.");
+ return false;
+ }
+ }
}
diff --git a/fileformat/src/main/java/de/bmarwell/zchunk/fileformat/util/OffsetUtil.java b/fileformat/src/main/java/de/bmarwell/zchunk/fileformat/util/OffsetUtil.java
index 0afe766..84ef792 100644
--- a/fileformat/src/main/java/de/bmarwell/zchunk/fileformat/util/OffsetUtil.java
+++ b/fileformat/src/main/java/de/bmarwell/zchunk/fileformat/util/OffsetUtil.java
@@ -16,7 +16,10 @@
package de.bmarwell.zchunk.fileformat.util;
+import de.bmarwell.zchunk.compressedint.CompressedInt;
import de.bmarwell.zchunk.fileformat.OptionalElement;
+import de.bmarwell.zchunk.fileformat.ZChunkHeader;
+import de.bmarwell.zchunk.fileformat.ZChunkHeaderChunkInfo;
import de.bmarwell.zchunk.fileformat.ZChunkHeaderLead;
import de.bmarwell.zchunk.fileformat.ZChunkHeaderPreface;
import java.math.BigInteger;
@@ -73,4 +76,17 @@ private static long getOptElementCountBytes(final ZChunkHeaderPreface preface) {
return preface.getOptionalElementCount().getCompressedBytes().length;
}
+ public static long getChunkOffset(final ZChunkHeader zChunkHeader, final long chunkId) {
+ final long totalHeaderSize = OffsetUtil.getTotalHeaderSize(zChunkHeader.getLead());
+ final CompressedInt dictLength = zChunkHeader.getIndex().getDictLength();
+
+ final long chunkOffset = zChunkHeader.getIndex().getChunkInfoSortedByIndex().stream()
+ .limit(chunkId)
+ .map(ZChunkHeaderChunkInfo::getChunkLength)
+ .mapToLong(CompressedInt::getLongValue)
+ .sum();
+
+ return totalHeaderSize + dictLength.getLongValue() + chunkOffset;
+ }
+
}
diff --git a/fileformat/src/test/java/de/bmarwell/zchunk/fileformat/ZChunkFileTest.java b/fileformat/src/test/java/de/bmarwell/zchunk/fileformat/ZChunkFileTest.java
index 1b0bc80..8cd0755 100644
--- a/fileformat/src/test/java/de/bmarwell/zchunk/fileformat/ZChunkFileTest.java
+++ b/fileformat/src/test/java/de/bmarwell/zchunk/fileformat/ZChunkFileTest.java
@@ -29,13 +29,19 @@ public class ZChunkFileTest {
private static final Logger LOG = Logger.getLogger(ZChunkFileTest.class.getCanonicalName());
- private static final File TEST_FILE = new File(ZChunkFileTest.class.getResource("/testfiles/LICENSE.dict.fodt.zck").getPath());
- private static final File TEST_FILE_INVALID = new File(
+ public static final File TEST_FILE = new File(ZChunkFileTest.class.getResource("/testfiles/LICENSE.dict.fodt.zck").getPath());
+
+ public static final File TEST_FILE_INVALID = new File(
ZChunkFileTest.class.getResource("/testfiles/LICENSE.dict.fodt.zck.invalid").getPath());
+ public static final File TEST_FILE_HEADER_CKSUM_INVALID = new File(
+ ZChunkFileTest.class.getResource("/testfiles/LICENSE.dict.fodt.header-cksum-invalid.zck").getPath());
+
+ public static final File TEST_FILE_HEADER_DIGEST_INVALID = new File(
+ ZChunkFileTest.class.getResource("/testfiles/LICENSE.dict.fodt.digest-invalid.zck").getPath());
@Test
public void testFileFormat() {
- final ZChunkFile zChunkFile = ZChunkHeaderFactory.fromFile(TEST_FILE);
+ final ZChunkFile zChunkFile = ZChunk.fromFile(TEST_FILE);
final ZChunkHeader header = zChunkFile.getHeader();
@@ -53,7 +59,7 @@ private void checkChecksum(final ZChunkHeader header) {
Assertions.assertAll(
() -> Assertions.assertArrayEquals(exp, actual),
- () -> Assertions.assertTrue(ChecksumUtil.isValid(header))
+ () -> Assertions.assertTrue(ChecksumUtil.isValidHeader(header))
);
}
@@ -61,7 +67,7 @@ private void checkChecksum(final ZChunkHeader header) {
public void testInvalidFile() {
Assertions.assertAll(
() -> Assertions.assertThrows(IllegalArgumentException.class, () -> ZChunkHeaderFactory.readFileHeaderLead(TEST_FILE_INVALID)),
- () -> Assertions.assertThrows(IllegalArgumentException.class, () -> ZChunkHeaderFactory.fromFile(TEST_FILE_INVALID))
+ () -> Assertions.assertThrows(IllegalArgumentException.class, () -> ZChunk.fromFile(TEST_FILE_INVALID))
);
}
@@ -70,7 +76,7 @@ private void testLead(final ZChunkHeaderLead lead) {
Assertions.assertAll(
() -> Assertions.assertArrayEquals(ZChunkConstants.Header.FILE_MAGIC, lead.getId()),
- () -> Assertions.assertEquals(1, lead.getChecksumType().ordinal()),
+ () -> Assertions.assertEquals(1L, lead.getChecksumType().getIdentifier()),
() -> Assertions.assertEquals(394L, lead.getHeaderSize().getLongValue()),
() -> Assertions.assertEquals(394, lead.getHeaderSize().getIntValue()),
// TODO: 434 (reported by zck_read_header) vs 432 (this implementation).
diff --git a/fileformat/src/test/java/de/bmarwell/zchunk/fileformat/ZChunkTest.java b/fileformat/src/test/java/de/bmarwell/zchunk/fileformat/ZChunkTest.java
new file mode 100644
index 0000000..d4e12fc
--- /dev/null
+++ b/fileformat/src/test/java/de/bmarwell/zchunk/fileformat/ZChunkTest.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2019, the zchunk-java contributors.
+ *
+ * Licensed 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 de.bmarwell.zchunk.fileformat;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class ZChunkTest {
+
+ @Test
+ public void testZChunk_validate_valid() {
+ final boolean validateFile = ZChunk.validateFile(ZChunkFileTest.TEST_FILE);
+ Assertions.assertTrue(validateFile);
+ }
+
+ @Test
+ public void testZChunk_validate_invalid() {
+ Assertions.assertThrows(
+ IllegalArgumentException.class,
+ () -> ZChunk.validateFile(ZChunkFileTest.TEST_FILE_INVALID));
+ }
+
+ @Test
+ public void testZChunk_validate_checksum_header_invalid() {
+ final boolean validateFile = ZChunk.validateFile(ZChunkFileTest.TEST_FILE_HEADER_CKSUM_INVALID);
+ Assertions.assertFalse(validateFile);
+ }
+
+ @Test
+ public void testZChunk_validate_digest_invalid() {
+ Assertions.assertThrows(
+ UnsupportedOperationException.class,
+ () -> ZChunk.validateFile(ZChunkFileTest.TEST_FILE_HEADER_DIGEST_INVALID));
+ }
+
+}
diff --git a/fileformat/src/test/resources/testfiles/LICENSE.dict.fodt.digest-invalid.zck b/fileformat/src/test/resources/testfiles/LICENSE.dict.fodt.digest-invalid.zck
new file mode 100644
index 0000000..feb138c
Binary files /dev/null and b/fileformat/src/test/resources/testfiles/LICENSE.dict.fodt.digest-invalid.zck differ
diff --git a/fileformat/src/test/resources/testfiles/LICENSE.dict.fodt.header-cksum-invalid.zck b/fileformat/src/test/resources/testfiles/LICENSE.dict.fodt.header-cksum-invalid.zck
new file mode 100644
index 0000000..ec88fe8
Binary files /dev/null and b/fileformat/src/test/resources/testfiles/LICENSE.dict.fodt.header-cksum-invalid.zck differ