content: package com.agentdid127.resourcepack.library.utilities;
  
  import java.io.*;
  import java.util.ArrayList;
  import java.util.Arrays;
  import java.util.List;
  
  /**
   * 
   * Retrieved from http://www.javapractices.com/topic/TopicAction.do?Id=257.
   * 
   * 
   * Detect and remove Byte Order Marks (BOMs) from text files saved with a
   * Unicode encoding.
   * 
   * <P>
   * Dev tool only. If you use this tool to remove BOMs, please ensure
   * you have made a backup.
   * 
   * <P>
   * This class assumes the UTF-8 encoding for the BOM, but
   * is easily changed to handle any encoding.
   * See http://en.wikipedia.org/wiki/Byte_order_mark for more info.
   * JDK 5+.
   */
  public final class BomDetector {
      /*
       * /** Run the tool against a root directory.
       * public static void main(String... args) throws IOException{
       * BomDetector bom = new BomDetector(
       * "C:\\Temp3\\test\\",
       * ".txt", ".jsp", ".jspf", ".tag", ".html",
       * ".css", ".xml", ".js", ".sql", ".tld"
       * );
       * 
       * int count = 0;
       * for(String file : bom.findBOMs()){
       * log(file);
       * ++count;
       * }
       * log("Number of files with BOM:" + count);
       * 
       * /*
       * for(String file : bom.removeBOMs()){
       * log("Removed BOM from: " + file);
       * }
       * 
       * }
       */
  
      public BomDetector(String rootDirectory, String... fileExtensions) {
          this.rootDir = new File(rootDirectory);
          this.extensions = Arrays.asList(fileExtensions);
          if (!rootDir.exists() || rootDir.isFile())
              throw new RuntimeException("Root directory not valid.");
      }
  
      /** Find files with BOMs under the given root directory. Return their names. */
      public List<String> findBOMs() throws IOException {
          List<String> result = new ArrayList<String>();
          for (File textFile : findTextFilesBeneath(rootDir))
              if (startsWithBOM(textFile))
                  result.add(textFile.getCanonicalPath());
          return result;
      }
  
      /**
       * Find and remove BOMs from files under the given root directory.
       * Overwrites files.
       * Return the names of the affected files.
       */
      public List<String> removeBOMs() throws IOException {
          List<String> result = new ArrayList<String>();
          for (String bomFile : findBOMs()) {
              stripBomFrom(bomFile);
              result.add(bomFile);
          }
          return result;
      }
  
      // PRIVATE
      private File rootDir;
      private List<String> extensions;
  
      /** Different encodings will have different BOMs. This is for UTF-8. */
      private final int[] BYTE_ORDER_MARK = { 239, 187, 191 };
  
      private List<File> findTextFilesBeneath(File startingDir) throws IOException {
          List<File> result = new ArrayList<File>();
          File[] filesAndDirs = startingDir.listFiles();
          List<File> filesDirs = Arrays.asList(filesAndDirs);
          for (File file : filesDirs) {
              if (isTextFile(file))
                  result.add(file);
              if (file.isDirectory()) {
                  // recursive call!!
                  List<File> deeperList = findTextFilesBeneath(file);
                  result.addAll(deeperList);
              }
          }
          return result;
      }
  
      private boolean isTextFile(File file) throws IOException {
          boolean result = false;
          String fileName = file.getCanonicalPath();
          int finalDot = fileName.lastIndexOf(".");
          if (finalDot > -1) {
              String extension = fileName.substring(finalDot);
              result = extensions.contains(extension);
          }
          return result;
      }
  
      private boolean startsWithBOM(File textFile) throws IOException {
          boolean result = false;
          if (textFile.length() < BYTE_ORDER_MARK.length)
              return false;
          // open as bytes here, not characters
          int[] firstFewBytes = new int[BYTE_ORDER_MARK.length];
          InputStream input = null;
          try {
              input = new FileInputStream(textFile);
              for (int index = 0; index < BYTE_ORDER_MARK.length; ++index)
                  firstFewBytes[index] = input.read(); // read a single byte
              result = Arrays.equals(firstFewBytes, BYTE_ORDER_MARK);
          } finally {
              input.close();
          }
          return result;
      }
  
      private void stripBomFrom(String textFile) throws IOException {
          File bomFile = new File(textFile);
          long initialSize = bomFile.length();
          long truncatedSize = initialSize - BYTE_ORDER_MARK.length;
          byte[] memory = new byte[(int) (truncatedSize)];
          InputStream input = null;
          try {
              input = new BufferedInputStream(new FileInputStream(bomFile));
              input.skip(BYTE_ORDER_MARK.length);
              int totalBytesReadIntoMemory = 0;
              while (totalBytesReadIntoMemory < truncatedSize) {
                  int bytesRemaining = (int) truncatedSize - totalBytesReadIntoMemory;
                  int bytesRead = input.read(memory, totalBytesReadIntoMemory, bytesRemaining);
                  if (bytesRead > 0)
                      totalBytesReadIntoMemory = totalBytesReadIntoMemory + bytesRead;
              }
              overwriteWithoutBOM(memory, bomFile);
          } finally {
              input.close();
          }
          File after = new File(textFile);
          long finalSize = after.length();
          long changeInSize = initialSize - finalSize;
          if (changeInSize != BYTE_ORDER_MARK.length) {
              throw new RuntimeException(
                      "Change in file size: " + changeInSize + " Expected change: " + BYTE_ORDER_MARK.length);
          }
      }
  
      private void overwriteWithoutBOM(byte[] bytesWithoutBOM, File textFile) throws IOException {
          OutputStream output = null;
          try {
              output = new BufferedOutputStream(new FileOutputStream(textFile));
              output.write(bytesWithoutBOM);
          } finally {
              output.close();
          }
      }
  }