other files. Also, it can now filter to only show IDs that had data unique to the one file of interest. This all should make it easier to find data.
351 lines
12 KiB
C++
351 lines
12 KiB
C++
#include "filecomparatorwindow.h"
|
|
#include "ui_filecomparatorwindow.h"
|
|
|
|
#include <QSettings>
|
|
|
|
FileComparatorWindow::FileComparatorWindow(QWidget *parent) :
|
|
QDialog(parent),
|
|
ui(new Ui::FileComparatorWindow)
|
|
{
|
|
ui->setupUi(this);
|
|
|
|
connect(ui->btnInterestedFile, SIGNAL(clicked(bool)), this, SLOT(loadInterestedFile()));
|
|
connect(ui->btnLoadRefFile, SIGNAL(clicked(bool)), this, SLOT(loadReferenceFile()));
|
|
connect(ui->btnSaveDetails, SIGNAL(clicked(bool)), this, SLOT(saveDetails()));
|
|
connect(ui->btnClear, SIGNAL(clicked(bool)), this, SLOT(clearReference()));
|
|
|
|
ui->lblFirstFile->setText("");
|
|
ui->lblRefFrames->setText("0");
|
|
}
|
|
|
|
FileComparatorWindow::~FileComparatorWindow()
|
|
{
|
|
delete ui;
|
|
}
|
|
|
|
void FileComparatorWindow::showEvent(QShowEvent *)
|
|
{
|
|
readSettings();
|
|
}
|
|
|
|
void FileComparatorWindow::closeEvent(QCloseEvent *event)
|
|
{
|
|
writeSettings();
|
|
}
|
|
|
|
void FileComparatorWindow::readSettings()
|
|
{
|
|
QSettings settings;
|
|
if (settings.value("Main/SaveRestorePositions", false).toBool())
|
|
{
|
|
resize(settings.value("FileComparator/WindowSize", QSize(720, 631)).toSize());
|
|
move(settings.value("FileComparator/WindowPos", QPoint(50, 50)).toPoint());
|
|
}
|
|
}
|
|
|
|
void FileComparatorWindow::writeSettings()
|
|
{
|
|
QSettings settings;
|
|
|
|
if (settings.value("Main/SaveRestorePositions", false).toBool())
|
|
{
|
|
settings.setValue("FileComparator/WindowSize", size());
|
|
settings.setValue("FileComparator/WindowPos", pos());
|
|
}
|
|
}
|
|
|
|
void FileComparatorWindow::loadInterestedFile()
|
|
{
|
|
interestedFrames.clear();
|
|
QString result = FrameFileIO::loadFrameFile(&interestedFrames);
|
|
if (result.length() > 0)
|
|
{
|
|
ui->lblFirstFile->setText(result);
|
|
interestedFilename = result;
|
|
if (interestedFrames.count() > 0 && referenceFrames.count() > 0) calculateDetails();
|
|
}
|
|
}
|
|
|
|
void FileComparatorWindow::loadReferenceFile()
|
|
{
|
|
//secondFileFrames.clear();
|
|
QString result = FrameFileIO::loadFrameFile(&referenceFrames);
|
|
if (result.length() > 0)
|
|
{
|
|
ui->lblRefFrames->setText(QString::number(referenceFrames.length()));
|
|
if (interestedFrames.count() > 0 && referenceFrames.count() > 0) calculateDetails();
|
|
}
|
|
}
|
|
|
|
void FileComparatorWindow::clearReference()
|
|
{
|
|
referenceFrames.clear();
|
|
ui->treeDetails->clear();
|
|
}
|
|
|
|
void FileComparatorWindow::calculateDetails()
|
|
{
|
|
QMap<int, FrameData> interestedIDs;
|
|
QMap<int, FrameData> referenceIDs;
|
|
QTreeWidgetItem *interestedOnlyBase, *referenceOnlyBase, *sharedBase, *bitmapBaseInterested, *bitmapBaseReference;
|
|
QTreeWidgetItem *valuesBase, *detail, *sharedItem, *valuesInterested, *valuesReference;
|
|
uint64_t tmp;
|
|
|
|
bool uniqueInterested = ui->ckUniqueToInterested->isChecked();
|
|
|
|
ui->treeDetails->clear();
|
|
|
|
interestedOnlyBase = new QTreeWidgetItem();
|
|
interestedOnlyBase->setText(0,"IDs found only in " + interestedFilename);
|
|
if (!uniqueInterested)
|
|
{
|
|
referenceOnlyBase = new QTreeWidgetItem();
|
|
referenceOnlyBase->setText(0, "IDs found only in reference frames");
|
|
}
|
|
sharedBase = new QTreeWidgetItem();
|
|
sharedBase->setText(0,"IDs found in both places");
|
|
|
|
//first we have to fill out the data structures to get ready to do the report
|
|
for (int x = 0; x < interestedFrames.count(); x++)
|
|
{
|
|
CANFrame frame = interestedFrames.at(x);
|
|
if (interestedIDs.contains(frame.ID)) //if we saw this ID before then add to the QList in there
|
|
{
|
|
for (int y = 0; y < frame.len; y++)
|
|
{
|
|
interestedIDs[frame.ID].values[y][frame.data[y]]++;
|
|
tmp = frame.data[y];
|
|
tmp = tmp << (8 * y);
|
|
interestedIDs[frame.ID].bitmap |= tmp;
|
|
//qDebug() << "bitmap: " << QString::number(interestedIDs[frame.ID].bitmap, 16);
|
|
}
|
|
}
|
|
else //never seen this ID before so add one
|
|
{
|
|
FrameData *newData = new FrameData();
|
|
newData->ID = frame.ID;
|
|
newData->dataLen = frame.len;
|
|
//it would be possible to implement a constructor for FrameData
|
|
//that sets the bitmap and values to zero. That would be cleaner and better.
|
|
newData->bitmap = 0;
|
|
for (int x = 0; x < 8; x++)
|
|
{
|
|
for (int y = 0; y < 256; y++)
|
|
{
|
|
newData->values[x][y] = 0;
|
|
}
|
|
}
|
|
//memset(newData->values, 0, 256 * 8);
|
|
for (int y = 0; y < frame.len; y++)
|
|
{
|
|
newData->values[y][frame.data[y]] = 1;
|
|
tmp = frame.data[y];
|
|
tmp = tmp << (8 * y);
|
|
newData->bitmap |= tmp;
|
|
//qDebug() << "bitmap: " << QString::number(newData->bitmap, 16);
|
|
}
|
|
interestedIDs.insert(frame.ID, *newData);
|
|
}
|
|
}
|
|
|
|
for (int x = 0; x < referenceFrames.count(); x++)
|
|
{
|
|
CANFrame frame = referenceFrames.at(x);
|
|
if (referenceIDs.contains(frame.ID)) //if we saw this ID before then add to the QList in there
|
|
{
|
|
for (int y = 0; y < frame.len; y++)
|
|
{
|
|
referenceIDs[frame.ID].values[y][frame.data[y]]++;
|
|
tmp = frame.data[y];
|
|
tmp = tmp << (8 * y);
|
|
referenceIDs[frame.ID].bitmap |= tmp;
|
|
//qDebug() << "bitmap: " << QString::number(referenceIDs[frame.ID].bitmap, 16);
|
|
}
|
|
}
|
|
else //never seen this ID before so add one
|
|
{
|
|
FrameData *newData = new FrameData();
|
|
newData->ID = frame.ID;
|
|
newData->dataLen = frame.len;
|
|
newData->bitmap = 0;
|
|
for (int x = 0; x < 8; x++)
|
|
{
|
|
for (int y = 0; y < 256; y++)
|
|
{
|
|
newData->values[x][y] = 0;
|
|
}
|
|
}
|
|
//memset(newData->values, 0, 256 * 8);
|
|
for (int y = 0; y < frame.len; y++)
|
|
{
|
|
newData->values[y][frame.data[y]] = 1;
|
|
tmp = frame.data[y];
|
|
tmp = tmp << (8 * y);
|
|
newData->bitmap |= tmp;
|
|
//qDebug() << "bitmap: " << QString::number(newData->bitmap, 16);
|
|
}
|
|
referenceIDs.insert(frame.ID, *newData);
|
|
}
|
|
}
|
|
|
|
//now we iterate through the IDs within both files and see which are unique to one file and which
|
|
//are shared
|
|
bool interestedHadUnique = false;
|
|
QMap<int, FrameData>::iterator i;
|
|
for (i = interestedIDs.begin(); i != interestedIDs.end(); ++i)
|
|
{
|
|
int keyone = i.key();
|
|
if (!referenceIDs.contains(keyone))
|
|
{
|
|
valuesBase = new QTreeWidgetItem();
|
|
valuesBase->setText(0, QString::number(keyone, 16));
|
|
interestedOnlyBase->addChild(valuesBase);
|
|
}
|
|
else //ID was in both files
|
|
{
|
|
interestedHadUnique = false;
|
|
sharedItem = new QTreeWidgetItem();
|
|
sharedItem->setText(0, Utility::formatHexNum(keyone));
|
|
//if the ID was in both files then we can use the data accumulated above in bitmap
|
|
//and values to figure out what has changed between the two files
|
|
|
|
FrameData interested = interestedIDs[keyone];
|
|
FrameData reference = referenceIDs[keyone];
|
|
|
|
bitmapBaseInterested = new QTreeWidgetItem();
|
|
bitmapBaseInterested->setText(0, "Bits set only in " + interestedFilename);
|
|
if (!uniqueInterested)
|
|
{
|
|
bitmapBaseReference = new QTreeWidgetItem();
|
|
bitmapBaseReference->setText(0, "Bits set only in reference frames");
|
|
}
|
|
sharedItem->addChild(bitmapBaseInterested);
|
|
sharedItem->addChild(bitmapBaseReference);
|
|
|
|
uint64_t interestedBits = interested.bitmap;
|
|
uint64_t referenceBits = reference.bitmap;
|
|
|
|
//first up, which bits were set in one file but not the other
|
|
for (int b = 0; b < (8 * interested.dataLen); b++)
|
|
{
|
|
detail = new QTreeWidgetItem();
|
|
detail->setText(0, QString::number(b) + " (" + QString::number(b / 8) + ":" + QString::number(b % 8) + ")");
|
|
if ( (interestedBits & 1) && !(referenceBits & 1) )
|
|
{
|
|
bitmapBaseInterested->addChild(detail);
|
|
interestedHadUnique = true;
|
|
}
|
|
else if ( !(interestedBits & 1) && (referenceBits & 1) )
|
|
{
|
|
if (!uniqueInterested) bitmapBaseReference->addChild(detail);
|
|
}
|
|
//qDebug() << b << " " << QString::number(interestedBits, 16) << " " << QString::number(referenceBits, 16);
|
|
interestedBits = interestedBits >> 1;
|
|
referenceBits = referenceBits >> 1;
|
|
}
|
|
|
|
for (int i = 0; i < qMax(interested.dataLen, reference.dataLen); i++)
|
|
{
|
|
valuesBase = new QTreeWidgetItem();
|
|
valuesBase->setText(0, "Byte " + QString::number(i));
|
|
sharedItem->addChild(valuesBase);
|
|
valuesInterested = new QTreeWidgetItem();
|
|
valuesInterested->setText(0, "Values found only in " + interestedFilename);
|
|
if (!uniqueInterested)
|
|
{
|
|
valuesReference = new QTreeWidgetItem();
|
|
valuesReference->setText(0, "Values found only in reference frames");
|
|
}
|
|
valuesBase->addChild(valuesInterested);
|
|
if (!uniqueInterested) valuesBase->addChild(valuesReference);
|
|
for (int j = 0; j < 256; j++)
|
|
{
|
|
detail = new QTreeWidgetItem();
|
|
detail->setText(0, Utility::formatHexNum(j));
|
|
if ((interested.values[i][j] > 0) && (reference.values[i][j] == 0) )
|
|
{
|
|
valuesInterested->addChild(detail);
|
|
interestedHadUnique = true;
|
|
}
|
|
if ((reference.values[i][j] > 0) && (interested.values[i][j] == 0) )
|
|
{
|
|
if (!uniqueInterested) valuesReference->addChild(detail);
|
|
}
|
|
}
|
|
}
|
|
if (interestedHadUnique || !uniqueInterested) sharedBase->addChild(sharedItem);
|
|
}
|
|
}
|
|
|
|
if (!uniqueInterested)
|
|
{
|
|
QMap<int, FrameData>::iterator itwo;
|
|
for (itwo = referenceIDs.begin(); itwo != referenceIDs.end(); ++itwo)
|
|
{
|
|
int keytwo = itwo.key();
|
|
if (!interestedIDs.contains(keytwo))
|
|
{
|
|
valuesBase = new QTreeWidgetItem();
|
|
valuesBase->setText(0, Utility::formatHexNum(keytwo));
|
|
referenceOnlyBase->addChild(valuesBase);
|
|
}
|
|
}
|
|
}
|
|
|
|
ui->treeDetails->addTopLevelItem(interestedOnlyBase);
|
|
if (!uniqueInterested) ui->treeDetails->addTopLevelItem(referenceOnlyBase);
|
|
ui->treeDetails->addTopLevelItem(sharedBase);
|
|
|
|
//ui->treeDetails->setSortingEnabled(true);
|
|
//ui->treeDetails->sortByColumn(0, Qt::AscendingOrder);
|
|
|
|
QSettings settings;
|
|
if (settings.value("InfoCompare/AutoExpand", false).toBool())
|
|
{
|
|
ui->treeDetails->expandAll();
|
|
}
|
|
}
|
|
|
|
void FileComparatorWindow::saveDetails()
|
|
{
|
|
QString filename;
|
|
QFileDialog dialog(this);
|
|
|
|
QStringList filters;
|
|
filters.append(QString(tr("Text File (*.txt)")));
|
|
|
|
dialog.setFileMode(QFileDialog::AnyFile);
|
|
dialog.setNameFilters(filters);
|
|
dialog.setViewMode(QFileDialog::Detail);
|
|
dialog.setAcceptMode(QFileDialog::AcceptSave);
|
|
|
|
if (dialog.exec() == QDialog::Accepted)
|
|
{
|
|
filename = dialog.selectedFiles()[0];
|
|
QFile *outFile = new QFile(filename);
|
|
|
|
if (!outFile->open(QIODevice::WriteOnly | QIODevice::Text))
|
|
return;
|
|
|
|
QTreeWidget *tree = ui->treeDetails;
|
|
|
|
|
|
QTreeWidgetItemIterator it(tree);
|
|
while (*it) {
|
|
QTreeWidgetItem *item = *it;
|
|
QString itemText = item->text(0);
|
|
while (item->parent())
|
|
{
|
|
outFile->write(" ");
|
|
item = item->parent();
|
|
}
|
|
outFile->write(itemText.toUtf8() + "\n");
|
|
++it;
|
|
}
|
|
|
|
outFile->close();
|
|
|
|
}
|
|
}
|
|
|