From 44a92b6923c1e893d6d3f67b7df7823142d3733c Mon Sep 17 00:00:00 2001 From: Vojtech Moravec <vojtech.moravec.st@vsb.cz> Date: Fri, 4 Dec 2020 10:25:58 +0100 Subject: [PATCH] Create FileTypeInspector which determine file type based on magic value. --- .../java/cz/it4i/qcmp/DataCompressor.java | 106 ++++++++++++------ .../it4i/qcmp/fileformat/QCMPFileHeader.java | 2 +- .../cz/it4i/qcmp/io/FileTypeInspector.java | 64 +++++++++++ .../cz/it4i/qcmp/utilities/ColorConsole.java | 4 +- 4 files changed, 139 insertions(+), 37 deletions(-) create mode 100644 src/main/java/cz/it4i/qcmp/io/FileTypeInspector.java diff --git a/src/main/java/cz/it4i/qcmp/DataCompressor.java b/src/main/java/cz/it4i/qcmp/DataCompressor.java index 0c0de09..b87be17 100644 --- a/src/main/java/cz/it4i/qcmp/DataCompressor.java +++ b/src/main/java/cz/it4i/qcmp/DataCompressor.java @@ -7,10 +7,11 @@ import cz.it4i.qcmp.cli.CustomFunctionBase; import cz.it4i.qcmp.cli.functions.DebugFunction; import cz.it4i.qcmp.compression.ImageCompressor; import cz.it4i.qcmp.compression.ImageDecompressor; -import cz.it4i.qcmp.fileformat.FileExtensions; import cz.it4i.qcmp.fileformat.IQvcFile; +import cz.it4i.qcmp.io.FileTypeInspector; import cz.it4i.qcmp.io.QuantizationCacheManager; import cz.it4i.qcmp.io.QvcFileReader; +import cz.it4i.qcmp.utilities.ColorConsole; import org.apache.commons.cli.*; import java.io.IOException; @@ -108,47 +109,69 @@ public class DataCompressor { } break; case InspectFile: { - if (parsedOptions.getInputDataInfo().getFilePath().endsWith(FileExtensions.CACHE_FILE_EXT)) { - QuantizationCacheManager.inspectCacheFile(parsedOptions.getInputDataInfo().getFilePath(), - parsedOptions.isVerbose()); - } else { - final ImageDecompressor decompressor = new ImageDecompressor(parsedOptions); - try { - System.out.println(decompressor.inspectCompressedFile()); - } catch (final IOException e) { - System.err.println("Errors occurred during inspecting file."); - System.err.println(e.getMessage()); - e.printStackTrace(); + final FileTypeInspector.FileType fileType = FileTypeInspector.inspectFile(parsedOptions.getInputDataInfo().getFilePath()); + switch (fileType) { + case Qcmp: { + final ImageDecompressor decompressor = new ImageDecompressor(parsedOptions); + try { + System.out.println(decompressor.inspectCompressedFile()); + } catch (final IOException e) { + System.err.println("Errors occurred during inspecting file."); + System.err.println(e.getMessage()); + e.printStackTrace(); + } } + break; + case Qvc: { + QuantizationCacheManager.inspectCacheFile(parsedOptions.getInputDataInfo().getFilePath(), + parsedOptions.isVerbose()); + } + break; + case InvalidPath: + exitWithInvalidFilePath(); + break; + case Unknown: + exitWithUnknownFile(); + break; } } break; case Convert: { - final boolean inPlace = parsedOptions.getOutputFilePath() == null; - // TODO(Moravec): Maybe replace with generic reader which can determine file type based on magic value and not an extension. - if (parsedOptions.getInputDataInfo().getFilePath().endsWith(FileExtensions.CACHE_FILE_EXT)) { - IQvcFile cacheFile = null; - try { - cacheFile = QvcFileReader.readCacheFile(parsedOptions.getInputDataInfo().getFilePath()); - } catch (final IOException e) { - System.err.println("Unable to read QVC file. Error: " + e.getMessage()); - exitApplication(1); - } - try { - assert (cacheFile != null); - cacheFile.convertToNewerVersion(inPlace, parsedOptions.getInputDataInfo().getFilePath(), - parsedOptions.getOutputFilePath()); - } catch (final IOException e) { - System.err.println("Unable to convert specified QVC file. Error: " + e.getMessage()); - exitApplication(1); + final FileTypeInspector.FileType fileType = FileTypeInspector.inspectFile(parsedOptions.getInputDataInfo().getFilePath()); + switch (fileType) { + case Qcmp: { + System.err.println("Qcmp file conversion isn't supported yet"); } + break; + case Qvc: { + IQvcFile cacheFile = null; + try { + cacheFile = QvcFileReader.readCacheFile(parsedOptions.getInputDataInfo().getFilePath()); + } catch (final IOException e) { + System.err.println("Unable to read QVC file. Error: " + e.getMessage()); + exitApplication(1); + } + final boolean inPlace = parsedOptions.getOutputFilePath() == null; + try { + assert (cacheFile != null); + cacheFile.convertToNewerVersion(inPlace, parsedOptions.getInputDataInfo().getFilePath(), + parsedOptions.getOutputFilePath()); + } catch (final IOException e) { + System.err.println("Unable to convert specified QVC file. Error: " + e.getMessage()); + exitApplication(1); + } - if (parsedOptions.isVerbose()) { - System.err.println("Qvc file is converted."); + if (parsedOptions.isVerbose()) { + System.err.println("Qvc file is converted."); + } } - - } else { - System.err.println("Qcmp file conversion isn't supported yet"); + break; + case InvalidPath: + exitWithInvalidFilePath(); + break; + case Unknown: + exitWithUnknownFile(); + break; } } break; @@ -156,6 +179,21 @@ public class DataCompressor { ScifioWrapper.dispose(); } + private static void exitWithUnknownFile() { + ColorConsole.fprintf(ColorConsole.Target.stderr, + ColorConsole.Color.Red, + "Provided file is of unknown type. Only QCMP and QVC files are supported.\n"); + + exitApplication(1); + } + + private static void exitWithInvalidFilePath() { + ColorConsole.fprintf(ColorConsole.Target.stderr, + ColorConsole.Color.Red, + "File specified by provided path doesn't exist.\n"); + exitApplication(1); + } + private static void exitApplication(final int exitCode) { ScifioWrapper.dispose(); System.exit(exitCode); diff --git a/src/main/java/cz/it4i/qcmp/fileformat/QCMPFileHeader.java b/src/main/java/cz/it4i/qcmp/fileformat/QCMPFileHeader.java index e9522b4..e720b0d 100644 --- a/src/main/java/cz/it4i/qcmp/fileformat/QCMPFileHeader.java +++ b/src/main/java/cz/it4i/qcmp/fileformat/QCMPFileHeader.java @@ -15,7 +15,7 @@ public class QCMPFileHeader implements IFileHeader, Cloneable { //region Constants private static final int VERSION = 1; private static final int BASE_QCMP_HEADER_SIZE = 23; - private static final String MAGIC_VALUE = "QCMPFILE"; + public static final String MAGIC_VALUE = "QCMPFILE"; //endregion //region Header fields diff --git a/src/main/java/cz/it4i/qcmp/io/FileTypeInspector.java b/src/main/java/cz/it4i/qcmp/io/FileTypeInspector.java new file mode 100644 index 0000000..14a99bd --- /dev/null +++ b/src/main/java/cz/it4i/qcmp/io/FileTypeInspector.java @@ -0,0 +1,64 @@ +package cz.it4i.qcmp.io; + +import cz.it4i.qcmp.fileformat.QCMPFileHeader; +import cz.it4i.qcmp.fileformat.QvcHeaderV1; +import cz.it4i.qcmp.fileformat.QvcHeaderV2; + +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; + +public class FileTypeInspector { + public enum FileType { + /** + * Compressed image hyperstack. + */ + Qcmp, + /** + * Codebook cache file. + */ + Qvc, + /** + * Invalid file path. + */ + InvalidPath, + /** + * No known magic value was matched. + */ + Unknown + } + + /** + * Inspect file specified by path and return its type. + * + * @param filePath Path to the file. + * @return File type. + */ + public static FileType inspectFile(final String filePath) { + // QCMPFileHeader.MAGIC_VALUE // 8 bytes + // QvcHeaderV1.MAGIC_VALUE // 9 bytes + // QvcHeaderV2.MAGIC_VALUE // 9 bytes + try (final FileInputStream stream = new FileInputStream(filePath)) { + final byte[] buf1 = new byte[QCMPFileHeader.MAGIC_VALUE.length()]; + RawDataIO.readFullBuffer(stream, buf1); + if (new String(buf1).equals(QCMPFileHeader.MAGIC_VALUE)) { + return FileType.Qcmp; + } + + final byte[] buf2 = new byte[QvcHeaderV1.MAGIC_VALUE.length()]; + System.arraycopy(buf1, 0, buf2, 0, buf1.length); + final int read = stream.read(buf2, buf1.length, 1); + if (read != 1) + return FileType.Unknown; + + final String magicValue = new String(buf2); + if (magicValue.equals(QvcHeaderV1.MAGIC_VALUE) || magicValue.equals(QvcHeaderV2.MAGIC_VALUE)) + return FileType.Qvc; + } catch (final FileNotFoundException e) { + return FileType.InvalidPath; + } catch (final IOException e) { + return FileType.Unknown; + } + return FileType.Unknown; + } +} diff --git a/src/main/java/cz/it4i/qcmp/utilities/ColorConsole.java b/src/main/java/cz/it4i/qcmp/utilities/ColorConsole.java index d41b659..a3625f1 100644 --- a/src/main/java/cz/it4i/qcmp/utilities/ColorConsole.java +++ b/src/main/java/cz/it4i/qcmp/utilities/ColorConsole.java @@ -48,10 +48,10 @@ public final class ColorConsole { switch (target) { case stdout: - System.out.println(getColor(color) + string + ANSI_RESET); + System.out.print(getColor(color) + string + ANSI_RESET); break; case stderr: - System.err.println(getColor(color) + string + ANSI_RESET); + System.err.print(getColor(color) + string + ANSI_RESET); break; } } -- GitLab