diff --git a/DefinedStructs/ConstDataHolder.cpp b/DefinedStructs/ConstDataHolder.cpp
index 638e3ac..ba55a03 100644
--- a/DefinedStructs/ConstDataHolder.cpp
+++ b/DefinedStructs/ConstDataHolder.cpp
@@ -1,4 +1,6 @@
#include "ConstDataHolder.hpp"
+#include "DescriptorStruct.hpp"
+
DataHolder* DataHolder::holder = nullptr;
@@ -26,6 +28,7 @@ DataHolder::DataHolder()
TRANSFER_LEFTOVER_DATA = Qt::UserRole + 1;
TRANSFER_OPTIONAL_HEADER = Qt::UserRole + 2;
USBPCAP_HEADER_DATA = Qt::UserRole + 3;
+ DescriptorPath = std::filesystem::current_path().string() + "\\Descriptors\\";
}
///
@@ -53,6 +56,28 @@ void DataHolder::FillDataColorsMap()
DataColors.insert(std::pair(UNKNOWN_TRANSFER, { 0,0,255,255 }));
}
+///
+/// Tries to load new descriptor from file if description for given descriptor exists
+///
+/// Type of descriptor we want to get
+/// Pointer to loaded descriptor if exists, else nullptr
+DescriptorStruct* DataHolder::TryLoadNewDescriptor(BYTE descType)
+{
+ std::stringstream stream(DescriptorPath, std::ios_base::app | std::ios_base::out);
+
+ stream << "Desc";
+ stream << std::setw(2) << std::setfill('0') << (int)descType;
+ stream << ".txt";
+
+ if (std::filesystem::exists(stream.str().c_str()))
+ {
+ descriptors.emplace_back(std::make_unique(stream.str().c_str(), descType));
+ return descriptors[descriptors.size() - 1].get();
+ }
+
+ return nullptr;
+}
+
///
/// Get string representation for USBPcap transfer.
///
diff --git a/DefinedStructs/ConstDataHolder.hpp b/DefinedStructs/ConstDataHolder.hpp
index d133aa9..ba445d9 100644
--- a/DefinedStructs/ConstDataHolder.hpp
+++ b/DefinedStructs/ConstDataHolder.hpp
@@ -1,9 +1,14 @@
#ifndef CONSTDATAHOLDER_HPP
#define CONSTDATAHOLDER_HPP
-#include "PacketExternStructs.hpp"
#include
#include
static DataHolder* holder;
+
+ std::string DescriptorPath;
};
#endif // !CONSTDATAHOLDER_HPP
\ No newline at end of file
diff --git a/DefinedStructs/DescriptorStruct.cpp b/DefinedStructs/DescriptorStruct.cpp
new file mode 100644
index 0000000..36ae2a6
--- /dev/null
+++ b/DefinedStructs/DescriptorStruct.cpp
@@ -0,0 +1,98 @@
+#include "DescriptorStruct.hpp"
+#include
+
+
+///
+/// Fills up fields for this concrete descriptor struct
+///
+void DescriptorStruct::FillUpFields()
+{
+ std::ifstream input;
+ input.open(filename);
+ std::string line;
+ //read first line to get descriptor type and name
+ if (input.good())
+ {
+ if (std::getline(input, line))
+ {
+ std::istringstream ss(line);
+ std::string bDescType;
+ ss >> bDescType;
+ if (std::stoi(bDescType) != descriptorType)
+ {
+ return;
+ }
+ std::string descName = ss.str();
+ fields.emplace_back(std::make_unique>(descName));
+ }
+ }
+ while (input.good())
+ {
+ if (std::getline(input, line))
+ {
+ //last added field has more detailed structure (on bit level of detail)
+ //with given range and values (representing more fields) so fill them up
+ if (line == "<")
+ {
+ fields[fields.size() - 1]->FillUpField(input);
+ }
+ else
+ {
+ std::istringstream ss(line);
+ std::string firstWord;
+ ss >> firstWord;
+ if (!std::isdigit(firstWord[0]))
+ {
+ //means input will be read by the end and has no fixed length (e.g. wstring in String Descriptor)
+ if (firstWord == "..")
+ {
+ std::string type;
+ ss >> type;
+ if (type == "wstring")
+ {
+ fields.emplace_back(std::make_unique>(ss.str()));
+ }
+ }
+ }
+ else
+ {
+ //according to length determine exact type
+ //currently supporting 2 most common - BYTE and USHORT
+ switch (std::stoi(firstWord))
+ {
+ case 1:
+ {
+ fields.emplace_back(std::make_unique>(ss.str()));
+ break;
+ }
+ case 2:
+ {
+ fields.emplace_back(std::make_unique>(ss.str()));
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+
+///
+/// Interpret data according to concrete descriptor
+///
+/// Root tree item of tree view
+/// Data to be interpreted
+/// Pointer to AdditionalDataModel
+void DescriptorStruct::InterpretData(TreeItem* rootItem, const QByteArray& data, AdditionalDataModel* additionalDataModel)
+{
+ const char* packet = data.constData();
+ std::size_t dataLeft = data.size();
+ for (int i = 0; i < fields.size(); i++)
+ {
+ std::size_t value = fields[i]->InterpretField(rootItem, (const unsigned char*)packet, dataLeft, additionalDataModel);
+ packet += value;
+ dataLeft -= value;
+ }
+}
\ No newline at end of file
diff --git a/DefinedStructs/DescriptorStruct.hpp b/DefinedStructs/DescriptorStruct.hpp
new file mode 100644
index 0000000..cf1e08d
--- /dev/null
+++ b/DefinedStructs/DescriptorStruct.hpp
@@ -0,0 +1,235 @@
+#ifndef DESCRIPTOR_STRUCT_HPP
+#define DESCRIPTOR_STRUCT_HPP
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "PacketExternStructs.hpp"
+#include "../Models/AdditionalDataModel.hpp"
+
+///
+/// Abstract class representing 1 field in descriptor
+///
+class AbstractDescriptorField
+{
+public:
+ AbstractDescriptorField() {}
+ virtual ~AbstractDescriptorField() noexcept {}
+ virtual void FillUpField(std::ifstream& input) = 0;
+ virtual std::size_t InterpretField(TreeItem* rootItem, const unsigned char* data, std::size_t size,
+ AdditionalDataModel* additionalDataModel) = 0;
+};
+
+///
+/// Structure representing one segment of field which has bit level details
+///
+template
+struct BitField
+{
+ ///
+ /// starting position of analyzing bits
+ ///
+ int start;
+ ///
+ /// size of analyzing bits
+ ///
+ int size;
+ ///
+ /// map holding descriptions to given values
+ ///
+ std::map descriptions;
+};
+
+///
+/// Conrete class representing 1 field in descriptor
+///
+/// type of concrete field (e.g. INT32, INT64, ...)
+template
+class DescriptorField : public AbstractDescriptorField
+{
+public:
+ DescriptorField(std::string descr) : description(descr), value() {}
+ void FillUpField(std::ifstream& input) override;
+ std::size_t InterpretField(TreeItem* rootItem, const unsigned char* data, std::size_t sizeLeft,
+ AdditionalDataModel* additionalDataModel) override;
+private:
+ void CharToNumberConvert(const unsigned char* addr)
+ {
+ if constexpr (!std::is_same_v && !std::is_same_v)
+ {
+ value = T();
+ for (int i = sizeof(T); i > 0; i--)
+ {
+ value = (value << 8) | addr[i - 1];
+ }
+ }
+ }
+
+ void CharToConcreteNumberConvert(const unsigned char* addr, T& value)
+ {
+ if constexpr (!std::is_same_v && !std::is_same_v)
+ {
+ value = T();
+ for (int i = sizeof(T); i > 0; i--)
+ {
+ value = (value << 8) | addr[i - 1];
+ }
+ }
+ }
+
+ T GetBitFieldValue(BitField& field);
+
+ std::string description;
+ std::vector> bitFields;
+ T value;
+};
+
+///
+/// fill up one concrete fields along with its bit defined fields
+///
+/// Type of descriptor field
+/// input stream
+template
+void DescriptorField::FillUpField(std::ifstream& input)
+{
+ while (input.good())
+ {
+ std::string line;
+ if (std::getline(input, line))
+ {
+ //end of the whole field
+ if (line == ">")
+ {
+ return;
+ }
+ std::istringstream ss(line);
+ BitField b;
+ ss >> b.start;
+ ss.get(); //separator
+ ss >> b.size;
+ char separator = input.get();
+ if (input.good() && separator == '{')
+ {
+ while (input.good())
+ {
+ if (std::getline(input, line))
+ {
+ //end of bit field
+ if (line == "}")
+ {
+ return;
+ }
+ //else fill up one bit field with value - description pairs
+ ss = std::istringstream(line);
+ T value;
+ CharToConcreteNumberConvert((const unsigned char*)(ss.str().c_str()), value);
+ b.descriptions[value] = ss.str();
+ }
+ }
+ }
+ }
+ }
+}
+
+///
+/// Interpret concrete field (and its possible bit fields)
+///
+/// Type of descriptor field
+/// Root tree item of tree view
+/// Starting point of data to be interpreted
+/// Size of data that are still valid and has not been proccessed yet
+/// Pointer to AdditionalDataModel instance
+/// Size of data that were interpreted
+template
+std::size_t DescriptorField::InterpretField(TreeItem* rootItem, const unsigned char* data, std::size_t sizeLeft,
+ AdditionalDataModel* additionalDataModel)
+{
+ QString hexData;
+ //wstring ... proccess all left data
+ if (std::is_same_v)
+ {
+ additionalDataModel->CharToHexConvert(&data, sizeLeft, hexData);
+ std::wstring wString(data, data + sizeLeft);
+ std::string bString(wString.begin(), wString.end());
+ rootItem->AppendChild(new TreeItem(QVector{hexData, description.c_str(), bString.c_str()}, rootItem));
+ return sizeLeft;
+ }
+
+ //used so we can work with std::stringstream and its operator << (it wouldnt work with wstring)
+ if constexpr (!std::is_same_v && !std::is_same_v)
+ {
+ //some other data type
+ //convert char* to number and fill value data field
+ CharToNumberConvert(data);
+ additionalDataModel->CharToHexConvert(&data, sizeof(T), hexData);
+ std::stringstream ss;
+ ss << value;
+ rootItem->AppendChild(new TreeItem(QVector{hexData, description.c_str(), ss.str().c_str()}, rootItem));
+
+ //check if it carries some bit defined information
+ //if not, return proccessed size
+ if (bitFields.empty())
+ {
+ return sizeof(T);
+ }
+ //else go through bitFields and interpret them
+ TreeItem* bitFieldParent = rootItem->Child(rootItem->ChildCount() - 1);
+ for (std::size_t i = 0; i < bitFields.size(); i++)
+ {
+ T bitValue = GetBitFieldValue(bitFields[i]);
+ auto fieldDesc = bitFields[i].descriptions[bitValue];
+ ss.clear();
+ ss << value;
+ std::stringstream ss2;
+ ss2 << bitValue;
+ bitFieldParent->AppendChild(new TreeItem(QVector{
+ additionalDataModel->ShowBits(bitFields[i].start, bitFields[i].size, ss.str().c_str()),
+ fieldDesc.c_str(), ss2.str().c_str()}, bitFieldParent));
+ }
+ }
+}
+
+///
+/// Get value of given bit-field
+///
+/// Type of descriptor field
+/// Concrete field
+/// Value of given bit-field
+template
+T DescriptorField::GetBitFieldValue(BitField& field)
+{
+ T bitmask = (1 << field.size) - 1;
+ bitmask = bitmask << field.start;
+ T bitValue = (value & bitmask) >> field.start;
+
+ return bitValue;
+}
+
+///
+/// Class representing concrete descriptor.
+///
+class DescriptorStruct
+{
+public:
+ DescriptorStruct(std::string fName, BYTE dType) : filename(fName), descriptorType(dType) { FillUpFields(); }
+ ///
+ /// Fill up concrete tree representing this descriptor
+ ///
+ ///
+ ///
+ void InterpretData(TreeItem* rootItem, const QByteArray& data, AdditionalDataModel* additionalDataModel);
+ BYTE descriptorType;
+private:
+ void FillUpFields();
+
+ std::string filename;
+ std::vector> fields;
+};
+
+#endif // !DESCRIPTOR_STRUCT_HPP
+
diff --git a/Descriptors/Desc03.txt b/Descriptors/Desc03.txt
new file mode 100644
index 0000000..d9a58b5
--- /dev/null
+++ b/Descriptors/Desc03.txt
@@ -0,0 +1,4 @@
+03 STRING DESCRIPTOR
+1 bLength
+1 bDescriptorType
+.. wstring bString
\ No newline at end of file
diff --git a/Interpreters/ControlTransferInterpreter.cpp b/Interpreters/ControlTransferInterpreter.cpp
new file mode 100644
index 0000000..994e168
--- /dev/null
+++ b/Interpreters/ControlTransferInterpreter.cpp
@@ -0,0 +1,70 @@
+#include "ControlTransferInterpreter.hpp"
+#include "../DefinedStructs/DescriptorStruct.hpp"
+
+
+ControlTransferInterpreter::ControlTransferInterpreter(TreeItem* rootItem, QTableWidgetItem* item, AdditionalDataModel* additionalDataModel) :
+ BaseInterpreter(rootItem, item, additionalDataModel)
+{
+ this->holder = DataHolder::GetDataHolder();
+}
+
+///
+/// Iterate through data and interpret known descriptors
+///
+void ControlTransferInterpreter::Interpret()
+{
+ QByteArray data = item->data(holder->TRANSFER_LEFTOVER_DATA).toByteArray();
+ const char* packet = data.constData();
+ BYTE descriptorType = (BYTE) * (++packet);
+ DescriptorStruct* descStruct = GetDescriptorStruct(descriptorType);
+ if (descStruct == nullptr)
+ {
+ InterpretUnknownDescriptor((const unsigned char*)packet);
+ }
+ else
+ {
+ descStruct->InterpretData(rootItem, data, additionalDataModel);
+ }
+}
+
+///
+/// Gets struct that represents given descriptor. If it doesnt exists yet, try to load it
+///
+/// Type of descriptor we want to get struct of
+///
+DescriptorStruct* ControlTransferInterpreter::GetDescriptorStruct(BYTE descriptorType)
+{
+ auto predicate = [descriptorType](std::unique_ptr& desc) {return desc->descriptorType == descriptorType; };
+ auto descStructIterator = std::find_if(holder->descriptors.begin(), holder->descriptors.end(), predicate);
+ if (descStructIterator == holder->descriptors.end())
+ {
+ DescriptorStruct* descStruct = holder->TryLoadNewDescriptor(descriptorType);
+ return descStruct;
+ }
+ else
+ {
+ return descStructIterator->get();
+ }
+}
+
+///
+/// Inteprets unknown descriptor
+///
+/// Pointer to descriptor data
+void ControlTransferInterpreter::InterpretUnknownDescriptor(const unsigned char* packet)
+{
+ rootItem->AppendChild(new TreeItem(QVector{"UNKNOWN_DESCRIPTOR", "", ""}, rootItem));
+ TreeItem* unknownDescriptorChild = rootItem->Child(rootItem->ChildCount() - 1);
+ BYTE descriptorSize = (*packet);
+
+ QString hexData;
+ additionalDataModel->CharToHexConvert(&packet, 1, hexData);
+ unknownDescriptorChild->AppendChild(new TreeItem(QVector{hexData, "bLength", descriptorSize}, unknownDescriptorChild));
+
+ BYTE descriptorType = (*packet);
+ additionalDataModel->CharToHexConvert(&packet, 1, hexData);
+ unknownDescriptorChild->AppendChild(new TreeItem(QVector{hexData, "bDescriptorType", descriptorType}, unknownDescriptorChild));
+
+ additionalDataModel->CharToHexConvert(&packet, descriptorSize - 1, hexData); // -1 for descriptorType
+ unknownDescriptorChild->AppendChild(new TreeItem(QVector{hexData, "unspecified"}, unknownDescriptorChild));
+}
\ No newline at end of file
diff --git a/Interpreters/ControlTransferInterpreter.hpp b/Interpreters/ControlTransferInterpreter.hpp
new file mode 100644
index 0000000..b0cd112
--- /dev/null
+++ b/Interpreters/ControlTransferInterpreter.hpp
@@ -0,0 +1,21 @@
+#ifndef CONTROLTRANSFERINTERPRETER_HPP
+#define CONTROLTRANSFERINTERPRETER_HPP
+
+#include "BaseInterpreter.hpp"
+
+#include
+
+class ControlTransferInterpreter : public BaseInterpreter
+{
+public:
+ ControlTransferInterpreter(TreeItem* rootItem, QTableWidgetItem* item, AdditionalDataModel* additionalDataModel);
+
+ void Interpret() override;
+private:
+ DescriptorStruct* GetDescriptorStruct(BYTE descriptorType);
+ void InterpretUnknownDescriptor(const unsigned char* packet);
+
+ DataHolder* holder;
+};
+
+#endif // !CONTROLTRANSFERINTERPRETER_HPP
diff --git a/Interpreters/InterpreterFactory.cpp b/Interpreters/InterpreterFactory.cpp
index cb1578c..adcf001 100644
--- a/Interpreters/InterpreterFactory.cpp
+++ b/Interpreters/InterpreterFactory.cpp
@@ -22,6 +22,23 @@ InterpreterFactory::InterpreterFactory(TreeItem* rootItem, QTableWidgetItem* ite
/// Pointer to appropriate interpreter
BaseInterpreter* InterpreterFactory::GetInterpreter()
{
+ PUSBPCAP_BUFFER_PACKET_HEADER usbh = (PUSBPCAP_BUFFER_PACKET_HEADER)item->
+ data(DataHolder::GetDataHolder()->USBPCAP_HEADER_DATA).toByteArray().constData();
+ UCHAR transferType = usbh->transfer;
+ switch (transferType)
+ {
+ case 1: //interrupt
+ {
+ return new InterruptTransferInterpreter(rootItem, item, additionalDataModel);
+ }
+ case 2: // control
+ {
+
+ }
+ default:
+ break;
+ }
+
switch (dataType)
{
case INTERR_TRANSFER:
diff --git a/Models/AdditionalDataModel.cpp b/Models/AdditionalDataModel.cpp
index 8773202..2107734 100644
--- a/Models/AdditionalDataModel.cpp
+++ b/Models/AdditionalDataModel.cpp
@@ -1,6 +1,7 @@
#include "AdditionalDataModel.hpp"
-#include "../Interpreters/InterpreterFactory.hpp"
+#include "../Interpreters/InterruptTransferInterpreter.hpp"
+#include "../Interpreters/ControlTransferInterpreter.hpp"
///
/// Constructor of AdditionaldataModel.
@@ -56,10 +57,24 @@ QVariant AdditionalDataModel::headerData(int section, Qt::Orientation orientatio
///
void AdditionalDataModel::SetupSpecifiedModelData()
{
- InterpreterFactory factory(rootItem.get(), item, this,dataType);
- std::unique_ptr interpreter(factory.GetInterpreter());
- if (interpreter != nullptr)
+ PUSBPCAP_BUFFER_PACKET_HEADER usbh = (PUSBPCAP_BUFFER_PACKET_HEADER)item->
+ data(DataHolder::GetDataHolder()->USBPCAP_HEADER_DATA).toByteArray().constData();
+ UCHAR transferType = usbh->transfer;
+ switch (transferType)
{
+ case 1: //interrupt
+ {
+ std::unique_ptr interpreter = std::make_unique(rootItem.get(), item, this);
interpreter->Interpret();
+ break;
+ }
+ case 2: // control
+ {
+ std::unique_ptr interpreter = std::make_unique(rootItem.get(), item, this);
+ interpreter->Interpret();
+ break;
+ }
+ default:
+ break;
}
}
\ No newline at end of file
diff --git a/Models/TreeItemBaseModel.h b/Models/TreeItemBaseModel.h
index c8391bf..747e4da 100644
--- a/Models/TreeItemBaseModel.h
+++ b/Models/TreeItemBaseModel.h
@@ -55,27 +55,30 @@ template
QString TreeItemBaseModel::ShowBits(const uint32_t start, const size_t size, T number) const
{
std::stringstream stream;
- for (int i = 0; i < sizeof(T) * 8; i++)
+ if constexpr (!std::is_same_v && !std::is_same_v && !std::is_same_v)
{
- if (i != 0 && i % 4 == 0)
+ for (int i = 0; i < sizeof(T) * 8; i++)
{
- stream << ' ';
- }
- if (i < start || i >= start + size)
- {
- stream << std::setw(2) << std::setfill(' ') << '.';
+ if (i != 0 && i % 4 == 0)
+ {
+ stream << ' ';
+ }
+ if (i < start || i >= start + size)
+ {
+ stream << std::setw(2) << std::setfill(' ') << '.';
+ number = number << 1;
+ continue;
+ }
+ if (number & (0x1 << ((sizeof(T) * 8) - 1)))
+ {
+ stream << '1';
+ }
+ else
+ {
+ stream << '0';
+ }
number = number << 1;
- continue;
- }
- if (number & (0x1 << ((sizeof(T) * 8) - 1)))
- {
- stream << '1';
- }
- else
- {
- stream << '0';
}
- number = number << 1;
}
return QString(stream.str().c_str());