Implement find-replace logic for fields <= 64 bits
This commit is contained in:
parent
e19083ed3f
commit
b60aad45d1
@ -19,7 +19,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
#include "findreplace.h"
|
||||
|
||||
#include "../common/abstractprotocol.h"
|
||||
#include "../common/protocolmanager.h"
|
||||
#include "stream.h"
|
||||
|
||||
#include <QPushButton>
|
||||
|
||||
extern ProtocolManager *OstProtocolManager;
|
||||
|
||||
@ -32,23 +36,86 @@ FindReplaceDialog::FindReplaceDialog(Action *action, QWidget *parent)
|
||||
useFindMask->setChecked(false);
|
||||
useReplaceMask->setChecked(false);
|
||||
|
||||
protocol->addItems(OstProtocolManager->protocolDatabase());
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
|
||||
protocol->setPlaceholderText(tr("Select"));
|
||||
#endif
|
||||
protocol->setCurrentIndex(-1);
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
|
||||
field->setPlaceholderText(tr("Select"));
|
||||
#endif
|
||||
// TODO: remove combo protocols, sample, userscript
|
||||
QStringList protocolList = OstProtocolManager->protocolDatabase();
|
||||
protocolList.sort();
|
||||
protocol->addItems(protocolList);
|
||||
|
||||
// Enable this setting if we have streams selected on input
|
||||
selectedStreamsOnly->setEnabled(action->selectedStreamsOnly);
|
||||
|
||||
// Reset for user input
|
||||
action->selectedStreamsOnly = false;
|
||||
|
||||
buttonBox->button(QDialogButtonBox::Ok)->setText(tr("Replace All"));
|
||||
}
|
||||
|
||||
void FindReplaceDialog::on_protocol_currentIndexChanged(const QString &/*name*/)
|
||||
void FindReplaceDialog::on_protocol_currentIndexChanged(const QString &name)
|
||||
{
|
||||
field->clear();
|
||||
fieldAttrib_.clear();
|
||||
|
||||
Stream stream;
|
||||
AbstractProtocol *protocol = OstProtocolManager->createProtocol(
|
||||
name, &stream);
|
||||
int count = protocol->fieldCount();
|
||||
for (int i = 0; i < count; i++) {
|
||||
// XXX: It might be useful to support meta fields too, later!
|
||||
if (!protocol->fieldFlags(i).testFlag(AbstractProtocol::FrameField))
|
||||
continue;
|
||||
|
||||
int bitSize = protocol->fieldData(i, AbstractProtocol::FieldBitSize)
|
||||
.toInt();
|
||||
if (bitSize <= 0) // skip optional fields
|
||||
continue;
|
||||
|
||||
FieldAttrib fieldAttrib;
|
||||
fieldAttrib.index = i; // fieldIndex
|
||||
fieldAttrib.bitSize = bitSize;
|
||||
fieldAttrib.max = (1 << bitSize) - 1; // min is always 0
|
||||
|
||||
// field and fieldAttrib_ have same count and order of fields
|
||||
fieldAttrib_.append(fieldAttrib);
|
||||
field->addItem(protocol->fieldData(i, AbstractProtocol::FieldName)
|
||||
.toString());
|
||||
}
|
||||
|
||||
protocolId_ = protocol->protocolNumber();
|
||||
delete protocol;
|
||||
}
|
||||
|
||||
void FindReplaceDialog::on_buttonBox_accepted()
|
||||
{
|
||||
FieldAttrib fieldAttrib = fieldAttrib_.at(field->currentIndex());
|
||||
action_->protocolNumber = protocolId_;
|
||||
action_->fieldIndex = fieldAttrib.index;
|
||||
action_->fieldBitSize = fieldAttrib.bitSize;
|
||||
|
||||
// XXX: All find/replace value/mask QVariants are set to
|
||||
// 64-bit decimal number encoded as string
|
||||
// - The action user is expected to convert to appropriate type
|
||||
// (fieldBitSize is included as a hint)
|
||||
// - QVariant can only do decimal conversions (not hex)
|
||||
|
||||
if (matchAny->isChecked()) {
|
||||
action_->findMask.setValue(QString("0"));
|
||||
action_->findValue.setValue(QString("0"));
|
||||
} else {
|
||||
action_->findMask.setValue(QString::number(
|
||||
useFindMask->isChecked() ?
|
||||
findMask->text().toULongLong(nullptr, BASE_HEX) :
|
||||
quint64(~0)));
|
||||
action_->findValue.setValue(QString::number(
|
||||
findValue->text().toULongLong(nullptr, 0)));
|
||||
}
|
||||
|
||||
action_->replaceMask.setValue(QString::number(
|
||||
useReplaceMask->isChecked() ?
|
||||
replaceMask->text().toULongLong(nullptr, BASE_HEX) :
|
||||
quint64(~0)));
|
||||
action_->replaceValue.setValue(QString::number(
|
||||
replaceValue->text().toULongLong(nullptr, 0)));
|
||||
|
||||
action_->selectedStreamsOnly = selectedStreamsOnly->isChecked();
|
||||
}
|
||||
|
||||
|
@ -32,15 +32,21 @@ public:
|
||||
|
||||
private slots:
|
||||
void on_protocol_currentIndexChanged(const QString &name);
|
||||
void on_buttonBox_accepted();
|
||||
|
||||
private:
|
||||
struct FieldAttrib;
|
||||
|
||||
quint32 protocolId_{0};
|
||||
Action *action_{nullptr};
|
||||
QList<FieldAttrib> fieldAttrib_;
|
||||
};
|
||||
|
||||
struct FindReplaceDialog::Action
|
||||
{
|
||||
quint32 protocolNumber;
|
||||
quint32 fieldIndex;
|
||||
int fieldBitSize;
|
||||
QVariant findValue;
|
||||
QVariant findMask;
|
||||
QVariant replaceValue;
|
||||
@ -49,5 +55,11 @@ struct FindReplaceDialog::Action
|
||||
bool selectedStreamsOnly; // in-out param
|
||||
};
|
||||
|
||||
struct FindReplaceDialog::FieldAttrib
|
||||
{
|
||||
quint32 index;
|
||||
int bitSize;
|
||||
quint64 max;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
@ -314,33 +314,41 @@ void StreamsWidget::on_actionFind_Replace_triggered()
|
||||
if (findReplace.exec() == QDialog::Accepted) {
|
||||
int changed = 0;
|
||||
Port &port = plm->port(currentPortIndex_);
|
||||
// TODO: progress bar
|
||||
if (action.selectedStreamsOnly) {
|
||||
foreach(QModelIndex index, selectionModel->selectedRows()) {
|
||||
Stream *stream = port.mutableStreamByIndex(index.row(), false);
|
||||
if (stream->findReplace(action.protocolNumber,
|
||||
action.fieldIndex,
|
||||
action.findValue,
|
||||
action.findMask,
|
||||
action.replaceValue,
|
||||
action.replaceMask))
|
||||
if (stream->protocolFieldReplace(action.protocolNumber,
|
||||
action.fieldIndex,
|
||||
action.fieldBitSize,
|
||||
action.findValue,
|
||||
action.findMask,
|
||||
action.replaceValue,
|
||||
action.replaceMask))
|
||||
changed++;
|
||||
}
|
||||
} else {
|
||||
int count = tvStreamList->model()->rowCount();
|
||||
for (int i = 0; i < count; i++) {
|
||||
Stream *stream = port.mutableStreamByIndex(i, false);
|
||||
if (stream->findReplace(action.protocolNumber,
|
||||
action.fieldIndex,
|
||||
action.findValue,
|
||||
action.findMask,
|
||||
action.replaceValue,
|
||||
action.replaceMask))
|
||||
if (stream->protocolFieldReplace(action.protocolNumber,
|
||||
action.fieldIndex,
|
||||
action.fieldBitSize,
|
||||
action.findValue,
|
||||
action.findMask,
|
||||
action.replaceValue,
|
||||
action.replaceMask))
|
||||
changed++;
|
||||
}
|
||||
}
|
||||
|
||||
if (changed)
|
||||
port.setLocalConfigChanged(true);
|
||||
|
||||
// TODO: count # of fields and # of streams changed
|
||||
QMessageBox::information(this, tr("Find & Replace"),
|
||||
tr("%1 streams changed").arg(changed));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -270,6 +270,7 @@ QVariant MacProtocol::fieldData(int index, FieldAttrib attrib,
|
||||
bool MacProtocol::setFieldData(int index, const QVariant &value,
|
||||
FieldAttrib attrib)
|
||||
{
|
||||
// FIXME: make sure isOk is set correctly for all fields and protocols
|
||||
bool isOk = false;
|
||||
|
||||
if (attrib != FieldValue)
|
||||
|
@ -236,3 +236,33 @@ QStringList ProtocolManager::protocolDatabase()
|
||||
{
|
||||
return numberToNameMap.values();
|
||||
}
|
||||
|
||||
#if 0
|
||||
void ProtocolManager::showFieldAttribs()
|
||||
{
|
||||
QStringList protocolList = protocolDatabase();
|
||||
Stream stream;
|
||||
foreach(QString name, protocolList) {
|
||||
if (name.contains("/")) // assume combo
|
||||
continue;
|
||||
AbstractProtocol *protocol = OstProtocolManager->createProtocol(name, &stream);
|
||||
int count = protocol->fieldCount();
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (!protocol->fieldFlags(i).testFlag(AbstractProtocol::FrameField))
|
||||
continue;
|
||||
|
||||
uint bitSize = protocol->fieldData(i, AbstractProtocol::FieldBitSize)
|
||||
.toInt();
|
||||
qDebug("$$$$, %s, %d, %s, %u, %x, %llu",
|
||||
qPrintable(name),
|
||||
i,
|
||||
qPrintable(protocol->fieldData(i, AbstractProtocol::FieldName).toString()),
|
||||
bitSize,
|
||||
0, // min
|
||||
(1 << bitSize) - 1);
|
||||
}
|
||||
|
||||
delete protocol;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -24,6 +24,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
#include "protocollistiterator.h"
|
||||
#include "protocolmanager.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
extern ProtocolManager *OstProtocolManager;
|
||||
extern quint64 getDeviceMacAddress(int portId, int streamId, int frameIndex);
|
||||
extern quint64 getNeighborMacAddress(int portId, int streamId, int frameIndex);
|
||||
@ -598,12 +600,56 @@ int StreamBase::frameValue(uchar *buf, int bufMaxSize, int frameIndex,
|
||||
return len;
|
||||
}
|
||||
|
||||
bool StreamBase::findReplace(quint32 /*protocolNumber*/, int /*fieldIndex*/,
|
||||
QVariant /*findValue*/, QVariant /*findMask*/,
|
||||
QVariant /*replaceValue*/, QVariant /*replaceMask*/)
|
||||
template <typename T>
|
||||
int StreamBase::findReplace(quint32 protocolNumber, int fieldIndex,
|
||||
QVariant findValue, QVariant findMask,
|
||||
QVariant replaceValue, QVariant replaceMask)
|
||||
{
|
||||
// TODO
|
||||
return false;
|
||||
int replaceCount = 0;
|
||||
ProtocolListIterator *iter = createProtocolListIterator();
|
||||
|
||||
// FIXME: Because protocol list iterator is unaware of combo protocols
|
||||
// search for ip4.src will NOT succeed in a combo protocol containing ip4
|
||||
while (iter->hasNext()) {
|
||||
AbstractProtocol *proto = iter->next();
|
||||
if (proto->protocolNumber() != protocolNumber)
|
||||
continue;
|
||||
|
||||
T fieldValue = proto->fieldData(fieldIndex,
|
||||
AbstractProtocol::FieldValue).value<T>();
|
||||
qDebug() << "findReplace:"
|
||||
<< "field" << fieldValue
|
||||
<< "findMask" << hex << findMask.value<T>() << dec
|
||||
<< "findValue" << findValue.value<T>();
|
||||
if ((fieldValue & findMask.value<T>()) == findValue.value<T>()) {
|
||||
T newValue = (fieldValue & ~replaceMask.value<T>())
|
||||
| (replaceValue.value<T>() & replaceMask.value<T>());
|
||||
qDebug() << "findReplace:"
|
||||
<< "replaceMask" << hex << replaceMask.value<T>() << dec
|
||||
<< "replaceValue" << replaceValue.value<T>()
|
||||
<< "newValue" << newValue;
|
||||
if (proto->setFieldData(fieldIndex, newValue))
|
||||
replaceCount++;
|
||||
}
|
||||
}
|
||||
delete iter;
|
||||
|
||||
return replaceCount;
|
||||
}
|
||||
|
||||
int StreamBase::protocolFieldReplace(quint32 protocolNumber,
|
||||
int fieldIndex, int fieldBitSize,
|
||||
QVariant findValue, QVariant findMask,
|
||||
QVariant replaceValue, QVariant replaceMask)
|
||||
{
|
||||
if (fieldBitSize <= 64)
|
||||
return findReplace<qulonglong>(protocolNumber, fieldIndex,
|
||||
findValue, findMask, replaceValue, replaceMask);
|
||||
|
||||
// TODO: > 64 (e.g. IPv6 128 bit)
|
||||
|
||||
qWarning("Unknown find/replace type %d", findValue.type());
|
||||
return 0;
|
||||
}
|
||||
|
||||
quint64 StreamBase::deviceMacAddress(int frameIndex) const
|
||||
|
@ -142,9 +142,10 @@ public:
|
||||
int frameValue(uchar *buf, int bufMaxSize, int frameIndex,
|
||||
FrameValueAttrib *attrib = nullptr) const;
|
||||
|
||||
bool findReplace(quint32 protocolNumber, int fieldIndex,
|
||||
QVariant findValue, QVariant findMask,
|
||||
QVariant replaceValue, QVariant replaceMask);
|
||||
int protocolFieldReplace(quint32 protocolNumber,
|
||||
int fieldIndex, int fieldBitSize,
|
||||
QVariant findValue, QVariant findMask,
|
||||
QVariant replaceValue, QVariant replaceMask);
|
||||
|
||||
quint64 deviceMacAddress(int frameIndex) const;
|
||||
quint64 neighborMacAddress(int frameIndex) const;
|
||||
@ -154,6 +155,10 @@ public:
|
||||
static bool StreamLessThan(StreamBase* stream1, StreamBase* stream2);
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
int findReplace(quint32 protocolNumber, int fieldIndex,
|
||||
QVariant findValue, QVariant findMask,
|
||||
QVariant replaceValue, QVariant replaceMask);
|
||||
int portId_;
|
||||
|
||||
OstProto::StreamId *mStreamId;
|
||||
|
Loading…
Reference in New Issue
Block a user