Refactored mactime-file-parsing code to fix bug that was missing many

entries. In support of AUT-745.
This commit is contained in:
Tim McIver 2013-01-16 15:55:19 -05:00
parent 17e13a5e5d
commit 8458b92f55

View File

@ -29,6 +29,7 @@ import java.io.IOException;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.text.DateFormat; import java.text.DateFormat;
import java.text.DateFormatSymbols;
import java.text.ParseException; import java.text.ParseException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
@ -196,7 +197,7 @@ public class Simile2 extends CallableSystemAction implements Presenter.Toolbar {
//Making a dropdown box to select years. //Making a dropdown box to select years.
List<String> lsi = new ArrayList<String>(); //List is in the format of {Year : Number of Events}, used for selecting from the dropdown. List<String> lsi = new ArrayList<String>(); //List is in the format of {Year : Number of Events}, used for selecting from the dropdown.
for (YearEpoch ye : lsye) { for (YearEpoch ye : lsye) {
lsi.add(ye.year + " : " + ye.total); lsi.add(ye.year + " : " + ye.getNumFiles());
} }
ObservableList<String> listSelect = FXCollections.observableArrayList(lsi); ObservableList<String> listSelect = FXCollections.observableArrayList(lsi);
dropdown_SelectYears = new ComboBox(listSelect); dropdown_SelectYears = new ComboBox(listSelect);
@ -291,7 +292,7 @@ public class Simile2 extends CallableSystemAction implements Presenter.Toolbar {
ObservableList<BarChart.Series<String, Number>> bcData = FXCollections.observableArrayList(); ObservableList<BarChart.Series<String, Number>> bcData = FXCollections.observableArrayList();
BarChart.Series<String, Number> se = new BarChart.Series<String, Number>(); BarChart.Series<String, Number> se = new BarChart.Series<String, Number>();
for (final YearEpoch ye : allYears) { for (final YearEpoch ye : allYears) {
se.getData().add(new BarChart.Data<String, Number>(String.valueOf(ye.year), ye.total)); se.getData().add(new BarChart.Data<String, Number>(String.valueOf(ye.year), ye.getNumFiles()));
} }
bcData.add(se); bcData.add(se);
@ -320,7 +321,7 @@ public class Simile2 extends CallableSystemAction implements Presenter.Toolbar {
}); });
//If a single click, hover a label over the cursor with information about the selection //If a single click, hover a label over the cursor with information about the selection
} else if (e.getClickCount() == 1) { } else if (e.getClickCount() == 1) {
l.setText(findYear(allYears, Integer.valueOf((String) data.getXValue())).total + " events"); l.setText(findYear(allYears, Integer.valueOf((String) data.getXValue())).getNumFiles() + " events");
l.setTranslateX(e.getX()); l.setTranslateX(e.getX());
l.setTranslateY(e.getY()); l.setTranslateY(e.getY());
} }
@ -350,7 +351,7 @@ public class Simile2 extends CallableSystemAction implements Presenter.Toolbar {
BarChart.Series<String, Number> se = new BarChart.Series<String, Number>(); BarChart.Series<String, Number> se = new BarChart.Series<String, Number>();
for (final MonthEpoch me : ye.months) { for (final MonthEpoch me : ye.months) {
se.getData().add(new BarChart.Data<String, Number>(me.getMonthName(), me.total)); //Adding new data at {X-pos, Y-Pos} se.getData().add(new BarChart.Data<String, Number>(me.getMonthName(), me.getNumFiles())); //Adding new data at {X-pos, Y-Pos}
} }
bcData.add(se); bcData.add(se);
final BarChart<String, Number> bc = new BarChart<String, Number>(xAxis, yAxis, bcData); final BarChart<String, Number> bc = new BarChart<String, Number>(xAxis, yAxis, bcData);
@ -373,7 +374,7 @@ public class Simile2 extends CallableSystemAction implements Presenter.Toolbar {
PlatformImpl.startup(new Runnable() { PlatformImpl.startup(new Runnable() {
@Override @Override
public void run() { public void run() {
chart_Events = createEventsByMonth(findMonth(ye.months, month_StringtoInt((String) data.getXValue()))); chart_Events = createEventsByMonth(findMonth(ye.months, month_StringtoInt((String) data.getXValue())), ye);
scroll_Events.setContent(chart_Events); scroll_Events.setContent(chart_Events);
} }
}); });
@ -396,14 +397,14 @@ public class Simile2 extends CallableSystemAction implements Presenter.Toolbar {
* Displays a chart with events from one month only. * Displays a chart with events from one month only.
* Up to 31 days per month, as low as 28 as determined by the specific MonthEpoch * Up to 31 days per month, as low as 28 as determined by the specific MonthEpoch
*/ */
private BarChart createEventsByMonth(final MonthEpoch me) { private BarChart createEventsByMonth(final MonthEpoch me, final YearEpoch ye) {
final CategoryAxis xAxis = new CategoryAxis(); final CategoryAxis xAxis = new CategoryAxis();
final NumberAxis yAxis = new NumberAxis(); final NumberAxis yAxis = new NumberAxis();
xAxis.setLabel("Day of Month"); xAxis.setLabel("Day of Month");
yAxis.setLabel("Number of Events"); yAxis.setLabel("Number of Events");
ObservableList<BarChart.Data> bcData = makeObservableListByMonthAllDays(me); ObservableList<BarChart.Data> bcData = makeObservableListByMonthAllDays(me);
BarChart.Series<String, Number> series = new BarChart.Series(bcData); BarChart.Series<String, Number> series = new BarChart.Series(bcData);
series.setName(me.getMonthName() + " " + me.year); series.setName(me.getMonthName() + " " + ye.getYear());
ObservableList<BarChart.Series<String, Number>> ol = FXCollections.observableArrayList(series); ObservableList<BarChart.Series<String, Number>> ol = FXCollections.observableArrayList(series);
@ -432,7 +433,7 @@ public class Simile2 extends CallableSystemAction implements Presenter.Toolbar {
private ObservableList<BarChart.Data> makeObservableListByMonthAllDays(final MonthEpoch me) { private ObservableList<BarChart.Data> makeObservableListByMonthAllDays(final MonthEpoch me) {
ObservableList<BarChart.Data> bcData = FXCollections.observableArrayList(); ObservableList<BarChart.Data> bcData = FXCollections.observableArrayList();
for (DayEpoch day : me.getDays()) { for (DayEpoch day : me.getDays()) {
BarChart.Data d = new BarChart.Data(me.month + 1 + "-" + String.valueOf(day.dayNum), day.events.size()); BarChart.Data d = new BarChart.Data(me.month + 1 + "-" + String.valueOf(day.dayNum), day.files.size());
d.setExtraValue(me); d.setExtraValue(me);
bcData.add(d); bcData.add(d);
} }
@ -494,63 +495,95 @@ public class Simile2 extends CallableSystemAction implements Presenter.Toolbar {
* All of those are Epochs. * All of those are Epochs.
*/ */
abstract class Epoch { abstract class Epoch {
Calendar calendar; abstract public int getNumFiles();
int year;
boolean isDay = false;
boolean isMonth = false;
boolean isYear = false;
int total = 0; //total numder of events for this epoch
Epoch(int year) {
this.year = year;
this.calendar = Calendar.getInstance();
}
} }
private class YearEpoch extends Epoch { private class YearEpoch extends Epoch {
List<MonthEpoch> months; private int year;
int numDays = 0; //Days in this year. Will be between 366 and 365 private List<MonthEpoch> months = new ArrayList<>();
YearEpoch(int year, List<MonthEpoch> months) { YearEpoch(int year) {
super(year); this.year = year;
this.calendar.set(year, 0, 1); //default to January 1st }
isYear = true;
this.months = months; public int getYear() {
return year;
}
@Override
public int getNumFiles() {
int size = 0;
for (MonthEpoch me : months) { for (MonthEpoch me : months) {
total += me.total; size += me.getNumFiles();
numDays += me.numDays;
} }
return size;
}
public void add(AbstractFile af, int month, int day) {
// see if this month is in the list
MonthEpoch monthEpoch = null;
for (MonthEpoch me : months) {
if (me.getMonthInt() == month) {
monthEpoch = me;
break;
}
}
if (monthEpoch == null) {
monthEpoch = new MonthEpoch(month);
months.add(monthEpoch);
}
// add the file the the MonthEpoch object
monthEpoch.add(af, day);
} }
} }
private class MonthEpoch extends Epoch { private class MonthEpoch extends Epoch {
int month; //Zero-indexed: June = 5, August = 7, etc private int month; //Zero-indexed: June = 5, August = 7, etc
String month_name; //Full name: January, October, July, etc private List<DayEpoch> days = new ArrayList<>(); //List of DayEpochs in this month, max 31
List<DayEpoch> days; //List of DayEpochs in this month, max 31
int numDays = 0; //Number of days in this month, max 31
MonthEpoch(int month, int year, List<DayEpoch> days) { MonthEpoch(int month) {
super(year);
isMonth = true;
this.month = month; this.month = month;
calendar.set(year, month, 1); }
java.util.Date d = new java.util.Date(calendar.getTimeInMillis());
this.month_name = new SimpleDateFormat("MMMM").format(d); public int getMonthInt() {
this.numDays = calendar.getActualMaximum(Calendar.DAY_OF_MONTH); return month;
this.year = year; }
this.days = days;
@Override
public int getNumFiles() {
int numFiles = 0;
for (DayEpoch de : days) { for (DayEpoch de : days) {
total += de.total; numFiles += de.getNumFiles();
} }
return numFiles;
}
public void add(AbstractFile af, int day) {
DayEpoch dayEpoch = null;
for (DayEpoch de : days) {
if (de.getDayInt() == day) {
dayEpoch = de;
break;
}
}
if (dayEpoch == null) {
dayEpoch = new DayEpoch(day);
days.add(dayEpoch);
}
dayEpoch.add(af);
} }
/** /**
* Returns the month's name in String format, e.g., September, July, * Returns the month's name in String format, e.g., September, July,
*/ */
String getMonthName() { String getMonthName() {
return this.month_name; return new DateFormatSymbols().getMonths()[month];
} }
/** /**
@ -563,27 +596,27 @@ public class Simile2 extends CallableSystemAction implements Presenter.Toolbar {
private class DayEpoch extends Epoch { private class DayEpoch extends Epoch {
private List<AbstractFile> events; private List<AbstractFile> files = new ArrayList<>();
int dayNum = 0; //Day of the month this Epoch represents, 1 indexed: 28=28. int dayNum = 0; //Day of the month this Epoch represents, 1 indexed: 28=28.
DayEpoch(int year, int month, int day, List<AbstractFile> events) { DayEpoch(int dayOfMonth) {
super(year); this.dayNum = dayOfMonth;
isDay = true;
this.dayNum = day;
this.events = events;
total = events.size();
} }
//Constructor for null-days to fill out a Month. public int getDayInt() {
DayEpoch(int year, int month, int day) { return dayNum;
super(year); }
this.dayNum = day;
this.events = new ArrayList<AbstractFile>(); public int getNumFiles() {
this.total = 0; return files.size();
}
public void add(AbstractFile af) {
files.add(af);
} }
List<AbstractFile> getEvents() { List<AbstractFile> getEvents() {
return this.events; return this.files;
} }
} }
@ -626,134 +659,49 @@ public class Simile2 extends CallableSystemAction implements Presenter.Toolbar {
} }
} }
/**
* Fills an array list with empty day objects according to the number of
* days in a month
*
* @param daysToFill
* @param daysInMonth Must be Zero Indexed
*/
private ArrayList<DayEpoch> fillOutDays(DayEpoch[] daysToFill, int daysInMonth, int year, int month) {
for (int i = 0; i < daysInMonth; i++) {
if (daysToFill[i] == null) {
daysToFill[i] = new DayEpoch(year, month, i + 1);
}
}
return new ArrayList<DayEpoch>(Arrays.asList(daysToFill));
}
private ArrayList<MonthEpoch> fillOutMonths(MonthEpoch[] monthsToFill, int year) {
for (int i = 0; i < 12; i++) {
if (monthsToFill[i] == null) {
Calendar cal2 = Calendar.getInstance();
cal2.set(year, i, 1);
int daysinMonth = cal2.getActualMaximum(Calendar.DAY_OF_MONTH) - 1;
monthsToFill[i] = new MonthEpoch(i, year, fillOutDays(new DayEpoch[daysinMonth], daysinMonth, year, i));
}
}
return new ArrayList<MonthEpoch>(Arrays.asList(monthsToFill));
}
private List<YearEpoch> parseMacTime(java.io.File f) { private List<YearEpoch> parseMacTime(java.io.File f) {
List<YearEpoch> years = new ArrayList<>();
Scanner scan;
try { try {
boolean firstRun = true; //used to help method not screw up on the first run scan = new Scanner(new FileInputStream(f));
Scanner scan = new Scanner(new FileInputStream(f)); } catch (FileNotFoundException ex) {
scan.nextLine(); logger.log(Level.SEVERE, "Error: could not find mactime file.", ex);
SleuthkitCase skCase = Case.getCurrentCase().getSleuthkitCase();
Calendar cal = Calendar.getInstance();
int daysInThisMonth = 31; //Number of days in the currentMonth
scan.useDelimiter(",");
String prevDate = "";
int prevYear = -1;
int prevMonth = -1;
int prevDay = -1;
long prevObjId = -1;
String prevType = "-1";
List<AbstractFile> fs = new ArrayList<AbstractFile>(); //Single day's events
DayEpoch[] dayz = new DayEpoch[31]; //Default initialization to 31 slots
MonthEpoch[] monthz = new MonthEpoch[12];
List<YearEpoch> years = new ArrayList<YearEpoch>();
while (scan.hasNextLine()) {
AbstractFsContentNode n;
String[] s = scan.nextLine().split(","); //1999-02-08T11:08:08Z, 78706, m..b, rrwxrwxrwx, 0, 0, 8355, /img...
String[] datetime = s[0].split("T"); //{1999-02-08, 11:08:08Z}
String[] date = datetime[0].split("-"); // {1999, 02, 08}
int year = Integer.valueOf(date[0]);
int month = Integer.valueOf(date[1]) - 1; //Months are zero indexed: 1 = February, 6 = July, 11 = December
int day = Integer.valueOf(date[2]); //Days are 1 indexed
String type = s[2];
long ObjId = Long.valueOf(s[4]);
//First values
if (firstRun) {
prevDate = datetime[0];
prevYear = year;
prevMonth = month;
prevDay = day;
prevObjId = ObjId;
prevType = type;
cal.set(prevYear, prevMonth, 1);
daysInThisMonth = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
dayz = new DayEpoch[daysInThisMonth];
firstRun = false;
}
/**
* End Testing Stuff
*/
//Intermediate values
if ((!prevDate.equals(datetime[0]))) { //Did the Day change?
cal.set(prevYear, prevMonth, 1);
DayEpoch d = new DayEpoch(prevYear, prevMonth, prevDay, fs);
dayz[prevDay - 1] = d;
fs = new ArrayList<AbstractFile>();
prevDate = datetime[0];
prevDay = day;
if (month != prevMonth) { //Did the Month change?
ArrayList<DayEpoch> da = fillOutDays(dayz, daysInThisMonth, prevYear, prevMonth);
MonthEpoch m = new MonthEpoch(prevMonth, prevYear, da);
monthz[prevMonth] = m;
prevMonth = month;
cal.set(prevYear, prevMonth, 1);
daysInThisMonth = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
dayz = new DayEpoch[daysInThisMonth];
if (Integer.valueOf(year) != prevYear) { //Did the Year change?
YearEpoch y = new YearEpoch(prevYear, fillOutMonths(monthz, prevYear));
monthz = new MonthEpoch[12];
years.add(y);
prevYear = Integer.valueOf(year);
}
}
prevObjId = ObjId;
prevType = type;
} else {
AbstractFile file = skCase.getAbstractFileById(ObjId);
fs.add(file);
}
}
//Final values
cal.set(prevYear, prevMonth, 1);
DayEpoch d = new DayEpoch(prevYear, prevMonth, prevDay, fs);
dayz[prevDay - 1] = d;
ArrayList<DayEpoch> da = fillOutDays(dayz, daysInThisMonth, prevYear, prevMonth);
MonthEpoch m = new MonthEpoch(prevMonth, prevYear, da);
monthz[prevMonth] = m;
YearEpoch y = new YearEpoch(prevYear, fillOutMonths(monthz, prevYear));
years.add(y);
return years; return years;
} catch (FileNotFoundException fnfe) {
logger.log(Level.SEVERE, "Error 404: can't find Mactime file", fnfe);
return null;
} catch (TskCoreException tce) {
logger.log(Level.SEVERE, "Error 500: can't parse mactime file", tce);
return null;
} }
scan.useDelimiter(",");
scan.nextLine(); // skip the header line
SleuthkitCase skCase = Case.getCurrentCase().getSleuthkitCase();
int prevYear = -1;
YearEpoch ye = null;
while (scan.hasNextLine()) {
String[] s = scan.nextLine().split(","); //1999-02-08T11:08:08Z, 78706, m..b, rrwxrwxrwx, 0, 0, 8355, /img...
String[] datetime = s[0].split("T"); //{1999-02-08, 11:08:08Z}
String[] date = datetime[0].split("-"); // {1999, 02, 08}
int year = Integer.valueOf(date[0]);
int month = Integer.valueOf(date[1]) - 1; //Months are zero indexed: 1 = February, 6 = July, 11 = December
int day = Integer.valueOf(date[2]); //Days are 1 indexed
long ObjId = Long.valueOf(s[4]);
// when the year changes, create and add a new YearEpoch object to the list
if (year != prevYear) {
ye = new YearEpoch(year);
years.add(ye);
prevYear = year;
}
// create and add the file
AbstractFile file;
try {
file = skCase.getAbstractFileById(ObjId);
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Could not find a file with ID " + ObjId, ex);
continue;
}
ye.add(file, month, day);
}
return years;
} }
private String makeBodyFile() { private String makeBodyFile() {