summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/box.hpp50
-rw-r--r--src/compareDlg.cpp305
-rw-r--r--src/compareDlg.hpp56
-rw-r--r--src/conversionDlg.cpp363
-rw-r--r--src/conversionDlg.hpp78
-rwxr-xr-xsrc/cursor.cpp158
-rwxr-xr-xsrc/cursor.hpp71
-rwxr-xr-xsrc/delta.cpp126
-rwxr-xr-xsrc/delta.hpp93
-rw-r--r--src/driver.cpp100
-rw-r--r--src/expr.h27
-rw-r--r--src/expr.l154
-rw-r--r--src/expr.y61
-rw-r--r--src/grid.cpp42
-rw-r--r--src/grid.hpp35
-rwxr-xr-xsrc/hexEditor.cpp1112
-rwxr-xr-xsrc/hexEditor.hpp242
-rw-r--r--src/hexGui.cpp326
-rw-r--r--src/hexGui.hpp97
-rw-r--r--src/images.qrc9
-rw-r--r--src/img/exit.xbm6
-rw-r--r--src/img/first.xbm6
-rw-r--r--src/img/last.xbm6
-rw-r--r--src/img/next.xbm6
-rw-r--r--src/img/prev.xbm6
-rwxr-xr-xsrc/lfhexbin0 -> 2849919 bytes
-rw-r--r--src/lfhex.pro60
-rw-r--r--src/local.h30
-rwxr-xr-xsrc/mappings.h179
-rw-r--r--src/offsetConstraint.cpp98
-rw-r--r--src/offsetConstraint.hpp48
-rw-r--r--src/reader.cpp364
-rw-r--r--src/reader.hpp95
-rw-r--r--src/save.cpp67
-rw-r--r--src/save.hpp25
-rwxr-xr-xsrc/translate.cpp189
-rwxr-xr-xsrc/translate.hpp47
37 files changed, 4737 insertions, 0 deletions
diff --git a/src/box.hpp b/src/box.hpp
new file mode 100644
index 0000000..3edd733
--- /dev/null
+++ b/src/box.hpp
@@ -0,0 +1,50 @@
+#ifndef LFHEX_BOX_HPP
+#define LFHEX_BOX_HPP
+/* $Id: box.hpp,v 1.1 2006-11-05 04:42:43 ganzhorn Exp $
+ * This file is part of lfhex.
+ * Copyright (C) 2006 Salem Ganzhorn <eyekode@yahoo.com>
+ *
+ * This program 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 version 2.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <QWidget>
+#include <QHBoxLayout>
+#include <QVBoxLayout>
+#include <QChildEvent>
+
+template< class _layout >
+class box : public QWidget {
+public:
+ box( QWidget* parent ) : QWidget(parent) {
+ QLayout* l = new _layout(this);
+ setLayout(l);
+ }
+ void addStretch( int s )
+ {
+ dynamic_cast<QBoxLayout*>(layout())->addStretch(s);
+ }
+protected:
+ void childEvent( QChildEvent *e ) {
+ if( e->added() && e->child()->isWidgetType() ) {
+ QWidget* w = dynamic_cast<QWidget*>(e->child());
+ layout()->addWidget(w);
+ }
+ }
+};
+
+typedef box<QHBoxLayout> hbox;
+typedef box<QVBoxLayout> vbox;
+
+#endif
+
diff --git a/src/compareDlg.cpp b/src/compareDlg.cpp
new file mode 100644
index 0000000..3c4e104
--- /dev/null
+++ b/src/compareDlg.cpp
@@ -0,0 +1,305 @@
+/* $Id: compareDlg.cpp,v 1.9 2008-09-11 01:49:00 salem Exp $
+ * This file is part of lfhex.
+ * Copyright (C) 2006 Salem Ganzhorn <eyekode@yahoo.com>
+ *
+ * This program 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 version 2.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <QLabel>
+#include <QLineEdit>
+#include <QCheckBox>
+#include <qlayout.h>
+#include <qpushbutton.h>
+#include <QToolBar>
+#include <QFileDialog>
+#include <QMessageBox>
+#include <QApplication>
+#include <qcombobox.h>
+#include <qtabwidget.h>
+#include <QBitmap>
+#include <QVBoxLayout>
+#include <QMenuBar>
+
+#include "compareDlg.hpp"
+#include "offsetConstraint.hpp"
+#include "hexGui.hpp"
+#include "reader.hpp"
+#include "box.hpp"
+
+// icon images:
+#include "img/prev.xbm"
+#include "img/next.xbm"
+#include "img/last.xbm"
+#include "img/first.xbm"
+#include "img/exit.xbm"
+
+//extern QApplication * qApp;
+
+CompareDlg::CompareDlg(const char *file0,
+ const char *file1,
+ QWidget*parent)
+ : QMainWindow(parent)
+{
+ tabLayout = new QTabWidget(this);
+ setCentralWidget(tabLayout);
+
+ QWidget *options = new QWidget(tabLayout);
+ QVBoxLayout *optionLayout = new QVBoxLayout(options);
+
+ optionLayout->setMargin(3);
+ optionLayout->setSpacing(2);
+
+ // setup alignment entries:
+ offsetConstraint = new OffsetConstraint(options);
+ offsetConstraint->setTitle( "Constrain offset to X*n+Y" );
+ optionLayout->addWidget(offsetConstraint);
+ // setup cursor offsets
+ diffOffsets = new QCheckBox("Allow different file offsets",options);
+ optionLayout->addWidget(diffOffsets);
+ // add a dummy strechable widget for alignment.
+ optionLayout->addStretch(1);
+ connect(diffOffsets,SIGNAL(stateChanged(int)),
+ this,SLOT(setAllowDiffOffsets(int)));
+ diffOffsets->setChecked(false);
+ setAllowDiffOffsets(false);
+
+ // setup menu
+ QMenu* fileMenu = menuBar()->addMenu("File");
+ fileMenu->addAction( QBitmap::fromData(QSize(exit_width,exit_height),
+ exit_bits),"Exit",qApp,SLOT(quit()));
+
+
+ // setup toolbar
+ QToolBar *tools = new QToolBar(this);
+
+ tools->addAction(QBitmap::fromData(QSize(first_width,first_height),first_bits),
+ "First Difference",this,SLOT(first()));
+ tools->addAction(QBitmap::fromData(QSize(prev_width,prev_height),prev_bits),
+ "Previous Difference", this,SLOT(prev()));
+ tools->addAction(QBitmap::fromData(QSize(next_width,next_height),next_bits),
+ "Next Difference", this,SLOT(next()));
+ tools->addAction(QBitmap::fromData(QSize(last_width,last_height),last_bits),
+ "Last Difference", this,SLOT(last()));
+
+ // setup compare section
+ QWidget *view = new QWidget(tabLayout);
+ QVBoxLayout *layout = new QVBoxLayout(view);
+
+ hexGui[0] = new HexGui(view);
+ hexGui[1] = new HexGui(view);
+ reader[0] = hexGui[0]->reader();
+ reader[1] = hexGui[1]->reader();
+
+ if( file0 )
+ hexGui[0]->open(file0);
+ if( file1 )
+ hexGui[1]->open(file1);
+
+ layout->addWidget(hexGui[0]);
+ layout->addWidget(hexGui[1]);
+ hexGui[0]->setWindowFlags(Qt::SubWindow);
+ hexGui[1]->setWindowFlags(Qt::SubWindow);
+
+
+ tabLayout->addTab(view,"&Compare");
+ tabLayout->addTab(options,"&Options");
+ addToolBar(tools);
+ // request a size large enough for both hexEditors
+ resize(500,500);
+ setWindowTitle("Compare dialog");
+}
+
+bool CompareDlg::enabled()
+{
+ if( reader[0]->is_open() && reader[1]->is_open() ) {
+ // check to see if modified!!!
+ if( hexGui[0]->isModified() || hexGui[1]->isModified() ) {
+ QMessageBox::critical(this,PROGRAM_STRING,
+ "Error, cannot use comparison"
+ " functions on modified buffers.");
+ return false;
+ }
+ return true;
+ }
+
+ return false;
+}
+// public slots
+void CompareDlg::setAllowDiffOffsets(int state)
+{
+ diffOffsets->setChecked(state);
+}
+
+bool CompareDlg::first()
+{
+ if( !enabled() )
+ return false;
+
+ // see Compare::last() for description of concept
+ off_t offset = offsetConstraint->next(0);
+ hexGui[0]->gotoOffset(offset);
+ hexGui[1]->gotoOffset(offset);
+ if( prev() )
+ return true;
+ hexGui[0]->gotoOffset(0);
+ hexGui[1]->gotoOffset(0);
+ return next();
+}
+
+bool CompareDlg::last()
+{
+ if( !enabled() )
+ return false;
+
+ // look at lastidx 's previous's next range
+ // prev(x) is garranteed to not contain x, and next(prev(x)) will contain x
+ off_t min_size_decr = min( reader[0]->size()-1,
+ reader[1]->size()-1 );
+ off_t offset = offsetConstraint->prev( min_size_decr );
+ hexGui[0]->gotoOffset(offset);
+ hexGui[1]->gotoOffset(offset);
+ if( next() )
+ return true;
+ hexGui[0]->gotoOffset( min_size_decr );
+ hexGui[1]->gotoOffset( min_size_decr );
+ return prev();
+}
+
+bool CompareDlg::prev()
+{
+ if( !enabled() )
+ return false;;
+ // find previous diff
+ off_t offset[2];
+ offset[0] = hexGui[0]->offset();
+ offset[1] = (diffOffsets->isChecked()) ? hexGui[1]->offset() : offset[0];
+
+ if( offsetConstraint->getStride() > 1 ) {
+ off_t stop[2];
+ off_t pos[2];
+ for( pos[0] = offset[0] = offsetConstraint->prev(offset[0]),
+ pos[1] = offset[1] = offsetConstraint->prev(offset[1]);
+ offset[0] >= 0 && offset[1] >= 0;
+ pos[0] = offset[0] = offsetConstraint->prev(offset[0]),
+ pos[1] = offset[1] = offsetConstraint->prev(offset[1])) {
+
+ // calculate stop
+ stop[0] = offset[0]+offsetConstraint->getStride();
+ stop[1] = offset[1]+offsetConstraint->getStride();
+
+ // ignore lookups on less than a full stride length
+ // this would only happen if the file size is less than the stride
+ if( stop[0] > reader[0]->size() || stop[1] > reader[1]->size() )
+ return false;
+
+ while( pos[0] < stop[0] ) {
+ if( (*reader[0])[pos[0]++] != (*reader[1])[pos[1]++] ) {
+ // we have a difference
+ hexGui[0]->setSelection(offset[0],stop[0]);
+ hexGui[1]->setSelection(offset[1],stop[1]);
+ hexGui[0]->gotoOffset(offset[0]);
+ hexGui[1]->gotoOffset(offset[1]);
+ return true;
+ }
+ }
+ }
+ } else {
+ // just go one char at a time
+
+ // make sure we are not past the eof of the second buffer
+ if( offset[1] >= reader[1]->size() )
+ return false;
+ if( offset[0] <= 0 || offset[1] <= 0 )
+ return false;
+ do {
+ offset[0]--;
+ offset[1]--;
+
+ if( (*reader[0])[offset[0]] != (*reader[1])[offset[1]] ) {
+ hexGui[0]->gotoOffset(offset[0]);
+ hexGui[1]->gotoOffset(offset[1]);
+ hexGui[0]->setSelection(offset[0],offset[0]+1);
+ hexGui[1]->setSelection(offset[1],offset[1]+1);
+ return true;
+ }
+ } while( offset[0] > 0 && offset[1] > 0 );
+ }
+ return false;
+}
+
+bool CompareDlg::next()
+{
+ // find next diff
+ if( !enabled() )
+ return false;
+
+ off_t offset[2];
+ offset[0] = hexGui[0]->offset();
+ offset[1] = (diffOffsets->isChecked()) ? hexGui[1]->offset() : offset[0];
+
+ off_t size[2];
+ size[0] = reader[0]->size();
+ size[1] = reader[1]->size();
+
+ if( offsetConstraint->getStride() > 1 ) {
+ off_t stop[2];
+ off_t pos[2];
+ for( pos[0] = offset[0] = offsetConstraint->next(offset[0]),
+ pos[1] = offset[1] = offsetConstraint->next(offset[1]);
+ offset[0] < size[0] && offset[1] < size[1];
+ pos[0] = offset[0] = offsetConstraint->next( offset[0] ),
+ pos[1] = offset[1] = offsetConstraint->next( offset[1] )) {
+ // compare from offset to offset+stride()
+ stop[0] = offset[0]+offsetConstraint->getStride();
+ stop[1] = offset[1]+offsetConstraint->getStride();
+ // if this will go past the bounds of the files, then the difference
+ // does not matter, ignore it.
+ if( stop[0] > size[0] || stop[1] > size[1] ) {
+ return false;
+ }
+
+ while( pos[0] < stop[0] ) {
+ if( (*reader[0])[pos[0]++] != (*reader[1])[pos[1]++] ) {
+ // we have a difference
+ hexGui[0]->setSelection(offset[0],stop[0]);
+ hexGui[1]->setSelection(offset[1],stop[1]);
+ hexGui[0]->gotoOffset(offset[0]);
+ hexGui[1]->gotoOffset(offset[1]);
+ return true; // bail out of fn
+ }
+ }
+ }
+ } else {
+ // just go one at a time
+ if( offset[0] >= size[0] || offset[1] >= size[1] )
+ return false;
+ if( offset[0] < 0 || offset[1] < 0 )
+ return false;
+ offset[0]++;
+ offset[1]++;
+ while( offset[0] < size[0] && offset[1] < size[1] ) {
+ // don't compare the one we are on
+ if( (*reader[0])[offset[0]] != (*reader[1])[offset[1]] ) {
+ hexGui[0]->gotoOffset(offset[0]);
+ hexGui[1]->gotoOffset(offset[1]);
+ hexGui[0]->setSelection(offset[0],offset[0]+1);
+ hexGui[1]->setSelection(offset[1],offset[1]+1);
+ return true;
+ }
+ offset[0]++;
+ offset[1]++;
+ }
+ }
+ return false;
+}
diff --git a/src/compareDlg.hpp b/src/compareDlg.hpp
new file mode 100644
index 0000000..1a51671
--- /dev/null
+++ b/src/compareDlg.hpp
@@ -0,0 +1,56 @@
+#ifndef COMPARE_DLG_HPP
+#define COMPARE_DLG_HPP
+/* $Id: compareDlg.hpp,v 1.5 2006-11-05 04:42:43 ganzhorn Exp $
+ * This file is part of lfhex.
+ * Copyright (C) 2006 Salem Ganzhorn <eyekode@yahoo.com>
+ *
+ * This program 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 version 2.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <QMainWindow>
+#include <list>
+#include "local.h"
+// forward decl to speed compile times
+class QCheckBox;
+class QLineEdit;
+class OffsetConstraint;
+class HexGui;
+class Reader;
+class QTabWidget;
+
+class CompareDlg : public QMainWindow {
+ Q_OBJECT
+public:
+ CompareDlg(const char * file0 = 0,
+ const char * file1 = 0,
+ QWidget * parent = 0);
+
+ public slots:
+ void setAllowDiffOffsets(int state);
+ bool first();
+ bool last();
+ bool prev();
+ bool next();
+protected:
+ bool enabled();
+
+protected:
+ QTabWidget * tabLayout;
+ QCheckBox * diffOffsets;
+ HexGui * hexGui[2];
+ Reader * reader[2];
+ OffsetConstraint * offsetConstraint;
+};
+
+#endif
diff --git a/src/conversionDlg.cpp b/src/conversionDlg.cpp
new file mode 100644
index 0000000..114ab19
--- /dev/null
+++ b/src/conversionDlg.cpp
@@ -0,0 +1,363 @@
+/* $Id: conversionDlg.cpp,v 1.7 2006-11-05 04:42:43 ganzhorn Exp $
+ * This file is part of lfhex.
+ * Copyright (C) 2006 Salem Ganzhorn <eyekode@yahoo.com>
+ *
+ * This program 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 version 2.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <QLabel>
+#include <QApplication>
+#include <QCheckBox>
+#include <QLineEdit>
+#include <QPushButton>
+#include <QMenuBar>
+#include <QToolTip>
+
+#include <iostream>
+#include <float.h>
+
+#include "conversionDlg.hpp"
+#include "local.h"
+#include "grid.hpp"
+#include "box.hpp"
+
+ConversionDlg::ConversionDlg ( QWidget*parent )
+ : QWidget(parent)
+{
+ inValueChanged = false;
+
+
+ QVBoxLayout *vbox = new QVBoxLayout(this);
+ grid* g = new grid(3,this);
+
+ g->setContentsMargins(3,3,3,3);
+
+ vbox->addWidget(g);
+
+ new QWidget(g);
+ new QLabel(" Hex:",g);
+ leditors[HexLE] = new QLineEdit(g);
+
+ new QWidget(g);
+ new QLabel(" ASCII:",g);
+ leditors[AsciiLE] = new QLineEdit(g);
+
+ byteSwapFlag[IntegerBS] = new QCheckBox("b/s",g);
+ new QLabel(" Int:",g);
+ leditors[IntegerLE] = new QLineEdit(g);
+
+ byteSwapFlag[FloatBS] = new QCheckBox("b/s",g);
+ new QLabel(" Float:",g);
+ leditors[FloatLE] = new QLineEdit(g);
+
+ byteSwapFlag[DoubleBS] = new QCheckBox("b/s",g);
+ new QLabel(" Double:",g);
+ leditors[DoubleLE] = new QLineEdit(g);
+
+ // make sure to do an update if any of the byte swap flags toggle
+ for(int i = MinBS; i < MaxBS; ++i) {
+ connect(byteSwapFlag[i],SIGNAL(clicked()),
+ this,SLOT(valueChanged()));
+ // add tool tip
+ byteSwapFlag[i]->setToolTip("Byte Swap Data");
+ }
+
+ // setup validators
+ leditors[DoubleLE]->setValidator( new QDoubleValidator(this) );
+ QDoubleValidator *vd = new QDoubleValidator(this);
+ vd->setRange( FLT_MAX, FLT_MAX );
+ leditors[FloatLE]->setValidator( vd );
+ leditors[IntegerLE]->setValidator( new QIntValidator(this) );
+ leditors[HexLE]->setValidator( new HexValidator(this) );
+
+ // setup editor connections
+ connect(leditors[DoubleLE],SIGNAL(textChanged(const QString& )),
+ this,SLOT(doubleChanged(const QString&)) );
+ connect(leditors[FloatLE],SIGNAL(textChanged(const QString& )),
+ this,SLOT(floatChanged(const QString&)) );
+ connect(leditors[IntegerLE],SIGNAL(textChanged(const QString&)),
+ this,SLOT(integerChanged(const QString&)) );
+ connect(leditors[HexLE],SIGNAL(textChanged(const QString&)),
+ this,SLOT(valueChanged(const QString&)));
+ connect(leditors[AsciiLE],SIGNAL(textChanged(const QString&)),
+ this,SLOT(asciiChanged(const QString&)));
+
+ for( int i = MinLE; i < MaxLE; ++i ) {
+ connect(leditors[i],SIGNAL(returnPressed()),
+ this,SIGNAL(nextPressed()));
+ }
+
+ hbox * h = new hbox(this);
+ vbox->addWidget(h);
+ vbox->addStretch(1);
+ QPushButton* prev = new QPushButton("<",h);
+ QPushButton* next = new QPushButton(">",h);
+
+ connect(prev,SIGNAL(clicked()),this,SIGNAL(prevPressed()));
+ connect(next,SIGNAL(clicked()),this,SIGNAL(nextPressed()));
+
+ setWindowTitle("Conversion Dialog");
+}
+
+ConversionDlg::~ConversionDlg()
+{
+ cout << "died" <<endl;
+}
+
+void ConversionDlg::floatChanged(const QString& str)
+{
+ QChar lastCh = str[str.length()-1];
+ if( lastCh == 'e' || lastCh == '-' || lastCh == '.' ) {
+ return;
+ }
+
+ bool success;
+ float value = str.toFloat(&success);
+
+ if( !success && !value ) {
+ return;
+ }
+
+ // double to hex:
+ uchar * ptr = (uchar*) &value;
+ vector<uchar> bytes;
+
+ if( byteSwapFlag[FloatBS]->isChecked() ) {
+ for( int i = sizeof(float)-1; i > -1; i--)
+ bytes.push_back(ptr[i]);
+ } else {
+ for( unsigned int i = 0; i < sizeof(float); i++ )
+ bytes.push_back(ptr[i]);
+ }
+
+ QString hex;
+ Translate::ByteToHex(hex,bytes);
+
+ valueChanged( hex );
+}
+
+void ConversionDlg::doubleChanged(const QString& str)
+{
+ QChar lastCh = str[str.length()-1];
+ if( lastCh == 'e' || lastCh == '-' || lastCh == '.' ) {
+ return;
+ }
+
+ bool success;
+ double value = str.toDouble(&success);
+
+ if( !success && !value ) {
+ return;
+ }
+
+ // double to hex:
+ uchar * ptr = (uchar*)&value;
+ vector<uchar> bytes;
+
+ if(byteSwapFlag[DoubleBS]->isChecked() ) {
+ for(int i = sizeof(double)-1; i > -1; --i)
+ bytes.push_back(ptr[i]);
+ } else {
+ for(unsigned int i = 0; i < sizeof(double); i++ )
+ bytes.push_back(ptr[i]);
+ }
+ QString hex;
+ Translate::ByteToHex(hex,bytes);
+
+ valueChanged( hex );
+}
+
+void ConversionDlg::asciiChanged(const QString &str)
+{
+ vector<uchar> bytes;
+ QString hex;
+ Translate::CharToByte(bytes,str);
+ Translate::ByteToHex(hex,bytes);
+
+ valueChanged( hex );
+}
+
+void ConversionDlg::integerChanged( const QString & str )
+{
+ bool success;
+ int value = str.toInt(&success);
+
+ uchar * ptr = (uchar*) &value;
+ vector<uchar> bytes;
+
+ if( byteSwapFlag[IntegerBS]->isChecked() ) {
+ for( int i = sizeof(int)-1; i > -1 ;--i )
+ bytes.push_back(ptr[i]);
+ } else {
+ for( unsigned int i = 0; i < sizeof(int)/sizeof(uchar); i++)
+ bytes.push_back(ptr[i]);
+ }
+
+ QString hex;
+ Translate::ByteToHex(hex,bytes);
+
+ valueChanged( hex );
+}
+
+// this slot just recalculates conversions
+void ConversionDlg::valueChanged()
+{
+ // make sure the HexLE has focus, so valueChanged(str) updates all fields
+ leditors[HexLE]->setFocus();
+ valueChanged( leditors[HexLE]->text() );
+}
+// convert data to hex, then call updateData to set all the other data fields
+void ConversionDlg::valueChanged( const QString& str )
+{
+ if( str.size()%2 ) {
+ return;
+ }
+ // don't allow this call to nest
+ if(inValueChanged)
+ return;
+
+ if( str.isEmpty() )
+ return;
+
+ inValueChanged = true;
+ // remmember cursor offset
+ int cursor_pos = leditors[HexLE]->cursorPosition();
+ // conversion is safe because all chars are less than 'f'
+ leditors[HexLE]->setText( str );
+ leditors[HexLE]->setCursorPosition( cursor_pos );
+
+ vector<uchar> bytes;
+ Translate::HexToByte(bytes,str);
+ if( !leditors[AsciiLE]->hasFocus() ) {
+
+ if(!bytes.size()) {
+ for(int i = MinLE; i < MaxLE; ++i)
+ leditors[i]->setText( "" );
+ inValueChanged = 0;
+ return;
+ }
+
+ // update the ascii entry:
+ QString ascii;
+ Translate::ByteToChar(ascii,bytes);
+
+ leditors[AsciiLE]->setText( ascii );
+ }
+
+ // scratch conversion vars
+ QString strvalue;
+ uchar * ucharPtr;
+
+ if( !leditors[IntegerLE]->hasFocus() ) {
+ // update the int entry:
+ // pad right with 0x00
+ int intvalue = 0;
+ ucharPtr = (uchar*) &intvalue;
+ if( byteSwapFlag[IntegerBS]->isChecked() ) {
+ for(unsigned int i = 0; (i < sizeof(int)) && (i < bytes.size()); i++)
+ ucharPtr[sizeof(int)-1-i] = bytes[i];
+ } else {
+ memcpy(&intvalue,&bytes.begin()[0],
+ min(sizeof(int),bytes.size()));
+ }
+ strvalue.setNum(intvalue);
+ leditors[IntegerLE]->setText( strvalue );
+ }
+
+ if( ! leditors[FloatLE]->hasFocus() ) {
+ // update the float entry:
+ float fvalue;
+ ucharPtr = (uchar*)(&fvalue);
+ if( byteSwapFlag[FloatBS]->isChecked() ) {
+ for(unsigned int i = 0; i < sizeof(float); ++i) {
+ if( i < bytes.size() ) {
+ ucharPtr[sizeof(float)-1-i] = bytes[i];
+ } else {
+ ucharPtr[sizeof(float)-1-i] = 0x00;
+ }
+ }
+ } else {
+ if(bytes.size() < sizeof(float) ) {
+ for(unsigned int i= 0; i < sizeof(float); ++i) {
+ if( i < bytes.size() ) {
+ *ucharPtr++ = bytes[i];
+ } else {
+ *ucharPtr++ = 0x00;
+ }
+ }
+ } else {
+ memcpy(&fvalue,&bytes.begin()[0],sizeof(float));
+ }
+ }
+ strvalue.setNum( fvalue );
+ leditors[FloatLE]->setText( strvalue );
+ }
+
+ if( ! leditors[DoubleLE]->hasFocus() ) {
+ // update the double entry:
+ double dvalue;
+ ucharPtr = (uchar*)&dvalue;
+ if( byteSwapFlag[DoubleBS]->isChecked() ) {
+ for(unsigned int i= 0; i < sizeof(double); ++i) {
+ if( i < bytes.size() ) {
+ ucharPtr[sizeof(double)-1-i] = bytes[i];
+ } else {
+ ucharPtr[sizeof(double)-1-i] = 0x00;
+ }
+ }
+ } else {
+ if(bytes.size() < sizeof(double) ) {
+ for(unsigned int i= 0; i < sizeof(double); ++i) {
+ if( i < bytes.size() ) {
+ *ucharPtr++ = bytes[i];
+ } else {
+ *ucharPtr++ = 0x00;
+ }
+ }
+ } else {
+ memcpy(&dvalue,&bytes.begin()[0],sizeof(double));
+ }
+ }
+ strvalue.setNum( dvalue );
+ leditors[DoubleLE]->setText( strvalue );
+ }
+
+ inValueChanged = false;
+}
+
+QString ConversionDlg::hexValue() const
+{
+ return leditors[HexLE]->text();
+}
+
+HexValidator::HexValidator( QWidget * parent )
+ : QValidator(parent)
+{
+}
+
+// allow 0xfff syntax
+QValidator::State HexValidator::validate ( QString &str, int &pos ) const
+{
+ str = str.toLower();
+ for(int i = 0; i < pos; i++) {
+ if( ! ((str[i] >= 'a' && str[i] <= 'f') ||
+ (str[i] >= '0' && str[i] <= '9') ) &&
+ ! (i == 1 && str[i] == 'x' )
+ ) {
+ return Invalid;
+ }
+ }
+ return Acceptable;
+}
+
diff --git a/src/conversionDlg.hpp b/src/conversionDlg.hpp
new file mode 100644
index 0000000..6c61282
--- /dev/null
+++ b/src/conversionDlg.hpp
@@ -0,0 +1,78 @@
+/* $Id: conversionDlg.hpp,v 1.4 2006-11-05 04:42:43 ganzhorn Exp $
+ * This file is part of lfhex.
+ * Copyright (C) 2006 Salem Ganzhorn <eyekode@yahoo.com>
+ *
+ * This program 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 version 2.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _CONVERSION_DLG_HPP_
+#define _CONVERSION_DLG_HPP_
+#include <QWidget>
+#include <QWidget>
+#include <QValidator>
+
+#include "translate.hpp"
+
+class QLineEdit;
+class QCheckBox;
+
+class ConversionDlg : public QWidget {
+ Q_OBJECT
+public:
+ ConversionDlg(QWidget* parent=0);
+ ~ConversionDlg();
+
+ QString hexValue() const;
+
+signals:
+ void nextPressed();
+ void prevPressed();
+
+public slots:
+ void doubleChanged( const QString& str );
+ void floatChanged( const QString& str );
+ void integerChanged( const QString& str );
+ void valueChanged( const QString& str );
+ void valueChanged();
+ void asciiChanged( const QString& str );
+
+protected:
+ enum {
+ MinLE = 0,
+ HexLE = 0 ,
+ AsciiLE,
+ DoubleLE,
+ FloatLE,
+ IntegerLE,
+ MaxLE
+ };
+ enum {
+ MinBS =0,
+ DoubleBS=0,
+ FloatBS,
+ IntegerBS,
+ MaxBS
+ };
+ QLineEdit * leditors[MaxLE];
+ QCheckBox * byteSwapFlag[MaxBS];
+ bool inValueChanged;
+};
+
+class HexValidator : public QValidator {
+public:
+ HexValidator( QWidget* parent );
+ State validate( QString & str, int & pos ) const;
+};
+
+#endif
diff --git a/src/cursor.cpp b/src/cursor.cpp
new file mode 100755
index 0000000..92f4bef
--- /dev/null
+++ b/src/cursor.cpp
@@ -0,0 +1,158 @@
+/* $Id: cursor.cpp,v 1.3 2006-11-05 04:42:43 ganzhorn Exp $
+ * This file is part of lfhex.
+ * Copyright (C) 2006 Salem Ganzhorn <eyekode@yahoo.com>
+ *
+ * This program 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 version 2.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "local.h"
+#include "cursor.hpp"
+
+//
+// Cursor implimentation
+//
+
+Cursor::Cursor(off_t byteOffset,
+ off_t charOffset,
+ off_t low,
+ off_t high,
+ off_t charsPerByte)
+: _byteOffset(byteOffset),
+ _charOffset(charOffset),
+ _low(low),
+ _high(high),
+ _charsPerByte(charsPerByte)
+{}
+// note: range includes low but excludes high: [low,high) (like stl)
+// note: [foo,foo) is considered the empty set
+bool Cursor::setRange( off_t low, off_t high )
+{
+ if ( low > high )
+ return false;
+ _low = low;
+ _high = high;
+ return true;
+}
+
+off_t Cursor::decrByByte( off_t n )
+{
+ // check for underflow
+ if (n > _byteOffset)
+ return OutOfRange;
+ else
+ _byteOffset -= n;
+ return _byteOffset;
+}
+off_t Cursor::decrByChar( off_t n )
+{
+ off_t byteDelta = n/_charsPerByte;
+ off_t charDelta = n%_charsPerByte;
+
+ if ( charDelta > _charOffset ) {
+ if( byteDelta == MAX_OFFSET ) {
+ throw out_of_range("Cursor decriment underflowed.\n");
+ }
+ byteDelta++;
+ }
+ // if underflow.. then just return
+ if( byteDelta && OutOfRange == decrByByte( byteDelta ) ) {
+ return _charOffset;
+ }
+ if ( charDelta > _charOffset ) {
+ // offset == maxidx - abs(_charOffset - charDelta)
+ _charOffset = (_charsPerByte) - (charDelta - _charOffset);
+ } else {
+ _charOffset -= charDelta;
+ }
+ return _charOffset;
+}
+// note: off_t is always positive
+off_t Cursor::incrByChar( off_t n )
+{
+ off_t byteDelta = n/_charsPerByte;
+ off_t charDelta = n%_charsPerByte;
+
+ // carry
+ if ( charDelta + _charOffset >= _charsPerByte ) {
+ // Note: this cannot overflow unless chars perbyte == 1
+ if ( byteDelta == MAX_OFFSET ) {
+ throw out_of_range("Cursor increment exceeded maximum offset.\n");
+ }
+ byteDelta++;
+ }
+ // if out of range, just leave the char offset where it is
+ if( byteDelta && OutOfRange == incrByByte( byteDelta ) ) {
+ return _charOffset;
+ }
+ // limit _charOffset to _charsPerByte - 1
+ _charOffset = (charDelta + _charOffset)%_charsPerByte;
+ return _charOffset;
+}
+
+off_t Cursor::incrByByte( off_t byteDelta )
+{
+ if ( byteDelta > MAX_OFFSET - _byteOffset ) {
+ throw out_of_range("Cursor increment exceeded maximum offset.\n");
+ }
+ if ( _byteOffset + byteDelta >= _high )
+ return OutOfRange;
+ return (_byteOffset += byteDelta);
+}
+
+//
+// accessor implimentations
+//
+off_t Cursor::byteOffset() const
+{
+ return _byteOffset;
+}
+off_t Cursor::charOffset() const
+{
+ return _charOffset;
+}
+#define MIN(a,b) (a < b)?a:b
+off_t Cursor::setCharsPerByte( off_t charsPerByte )
+{
+ _charsPerByte = charsPerByte;
+ _charOffset = MIN(_charOffset,charsPerByte-1);
+ return _charsPerByte;
+}
+// _byteOffset values are clamped to:
+// [_low,_high)
+// _charOffset values are clamped to:
+// [0,_charsPerByte-1]
+void Cursor::setOffset( off_t byteOffset, off_t charOffset )
+{
+ assignClamped(_byteOffset,byteOffset,0,_high);
+ assignClamped(_charOffset,charOffset,0,_charsPerByte);
+}
+off_t Cursor::charOffsetAbsolute() const
+{
+ return _byteOffset*_charsPerByte + _charOffset;
+}
+//
+// void Cursor::assignClamped(dst,src, low,high);
+// convienience function for assigning dst = src
+// clamped to [low,high)
+//
+void Cursor::assignClamped(off_t& dst, off_t src, off_t low, off_t high)
+{
+ if( src < low ) {
+ dst = low;
+ } else if( src >= high ) {
+ dst = high-1;
+ } else {
+ dst = src;
+ }
+}
diff --git a/src/cursor.hpp b/src/cursor.hpp
new file mode 100755
index 0000000..6b09a24
--- /dev/null
+++ b/src/cursor.hpp
@@ -0,0 +1,71 @@
+/* $Id: cursor.hpp,v 1.4 2006-11-05 04:42:43 ganzhorn Exp $
+ * This file is part of lfhex.
+ * Copyright (C) 2006 Salem Ganzhorn <eyekode@yahoo.com>
+ *
+ * This program 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 version 2.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _CURSOR_HPP_
+#define _CURSOR_HPP_
+
+#include <sys/types.h>
+#include <limits.h>
+#include <stdexcept>
+
+#ifdef _LARGEFILE_SOURCE
+#define MAX_OFFSET LONG_LONG_MAX
+#else
+#define MAX_OFFSET LONG_MAX
+#endif
+
+class Cursor {
+public:
+ Cursor( off_t byteOffset = 0,
+ off_t charOffset = 0,
+ off_t low = 0,
+ off_t high = 1,
+ off_t charsPerByte = 2 ); // defaults to hex
+ Cursor( const Cursor& c);
+
+ off_t incrByChar( off_t n );
+ off_t incrByByte( off_t n );
+ off_t decrByChar( off_t n );
+ off_t decrByByte( off_t n );
+
+ off_t byteOffset() const; //returns the current byte offset
+ off_t charOffset() const; //returns the current char offset. (relative)
+ off_t charOffsetAbsolute() const; //returns the current absolute offset.
+
+ bool setRange( off_t low, off_t high );
+ // setCharsPerByte:
+ // sideEffect: sets charOffset to min(_charsPerByte-1,_charOffset)
+ off_t setCharsPerByte( off_t charsPerByte );
+ void setOffset( off_t byteOffset, off_t charOffset );
+
+protected:
+ // performs: dst = src; and clamps the value to [low,high)
+ void assignClamped(off_t& dst,off_t src,off_t low,off_t high);
+
+ enum {
+ OutOfRange = -1,
+ };
+protected:
+ off_t _byteOffset;
+ off_t _charOffset;
+ off_t _low;
+ off_t _high;
+ off_t _charsPerByte;
+};
+
+#endif
diff --git a/src/delta.cpp b/src/delta.cpp
new file mode 100755
index 0000000..de8ed3f
--- /dev/null
+++ b/src/delta.cpp
@@ -0,0 +1,126 @@
+/* $Id: delta.cpp,v 1.4 2006-11-05 04:42:43 ganzhorn Exp $
+ * This file is part of lfhex.
+ * Copyright (C) 2006 Salem Ganzhorn <eyekode@yahoo.com>
+ *
+ * This program 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 version 2.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "delta.hpp"
+
+//
+// DeltaMap class implimentation:
+//
+
+DeltaMap::DeltaMap() {} // noop
+DeltaMap::~DeltaMap()
+{
+ // just free all of the Delta's
+ clear();
+}
+
+// Free all the Delta's
+// Note: this invalidates all pointers to Delta's returned through search()
+// do NOT keep returned pointers arround for long.
+//
+void DeltaMap::clear()
+{
+ _map.erase(_map.begin(),_map.end());
+
+ // note: the union of _undo and _redo should contain ALL of the Delta's
+ // in the map. The intersection of _undo and _redo should be the empty set.
+ while ( !_undo.empty() ) {
+ delete _undo.top();
+ _undo.pop();
+ }
+ while ( !_redo.empty() ) {
+ delete _redo.top();
+ _redo.pop();
+ }
+}
+
+// returns const ptr to the most recent delta on offset off_t
+const Delta * DeltaMap::search( off_t offset ) const
+{
+ delta_map_t::const_iterator itr = _map.find(offset);
+ if ( itr != _map.end() && (itr->second).size() )
+ return itr->second.back();
+ else
+ return 0;
+}
+
+size_t DeltaMap::insert( off_t offset,
+ const vector<uchar>& oldData,
+ const vector<uchar>& newData )
+{
+ //
+ // only modify the newData of the top undo iff the offsets match
+ // and the redo stack is empty.
+ //
+ if( _undo.size() && _undo.top()->offset() == offset && _redo.empty() ) {
+ //just modify the newData of the top delta
+ _undo.top()->setNewData( newData );
+
+ // _map[offset] _should_ exist
+ return _map[offset].size();
+ } else {
+ // create a new delta
+ Delta * tmp = new Delta(offset, oldData, newData);
+ _map[offset].push_back( tmp );
+ _undo.push( tmp );
+ return _map[offset].size();
+ }
+}
+
+bool DeltaMap::undo()
+{
+ if( _undo.empty() )
+ return false;
+
+ Delta* d = _undo.top();
+ _undo.pop();
+ // find the delta in the delta list indexed by d->offset and remove it.
+ map<off_t,list<Delta*> >::iterator itr = _map.find(d->offset());
+ itr->second.remove(d);
+ // remove the entry iff the list is empty
+ if( itr->second.empty() ) {
+ _map.erase(itr);
+ }
+ // push the delta back onto the redo stack.
+ _redo.push( d );
+ return true;
+}
+
+bool DeltaMap::redo()
+{
+ if( _redo.empty() )
+ return false;
+
+ // insert the delta back into the modification list
+ Delta *d = _redo.top();
+ _redo.pop();
+ _map[d->offset()].push_back( d );
+ _undo.push( d );
+ return true;
+}
+
+// methods for iterating over all the modifications in the tree
+off_t DeltaMap::lower_bound(off_t lb) const
+{
+ delta_map_t::const_iterator itr = _map.lower_bound(lb);
+ if( itr == _map.end() ) {
+ return -1;
+ } else {
+ return itr->first;
+ }
+}
diff --git a/src/delta.hpp b/src/delta.hpp
new file mode 100755
index 0000000..1c7d3e2
--- /dev/null
+++ b/src/delta.hpp
@@ -0,0 +1,93 @@
+/* $Id: delta.hpp,v 1.5 2006-11-05 04:42:43 ganzhorn Exp $
+ * This file is part of lfhex.
+ * Copyright (C) 2006 Salem Ganzhorn <eyekode@yahoo.com>
+ *
+ * This program 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 version 2.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _DELTA_MAP_
+#define _DELTA_MAP_
+
+#include <sys/types.h>
+#include <list>
+#include <map>
+#include <vector>
+#include <stack>
+
+#include <iostream>
+
+#include "local.h"
+
+class Delta {
+public:
+ Delta( off_t i, const vector<uchar>& oldData, const vector<uchar>& newData) :
+ _offset(i), _old(oldData), _new(newData) {}
+
+ void setNewData( const vector<uchar>& ndata ) { _new = ndata; }
+
+ off_t offset() const { return _offset; }
+ const vector<uchar>& newData() const { return _new;}
+ const vector<uchar>& oldData() const { return _old;}
+protected:
+ off_t _offset;
+ vector<uchar> _old;
+ vector<uchar> _new;
+};
+
+
+// allocation for all delta's is dynamic, but it is all handled
+// within the class.
+// the user of the class does not need to worry about memory
+// allocation/deallocation.
+class DeltaMap {
+public:
+ DeltaMap();
+ ~DeltaMap();
+
+public:
+ // insert a new delta
+ size_t insert(off_t offset,
+ const vector<uchar>& oldData,
+ const vector<uchar>& newData);
+ // return the offset of the last inserted Delta.
+ off_t lastOffset() const;
+ // set the last delta's newData to data
+ void setLastData( const vector<uchar>& data);
+ int numEdits() const { return _undo.size(); }
+ // find the most recent delta
+ const Delta* search(off_t offset) const;
+
+ // cleans undo/redo stacks and frees memory for all deltas.
+ // Makes references to delta's invalid.
+ void clear();
+
+ bool undo(); //undo last insert
+ bool redo(); //redo last insert
+
+ // method for iterating over all of the modifications
+ // finds the first offset that is is not less than lb
+ // so lower_bound(0) returns the offset of the first delta
+ // (off_t) -1 is returned on failure
+ off_t lower_bound(off_t lb) const;
+
+protected:
+ typedef map<off_t,list<Delta*> > delta_map_t;
+ // notes:
+ // the back of the delta list is always the most recent/non undone delta.
+ map<off_t,list<Delta*> > _map;
+ stack<Delta*> _undo;
+ stack<Delta*> _redo;
+};
+
+#endif
diff --git a/src/driver.cpp b/src/driver.cpp
new file mode 100644
index 0000000..da72bf5
--- /dev/null
+++ b/src/driver.cpp
@@ -0,0 +1,100 @@
+/* $Id: driver.cpp,v 1.9 2008-09-11 01:49:00 salem Exp $
+ * This file is part of lfhex.
+ * Copyright (C) 2006 Salem Ganzhorn <eyekode@yahoo.com>
+ *
+ * This program 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 version 2.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <qapplication.h>
+#include <stdexcept>
+#include <unistd.h>
+
+extern "C" {
+ int optind;
+};
+#include "hexGui.hpp"
+#include "local.h"
+#include "compareDlg.hpp"
+
+#define STUB(x) extern "C" { void x() {}}
+STUB(glXCreateGLXPixmapMESA);
+STUB(glXReleaseBuffersMESA);
+
+// this is used for debugging because I cannot seem to figure out how to see
+// the asci representation of a QString while in the debugger.
+#include <iostream>
+void coutAsciText( const QString& str )
+{
+ cout << &str << " -> \"" << C_STR(str) << "\"" << endl;
+}
+
+int main (int argc, char ** argv)
+{
+ QApplication a(argc,argv);
+ a.setStyle( "plastique" );
+ // parse the command line and see what major mode we should be in
+ int compare = false;
+ int c;
+ // skip argv[0]
+ optind = 1;
+ while( EOF != (c = getopt(argc,argv,"c")) ) {
+ switch (c) {
+ case 'c':
+ compare = true;
+ break;
+ default:
+ cerr << "usage: " PROGRAM " [-c [file1 file2]] files..." <<endl;
+ exit(1);
+ break;
+ }
+ }
+ if( compare ) {
+ int nopts = argc - optind;
+ // check to see if files were passed in
+ if( nopts >= 2 ) {
+ (new CompareDlg(argv[optind],argv[optind+1]))->show();
+ optind+=2;
+ } else {
+ (new CompareDlg())->show();
+ }
+ // treat remaining cmdline options as files to be opened.
+ while( optind < argc ) {
+ HexGui *hg = new HexGui();
+ hg->open(argv[optind++]);
+ hg->show();
+ }
+ } else {
+ // each remaining argument is assumed to be a file
+ if( optind >= argc ) {
+ // no files, just open a hexGui
+ (new HexGui())->show();
+ } else {
+ while( optind < argc ) {
+ HexGui *hg = new HexGui();
+ hg->open(argv[optind++]);
+ hg->show();
+ }
+ }
+ }
+
+ a.connect( &a, SIGNAL(lastWindowClosed()), &a, SLOT(quit()) );
+ int ret=0;
+ try {
+ ret = a.exec();
+ } catch (const exception& e) {
+ ret = 1;
+ cerr << "[error] - unhandled exeption in main:\"" << e.what() << "\"" <<endl;
+ }
+ return ret;
+}
diff --git a/src/expr.h b/src/expr.h
new file mode 100644
index 0000000..e90f4f5
--- /dev/null
+++ b/src/expr.h
@@ -0,0 +1,27 @@
+#ifndef EXPR_H
+#define EXPR_H
+/* $Id: expr.h,v 1.2 2006-11-05 04:42:43 ganzhorn Exp $
+ * This file is part of lfhex.
+ * Copyright (C) 2006 Salem Ganzhorn <eyekode@yahoo.com>
+ *
+ * This program 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 version 2.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <string>
+
+bool expr_eval( const std::string &str, off_t &value );
+
+#define YYSTYPE off_t
+
+#endif
diff --git a/src/expr.l b/src/expr.l
new file mode 100644
index 0000000..aa6f538
--- /dev/null
+++ b/src/expr.l
@@ -0,0 +1,154 @@
+%{
+/* $Id: expr.l,v 1.4 2006-11-05 04:42:43 ganzhorn Exp $
+ * This file is part of lfhex.
+ * Copyright (C) 2006 Salem Ganzhorn <eyekode@yahoo.com>
+ *
+ * This program 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 version 2.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#include <math.h>
+
+#include <string>
+#include <stdexcept>
+#include <iostream>
+
+using namespace std;
+
+#include "expr.h"
+#include "expr_yacc.h"
+
+int exprparse();
+
+extern off_t expr_value;
+
+static off_t hex2l( const string &str );
+
+#define yylval exprlval
+
+%}
+
+%option noyywrap
+
+hexnum [0-9a-fA-F]+
+
+%%
+
+[1-9][0-9]* {
+ yylval = atol(yytext);
+ return NUMBER;
+ }
+{hexnum} |
+0x{hexnum} {
+ string hexnum = yytext;
+ if( hexnum.substr(0,2) == "0x" ) {
+ hexnum = hexnum.substr(2);
+ }
+ yylval = hex2l(hexnum);
+ return NUMBER;
+ }
+[-+*()] { return yytext[0]; }
+[ \r\n\t] {/*nop*/}
+. { return yytext[0]; }
+
+%%
+
+static off_t
+hex2l(
+ const string &str
+ )
+{
+ //
+ off_t ret = 0;
+ size_t scale = 1;
+ int i = str.size()-1;
+ while( i > -1 ) {
+ switch( str[i] ) {
+ case '0':
+ break;
+ case '1':
+ ret += 1*scale;
+ break;
+ case '2':
+ ret += 2*scale;
+ break;
+ case '3':
+ ret += 3*scale;
+ break;
+ case '4':
+ ret += 4*scale;
+ break;
+ case '5':
+ ret += 5*scale;
+ break;
+ case '6':
+ ret += 6*scale;
+ break;
+ case '7':
+ ret += 7*scale;
+ break;
+ case '8':
+ ret += 8*scale;
+ break;
+ case '9':
+ ret += 9*scale;
+ break;
+ case 'a':
+ case 'A':
+ ret += 10*scale;
+ break;
+ case 'b':
+ case 'B':
+ ret += 11*scale;
+ break;
+ case 'c':
+ case 'C':
+ ret += 12*scale;
+ break;
+ case 'd':
+ case 'D':
+ ret += 13*scale;
+ break;
+ case 'e':
+ case 'E':
+ ret += 14*scale;
+ break;
+ case 'f':
+ case 'F':
+ ret += 15*scale;
+ break;
+ default:
+ char buf[1024];
+ sprintf(buf,"Unknown hex char: \"%s\"[%d]",str.c_str(),i);
+ throw runtime_error(buf);
+ }
+ --i;
+ scale *= 16;
+ }
+ return ret;
+}
+
+bool
+expr_eval(
+ const string &str,
+ off_t &retval
+ )
+{
+// exprrestart(NULL);
+ expr_scan_string(str.c_str());
+ expr_value = 0;
+ bool status = !exprparse();
+ retval = expr_value;
+ return status;
+}
+
+
diff --git a/src/expr.y b/src/expr.y
new file mode 100644
index 0000000..285ea8d
--- /dev/null
+++ b/src/expr.y
@@ -0,0 +1,61 @@
+%{
+/* $Id: expr.y,v 1.2 2006-11-05 04:42:43 ganzhorn Exp $
+ * This file is part of lfhex.
+ * Copyright (C) 2006 Salem Ganzhorn <eyekode@yahoo.com>
+ *
+ * This program 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 version 2.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#include <iostream>
+
+#include <math.h>
+
+#include "expr.h"
+
+using namespace std;
+
+off_t expr_value;
+
+int exprlex();
+
+static int exprerror( const char * );
+
+%}
+
+%token NUMBER
+%left '-' '+' '*' '/'
+
+%%
+target : expr {
+ expr_value = $1;
+}
+;
+
+expr: /* nothing */
+| NUMBER { $$ = $1; }
+| expr '+' expr { $$ = $1 + $3; }
+| expr '-' expr { $$ = $1 - $3; }
+| expr '*' expr { $$ = $1 * $3; }
+| '(' expr ')' { $$ = $2; }
+;
+
+
+%%
+
+static int
+exprerror(
+ const char * str
+ )
+{
+ return 0;
+}
diff --git a/src/grid.cpp b/src/grid.cpp
new file mode 100644
index 0000000..3f0dad8
--- /dev/null
+++ b/src/grid.cpp
@@ -0,0 +1,42 @@
+/* $Id: grid.cpp,v 1.1 2006-11-05 04:42:43 ganzhorn Exp $
+ * This file is part of lfhex.
+ * Copyright (C) 2006 Salem Ganzhorn <eyekode@yahoo.com>
+ *
+ * This program 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 version 2.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "grid.hpp"
+#include <QGridLayout>
+#include <QChildEvent>
+
+grid::grid( int cols, QWidget* parent )
+ : QWidget(parent), m_cols(cols), m_row(0), m_col(0)
+{
+
+ setLayout( new QGridLayout(this) );
+}
+
+void grid::childEvent( QChildEvent* e )
+{
+ if( e->added() && e->child()->isWidgetType() ) {
+ QWidget* w = dynamic_cast<QWidget*>(e->child());
+ QGridLayout* l = dynamic_cast<QGridLayout*>(layout());
+ l->addWidget(w,m_row,m_col);
+ ++m_col;
+ if( m_col >= m_cols ) {
+ m_col = 0;
+ ++m_row;
+ }
+ }
+}
diff --git a/src/grid.hpp b/src/grid.hpp
new file mode 100644
index 0000000..d7cc89a
--- /dev/null
+++ b/src/grid.hpp
@@ -0,0 +1,35 @@
+#ifndef LFHEX_GRID_HPP
+#define LFHEX_GRID_HPP
+/* $Id: grid.hpp,v 1.1 2006-11-05 04:42:43 ganzhorn Exp $
+ * This file is part of lfhex.
+ * Copyright (C) 2006 Salem Ganzhorn <eyekode@yahoo.com>
+ *
+ * This program 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 version 2.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#include <QWidget>
+
+class grid : public QWidget {
+public:
+ grid( int cols, QWidget* parent );
+
+protected:
+ void childEvent( QChildEvent *e );
+
+protected:
+ int m_cols;
+ int m_row;
+ int m_col;
+};
+
+#endif
diff --git a/src/hexEditor.cpp b/src/hexEditor.cpp
new file mode 100755
index 0000000..48cfe8b
--- /dev/null
+++ b/src/hexEditor.cpp
@@ -0,0 +1,1112 @@
+/* $Id: hexEditor.cpp,v 1.14 2006-11-05 04:42:43 ganzhorn Exp $
+ * This file is part of lfhex.
+ * Copyright (C) 2006 Salem Ganzhorn <eyekode@yahoo.com>
+ *
+ * This program 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 version 2.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <math.h>
+#include <assert.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <ctype.h>
+#include <algorithm>
+#include <iostream>
+
+#include <QApplication>
+#include <QMessageBox>
+#include <QFileDialog>
+#include <QProgressDialog>
+#include <QPainter>
+#include <QPixmap>
+#include <QFocusEvent>
+#include <QPaintEvent>
+#include <QKeyEvent>
+#include <QResizeEvent>
+#include <QMouseEvent>
+
+#include "hexEditor.hpp"
+#include "translate.hpp"
+#include "local.h"
+
+extern int errno;
+
+HexEditor::HexEditor( QWidget * parent )
+ : QWidget(parent)
+{
+ _cols = 5;
+ _rows = 10;
+ _charsPerByte = 2;
+ _base = 16;
+ _topLeft = 0;
+ _topMargin = _wordSpacing = 6;
+ _bytesPerWord = 1;
+ _lastValidWord = -1;
+ _selection[SelectionStart] = _selection[SelectionEnd] = -1;
+
+ setFocusPolicy(Qt::StrongFocus);
+ // the first setBytesPerWord should not come before the first setFont()
+ QFont font("fixed");
+ font.setFixedPitch(1);
+ setFont( font );
+ setBackgroundRole( QPalette::Base );
+}
+
+HexEditor::~HexEditor()
+{
+ _reader.close();
+}
+
+bool HexEditor::isModified() const
+{
+ return ( _reader.is_open() && _delta.numEdits() );
+}
+
+bool HexEditor::save( QString filename )
+{
+ if( !isModified() ) {
+ QString errMsg = "Error, file is not open or has not been modified. "
+ "Aborting save.";
+ QMessageBox::warning(this,PROGRAM_STRING,errMsg);
+ return false;
+ }
+
+ if( filename != "" ) {
+ // copy open reader file to filename
+ QString oldFilename = _reader.filename();
+
+ if( oldFilename == "" )
+ return false;
+
+ _reader.close();
+ FILE* fin = fopen(C_STR(oldFilename),"r");
+ if( !fin ) {
+ QString errMsg = "Error opening \"" + oldFilename + "\" for reading: " +
+ strerror(errno);
+ QMessageBox::warning(this,PROGRAM_STRING,errMsg);
+ return false;
+ }
+ FILE* fout = fopen(C_STR(filename),"w");
+ if( !fout ) {
+ QString errMsg = "Error opening \"" + filename+ "\" for writing: " +
+ strerror(errno);
+ QMessageBox::warning(this,PROGRAM_STRING,errMsg);
+ fclose(fin);
+ return false;
+ }
+ int length;
+ uchar bytes[4096];
+ while( (length = fread(bytes,1,4096,fin)) ) {
+ fwrite( bytes, 1, length, fout );
+ }
+ fclose(fin);
+ fclose(fout);
+ } else {
+ filename = _reader.filename();
+ _reader.close();
+ }
+
+ if( filename == "" )
+ return false;
+
+ if( !_delta.numEdits() )
+ return false;
+
+ if( !writeDeltas(C_STR(filename),_delta) ) {
+ _reader.open(C_STR(filename));
+ return false;
+ }
+ _delta.clear();
+ _reader.open(C_STR(filename));
+ setTopLeft(_topLeft);
+ return true;
+}
+
+QString HexEditor::filename() const
+{
+ return _reader.filename();
+}
+
+bool HexEditor::open( const QString & filename )
+{
+ if( closeFile() == QMessageBox::Cancel )
+ return false;
+
+ if(!_reader.open(C_STR(filename))) {
+ QMessageBox::critical( this, "HexEdit",
+ "Error loading \"" + filename + "\"\n" +
+ _reader.lastError(),
+ QMessageBox::Ok,0);
+ return false;
+ }
+ _delta.clear(); // reset modification tree
+
+ // set the new range for the scrollbar
+ _cursor.setRange(0,_reader.size());
+ _cursor.setCharsPerByte(_charsPerByte);
+ setSelection(SelectionStart,-1);
+ setSelection(SelectionEnd,-1);
+ emit rangeChanged(0,_reader.size()/bytesPerLine());
+ calculateFontMetrics(); // update labels
+ setTopLeft(0); // reset the GUI
+ return true;
+}
+
+int HexEditor::closeFile(bool force)
+{
+ int retval = QMessageBox::No;
+ if( _delta.numEdits() ) {
+ QString message =
+ "Save changes to \"" + QString(_reader.filename()) + "\"?";
+ if( force ) {
+ retval = QMessageBox::warning( this,
+ PROGRAM_STRING,
+ message,
+ QMessageBox::Yes,
+ QMessageBox::No );
+ } else {
+ retval = QMessageBox::warning( this,
+ PROGRAM_STRING,
+ message,
+ QMessageBox::Yes,
+ QMessageBox::No,
+ QMessageBox::Cancel);
+ }
+ }
+ if( retval == QMessageBox::Yes )
+ save();
+ return retval;
+}
+
+void HexEditor::setBytesPerWord( int nbytes )
+{
+ _bytesPerWord = nbytes;
+ calculateFontMetrics();
+ QResizeEvent *re = new QResizeEvent(QSize(size()),QSize(size()));
+ resizeEvent(re);
+ delete re;
+}
+int HexEditor::fontHeight() const
+{
+ return _fontHeight;
+}
+int HexEditor::lineSpacing() const
+{
+ return _lineSpacing;
+}
+int HexEditor::fontMaxWidth() const
+{
+ return _fontMaxWidth;
+}
+void HexEditor::calculateFontMetrics()
+{
+ _lineSpacing = fontMetrics().lineSpacing();
+ _fontMaxWidth = fontMetrics().maxWidth();
+ _wordWidth = _fontMaxWidth*charsPerWord();
+ _fontHeight = fontMetrics().height();
+ // see how many bytes are needed to show the size of this file
+ // log base 16 -> log16(x) = log(x)/log(16)
+ if( _reader.size() ) {
+ double width = log(static_cast<float>(_reader.size()))/log(16.0)+2;
+ _offsetLabelBytes = static_cast<int>( width );
+ } else {
+ _offsetLabelBytes = 0;
+ }
+ _leftMargin = _topMargin + _fontMaxWidth*(_offsetLabelBytes + 2);
+ // make sure bboxes are updated with new offset subdivision
+ QResizeEvent *re = new QResizeEvent(QSize(size()),QSize(size()));
+ resizeEvent(re);
+ delete re;
+}
+void HexEditor::setFont(const QFont& font )
+{
+ if( !font.fixedPitch() ) {
+ cerr << "setFont() failed, font was not fixedPitch()." << endl;
+ return;
+ }
+ QWidget::setFont(font);
+ calculateFontMetrics();
+}
+// set the top left editor to offset in reader
+void HexEditor::setTopLeft( off_t offset )
+{
+ static bool inTopLeft;
+ if( inTopLeft ) {
+ // don't nest
+ return;
+ }
+ inTopLeft = true;
+ try {
+ if( offset < 0 ) {
+ _topLeft = 0;
+ } else if( offset > _reader.size() ) {
+ _topLeft = _reader.size();
+ } else {
+ _topLeft = offset;
+ }
+ // only let _topLeft be an integer multiple of the line length (round down)
+ _topLeft = (_topLeft/bytesPerLine()) * bytesPerLine();
+ // update the labels
+ // setOffsetLabels(_topLeft);
+
+ const Delta * delta;
+
+ _reader.seek(_topLeft);
+ _reader.read(_data,bytesPerPage());
+
+ // update data from delta map
+ for( offset = _delta.lower_bound(_topLeft);
+ (offset != -1) && (offset < _topLeft + bytesPerPage());
+ offset = _delta.lower_bound(offset) ) {
+ delta = _delta.search(offset);
+ _data[offset++-_topLeft] = delta->newData()[0];
+ }
+
+ repaint();
+ emit topLeftChanged(_topLeft);
+ } catch( const exception &e ) {
+ inTopLeft = false;
+ throw e;
+ }
+ inTopLeft = false;
+}
+
+//void HexEditor::setOffsetLabels( off_t topLeft )
+//{
+ // need to impliment manually printing labels
+//}
+
+int HexEditor::topMargin() const
+{
+ return _topMargin;
+}
+int HexEditor::leftMargin() const
+{
+ return _leftMargin;
+}
+//
+// access fn's for offset manip
+//
+int HexEditor::bytesPerPage() const
+{
+ return _rows*_cols*bytesPerWord();
+}
+int HexEditor::bytesPerWord() const
+{
+ return _bytesPerWord;
+}
+int HexEditor::bytesPerLine() const
+{
+ return bytesPerWord()*wordsPerLine();
+}
+int HexEditor::wordsPerLine() const
+{
+ return _cols;
+}
+int HexEditor::linesPerPage() const
+{
+ return _rows;
+}
+int HexEditor::wordsPerPage() const
+{
+ return _rows*_cols;
+}
+int HexEditor::charsPerByte() const
+{
+ return _charsPerByte;
+}
+int HexEditor::charsPerWord() const
+{
+ return _charsPerByte*bytesPerWord();
+}
+int HexEditor::charsPerLine() const
+{
+ return _charsPerByte*(bytesPerLine());
+}
+// translate local byte offsets to global byte offsets
+off_t HexEditor::globalOffset( off_t local ) const
+{
+ return local+_topLeft;
+}
+// translate global byte offsets to viewport byte offsets
+off_t HexEditor::localOffset( off_t global ) const
+{
+ return global-_topLeft;
+}
+
+int HexEditor::offsetToPercent(
+ off_t offset
+ )
+{
+ // round up
+ return _reader.size() ? (int)ceil(100.0*offset/_reader.size()) : 0;
+}
+
+// public slots:
+bool HexEditor::browseLoadFile()
+{
+ QString filename = QFileDialog::getOpenFileName();
+ if( filename.isNull() )
+ return false;
+ return open(filename);
+}
+
+QRect HexEditor::charBBox( off_t charIdx ) const {
+ // byteIdx = charIdx/charsPerByte
+ // wordIdx = byteIdx/bytesPerWord
+ int wordIdx = (charIdx/charsPerByte())/bytesPerWord();
+ int localCharIdx = charIdx % charsPerWord();
+ return QRect( _wordBBox[wordIdx].left() + localCharIdx*fontMaxWidth() +
+ wordSpacing()/2,
+ _wordBBox[wordIdx].top(),
+ fontMaxWidth(),
+ fontHeight() );
+}
+
+QRect HexEditor::byteBBox( off_t byteIdx ) const {
+ // wordIdx = byteIdx/bytesPerWord
+ int wordIdx = byteIdx/bytesPerWord();
+ int localByteIdx = byteIdx % bytesPerWord();
+ return QRect( _wordBBox[wordIdx].left() + localByteIdx*2*fontMaxWidth() +
+ wordSpacing()/2,
+ _wordBBox[wordIdx].top(),
+ fontMaxWidth()*2,
+ lineSpacing() );
+}
+
+void HexEditor::setTopLeftToPercent( int percent )
+{
+ setTopLeft( (_reader.size()/100)*percent );
+}
+
+//
+// slot for setting cursor offset.
+//
+void HexEditor::setOffset( off_t offset )
+{
+ off_t oldWordOffset = localWordOffset();
+ _cursor.setOffset( offset, 0 );
+ // updateWord clamps the wordIdx to [0,_rows*_cols)
+ updateWord( oldWordOffset );
+ emit offsetChanged( _cursor.byteOffset() );
+}
+
+void HexEditor::nextLine()
+{
+ setTopLeft(_topLeft+bytesPerLine());
+}
+void HexEditor::prevLine()
+{
+ setTopLeft(_topLeft-bytesPerLine());
+}
+void HexEditor::nextPage()
+{
+ setTopLeft(_topLeft+bytesPerPage());
+}
+void HexEditor::prevPage()
+{
+ setTopLeft(_topLeft-bytesPerPage());
+}
+
+off_t HexEditor::localByteOffsetAtXY(off_t x, off_t y)
+{
+ off_t wordIdx;
+ off_t wordLength = wordSpacing()+wordWidth();
+ off_t line = min(y/lineSpacing(),(off_t)linesPerPage());
+
+ // constrain x to be less than the right side of the last char on a line
+ x = max( (off_t)0, x - leftMargin());
+ x = min(wordsPerLine()*wordLength - 1 ,x);
+ // constrain y to be > topMargin() and less than bottom of last line
+ y = max( (off_t)0, y - topMargin());
+ line = min(y/lineSpacing(), (off_t)linesPerPage()-1);
+ wordIdx = line*wordsPerLine() + x/wordLength;
+
+ off_t byteOffsetInWord = (x%wordLength)*bytesPerWord()/wordLength;
+ // = wordIdx*bytesPerWord + byteOffsetInWord
+ return min( (off_t) bytesPerPage()-1,
+ wordIdx*bytesPerWord() + byteOffsetInWord);
+
+}
+//
+// event handler implimentation:
+//
+void HexEditor::setCursorFromXY(int x,int y)
+{
+ off_t oldWordIdx = localWordOffset();
+
+ _cursor.setOffset( _topLeft+localByteOffsetAtXY(x,y) ,0 );
+
+ // update where the cursor used to be, and where it is now
+ if( oldWordIdx != localWordOffset() ) {
+ updateWord( oldWordIdx );
+ }
+ updateWord( localWordOffset() );
+ emit offsetChanged(_cursor.byteOffset());
+}
+
+void HexEditor::mousePressEvent( QMouseEvent* e )
+{
+ setCursorFromXY(e->x(),e->y());
+
+ off_t byte_offset = localByteOffset();
+ QRect bbox = byteBBox(byte_offset);
+ if( e->x() > bbox.right() ) {
+ byte_offset++;
+ }
+ setSelection( SelectionStart, globalOffset( byte_offset ));
+}
+
+void HexEditor::mouseMoveEvent( QMouseEvent* e )
+{
+ setCursorFromXY(e->x(),e->y());
+
+ off_t byte_offset = localByteOffset();
+ QRect bbox = byteBBox(byte_offset);
+ if(e->x() > bbox.right() ) {
+ byte_offset++;
+ }
+
+ setSelection( SelectionEnd, globalOffset( byte_offset ));
+}
+
+void HexEditor::mouseReleaseEvent( QMouseEvent* e )
+{
+ setCursorFromXY(e->x(),e->y());
+
+ off_t byte_offset = localByteOffset();
+ QRect bbox = byteBBox(byte_offset);
+ if(e->x() > bbox.right() ) {
+ byte_offset++;
+ }
+
+ setSelection( SelectionEnd, globalOffset( byte_offset ));
+}
+
+off_t HexEditor::selectionStart() const
+{
+ if( _selection[SelectionStart] == -1 || _selection[SelectionEnd] == -1 )
+ return -1;
+ return min(_selection[SelectionStart],_selection[SelectionEnd]);
+}
+// note: end is open. range is: [start,end)
+
+off_t HexEditor::selectionEnd() const
+{
+ if( _selection[SelectionStart] == -1 || _selection[SelectionEnd] == -1 )
+ return -1;
+ return max(_selection[SelectionStart],_selection[SelectionEnd]);
+}
+
+void HexEditor::setSelection(SelectionPos_e pos, off_t offset)
+{
+ if( !_reader.is_open() ) {
+ return;
+ }
+ if( pos == SelectionStart ) {
+ _selection[SelectionEnd] = -1;
+ }
+ _selection[pos] = offset;
+
+ if( _selection[SelectionStart] < 0 ) {
+ emit selectionChanged("");
+ } else {
+ if( selectionEnd() > -1 && selectionEnd() <= _reader.size() ) {
+ QString data;
+ const Delta* delta;
+ for(off_t i = selectionStart();
+ i < selectionEnd();
+ ++i) {
+ if( (delta = _delta.search(i)) )
+ data += Translate::ByteToHex(delta->newData()[0]);
+ else
+ data += Translate::ByteToHex(_reader[i]);
+ }
+ emit selectionChanged( data );
+ } else {
+ emit selectionChanged( "" );
+ }
+ }
+
+ repaint();
+}
+
+//
+// Editor implimentation
+//
+void HexEditor::keyPressEvent( QKeyEvent *e )
+{
+ int key = e->key();
+
+ switch(_base) {
+ case -1:
+ // ascii
+ // range is taken from qnamespace.h
+ if( key >= Qt::Key_Space && key <= Qt::Key_AsciiTilde ) {
+ seeCursor();
+ vector<uchar> oldData;
+ vector<uchar> newData;
+ vector<uchar> chars;
+
+ oldData.push_back( *(_data.begin()+localByteOffset()) );
+ Translate::ByteToChar(chars,oldData);
+ chars[0] = key;
+ Translate::CharToByte(newData,chars);
+ _delta.insert( _cursor.byteOffset(),
+ oldData,
+ newData);
+ _data[_cursor.byteOffset()-_topLeft] = newData[0];
+ cursorRight();
+ setSelection(SelectionStart,-1);
+ return;
+ }
+ break;
+ case 16:
+ if ( key >= 'A' && key <= 'F' ) {
+ key = tolower(key);
+ }
+ if ( (key >= 'a' && key <= 'f') ||
+ (key >= '0' && key <= '9') ) {
+ //
+ // make sure we can see where the cursor is
+ //
+ seeCursor();
+ vector<uchar> oldData;
+ vector<uchar> newData;
+ vector<uchar> hex;
+
+ oldData.push_back( *(_data.begin()+localByteOffset()) );
+ Translate::ByteToHex(hex,oldData);
+ hex[_cursor.charOffset()] = key;
+ Translate::HexToByte(newData,hex);
+
+ _delta.insert( _cursor.byteOffset(),
+ oldData,
+ newData );
+ _data[_cursor.byteOffset()-_topLeft] = newData[0];
+ // move to the next char
+ cursorRight();
+ setSelection(SelectionStart,-1);
+ return;
+ }
+ break;
+ case 8:
+ if( key >= '0' && key < '8' ) {
+ // valid octal key
+ seeCursor();
+ vector<uchar> oldData;
+ vector<uchar> newData;
+ vector<uchar> octal;
+
+ oldData.push_back( *(_data.begin()+localByteOffset()) );
+ Translate::ByteToOctal(octal,oldData);
+ octal[_cursor.charOffset()] = key;
+ Translate::OctalToByte(newData,octal);
+
+ _delta.insert( _cursor.byteOffset(),
+ oldData,
+ newData );
+ _data[_cursor.byteOffset()-_topLeft] = newData[0];
+ cursorRight();
+ setSelection(SelectionStart,-1);
+ return;
+ }
+ break;
+ case 2:
+ if( key >= '0' && key < '2' ) {
+ // valid binary key
+ seeCursor();
+ vector<uchar> oldData;
+ vector<uchar> newData;
+ vector<uchar> binary;
+
+ oldData.push_back( *(_data.begin()+localByteOffset()) );
+ Translate::ByteToBinary(binary,oldData);
+ binary[_cursor.charOffset()] = key;
+ Translate::BinaryToByte(newData,binary);
+
+ _delta.insert( _cursor.byteOffset(),
+ oldData,
+ newData );
+ _data[_cursor.byteOffset()-_topLeft] = newData[0];
+ cursorRight();
+ setSelection(SelectionStart,-1);
+ return;
+ }
+ break;
+ }
+ switch ( e->key() ) {
+ case Qt::Key_Left:
+ cursorLeft();
+ break;
+ case Qt::Key_Right:
+ cursorRight();
+ break;
+ case Qt::Key_Up:
+ cursorUp();
+ break;
+ case Qt::Key_Down:
+ cursorDown();
+ break;
+ case Qt::Key_PageUp:
+ prevPage();
+ break;
+ case Qt::Key_PageDown:
+ nextPage();
+ break;
+ case Qt::Key_End:
+ setTopLeft( _reader.size() - bytesPerPage()/2 );
+ break;
+ case Qt::Key_Home:
+ setTopLeft(0);
+ break;
+ default:
+ e->ignore();
+ break;
+ }
+}
+
+void HexEditor::resizeEvent( QResizeEvent * e )
+{
+ int height= lineSpacing();
+ int totalWordWidth = wordWidth() + wordSpacing();
+ int linewidth = e->size().width();
+
+ // don't let _rows or _cols drop below 1
+ _rows = max(1,(e->size().height() - _topMargin)/height);
+ _cols = max(1,(e->size().width() - _leftMargin)/totalWordWidth);
+
+ // now update the line && word bbox vectors
+ _lineBBox.reserve(_rows);
+ _wordBBox.reserve(_rows*_cols);
+ int top,left;
+ for(int r = 0; r < _rows; r++) {
+ top = r*height + _topMargin;
+ for(int c = 0; c < _cols; c++) {
+ left = totalWordWidth*c + _leftMargin;
+ _wordBBox[r*_cols+c] = QRect(left, //left
+ top, //top
+ totalWordWidth, //width
+ height); //height
+ }
+ _lineBBox[r] = QRect(_leftMargin,top,linewidth,height);
+ }
+ // calculate offset label bounding box
+ _labelBBox.setRect(0, // x
+ 0, // y
+ _leftMargin, // width
+ e->size().height()); // height
+
+ // do this to recalculate the amount of displayed data.
+ setTopLeft(_topLeft);
+ emit rangeChanged(0,_reader.size()/bytesPerLine());
+}
+//
+// Reimplimented to be more efficient then repainting the whole screen on
+// focus events.
+//
+void HexEditor::focusInEvent( QFocusEvent* )
+{
+ updateWord( localWordOffset() );
+}
+void HexEditor::focusOutEvent( QFocusEvent* )
+{
+ updateWord( localWordOffset() );
+}
+// generate's paint events for wordIdx (global wordIdx)
+// is safe to call with any wordIdx
+void HexEditor::updateWord( off_t wordIdx )
+{
+ if( wordIdx > -1 && wordIdx < _rows*_cols )
+ repaint(_wordBBox[wordIdx]);
+}
+
+void HexEditor::paintLabels( QPainter* paintPtr)
+{
+ // ignore redraw range for first aproximation:
+ int y = _wordBBox[0].bottom();
+ unsigned int i;
+ off_t offset = _topLeft;
+ uchar *ucptr;
+ QString label;
+
+ for(int row = 0; row < _rows;++row) {
+ label = "";
+#ifdef WORDS_BIGENDIAN
+ for(i=0, ucptr = (uchar*)&offset; i<sizeof(off_t);++i) {
+ label += Translate::ByteToHex(*ucptr++);
+ }
+#else
+ // make sure we write offset labels in big-endian (easier to read)
+ ucptr = (uchar*)(&offset) + sizeof(off_t)-1;
+ for(i=0;i<sizeof(off_t);++i) {
+ label += Translate::ByteToHex(*ucptr--);
+ }
+#endif
+ label = label.mid(sizeof(off_t)*2-_offsetLabelBytes);
+ paintPtr->drawText( 5, y, label );
+ offset+=bytesPerLine();
+ y+=lineSpacing();
+ }
+ // draw dividing line between offset labels and data
+ int x = leftMargin()-fontMaxWidth();
+ paintPtr->drawLine(x,topMargin(),
+ x,height()-topMargin());
+}
+//
+// painting optimizations, each time resize is called, it calculates
+// the bounding boxes for each word and each line.
+// This data can then be retrieved with wordBBox()
+// We can then test intersections to see which words need to be redrawn
+//
+void HexEditor::paintEvent( QPaintEvent* e)
+{
+/* QPixmap pixmap(this->width(),this->height());
+ pixmap.fill(backgroundRole());*/
+ QPainter paint( this );//&pixmap);
+
+ // set up painter;/
+ paint.setFont(font());
+ const QPalette& p = qApp->palette();
+ paint.setBrush(p.background());
+
+ if( _labelBBox.intersects(e->rect()) ) {
+ paintLabels(&paint);
+ }
+
+ QString text;
+ if( !getDisplayText(text) ) {
+ cerr << "[error] - internal inconsitency. Please file bug report."
+ << endl;
+ return;
+ }
+
+ // both cursor and selection is drawn underneath the text
+ drawCursor( paint );
+ drawSelection( paint );
+
+ // Find the stop/start row/col idx's for the repaint
+ int totalWordWidth = wordWidth()+wordSpacing();
+ int row_start = max(0,(e->rect().top()-topMargin())/lineSpacing() );
+ int col_start = max(0,(e->rect().left()-leftMargin())/totalWordWidth);
+ int row_stop = min(_rows-1,e->rect().bottom() / lineSpacing());
+ int col_stop = min(_cols-1,e->rect().right() / totalWordWidth);
+
+ // draw text in repaint event
+ drawTextRegion( paint, text, row_start, row_stop, col_start, col_stop );
+}
+
+bool HexEditor::getDisplayText( QString& text )
+{
+ // get data to draw
+ switch (_base) {
+ case 16:
+ Translate::ByteToHex(text,_data);
+ break;
+ case 8:
+ Translate::ByteToOctal(text,_data);
+ break;
+ case 2:
+ Translate::ByteToBinary(text,_data);
+ break;
+ case -1:
+ Translate::ByteToChar(text,_data);
+ break;
+ default:
+ // error state
+ return false;
+ }
+ return true;
+}
+
+bool HexEditor::wordModified ( off_t wordIdx ) const
+{
+ off_t lboffset = wordIdx*bytesPerWord()+_topLeft;
+ off_t nearest_offset = _delta.lower_bound(lboffset);
+ return ( nearest_offset != -1 && nearest_offset < lboffset+bytesPerWord() );
+}
+
+//
+// accessors for local offsets
+//
+off_t HexEditor::localByteOffset() const
+{
+ return _cursor.byteOffset() - _topLeft;
+}
+off_t HexEditor::localWordOffset() const
+{
+ return localByteOffset()/bytesPerWord();
+}
+// in offset relative to _data[0]
+off_t HexEditor::localCharOffset() const
+{
+ return localByteOffset()*charsPerByte() + _cursor.charOffset();
+}
+off_t HexEditor::localLineOffset() const
+{
+ return localWordOffset()/wordsPerLine();
+}
+int HexEditor::wordWidth() const
+{
+ return _fontMaxWidth*charsPerWord();
+}
+int HexEditor::wordSpacing() const
+{
+ return _wordSpacing;
+}
+//
+// cursor movement members
+//
+void HexEditor::seeCursor()
+{
+ // see if it is already visible
+ if ( _cursor.byteOffset() >= _topLeft &&
+ _cursor.byteOffset() <= _topLeft+bytesPerPage()-1 ) {
+ updateWord( localWordOffset() );
+ return;
+ } else {
+ // setTopLeft so cursor is in middle line of screen
+ setTopLeft( max(_cursor.byteOffset() - bytesPerPage()/2, (off_t)0) );
+ }
+}
+
+void HexEditor::cursorLeft()
+{
+ off_t oldWordIdx = localWordOffset();
+ // move the cursor
+ _cursor.decrByChar(1);
+ // make sure the user can see the cursor
+ seeCursor();
+ // redraw where the cursor used to be
+ if( localWordOffset() != oldWordIdx )
+ updateWord( oldWordIdx );
+ emit offsetChanged( _cursor.byteOffset() );
+}
+void HexEditor::cursorRight()
+{
+ off_t oldWordIdx = localWordOffset();
+ _cursor.incrByChar(1);
+ seeCursor();
+ if( localWordOffset() != oldWordIdx )
+ updateWord( oldWordIdx );
+ emit offsetChanged( _cursor.byteOffset() );
+}
+void HexEditor::cursorUp()
+{
+ off_t oldWordIdx = localWordOffset();
+ _cursor.decrByByte( bytesPerLine() );
+ seeCursor();
+ if( localWordOffset() != oldWordIdx )
+ updateWord( oldWordIdx );
+ emit offsetChanged( _cursor.byteOffset() );
+}
+void HexEditor::cursorDown()
+{
+ off_t oldWordIdx = localWordOffset();
+ _cursor.incrByByte( bytesPerLine() );
+ seeCursor();
+ if( localWordOffset() != oldWordIdx )
+ updateWord( oldWordIdx );
+ emit offsetChanged( _cursor.byteOffset() );
+}
+
+// slots for undo/redo.
+// note: it is necessary to reset topLeft to force a reread of the data.
+//
+void HexEditor::redo()
+{
+ _delta.redo();
+ setTopLeft(_topLeft);
+ off_t start = selectionStart();
+ off_t end = selectionEnd();
+ setSelection(SelectionStart,start);
+ setSelection(SelectionEnd,end);
+}
+
+void HexEditor::undo()
+{
+ _delta.undo();
+ setTopLeft(_topLeft);
+ off_t start = selectionStart();
+ off_t end = selectionEnd();
+ setSelection(SelectionStart,start);
+ setSelection(SelectionEnd,end);
+}
+
+void HexEditor::search( const QString& hexText, bool forwards )
+{
+ QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) );
+ if( !hexText.length() || _reader.filename() == "" )
+ return;
+
+ if( -1 != _delta.lower_bound(0) ) {
+ QMessageBox::information(this,PROGRAM_STRING,
+ "Cannot search file with unsaved modifications.");
+ return;
+ }
+
+ vector<uchar> data;
+ Translate::HexToByte(data,hexText);
+// QProgressDialog progress( "Searching...","Cancel", 0,
+// _reader.size(),this );
+// progress.setWindowModality( Qt::WindowModal );
+// progress.setWindowTitle(PROGRAM_STRING);
+// progress.setValue(0);
+ off_t pos;
+ if( forwards ) {
+ pos = _reader.findIndex(_cursor.byteOffset(),data,_reader.size()-1);
+ } else {
+ pos = _reader.rFindIndex(_cursor.byteOffset(),data,0);
+ }
+ if( pos < _reader.size() ) {
+ showMatch(pos,data.size());
+ setOffset( forwards?selectionEnd():selectionStart()-1 );
+ seeCursor();
+ } else {
+ QMessageBox::information(this,PROGRAM_STRING,
+ "Could not find search data 0x" + hexText);
+ }
+ QApplication::restoreOverrideCursor();
+}
+void HexEditor::setBaseASCII() {
+ setBase(-1);
+}
+void HexEditor::setBaseHex()
+{
+ setBase(16);
+}
+void HexEditor::setBaseOctal()
+{
+ setBase(8);
+}
+void HexEditor::setBaseBinary()
+{
+ setBase(2);
+}
+void HexEditor::setBase(int base)
+{
+ switch(base) {
+ case -1:
+ // setup ascii editing mode
+ _charsPerByte = 1;
+ break;
+ case 2:
+ // setup binary editing mode
+ _charsPerByte = 8;
+ break;
+ case 8:
+ // setup octal editing mode
+ _charsPerByte = 3;
+ break;
+ case 16:
+ // setup hex editing mode
+ _charsPerByte = 2;
+ break;
+ default:
+ // just ignore unsupported bases for now
+ return;
+ }
+ _base = base;
+ _cursor.setCharsPerByte(_charsPerByte);
+ // refresh the display
+ // note: cannot call resize() because it will ignore resize events
+ // if the size has not changed.
+ QResizeEvent *re = new QResizeEvent(QSize(size()),QSize(size()));
+ resizeEvent(re);
+ delete re;
+ // make sure we can still see the cursor
+ // switching from a larger base to a smaller base has the
+ // possibility of pushing the cursor off the screen
+ seeCursor();
+}
+
+off_t HexEditor::offset() const
+{
+ return _cursor.byteOffset();
+}
+
+Reader * HexEditor::reader()
+{
+ return &_reader;
+}
+
+void HexEditor::showMatch( off_t pos, int len )
+{
+ setSelection( SelectionStart, pos );
+ setSelection( SelectionEnd, pos + len );
+}
+
+void HexEditor::drawTextRegion( QPainter& paint, const QString& text,
+ int row_start, int row_stop,
+ int col_start, int col_stop )
+{
+ paint.setPen(qApp->palette().foreground().color());
+ for(int r = row_start; r <= row_stop; r++) {
+ for(int c = col_start; c <= col_stop; c++) {
+ int widx = r*_cols+c;
+ if ( wordModified( widx ) ) {
+ paint.setPen(qApp->palette().link().color());
+ paint.drawText( _wordBBox[widx].left() + wordSpacing()/2,
+ _wordBBox[widx].bottom(),
+ text.mid(widx*charsPerWord(),charsPerWord()) );
+ paint.setPen(qApp->palette().foreground().color());
+ } else {
+ paint.drawText( _wordBBox[widx].left() + wordSpacing()/2,
+ _wordBBox[widx].bottom(),
+ text.mid(widx*charsPerWord(),charsPerWord()) );
+ }
+ }
+ }
+}
+
+void HexEditor::drawSelection( QPainter& paint )
+{
+ // draw selection
+ off_t start = max( (off_t)0, selectionStart() - _topLeft);
+ if( start < bytesPerPage() ) {
+ off_t stop = min(selectionEnd() - _topLeft, (off_t)bytesPerPage());
+ paint.setPen(Qt::NoPen);
+ paint.setBrush( qApp->palette().highlight() );
+ // foreach line with selection
+ stop--;
+ while( start <= stop ) {
+ // linestop = min(stop,endofline)
+ off_t linestop =
+ min(stop, start+bytesPerLine()-1 -(start % bytesPerLine()));
+ QRect bbox = byteBBox(start);
+ bbox.setRight( byteBBox(linestop).right() );
+ paint.drawRect( bbox );
+ start = linestop+1;
+ }
+ }
+}
+
+void HexEditor::drawCursor( QPainter& paint )
+{
+ QBrush b = qApp->palette().mid();
+ if( localWordOffset() > -1 && localWordOffset() < wordsPerPage() ) {
+ if( hasFocus() ) {
+ // draw a solid cursor
+ paint.setPen(Qt::NoPen);
+ paint.setBrush(b);
+ } else {
+ // just draw the outline
+ paint.setPen(b.color());
+ paint.setBrush(Qt::NoBrush);
+ }
+ QRect box = charBBox( localCharOffset() );
+ paint.drawRect( box );
+ }
+}
diff --git a/src/hexEditor.hpp b/src/hexEditor.hpp
new file mode 100755
index 0000000..be96952
--- /dev/null
+++ b/src/hexEditor.hpp
@@ -0,0 +1,242 @@
+/* $Id: hexEditor.hpp,v 1.7 2006-11-05 04:42:43 ganzhorn Exp $
+ * This file is part of lfhex.
+ * Copyright (C) 2006 Salem Ganzhorn <eyekode@yahoo.com>
+ *
+ * This program 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 version 2.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#ifndef _HEX_EDITOR_
+#define _HEX_EDITOR_
+
+#include <QMouseEvent>
+#include <QFocusEvent>
+#include <QResizeEvent>
+#include <QKeyEvent>
+#include <QPaintEvent>
+#include <QWidget>
+
+// STL headers
+#include <vector>
+
+// System headers
+#include <sys/types.h>
+
+// Local headers
+#include "local.h"
+#include "reader.hpp"
+#include "delta.hpp"
+#include "cursor.hpp"
+#include "save.hpp"
+
+class HexEditor : public QWidget {
+ Q_OBJECT
+public:
+ HexEditor( QWidget * parent =0 );
+ ~HexEditor();
+
+ // note: closeFile returns QMessageBox::{Yes,No,Cancel}
+ int closeFile(bool force = false );
+ bool open(const QString& filename);
+ // becomes "save as" if filename != ""
+ bool save(QString filename = "");
+ bool isModified() const;
+ QString filename() const;
+ Reader * reader();
+ off_t offset() const;
+
+
+ // returns the word (string representation) that the cursor is in
+ // QString currentWord() const;
+ //
+ // cursor movement related fn's
+ //
+ void seeCursor();
+ void cursorLeft();
+ void cursorRight();
+ void cursorUp();
+ void cursorDown();
+ int wordWidth() const;
+ int wordSpacing() const;
+ void setCursorFromXY(int x,int y);
+
+public:
+ enum SelectionPos_e {
+ SelectionStart,
+ SelectionEnd,
+ };
+ void setSelection(SelectionPos_e pos,off_t byte_offset);
+ off_t selectionStart() const;
+ off_t selectionEnd() const;
+ // get the char offset from topleft of the point (x,y)
+ // Note: this wont work for large files, off_t is 2*size() at eof for hex
+ //off_t charOffsetAtXY( off_t x, off_t y );
+ int offsetToPercent( off_t offset );
+
+ off_t localByteOffsetAtXY( off_t x, off_t y );
+protected:
+ // accessors for local offset's
+ // note: returned offset's are not necessarily visible
+ off_t localByteOffset() const;
+ off_t localWordOffset() const;
+ off_t localCharOffset() const;
+ off_t localLineOffset() const;
+
+signals:
+ // attach to know when line ranges change (for a scrollbar)
+ void rangeChanged(off_t low, off_t high);
+ void offsetChanged(off_t byte);
+ void topLeftChanged(off_t offset);
+ void selectionChanged(const QString& selection);
+
+public slots:
+ bool browseLoadFile();
+ void setOffset(off_t offset); // sets cursor offset
+ void setTopLeftToPercent( int percent ); // for setting pos from scroll
+ //
+ // slots for setting the number of bytes per column
+ // I really should change all references of "bytesPerWord" to "bytesPerCol"
+ // sorry for the confusion -Salem
+ //
+ void setBytesPerWord( int i );
+ void set1BPC() { setBytesPerWord(1); };
+ void set2BPC() { setBytesPerWord(2); };
+ void set4BPC() { setBytesPerWord(4); };
+ void set8BPC() { setBytesPerWord(8); };
+ void nextLine();
+ void prevLine();
+ void nextPage();
+ void prevPage();
+ void setFont(const QFont& font);
+ void undo();
+ void redo();
+ void search(const QString& hexText, bool forwards);
+ void setBase(int base); // only 2 8 16 acceptableO
+ void setBaseHex();
+ void setBaseOctal();
+ void setBaseBinary();
+ void setBaseASCII();
+
+protected:
+ // void setOffsetLabels( off_t topLeft );
+ void setTopLeft( off_t offset );
+
+protected:
+ bool wordModified( off_t widx ) const;
+ // template setWord so I can call it with different types of string data
+ template <class _vectType>
+ void setWord( off_t wordIdx, const _vectType& str );
+ // calculate the rectangle which bounds the word at _offset+idx
+ QRect charBBox( off_t charIdx ) const;
+ QRect byteBBox( off_t byteIdx ) const;
+
+ // translate widget coord to word index
+ int pointToWord(const QPoint& pt);
+ QChar& pointToChar(const QPoint& pt);
+ // inlined access fn's
+protected:
+ void calculateFontMetrics();
+ int charsPerByte() const;
+ int charsPerWord() const;
+ int charsPerLine() const;
+ int bytesPerPage() const;
+ int bytesPerWord() const;
+ int bytesPerLine() const;
+ int wordsPerLine() const;
+ int wordsPerPage() const;
+ int linesPerPage() const;
+
+ int lineSpacing() const;
+ int fontHeight() const;
+ int fontMaxWidth() const;
+ int topMargin() const;
+ int leftMargin() const;
+
+ // translate local offset to global offset
+ off_t globalOffset( off_t local ) const;
+ // translate global offset to local offset.
+ // Note: globalOffset may not exist in local viewport.
+ off_t localOffset ( off_t global) const;
+
+protected:
+ void showMatch( off_t pos, int len );
+ // drawing utilities
+protected:
+ bool getDisplayText( QString& text );
+ void drawCursor( QPainter& p );
+ void drawSelection( QPainter& p );
+ void drawTextRegion( QPainter& p, const QString& text,
+ int row_start, int row_end,
+ int col_start, int col_end );
+ // event handlers
+protected:
+ void resizeEvent ( QResizeEvent *e );
+ // generates update() events for the bbox for the word given byh wordIdx
+ // note: this is range safe, no need to do range checking before passing in
+ void updateWord ( off_t wordIdx );
+ void paintEvent ( QPaintEvent*e );
+ void paintLabels ( QPainter*painter);
+ void focusInEvent ( QFocusEvent*e );
+ void focusOutEvent ( QFocusEvent*e );
+ void keyPressEvent ( QKeyEvent *e );
+ void mousePressEvent ( QMouseEvent * e );
+ void mouseReleaseEvent( QMouseEvent *e );
+ void mouseMoveEvent ( QMouseEvent *e );
+
+protected:
+ Reader _reader;
+
+ int _wordSpacing;
+ int _wordWidth;
+ int _lineSpacing;
+ int _fontHeight;
+ int _bytesPerWord;
+ int _charsPerByte;
+ off_t _topLeft;
+
+ //
+ // current screen data info
+ //
+ vector<uchar> _data;
+ int _base; // either 2 8 or 16
+
+ off_t _lastValidWord;
+
+ // data used to optimize drawing.
+ vector<QRect> _lineBBox;
+ vector<QRect> _wordBBox;
+ QRect _labelBBox;
+
+ int _linspacing;
+ int _fontMaxWidth;
+
+ int _topMargin,_leftMargin;
+ int _offsetLabelBytes;
+
+ int _cols;
+ int _rows;
+ int _width;
+ Cursor _cursor;
+
+ //
+ // when refering to the offset of a word, I always mean the offset of the
+ // first byte of the word
+ //
+
+ // this class keeps track of modifications
+ DeltaMap _delta;
+
+ // selection:
+ off_t _selection[2];
+};
+
+#endif
diff --git a/src/hexGui.cpp b/src/hexGui.cpp
new file mode 100644
index 0000000..a2cb65e
--- /dev/null
+++ b/src/hexGui.cpp
@@ -0,0 +1,326 @@
+/* $Id: hexGui.cpp,v 1.13 2006-11-05 04:42:43 ganzhorn Exp $
+ * This file is part of lfhex.
+ * Copyright (C) 2006 Salem Ganzhorn <eyekode@yahoo.com>
+ *
+ * This program 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 version 2.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <QFileDialog>
+#include <qsizepolicy.h>
+#include <qstatusbar.h>
+#include <qmenubar.h>
+#include <qapplication.h>
+#include <qscrollbar.h>
+#include <qstring.h>
+#include <qmessagebox.h>
+#include <qlineedit.h>
+#include <QDockWidget>
+#include <QLabel>
+#include <QCloseEvent>
+#include <QPushButton>
+
+#include "hexGui.hpp"
+#include "box.hpp"
+#include "expr.h"
+
+HexGui::HexGui (QWidget * p)
+ : QMainWindow(p)
+{
+ QWidget* h = new QWidget(this);
+ QHBoxLayout* l = new QHBoxLayout(h);
+
+ hexEditor = new HexEditor(h);
+ hexEditor->setSizePolicy( QSizePolicy( QSizePolicy::Expanding,
+ QSizePolicy::Expanding ) );
+ l->addWidget(hexEditor);
+ vsb = new QScrollBar(h);
+ l->addWidget(vsb);
+ vsb->setRange(0,0);
+
+ setCentralWidget(h);
+
+ connect( hexEditor,SIGNAL(rangeChanged(off_t,off_t)),
+ this,SLOT(setScrollBarRange(off_t,off_t)) );
+ connect( vsb, SIGNAL(valueChanged(int)),
+ hexEditor,SLOT(setTopLeftToPercent(int)) );
+ connect( hexEditor, SIGNAL(topLeftChanged(off_t)),
+ this, SLOT(setScrollBarValue(off_t)) );
+ connect( hexEditor, SIGNAL(offsetChanged(off_t)),
+ this, SLOT(setOffsetLabel(off_t)) );
+
+ // setup dock
+ QDockWidget* dock = new QDockWidget("Conversions Assistant",this);
+ vbox* vb = new vbox(dock);
+ conversionDlg = new ConversionDlg(vb);
+ connect(conversionDlg,SIGNAL(nextPressed()),this,SLOT(searchForwards()));
+ connect(conversionDlg,SIGNAL(prevPressed()),this,SLOT(searchBackwards()));
+
+ dock->setWidget(vb);
+ dock->hide();
+ connect(hexEditor,SIGNAL(selectionChanged(const QString &)),
+ conversionDlg, SLOT(valueChanged(const QString&)) );
+ addDockWidget( Qt::RightDockWidgetArea, dock );
+ dock->setFloating(true);
+
+ // setup menu:
+ fileMenu = new QMenu("&File",this);
+ fileMenu->addAction("&Open...",this,SLOT(browseLoadFile()));
+ fileMenu->addAction("&Open in new editor...",this,
+ SLOT(browseLoadFileNew()));
+ fileMenu->addSeparator();
+ actions[SaveAction] = fileMenu->addAction("&Save",this,SLOT(save()));
+ actions[SaveAsAction] = fileMenu->addAction("Save &As...",this,
+ SLOT(saveAs()));
+ // only include close functions in menu if this is a toplevel window
+ if( isTopLevel() ) {
+ fileMenu->addSeparator();
+ if( isTopLevel() )
+ fileMenu->addAction("Close Editor",this,SLOT(close()));
+ else
+ fileMenu->addAction("Close File",this,SLOT(closeFile()));
+ fileMenu->addAction("&Exit Application",qApp, SLOT(quit()));
+ }
+ menuBar()->addMenu( fileMenu );
+
+ // edit pulldown
+ editMenu = new QMenu( "&Edit", this );
+ actions[UndoAction] = editMenu->addAction("&Undo",hexEditor,SLOT(undo()));
+ actions[RedoAction] = editMenu->addAction("&Redo",hexEditor,SLOT(redo()));
+ menuBar()->addMenu( editMenu );
+
+ // view menu
+ viewMenu = new QMenu("&View",this);
+ QAction* dockAction = dock->toggleViewAction();
+ viewMenu->addAction( dockAction );
+
+ // menu for selecting editing base (octal/binary/hex)
+ QMenu * baseMenu = new QMenu("&Editing base", this);
+ baseMenu->addAction("&Hex",hexEditor,SLOT(setBaseHex()));
+ baseMenu->addAction("&ASCII",hexEditor,SLOT(setBaseASCII()));
+ baseMenu->addAction("&Binary",hexEditor,SLOT(setBaseBinary()));
+ baseMenu->addAction("&Octal",hexEditor,SLOT(setBaseOctal()));
+ viewMenu->addMenu(baseMenu);
+ // menu for selecting bytes per column
+ QMenu * nbytesMenu = new QMenu("&Bytes per column",this);
+ nbytesMenu->addAction("&1",hexEditor,SLOT(set1BPC()));
+ nbytesMenu->addAction("&2",hexEditor,SLOT(set2BPC()));
+ nbytesMenu->addAction("&4",hexEditor,SLOT(set4BPC()));
+ nbytesMenu->addAction("&8",hexEditor,SLOT(set8BPC()));
+ viewMenu->addMenu(nbytesMenu);
+ menuBar()->addMenu(viewMenu);
+
+ resize(400,196);
+ statusBar()->showMessage("Ready",2000);
+ statusBar()->addWidget(new QLabel("Cursor Offset:",statusBar()));
+ offsetLineEdit = new QLineEdit(statusBar());
+// offsetLineEdit->setValidator( new HexValidator(offsetLineEdit) );
+ connect(offsetLineEdit,SIGNAL(returnPressed()),
+ SLOT(setOffsetFromStatusBar()));
+ statusBar()->addWidget(offsetLineEdit);
+ // progressBar = new QProgressBar(statusBar());
+ // statusBar()->addWidget(progressBar,1,FALSE);
+ statusLabel = new QLabel("",statusBar());
+ statusBar()->addWidget(statusLabel,1);
+ statusBar()->setSizeGripEnabled( !parent() );
+ setWindowTitle(PROGRAM_STRING);
+
+ // deactivate save,saveas undo and redo
+ actions[SaveAction]->setEnabled(false);
+ actions[SaveAsAction]->setEnabled(false);
+ actions[UndoAction]->setEnabled(false);
+ actions[RedoAction]->setEnabled(false);
+}
+
+HexGui::~HexGui()
+{
+}
+
+bool HexGui::open(const char * filename)
+{
+ if (hexEditor->open(filename)) {
+ if( isTopLevel() )
+ setWindowTitle(filename);
+ else
+ statusLabel->setText(filename);
+ actions[SaveAction]->setEnabled(true);
+ actions[SaveAsAction]->setEnabled(true);
+ actions[UndoAction]->setEnabled(true);
+ actions[RedoAction]->setEnabled(true);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+void HexGui::gotoOffset(off_t offset)
+{
+ hexEditor->setOffset(offset);
+ hexEditor->seeCursor();
+ emit offsetChanged(offset);
+}
+
+bool HexGui::browseLoadFile()
+{
+ QString filename = QFileDialog::getOpenFileName();
+ if( filename.isNull() )
+ return false;
+ return open( C_STR(filename) );
+}
+bool HexGui::browseLoadFileNew()
+{
+ QString filename = QFileDialog::getOpenFileName();
+ if( filename.isNull() )
+ return false;
+ HexGui * hg = new HexGui();
+ bool retval = hg->open( C_STR(filename) );
+ hg->show();
+ return retval;
+}
+
+bool HexGui::save()
+{
+ statusBar()->showMessage("saveing " + hexEditor->filename()) ;
+ bool retval = hexEditor->save();
+ statusBar()->showMessage("done.",2000);
+ return retval;
+}
+
+bool HexGui::saveAs()
+{
+ QString filename = QFileDialog::getSaveFileName();
+ if( filename.isNull() )
+ return false;
+ statusBar()->showMessage("saveing to \"" + filename + "\"...");
+ bool retval = hexEditor->save(filename);
+ statusBar()->showMessage("done.",2000);
+ setWindowTitle(filename);
+ return retval;
+}
+
+int HexGui::closeFile()
+{
+ return closeFile( false );
+}
+int HexGui::closeFile( bool force )
+{
+ return hexEditor->closeFile(force);
+}
+
+void HexGui::closeEvent( QCloseEvent * ce )
+{
+ if( hexEditor->closeFile() == QMessageBox::Cancel )
+ ce->ignore();
+ else
+ ce->accept();
+}
+
+void HexGui::setScrollBarRange(off_t low, off_t high)
+{
+ (void)low;(void)high;
+ // range must be contained in the space of an integer, just do 100
+ // increments
+ vsb->setRange(0,100);
+}
+void HexGui::setScrollBarValue(off_t pos)
+{
+ // pos is the topLeft pos, set the scrollbar to the
+ // location of the last byte on the page
+ // Note: offsetToPercent now rounds up, so we don't
+ // have to worry about if this is the topLeft or bottom right
+ vsb->setValue(hexEditor->offsetToPercent(pos));
+}
+void HexGui::setOffsetLabel(off_t pos)
+{
+ QString label;
+ char buffer[64];
+#if _LARGEFILE_SOURCE
+ sprintf(buffer,"0x%lx",pos);
+#else
+ sprintf(buffer,"0x%x",pos);
+#endif
+ label = buffer;
+ offsetLineEdit->setText(label);
+}
+
+const QString& HexGui::filename(void) const
+{
+ static QString value = "";
+ if(!hexEditor)
+ return (value="");
+ return (value=hexEditor->filename());
+}
+
+void HexGui::setOffsetFromStatusBar()
+{
+ // remove leading "0x" if necessary
+ off_t o;
+ if( !expr_eval( C_STR(offsetLineEdit->text()),o ) || o < 0 ) {
+ QApplication::beep();
+ } else {
+ gotoOffset(o);
+ }
+ return;
+ bool ok;
+ off_t offset;
+ QString value = offsetLineEdit->text();
+ if( value.length() > 2 && value[1] == 'x' ) {
+ value = value.mid(2);
+ offset = value.toInt(&ok,16);
+ } else {
+ offset = value.toInt(&ok,10);
+ if( !ok ) {
+ offset = value.toInt(&ok,16);
+ }
+ }
+ if( !ok ) {
+ cerr << "Error converting offset: " << C_STR(offsetLineEdit->text())
+ << endl;
+ } else {
+ gotoOffset(offset);
+ }
+}
+
+off_t HexGui::offset() const
+{
+ return hexEditor->offset();
+}
+
+Reader * HexGui::reader()
+{
+ return hexEditor->reader();
+}
+
+void HexGui::setSelection(off_t start,off_t stop)
+{
+ hexEditor->setSelection(HexEditor::SelectionStart,start);
+ hexEditor->setSelection(HexEditor::SelectionEnd,stop);
+}
+
+void HexGui::search( bool forward )
+{
+ QString hex = conversionDlg->hexValue();
+ if( !hex.isEmpty() ) {
+ hexEditor->search( hex, forward );
+ }
+}
+
+void HexGui::searchForwards()
+{
+ search(true);
+}
+
+void HexGui::searchBackwards()
+{
+ search(false);
+}
diff --git a/src/hexGui.hpp b/src/hexGui.hpp
new file mode 100644
index 0000000..d90a4c5
--- /dev/null
+++ b/src/hexGui.hpp
@@ -0,0 +1,97 @@
+/* $Id: hexGui.hpp,v 1.5 2006-11-05 04:42:43 ganzhorn Exp $
+ * This file is part of lfhex.
+ * Copyright (C) 2006 Salem Ganzhorn <eyekode@yahoo.com>
+ *
+ * This program 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 version 2.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _GUI_HPP_
+#define _GUI_HPP_
+
+#include <QMainWindow>
+#include <QLabel>
+#include <QCloseEvent>
+
+#include "hexEditor.hpp"
+#include "conversionDlg.hpp"
+#include "local.h"
+
+class QScrollBar;
+class QMenu;
+class QString;
+class QLabel;
+//class QProgressBar;
+
+class HexGui : public QMainWindow {
+ Q_OBJECT
+public:
+ HexGui( QWidget * parent = 0 );
+ ~HexGui();
+
+ const QString& filename(void) const;
+ // see through call to isModified in hexEditor
+ bool isModified() const {return hexEditor->isModified();}
+ // public access functions
+ off_t offset() const;
+ Reader * reader();
+
+signals:
+ void offsetChanged(off_t offset);
+
+public slots:
+// sets selection to [start,stop)
+ void setSelection(off_t start, off_t stop);
+ bool browseLoadFile();
+ bool browseLoadFileNew();
+ bool open(const char * filename);
+ void gotoOffset(off_t offset);
+ void setOffsetFromStatusBar(void);
+
+ bool save();
+ bool saveAs();
+ void setScrollBarRange(off_t low, off_t high);
+ void setScrollBarValue(off_t pos);
+ void setOffsetLabel(off_t pos);
+ void closeEvent(QCloseEvent *ce);
+ // had to trivially overload closeFile() == closeFile(false) for Qt slots
+ int closeFile();
+ int closeFile(bool force);
+ void searchForwards();
+ void searchBackwards();
+
+protected:
+ void search( bool forwards );
+
+protected:
+ enum ActionID_e {
+ UndoAction,
+ RedoAction,
+ SaveAction,
+ SaveAsAction,
+ TotalActions
+ };
+
+ QLabel *statusLabel;
+ QLineEdit *offsetLineEdit;
+ // QProgressBar *progressBar;
+ HexEditor *hexEditor;
+ ConversionDlg *conversionDlg;
+ QScrollBar *vsb;
+ QAction* actions[TotalActions];
+ QMenu *fileMenu;
+ QMenu *editMenu;
+ QMenu *viewMenu;
+};
+
+#endif
diff --git a/src/images.qrc b/src/images.qrc
new file mode 100644
index 0000000..6304052
--- /dev/null
+++ b/src/images.qrc
@@ -0,0 +1,9 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+ <file>img/exit.xbm</file>
+ <file>img/first.xbm</file>
+ <file>img/last.xbm</file>
+ <file>img/next.xbm</file>
+ <file>img/prev.xbm</file>
+</qresource>
+</RCC> \ No newline at end of file
diff --git a/src/img/exit.xbm b/src/img/exit.xbm
new file mode 100644
index 0000000..40c6979
--- /dev/null
+++ b/src/img/exit.xbm
@@ -0,0 +1,6 @@
+#define exit_width 16
+#define exit_height 16
+static unsigned char exit_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x38, 0x38, 0x70, 0x3c, 0xc0, 0x1e, 0x80, 0x07,
+ 0xc0, 0x03, 0xe0, 0x06, 0x70, 0x0c, 0x78, 0x1c, 0x3c, 0x1c, 0x3c, 0x18,
+ 0x1c, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/src/img/first.xbm b/src/img/first.xbm
new file mode 100644
index 0000000..081acc8
--- /dev/null
+++ b/src/img/first.xbm
@@ -0,0 +1,6 @@
+#define first_width 16
+#define first_height 16
+static unsigned char first_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x60, 0x60, 0x70, 0x70, 0x78, 0x78,
+ 0x7c, 0x7c, 0x7e, 0x7e, 0x7e, 0x7e, 0x7c, 0x7c, 0x78, 0x78, 0x70, 0x70,
+ 0x60, 0x60, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00};
diff --git a/src/img/last.xbm b/src/img/last.xbm
new file mode 100644
index 0000000..39907a8
--- /dev/null
+++ b/src/img/last.xbm
@@ -0,0 +1,6 @@
+#define last_width 16
+#define last_height 16
+static unsigned char last_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x06, 0x06, 0x0e, 0x0e, 0x1e, 0x1e,
+ 0x3e, 0x3e, 0x7e, 0x7e, 0x7e, 0x7e, 0x3e, 0x3e, 0x1e, 0x1e, 0x0e, 0x0e,
+ 0x06, 0x06, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00};
diff --git a/src/img/next.xbm b/src/img/next.xbm
new file mode 100644
index 0000000..b7b5646
--- /dev/null
+++ b/src/img/next.xbm
@@ -0,0 +1,6 @@
+#define next_width 16
+#define next_height 16
+static unsigned char next_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x60, 0x00, 0xe0, 0x00, 0xe0, 0x01,
+ 0xe0, 0x03, 0xe0, 0x07, 0xe0, 0x07, 0xe0, 0x03, 0xe0, 0x01, 0xe0, 0x00,
+ 0x60, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/src/img/prev.xbm b/src/img/prev.xbm
new file mode 100644
index 0000000..5cb72fc
--- /dev/null
+++ b/src/img/prev.xbm
@@ -0,0 +1,6 @@
+#define prev_width 16
+#define prev_height 16
+static unsigned char prev_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x06, 0x00, 0x07, 0x80, 0x07,
+ 0xc0, 0x07, 0xe0, 0x07, 0xe0, 0x07, 0xc0, 0x07, 0x80, 0x07, 0x00, 0x07,
+ 0x00, 0x06, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00};
diff --git a/src/lfhex b/src/lfhex
new file mode 100755
index 0000000..08cf35b
--- /dev/null
+++ b/src/lfhex
Binary files differ
diff --git a/src/lfhex.pro b/src/lfhex.pro
new file mode 100644
index 0000000..892df3d
--- /dev/null
+++ b/src/lfhex.pro
@@ -0,0 +1,60 @@
+# $Id: lfhex.pro,v 1.2 2008-09-11 01:49:00 salem Exp $
+TARGET = lfhex
+VERSION = 0.42
+TEMPLATE = app
+SOURCES = reader.cpp \
+ save.cpp \
+ translate.cpp \
+ hexEditor.cpp \
+ hexGui.cpp \
+ grid.cpp \
+ compareDlg.cpp \
+ conversionDlg.cpp \
+ cursor.cpp \
+ delta.cpp \
+ offsetConstraint.cpp \
+ driver.cpp
+HEADERS = box.hpp \
+ compareDlg.hpp \
+ conversionDlg.hpp \
+ cursor.hpp \
+ delta.hpp \
+ grid.hpp \
+ hexEditor.hpp \
+ hexGui.hpp \
+ offsetConstraint.hpp \
+ reader.hpp \
+ save.hpp \
+ translate.hpp \
+ expr.h \
+ local.h \
+ mappings.h
+
+# The following defines are used to select large file offsets.
+# If your OS does not support this comment it out.
+DEFINES += _LARGEFILE_SOURCE _FILE_OFFSET_BITS=64
+# If your machine is big endian then uncomment the following, otherwise the
+# offset labels will be in little endian (which some find hard to read).
+# DEFINES += WORDS_BIGENDIAN
+lfhex.path = /usr/local/bin
+lfhex.files = lfhex
+INSTALLS += lfhex
+RESOURCES = images.qrc
+YACCSOURCES += expr.y
+LEXSOURCES += expr.l
+QMAKE_LEX = flex
+QMAKE_YACC = bison
+QMAKE_YACCFLAGS = -d -b expr -p expr
+DISTFILES += ../README \
+ ../README.install \
+ ../COPYING \
+ $$YACCSOURCES \
+ $$LEXSOURCES \
+ img/exit.xbm \
+ img/first.xbm \
+ img/last.xbm \
+ img/next.xbm \
+ img/prev.xbm
+# Uncomment this to compile in debug mode
+# CONFIG += debug
+
diff --git a/src/local.h b/src/local.h
new file mode 100644
index 0000000..fd97c75
--- /dev/null
+++ b/src/local.h
@@ -0,0 +1,30 @@
+#ifndef _LOCAL_H_
+#define _LOCAL_H_
+/* $Id: local.h,v 1.6 2008-09-11 01:49:00 salem Exp $
+ * This file is part of lfhex.
+ * Copyright (C) 2006 Salem Ganzhorn <eyekode@yahoo.com>
+ *
+ * This program 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 version 2.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+typedef unsigned char uchar;
+
+using namespace std;
+
+#define C_STR(x) x.toAscii().constData()
+#define PROGRAM "lfhex"
+#define VERSION "0.42"
+#define PROGRAM_STRING PROGRAM " " VERSION
+
+#endif
diff --git a/src/mappings.h b/src/mappings.h
new file mode 100755
index 0000000..73212b1
--- /dev/null
+++ b/src/mappings.h
@@ -0,0 +1,179 @@
+/* $Id: mappings.h,v 1.3 2006-11-05 04:42:43 ganzhorn Exp $
+ * This file is part of lfhex.
+ * Copyright (C) 2006 Salem Ganzhorn <eyekode@yahoo.com>
+ *
+ * This program 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 version 2.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/* automatically generated mappings from gen*To*Map.pl scripts */
+
+namespace TranslationTables {
+ char * byteToBinaryMap[256] = {
+ "00000000", "00000001", "00000010", "00000011", "00000100", "00000101",
+ "00000110", "00000111", "00001000", "00001001", "00001010", "00001011",
+ "00001100", "00001101", "00001110", "00001111", "00010000", "00010001",
+ "00010010", "00010011", "00010100", "00010101", "00010110", "00010111",
+ "00011000", "00011001", "00011010", "00011011", "00011100", "00011101",
+ "00011110", "00011111", "00100000", "00100001", "00100010", "00100011",
+ "00100100", "00100101", "00100110", "00100111", "00101000", "00101001",
+ "00101010", "00101011", "00101100", "00101101", "00101110", "00101111",
+ "00110000", "00110001", "00110010", "00110011", "00110100", "00110101",
+ "00110110", "00110111", "00111000", "00111001", "00111010", "00111011",
+ "00111100", "00111101", "00111110", "00111111", "01000000", "01000001",
+ "01000010", "01000011", "01000100", "01000101", "01000110", "01000111",
+ "01001000", "01001001", "01001010", "01001011", "01001100", "01001101",
+ "01001110", "01001111", "01010000", "01010001", "01010010", "01010011",
+ "01010100", "01010101", "01010110", "01010111", "01011000", "01011001",
+ "01011010", "01011011", "01011100", "01011101", "01011110", "01011111",
+ "01100000", "01100001", "01100010", "01100011", "01100100", "01100101",
+ "01100110", "01100111", "01101000", "01101001", "01101010", "01101011",
+ "01101100", "01101101", "01101110", "01101111", "01110000", "01110001",
+ "01110010", "01110011", "01110100", "01110101", "01110110", "01110111",
+ "01111000", "01111001", "01111010", "01111011", "01111100", "01111101",
+ "01111110", "01111111", "10000000", "10000001", "10000010", "10000011",
+ "10000100", "10000101", "10000110", "10000111", "10001000", "10001001",
+ "10001010", "10001011", "10001100", "10001101", "10001110", "10001111",
+ "10010000", "10010001", "10010010", "10010011", "10010100", "10010101",
+ "10010110", "10010111", "10011000", "10011001", "10011010", "10011011",
+ "10011100", "10011101", "10011110", "10011111", "10100000", "10100001",
+ "10100010", "10100011", "10100100", "10100101", "10100110", "10100111",
+ "10101000", "10101001", "10101010", "10101011", "10101100", "10101101",
+ "10101110", "10101111", "10110000", "10110001", "10110010", "10110011",
+ "10110100", "10110101", "10110110", "10110111", "10111000", "10111001",
+ "10111010", "10111011", "10111100", "10111101", "10111110", "10111111",
+ "11000000", "11000001", "11000010", "11000011", "11000100", "11000101",
+ "11000110", "11000111", "11001000", "11001001", "11001010", "11001011",
+ "11001100", "11001101", "11001110", "11001111", "11010000", "11010001",
+ "11010010", "11010011", "11010100", "11010101", "11010110", "11010111",
+ "11011000", "11011001", "11011010", "11011011", "11011100", "11011101",
+ "11011110", "11011111", "11100000", "11100001", "11100010", "11100011",
+ "11100100", "11100101", "11100110", "11100111", "11101000", "11101001",
+ "11101010", "11101011", "11101100", "11101101", "11101110", "11101111",
+ "11110000", "11110001", "11110010", "11110011", "11110100", "11110101",
+ "11110110", "11110111", "11111000", "11111001", "11111010", "11111011",
+ "11111100", "11111101", "11111110", "11111111",
+ };
+ char byteToCharMap[256] = {
+ '.','.','.','.','.','.','.','.','.','.',
+ '.','.','.','.','.','.','.','.','.','.',
+ '.','.','.','.','.','.','.','.','.','.',
+ '.','.',' ','!','"','#','.','%','&','\'',
+ '(',')','*','+',',','-','.','/','0','1',
+ '2','3','4','5','6','7','8','9',':',';',
+ '<','=','>','?','@','A','B','C','D','E',
+ 'F','G','H','I','J','K','L','M','N','O',
+ 'P','Q','R','S','T','U','V','W','X','Y',
+ 'Z','[','\\',']','^','_','`','a','b','c',
+ 'd','e','f','g','h','i','j','k','l','m',
+ 'n','o','p','q','r','s','t','u','v','w',
+ 'x','y','z','{','|','}','~','.','.','.',
+ '.','.','.','.','.','.','.','.','.','.',
+ '.','.','.','.','.','.','.','.','.','.',
+ '.','.','.','.','.','.','.','.','.','.',
+ '.','.','.','.','.','.','.','.','.','.',
+ '.','.','.','.','.','.','.','.','.','.',
+ '.','.','.','.','.','.','.','.','.','.',
+ '.','.','.','.','.','.','.','.','.','.',
+ '.','.','.','.','.','.','.','.','.','.',
+ '.','.','.','.','.','.','.','.','.','.',
+ '.','.','.','.','.','.','.','.','.','.',
+ '.','.','.','.','.','.','.','.','.','.',
+ '.','.','.','.','.','.','.','.','.','.',
+ '.','.','.','.','.','.',
+ };
+ char * byteToHexMap[256] = {
+ "00", "01", "02", "03", "04", "05", "06", "07", "08", "09",
+ "0a", "0b", "0c", "0d", "0e", "0f", "10", "11", "12", "13",
+ "14", "15", "16", "17", "18", "19", "1a", "1b", "1c", "1d",
+ "1e", "1f", "20", "21", "22", "23", "24", "25", "26", "27",
+ "28", "29", "2a", "2b", "2c", "2d", "2e", "2f", "30", "31",
+ "32", "33", "34", "35", "36", "37", "38", "39", "3a", "3b",
+ "3c", "3d", "3e", "3f", "40", "41", "42", "43", "44", "45",
+ "46", "47", "48", "49", "4a", "4b", "4c", "4d", "4e", "4f",
+ "50", "51", "52", "53", "54", "55", "56", "57", "58", "59",
+ "5a", "5b", "5c", "5d", "5e", "5f", "60", "61", "62", "63",
+ "64", "65", "66", "67", "68", "69", "6a", "6b", "6c", "6d",
+ "6e", "6f", "70", "71", "72", "73", "74", "75", "76", "77",
+ "78", "79", "7a", "7b", "7c", "7d", "7e", "7f", "80", "81",
+ "82", "83", "84", "85", "86", "87", "88", "89", "8a", "8b",
+ "8c", "8d", "8e", "8f", "90", "91", "92", "93", "94", "95",
+ "96", "97", "98", "99", "9a", "9b", "9c", "9d", "9e", "9f",
+ "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9",
+ "aa", "ab", "ac", "ad", "ae", "af", "b0", "b1", "b2", "b3",
+ "b4", "b5", "b6", "b7", "b8", "b9", "ba", "bb", "bc", "bd",
+ "be", "bf", "c0", "c1", "c2", "c3", "c4", "c5", "c6", "c7",
+ "c8", "c9", "ca", "cb", "cc", "cd", "ce", "cf", "d0", "d1",
+ "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "da", "db",
+ "dc", "dd", "de", "df", "e0", "e1", "e2", "e3", "e4", "e5",
+ "e6", "e7", "e8", "e9", "ea", "eb", "ec", "ed", "ee", "ef",
+ "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9",
+ "fa", "fb", "fc", "fd", "fe", "ff",
+ };
+ char * byteToOctalMap[256] = {
+ "000", "001", "002", "003", "004", "005", "006", "007", "010", "011",
+ "012", "013", "014", "015", "016", "017", "020", "021", "022", "023",
+ "024", "025", "026", "027", "030", "031", "032", "033", "034", "035",
+ "036", "037", "040", "041", "042", "043", "044", "045", "046", "047",
+ "050", "051", "052", "053", "054", "055", "056", "057", "060", "061",
+ "062", "063", "064", "065", "066", "067", "070", "071", "072", "073",
+ "074", "075", "076", "077", "100", "101", "102", "103", "104", "105",
+ "106", "107", "110", "111", "112", "113", "114", "115", "116", "117",
+ "120", "121", "122", "123", "124", "125", "126", "127", "130", "131",
+ "132", "133", "134", "135", "136", "137", "140", "141", "142", "143",
+ "144", "145", "146", "147", "150", "151", "152", "153", "154", "155",
+ "156", "157", "160", "161", "162", "163", "164", "165", "166", "167",
+ "170", "171", "172", "173", "174", "175", "176", "177", "200", "201",
+ "202", "203", "204", "205", "206", "207", "210", "211", "212", "213",
+ "214", "215", "216", "217", "220", "221", "222", "223", "224", "225",
+ "226", "227", "230", "231", "232", "233", "234", "235", "236", "237",
+ "240", "241", "242", "243", "244", "245", "246", "247", "250", "251",
+ "252", "253", "254", "255", "256", "257", "260", "261", "262", "263",
+ "264", "265", "266", "267", "270", "271", "272", "273", "274", "275",
+ "276", "277", "300", "301", "302", "303", "304", "305", "306", "307",
+ "310", "311", "312", "313", "314", "315", "316", "317", "320", "321",
+ "322", "323", "324", "325", "326", "327", "330", "331", "332", "333",
+ "334", "335", "336", "337", "340", "341", "342", "343", "344", "345",
+ "346", "347", "350", "351", "352", "353", "354", "355", "356", "357",
+ "360", "361", "362", "363", "364", "365", "366", "367", "370", "371",
+ "372", "373", "374", "375", "376", "377",
+ };
+ unsigned char hexToByteMap[256] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+ 2, 3, 4, 5, 6, 7, 8, 9, 0, 0,
+ 0, 0, 0, 0, 0, 10, 11, 12, 13, 14,
+ 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 10, 11, 12,
+ 13, 14, 15, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ };
+};
diff --git a/src/offsetConstraint.cpp b/src/offsetConstraint.cpp
new file mode 100644
index 0000000..72c1652
--- /dev/null
+++ b/src/offsetConstraint.cpp
@@ -0,0 +1,98 @@
+/* $Id: offsetConstraint.cpp,v 1.7 2006-11-05 04:42:43 ganzhorn Exp $
+ * This file is part of lfhex.
+ * Copyright (C) 2006 Salem Ganzhorn <eyekode@yahoo.com>
+ *
+ * This program 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 version 2.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <QLabel>
+#include <QSpinBox>
+#include <QHBoxLayout>
+
+#include <algorithm> // for min<>()
+
+#include "local.h"
+#include "offsetConstraint.hpp"
+#include "box.hpp"
+
+OffsetConstraint::OffsetConstraint( QWidget * parent )
+ : QGroupBox(parent)
+{
+ QLayout* l = new QHBoxLayout(this);
+ this->setLayout(l);
+ hbox * h = new hbox(this);
+ l->addWidget(h);
+ new QLabel("X =",h);
+ stride = new QSpinBox(h);
+ stride->setRange(1,16);
+ stride->setValue(1);
+ connect(stride,SIGNAL(valueChanged(int)),
+ this,SLOT(setStride(int)));
+
+ h = new hbox(this);
+ l->addWidget(h);
+ new QLabel("Y =",h);
+ offset = new QSpinBox(h);
+ offset->setRange(1,16);
+ offset->setValue(1);
+
+ setSizePolicy(QSizePolicy(QSizePolicy::Expanding,QSizePolicy::Fixed));
+}
+
+// public interface
+
+int OffsetConstraint::getStride(void) const
+{
+ return stride->text().toInt();
+}
+
+int OffsetConstraint::getOffset(void) const
+{
+ return offset->text().toInt();
+}
+
+off_t OffsetConstraint::next(off_t off) const
+{
+ return( ((off-getOffset())/getStride()+1)*getStride()+getOffset() );
+}
+
+off_t OffsetConstraint::prev(off_t off) const
+{
+ return( ((off-getOffset())/getStride() - 1)*getStride()+getOffset() );
+}
+
+// public slots
+void OffsetConstraint::setOffset(int x)
+{
+ offset->setValue( min(x,getStride()-1) );
+}
+
+void OffsetConstraint::setStride(int x)
+{
+ // constrain x to (0,MAXINT)
+ if( x < 1 ) {
+ stride->setValue(1);
+ return;
+ }
+
+ // constrain offset to [0,x)
+
+ // setRange() does not seem to work as the documentation says, so
+ // we have to manually change the value
+ if( offset->text().toInt() >= x )
+ offset->setValue(x-1);
+ offset->setRange(0,x-1);
+ return;
+}
+
diff --git a/src/offsetConstraint.hpp b/src/offsetConstraint.hpp
new file mode 100644
index 0000000..2184ce4
--- /dev/null
+++ b/src/offsetConstraint.hpp
@@ -0,0 +1,48 @@
+/* $Id: offsetConstraint.hpp,v 1.5 2006-11-05 04:42:43 ganzhorn Exp $
+ * This file is part of lfhex.
+ * Copyright (C) 2006 Salem Ganzhorn <eyekode@yahoo.com>
+ *
+ * This program 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 version 2.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+// widget for constraining offset to stride*n+offset
+
+#include <sys/types.h>
+#include <QGroupBox>
+
+class QWidget;
+class QSpinBox;
+
+class OffsetConstraint :public QGroupBox {
+ Q_OBJECT
+
+public:
+ OffsetConstraint( QWidget * parent = 0 );
+
+ int getStride(void) const;
+ int getOffset(void) const;
+
+ // applies formula to find next/previous constrained offset
+ off_t next(off_t off) const;
+ off_t prev(off_t off) const;
+
+public slots:
+ void setStride(int);
+ void setOffset(int);
+
+protected:
+ QSpinBox * stride;
+ QSpinBox * offset; // [0,stride)
+
+};
diff --git a/src/reader.cpp b/src/reader.cpp
new file mode 100644
index 0000000..804f54c
--- /dev/null
+++ b/src/reader.cpp
@@ -0,0 +1,364 @@
+/* $Id: reader.cpp,v 1.11 2008-09-11 01:49:00 salem Exp $
+ * This file is part of lfhex.
+ * Copyright (C) 2006 Salem Ganzhorn <eyekode@yahoo.com>
+ *
+ * This program 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 version 2.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <stdexcept>
+#include <algorithm>
+#include <new>
+
+// for stat:
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+// for strerror and errno:
+#include <string.h>
+#include <errno.h>
+
+#include <assert.h>
+
+#include <stdexcept>
+
+#include "local.h"
+#include "reader.hpp" // some systems #define to map fn's to thier 64 bit
+ // equivalents. make sure the header gets processed the
+ // same as the .cc file
+
+Reader::Reader( const string& filename, off_t npages, off_t pageSize )
+ : _filename(filename),
+ _pageSize(pageSize)
+{
+ _maxPages = _freePages = (npages < 10) ? 10: npages;
+ _error = "";
+ _is_open = false;
+ _offset = 0;
+ _size = 0;
+ _firstPage = -1;
+ _lastPage = -1;
+
+ if( !filename.empty() )
+ open(filename);
+}
+
+Reader::~Reader()
+{
+ if( _is_open )
+ close();
+}
+
+//
+// public methods
+//
+
+bool Reader::open( const string& filename )
+{
+ // clear old data
+ if( is_open() ) {
+ this->close();
+ if( is_open() ) // only occurs if close somehow fails.
+ return false;
+ } else {
+ _is_open = false;
+ }
+
+ if( 0 == (_fptr = fopen( filename.c_str() , "r" )) ) {
+ _error = "Failed to open \"" + filename + "\"";
+ return false;
+ }
+
+ // get filesize
+ struct stat statBuf;
+ if( -1 == stat(filename.c_str(), &statBuf) ) {
+ _error = "Could not stat \"" + filename + "\"";
+ return false;
+ }
+
+ off_t filesize = statBuf.st_size;
+ _size = filesize;
+ // calculate necessary number of pages
+ off_t npages = filesize/_pageSize +1;
+ // initialize page pointers
+ _data.resize(npages);
+ fill( _data.begin(), _data.begin()+npages, (uchar*)0 );
+
+ _filename = filename;
+ _is_open = true;
+ _firstPage = _lastPage = 0;
+ return loadPage(0);
+}
+
+bool Reader::close()
+{
+ if( !is_open() ) {
+ _error = "attempted to close non-open reader.";
+ return false;
+ }
+
+ _filename = "";
+ _error = "";
+ if( EOF == fclose(_fptr) ) {
+ _error = strerror(errno);
+ return false;
+ }
+ // free data pages
+ vector<uchar*>::iterator itr;
+ for( itr = _data.begin(); itr != _data.end(); ++itr )
+ delete [] (*itr);
+ _is_open = false;
+ _firstPage = _lastPage = -1;
+ _freePages = _maxPages;
+ return true;
+}
+
+bool Reader::is_open() const
+{
+ return _is_open;
+}
+
+size_t Reader::read(vector<uchar>& v, size_t numBytes)
+{
+ int lastPageIdx = 0;
+ size_t bytesRead;
+
+ // if we don't have enough bytes left... then set page_end to lastPageIdx
+ // to the last page and set bytesRead to the remaining number of bytes
+ if( _offset+numBytes >= size() ) {
+ _eof = true;
+ lastPageIdx = _data.size()-1;
+ bytesRead = size()-tell();
+ // we use numBytes as a counter for the number of operations to make
+ // so limit numBytes to the actual the max number of bytes left
+ numBytes = bytesRead;
+ } else {
+ lastPageIdx = (_offset+numBytes)/_pageSize;
+ bytesRead = numBytes;
+ }
+
+ if( !numBytes )
+ return numBytes;
+
+ // only do one realloc if necessary
+ v.erase(v.begin(),v.end());
+ v.reserve(v.size()+numBytes);
+
+ // int byte_end; // == lastByteIndex+1
+ // copy the data a page at a time
+ for(int page = _offset/_pageSize; page <= lastPageIdx; page++) {
+ // ensure the page is loaded.
+ try {
+ loadPage( page );
+ }
+ catch (bad_alloc){
+ // out of memory
+ _error = "Out of memory.";
+ // return the number of bytes read
+ return (_offset/_pageSize - page)*_pageSize;
+ }
+
+ int start = _offset%_pageSize;
+ int stop = (page == lastPageIdx)? start+numBytes: _pageSize;
+ for(int i = start; i < stop; i++) {
+ v.push_back(_data[page][i]);
+ }
+ numBytes -= stop-start;
+ _offset += stop-start;
+ }
+ return bytesRead;
+}
+bool Reader::eof()
+{
+ return (is_open())? _eof : 0;
+}
+off_t Reader::seek(off_t offset)
+{
+ if( !is_open() )
+ return -1;
+
+ // seek resets eof... even if the seek is past eof
+ _eof = false;
+
+ _offset = max( min( offset, size()-1 ), (off_t)0);
+ if( fseek(_fptr, _offset, SEEK_SET) ) {
+ _error = "Seek to offset:";
+ _error += _offset;
+ _error += " failed.";
+ return -1;
+ }
+ assert(_offset == ftell(_fptr));
+ return _offset;
+}
+
+off_t Reader::tell() const
+{
+ if(!is_open())
+ return -1;
+ return _offset;
+}
+
+off_t Reader::size() const
+{
+ return _size;
+}
+
+const char* Reader::lastError() const
+{
+ return _error.c_str();
+}
+const char* Reader::filename() const
+{
+ return _filename.c_str();
+}
+
+//
+// Protected member fn's
+//
+
+bool Reader::loadPage(off_t pageIdx)
+{
+ if( !is_open() )
+ return false;
+ if(_data[pageIdx] != 0)
+ return true;
+
+ if( !nFreePages() ) {
+ // free the page which is the furthest away from the page we are loading
+
+ // this could be trouble if off_t is unsigned!
+ if( abs(_firstPage - pageIdx) > abs(_lastPage - pageIdx) )
+ while(!freePage(_firstPage++));
+ else
+ while(!freePage(_lastPage--));
+ }
+ _data[pageIdx] = new uchar [_pageSize];
+ // page added, subtract from num available
+ --nFreePages();
+
+ fseek(_fptr,pageIdx*_pageSize, SEEK_SET);
+
+ off_t retval = fread(_data[pageIdx], sizeof(uchar), _pageSize, _fptr);
+
+ if( retval ) {
+ if( pageIdx < _firstPage )
+ _firstPage = pageIdx;
+
+ if( pageIdx > _lastPage )
+ _lastPage = pageIdx;
+ }
+ return retval;
+}
+
+bool Reader::freePage(off_t pageIdx)
+{
+ // check range
+ if( pageIdx < 0 || (unsigned)pageIdx >= _data.size() || !_data[pageIdx] )
+ return false;
+
+ delete [] _data[pageIdx];
+ _data[pageIdx] = 0;
+ ++nFreePages(); // page freed
+ return true;
+}
+
+uchar Reader::operator[] (off_t offset)
+{
+ if( !is_open() )
+ throw logic_error("Reader::operator[] - attempt to access non-open file.");
+ if( offset < 0 )
+ throw out_of_range("Reader::operator[] - "
+ "attempt to access negative offset.");
+ if( offset >= size() )
+ throw out_of_range("Reader::operator[] - "
+ "attempt to access past end of file");
+
+ off_t page_idx = offset/_pageSize;
+ bool loaded = loadPage( page_idx );
+ assert( loaded );
+ return _data[page_idx][ offset%_pageSize ];
+}
+
+off_t
+Reader::nFreePages() const
+{
+ return _freePages;
+}
+
+off_t&
+Reader::nFreePages()
+{
+ return _freePages;
+}
+
+bool
+Reader::dataIsAtOffset( const vector<uchar>& data, off_t pos )
+{
+ size_t i = 0;
+ while( i < data.size() ) {
+ if( data[i] != (*this)[pos+i] ) {
+ return false;
+ }
+ ++i;
+ }
+ return true;
+}
+
+
+off_t
+Reader::findIndex( off_t start, const vector<uchar>& data, off_t stop )
+{
+ off_t pos = start;
+ while( pos <= stop ) {
+ if( data[0] == (*this)[pos] ) {
+ if( dataIsAtOffset( data, pos ) ) {
+ return pos;
+ }
+ }
+ ++pos;
+ }
+ return size();
+}
+
+off_t
+Reader::rFindIndex( off_t start, const vector<uchar>& data, off_t stop )
+{
+ off_t pos = start;
+ while( pos >= stop ) {
+ if( data[0] == (*this)[pos] ) {
+ if( dataIsAtOffset( data, pos ) ) {
+ return pos;
+ }
+ }
+ --pos;
+ }
+ return size();
+}
+
+//
+// ReadBuffer friends and aquaintances (only for debugging)
+//
+
+#if 0
+ostream& operator<< (ostream&out, const ReadBuffer& buff)
+{
+ ios_base::fmtflags old_flags = out.flags();
+ out.flags(old_flags | ios::hex | ios::showbase);
+ for(size_t i = 0; i < buff.size(); i++)
+ out << buff[i];
+ // restore old flags
+ out.flags(old_flags);
+ return out;
+}
+#endif
diff --git a/src/reader.hpp b/src/reader.hpp
new file mode 100644
index 0000000..4307c3f
--- /dev/null
+++ b/src/reader.hpp
@@ -0,0 +1,95 @@
+/* $Id: reader.hpp,v 1.6 2006-11-05 04:42:43 ganzhorn Exp $
+ * This file is part of lfhex.
+ * Copyright (C) 2006 Salem Ganzhorn <eyekode@yahoo.com>
+ *
+ * This program 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 version 2.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#ifndef _READER_H_
+#define _READER_H_
+
+//
+// Interface for Reader object.
+//
+// Reader object supports:
+// open(const QString& filename ); -> open a file for reading
+// bool is_open(); -> see if file is open
+// close(); -> free resources for open file.
+// int read( vector<uchar>& v, int maxSize ) -> fill v with maxSize data from
+// open file.
+// off_t seek( off_t offset ); -> move file pointer to offset offset.
+//
+
+#include <sys/types.h>
+#include <stdio.h>
+
+#include <vector>
+#include <string>
+#include <iostream>
+
+#include "local.h"
+
+typedef vector<uchar> ReadBuffer;
+
+#ifdef __GNUC__
+ostream& operator<< (ostream&out,const ReadBuffer& buff);
+#endif
+
+class Reader {
+ public:
+ // default is only 50*4k = 200k memory image.
+ Reader(const string& filename = "",off_t npages = 50, off_t pageSize = 4096);
+ ~Reader();
+
+ bool open(const string& filename);
+ bool close();
+ bool eof();
+ bool is_open() const;
+
+ size_t read( ReadBuffer& v, size_t numBytes );
+ off_t seek( off_t offset );
+ off_t tell() const; // returns the current offset or -1 if !open
+ off_t size() const;
+ const char* lastError() const;
+ const char* filename() const;
+
+ uchar operator[] (off_t offset); // cannot be const because it does change
+ // data by loading/swapping pages
+ off_t findIndex( off_t start, const vector<uchar>& data,
+ off_t stop );
+ off_t rFindIndex( off_t start, const vector<uchar>& data,
+ off_t stop );
+ protected:
+ bool dataIsAtOffset( const vector<uchar>& data, off_t pos );
+ bool loadPage(off_t pageIdx);
+ bool freePage(off_t pageIdx);
+ off_t nFreePages() const;
+ off_t& nFreePages();
+
+ protected:
+ string _error;
+ FILE* _fptr;
+ bool _is_open;
+ bool _eof;
+ string _filename;
+ off_t _offset; // current offset
+ off_t _size; // file size from fstat
+ off_t _pageSize; // number of bytes in a page
+ off_t _firstPage; // first currently loaded page
+ off_t _lastPage; // last currently loaded page
+ off_t _maxPages; // maximum number of pages which could be currently loaded
+ off_t _freePages; // number of free pages
+ vector< uchar *> _data;
+};
+
+#endif
diff --git a/src/save.cpp b/src/save.cpp
new file mode 100644
index 0000000..ba75043
--- /dev/null
+++ b/src/save.cpp
@@ -0,0 +1,67 @@
+/* $Id: save.cpp,v 1.4 2006-11-05 04:42:43 ganzhorn Exp $
+ * This file is part of lfhex.
+ * Copyright (C) 2006 Salem Ganzhorn <eyekode@yahoo.com>
+ *
+ * This program 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 version 2.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <errno.h>
+#include <string>
+#include <vector>
+#include <qmessagebox.h>
+#include <sys/types.h>
+
+#include "translate.hpp"
+#include "local.h"
+#include "delta.hpp"
+#include "reader.hpp"
+
+extern int errno;
+
+bool writeDeltas( const string& filename , DeltaMap& dmap )
+{
+ FILE* fptr = fopen( filename.c_str(), "r+" );
+ if( NULL == fptr ) {
+ QString message = "Error opening \"";
+ message += filename.c_str();
+ message += "\": ";
+ message += strerror(errno);
+ QMessageBox::critical( NULL, PROGRAM_STRING,
+ message,
+ "Ok");
+ return false;
+ }
+
+ const Delta * deltaPtr;
+ for(off_t offset = dmap.lower_bound(0);
+ offset != -1;
+ offset = dmap.lower_bound(offset+1)) {
+ if( fseek(fptr,offset,SEEK_SET) ) {
+ fclose(fptr);
+ QString message = "Error seeking to offset ";
+ message += offset;
+ message += ": ";
+ message += strerror(errno);
+ QMessageBox::critical( NULL, PROGRAM_STRING,
+ message,
+ "Ok");
+ return false;
+ }
+ deltaPtr = dmap.search(offset);
+ fwrite( &(deltaPtr->newData()[0]), sizeof(uchar) ,
+ deltaPtr->newData().size(), fptr);
+ }
+ fclose(fptr);
+ return true;
+}
diff --git a/src/save.hpp b/src/save.hpp
new file mode 100644
index 0000000..e0c4136
--- /dev/null
+++ b/src/save.hpp
@@ -0,0 +1,25 @@
+
+/* $Id: save.hpp,v 1.3 2006-11-05 04:42:43 ganzhorn Exp $
+ * This file is part of lfhex.
+ * Copyright (C) 2006 Salem Ganzhorn <eyekode@yahoo.com>
+ *
+ * This program 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 version 2.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _HEXEDIT_SAVE_
+#define _HEXEDIT_SAVE_
+
+bool writeDeltas( const string& filename , DeltaMap& dmap );
+
+#endif
diff --git a/src/translate.cpp b/src/translate.cpp
new file mode 100755
index 0000000..b0a96a3
--- /dev/null
+++ b/src/translate.cpp
@@ -0,0 +1,189 @@
+/* $Id: translate.cpp,v 1.4 2006-11-05 04:42:43 ganzhorn Exp $
+ * This file is part of lfhex.
+ * Copyright (C) 2006 Salem Ganzhorn <eyekode@yahoo.com>
+ *
+ * This program 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 version 2.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "translate.hpp"
+
+// translation maps from byte->hex, hex->byte, and byte->char
+// mappings are static arrays for speed
+#include "mappings.h"
+
+void Translate::CharToByte(vector<uchar>& dst, const vector<uchar>& src)
+{
+ // just copy the base into the byte vector
+ dst = vector<uchar>(src.begin(),src.end());
+}
+void Translate::CharToByte(vector<uchar>& dst, const QString& src)
+{
+ // just copy the base into the byte vector
+ dst.resize( src.length() );
+ for(int i =0 ; i < src.length(); ++i)
+ dst[i] = src[i].toAscii();
+}
+
+
+void Translate::ByteToChar(vector<uchar>& dst, const vector<uchar>& src)
+{
+ dst.erase(dst.begin(),dst.end());
+ dst.reserve(src.size());
+ for(unsigned int i = 0; i < src.size(); i++) {
+ dst.push_back(TranslationTables::byteToCharMap[src[i]]);
+ }
+}
+
+void Translate::ByteToChar(QString& dst, const vector<uchar>& src)
+{
+ dst = "";
+ for(unsigned int i = 0; i < src.size(); i++) {
+ dst += TranslationTables::byteToCharMap[src[i]];
+ }
+}
+
+void Translate::HexToByte(vector<uchar>& dst, const vector<uchar>& src)
+{
+ dst.erase(dst.begin(),dst.end());
+ int start;
+
+ if( src.size() % 2 ) {
+ // if odd
+ dst.reserve(src.size()/2+1);
+ dst.push_back(TranslationTables::hexToByteMap[src[0]]);
+ start = 1;
+ } else {
+ start = 0;
+ dst.reserve(src.size()/2);
+ }
+ for(unsigned int i = start; i < src.size(); i+=2) {
+ dst.push_back(TranslationTables::hexToByteMap[src[i]]*16 +
+ TranslationTables::hexToByteMap[src[i+1]]);
+ }
+}
+
+void Translate::HexToByte(vector<uchar>& dst, const QString& src)
+{
+ dst.erase(dst.begin(),dst.end());
+ dst.reserve(src.length()/2);
+ int i = 0;
+ if( src.length() % 2 ) {
+ i = 1;
+ }
+ for(; i < src.length(); i+=2) {
+ uchar hi = src[i].toAscii();
+ uchar lo = src[i+1].toAscii();
+ dst.push_back( TranslationTables::hexToByteMap[hi]*16 +
+ TranslationTables::hexToByteMap[lo] );
+ }
+}
+
+void Translate::OctalToByte(vector<uchar> &dst, const vector<uchar>& src)
+{
+ dst.erase(dst.begin(),dst.end());
+ dst.reserve(src.size()/3);
+ for(unsigned int i = 0; i+2 < src.size(); i+=3) {
+ dst.push_back(TranslationTables::hexToByteMap[src[i]]*64+
+ TranslationTables::hexToByteMap[src[i+1]]*8+
+ TranslationTables::hexToByteMap[src[i+2]]);
+ }
+}
+
+void Translate::BinaryToByte(vector<uchar> &dst, const vector<uchar>& src)
+{
+ dst.erase(dst.begin(),dst.end());
+ dst.reserve(src.size()/8);
+ // FIXME: would be faster if we compared each src[i] with '1' before mult
+ for(unsigned int i = 0; i < src.size(); i+=8) {
+ dst.push_back(TranslationTables::hexToByteMap[src[i]]*128+
+ TranslationTables::hexToByteMap[src[i+1]]*64+
+ TranslationTables::hexToByteMap[src[i+2]]*32+
+ TranslationTables::hexToByteMap[src[i+3]]*16+
+ TranslationTables::hexToByteMap[src[i+4]]*8+
+ TranslationTables::hexToByteMap[src[i+5]]*4+
+ TranslationTables::hexToByteMap[src[i+6]]*2+
+ TranslationTables::hexToByteMap[src[i+7]]);
+ }
+}
+
+const char * Translate::ByteToHex(uchar b)
+{
+ return TranslationTables::byteToHexMap[b];
+}
+
+void Translate::ByteToHex(vector<uchar>& dst, const vector<uchar>& src)
+{
+ const char * str;
+ dst.erase(dst.begin(),dst.end());
+ dst.reserve(src.size()*2);
+ for(unsigned int i = 0; i < src.size(); i++) {
+ str = TranslationTables::byteToHexMap[src[i]];
+ dst.push_back(*str);
+ dst.push_back(*(str+1));
+ }
+}
+
+void Translate::ByteToHex(QString& dst, const vector<uchar>&src)
+{
+ dst = "";
+ for(unsigned int i = 0; i < src.size(); i++) {
+ dst += TranslationTables::byteToHexMap[src[i]];
+ }
+}
+
+void Translate::ByteToOctal(vector<uchar>&dst, const vector<uchar>&src)
+{
+ dst.erase(dst.begin(),dst.end());
+ dst.reserve(src.size()*3);
+
+ vector<uchar>::const_iterator itr;
+ const char * str;
+ for(itr = src.begin(); itr != src.end(); ++itr) {
+ str = TranslationTables::byteToOctalMap[*itr];
+ dst.insert( dst.end(), str, str+3 );
+ }
+}
+
+void Translate::ByteToOctal(QString&dst, const vector<uchar>&src)
+{
+ dst = "";
+ vector<uchar>::const_iterator itr;
+ for(itr = src.begin(); itr != src.end(); ++itr) {
+ dst += TranslationTables::byteToOctalMap[*itr];
+ }
+}
+
+void Translate::ByteToBinary(vector<uchar>&dst, const vector<uchar>&src)
+{
+ dst.erase(dst.begin(),dst.end());
+ dst.reserve(src.size()*8);
+
+ vector<uchar>::const_iterator itr;
+ const char * str;
+ for(itr = src.begin(); itr != src.end(); ++itr) {
+ str = TranslationTables::byteToBinaryMap[*itr];
+ dst.insert(dst.end(), str, str+8);
+ }
+}
+
+void Translate::ByteToBinary(QString&dst, const vector<uchar>&src)
+{
+ dst = "";
+
+ vector<uchar>::const_iterator itr;
+ for(itr = src.begin(); itr != src.end(); ++itr) {
+ dst += TranslationTables::byteToBinaryMap[*itr];
+ }
+}
+
diff --git a/src/translate.hpp b/src/translate.hpp
new file mode 100755
index 0000000..6fa9898
--- /dev/null
+++ b/src/translate.hpp
@@ -0,0 +1,47 @@
+/* $Id: translate.hpp,v 1.4 2006-11-05 04:42:43 ganzhorn Exp $
+ * This file is part of lfhex.
+ * Copyright (C) 2006 Salem Ganzhorn <eyekode@yahoo.com>
+ *
+ * This program 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 version 2.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#include <vector>
+#include <QString>
+
+#include "local.h"
+
+typedef unsigned char uchar;
+
+namespace Translate {
+ const char* ByteToHex(uchar b);
+ void ByteToHex(vector<uchar>& dst , const vector<uchar>& src);
+ void ByteToChar(vector<uchar>& dst, const vector<uchar>& src);
+ void ByteToOctal(vector<uchar>& dst,const vector<uchar>& src);
+ void ByteToBinary(vector<uchar>& dst,const vector<uchar>& src);
+
+ void ByteToHex(QString& dst , const vector<uchar>& src);
+ void ByteToChar(QString& dst, const vector<uchar>& src);
+ void ByteToOctal(QString& dst,const vector<uchar>& src);
+ void ByteToBinary(QString& dst,const vector<uchar>& src);
+
+ void BinaryToByte(vector<uchar>& dst,const vector<uchar>& src);
+
+ void OctalToByte(vector<uchar>& dst,const vector<uchar>& src);
+
+ void CharToByte(vector<uchar>& dst, const vector<uchar>& src);
+ void CharToByte(vector<uchar>& dst, const QString& src);
+
+ void HexToByte(vector<uchar>& dst , const vector<uchar>& src);
+ void HexToByte(vector<uchar>& dst , const QString& src);
+
+};