View Javadoc
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  }