diff --git a/client/ostinato.pro b/client/ostinato.pro index e61730e..fa69080 100644 --- a/client/ostinato.pro +++ b/client/ostinato.pro @@ -25,6 +25,7 @@ win32 { POST_TARGETDEPS += "../common/libostproto.a" "../rpc/libpbrpc.a" } LIBS += -lprotobuf +LIBS += -L"../extra/qhexedit2/$(OBJECTS_DIR)/" -lqhexedit2 RESOURCES += ostinato.qrc HEADERS += \ dumpview.h \ diff --git a/client/streamconfigdialog.cpp b/client/streamconfigdialog.cpp index 993cd1c..cc47dd7 100644 --- a/client/streamconfigdialog.cpp +++ b/client/streamconfigdialog.cpp @@ -243,6 +243,7 @@ void StreamConfigDialog::setupUiExtra() #else bgProto[ProtoPayload]->addButton(rbPayloadNone, ButtonIdNone); bgProto[ProtoPayload]->addButton(rbPayloadPattern, OstProto::Protocol::kPayloadFieldNumber); + bgProto[ProtoPayload]->addButton(rbPayloadHexDump, OstProto::Protocol::kHexDumpFieldNumber); bgProto[ProtoPayload]->addButton(rbPayloadOther, ButtonIdOther); #endif /* diff --git a/client/streamconfigdialog.ui b/client/streamconfigdialog.ui index 43c56b6..1f0a838 100644 --- a/client/streamconfigdialog.ui +++ b/client/streamconfigdialog.ui @@ -8,7 +8,7 @@ 0 0 - 626 + 634 507 @@ -173,7 +173,7 @@ QLineEdit:enabled[inputMask = "HH HH HH HH HH HH; "] { background-color: #ccccff 0 0 - 584 + 592 269 @@ -181,7 +181,7 @@ QLineEdit:enabled[inputMask = "HH HH HH HH HH HH; "] { background-color: #ccccff Simple - + L1 @@ -220,7 +220,7 @@ QLineEdit:enabled[inputMask = "HH HH HH HH HH HH; "] { background-color: #ccccff - + true @@ -403,17 +403,17 @@ QLineEdit:enabled[inputMask = "HH HH HH HH HH HH; "] { background-color: #ccccff - - + + true - Payload + L5 - + None @@ -423,17 +423,17 @@ QLineEdit:enabled[inputMask = "HH HH HH HH HH HH; "] { background-color: #ccccff - - - Pattern - - + + false + + Text + - + false @@ -445,7 +445,49 @@ QLineEdit:enabled[inputMask = "HH HH HH HH HH HH; "] { background-color: #ccccff - + + + + true + + + VLAN + + + false + + + false + + + + + + Untagged + + + true + + + + + + + Tagged + + + + + + + Stacked + + + + + + + true @@ -517,59 +559,17 @@ QLineEdit:enabled[inputMask = "HH HH HH HH HH HH; "] { background-color: #ccccff - - + + true - VLAN - - - false - - - false + Payload - - - Untagged - - - true - - - - - - - Tagged - - - - - - - Stacked - - - - - - - - - - true - - - L5 - - - - + None @@ -579,17 +579,24 @@ QLineEdit:enabled[inputMask = "HH HH HH HH HH HH; "] { background-color: #ccccff - - - false - + - Text + Pattern + + + false - + + + Hex Dump + + + + + false @@ -601,19 +608,6 @@ QLineEdit:enabled[inputMask = "HH HH HH HH HH HH; "] { background-color: #ccccff - - - - Qt::Vertical - - - - 20 - 40 - - - - diff --git a/common/hexdump.cpp b/common/hexdump.cpp new file mode 100644 index 0000000..f579430 --- /dev/null +++ b/common/hexdump.cpp @@ -0,0 +1,263 @@ +/* +Copyright (C) 2010 Srivats P. + +This file is part of "Ostinato" + +This is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +#include "hexdump.h" +#include "streambase.h" + +#include + +HexDumpConfigForm::HexDumpConfigForm(QWidget *parent) + : QWidget(parent) +{ + setupUi(this); + + hexEdit->setFont(QFont("Courier")); + hexEdit->setOverwriteMode(false); +} + +void HexDumpConfigForm::on_hexEdit_overwriteModeChanged(bool isOverwriteMode) +{ + if (isOverwriteMode) + mode->setText(tr("Ovr")); + else + mode->setText(tr("Ins")); +} + +HexDumpProtocol::HexDumpProtocol(StreamBase *stream, AbstractProtocol *parent) + : AbstractProtocol(stream, parent) +{ + /* The configWidget is created lazily */ + configForm = NULL; +} + +HexDumpProtocol::~HexDumpProtocol() +{ + delete configForm; +} + +AbstractProtocol* HexDumpProtocol::createInstance(StreamBase *stream, + AbstractProtocol *parent) +{ + return new HexDumpProtocol(stream, parent); +} + +quint32 HexDumpProtocol::protocolNumber() const +{ + return OstProto::Protocol::kHexDumpFieldNumber; +} + +void HexDumpProtocol::protoDataCopyInto(OstProto::Protocol &protocol) const +{ + protocol.MutableExtension(OstProto::hexDump)->CopyFrom(data); + protocol.mutable_protocol_id()->set_id(protocolNumber()); +} + +void HexDumpProtocol::protoDataCopyFrom(const OstProto::Protocol &protocol) +{ + if (protocol.protocol_id().id() == protocolNumber() && + protocol.HasExtension(OstProto::hexDump)) + data.MergeFrom(protocol.GetExtension(OstProto::hexDump)); +} + +QString HexDumpProtocol::name() const +{ + return QString("HexDump"); +} + +QString HexDumpProtocol::shortName() const +{ + return QString("HexDump"); +} + +int HexDumpProtocol::fieldCount() const +{ + return hexDump_fieldCount; +} + +AbstractProtocol::FieldFlags HexDumpProtocol::fieldFlags(int index) const +{ + AbstractProtocol::FieldFlags flags; + + flags = AbstractProtocol::fieldFlags(index); + + switch (index) + { + case hexDump_content: + flags |= FrameField; + break; + + case hexDump_pad_until_end: + flags &= ~FrameField; + flags |= MetaField; + break; + + default: + qFatal("%s: unimplemented case %d in switch", __PRETTY_FUNCTION__, + index); + break; + } + + return flags; +} + +QVariant HexDumpProtocol::fieldData(int index, FieldAttrib attrib, + int streamIndex) const +{ + switch (index) + { + case hexDump_content: + { + QByteArray ba; + QByteArray pad; + + switch(attrib) + { + case FieldValue: + case FieldTextValue: + case FieldFrameValue: + ba.append(QString().fromStdString(data.content())); + if (data.pad_until_end()) + { + pad = QByteArray( + protocolFrameSize(streamIndex) - ba.size(), '\0'); + } + break; + + default: + break; + } + + switch(attrib) + { + case FieldName: + return QString("Content"); + case FieldValue: + return ba; + case FieldTextValue: + return ba.append(pad).toHex(); + case FieldFrameValue: + return ba.append(pad); + default: + break; + } + break; + + } + + // Meta fields + case hexDump_pad_until_end: + { + switch(attrib) + { + case FieldValue: + return data.pad_until_end(); + default: + break; + } + break; + } + default: + qFatal("%s: unimplemented case %d in switch", __PRETTY_FUNCTION__, + index); + break; + } + + return AbstractProtocol::fieldData(index, attrib, streamIndex); +} + +bool HexDumpProtocol::setFieldData(int index, const QVariant &value, + FieldAttrib attrib) +{ + bool isOk = false; + + if (attrib != FieldValue) + goto _exit; + + switch (index) + { + case hexDump_content: + { + QByteArray ba = value.toByteArray(); + data.set_content(ba.constData(), ba.size()); + isOk = true; + break; + } + case hexDump_pad_until_end: + { + bool pad = value.toBool(); + data.set_pad_until_end(pad); + isOk = true; + break; + } + default: + qFatal("%s: unimplemented case %d in switch", __PRETTY_FUNCTION__, + index); + break; + } + +_exit: + return isOk; +} + +int HexDumpProtocol::protocolFrameSize(int streamIndex) const +{ + int len = data.content().size(); + + if (data.pad_until_end()) + { + int pad = mpStream->frameLen(streamIndex) + - (protocolFrameOffset(streamIndex) + len + kFcsSize); + if (pad < 0) + pad = 0; + len += pad; + } + + return len; +} + +QWidget* HexDumpProtocol::configWidget() +{ + /* Lazy creation of the configWidget */ + if (configForm == NULL) + { + configForm = new HexDumpConfigForm; + loadConfigWidget(); + } + + return configForm; +} + +void HexDumpProtocol::loadConfigWidget() +{ + configWidget(); + + configForm->hexEdit->setData( + fieldData(hexDump_content, FieldValue).toByteArray()); + configForm->padUntilEnd->setChecked( + fieldData(hexDump_pad_until_end, FieldValue).toBool()); +} + +void HexDumpProtocol::storeConfigWidget() +{ + configWidget(); + + setFieldData(hexDump_content, configForm->hexEdit->data()); + setFieldData(hexDump_pad_until_end, configForm->padUntilEnd->isChecked()); +} + diff --git a/common/hexdump.h b/common/hexdump.h new file mode 100644 index 0000000..f5b6932 --- /dev/null +++ b/common/hexdump.h @@ -0,0 +1,89 @@ +/* +Copyright (C) 2010 Srivats P. + +This file is part of "Ostinato" + +This is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +#ifndef _HEXDUMP_H +#define _HEXDUMP_H + +#include "hexdump.pb.h" +#include "ui_hexdump.h" + +#include "abstractprotocol.h" + +/* +HexDump Protocol Frame Format - + +---------+---------+ + | User | Zero | + | HexDump | Padding | + +---------+---------+ +*/ + +class HexDumpConfigForm : public QWidget, public Ui::HexDump +{ + Q_OBJECT +public: + HexDumpConfigForm(QWidget *parent = 0); +private slots: + void on_hexEdit_overwriteModeChanged(bool isOverwriteMode); +}; + +class HexDumpProtocol : public AbstractProtocol +{ +public: + HexDumpProtocol(StreamBase *stream, AbstractProtocol *parent = 0); + virtual ~HexDumpProtocol(); + + static AbstractProtocol* createInstance(StreamBase *stream, + AbstractProtocol *parent = 0); + virtual quint32 protocolNumber() const; + + virtual void protoDataCopyInto(OstProto::Protocol &protocol) const; + virtual void protoDataCopyFrom(const OstProto::Protocol &protocol); + + virtual QString name() const; + virtual QString shortName() const; + + virtual int fieldCount() const; + + virtual AbstractProtocol::FieldFlags fieldFlags(int index) const; + virtual QVariant fieldData(int index, FieldAttrib attrib, + int streamIndex = 0) const; + virtual bool setFieldData(int index, const QVariant &value, + FieldAttrib attrib = FieldValue); + + virtual int protocolFrameSize(int streamIndex = 0) const; + + virtual QWidget* configWidget(); + virtual void loadConfigWidget(); + virtual void storeConfigWidget(); + +private: + OstProto::HexDump data; + HexDumpConfigForm *configForm; + enum hexDumpfield + { + // Frame Fields + hexDump_content = 0, + + // Meta Fields + hexDump_pad_until_end, + + hexDump_fieldCount + }; +}; +#endif diff --git a/common/hexdump.proto b/common/hexdump.proto new file mode 100644 index 0000000..6cdc3d5 --- /dev/null +++ b/common/hexdump.proto @@ -0,0 +1,32 @@ +/* +Copyright (C) 2010 Srivats P. + +This file is part of "Ostinato" + +This is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +import "protocol.proto"; + +package OstProto; + +// HexDump Protocol +message HexDump { + optional bytes content = 1; + optional bool pad_until_end = 2 [default = true]; +} + +extend Protocol { + optional HexDump hexDump = 104; +} diff --git a/common/hexdump.ui b/common/hexdump.ui new file mode 100644 index 0000000..61f187a --- /dev/null +++ b/common/hexdump.ui @@ -0,0 +1,76 @@ + + HexDump + + + + 0 + 0 + 511 + 190 + + + + Form + + + + + + + + + Pad until end of packet + + + + + + + Qt::Horizontal + + + + 281 + 20 + + + + + + + + + 50 + 0 + + + + QFrame::Panel + + + QFrame::Sunken + + + 1 + + + + + + Qt::AlignCenter + + + + + + + + QHexEdit + QWidget +
qhexedit.h
+ 1 +
+
+ + +
diff --git a/common/ostproto.pro b/common/ostproto.pro index 68f1cc6..28d5dc7 100644 --- a/common/ostproto.pro +++ b/common/ostproto.pro @@ -1,6 +1,7 @@ TEMPLATE = lib CONFIG += qt staticlib QT += network script +INCLUDEPATH += "../extra/qhexedit2/src" LIBS += \ -lprotobuf FORMS += \ @@ -19,6 +20,7 @@ FORMS += \ udp.ui \ textproto.ui \ userscript.ui \ + hexdump.ui \ sample.ui PROTOS += \ protocol.proto \ @@ -46,6 +48,7 @@ PROTOS += \ udp.proto \ textproto.proto \ userscript.proto \ + hexdump.proto \ sample.proto HEADERS += \ abstractprotocol.h \ @@ -78,6 +81,7 @@ HEADERS += \ udp.h \ textproto.h \ userscript.h \ + hexdump.h \ sample.h SOURCES += \ abstractprotocol.cpp \ @@ -103,6 +107,7 @@ SOURCES += \ udp.cpp \ textproto.cpp \ userscript.cpp \ + hexdump.cpp \ sample.cpp QMAKE_DISTCLEAN += object_script.* diff --git a/common/protocol.proto b/common/protocol.proto index 3510e2b..25b0fbb 100644 --- a/common/protocol.proto +++ b/common/protocol.proto @@ -86,6 +86,7 @@ message Protocol { kPayloadFieldNumber = 101; kSampleFieldNumber = 102; kUserScriptFieldNumber = 103; + kHexDumpFieldNumber = 104; kEth2FieldNumber = 200; kDot3FieldNumber = 201; diff --git a/common/protocolmanager.cpp b/common/protocolmanager.cpp index 0910e1a..b256135 100644 --- a/common/protocolmanager.cpp +++ b/common/protocolmanager.cpp @@ -43,6 +43,7 @@ along with this program. If not, see #include "udp.h" #include "textproto.h" #include "userscript.h" +#include "hexdump.h" #include "sample.h" ProtocolManager *OstProtocolManager; @@ -99,6 +100,8 @@ ProtocolManager::ProtocolManager() registerProtocol(OstProto::Protocol::kTextProtocolFieldNumber, (void*) TextProtocol::createInstance); + registerProtocol(OstProto::Protocol::kHexDumpFieldNumber, + (void*) HexDumpProtocol::createInstance); registerProtocol(OstProto::Protocol::kPayloadFieldNumber, (void*) PayloadProtocol::createInstance); diff --git a/extra/qhexedit2/qhexedit2.pro b/extra/qhexedit2/qhexedit2.pro new file mode 100644 index 0000000..c7b9989 --- /dev/null +++ b/extra/qhexedit2/qhexedit2.pro @@ -0,0 +1,8 @@ +TEMPLATE = lib +CONFIG += qt staticlib warn_on + +HEADERS = src/qhexedit.h \ + src/qhexedit_p.h + +SOURCES = src/qhexedit.cpp \ + src/qhexedit_p.cpp diff --git a/extra/qhexedit2/src/license.txt b/extra/qhexedit2/src/license.txt new file mode 100644 index 0000000..f166cc5 --- /dev/null +++ b/extra/qhexedit2/src/license.txt @@ -0,0 +1,502 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! \ No newline at end of file diff --git a/extra/qhexedit2/src/qhexedit.cpp b/extra/qhexedit2/src/qhexedit.cpp new file mode 100644 index 0000000..a295110 --- /dev/null +++ b/extra/qhexedit2/src/qhexedit.cpp @@ -0,0 +1,106 @@ +#include + +#include "qhexedit.h" + + +QHexEdit::QHexEdit(QWidget *parent) : QScrollArea(parent) +{ + qHexEdit_p = new QHexEditPrivate(this); + setWidget(qHexEdit_p); + setWidgetResizable(true); + + connect(qHexEdit_p, SIGNAL(dataChanged()), this, SIGNAL(dataChanged())); + connect(qHexEdit_p, SIGNAL(currentAddress(int)), this, SIGNAL(currentAddress(int))); + connect(qHexEdit_p, SIGNAL(overwriteModeChanged(bool)), this, SIGNAL(overwriteModeChanged(bool))); +} + +void QHexEdit::insert(int i, const QByteArray & ba) +{ + qHexEdit_p->insert(i, ba); +} + +void QHexEdit::insert(int i, char ch) +{ + qHexEdit_p->insert(i, ch); +} + +void QHexEdit::remove(int pos, int len) +{ + qHexEdit_p->remove(pos, len); +} + +void QHexEdit::setAddressArea(bool addressArea) +{ + qHexEdit_p->setAddressArea(addressArea); +} + +void QHexEdit::setAddressWidth(int addressWidth) +{ + qHexEdit_p->setAddressWidth(addressWidth); +} + +void QHexEdit::setAsciiArea(bool asciiArea) +{ + qHexEdit_p->setAsciiArea(asciiArea); +} + +void QHexEdit::setHighlighting(bool mode) +{ + qHexEdit_p->setHighlighting(mode); +} + +void QHexEdit::setAddressOffset(int offset) +{ + qHexEdit_p->setAddressOffset(offset); +} + +int QHexEdit::addressOffset() +{ + return addressOffset(); +} + +void QHexEdit::setData(const QByteArray &data) +{ + qHexEdit_p->setData(data); +} + +QByteArray QHexEdit::data() +{ + return qHexEdit_p->data(); +} + +void QHexEdit::setAddressAreaColor(const QColor &color) +{ + qHexEdit_p->setAddressAreaColor(color); +} + +QColor QHexEdit::addressAreaColor() +{ + return qHexEdit_p->addressAreaColor(); +} + +void QHexEdit::setHighlightingColor(const QColor &color) +{ + qHexEdit_p->setHighlightingColor(color); +} + +QColor QHexEdit::highlightingColor() +{ + return qHexEdit_p->highlightingColor(); +} + +void QHexEdit::setOverwriteMode(bool overwriteMode) +{ + qHexEdit_p->setOverwriteMode(overwriteMode); +} + +bool QHexEdit::overwriteMode() +{ + return qHexEdit_p->overwriteMode(); +} + +void QHexEdit::setFont(const QFont &font) +{ + qHexEdit_p->setFont(font); +} + diff --git a/extra/qhexedit2/src/qhexedit.h b/extra/qhexedit2/src/qhexedit.h new file mode 100644 index 0000000..2b94581 --- /dev/null +++ b/extra/qhexedit2/src/qhexedit.h @@ -0,0 +1,145 @@ +#ifndef QHEXEDIT_H +#define QHEXEDIT_H + +#include +#include "qhexedit_p.h" + +/** \mainpage +QHexEdit is a binary editor widget for Qt. + +\version Version 0.4.3 +\image html hexedit.png +*/ + + +/*! QHexEdit is a hex editor widget written in C++ for the Qt (Qt4) framework. +It is a simple editor for binary data, just like QPlainTextEdit is for text data. +There are sip configuration files included, so it is easy to create bindings +for PyQt and you can use this widget also in python. + +QHexEdit takes the data of a QByteArray (setData()) and shows it. You can use the +mouse or the keyboard to navigate inside the widget. If you hit the keys (0..9, a..f) +you will change the data. Changed data is highlighted and can be accessed via data(). + +Normaly QHexEdit works in the overwrite Mode. You can set overwriteMode(false) and +insert data. In this case the size of data() increases. It is also possible to delete +bytes under the cursor, here the size of data decreases. + +There are some limitations: The size of data has in general to be below 10 megabytes, +otherwise the scroll sliders ard not shown and you can't scroll any more. Copy and +paste functionality is perhaps a subject of a later release. +*/ + class QHexEdit : public QScrollArea +{ + Q_OBJECT + /*! Property data holds the content of QHexEdit. Call setData() to set the + content of QHexEdit, data() returns the actual content. + */ + Q_PROPERTY(QByteArray data READ data WRITE setData) + + /*! Property addressOffset is added to the Numbers of the Address Area. + A offset in the address area (left side) is sometimes usefull, whe you show + only a segment of a complete memory picture. With setAddressOffset() you set + this property - with addressOffset() you get the actual value. + */ + Q_PROPERTY(int addressOffset READ addressOffset WRITE setAddressOffset) + + /*! Property address area color sets (setAddressAreaColor()) the backgorund + color of address areas. You can also read the color (addressaAreaColor()). + */ + Q_PROPERTY(QColor addressAreaColor READ addressAreaColor WRITE setAddressAreaColor) + + /*! Property highlighting color sets (setHighlightingColor()) the backgorund + color of highlighted text areas. You can also read the color + (highlightingColor()). + */ + Q_PROPERTY(QColor highlightingColor READ highlightingColor WRITE setHighlightingColor) + + /*! Porperty overwrite mode sets (setOverwriteMode()) or gets (overwriteMode()) the mode + in which the editor works. In overwritem mode the user will overwrite existing data. + */ + Q_PROPERTY(bool overwriteMode READ overwriteMode WRITE setOverwriteMode) + +public: + /*! Creates an instance of QHexEdit. + \param parent Parent widget of QHexEdit. + */ + QHexEdit(QWidget *parent = 0); + + /*! Inserts a byte array. + \param i Index position, where to insert + \param ba byte array, which is to insert + */ + void insert(int i, const QByteArray & ba); + + /*! Inserts a char. + \param i Index position, where to insert + \param ch Char, which is to insert + */ + void insert(int i, char ch); + + /*! Removes len bytes from the content. + \param pos Index position, where to remove + \param len Amount of bytes to remove + */ + void remove(int pos, int len=1); + + /*! Set the font of the widget. Please use fixed width fonts like Mono or Courier.*/ + void setFont(const QFont &); + + /*! \cond docNever */ + void setAddressOffset(int offset); + int addressOffset(); + void setData(QByteArray const &data); + QByteArray data(); + void setAddressAreaColor(QColor const &color); + QColor addressAreaColor(); + void setHighlightingColor(QColor const &color); + QColor highlightingColor(); + void setOverwriteMode(bool); + bool overwriteMode(); + /*! \endcond docNever */ + +public slots: + + /*! Set the minimum width of the address area. + \param addressWidth Width in characters. + */ + void setAddressWidth(int addressWidth); + + /*! Switch the address area on or off. + \param addressArea true (show it), false (hide it). + */ + void setAddressArea(bool addressArea); + + /*! Switch the ascii area on or off. + \param asciiArea true (show it), false (hide it). + */ + void setAsciiArea(bool asciiArea); + + /*! Switch the highlighting feature on or of. + \param mode true (show it), false (hide it). + */ + void setHighlighting(bool mode); + +signals: + + /*! Contains the address, where the cursor is located. */ + void currentAddress(int address); + + /*! The signal is emited every time, the data is changed. */ + void dataChanged(); + + /*! The signal is emited every time, the overwrite mode is changed. */ + void overwriteModeChanged(bool state); + +private: + /*! \cond docNever */ + QHexEditPrivate *qHexEdit_p; + QHBoxLayout *layout; + QScrollArea *scrollArea; + /*! \endcond docNever */ +}; + +#endif + diff --git a/extra/qhexedit2/src/qhexedit_p.cpp b/extra/qhexedit2/src/qhexedit_p.cpp new file mode 100644 index 0000000..30f0660 --- /dev/null +++ b/extra/qhexedit2/src/qhexedit_p.cpp @@ -0,0 +1,414 @@ +#include + +#include "qhexedit_p.h" + +const int HEXCHARS_IN_LINE = 47; +const int GAP_ADR_HEX = 10; +const int GAP_HEX_ASCII = 16; +const int BYTES_PER_LINE = 16; + +QHexEditPrivate::QHexEditPrivate(QScrollArea *parent) : QWidget(parent) +{ + _scrollArea = parent; + setAddressWidth(4); + setAddressOffset(0); + setAddressArea(true); + setAsciiArea(true); + setHighlighting(true); + setOverwriteMode(true); + setAddressAreaColor(QColor(Qt::lightGray).lighter(110)); + setHighlightingColor(QColor(Qt::yellow).lighter(160)); + + setFont(QFont("Mono", 10)); + connect(&_cursorTimer, SIGNAL(timeout()), this, SLOT(updateCursor())); + + _cursorTimer.setInterval(500); + _cursorTimer.start(); + + setFocusPolicy(Qt::StrongFocus); +} + +void QHexEditPrivate::setAddressOffset(int offset) +{ + _addressOffset = offset; + adjust(); +} + +int QHexEditPrivate::addressOffset() +{ + return _addressOffset; +} + +void QHexEditPrivate::setData(const QByteArray &data) +{ + _data = data; + _originalData = data; + adjust(); + setCursorPos(0); + setFocus(); +} + +QByteArray QHexEditPrivate::data() +{ + return _data; +} + +void QHexEditPrivate::setAddressAreaColor(const QColor &color) +{ + _addressAreaColor = color; + update(); +} + +QColor QHexEditPrivate::addressAreaColor() +{ + return _addressAreaColor; +} + +void QHexEditPrivate::setHighlightingColor(const QColor &color) +{ + _highlightingColor = color; + update(); +} + +QColor QHexEditPrivate::highlightingColor() +{ + return _highlightingColor; +} + +void QHexEditPrivate::setOverwriteMode(bool overwriteMode) +{ + if (overwriteMode != _overwriteMode) + { + emit overwriteModeChanged(overwriteMode); + _overwriteMode = overwriteMode; + adjust(); + } +} + +bool QHexEditPrivate::overwriteMode() +{ + return _overwriteMode; +} + +void QHexEditPrivate::insert(int i, const QByteArray & ba) +{ + _data.insert(i, ba); + _originalData.insert(i, ba); +} + +void QHexEditPrivate::insert(int i, char ch) +{ + _data.insert(i, ch); + _originalData.insert(i, ch); +} + +void QHexEditPrivate::remove(int index, int len) +{ + _data.remove(index, len); + _originalData.remove(index, len); +} + +void QHexEditPrivate::setAddressArea(bool addressArea) +{ + _addressArea = addressArea; + adjust(); + setCursorPos(_cursorPosition); +} + +void QHexEditPrivate::setAddressWidth(int addressWidth) +{ + if ((addressWidth >= 0) and (addressWidth<=6)) + { + _addressNumbers = addressWidth; + adjust(); + setCursorPos(_cursorPosition); + } +} + +void QHexEditPrivate::setAsciiArea(bool asciiArea) +{ + _asciiArea = asciiArea; + adjust(); +} + +void QHexEditPrivate::setFont(const QFont &font) +{ + QWidget::setFont(font); + adjust(); +} + +void QHexEditPrivate::setHighlighting(bool mode) +{ + _highlighting = mode; + update(); +} + +void QHexEditPrivate::keyPressEvent(QKeyEvent *event) +{ + bool down = false; + int charX = (_cursorX - _xPosHex) / _charWidth; + int posX = (charX / 3) * 2 + (charX % 3); + int posBa = (_cursorY / _charHeight) * BYTES_PER_LINE + posX / 2; + + int key = int(event->text()[0].toAscii()); + if ((key>='0' && key<='9') || (key>='a' && key <= 'f')) + { + // calc address + + + // insert char + if (_overwriteMode == false) + if ((charX % 3) == 0) + { + insert(posBa, char(0)); + adjust(); + } + QByteArray hexValue = _data.mid(posBa, 1).toHex(); + if ((charX % 3) == 0) + hexValue[0] = key; + else + hexValue[1] = key; + _data.replace(posBa, 1, QByteArray().fromHex(hexValue)); + emit dataChanged(); + + setCursorPos(_cursorPosition + 1); + down = true; + } + + // delete char + if (event->matches(QKeySequence::Delete)) + remove(posBa); + if (event->key() == Qt::Key_Backspace) + { + remove(posBa - 1); + setCursorPos(_cursorPosition - 2); + } + + // handle other function keys + if (event->key() == Qt::Key_Insert) + setOverwriteMode(!_overwriteMode); + + if (event->matches(QKeySequence::MoveToNextChar)) + { + setCursorPos(_cursorPosition + 1); + down = true; + } + if (event->matches(QKeySequence::MoveToPreviousChar)) + setCursorPos(_cursorPosition - 1); + if (event->matches(QKeySequence::MoveToStartOfLine)) + setCursorPos(_cursorPosition - (_cursorPosition % (2 * BYTES_PER_LINE))); + if (event->matches(QKeySequence::MoveToEndOfLine)) + setCursorPos(_cursorPosition | (2 * BYTES_PER_LINE -1)); + if (event->matches(QKeySequence::MoveToPreviousLine)) + setCursorPos(_cursorPosition - (2 * BYTES_PER_LINE)); + if (event->matches(QKeySequence::MoveToPreviousPage)) + setCursorPos(_cursorPosition - (((_scrollArea->viewport()->height() / _charHeight) - 1) * 2 * BYTES_PER_LINE)); + if (event->matches(QKeySequence::MoveToStartOfDocument)) + setCursorPos(0); + if (event->matches(QKeySequence::MoveToNextLine)) + { + setCursorPos(_cursorPosition + (2 * BYTES_PER_LINE)); + down = true; + } + if (event->matches(QKeySequence::MoveToEndOfDocument)) + { + setCursorPos(_data.size() * 2); + down = true; + } + if (event->matches(QKeySequence::MoveToNextPage)) + { + setCursorPos(_cursorPosition + (((_scrollArea->viewport()->height() / _charHeight) - 1) * 2 * BYTES_PER_LINE)); + down = true; + } + + // when we move downwards, we have to go a little further + if (down) + _scrollArea->ensureVisible(_cursorX, _cursorY, 3, 3 + _charHeight); + else + _scrollArea->ensureVisible(_cursorX, _cursorY, 3, 3); + update(); +} + +void QHexEditPrivate::mousePressEvent(QMouseEvent * event) +{ + setCursorPos(event->pos()); +} + +void QHexEditPrivate::paintEvent(QPaintEvent *event) +{ + QPainter painter(this); + + // draw some patterns if needed + painter.fillRect(event->rect(), this->palette().color(QPalette::Base)); + if (_addressArea) + painter.fillRect(QRect(_xPosAdr, event->rect().top(), _xPosHex - GAP_ADR_HEX + 2, height()), _addressAreaColor); + if (_asciiArea) + { + int linePos = _xPosAscii - (GAP_HEX_ASCII / 2); + painter.setPen(Qt::gray); + painter.drawLine(linePos, event->rect().top(), linePos, height()); + } + + painter.setPen(this->palette().color(QPalette::WindowText)); + + // calc position + int firstLineIdx = ((event->rect().top()/ _charHeight) - _charHeight) * BYTES_PER_LINE; + if (firstLineIdx < 0) + firstLineIdx = 0; + int lastLineIdx = ((event->rect().bottom() / _charHeight) + _charHeight) * BYTES_PER_LINE; + if (lastLineIdx > _data.size()) + lastLineIdx = _data.size(); + int yPosStart = ((firstLineIdx) / BYTES_PER_LINE) * _charHeight + _charHeight; + + // paint address area + if (_addressArea) + { + for (int lineIdx = firstLineIdx, yPos = yPosStart; lineIdx < lastLineIdx; lineIdx += BYTES_PER_LINE, yPos +=_charHeight) + { + QString address = QString("%1") + .arg(lineIdx + _addressOffset, _realAddressNumbers, 16, QChar('0')); + painter.drawText(_xPosAdr, yPos, address); + } + } + + // paint hex area + QByteArray hexBa(_data.mid(firstLineIdx, lastLineIdx - firstLineIdx + 1).toHex()); + QBrush highLighted = QBrush(_highlightingColor); + painter.setBackground(highLighted); + painter.setBackgroundMode(Qt::TransparentMode); + for (int lineIdx = firstLineIdx, yPos = yPosStart; lineIdx < lastLineIdx; lineIdx += BYTES_PER_LINE, yPos +=_charHeight) + { + QByteArray hex; + int xPos = _xPosHex; + for (int colIdx = 0; ((lineIdx + colIdx) < _data.size() and (colIdx < BYTES_PER_LINE)); colIdx++) + { + // hilight diff bytes + if (_highlighting) + { + int posBa = lineIdx + colIdx; + if (posBa >= _originalData.size()) + painter.setBackgroundMode(Qt::TransparentMode); + else + if (_data[posBa] == _originalData[posBa]) + painter.setBackgroundMode(Qt::TransparentMode); + else + painter.setBackgroundMode(Qt::OpaqueMode); + } + + // render hex value + if (colIdx == 0) + { + hex = hexBa.mid((lineIdx - firstLineIdx) * 2, 2); + painter.drawText(xPos, yPos, hex); + xPos += 2 * _charWidth; + } else { + hex = hexBa.mid((lineIdx + colIdx - firstLineIdx) * 2, 2).prepend(" "); + painter.drawText(xPos, yPos, hex); + xPos += 3 * _charWidth; + } + } + } + painter.setBackgroundMode(Qt::TransparentMode); + + // paint ascii area + if (_asciiArea) + { + for (int lineIdx = firstLineIdx, yPos = yPosStart; lineIdx < lastLineIdx; lineIdx += BYTES_PER_LINE, yPos +=_charHeight) + { + QByteArray ascii = _data.mid(lineIdx, BYTES_PER_LINE); + for (int idx=0; idx < ascii.size(); idx++) + if (((char)ascii[idx] < 0x20) or ((char)ascii[idx] > 0x7e)) + ascii[idx] = '.'; + painter.drawText(_xPosAscii, yPos, ascii); + } + } + + // paint cursor + if ((_data.size() > 0) and _blink) + painter.fillRect(_cursorX, _cursorY, _cursorWidth, _cursorHeight, this->palette().color(QPalette::WindowText)); +} + +void QHexEditPrivate::setCursorPos(int position) +{ + // delete cursor + _blink = false; + update(); + + // cursor in range? + if (_overwriteMode) + { + if (position > (_data.size() * 2 - 1)) + position = _data.size() * 2 - 1; + } else { + if (position > (_data.size() * 2)) + position = _data.size() * 2; + } + + if (position < 0) + position = 0; + + // calc position + _cursorPosition = position; + _cursorY = (position / (2 * BYTES_PER_LINE)) * _charHeight + 4; + int x = (position % (2 * BYTES_PER_LINE)); + _cursorX = (((x / 2) * 3) + (x % 2)) * _charWidth + _xPosHex; + + // immiadately draw cursor + _blink = true; + update(); + emit currentAddress(_cursorPosition/2); +} + +void QHexEditPrivate::setCursorPos(QPoint pos) +{ + // find char under cursor + if ((pos.x() >= _xPosHex) and (pos.x() < (_xPosHex + HEXCHARS_IN_LINE * _charWidth))) + { + int x = (pos.x() - _xPosHex) / _charWidth; + if ((x % 3) == 0) + x = (x / 3) * 2; + else + x = ((x / 3) * 2) + 1; + int y = (pos.y() / _charHeight) * 2 * BYTES_PER_LINE; + setCursorPos(x + y); + } +} + +void QHexEditPrivate::updateCursor() +{ + if (_blink) + _blink = false; + else + _blink = true; + update(_cursorX, _cursorY, _charWidth, _charHeight); +} + +void QHexEditPrivate::adjust() +{ + _charWidth = fontMetrics().width(QLatin1Char('9')); + _charHeight = fontMetrics().height(); + + // is addressNumbers wide enought? + QString test = QString("%1") + .arg(_data.size() + _addressOffset, _addressNumbers, 16, QChar('0')); + _realAddressNumbers = test.size(); + + _xPosAdr = 0; + if (_addressArea) + _xPosHex = _realAddressNumbers *_charWidth + GAP_ADR_HEX; + else + _xPosHex = 0; + _xPosAscii = _xPosHex + HEXCHARS_IN_LINE * _charWidth + GAP_HEX_ASCII; + + if (_overwriteMode) + _cursorWidth = _charWidth; + else + _cursorWidth = 2; + _cursorHeight = _charHeight - 3; + + // tell QAbstractScollbar, how big we are + setMinimumHeight(((_data.size()/16 + 1) * _charHeight) + 3); + setMinimumWidth(_xPosAscii + (BYTES_PER_LINE * _charWidth)); + + update(); +} diff --git a/extra/qhexedit2/src/qhexedit_p.h b/extra/qhexedit2/src/qhexedit_p.h new file mode 100644 index 0000000..c422c58 --- /dev/null +++ b/extra/qhexedit2/src/qhexedit_p.h @@ -0,0 +1,82 @@ +#ifndef QHEXEDIT_P_H +#define QHEXEDIT_P_H + +/** \cond docNever */ + + +#include + +class QHexEditPrivate : public QWidget +{ +Q_OBJECT + +public: + QHexEditPrivate(QScrollArea *parent); + + void setAddressOffset(int offset); + int addressOffset(); + + void setData(QByteArray const &data); + QByteArray data(); + + void setAddressAreaColor(QColor const &color); + QColor addressAreaColor(); + + void setHighlightingColor(QColor const &color); + QColor highlightingColor(); + + void setOverwriteMode(bool overwriteMode); + bool overwriteMode(); + + void insert(int i, const QByteArray & ba); + void insert(int i, char ch); + void remove(int index, int len=1); + + void setAddressArea(bool addressArea); + void setAddressWidth(int addressWidth); + void setAsciiArea(bool asciiArea); + void setHighlighting(bool mode); + virtual void setFont(const QFont &font); + +signals: + void currentAddress(int address); + void dataChanged(); + void overwriteModeChanged(bool state); + +protected: + void keyPressEvent(QKeyEvent * event); + void mousePressEvent(QMouseEvent * event); + void paintEvent(QPaintEvent *event); + void setCursorPos(QPoint pos); + void setCursorPos(int position); + +private slots: + void updateCursor(); + +private: + void adjust(); + + QColor _addressAreaColor; + QByteArray _data; + QByteArray _originalData; + QColor _highlightingColor; + QScrollArea *_scrollArea; + QTimer _cursorTimer; + + bool _blink; + bool _addressArea; + bool _asciiArea; + bool _highlighting; + bool _overwriteMode; + + int _addressNumbers, _realAddressNumbers; + int _addressOffset; + int _charWidth, _charHeight; + int _cursorX, _cursorY, _cursorWidth, _cursorHeight, _cursorPosition; + int _xPosAdr, _xPosHex, _xPosAscii; +}; + +/** \endcond docNever */ + +#endif + diff --git a/server/drone.pro b/server/drone.pro index b2b25d1..160973b 100644 --- a/server/drone.pro +++ b/server/drone.pro @@ -25,6 +25,7 @@ win32 { POST_TARGETDEPS += "../common/libostproto.a" "../rpc/libpbrpc.a" } LIBS += -lprotobuf +LIBS += -L"../extra/qhexedit2/$(OBJECTS_DIR)/" -lqhexedit2 RESOURCES += drone.qrc HEADERS += drone.h FORMS += drone.ui