diff --git a/.gitignore b/.gitignore index a7d99dc..da74824 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ # maven **/target +**/dependency-reduced-pom.xml # intellij .idea/** diff --git a/bundle/pom.xml b/bundle/pom.xml new file mode 100644 index 0000000..de18cb5 --- /dev/null +++ b/bundle/pom.xml @@ -0,0 +1,80 @@ + + + + zchunk-parent + io.github.zchunk + 1.0.0-SNAPSHOT + + 4.0.0 + + zchunk-bundle + bundle + ZChunk library bundle jar + + + + io.github.zchunk + zchunk-fileformat + 1.0.0-SNAPSHOT + + + + io.github.zchunk + zchunk-compression-none + 1.0.0-SNAPSHOT + + + + io.github.zchunk + zchunk-compression-zstd + 1.0.0-SNAPSHOT + + + + + org.junit.jupiter + junit-jupiter-api + test + + + org.junit.jupiter + junit-jupiter-engine + test + + + + + + + + org.apache.maven.plugins + maven-shade-plugin + + + package + + shade + + + io.github.zchunk + false + true + true + true + + + + ZChunk Library + + + + + + + + + + diff --git a/fileformat/src/test/java/io/github/zchunk/fileformat/ZChunkCompressionSupportTest.java b/bundle/src/test/java/io/github/zchunk/fileformat/ZChunkCompressionSupportTest.java similarity index 86% rename from fileformat/src/test/java/io/github/zchunk/fileformat/ZChunkCompressionSupportTest.java rename to bundle/src/test/java/io/github/zchunk/fileformat/ZChunkCompressionSupportTest.java index c13581b..e32f6d6 100644 --- a/fileformat/src/test/java/io/github/zchunk/fileformat/ZChunkCompressionSupportTest.java +++ b/bundle/src/test/java/io/github/zchunk/fileformat/ZChunkCompressionSupportTest.java @@ -8,16 +8,13 @@ import io.github.zchunk.compression.api.err.DecompressionException; import java.util.Map; import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; -@Disabled(value = "does not work with test-only dependencies. " - + "Move into separate test module or create zchunk-all / zchunk-lib.") public class ZChunkCompressionSupportTest { @Test public void testCompressionImplementations() { - final Map> algorithms = CompressionAlgorithmFactory.getKnownAlgorithms(); + final Map algorithms = CompressionAlgorithmFactory.getKnownAlgorithms(); Assertions.assertTrue(algorithms.size() >= 3); } diff --git a/compression/compression-api/src/main/java/io/github/zchunk/compression/api/CompressionAlgorithmFactory.java b/compression/compression-api/src/main/java/io/github/zchunk/compression/api/CompressionAlgorithmFactory.java index 7567369..74daf00 100644 --- a/compression/compression-api/src/main/java/io/github/zchunk/compression/api/CompressionAlgorithmFactory.java +++ b/compression/compression-api/src/main/java/io/github/zchunk/compression/api/CompressionAlgorithmFactory.java @@ -17,19 +17,21 @@ package io.github.zchunk.compression.api; import static java.util.Collections.unmodifiableMap; -import static java.util.stream.Collectors.toList; import static java.util.stream.Collectors.toMap; import io.github.zchunk.compressedint.CompressedInt; import io.github.zchunk.compression.algo.unknown.UnknownAlgorithm; -import io.github.zchunk.compression.api.internal.ReflectionUtil; import java.util.AbstractMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Objects; import java.util.Optional; +import java.util.ServiceLoader; +import java.util.logging.Logger; +import java.util.stream.Collectors; import java.util.stream.Stream; +import java.util.stream.StreamSupport; import org.checkerframework.checker.initialization.qual.UnderInitialization; import org.checkerframework.checker.nullness.qual.EnsuresNonNull; import org.checkerframework.checker.nullness.qual.Nullable; @@ -43,16 +45,10 @@ private CompressionAlgorithmFactory() { // util class. } - public static Map> getKnownAlgorithms() { + public static Map getKnownAlgorithms() { return unmodifiableMap(getTypeMappings()); } - private static Map.@Nullable Entry> mapEntryOrNull(final Class clazz) { - return ReflectionUtil.newInstance(clazz) - .map(compInstance -> new AbstractMap.SimpleEntry<>(compInstance.getCompressionTypeValue().getUnsignedLongValue(), clazz)) - .orElse(null); - } - /** * Tries to load a compression algorithm. If it fails, it will return {@link UnknownAlgorithm}. * @@ -64,17 +60,16 @@ public static Map> getKnownAlgorithms() { */ public static CompressionAlgorithm forType(final long compressionType) { return Optional.ofNullable(getTypeMappings().get(compressionType)) - .flatMap(ReflectionUtil::newInstance) .orElseGet(UnknownAlgorithm::new); } /* Utility methods */ - private static List> getImplementations() { + private static List getImplementations() { return ResourceHolder.newInstance(ROOT_PACKAGE).getImplementations(); } - private static Map> getTypeMappings() { + private static Map getTypeMappings() { return ResourceHolder.newInstance(ROOT_PACKAGE).getTypeMapping(); } @@ -87,19 +82,19 @@ private static class ResourceHolder { private static @Nullable ResourceHolder INSTANCE = null; - private final List> implementations; + private final List implementations; - private final Map> typeMapping; + private final Map typeMapping; - public ResourceHolder(final String rootPackage) { - this.implementations = loadImplementations(rootPackage, CompressionAlgorithm.class); + public ResourceHolder() { + this.implementations = loadImplementations(); this.typeMapping = loadTypeMapping(this.implementations); } @EnsuresNonNull({"INSTANCE"}) public static ResourceHolder newInstance(final String rootPackage) { if (INSTANCE == null) { - INSTANCE = new ResourceHolder(rootPackage); + INSTANCE = new ResourceHolder(); } return INSTANCE; @@ -108,39 +103,39 @@ public static ResourceHolder newInstance(final String rootPackage) { /** * Will try to load classes implementing clazz, from any package below rootpackage. * - * @param rootPackage - * the root package to search in. - * @param clazz - * the class which should be implemented by the found classes. - * @param - * the class type. * @return a list of classes implementing T / clazz. */ - public List> loadImplementations(@UnderInitialization ResourceHolder this, - final String rootPackage, - final Class clazz) { - final List> classes = ReflectionUtil.getClasses(rootPackage, clazz); - - return classes.stream() - .filter(ReflectionUtil.classImplementsCompressionAlgorithm(clazz)) - .collect(toList()); + public List loadImplementations(@UnderInitialization ResourceHolder this) { + final ServiceLoader load = ServiceLoader.load(CompressionAlgorithm.class); + final Logger logger = Logger.getLogger("io.github.zchunk"); + + logger.info("ServiceLoader: " + load); + + return StreamSupport.stream(load.spliterator(), false) + .peek(clazz2 -> logger.info("Class: " + clazz2.getClass())) + .collect(Collectors.toList()); } - private Map> loadTypeMapping(@UnderInitialization ResourceHolder this, - final List> implementations) { - final Stream<@Nullable Entry>> entryStream = implementations.stream() - .map(CompressionAlgorithmFactory::mapEntryOrNull); + private Map loadTypeMapping(@UnderInitialization ResourceHolder this, + final List implementations) { + final Stream<@Nullable Entry> entryStream = implementations.stream() + .map(ResourceHolder::mapEntryOrNull); return entryStream .filter(Objects::nonNull) .collect(toMap(Map.Entry::getKey, Map.Entry::getValue)); } - public List> getImplementations() { + public List getImplementations() { return this.implementations; } - public Map> getTypeMapping() { + public Map getTypeMapping() { return this.typeMapping; } + + private static Map.Entry mapEntryOrNull(final CompressionAlgorithm clazz) { + return new AbstractMap.SimpleEntry<>(clazz.getCompressionTypeValue().getUnsignedLongValue(), clazz); + } } + } diff --git a/compression/compression-api/src/main/java/io/github/zchunk/compression/api/internal/ReflectionUtil.java b/compression/compression-api/src/main/java/io/github/zchunk/compression/api/internal/ReflectionUtil.java deleted file mode 100644 index d1fe756..0000000 --- a/compression/compression-api/src/main/java/io/github/zchunk/compression/api/internal/ReflectionUtil.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * 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 io.github.zchunk.compression.api.internal; - -import static java.util.Collections.emptyList; -import static java.util.stream.Collectors.toList; - -import java.io.File; -import java.io.IOException; -import java.net.URL; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Enumeration; -import java.util.List; -import java.util.Optional; -import java.util.function.Predicate; -import java.util.logging.Level; -import java.util.logging.Logger; - -public final class ReflectionUtil { - - private static final Logger LOG = Logger.getLogger(ReflectionUtil.class.getCanonicalName()); - - private ReflectionUtil() { - // util - } - - public static List> getClasses(final String rootPackage, final Class targetClazz) { - try { - final ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); - final String path = rootPackage.replace('.', '/'); - final Enumeration resources = classLoader.getResources(path); - final List dirs = new ArrayList<>(); - - while (resources.hasMoreElements()) { - final URL resource = resources.nextElement(); - dirs.add(new File(resource.getFile())); - } - - return dirs.stream() - .map(dir -> findClasses(dir, rootPackage, targetClazz)) - .flatMap(Collection::stream) - .collect(toList()); - } catch (final IOException ioEx) { - LOG.log(Level.SEVERE, ioEx, () -> String.format("Unable to load classes in root package [%s].", rootPackage)); - return emptyList(); - } - } - - /** - * Recursive method used to find all classes in a given directory and subdirs. - * - * @param directory - * The base directory - * @param packageName - * The package name for classes found inside the base directory - * @return The classes - */ - private static List> findClasses(final File directory, final String packageName, final Class clazzType) { - if (!directory.exists()) { - return Collections.emptyList(); - } - - final List files = getListFromArray(directory.listFiles()); - - return files.stream() - .map(file -> findClasses(packageName, clazzType, file)) - .flatMap(Collection::stream) - .collect(toList()); - } - - private static List> findClasses(final String packageName, final Class clazzType, final File file) { - if (file.isDirectory()) { - if (file.getName().contains(".")) { - // bad match. - return emptyList(); - } - - return findClasses(file, packageName + "." + file.getName(), clazzType); - } - - if (file.getName().endsWith(".class")) { - return loadClass(packageName, clazzType, file) - .map(Collections::singletonList) - .orElseGet(Collections::emptyList); - } - - return emptyList(); - } - - private static Optional> loadClass(final String packageName, final Class clazzType, final File file) { - try { - final Class aClass = Class.forName(packageName + '.' + file.getName().substring(0, file.getName().length() - 6)); - final boolean classImplementsType = classImplementsCompressionAlgorithm(clazzType).test(aClass); - - if (classImplementsType) { - @SuppressWarnings("unchecked") - final Class castedClass = (Class) aClass; - return Optional.of(castedClass); - } - } catch (final ClassNotFoundException e) { - LOG.log(Level.WARNING, e, () -> String.format("Class file [%s] found, but unable to create instance.", file.getAbsolutePath())); - } - - return Optional.empty(); - } - - private static List getListFromArray(final T[] input) { - return Optional.ofNullable(input) - .map(Arrays::asList) - .orElseGet(Collections::emptyList); - } - - /** - * Tries to create a new instance using the default constructor. - * - * @param clazz - * the class to instantiate. - * @param - * the class type. - * @return {@link Optional#empty} if it did not succeed, Optional with an instance otherwise. - */ - public static Optional newInstance(final Class clazz) { - try { - return Optional.of(clazz.newInstance()); - } catch (final InstantiationException | IllegalAccessException e) { - LOG.log(Level.WARNING, e, () -> String.format("Unable to instantiate class [%s]. Skipping.", clazz)); - return Optional.empty(); - } - } - - public static Predicate> classImplementsCompressionAlgorithm(final Class type) { - return clazz -> getListFromArray(clazz.getInterfaces()).contains(type); - } - -} diff --git a/compression/compression-api/src/main/resources/META-INF/services/io.github.zchunk.compression.api.CompressionAlgorithm b/compression/compression-api/src/main/resources/META-INF/services/io.github.zchunk.compression.api.CompressionAlgorithm new file mode 100644 index 0000000..0ac7a96 --- /dev/null +++ b/compression/compression-api/src/main/resources/META-INF/services/io.github.zchunk.compression.api.CompressionAlgorithm @@ -0,0 +1 @@ +io.github.zchunk.compression.algo.unknown.UnknownAlgorithm diff --git a/compression/compression-none/src/main/resources/META-INF/services/io.github.zchunk.compression.api.CompressionAlgorithm b/compression/compression-none/src/main/resources/META-INF/services/io.github.zchunk.compression.api.CompressionAlgorithm new file mode 100644 index 0000000..468617b --- /dev/null +++ b/compression/compression-none/src/main/resources/META-INF/services/io.github.zchunk.compression.api.CompressionAlgorithm @@ -0,0 +1 @@ +io.github.zchunk.compression.algo.none.NoneCompressionAlgorithm diff --git a/compression/compression-zstd/src/main/resources/META-INF/services/io.github.zchunk.compression.api.CompressionAlgorithm b/compression/compression-zstd/src/main/resources/META-INF/services/io.github.zchunk.compression.api.CompressionAlgorithm new file mode 100644 index 0000000..0af6d66 --- /dev/null +++ b/compression/compression-zstd/src/main/resources/META-INF/services/io.github.zchunk.compression.api.CompressionAlgorithm @@ -0,0 +1 @@ +io.github.zchunk.compression.algo.zstd.ZStdCompressionAlgorithm diff --git a/fileformat/pom.xml b/fileformat/pom.xml index 7e6019b..8fea5bf 100644 --- a/fileformat/pom.xml +++ b/fileformat/pom.xml @@ -84,4 +84,5 @@ + diff --git a/fileformat/src/main/java/io/github/zchunk/fileformat/IndexChecksumType.java b/fileformat/src/main/java/io/github/zchunk/fileformat/IndexChecksumType.java index 8abbf9d..1d32b1f 100644 --- a/fileformat/src/main/java/io/github/zchunk/fileformat/IndexChecksumType.java +++ b/fileformat/src/main/java/io/github/zchunk/fileformat/IndexChecksumType.java @@ -16,9 +16,12 @@ package io.github.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; /** * Checksum type for everything in the index. @@ -32,17 +35,20 @@ *

*/ public enum IndexChecksumType { - SHA1("SHA-1", -1), - SHA256("SHA-256", -1), - SHA512("SHA-512", -1), - SHA512_128("SHA-512", 16); + UNKNOWN("none", -1L, 0), + SHA1("SHA-1", 0L, -1), + SHA256("SHA-256", 1L, -1), + SHA512("SHA-512", 2L, -1), + SHA512_128("SHA-512", 3L, 16); private final String digestAlgorithm; private final int length; + private final long identifier; - IndexChecksumType(final String digestAlgorithm, final int length) { + IndexChecksumType(final String digestAlgorithm, final long identifier, final int length) { try { this.digestAlgorithm = digestAlgorithm; + this.identifier = identifier; if (length != -1) { this.length = length; } else { @@ -53,6 +59,21 @@ public enum IndexChecksumType { } } + public static IndexChecksumType find(final BigInteger unsignedLongValue) { + if (unsignedLongValue.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) >= 1) { + final String message = String.format("Unknown Checksum type: [%s], exceeds [%d]!", unsignedLongValue.toString(), Integer.MAX_VALUE); + Logger.getLogger(IndexChecksumType.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 actualChecksumLength() { return this.length; } @@ -77,11 +98,16 @@ public MessageDigest getMessageDigest() { } } + public long getIdentifier() { + return this.identifier; + } + @Override public String toString() { return new StringJoiner(", ", IndexChecksumType.class.getSimpleName() + "[", "]") .add("digestAlgorithm=" + this.digestAlgorithm) .add("actualChecksumLength=" + this.length) + .add("identifier=" + this.identifier) .add("ordinal=" + this.ordinal()) .toString(); } diff --git a/fileformat/src/main/java/io/github/zchunk/fileformat/ZChunkHeaderFactory.java b/fileformat/src/main/java/io/github/zchunk/fileformat/ZChunkHeaderFactory.java index 97ba3c6..8220f67 100644 --- a/fileformat/src/main/java/io/github/zchunk/fileformat/ZChunkHeaderFactory.java +++ b/fileformat/src/main/java/io/github/zchunk/fileformat/ZChunkHeaderFactory.java @@ -21,6 +21,7 @@ import io.github.zchunk.compressedint.CompressedInt; import io.github.zchunk.compressedint.CompressedIntFactory; +import io.github.zchunk.compression.algo.unknown.UnknownAlgorithm; import io.github.zchunk.compression.api.CompressionAlgorithm; import io.github.zchunk.compression.api.CompressionAlgorithmFactory; import io.github.zchunk.fileformat.err.InvalidFileException; @@ -156,7 +157,11 @@ private static ZChunkHeaderPreface getZChunkFileHeaderPrefaceFromParser(final ZC final CompressedInt prefaceFlagsInt = prefaceParser.readFlagsInt(); final Set flags = PrefaceFlag.getPrefaceFlags(prefaceFlagsInt); - final CompressionAlgorithm compressionAlgorithm = CompressionAlgorithmFactory.forType(prefaceParser.readCompressionType()); + final CompressedInt compressionTypeInt = prefaceParser.readCompressionType(); + final CompressionAlgorithm compressionAlgorithm = CompressionAlgorithmFactory.forType(compressionTypeInt); + if (compressionAlgorithm.getClass().equals(UnknownAlgorithm.class)) { + throw new IllegalArgumentException("Unknown compression type for type " + compressionTypeInt); + } return ImmutableZChunkHeaderPreface.builder() .totalDataChecksum(prefaceParser.readTotalDataCksum()) diff --git a/fileformat/src/main/java/io/github/zchunk/fileformat/ZChunkHeaderIndex.java b/fileformat/src/main/java/io/github/zchunk/fileformat/ZChunkHeaderIndex.java index 1db24bc..bc787a8 100644 --- a/fileformat/src/main/java/io/github/zchunk/fileformat/ZChunkHeaderIndex.java +++ b/fileformat/src/main/java/io/github/zchunk/fileformat/ZChunkHeaderIndex.java @@ -63,7 +63,7 @@ public abstract class ZChunkHeaderIndex { @Value.Derived public IndexChecksumType getChunkChecksumType() { - return IndexChecksumType.values()[getChunkChecksumTypeInt().getIntValue()]; + return IndexChecksumType.find(getChunkChecksumTypeInt().getValue()); } public abstract CompressedInt getChunkCount(); diff --git a/fileformat/src/main/java/io/github/zchunk/fileformat/parser/ZChunkIndexParser.java b/fileformat/src/main/java/io/github/zchunk/fileformat/parser/ZChunkIndexParser.java index 188a973..de52134 100644 --- a/fileformat/src/main/java/io/github/zchunk/fileformat/parser/ZChunkIndexParser.java +++ b/fileformat/src/main/java/io/github/zchunk/fileformat/parser/ZChunkIndexParser.java @@ -56,7 +56,9 @@ private ZChunkIndexParser(final byte[] completeHeader, final ZChunkHeaderLead le this.completeHeader = completeHeader; this.lead = lead; this.preface = preface; - this.indexStart = OffsetUtil.getLeadLength(lead) + OffsetUtil.getPrefaceLength(preface); + final int leadLength = OffsetUtil.getLeadLength(lead); + final long prefaceLength = OffsetUtil.getPrefaceLength(preface); + this.indexStart = leadLength + prefaceLength; } public static ZChunkIndexParser fromBytes(final byte[] completeHeader, final ZChunkHeaderLead lead, final ZChunkHeaderPreface preface) { @@ -85,7 +87,11 @@ public CompressedInt readIndexCksumType() { bis.skip(this.cksumTypeOffset); final CompressedInt compressedInt = CompressedIntFactory.readCompressedInt(bis); this.chunkCountOffset = this.cksumTypeOffset + compressedInt.getCompressedBytes().length; - this.chunkChecksumType = IndexChecksumType.values()[compressedInt.getIntValue()]; + this.chunkChecksumType = IndexChecksumType.find(compressedInt.getValue()); + + if (this.chunkChecksumType.equals(IndexChecksumType.UNKNOWN)) { + throw new IllegalArgumentException("Cannot find index type."); + } return compressedInt; } catch (final IOException ioEx) { diff --git a/fileformat/src/main/java/io/github/zchunk/fileformat/util/OffsetUtil.java b/fileformat/src/main/java/io/github/zchunk/fileformat/util/OffsetUtil.java index 3a9a5b2..b8da79e 100644 --- a/fileformat/src/main/java/io/github/zchunk/fileformat/util/OffsetUtil.java +++ b/fileformat/src/main/java/io/github/zchunk/fileformat/util/OffsetUtil.java @@ -52,12 +52,16 @@ public static long getPrefaceLength(final ZChunkHeaderPreface preface) { * optional element count only exists if the flag is set. */ final long optElementCountBytes = getOptElementCountBytes(preface); + final BigInteger totalDataCksumLength = BigInteger.valueOf(preface.getTotalDataChecksum().length); + final BigInteger prefaceFlagsLength = BigInteger.valueOf(preface.getPrefaceFlagsInt().getCompressedBytes().length); + final BigInteger compressionTypeLength = BigInteger + .valueOf(preface.getCompressionAlgorithm().getCompressionTypeValue().getCompressedBytes().length); - return BigInteger.valueOf(preface.getTotalDataChecksum().length) + return totalDataCksumLength // plus highest preface flag - .add(BigInteger.valueOf(preface.getPrefaceFlagsInt().getCompressedBytes().length)) + .add(prefaceFlagsLength) // plus length of compression type - .add(BigInteger.valueOf(preface.getCompressionAlgorithm().getCompressionTypeValue().getCompressedBytes().length)) + .add(compressionTypeLength) // this might even be 0 if the flag was not set. .add(BigInteger.valueOf(optElementCountBytes)) .add(BigInteger.valueOf( diff --git a/fileformat/src/test/java/io/github/zchunk/fileformat/ZChunkChunkDecompressionTest.java b/fileformat/src/test/java/io/github/zchunk/fileformat/ZChunkChunkDecompressionTest.java new file mode 100644 index 0000000..4a2eb10 --- /dev/null +++ b/fileformat/src/test/java/io/github/zchunk/fileformat/ZChunkChunkDecompressionTest.java @@ -0,0 +1,51 @@ +/* + * Copyright 2018 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 io.github.zchunk.fileformat; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class ZChunkChunkDecompressionTest { + + public static final File TEST_FILE = new File( + ZChunkChunkDecompressionTest.class.getResource("/testfiles/LICENSE.dict.fodt.zck").getPath()); + + @Test + public void testDecompressDictOnFirstChunk() { + final ZChunkFile zChunkFile = ZChunk.fromFile(TEST_FILE); + final ZChunkHeader header = zChunkFile.getHeader(); + + final byte[] dict = ZChunk.getDecompressedDict(header, TEST_FILE); + final ZChunkHeaderChunkInfo chunkInfo = ZChunk.getChunkInfo(header, 0L); + final byte[] chunkBuffer = new byte[chunkInfo.getChunkUncompressedLength().getIntValue()]; + + try (final InputStream is = ZChunk.getDecompressedChunk(header, TEST_FILE, dict, 0L)) { + // only read the first few bytes to see if it works. + is.read(chunkBuffer, 0, 120); + } catch (final IOException ioEx) { + throw new RuntimeException(ioEx); + } + + final String readBytes = new String(chunkBuffer, StandardCharsets.UTF_8); + Assertions.assertTrue(readBytes.startsWith("")); + } + +} diff --git a/fileformat/src/test/java/io/github/zchunk/fileformat/ZChunkFileTest.java b/fileformat/src/test/java/io/github/zchunk/fileformat/ZChunkFileTest.java index ab30805..6d83603 100644 --- a/fileformat/src/test/java/io/github/zchunk/fileformat/ZChunkFileTest.java +++ b/fileformat/src/test/java/io/github/zchunk/fileformat/ZChunkFileTest.java @@ -20,9 +20,6 @@ import io.github.zchunk.fileformat.util.ChecksumUtil; import io.github.zchunk.fileformat.util.OffsetUtil; import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.StandardCharsets; import java.util.logging.Logger; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -52,8 +49,7 @@ public void testFileFormat() { () -> testLead(header.getLead()), () -> testPreface(header.getPreface()), () -> testIndex(header.getIndex()), - () -> checkChecksum(header), - () -> testDecompressDictOnFirstChunk(header, TEST_FILE) + () -> checkChecksum(header) ); } @@ -104,24 +100,9 @@ private void testIndex(final ZChunkHeaderIndex index) { Assertions.assertAll( () -> Assertions.assertEquals(357L, index.getIndexSize().getLongValue()), () -> Assertions.assertEquals(IndexChecksumType.SHA512_128, index.getChunkChecksumType()), - () -> Assertions.assertEquals(3, index.getChunkChecksumType().ordinal()), + () -> Assertions.assertEquals(3L, index.getChunkChecksumType().getIdentifier()), () -> Assertions.assertEquals(17L, index.getChunkCount().getLongValue()) ); } - private void testDecompressDictOnFirstChunk(final ZChunkHeader header, final File testFile) { - final byte[] dict = ZChunk.getDecompressedDict(header, testFile); - final ZChunkHeaderChunkInfo chunkInfo = ZChunk.getChunkInfo(header, 0L); - final byte[] chunkBuffer = new byte[chunkInfo.getChunkUncompressedLength().getIntValue()]; - - try (final InputStream is = ZChunk.getDecompressedChunk(header, testFile, dict, 0L)) { - // only read the first few bytes to see if it works. - is.read(chunkBuffer, 0, 120); - } catch (final IOException ioEx) { - throw new RuntimeException(ioEx); - } - - final String readBytes = new String(chunkBuffer, StandardCharsets.UTF_8); - Assertions.assertTrue(readBytes.startsWith("")); - } } diff --git a/pom.xml b/pom.xml index 095a451..0571e72 100644 --- a/pom.xml +++ b/pom.xml @@ -35,6 +35,8 @@ compression/compression-zstd fileformat + + bundle @@ -166,6 +168,12 @@ + + + org.apache.maven.plugins + maven-shade-plugin + 3.2.1 +