1 /*
2 * SPDX-FileCopyrightText: Copyright (c) 2011-2026 Yegor Bugayenko
3 * SPDX-License-Identifier: MIT
4 */
5 package com.qulice.spi;
6
7 import java.io.File;
8 import java.io.IOException;
9 import java.io.InputStream;
10 import java.nio.file.Files;
11
12 /**
13 * A file that is considered binary.
14 *
15 * <p>Detects binary files using the classic NULL-byte heuristic: if any
16 * of the first {@link #SNIFF} bytes of the file is {@code 0x00}, the file
17 * is treated as binary. This is the same rule used by {@code git diff}
18 * and GNU {@code grep} to decide whether a file is text or binary. It
19 * intentionally misclassifies nothing for typical source code (Java, XML,
20 * YAML, JSON, UTF-8) while correctly ignoring images, archives, compiled
21 * classes and similar blobs that should not be fed to text-based
22 * validators such as Checkstyle's {@code RegexpSinglelineCheck}.</p>
23 *
24 * <p>A file that does not exist, is not a regular file, or is empty is
25 * considered non-binary, so the caller may still attempt to open it and
26 * fail fast with a clear error, rather than silently skipping it here.</p>
27 *
28 * @since 0.24
29 */
30 public final class Binary {
31
32 /**
33 * Amount of bytes to sniff from the head of the file.
34 */
35 private static final int SNIFF = 8192;
36
37 /**
38 * The file to inspect.
39 */
40 private final File file;
41
42 /**
43 * Ctor.
44 *
45 * @param src File to inspect
46 */
47 public Binary(final File src) {
48 this.file = src;
49 }
50
51 /**
52 * Is the file binary?
53 *
54 * @return TRUE if the first {@value #SNIFF} bytes contain a NULL byte
55 */
56 public boolean yes() {
57 boolean binary = false;
58 if (this.file.isFile()) {
59 try (InputStream stream = Files.newInputStream(this.file.toPath())) {
60 final byte[] buffer = new byte[Binary.SNIFF];
61 final int read = stream.read(buffer);
62 for (int idx = 0; idx < read; ++idx) {
63 if (buffer[idx] == 0) {
64 binary = true;
65 break;
66 }
67 }
68 } catch (final IOException ex) {
69 throw new IllegalStateException(
70 String.format(
71 "Failed to inspect file '%s' for binary content",
72 this.file
73 ),
74 ex
75 );
76 }
77 }
78 return binary;
79 }
80 }