gt:                 date = DateExtractor.parse(dateStr);
context: package com.fillumina.emailrecovery;
  
  import java.io.File;
  import java.io.FileReader;
  import java.io.IOException;
  import java.util.ArrayList;
  import java.util.Date;
  import java.util.List;
  import java.util.regex.Pattern;
  
  /**
   *
   * @author Francesco Illuminati <fillumina@gmail.com>
   */
  public class FileParser {
      private static final Pattern HEADER =
              Pattern.compile("^[A-Z][A-Za-z0-9_0\\-]{1,}:\\ ");
      private static final String RECOVERY_HEADER = "X-Recovery-Fix-Import: ";
      private static final boolean SAVE_FRAGMENTS = false; // for debugging
  
      private static final String[] START_MAIL_HEADERS = new String[] {
          "From - ",
          "From ???@??? ",
          "Return-Path: ",
          "Received: from",
          "X-Mozilla-",
          "X-Spam-",
          "X-Account-Key: ",
          "X-Original-To: ",
          "X-UIDL: ",
          "X-Mozilla-Status: ",
          "X-Mozilla-Status2: ",
          "X-Mozilla-Keys: ",
          "X-Spam-Checker-Version: "
      };
  
      private final OwnAddress ownAddress;
      private final Logger log;
      private final FileFactory fileFactory;
      private final boolean write;
      private int mails, fragments;
  
      public FileParser(OwnAddress ownAddress,
              Logger log,
              FileFactory fileFactory,
              boolean write) {
          this.ownAddress = ownAddress;
          this.log = log;
          this.fileFactory = fileFactory;
          this.write = write;
      }
  
      public void parse(File file) throws IOException {
          final FileLoaderIterator iterator =
                  new FileLoaderIterator(new FileReader(file), 0);
          new Inner(file).parse(iterator);
      }
  
      public int getMails() {
          return mails;
      }
  
      public int getFragments() {
          return fragments;
      }
  
      private enum Status {
          HEADER, BODY
      }
  
      private class Inner {
          private final File file;
          private final List<String> text = new ArrayList<>();
          private String from;
          private String subject;
          private String id;
          private String contentType;
          private String closeBoundary;
          private String openBoundary;
          private Date date;
          private boolean untrustableDate = true;
          private Status status = Status.BODY;
          private int limboBodyLines;
  
          public Inner(File file) {
              this.file = file;
          }
  
          private void clearVariables() {
              text.clear();
              from = null;
              subject = null;
              id = null;
              contentType = null;
              closeBoundary = null;
              openBoundary = null;
              date = null;
              untrustableDate = true;
              status = Status.BODY;
              limboBodyLines = 0;
          }
  
          // passing here an iterable should make it easier to test
          public void parse(Iterable<String> iterable) throws IOException {
              final String absolutePath = file.getAbsolutePath();
              log.print("parsing " + absolutePath + "...");
  
              int binaryCounter = 0, lastBinaryCounter = 0;
              final List<String> limbo = new ArrayList<>();
              String line;
  
              for (String row : iterable) {
                  line = cleanBinaryData(row, binaryCounter > 0);
                  if (line == null) {
                      // binary data
                      binaryCounter += row.length();
                      if (!limbo.isEmpty()) {
                          int size = 0;
                          for (String l : limbo) {
                              size += l.length() + 1; // CR
                          }
                          binaryCounter += size + lastBinaryCounter;
                          limbo.clear();
                          lastBinaryCounter = 0;
                      }
                      continue;
                  }
  
                  int length = line.length();
                  if (binaryCounter > 0 || (!limbo.isEmpty() && limbo.size() < 5)) {
                      if (line.isEmpty() || // CR within a binary blob
                              length < 5 || // random txt
                              line.indexOf(' ') == -1) { // random
                          binaryCounter += length;
                          continue;
                      }
                      limbo.add(line);
                      log.print("limbo (" + binaryCounter + ")= " + line);
                      lastBinaryCounter = binaryCounter;
                      binaryCounter = 0;
                      continue;
                  }
  
                  if (!limbo.isEmpty()) {
                      log.print("binary data size= " + lastBinaryCounter);
                      log.print("file=" + file.getAbsolutePath());
                      log.print("first text after bin: ");
                      log.dump(limbo);
  
                      for (String l : limbo) {
                          parseLine(l);
                      }
  
                      lastBinaryCounter = 0;
                      limbo.clear();
                      continue;
                  }
  
                  parseLine(line);
  
                  text.add(line);
              }
              checkIfMailIsInBuffer();
          }
  
          private void parseLine(String line) throws IOException {
              log.printDebugLine(line);
  
              switch(status) {
                  case BODY:
                      // search for a new email
                      if (isStartingHeader(line)) {
                          log.print("start of email");
                          checkIfMailIsInBuffer();
                          status = Status.HEADER;
                          break;
                      } else {
                          limboBodyLines = 0;
                          checkBoundary(line);
                      }
                      break;
  
                  case HEADER:
                      if (isBodyText(line)) {
                          log.print("limbo body");
                          limboBodyLines++;
                          checkBoundary(line);
                          if (limboBodyLines > 2) {
                              // to overcome text noise in headers
                              log.print("starting body");
                              status = Status.BODY;
                          }
                          break;
                      } else {
                          limboBodyLines = 0;
                          readHeader(line);
                      }
                      break;
              }
  
          }
  
          private void checkIfMailIsInBuffer() throws IOException {
              if (text.isEmpty() || from == null || date == null) {
                  clearVariables();
                  return;
              }
              save();
              clearVariables();
          }
  
          private boolean isBodyText(String line) {
              return !line.startsWith(" ") &&
                      !line.startsWith("\t") &&
                      !HEADER.matcher(line).find();
          }
  
          private boolean isStartingHeader(String line) {
              for (String header : START_MAIL_HEADERS) {
                  if (line.startsWith(header)) {
                      return true;
                  }
              }
              return false;
          }
  
          private void readHeader(String line) throws IOException {
              // use every possible mean to capture a date
              if (date == null && line.startsWith("From - ")) {
                  final String dateStr = line.substring(7);
  