Autopsy  4.17.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
ExtractEdge.java
Go to the documentation of this file.
1 /*
2  *
3  * Autopsy Forensic Browser
4  *
5  * Copyright 2019-2020 Basis Technology Corp.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 package org.sleuthkit.autopsy.recentactivity;
20 
21 import java.io.File;
22 import java.io.FileInputStream;
23 import java.io.FileNotFoundException;
24 import java.io.IOException;
25 import java.nio.file.Path;
26 import java.nio.file.Paths;
27 import java.util.Date;
28 import java.text.ParseException;
29 import java.text.SimpleDateFormat;
30 import java.text.DateFormat;
31 import java.util.ArrayList;
32 import java.util.Arrays;
33 import java.util.Collection;
34 import java.util.HashMap;
35 import java.util.List;
36 import java.util.Locale;
37 import java.util.Scanner;
38 import java.util.logging.Level;
39 import java.util.regex.Matcher;
40 import java.util.regex.Pattern;
41 import org.openide.modules.InstalledFileLocator;
42 import org.openide.util.NbBundle.Messages;
54 import org.sleuthkit.datamodel.AbstractFile;
55 import org.sleuthkit.datamodel.BlackboardArtifact;
56 import org.sleuthkit.datamodel.Content;
57 import org.sleuthkit.datamodel.TskCoreException;
58 
62 final class ExtractEdge extends Extract {
63 
64  private static final Logger LOG = Logger.getLogger(ExtractEdge.class.getName());
65  private final Path moduleTempResultPath;
66  private Content dataSource;
67  private IngestJobContext context;
68  private HashMap<String, ArrayList<String>> containersTable;
69 
70  private static final String EDGE = "Edge"; //NON-NLS
71 
72  private static final String EDGE_KEYWORD_VISIT = "Visited:"; //NON-NLS
73  private static final String IGNORE_COMMA_IN_QUOTES_REGEX = ",(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)"; //NON-NLS
74 
75  private static final String EDGE_TABLE_TYPE_DOWNLOAD = "iedownload"; //NON-NLS
76  private static final String EDGE_TABLE_TYPE_HISTORY = "History"; //NON-NLS
77  private static final String EDGE_TABLE_TYPE_COOKIE = "cookie"; //NON-NLS
78 
79  private static final String EDGE_HEAD_URL = "url"; //NON-NLS
80  private static final String EDGE_HEAD_ACCESSTIME = "accessedtime"; //NON-NLS
81  private static final String EDGE_HEAD_NAME = "name"; //NON-NLS
82  private static final String EDGE_HEAD_CONTAINER_ID = "containerid"; //NON-NLS
83  private static final String EDGE_HEAD_RESPONSEHEAD = "responseheaders"; //NON-NLS
84  private static final String EDGE_HEAD_TITLE = "title"; //NON-NLS
85  private static final String EDGE_HEAD_RDOMAIN = "rdomain"; //NON-NLS
86  private static final String EDGE_HEAD_VALUE = "value"; //NON-NLS
87  private static final String EDGE_HEAD_LASTMOD = "lastmodified"; //NON-NLS
88 
89  private static final String EDGE_WEBCACHE_PREFIX = "WebCacheV01"; //NON-NLS
90  private static final String EDGE_CONTAINER_FILE_PREFIX = "Container_"; //NON-NLS
91  private static final String EDGE_CONTAINER_FILE_EXT = ".csv"; //NON-NLS
92  private static final String EDGE_WEBCACHE_EXT = ".dat"; //NON-NLS
93 
94  private static final String ESE_TOOL_NAME = "ESEDatabaseView.exe"; //NON-NLS
95  private static final String EDGE_WEBCACHE_NAME = "WebCacheV01.dat"; //NON-NLS
96  private static final String EDGE_SPARTAN_NAME = "Spartan.edb"; //NON-NLS
97  private static final String EDGE_CONTAINTERS_FILE_NAME = "Containers.csv"; //NON-NLS
98  private static final String EDGE_FAVORITE_FILE_NAME = "Favorites.csv"; //NON-NLS
99  private static final String EDGE_OUTPUT_FILE_NAME = "Output.txt"; //NON-NLS
100  private static final String EDGE_ERROR_FILE_NAME = "File.txt"; //NON-NLS
101  private static final String EDGE_WEBCACHE_FOLDER_NAME = "WebCache"; //NON-NLS
102  private static final String EDGE_SPARTAN_FOLDER_NAME = "MicrosoftEdge"; //NON-NLS
103 
104  private static final String ESE_TOOL_FOLDER = "ESEDatabaseView"; //NON-NLS
105  private static final String EDGE_RESULT_FOLDER_NAME = "results"; //NON-NLS
106 
107  // ESEDatabaseView converts long timestamps into a string based on the current locale,
108  // so the default format may not always work.
109  private SimpleDateFormat previouslyValidDateFormat = null;
110 
111  @Messages({
112  "ExtractEdge_process_errMsg_unableFindESEViewer=Unable to find ESEDatabaseViewer",
113  "ExtractEdge_process_errMsg_errGettingWebCacheFiles=Error trying to retrieving Edge WebCacheV01 file",
114  "ExtractEdge_process_errMsg_webcacheFail=Failure processing Microsoft Edge WebCacheV01.dat file",
115  "ExtractEdge_process_errMsg_spartanFail=Failure processing Microsoft Edge spartan.edb file",
116  "ExtractEdge_Module_Name=Microsoft Edge",
117  "ExtractEdge_getHistory_containerFileNotFound=Error while trying to analyze Edge history",
118  "Progress_Message_Edge_History=Microsoft Edge History",
119  "Progress_Message_Edge_Bookmarks=Microsoft Edge Bookmarks",
120  "Progress_Message_Edge_Cookies=Microsoft Edge Cookies",
121  })
122 
126  ExtractEdge() throws NoCurrentCaseException {
127  moduleTempResultPath = Paths.get(RAImageIngestModule.getRATempPath(Case.getCurrentCaseThrows(), EDGE), EDGE_RESULT_FOLDER_NAME);
128  }
129 
130  @Override
131  protected String getName() {
132  return Bundle.ExtractEdge_Module_Name();
133  }
134 
135  @Override
136  void process(Content dataSource, IngestJobContext context, DataSourceIngestModuleProgress progressBar) {
137  this.dataSource = dataSource;
138  this.context = context;
139  this.setFoundData(false);
140 
141  List<AbstractFile> webCacheFiles = null;
142  List<AbstractFile> spartanFiles = null;
143 
144  try {
145  webCacheFiles = fetchWebCacheDBFiles();
146  } catch (TskCoreException ex) {
147  this.addErrorMessage(Bundle.ExtractEdge_process_errMsg_errGettingWebCacheFiles());
148  LOG.log(Level.SEVERE, "Error fetching 'WebCacheV01.dat' files for Microsoft Edge", ex); //NON-NLS
149  }
150 
151  try {
152  spartanFiles = fetchSpartanDBFiles(); // For later use with bookmarks
153  } catch (TskCoreException ex) {
154  this.addErrorMessage(Bundle.ExtractEdge_process_errMsg_spartanFail());
155  LOG.log(Level.SEVERE, "Error fetching 'spartan.edb' files for Microsoft Edge", ex); //NON-NLS
156  }
157 
158  // No edge files found
159  if (webCacheFiles == null && spartanFiles == null) {
160  return;
161  }
162 
163  this.setFoundData(true);
164 
165  if (!PlatformUtil.isWindowsOS()) {
166  LOG.log(Level.WARNING, "Microsoft Edge files found, unable to parse on Non-Windows system"); //NON-NLS
167  return;
168  }
169 
170  final String esedumper = getPathForESEDumper();
171  if (esedumper == null) {
172  LOG.log(Level.SEVERE, "Error finding ESEDatabaseViewer program"); //NON-NLS
173  this.addErrorMessage(Bundle.ExtractEdge_process_errMsg_unableFindESEViewer());
174  return; //If we cannot find the ESEDatabaseView we cannot proceed
175  }
176 
177  try {
178  this.processWebCacheDbFile(esedumper, webCacheFiles, progressBar);
179  } catch (IOException | TskCoreException ex) {
180  LOG.log(Level.SEVERE, "Error processing 'WebCacheV01.dat' files for Microsoft Edge", ex); // NON-NLS
181  this.addErrorMessage(Bundle.ExtractEdge_process_errMsg_webcacheFail());
182  }
183 
184  progressBar.progress(Bundle.Progress_Message_Edge_Bookmarks());
185  try {
186  this.processSpartanDbFile(esedumper, spartanFiles);
187  } catch (IOException | TskCoreException ex) {
188  LOG.log(Level.SEVERE, "Error processing 'spartan.edb' files for Microsoft Edge", ex); // NON-NLS
189  this.addErrorMessage(Bundle.ExtractEdge_process_errMsg_spartanFail());
190  }
191  }
192 
202  void processWebCacheDbFile(String eseDumperPath, List<AbstractFile> webCacheFiles, DataSourceIngestModuleProgress progressBar) throws IOException, TskCoreException {
203 
204  for (AbstractFile webCacheFile : webCacheFiles) {
205 
206  if (context.dataSourceIngestIsCancelled()) {
207  return;
208  }
209 
210  clearContainerTable();
211 
212  //Run the dumper
213  String tempWebCacheFileName = EDGE_WEBCACHE_PREFIX
214  + Integer.toString((int) webCacheFile.getId()) + EDGE_WEBCACHE_EXT; //NON-NLS
215  File tempWebCacheFile = new File(RAImageIngestModule.getRATempPath(currentCase, EDGE), tempWebCacheFileName);
216 
217  try {
218  ContentUtils.writeToFile(webCacheFile, tempWebCacheFile,
219  context::dataSourceIngestIsCancelled);
220  } catch (IOException ex) {
221  throw new IOException("Error writingToFile: " + webCacheFile, ex); //NON-NLS
222  }
223 
224  File resultsDir = new File(moduleTempResultPath.toAbsolutePath() + Integer.toString((int) webCacheFile.getId()));
225  resultsDir.mkdirs();
226  try {
227  executeDumper(eseDumperPath, tempWebCacheFile.getAbsolutePath(),
228  resultsDir.getAbsolutePath());
229 
230  if (context.dataSourceIngestIsCancelled()) {
231  return;
232  }
233 
234  progressBar.progress(Bundle.Progress_Message_Edge_History());
235 
236  this.getHistory(webCacheFile, resultsDir);
237 
238  if (context.dataSourceIngestIsCancelled()) {
239  return;
240  }
241 
242  progressBar.progress(Bundle.Progress_Message_Edge_Cookies());
243 
244  this.getCookies(webCacheFile, resultsDir);
245 
246  } finally {
247  tempWebCacheFile.delete();
248  FileUtil.deleteFileDir(resultsDir);
249  }
250  }
251  }
252 
262  void processSpartanDbFile(String eseDumperPath, List<AbstractFile> spartanFiles) throws IOException, TskCoreException {
263 
264  for (AbstractFile spartanFile : spartanFiles) {
265 
266  if (context.dataSourceIngestIsCancelled()) {
267  return;
268  }
269 
270  //Run the dumper
271  String tempSpartanFileName = EDGE_WEBCACHE_PREFIX
272  + Integer.toString((int) spartanFile.getId()) + EDGE_WEBCACHE_EXT;
273  File tempSpartanFile = new File(RAImageIngestModule.getRATempPath(currentCase, EDGE), tempSpartanFileName);
274 
275  try {
276  ContentUtils.writeToFile(spartanFile, tempSpartanFile,
277  context::dataSourceIngestIsCancelled);
278  } catch (IOException ex) {
279  throw new IOException("Error writingToFile: " + spartanFile, ex); //NON-NLS
280  }
281 
282  File resultsDir = new File(moduleTempResultPath.toAbsolutePath() + Integer.toString((int) spartanFile.getId()));
283  resultsDir.mkdirs();
284  try {
285  executeDumper(eseDumperPath, tempSpartanFile.getAbsolutePath(),
286  resultsDir.getAbsolutePath());
287 
288  if (context.dataSourceIngestIsCancelled()) {
289  return;
290  }
291 
292  this.getBookmarks(spartanFile, resultsDir);
293 
294  } finally {
295  tempSpartanFile.delete();
296  FileUtil.deleteFileDir(resultsDir);
297  }
298  }
299  }
300 
310  private void getHistory(AbstractFile origFile, File resultDir) throws TskCoreException, FileNotFoundException {
311  ArrayList<File> historyFiles = getHistoryFiles(resultDir);
312 
313  if (historyFiles == null) {
314  return;
315  }
316 
317  for (File file : historyFiles) {
318  if (context.dataSourceIngestIsCancelled()) {
319  return;
320  }
321 
322  Scanner fileScanner;
323  try {
324  fileScanner = new Scanner(new FileInputStream(file.toString()));
325  } catch (FileNotFoundException ex) {
326  LOG.log(Level.WARNING, "Unable to find the ESEDatabaseView file at " + file.getPath(), ex); //NON-NLS
327  continue; // If we couldn't open this file, continue to the next file
328  }
329 
330  Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
331 
332  try {
333  List<String> headers = null;
334  while (fileScanner.hasNext()) {
335  if (context.dataSourceIngestIsCancelled()) {
336  return;
337  }
338 
339  String line = fileScanner.nextLine();
340  if (headers == null) {
341  headers = Arrays.asList(line.toLowerCase().split(","));
342  continue;
343  }
344 
345  if (line.contains(EDGE_KEYWORD_VISIT)) {
346  BlackboardArtifact ba = getHistoryArtifact(origFile, headers, line);
347  if (ba != null) {
348  bbartifacts.add(ba);
349  }
350  }
351  }
352  } finally {
353  fileScanner.close();
354  }
355 
356  if (!bbartifacts.isEmpty()) {
357  postArtifacts(bbartifacts);
358  }
359  }
360  }
361 
370  private void getBookmarks(AbstractFile origFile, File resultDir) throws TskCoreException {
371  Scanner fileScanner;
372  File favoriteFile = new File(resultDir, EDGE_FAVORITE_FILE_NAME);
373 
374  try {
375  fileScanner = new Scanner(new FileInputStream(favoriteFile));
376  } catch (FileNotFoundException ex) {
377  // This is a non-fatal error, if the favorites file is not found
378  // there might have not been any favorites\bookmarks
379  return;
380  }
381 
382  Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
383 
384  try {
385  List<String> headers = null;
386  while (fileScanner.hasNext()) {
387  String line = fileScanner.nextLine();
388  if (headers == null) {
389  headers = Arrays.asList(line.toLowerCase().split(","));
390  continue;
391  }
392 
393  BlackboardArtifact ba = getBookmarkArtifact(origFile, headers, line);
394  if (ba != null) {
395  bbartifacts.add(ba);
396  }
397  }
398  } finally {
399  fileScanner.close();
400  }
401 
402  if (!bbartifacts.isEmpty()) {
403  postArtifacts(bbartifacts);
404  }
405  }
406 
414  private void getCookies(AbstractFile origFile, File resultDir) throws TskCoreException {
415  File containerFiles[] = resultDir.listFiles((dir, name) -> name.toLowerCase().contains(EDGE_TABLE_TYPE_COOKIE));
416 
417  if (containerFiles == null) {
418  return;
419  }
420 
421  for (File file : containerFiles) {
422  if (context.dataSourceIngestIsCancelled()) {
423  return;
424  }
425 
426  Scanner fileScanner;
427  try {
428  fileScanner = new Scanner(new FileInputStream(file.toString()));
429  } catch (FileNotFoundException ex) {
430  LOG.log(Level.WARNING, "Unable to find the ESEDatabaseView file at " + file.getPath(), ex); //NON-NLS
431  continue; // If we couldn't open this file, continue to the next file
432  }
433 
434  Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
435 
436  try {
437  List<String> headers = null;
438  while (fileScanner.hasNext()) {
439  if (context.dataSourceIngestIsCancelled()) {
440  return;
441  }
442 
443  String line = fileScanner.nextLine();
444  if (headers == null) {
445  headers = Arrays.asList(line.toLowerCase().split(","));
446  continue;
447  }
448 
449  BlackboardArtifact ba = getCookieArtifact(origFile, headers, line);
450  if (ba != null) {
451  bbartifacts.add(ba);
452  }
453  }
454  } finally {
455  fileScanner.close();
456  }
457 
458  if (!bbartifacts.isEmpty()) {
459  postArtifacts(bbartifacts);
460  }
461  }
462  }
463 
474  private void getDownloads(AbstractFile origFile, File resultDir) throws TskCoreException, FileNotFoundException {
475  ArrayList<File> downloadFiles = getDownloadFiles(resultDir);
476 
477  if (downloadFiles == null) {
478  return;
479  }
480 
481  for (File file : downloadFiles) {
482  if (context.dataSourceIngestIsCancelled()) {
483  return;
484  }
485 
486  Scanner fileScanner;
487  try {
488  fileScanner = new Scanner(new FileInputStream(file.toString()));
489  } catch (FileNotFoundException ex) {
490  LOG.log(Level.WARNING, "Unable to find the ESEDatabaseView file at " + file.getPath(), ex); //NON-NLS
491  continue; // If we couldn't open this file, continue to the next file
492  }
493  Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
494 
495  try {
496  List<String> headers = null;
497  while (fileScanner.hasNext()) {
498  if (context.dataSourceIngestIsCancelled()) {
499  return;
500  }
501 
502  String line = fileScanner.nextLine();
503  if (headers == null) {
504  headers = Arrays.asList(line.toLowerCase().split(","));
505  continue;
506  }
507 
508  if (line.contains(EDGE_TABLE_TYPE_DOWNLOAD)) {
509 
510  BlackboardArtifact ba = getDownloadArtifact(origFile, headers, line);
511  if (ba != null) {
512  bbartifacts.add(ba);
513  }
514  }
515  }
516  } finally {
517  fileScanner.close();
518  }
519 
520  postArtifacts(bbartifacts);
521  }
522  }
523 
529  private String getPathForESEDumper() {
530  Path path = Paths.get(ESE_TOOL_FOLDER, ESE_TOOL_NAME);
531  File eseToolFile = InstalledFileLocator.getDefault().locate(path.toString(),
532  ExtractEdge.class.getPackage().getName(), false);
533  if (eseToolFile != null) {
534  return eseToolFile.getAbsolutePath();
535  }
536 
537  return null;
538  }
539 
546  private List<AbstractFile> fetchWebCacheDBFiles() throws TskCoreException {
548  = currentCase.getServices().getFileManager();
549  return fileManager.findFiles(dataSource, EDGE_WEBCACHE_NAME, EDGE_WEBCACHE_FOLDER_NAME);
550  }
551 
558  private List<AbstractFile> fetchSpartanDBFiles() throws TskCoreException {
560  = currentCase.getServices().getFileManager();
561  return fileManager.findFiles(dataSource, EDGE_SPARTAN_NAME, EDGE_SPARTAN_FOLDER_NAME);
562  }
563 
575  private void executeDumper(String dumperPath, String inputFilePath,
576  String outputDir) throws IOException {
577 
578  final Path outputFilePath = Paths.get(outputDir, EDGE_OUTPUT_FILE_NAME);
579  final Path errFilePath = Paths.get(outputDir, EDGE_ERROR_FILE_NAME);
580  LOG.log(Level.INFO, "Writing ESEDatabaseViewer results to: {0}", outputDir); //NON-NLS
581 
582  List<String> commandLine = new ArrayList<>();
583  commandLine.add(dumperPath);
584  commandLine.add("/table"); //NON-NLS
585  commandLine.add(inputFilePath);
586  commandLine.add("*"); //NON-NLS
587  commandLine.add("/scomma"); //NON-NLS
588  commandLine.add(outputDir + "\\" + "*.csv"); //NON-NLS
589 
590  ProcessBuilder processBuilder = new ProcessBuilder(commandLine);
591  processBuilder.redirectOutput(outputFilePath.toFile());
592  processBuilder.redirectError(errFilePath.toFile());
593 
594  ExecUtil.execute(processBuilder, new DataSourceIngestModuleProcessTerminator(context, true));
595  }
596 
607  private BlackboardArtifact getHistoryArtifact(AbstractFile origFile, List<String> headers, String line) throws TskCoreException {
608  String[] rowSplit = line.split(",");
609 
610  int index = headers.indexOf(EDGE_HEAD_URL);
611  String urlUserStr = rowSplit[index];
612 
613  String[] str = urlUserStr.split("@");
614  String user = (str[0].replace(EDGE_KEYWORD_VISIT, "")).trim();
615  String url = str[1];
616 
617  index = headers.indexOf(EDGE_HEAD_ACCESSTIME);
618  String accessTime = rowSplit[index].trim();
619  Long ftime = parseTimestamp(accessTime);
620 
621  BlackboardArtifact bbart = origFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_HISTORY);
622 
623  bbart.addAttributes(createHistoryAttribute(url, ftime,
624  null, null,
625  this.getName(),
626  NetworkUtils.extractDomain(url), user));
627 
628  return bbart;
629  }
630 
640  private BlackboardArtifact getCookieArtifact(AbstractFile origFile, List<String> headers, String line) throws TskCoreException {
641  String[] lineSplit = line.split(","); // NON-NLS
642 
643  String accessTime = lineSplit[headers.indexOf(EDGE_HEAD_LASTMOD)].trim();
644  Long ftime = parseTimestamp(accessTime);
645 
646  String domain = lineSplit[headers.indexOf(EDGE_HEAD_RDOMAIN)].trim();
647  String name = hexToChar(lineSplit[headers.indexOf(EDGE_HEAD_NAME)].trim());
648  String value = hexToChar(lineSplit[headers.indexOf(EDGE_HEAD_VALUE)].trim());
649  String url = flipDomain(domain);
650 
651  BlackboardArtifact bbart = origFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_COOKIE);
652  bbart.addAttributes(createCookieAttributes(url, ftime, name, value, this.getName(), NetworkUtils.extractDomain(url)));
653  return bbart;
654  }
655 
669  private BlackboardArtifact getDownloadArtifact(AbstractFile origFile, List<String> headers, String line) throws TskCoreException {
670  BlackboardArtifact bbart = null;
671 
672  String[] lineSplit = line.split(","); // NON-NLS
673  String rheader = lineSplit[headers.indexOf(EDGE_HEAD_RESPONSEHEAD)];
674 
675  return bbart;
676  }
677 
690  private BlackboardArtifact getBookmarkArtifact(AbstractFile origFile, List<String> headers, String line) throws TskCoreException {
691  // split on all commas as long as they are not inbetween quotes
692  String[] lineSplit = line.split(IGNORE_COMMA_IN_QUOTES_REGEX, -1);
693 
694  String url = lineSplit[headers.indexOf(EDGE_HEAD_URL)];
695  String title = lineSplit[headers.indexOf(EDGE_HEAD_TITLE)].replace("\"", ""); // NON-NLS
696 
697  if (url.isEmpty()) {
698  return null;
699  }
700 
701  BlackboardArtifact bbart = origFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_BOOKMARK);
702  bbart.addAttributes(createBookmarkAttributes(url, title, null,
703  this.getName(), NetworkUtils.extractDomain(url)));
704  return bbart;
705  }
706 
707 
722  private Long parseTimestamp(String timeStr) {
723 
724  // If we had a pattern that worked on the last date, use it again.
725  if (previouslyValidDateFormat != null) {
726  try {
727  return previouslyValidDateFormat.parse(timeStr).getTime() / 1000;
728  } catch (ParseException ex) {
729  // Continue on to format detection
730  }
731  }
732 
733  // Try the default US pattern
734  try {
735  SimpleDateFormat usDateFormat = new SimpleDateFormat("MM/dd/yyyy hh:mm:ss a"); //NON-NLS
736  usDateFormat.setLenient(false); // Fail if month or day are out of range
737  Long epochTime = usDateFormat.parse(timeStr).getTime();
738  previouslyValidDateFormat = usDateFormat;
739  return epochTime / 1000;
740  } catch (ParseException ex) {
741  // Continue on to format detection
742  }
743 
744  // This generally doesn't match the data in the file but can give information on whether
745  // the month or day is first.
746  boolean monthFirstFromLocale = true;
747  String localeDatePattern = ((SimpleDateFormat) DateFormat.getDateInstance(
748  DateFormat.SHORT, Locale.getDefault())).toPattern();
749  if (localeDatePattern.startsWith("d")) {
750  monthFirstFromLocale = false;
751  }
752 
753  // Try to determine if the month or day is first by looking at the data.
754  // If both variations appear valid, use the locale result.
755  boolean monthFirst = monthFirstFromLocale;
756  Pattern pattern = Pattern.compile("^([0-9]{1,2})[^0-9]([0-9]{1,2})");
757  Matcher matcher = pattern.matcher(timeStr);
758  if (matcher.find()) {
759  int firstVal = Integer.parseInt(matcher.group(1));
760  int secondVal = Integer.parseInt(matcher.group(2));
761 
762  if (firstVal > 12) {
763  monthFirst = false;
764  } else if (secondVal > 12) {
765  monthFirst = true;
766  }
767  // Otherwise keep the setting from the locale
768  }
769 
770  // See if the time has AM/PM attached
771  boolean hasAmPm = false;
772  if (timeStr.endsWith("M") || timeStr.endsWith("m")) {
773  hasAmPm = true;
774  }
775 
776  // See if the date appears to use forward slashes. If not, assume '.' is being used.
777  boolean hasSlashes = false;
778  if (timeStr.contains("/")) {
779  hasSlashes = true;
780  }
781 
782  // Make our best guess at the pattern
783  String dateFormatPattern;
784  if (monthFirst) {
785  if (hasSlashes) {
786  dateFormatPattern = "MM/dd/yyyy ";
787  } else {
788  dateFormatPattern = "MM.dd.yyyy ";
789  }
790  } else {
791  if (hasSlashes) {
792  dateFormatPattern = "dd/MM/yyyy ";
793  } else {
794  dateFormatPattern = "dd.MM.yyyy ";
795  }
796  }
797 
798  if (hasAmPm) {
799  dateFormatPattern += "hh:mm:ss a";
800  } else {
801  dateFormatPattern += "HH:mm:ss";
802  }
803 
804  try {
805  SimpleDateFormat dateFormat = new SimpleDateFormat(dateFormatPattern); //NON-NLS
806  dateFormat.setLenient(false); // Fail if month or day are out of range
807  Long epochTime = dateFormat.parse(timeStr).getTime();
808  previouslyValidDateFormat = dateFormat;
809  return epochTime / 1000;
810  } catch (ParseException ex) {
811  LOG.log(Level.WARNING, "Timestamp could not be parsed ({0})", timeStr); //NON-NLS
812  return null;
813  }
814  }
815 
822  private String hexToChar(String hexString) {
823  String[] hexValues = hexString.split(" "); // NON-NLS
824  StringBuilder output = new StringBuilder();
825 
826  for (String str : hexValues) {
827  try {
828  int value = Integer.parseInt(str, 16);
829  if (value > 31) { // Ignore non-print characters
830  output.append((char) value);
831  }
832  } catch (NumberFormatException ex) {
833  return null;
834  }
835  }
836 
837  return output.toString();
838  }
839 
851  private String flipDomain(String domain) {
852  if (domain == null || domain.isEmpty()) {
853  return null;
854  }
855 
856  String[] tokens = domain.split("\\."); // NON-NLS
857 
858  if (tokens.length < 2 || tokens.length > 3) {
859  return domain; // don't know what to do, just send it back as is
860  }
861 
862  StringBuilder buf = new StringBuilder();
863  if (tokens.length > 2) {
864  buf.append(tokens[2]);
865  buf.append(".");
866  }
867  buf.append(tokens[1]);
868  buf.append(".");
869  buf.append(tokens[0]);
870 
871  return buf.toString();
872  }
873 
881  private ArrayList<File> getDownloadFiles(File resultDir) throws FileNotFoundException {
882  return getContainerFiles(resultDir, EDGE_TABLE_TYPE_DOWNLOAD);
883  }
884 
892  private ArrayList<File> getHistoryFiles(File resultDir) throws FileNotFoundException {
893  return getContainerFiles(resultDir, EDGE_TABLE_TYPE_HISTORY);
894  }
895 
904  private ArrayList<File> getContainerFiles(File resultDir, String type) throws FileNotFoundException {
905  HashMap<String, ArrayList<String>> idTable = getContainerIDTable(resultDir);
906 
907  ArrayList<String> idList = idTable.get(type);
908  if (idList == null) {
909  return null;
910  }
911 
912  ArrayList<File> fileList = new ArrayList<>();
913  for (String str : idList) {
914  String fileName = EDGE_CONTAINER_FILE_PREFIX + str + EDGE_CONTAINER_FILE_EXT;
915  fileList.add(new File(resultDir, fileName));
916  }
917 
918  return fileList;
919  }
920 
931  private HashMap<String, ArrayList<String>> getContainerIDTable(File resultDir) throws FileNotFoundException {
932 
933  if (containersTable == null) {
934  File containerFile = new File(resultDir, EDGE_CONTAINTERS_FILE_NAME);
935 
936  try (Scanner fileScanner = new Scanner(new FileInputStream(containerFile))) {
937  List<String> headers = null;
938  containersTable = new HashMap<>();
939  int nameIdx = 0;
940  int idIdx = 0;
941  while (fileScanner.hasNext()) {
942  String line = fileScanner.nextLine();
943  if (headers == null) {
944  headers = Arrays.asList(line.toLowerCase().split(","));
945  nameIdx = headers.indexOf(EDGE_HEAD_NAME);
946  idIdx = headers.indexOf(EDGE_HEAD_CONTAINER_ID);
947  } else {
948  String[] row = line.split(","); // NON-NLS
949  String name = row[nameIdx];
950  String id = row[idIdx];
951 
952  ArrayList<String> idList = containersTable.get(name);
953  if (idList == null) {
954  idList = new ArrayList<>();
955  containersTable.put(name, idList);
956  }
957 
958  idList.add(id);
959  }
960  }
961  }
962  }
963 
964  return containersTable;
965  }
966 
970  private void clearContainerTable(){
971  containersTable = null;
972  }
973 }
synchronized List< AbstractFile > findFiles(String fileName)

Copyright © 2012-2021 Basis Technology. Generated on: Tue Jan 19 2021
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.