FileConvert.java

/*
 * This file is part of Waarp Project (named also Waarp or GG).
 *
 *  Copyright (c) 2019, Waarp SAS, and individual contributors by the @author
 *  tags. See the COPYRIGHT.txt in the distribution for a full listing of
 * individual contributors.
 *
 *  All Waarp Project is free software: you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or (at your
 * option) any later version.
 *
 * Waarp is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along with
 * Waarp . If not, see <http://www.gnu.org/licenses/>.
 */
package org.waarp.common.utility;


import org.waarp.common.command.exception.Reply550Exception;
import org.waarp.common.file.FileUtils;
import org.waarp.common.logging.WaarpLogger;
import org.waarp.common.logging.WaarpLoggerFactory;
import org.waarp.common.logging.WaarpSlf4JLoggerFactory;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

/**
 * Description: Converts Unix files to Dos and vice versa
 */
public class FileConvert extends Thread {
  /**
   * Internal Logger
   */
  private static volatile WaarpLogger logger;

  private final boolean unix2dos;
  private final boolean recursive;
  private File tmpDir = new File(System.getProperty("java.io.tmpdir"));
  private final List<File> files;

  /**
   * @param files list of files
   * @param unix2dos True for Unix2Dos, False for Dos2Unix
   * @param recursive True for Recursive from files, else unitary
   *     files
   * @param tmpDir if not null, specific tmp directory
   */
  public FileConvert(final List<File> files, final boolean unix2dos,
                     final boolean recursive, final File tmpDir) {
    if (logger == null) {
      logger = WaarpLoggerFactory.getLogger(FileConvert.class);
    }
    this.files = files;
    this.unix2dos = unix2dos;
    this.recursive = recursive;
    if (tmpDir != null) {
      this.tmpDir = tmpDir;
    }
  }

  /**
   * Direct call
   *
   * @param args
   */
  public static void main(final String[] args) {
    WaarpLoggerFactory.setDefaultFactoryIfNotSame(
        new WaarpSlf4JLoggerFactory(null));
    if (logger == null) {
      logger = WaarpLoggerFactory.getLogger(FileConvert.class);
    }

    final ArrayList<File> files = new ArrayList<File>();
    boolean unix2dos = false;
    boolean dos2unix = false;
    boolean recursive = false;
    File tmpDir = null;
    for (int i = 0; i < args.length; i++) {
      if (Pattern.compile("^-(u|-unix2dos|-unixtodos)$",
                          Pattern.CASE_INSENSITIVE).matcher(args[i])
                 .matches()) {
        unix2dos = true;
      } else if (Pattern.compile("^-(d|-dos2unix|-dostounix)$",
                                 Pattern.CASE_INSENSITIVE).matcher(args[i])
                        .matches()) {
        dos2unix = true;
      } else if (Pattern.compile("^-(r|-recursive)$", Pattern.CASE_INSENSITIVE)
                        .matcher(args[i]).matches()) {
        recursive = true;
      } else if (Pattern.compile("^-(t|-temporary)$", Pattern.CASE_INSENSITIVE)
                        .matcher(args[i]).matches()) {
        tmpDir = new File(args[++i]);
      } else {
        files.add(new File(args[i]));
      }
    }
    if (unix2dos && dos2unix) {
      syntax();
      System.exit(1);//NOSONAR
    }
    if (!unix2dos && !dos2unix) {
      syntax();
      System.exit(1);//NOSONAR
    }
    final FileConvert fileConvert =
        new FileConvert(files, unix2dos, recursive, tmpDir);
    fileConvert.run();//NOSONAR
  }

  /**
   * Use parameters given in instantiation
   */
  @Override
  public void run() {
    if (files == null) {
      return;
    }
    for (final File file : files) {
      if (file.isDirectory()) {
        if (recursive) {
          recursive(file);
        }
      } else {
        convert(file, unix2dos);
      }
    }
  }

  private void recursive(final File directory) {
    final File[] listFiles = directory.listFiles();
    if (listFiles != null) {
      for (final File file : listFiles) {
        if (file.isDirectory()) {
          recursive(file);
        } else {
          convert(file, unix2dos);
        }
      }
    }
  }

  private boolean copyFile(final File source, final File destination) {
    try {
      FileUtils.copy(source, destination, false, false);
      return true;
    } catch (final Reply550Exception e) {
      logger.error("FileConvert copy back in error: {}", e.getMessage());
      return false;
    }
  }

  /**
   * Convert Unix2Dos or Dos2Unix file in place, according to second argument
   *
   * @param input File to change
   * @param unix2dos True for UnixToDos, False for DosToUnix
   *
   * @return True if OK
   */
  public final boolean convert(final File input, final boolean unix2dos) {
    if (unix2dos) {
      logger.info("unix2Dos conversion of '{}'... ", input);
    } else {
      logger.info("dos2Unix conversion of '{}'... ", input);
    }
    FileInputStream fis = null;
    FileOutputStream fos = null;
    File tmpFile = null;
    try {
      fis = new FileInputStream(input);
      tmpFile =
          File.createTempFile("FileConevrt_" + input.getName(), null, tmpDir);
      fos = new FileOutputStream(tmpFile);
      if (unix2dos) {
        byte pb = -1;
        byte b;
        while ((b = (byte) fis.read()) != -1) {
          if (b == 10 && pb != 13) {
            fos.write((byte) 13);
          }
          fos.write(b);
          pb = b;
        }
      } else {
        byte b;
        byte nb;
        while ((b = (byte) fis.read()) != -1) {
          if (b == 13) {
            nb = (byte) fis.read();
            if (nb == -1) {
              fos.write(b);
            } else {
              if (nb != 10) {
                fos.write(b);
              }
              fos.write(nb);
            }
          } else {
            fos.write(b);
          }
        }
      }
      final boolean result = copyFile(tmpFile, input);
      if (result) {
        logger.info("done.");
      } else {
        logger.error("FileConvert in error during final copy: " + input + ':' +
                     unix2dos);
      }
      return result;
    } catch (final FileNotFoundException e) {
      logger.error("FileConvert in error: " + input + ':' + unix2dos + ": {}",
                   e.getMessage());
      return false;
    } catch (final IOException e) {
      logger.error("FileConvert in error: " + input + ':' + unix2dos + ": {}",
                   e.getMessage());
      return false;
    } finally {
      if (tmpFile != null) {
        if (!tmpFile.delete()) {
          logger.debug("Cannot delete temp file");
        }
      }
      FileUtils.close(fis);
      FileUtils.close(fos);
    }
  }

  private static void syntax() {
    logger.error(
        "Syntax: Covnert -(u|-nix2dos|-unixtodos) | -(d|-dos2unix|-dostounix) -(t|-temporary) directory  -(r|-recursive) file directory");
  }

}