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 * @param src File to inspect
45 */
46 public Binary(final File src) {
47 this.file = src;
48 }
49
50 /**
51 * Is the file binary?
52 * @return TRUE if the first {@value #SNIFF} bytes contain a NULL byte
53 */
54 public boolean yes() {
55 boolean binary = false;
56 if (this.file.isFile()) {
57 try (InputStream stream = Files.newInputStream(this.file.toPath())) {
58 final byte[] buffer = new byte[Binary.SNIFF];
59 final int read = stream.read(buffer);
60 for (int idx = 0; idx < read; ++idx) {
61 if (buffer[idx] == 0) {
62 binary = true;
63 break;
64 }
65 }
66 } catch (final IOException ex) {
67 throw new IllegalStateException(
68 String.format(
69 "Failed to inspect file '%s' for binary content",
70 this.file
71 ),
72 ex
73 );
74 }
75 }
76 return binary;
77 }
78 }