import java.io.*;

/**
 * Command line program to identify files that are not JPEG files,
 * print their names to standard output and optionally (if switch
 * -d was used) delete those files.
 * This program may be useful to identify JPEG files which were
 * truncated because of file transfer errors or partial recovery.
 *
 * Program parameters have to be either file names or the switch "-d".
 *
 * Note: if -d is used, <em>all</em> files are deleted that do not end 
 * in a certain byte sequence, not only those, who appear JPEG but aren't.
 * So use with care.
 *
 * Note: This program is not a full JPEG parser. It uses a heuristical
 * approach which may identify files as JPEG which in fact are not.
 * However, those "false positives" are relatively unlikely (1:65,536
 * for a random file).
 *
 * Best copy all files to be examined to a temporary directory and
 * run this program on that directory, to avoid accidental deletion:
 * <pre>java IdentifyTruncatedJpeg -d c:\temp\*</pre>
 *
 * License: This program and its source code are contributed to the
 * Public Domain.
 *
 * @author Marco Schmidt
 * @created 2006-10-31
 */
public class IdentifyTruncatedJpeg {
  private static boolean deleteNonJpegFiles;

  public static void main(String[] args) {
    // search for delete switch -d
    for (int i = 0; i < args.length; i++) {
      if ("-d".equals(args[i])) {
        deleteNonJpegFiles = true;
        break;
      }
    }
    // process all files
    for (int i = 0; i < args.length; i++) {
      String fileName = args[i];
      // skip switches
      if (fileName.startsWith("-")) {
        continue;
      }
      // check if file is a valid JPEG file
      if (!isValidJpeg(fileName)) {
        // no, it's not; print its name
        System.out.println(fileName);
        // delete it if that option was set
        if (deleteNonJpegFiles) {
          File file = new File(fileName);
          if (!file.delete()) {
            System.err.println("Could not delete " + fileName);
          }
        }
      }
    }
  }

  /**
   * @return true iff file is >= 50 bytes and contains a certain
   *  byte signature at the end
   */
  private static boolean isValidJpeg(String fileName) {
    boolean validJpeg = false;
    try {
      // open file for reading
      RandomAccessFile raf = new RandomAccessFile(fileName, "r");
      // determine its size in bytes
      long length = raf.length();
      // assume JPEG minimum file size is 50 bytes
      if (length >= 50) {
        // set file pointer before the last two bytes
        raf.seek(length - 2);
        // read those two bytes
        byte[] buffer = new byte[2];
        raf.readFully(buffer);
        // check if they contain the JPEG end-of-stream marker
        if (buffer[0] == (byte)0xff && buffer[1] == (byte)0xd9) {
          validJpeg = true;
        }
      }
      // close file
      raf.close();
    }
    catch (IOException ioe) {
      // print I/O errors to standard error
      ioe.printStackTrace();
    }
    return validJpeg;
  }
}
